How to run commands by sudo and enter password by ssh .net c#

Nastaran Hakimi picture Nastaran Hakimi · Jan 9, 2017 · Viewed 9.9k times · Source

I want to run command and get the result on remote computer which has Linux operating system. I am using ssh .net library to connect by C# code. I can connect and run some commands that it doesn't need to use "sudo" before. but I don't know How to run commands which need to be run by sudo, because after run -for instance- "sudo iptables -L -n" I should enter password and I don't know How to enter password after execute this command.

This is my code :

private void connectingToLinuxHost(string ip, string username, string password, int port)
{
    SshCommandLineRunner ssh = new SshCommandLineRunner(ip, username, password, port);
    ssh.Connect();
    string output1 = ssh.ExecuteCommand("ls");

    ssh.ExecuteCommand("sudo iptables -L -n");
    Thread.Sleep(1000);
    string output2 = ssh.ExecuteCommand(password);

    ssh.ExecuteCommand("sudo iptables -L -n \n");
    Thread.Sleep(1000);
    string output3 = ssh.ExecuteCommand(password);
}

when this function run, I can connect to remote pc successfully, output1 has correct value, but output2 and output3 are empty. actually it is obvious that after sudo command it is needed to enter password. I have read most question about ssh .net. some similar question has retain unanswered.

SSH .NET : freeze upon sudo su - user2 ( he or she didnt know the password but I know I dont know how to enter it via code)

How to su with SSH.Net? (I used create shell method but i couldn't understand what is for and like this question I got "Last login: ..." output.)

Answer

RogerN picture RogerN · Jan 9, 2017

The most secure way to do it, as already mentioned by a comment, is to use CreateShellStream and just write the password directly to the stream after running the sudo command. The password gets sent just as if you had been using an interactive terminal. This might not be a convenient solution, though, if you don't want to be locked into using an endless stream for the rest of what you want to do. Example:

var promptRegex = new Regex(@"\][#$>]"); // regular expression for matching terminal prompt
var modes = new Dictionary<Renci.SshNet.Common.TerminalModes, uint>();
using (var stream = ssh.CreateShellStream("xterm", 255, 50, 800, 600, 1024, modes))
{
    stream.Write("sudo iptables -L -n\n");
    stream.Expect("password");
    stream.Write("mypassword\n");
    var output = stream.Expect(promptRegex);
}

The downside is that your output will include junk you don't really want: control characters, prompts, and everything else that gets sent over the stream.

If you want to avoid using a shell stream then you may be able to (depending on security settings) provide a password via stdin. THIS IS INSECURE because commands get logged in various places and you might be revealing your password to other users with root access. If you're the only user, or if you don't care that everybody else can see your password, then this might be more convenient for you.

Example:

using (var cmd = ssh.RunCommand("echo -e 'mypassword\n' | sudo -S iptables -L -n"))
{
    if (cmd.ExitStatus == 0)
        Console.WriteLine(cmd.Result);
    else
        Console.WriteLine(cmd.Error);
}

Finally, it's also possible to have a script print your password to stdin. This way your password won't get logged along with the rest of the command line; but this still isn't much more secure since anyone with root access could potentially read the script and see the password:

using (var cmd = ssh.RunCommand("~/printpasswd.sh | sudo -S iptables -L -n"))
{
    if (cmd.ExitStatus == 0)
        Console.WriteLine(cmd.Result);
    else
        Console.WriteLine(cmd.Error);
}

and inside printpasswd.sh:

#!/bin/bash
echo -e 'mypassword\n'