Search K
Appearance
Appearance
这篇文章我们来介绍 TCP RST 攻击以及如何在不干预通信双方进程的情况下杀掉一条 TCP 连接。
RST 攻击也称为伪造 TCP 重置报文攻击,通过伪造 RST 报文来关闭掉一个正常的连接。
源 IP 地址伪造非常容易,不容易被伪造的是序列号,RST 攻击最重要的一点就是构造的包的序列号要落在对方的滑动窗口内,否则这个 RST 包会被忽略掉,达不到攻击的效果。
下面我们用实验演示不在滑动窗口内的 RST 包会被忽略的情况,完整的代码见:rst_out_of_window.pkt
+0 < S 0:0(0) win 32792 <mss 1460>
+0 > S. 0:0(0) ack 1 <...>
+.1 < . 1:1(0) ack 1 win 65535
+0 accept(3, ..., ...) = 4
+.010 < R. 29202:29202(0) ack 1 win 65535
+.010 write(4, ..., 1000) = 1000
+0 > P. 1:1001(1000) ack 1 <...>执行上面的脚本,抓包的结果如下,完整的包见:rst_out_of_window.pcap

抓包文件中的第 5 个包可以看到,write 调用成功,1000 字节发送成功,write 调用并没有收到 RST 包的影响。
下面来介绍两个工具,利用 RST 攻击的方式来杀掉一条连接。
Centos 下安装 tcpkill 命令步骤如下
yum install epel-release -y
yum install dsniff -y实验步骤:
机器 c2(10.211.55.10) 启动 nc 命令监听 8080 端口,充当服务器端,记为 B
nc -l 8080机器 c2 启动 tcpdump 抓包
sudo tcpdump -i any port 8080 -nn -U -vvv -w test.pcap本地机器终端(10.211.55.2,记为 A)使用 nc 与 B 的 8080 端口建立 TCP 连接
nc c2 8080在服务端 B 机器上可以看到这条 TCP 连接
netstat -nat | grep -i 8080
tcp 0 0 10.211.55.10:8080 10.211.55.2:60086 ESTABLISHED启动 tcpkill
sudo tcpkill -i eth0 port 8080注意这个时候 tcp 连接依旧安然无恙,并没有被杀掉。
在本地机器终端 nc 命令行中随便输入一点什么,这里输入 hello,发现这时服务端和客户端的 nc 进程已经退出了
下面来分析抓包文件,这个文件可以从我的 github 下载 tcpkill.pcap

可以看到,tcpkill 假冒了 A 和 B 的 IP 发送了 RST 包给通信的双方,那问题来了,伪造 ip 很简单,它是怎么知道当前会话的序列号的呢?
tcpkill 的原理跟 tcpdump 差不多,会通过 libpcap 库抓取符合条件的包。因此只有有数据传输的 tcp 连接它才可以拿到当前会话的序列号,通过这个序列号伪造 IP 发送符合条件的 RST 包。
原理如下图所示

可以看到 tcpkill 对每个端发送了 3 个 RST 包,这是因为在高速数据传输的连接上,根据当前抓的包计算的序列号可能已经不再 TCP 连接的窗口内了,这种情况下 RST 包会被忽略,因此默认情况下 tcpkill 未雨绸缪往后计算了几个序列号。还可以指定参数 -n 指定更多的 RST 包,比如 tcpkill -9
根据上面的分析 tcpkill 的局限还是很明显的,无法杀掉一条僵死连接,下面我们介绍一个新的工具 killcx,看看它是如何来处理这种情况的。
killcx 是一个用 perl 写的在 linux 下可以关闭 TCP 连接的脚本,无论 TCP 连接处于什么状态。
下面来做一下实验,实验的前几步骤跟第一个例子中一模一样
机器 c2(10.211.55.10) 启动 nc 命令监听 8080 端口,充当服务器端,记为 B
nc -l 8080机器 c2 启动 tcpdump 抓包
sudo tcpdump -i any port 8080 -nn -U -vvv -w test.pcap本地机器终端(10.211.55.2,记为 A)使用 nc 与 B 的 8080 端口建立 TCP 连接
nc c2 8080在服务端 B 机器上可以看到这条 TCP 连接
netstat -nat | grep -i 8080
tcp 0 0 10.211.55.10:8080 10.211.55.2:61632 ESTABLISHED客户端 A nc 命令行随便输入什么,这一步也完全可以省略,这里输入 "hello\n"
执行 killcx 命令,注意 killcx 是在步骤 4 之后执行的
sudo ./killcx 10.211.55.2:61632可以看到服务端和客户端的 nc 进程已经退出了。
抓包的结果如下

前 5 个包都很正常,三次握手加上一次数据传输,有趣的事情从第 6 个包开始
整个过程如下图所示

这篇文章介绍了杀掉 TCP 连接的两个工具 tcpkill 和 killcx:
有大神把 tcpkill 源代码魔改了一下,让 tcpkill 也支持了杀掉非活跃连接,原理上就是结合了 killcx 杀掉连接的方式,模拟 SYN 包。有兴趣的读者可以好好读一下:如何干掉一条 tcp 连接(活跃/非活跃)- 阿里云开发者社区 (aliyun.com)