三条SSH命令实现Socks代理反弹突破内网

0x00 前言

这两天闲来无事,翻看ssh的man pages,发现ssh的DESCRIPTION最后有一句很不起眼的话X11 connections, arbitrary TCP ports and UNIX-domain sockets can also be forwarded over the secure channel. 意思就是可以做端口转发咯。再结合最近开会校园的网站只能从校园网或者连VPN才能访问,于是萌发了做一些事的想法。

1
2
3
4
DESCRIPTION
ssh (SSH client) is a program for logging into a remote machine and for executing commands on a remote machine. It is intended to provide secure
encrypted communications between two untrusted hosts over an insecure network. X11 connections, arbitrary TCP ports and UNIX-domain sockets can also
be forwarded over the secure channel.

0x01 环境

闭上双眼,思考了一下自己所处的环境。目前是我由于做一些项目,向学校申请到了校内的两台虚拟主机,校内主机自然可以访问所有学校的网站,而且也是可以连通外网的。除此之外我还有一台腾讯云的1元云主机,可以连外网,连不上校内网,打算用这台作为代理跳板机。环境大概像下面这样。
4

0x02 思考

想连上校内的网站,肯定要有一条和校内网的通路。可以开启一条SSH Tunnel来做到。数据可以经过加密在这条隧道来回穿梭。数据传过去还不行,我们需要访问到内网其他主机的资源,自然就需要一台类似于代理服务器的服务器。刚好SSH还有一个动态端口转发的功能,实则就是在SSH Server端实现了一个Socks的代理,然后再在本地做一个远程端口转发。于是利用远程端口转发+动态端口转发,理论上可以做到实现我不用VPN以及校园网访问校内网站的目的。

0x03 实现

未方便表达,以下内容中,校园内的虚拟服务器称为host2,腾讯云称为host1。

0x030 Step 1 建立Socks服务

先坐在寝室,连上VPN,登录host2。开启一个本地的动态端口转发,用它充当Socks代理。先看看介绍:

1
2
3
4
5
6
-D [bind_address:]<local_port> <SSH Server>
Specifies a local “dynamic” application-level port forwarding. This works by allocating a socket to listen to port on the local side, option‐
ally bound to the specified bind_address. Whenever a connection is made to this port, the connection is forwarded over the secure channel,
and the application protocol is then used to determine where to connect to from the remote machine. Currently the SOCKS4 and SOCKS5 protocols
are supported, and ssh will act as a SOCKS server. Only root can forward privileged ports. Dynamic port forwardings can also be specified in
the configuration file.

其中SSH Server填127.0.0.1,这样就可以实现本地动态端口转发,使得本地成为一个Socks代理。

1
$ ssh -Nf -D 7001 root@127.0.0.1

1
2
3
-N Do not execute a remote command. This is useful for just forwarding ports.
-f Requests ssh to go to background just before command execution. This is useful if ssh is going to ask for passwords or passphrases, but the
user wants it in the background.

这看起来很鸡肋,因为当浏览器设置localhost:7001为代理时,请求经过代理后却还是通过本地网卡发送出去,所以似乎没什么用。当然还没完。
值得一提的是,这样做了动态端口转发后的端口是暴露在公网上的,最起码同一网段的主机也可以配置使用这个代理。

0x031 Step 2 动态端口转发

继续在host2上操作,前面已经建立了一个本地的socks5代理服务,接着再建立一个远程端口转发,把本地的socks代理服务通过ssh tunnel发送到host1上。因为host2可以连上host1,而host1连不上host2,所以必须采用远程端口转发。关于远程端口转发与本地端口转发的区别,可以看这里

1
$ ssh -Nf -R 8888:127.0.0.1:7001 mads@123.206.176.*

这样就打通了host1与host2,并且在host1上可以通过本地的8888端口访问host2的socks代理服务。到这里似乎一切都完成了,但实际配置之后发现访问不了。原因是目前只能在host1的本地访问host2的socks代理,所以还需要在host1上做一个本地端口转发把8888端口对应的服务暴露到公网上。

0x032 Step 3 本地端口转发

在host1上做本地端口转发

1
$ ssh -Nfg -L 6666:localhost:8888 mads@127.0.0.1

1
2
-g Allows remote hosts to connect to local forwarded ports. If used on a multiplexed connection, then this option must be specified on the mas‐
ter process.

关键就是这个 -g 参数,从介绍可以知道他可以允许远程的主机访问本地转发的端口。
还有一个值得说的就是命令里面的localhost指的是相对于SSH Server,但这里都是host1。
这样所有工作完成。可以看下两台主机的网络端口连通情况:
1
可以看到host2上监听了7001端口的Socks服务,以及监听ssh tunnel的端口22。
2
host1上有本地端口转发监听的6666端口以及远程端口转发开启的用于连接host2的socks服务的8888端口。

这一套组合拳打下来,就实现了穿透内网的功能。如果ssh原本地动态端口转发叫做本地端口转发,那么我想叫这种方法为远程动态端口转发。

0x033 Step 4 验证

实验:
3
在Firefox的代理配置Socks5代理,注意其他的代理不要填,因为这就是个Socks5代理。访问校内某网址,成功访问,由于是校内主机,速度还挺快。相当于一个利用SSH搭建了一个Socks反弹代理。如果校园网开启了ipv6,还可以访问Google哦。

0x04 增强

以上步骤都没问题,但是SSH提供的远程端口转发会超时自动关闭,所以需要写一个守护进程。也可以用一个现成的autossh代替ssh实现就行了。

Reference

https://www.ibm.com/developerworks/cn/linux/l-cn-sshforward/