带有密码提示 C# 的多跳 SSH 问题

Posted

技术标签:

【中文标题】带有密码提示 C# 的多跳 SSH 问题【英文标题】:Trouble with Multi-Hop SSH with password prompt C# 【发布时间】:2020-02-01 08:58:35 【问题描述】:

如何将密码传递给不允许我通过命令发送的 SSH 提示?

这不起作用

 KeyboardInteractiveAuthenticationMethod DEVICEkauth = new KeyboardInteractiveAuthenticationMethod(DEVICEsshUname);
            PasswordAuthenticationMethod DEVICEpauth = new PasswordAuthenticationMethod(DEVICEsshUname, DEVICEsshPass);

我正在尝试进行多跳 ssh 连接,但由于 SSH 协议识别,它在第三跳失败。

Multi hop SSH through SSH.NET in C# 没有解决我的问题 问题,它确实帮助我完成了大部分工作。这个问题试图 进行第三次跳跃,但不起作用。

这是通过 VeloCloud 网关连接到 Velo Edge,然后连接到终端设备(DiGi 传输)

我目前所拥有的:

    int sssshTimeOut = 1000;

    KeyboardInteractiveAuthenticationMethod VCGkauth = new KeyboardInteractiveAuthenticationMethod(VCGsshUname);
    PasswordAuthenticationMethod VCGpauth = new PasswordAuthenticationMethod(VCGsshUname, VCGsshPass);

    VCGkauth.AuthenticationPrompt += new EventHandler<AuthenticationPromptEventArgs>(VCGHandleKeyEvent);

    SshClient sshVCG = new SshClient(new ConnectionInfo(VCGsshHost, VCGsshPort, VCGsshUname, VCGpauth, VCGkauth));
    if (sssshTimeOut != 0)
    
        sshVCG.ConnectionInfo.Timeout = TimeSpan.FromSeconds(sssshTimeOut);
    

    void VCGHandleKeyEvent(Object sender, AuthenticationPromptEventArgs e)
    
        foreach (AuthenticationPrompt prompt in e.Prompts)
        
            if (prompt.Request.IndexOf("Password:", StringComparison.InvariantCultureIgnoreCase) != -1)
            
                prompt.Response = VCGsshPass;
            
        
    

    KeyboardInteractiveAuthenticationMethod EDGEkauth = new KeyboardInteractiveAuthenticationMethod(EDGEsshUname);
    PasswordAuthenticationMethod EDGEpauth = new PasswordAuthenticationMethod(EDGEsshUname, EDGEsshPass);

    EDGEkauth.AuthenticationPrompt += new EventHandler<AuthenticationPromptEventArgs>(EDGEHandleKeyEvent);
    void EDGEHandleKeyEvent(Object sender, AuthenticationPromptEventArgs e)
    
        foreach (AuthenticationPrompt prompt in e.Prompts)
        
            if (prompt.Request.IndexOf("Password:", StringComparison.InvariantCultureIgnoreCase) != -1)
            
                prompt.Response = EDGEsshPass;
            
        
    

    KeyboardInteractiveAuthenticationMethod DEVICEkauth = new KeyboardInteractiveAuthenticationMethod(DEVICEsshUname);
    PasswordAuthenticationMethod DEVICEpauth = new PasswordAuthenticationMethod(DEVICEsshUname, DEVICEsshPass);

    DEVICEkauth.AuthenticationPrompt += new EventHandler<AuthenticationPromptEventArgs>(DEVICEHandleKeyEvent);
    void DEVICEHandleKeyEvent(Object sender, AuthenticationPromptEventArgs e)
    
        foreach (AuthenticationPrompt prompt in e.Prompts)
        
            if (prompt.Request.IndexOf("password:", StringComparison.InvariantCultureIgnoreCase) != -1)
            
                prompt.Response = DEVICEsshPass;
            
        
    

    Console.WriteLine("Connecting to VCG: "+ VCGsshHost + "");
    sshVCG.Connect();

    Console.WriteLine("Sending ARP command to VCG: " + VCGsshHost + "");
    var commandVCG = sshVCG.CreateCommand("arp -n");
    var resultVCG = commandVCG.Execute();
    Console.WriteLine(resultVCG);

    Console.WriteLine("");
    Console.WriteLine("");
    Console.WriteLine("Forwarding SSH connection to Edge: " + EDGEsshHost + "");
    var portVCG = new ForwardedPortLocal("127.0.0.1", uintVCGsshPort, EDGEsshHost, uintEDGEsshPort);
    sshVCG.AddForwardedPort(portVCG);
    portVCG.Start();
    if (portVCG.IsStarted)
    
        Console.WriteLine("Forwarding SSH connection to Edge: Started!");
    
    else
    
        Console.WriteLine("Forwarding SSH connection to Edge: seems to have failed.....");
    

    SshClient sshEDGE = new SshClient(new ConnectionInfo(portVCG.BoundHost, (int)portVCG.BoundPort, EDGEsshUname, EDGEpauth, EDGEkauth));
    sshEDGE.Connect();

    Console.WriteLine("Sending ARP command to Edge: " + EDGEsshHost + "");
    var commandEDGE = sshEDGE.CreateCommand("arp -n");
    var resultEDGE = commandEDGE.Execute();
    Console.WriteLine(resultEDGE);

    Console.WriteLine("");
    Console.WriteLine("");
    Console.WriteLine("Forwarding SSH connection to EndDevice: " + DEVICEsshHost + "");
    var portEDGE = new ForwardedPortLocal("127.0.0.1", uintEDGEsshPort, DEVICEsshHost, uintDEVICEsshPort);
    sshEDGE.AddForwardedPort(portEDGE);
    //sshVCG.AddForwardedPort(portEDGE);
    portEDGE.Start();
    if (portEDGE.IsStarted)
    
        Console.WriteLine("Forwarding SSH connection to End Device: Started!");
    
    else
    
        Console.WriteLine("Forwarding SSH connection to End Device: seems to have failed.....");
    

    SshClient sshDEVICE = new SshClient(new ConnectionInfo(portEDGE.BoundHost, (int)portEDGE.BoundPort, DEVICEsshUname, DEVICEpauth, DEVICEkauth));
    //SshClient sshDEVICE = new SshClient(new ConnectionInfo(portVCG.BoundHost, (int)portVCG.BoundPort, DEVICEsshUname, DEVICEpauth, DEVICEkauth));
    //SshClient sshDEVICE = new SshClient(portEDGE.BoundHost, (int)portEDGE.BoundPort, DEVICEsshUname, DEVICEsshPass);
    sshDEVICE.Connect();

    Console.WriteLine("");
    Console.WriteLine("");
    Console.WriteLine("Sending HW command to End Device: " + DEVICEsshHost + "");
    var commandDEVICE = sshDEVICE.CreateCommand("hw");
    var resultDEVICE = commandDEVICE.Execute();
    Console.WriteLine(resultDEVICE);

我希望 SSH 连接到 VGC,然后是 Edge,然后是终端设备,然后运行命令。

如果我通过 Plink 执行此过程,则此过程会变得很远......

错误:

Renci.SshNet.Common.SshConnectionException: '服务器响应没有 包含 SSH 协议标识。'

链接

Plink Window 1

C:\Users\ncarter>Plink.exe -ssh -L 4000:xxx.xxx.xxx.2:22 xxxxxxx@xx.xx.xxx.85 -P 10444
Using username "xxxxxxx".
xxxxxx@xx.xx.xxx.85's password:
Welcome to Velocloud VCG (GNU/Linux 3.13.0-160-generic x86_64)

 * Documentation:  https://help.ubuntu.com/

  Get cloud support with Ubuntu Advantage Cloud Guest:
    http://www.ubuntu.com/business/services/cloud

Last login: Fri Oct 11 18:44:59 2019 from xxx.xxx.x.42
]0;xxxxxx@xxxx-xxlab: ~xxxxxx@xxxx-xxlab:~$

Plink Window 2

C:\Users\ncarter>Plink.exe -ssh -L 8001:xxx.xxx.xx.1:xxx97 xxxx@127.0.0.1 -P 4000
Using username "xxxxx".
Using keyboard-interactive authentication.
Password:


BusyBox v1.23.2 (2018-10-19 16:11:09 UTC) built-in shell (ash)

  _    __     __      ________                __
 | |  / /__  / /___  / ____/ /___  __  ______/ /
 | | / / _ \/ / __ \/ /   / / __ \/ / / / __  /
 | |/ /  __/ / /_/ / /___/ / /_/ / /_/ / /_/ /
 |___/\___/_/\____/\____/_/\____/\__,_/\__,_/

                                  VeloCloud Inc.
------------------------------------------------
velocloud Test-Edge-1:~# [6narp
Address                  HWtype  HWaddress           Flags Mask            Iface
192.168.11.1             ether   00:04:2d:07:b9:1f   C                     ge4
xx.xxx.xxx.227           ether   50:7b:9d:35:1d:12   C                     br-network1
SIP-xxxx.xxx             ether   80:5e:c0:29:61:ad   C                     br-network1
198.19.0.33              ether   00:50:56:91:ff:2e   C                     ge3
198.19.0.1               ether   90:6c:ac:bb:c9:8c   C                     ge3
198.19.0.32              ether   00:50:56:91:7f:da   C                     ge3
xxx.xxx.xx.4             ether   50:7b:9d:35:1d:12   C                     br-network1
velocloud Test-Edge-1:~# [6nssh -p xxx97 xxxxxx@192.168.11.1 -t 'hw'
xxxxxx@192.168.11.1's password:

SN:506143
Welcome. Your access level is SUPER

ss506143>
Serial Number: 506143
HW Rev: 3205b
MAC 0: 00042d07b91f
MAC 1: 00042df7b91f
MAC 2: 00042de7b91f
MAC 3: 00042dd7b91f
MAC 4: 00042dc7b91f
MAC 5: 000000000000
MAC 6: 000000000000
Model: WR11
Part#: WR11-L800-DE1-SU
RAM: 64 MB
OK

ss506143>Connection to 192.168.11.1 closed.
velocloud Test-Edge-1:~# [6n

【问题讨论】:

见Multi hop SSH through SSH.NET in C# 我在发布我的问题之前检查了这一点,该解决方案没有正确验证 SSH 连接。它在第一次连接时失败。同样,SSH 连接(两者)都需要键盘交互式身份验证。也许我做错了什么? 好的,我知道你需要使用键盘认证。但我相信你的键盘验证码是正确的。在我看来,这是端口转发代码。所以使用我的代码进行端口转发,只需将密码认证替换为键盘交互认证即可。 @MartinPrikryl,谢谢,就是这样!我需要使用 portVCG.BoundHost 和 portVCG.BoundPort 变量,它们替换了 EDGEsshHost 和 EDGEsshPort 变量。 这条线现在的样子 SshClient sshEDGE = new SshClient(new ConnectionInfo(portVCG.BoundHost, (int)portVCG.BoundPort, EDGEsshUname, EDGEpauth, EDGEkauth));错过这个我觉得很愚蠢! 我想我需要将新端口添加到第一跳,所以它看起来像 sshVCG.AddForwardedPort(portEDGE);。我会尽快对此进行测试。 【参考方案1】:

我找到了适合我具体情况的答案:

我只能通过 SSH 连接到 VCG(第一个设备),然后通过 SSH 隧道(转发)到 Edge(第二个设备),最后只需在 Edge 上运行 SSH 命令将命令传递给DiGi(Third Device),然后听触发器输入密码。

我所做的是创建一个名为“input”的 PipeStream,然后启动一个 shell 使用“输入”管道流作为外壳到称为“外壳”的边缘 输入。然后我在 “输入”管道流。

然后我将我的 SSH 命令发送到 sshEDGE shell 并监听 PipeStream 上的单词“密码”并传入所需的密码。

注意 while 循环,我将每个循环的位置重置为 0。

然后我正在监听“关闭”这个词或指定的超时时间 知道何时退出第二个 while 循环。

然后我 StreamRead '输出'并将其分配给我的'ssdeviceResponse' var (reader.ReadToEnd();).

ssdeviceResponse = "";
uint uintssvcgPort = (uint)(int)ssvcgPort;
uint uintEDGEsshPort = (uint)(int)ssedgePort;
uint uintssdevicePort = (uint)(int)ssdevicePort;
int sssshTimeOut = 1000;

KeyboardInteractiveAuthenticationMethod VCGkauth = new KeyboardInteractiveAuthenticationMethod(ssvcgUN);
PasswordAuthenticationMethod VCGpauth = new PasswordAuthenticationMethod(ssvcgUN, ssvcgPass);

VCGkauth.AuthenticationPrompt += new EventHandler<AuthenticationPromptEventArgs>(VCGHandleKeyEvent);

void VCGHandleKeyEvent(Object sender, AuthenticationPromptEventArgs e)

    foreach (AuthenticationPrompt prompt in e.Prompts)
    
        if (prompt.Request.IndexOf("Password:", StringComparison.InvariantCultureIgnoreCase) != -1)
        
            prompt.Response = ssvcgPass;
        
    


KeyboardInteractiveAuthenticationMethod EDGEkauth = new KeyboardInteractiveAuthenticationMethod(ssedgeUN);
PasswordAuthenticationMethod EDGEpauth = new PasswordAuthenticationMethod(ssedgeUN, ssedgePass);

EDGEkauth.AuthenticationPrompt += new EventHandler<AuthenticationPromptEventArgs>(EDGEHandleKeyEvent);
void EDGEHandleKeyEvent(Object sender, AuthenticationPromptEventArgs e)

    foreach (AuthenticationPrompt prompt in e.Prompts)
    
        if (prompt.Request.IndexOf("Password:", StringComparison.InvariantCultureIgnoreCase) != -1)
        
            prompt.Response = ssedgePass;
        
    


SshClient sshVCG = new SshClient(new ConnectionInfo(ssvcgAddress, ssvcgPort, ssvcgUN, VCGpauth, VCGkauth));
if (sssshTimeOut != 0)

    sshVCG.ConnectionInfo.Timeout = TimeSpan.FromSeconds(sssshTimeOut);

sshVCG.Connect();

var portVCG = new ForwardedPortLocal("127.0.0.1", ssedgeAddress, uintEDGEsshPort);
sshVCG.AddForwardedPort(portVCG);
portVCG.Start();

SshClient sshEDGE = new SshClient(new ConnectionInfo(portVCG.BoundHost, (int)portVCG.BoundPort, ssedgeUN, EDGEpauth, EDGEkauth));
sshEDGE.Connect();


var input = new PipeStream();
var streamWriter = new StreamWriter(input)  AutoFlush = true ;
Stream outPut = new MemoryStream();
var outPutEXT = new MemoryStream();

var shell = sshEDGE.CreateShell(input, outPut, outPutEXT);
shell.Start();

streamWriter.WriteLine("ssh -p " + ssdevicePort + " " + ssdeviceUN + "@" + ssdeviceAddress + " -t '" + ssdeviceCommand + "'");


int Count = 0;
while (input.CanRead)

    outPut.Position = 0;
    StreamReader reader1 = new StreamReader(outPut);
    string i = reader1.ReadToEnd();
    if (i.Contains("password"))
    
        streamWriter.WriteLine(ssdevicePass);
        break;
    



while (input.CanRead)

    Count = Count + 1;
    Thread.Sleep(2000); //Added this because the shell would close if I read to fast, weird...
    outPut.Position = 0;
    StreamReader reader1 = new StreamReader(outPut);
    string i = reader1.ReadToEnd();
    if (i.Contains("closed"))
    
        break;
    
    else if (Count >= 10)
    
        //Timeout
        break;
    


outPut.Position = 0;
StreamReader reader = new StreamReader(outPut);
ssdeviceResponse = reader.ReadToEnd();
//Console.WriteLine(ssdeviceResponse);
//Console.WriteLine("!!!END!!!");

streamWriter.Dispose();
reader.Dispose();
outPutEXT.Dispose();
outPut.Dispose();

【讨论】:

以上是关于带有密码提示 C# 的多跳 SSH 问题的主要内容,如果未能解决你的问题,请参考以下文章

如何使用织物进行多跳 ssh

在多跳 SSH 连接上重新建立交互式 shell

SSH实现多跳代理

论文泛读68使用多跳密集检索来回答复杂的开放域问题

ssh密码正确后没有提示

SourceTree提示ssh密钥认证失败的解决