反向ssh访问

通过ssh实现端口的反向转发,可以通过ssh实现内网机器直接在公网上被ssh访问

一、基本情况

  • 环境介绍:

– hostA 192.168.20.1(家用主机)

– hostB 139.224.10.45 (阿里云服务器)

  • 目的:为了实现在外网能够主动访问到家用网络中的个人电脑。

二、ssh命令使用

  • ssh相关参数   -D [bind_address:]port
          指定一个本地动态应用层端口做转发端口。工作方式是分配一个套接字监听在此端口,当监听到此端口有连接时,此连接中的数据将通过安全隧道转发到server端,server端再和目的地(端口)建立连接,目的地(端口)由应用层协议决定。目前支SOCK4和SOCK5两种协议,并且SSH将扮演SOCKS服务端角色。
            只有root用户可以开启特权端口。动态转发端口也可以在配置文件中指定。
                默认情况下,转发端口将绑定在GatewayPorts指令指定的地址上,但是可以显式指定bind_address,如果bind_address设置为”localhost”,则转发端口将绑定在回环地址上,如果bind_address不设置或设置为”*”,则转发端口绑定在所有网路接口上。
       
      -E log_file
                将debug日志写入到log_file中,而不是默认的标准错误输出stderr。
               
    -f     请求ssh在工作在后台模式。该选项隐含了”-n”选项,所以标准输入将变为/dev/null。

      -G     使用该选项将使得ssh在匹配完Host后将输出与之对应的配置选项,然后退出

      -g     允许远程主机连接到本地转发端口上。
       
      -N     明确表示不执行远程命令。仅作端口转发时比较有用。
       
      -q     静默模式。大多数警告信息将不输出。
       
      -R [bind_address:]port:host:hostport
      -R [bind_address:]port:local_socket
      -R remote_socket:host:hostport
      -R remote_socket:local_socket
                对远程(server端)指定的TCP端口port的连接都就将转发到本地主机和端口上,工作方式是在远端(server)分配一个套接字socket监听TCP端口。当监听到此端口有连接时,连接将通过安全隧道转发给本地,然后从本地主机建一条到host:hostport的连接。端口转发也可以在配置文件中指定。只有root用户才能转发特权端口(小于1024)。
                默认远程(server)套接字被绑定在回环地址上。但是,显式指定的bind_address可以用于绑定套接字到指定的地址上。如果不设置bind_address或设置为”*”则表示套接字监听在所有网络接口上。
                只有当远程(server)主机的GatewayPorts选项开启时,指定的bind_address才能生效。(见sshd_config(5))。
                如果port值为0,远程主机(server)监听的端口将被动态分配,并且在运行时报告给客户端。
  • 具体命令

ssh -fNR dport:localhost:sport user@dip -p port

ssh -fNR 4444:localhost:22 root@10.21.0.81 -p 256

  • 解析:
    • 功能:在远程主机10.21.0.81(dip)上打开4444(dport)端口,远程主机可通过访问本机的4444端口访问localhost源主机的对应端口
    • 详解:
      • -f 用于使给命令保持后台运行,-N不向目标发送任何命令
      • -R [bind_address:]port:host:hostport 格式: 远端地址:希望远端开放的端口:本机地址:本机ssh的端口 。远端地址可以省略,因为后面会有远端的访问地址。远端地址端口、本地地址端口都可以用套接字代替。这个-R参数在连接远端机器的同时,对远端机器做了这样的请求:在localhost端口4444上监听,并将在此接收到的数据包通过我们这个ssh连接转发给我。远端按照该请求执行是ssh协议允许的,在远端机器上4444端口监听的仍然是sshd进程,它可以决定将数据包用sshd下的哪个线程进行处理。当然,此后发往远端机器上4444端口的数据都会被sshd进程收到,并由本地与远端的ssh通道发送给本地机器。另外,本地机器收到这个数据后,认为这个数据是发给22号端口的,即本地机器上的ssh服务。整个过程都是在ssh服务框架下完成的。

三、实验

  • 主机A:Centos7.6 IP:192.168.44.17 本地主机主机B:Ubuntu18 IP:136.22.10.4 ssh端口:666 远程主机
    • 在A上执行命令ssh -fNR 4444:localhost:22 root@136.22.10.4 -p666
    • 查看B上的端口是否打开ss -ntlp
    • 在B上ssh测试ssh root@127.0.0.1 -p4444
  • 注意事项
    • 该操作只允许从本机访问127.0.0.1地址的对应端口实现
    • 关闭连接,通过kill掉远程对应端口下的sshd进程

四、扩展

4.1 实现第三方主机直接访问本地主机

4.1.1 通过iptables转发实现,参考命令:

iptables -t nat -A PREROUTING -p tcp -m tcp --dport 4444 -j DNAT --to-destination 127.0.0.1:4444

访问远程主机的4444端口时,远程主机会自动转发到本机127.0.0.1的4444端口。

注意:要实现转发到本机地址的端口,需手动开启本地路由,参考命令:

echo 1 > /proc/sys/net/ipv4/conf/all/route_localnet

4.1.2 配置服务器端ssh

修改公网主机 B 的 SSH 配置文件/etc/ssh/sshd_config

GatewayPorts yes

这样可以把监听的端口绑定到任意 IP 0.0.0.0 上,否则只有本机 127.0.0.1 可以访问。

重启 sshd 服务

sudo service sshd restart

4.2 实现其他端口的转发

– 上述ssh命令,将本机端口改为其他的服务端口时,依然能够生效,且能够实现端口的反向转发。例:

ssh -fNR 4444:localhost:80 root@136.22.10.4 -p666           #如果本地机器有http服务,且监听在80端口。那么执行该命令后,也可通过访问远端的4444端口来访问本机的http服务,即实现了反向的端口转发

4.3 利用 AutoSSH 实现稳定持久端口转发

在内网主机 A 上先安装autossh,利用 AutoSSH 建立一条 SSH 隧道

autossh -M 4010 -NR 80:localhost:4000 username@xxx.xxx.xxx.xxx (-p xxxx)

参数解释:

  • “-M 4010”意思是使用内网主机 A 的 4010 端口监视 SSH 连接状态,连接出问题了会自动重连
  • “ -N”意思是不执行远程命令
  • “-R”意思是将远程主机(公网主机 B)的某个端口转发到本地指定机器的指定端口

代码解释:

  • “80:localhost:4000”意思是将内网主机 A 的 4000 号端口转发至公网主机 B 的 80 号端口上
  • “username@xxx.xxx.xxx.xxx”意思是公网主机 B 的用户名和 IP
  • “-p xxxx”意思是公网主机 B 的 SSH 端口,如果是默认的 22 号端口,则可以不输入.
  • 总结
    • 该功能主要用于,无法被外部网络直接访问的主机,通过外部服务器(跳板机)进行访问,且实现端口转发等功能。

参考:https://zhuanlan.zhihu.com/p/112227542

https://www.cnblogs.com/bettersky/p/8588465.html