当前位置: 首页 > 知识库问答 >
问题:

paramiko:将ssh会话嵌套到另一台计算机,同时保留paramiko功能(ProxyJump)

东方华荣
2023-03-14
 MyLocalMachine ----||----> MiddleMachine --(netcat)--> AnotherMachine
 ('localhost')  (firewall)   ('1.1.1.1')                 ('2.2.2.2')
  • MyLocalMachineAnotherMachine
  • 没有直接连接
  • MiddleMachine上的SSH服务器将不接受任何打开连接到AnotherMachine
  • 的直接TCPIP通道的尝试
  • 我不能使用SSH密钥。只能通过给定的用户名和密码进行连接。
  • 我不能使用sshpass
  • 我不能使用pexpect
  • 我要自动连接
  • 我想保留paramiko的所有功能

我可以使用以下代码部分地实现这一点:

cli = paramiko.SSHClient()
cli.set_missing_host_key_policy(paramiko.AutoAddPolicy())
proxy = paramiko.ProxyCommand('ssh user@1.1.1.1 nc 2.2.2.2 22')
cli.connect(hostname='2.2.2.2', username='user', password='pass', sock=proxy)

问题是,因为proxycommand使用subprocess.popen来运行给定的命令,所以它要求我根据用户输入给出密码“ad-hoc”(而且,它要求mylocalmachine上的操作系统安装ssh-这并不总是这样)。

由于proxycommand方法(recvsend)是一个简单的绑定到专用的popen方法,所以我想知道是否可以欺骗paramiko客户机使用另一个客户机的会话作为代理?

共有1个答案

易星宇
2023-03-14

更新15.05.18:增加了缺失的代码(复制粘贴神对我没有好处)。

TL;DR:我使用简单的exec_command调用和一个假装是sock的类来实现这一点。

总结一下:

    null

下面的代码定义了一个类,可以用来代替paramiko.proxyCommand。它提供了标准socket对象所提供的所有方法。该类的init方法接受exec_command()通常返回的3元组:

注意:我对它进行了广泛的测试,但你不应该认为任何事情都是理所当然的。这是一个黑客。

import paramiko
import time
import socket     
from select import select                                                       


class ParaProxy(paramiko.proxy.ProxyCommand):                      
    def __init__(self, stdin, stdout, stderr):                             
        self.stdin = stdin                                                 
        self.stdout = stdout                                               
        self.stderr = stderr
        self.timeout = None
        self.channel = stdin.channel                                               

    def send(self, content):                                               
        try:                                                               
            self.stdin.write(content)                                      
        except IOError as exc:                                             
            raise socket.error("Error: {}".format(exc))                                                    
        return len(content)                                                

    def recv(self, size):                                                  
        try:
            buffer = b''
            start = time.time()

            while len(buffer) < size:
                select_timeout = self._calculate_remaining_time(start)
                ready, _, _ = select([self.stdout.channel], [], [],
                                     select_timeout)
                if ready and self.stdout.channel is ready[0]:
                      buffer += self.stdout.read(size - len(buffer))

        except socket.timeout:
            if not buffer:
                raise

        except IOError as e:
            return ""

        return buffer

    def _calculate_remaining_time(self, start):
        if self.timeout is not None:
            elapsed = time.time() - start
            if elapsed >= self.timeout:
                raise socket.timeout()
            return self.timeout - elapsed
        return None                                   

    def close(self):                                                       
        self.stdin.close()                                                 
        self.stdout.close()                                                
        self.stderr.close()
        self.channel.close()                                                                                                                            

下面展示了我是如何使用上面的类来解决我的问题的:

# Connecting to MiddleMachine and executing netcat
mid_cli = paramiko.SSHClient()
mid_cli.set_missing_host_key_policy(paramiko.AutoAddPolicy())
mid_cli.connect(hostname='1.1.1.1', username='user', password='pass')
io_tupple = mid_cli.exec_command('nc 2.2.2.2 22')

# Instantiate the 'masquerader' class
proxy = ParaProxy(*io_tupple)

# Connecting to AnotherMachine and executing... anything...
end_cli = paramiko.SSHClient()
end_cli.set_missing_host_key_policy(paramiko.AutoAddPolicy())
end_cli.connect(hostname='2.2.2.2', username='user', password='pass', sock=proxy)
end_cli.exec_command('echo THANK GOD FINALLY')
 类似资料:
  • 问题内容: 我正在重写我在Python中编写的Bash脚本。该脚本的关键是 我在使用paramiko进行嵌套身份验证时遇到问题。我找不到适合我具体情况的任何示例,但是我能够在远程主机上找到带有 sudo的 示例。 第一种方法写入标准输入 第二个创建通道并使用类似于套接字的 send 和 recv 。 我能够使 stdin.write 与 sudo一起使用 ,但在远程主机上的 ssh 上却不起作用。

  • 我正在编写一个python脚本,该脚本发送到网络中的每台交换机,并发出一个copy running-config TFTP命令,备份交换机的运行配置。我在windows上使用Python2.7中的paramiko库。 脚本本身非常简单,它所做的只是创建一个名为“备份”的目录(如果还不存在的话),以及另一个名为“今天的日期”的目录,然后将该目录用于TFTP。并启动TFTP服务器。然后它只需通过SSH

  • 我打算使用paramiko在远程主机上运行几个命令,但ssh会话在运行一个命令后关闭。 下面列出的代码: 那么有什么方法可以阻止ssh会话关闭吗?或者帕拉米科的替代品? 有什么方法可以让paramiko ssh会话一直处于活动状态吗? paramiko调试模式信息返回如下: 启动线程(客户端模式):0x2657E10L 已连接(版本1.99,客户端组件-5.20) kex ALGOS:[u'dif

  • 问题内容: 我是python新手。我写了一个脚本来连接到主机并执行一个命令 当远程命令不需要tty时,可以正常工作。我找到了一个与Paramiko的invoke_shell示例嵌套SSH会话。我对这种解决方案不满意,因为如果服务器上的提示未在我的脚本中指定->无限循环,或者脚本中指定的提示是返回文本中的字符串->不会接收到所有数据。有没有更好的解决方案,也许将stdout和stderr像我的脚本一

  • 我是Python的新手。我编写了一个脚本连接到主机并执行一个命令

  • 问题内容: 我正在尝试使用Paramiko嵌套SSH,在那儿我将从本地计算机连接到Server X,然后从那里连接到ServerY。在这里使用用户名,密码身份验证连接到Server XI,并使用用户名和密码连接到Server Y RSA密钥。事实是,RSA密钥托管在用于连接服务器Y的系统X中。如果我将密钥文件托管在本地PC中,并将本地PC目录路径提供给Paramiko SSH客户端,则能够成功运行