VLab-实验室
在后渗透场景中,代理几乎是不可或缺的一部分,对于多层网络架构的复杂内网环境而言,多级代理、多协议代理、端口复用等代理功能便尤为重要,本文将分以下几个部分逐步介绍:
1.常见代理的方式
2.代理端口复用研究
3.基于已有服务的端口复用方式
反向代理
反向代理(Reverse Proxy)指的是由目标服务器主动像客户端发起连接请求的代理模式,这种代理模式通常是攻防实战中完成边界突破后的代理方式的优选项,稳定性相对更佳。缺点是服务器需要具备出网能力,在流量侧会有主动外连的痕迹,如果使用的代理工具存在流量侧特征容易被态势感知等设备发现。列举几个反代工具:
1、frp
https://github.com/fatedier/frp.git
2、earthworm
https://github.com/idlefire/ew.git
3、ngrok
https://github.com/inconshreveable/ngrok.git
4、nps
https://github.com/ehang-io/nps
5、erfrp
https://github.com/Goqi/Erfrp
正向代理
正向代理(Forward Proxy)是指由客户端向代理服务器发起请求,并由代理服务器向目标转发的代理方式,这种代理模式是科学上网常用的代理方式。在攻防实战中,由于目标主机服务器通常在内网环境,服务由例如nginx等服务将服务端口代理映射出去,因此在服务上主动创建的代理监听服务很难通过公网访问到。通常做法是复用web服务,通过对应的开发语言写代理的服务,再通过正向代理实现连接,这种方式通常稳定性和速度相对较差,通常在服务器无法出网的情况下选择。列举两个webProxy:
1、reGeorg
https://github.com/sensepost/reGeorg.git
2、Neo-reGeorg
https://github.com/L-codes/Neo-reGeorg
正向代理
// 创建监听
反向代理
func Server(listen *net.TCPListener, s5listen *net.TCPListener) {
端口复用,也被称为端口共享,是指在同一台主机上,允许多个网络应用程序使用同一个网络端口的技术。这种技术可以有效地提高网络资源的利用率,避免端口资源的浪费。在网络安全场景下的端口复用主要目的是为了隐藏攻击痕迹和进行防火墙bypass。
使用场景通常为防火墙限制了访问端口。通过系统的流量转发功能实现,Linux下通过iptables实现流量转发。假设原本服务器开放了80端口,我们要将eth0网卡的80端口流量全部转发到本地代理监听端口8080。
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080
再由监听的代理服务做流量分流处理,将带有代理特征的流量保留下来,目标流量发送回对应服务,保证原本服务正常进行。比如如果我们劫持转发的服务为web服务,而我们的代理协议使用的是socks5协议,我们可以通过协议头进行判断和过滤。
package main
对于windows而言,非系统服务,比如重定向 Windows 上的 Apache 的 8080 端口到 1080 端口,我们可以使用 IpNat 进行转发。
# 转发命令
对于系统服务,需要重启系统或加载驱动,并且需要自己编写 Ring3 的部分代码来通过驱动回调增加过滤的条件等。本文不展开讨论这种方式。比较流行的方式有基于 WFP 实现的 WIndiver 以及基于 NDIS 的 WinpkFilter,可以参考https://github.com/BarbaTunnelCoder/BarbaTunnel/wiki/Choosing-FilterDriver-(WinDivert-vs-WinpkFilter)
ShadowMove是一种从non-cooperative进程中劫持Socket的技术,2020年发布于USENIX大《ShadowMove: A Stealthy Lateral Movement Strategy》,ShadowMove的基本思想是复用已建立的合法连接,从而在受感染的网络内横向移动。如上图所示,ShadowMove的工作分为三个主要步骤:首先,它复制合法客户端应用程序用来与服务器应用程序通信的套接字。其次,它使用复制的套接字在客户端和服务器之间的现有TCP会话中注入数据包。第三,服务器处理注入的数据包,并无意中保存和/或启动ShadowMove的新实例。通过以上步骤,攻击者会从客户端计算机秘密移动到服务器计算机。
具体实现步骤:
使用PROCESS_DUP_HANDLE权限打开所有者进程;
每一个句柄为0x24(文件)类型;
遍历句柄,找到\device\afd
getpeername() 获取远程IP和远程端口号;
调用WSADuplicateSocketW以获取特殊的WSAPROTOCOL_INFO结构;
创建重复的Socket;
使用这个Socket;
实现代理能力,需要跳板服务器我们可控一个合法进行外连我们的主机。假设三台主机A,B,C 其中A可以访问B的某些特定公开服务,B可以访问C。我们想在A上通过B访问C的服务,只需要通过B创建一个与C的目标的连接,并将两个socket通信数据进行io copy,则可以完成代理逻辑的实现。
引用ShadowMove套接字劫持技术,巧妙隐藏与C2的连接一文中的代码实现;
/* PoC of ShadowMove Pivot by Juan Manuel Fernández (@TheXC3LL) */
当然上述的使用仅能针对一个服务实现定向转发,我们也可以使用反代逻辑在接收到来自A的请求后解析目标请求的地址再构建socket连接并发送请求到目标主机。
当我们使用ShadowMove套接字劫持技术实现端口复用时,也面临一些问题:
1、socket数据存在同时被原始进程和代理进程消费的情况,一旦数据被原始进程消费后,代理进程将无法读到数据导致数据丢失。此时需要自定义数据完整性的验证逻辑。
2、socket被关闭导致超时,需要检测socket的状态。
在linux和windows中一个端口一旦被bind,那么另一个端口再去尝试bind时会报错already in use。在一定条件下也可以实现端口复用,实际在3.9版本之前,linux通过SO_REUSEADDR实现了处于TIME_WAIT状态的socket的端口实现复用绑定,但是实际生效也需要在当前socket完全释放后。
在内核版本3.9以上,引入了SO_REUSEPORT特性,该特性允许配置了SO_REUSEPORT的进程监听同一端口,但要求第一个监听该端口的进程必须进行相应配置,否则后续监听仍将失败。
当我们找到满足上述要求的合法进程后,面临有多个进程都 bind 和 listen 了同一个端口的时候。有客户端连接请求到来的时候就涉及到选择哪个 socket(进程)进行处理的问题。我们再简单看一下,响应连接时的处理过程。
查找 listen 状态的 socket 的时候需要查找该哈希表。我们进入响应握手请求的时候进入的一个关键函数 __inet_lookup_listener 来看。
//file: net/ipv4/inet_hashtables.c
其中 sk_nulls_for_each_rcu 是在遍历所有 hash 值相同的 listen 状态的 socket。注意看 compute_score 这个函数,这里是计算匹配分。当有多个 socket 都命中的时候,匹配分高的优先命中。我们来看一下这个函数里的一个细节。
//file: net/ipv4/inet_hashtables.c
demo如下:
A 进程:./test-server 10.0.0.2 6000
B 进程:./test-server 0.0.0.0 6000
C 进程:./test-server 127.0.0.1 6000
此时A、C进程的绑定方式为4分,B为2分,因此当目标主动访问10.0.0.2网卡时,将由进程A消费。假设主机还有一个192.0.0.2的网卡地址,当访问这个地址时,A C均不得分,B得2分,此时没有更高分数的情况下将由B完成消费。
那么假如存在如下情况:
A 进程:./test-server 10.0.0.2 6000
B 进程:./test-server 0.0.0.0 6000
C 进程:./test-server 10.0.0.2 6000
此时A C均绑定的10.0.0.2网卡,当有请求访问时,就由内核以随机的方式进行负载均衡随机分配到A C进程中了。
当我们使用两个不同权限用户绑定相同端口时,则会绑定失败。因此上述方法对权限有要求。
总结一下,如果想完美使用SO_REUSEPORT特性实施端口复用,需要找到一个开启了SO_REUSEPORT配置的合法进程,且该进程监听0.0.0.0,并且处于同一用户权限下。
在macOS中,默认允许多个进程可以绑定到相同的端口,而无需特殊配置,当有传入连接到达时,操作系统会根据某种负载均衡算法将连接分发给其中一个进程。因此可以跳过SO_REUSEPORT配置,快进到调度优先级配置部分。例如两个进程A、B,同时监听8888端口,其中A绑定10.10.1.2,B绑定0.0.0.0,将优先调度A的socket进行通信。
复用合法应用的端口我们需通过netstat查找绑定在0.0.0.0的端口服务,然后启用代理,做流量分析,符合代理特征的流量我们留下解析,属于源端口的流量我们转发到源端口,实现方式跟通过iptables同理。
// 端口监听相关代码片段
上文主要对基于端口限制的代理端口复用方式进行分析,还有一种场景是基于协议限制的策略,这种场景下假设我们可以通过某种方式访问到代理端口,此时我们的代理需要在监听接收到的连接请求进行协议分析,根据不同协议调用不同的handler处理逻辑,实现绕过(针对TCP/IP层以上的通信协议)。
package main
此时我们就完成了在同一个代理进程中使用不同代理协议的端口复用实现。
· https://www.freebuf.com/articles/web/261429.html
· https://saucer-man.com/operation\_and\_maintenance/586.html
· https://idiotc4t.com/defense-evasion/shadowmove-emersion-and-think
· https://www.usenix.org/system/files/sec20summer\_niakanlahiji\_prepub.pdf
往期回顾
引领智能网络攻防科技
点击在看
分享给小伙伴
↓↓点击阅读原文,了解更多墨云信息