ESTABLISHED状态的连接收到 SYN 会回复什么?( 二 )

再次使用 scapy 发送一个 syn 包 , 内核同样会回复 ACK , 此时 stap 输出结果如下 。
send ack : 10.211.55.10:9090:->10.211.55.20:50718 0xffffffff815d0940 : tcp_send_ack+0x0/0x170 [kernel] 0xffffffff815cb1d2 : tcp_validate_incoming+0x212/0x2d0 [kernel] 0xffffffff815cb44d : tcp_rcv_established+0x1bd/0x760 [kernel] 0xffffffff815d5f8a : tcp_v4_do_rcv+0x10a/0x340 [kernel] 0xffffffff815d76d9 : tcp_v4_rcv+0x799/0x9a0 [kernel] 0xffffffff815b1094 : ip_local_deliver_finish+0xb4/0x1f0 [kernel] 0xffffffff815b1379 : ip_local_deliver+0x59/0xd0 [kernel] 0xffffffff815b0d1a : ip_rcv_finish+0x8a/0x350 [kernel] 0xffffffff815b16a6 : ip_rcv+0x2b6/0x410 [kernel]可以看到这个 ACK 经过了下面这些函数调用 。
tcp_v4_rcv-> tcp_v4_do_rcv-> tcp_rcv_established-> tcp_validate_incoming-> tcp_send_acktcp_validate_incoming 函数精简后的部分代码如下所示 。
static bool tcp_validate_incoming(struct sock *sk, struct sk_buff *skb,const struct tcphdr *th){// seq 不在窗口内 /* Step 1: check sequence number */ if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq)) {// RST 标记没有设置if (!th->rst) {if (th->syn)goto syn_challenge;}goto discard; }/* step 4: Check for a SYN 。RFC 5961 4.2 : Send a challenge ack */ if (th->syn) {syn_challenge: // 处理 SYN Challenge 的情况tcp_send_challenge_ack(sk, skb); //goto discard; 复制代码tcp_send_challenge_ack 函数真正调用了 tcp_send_ack 函数 。这里的注释提到了 RFC 5961 4.2 , 说的正是 Challenge ACK 相关的内容 。
如果攻击者疯狂发送假的乱序包 , 接收端也跟着回复 Challenge ACK , 会耗费大量的 CPU 和带宽资源 。 于是 RFC 5961 提出了 ACK Throttling 方案 , 限制了每秒钟发送 Challenge ACK 报文的数量 , 这个值由 net.ipv4.tcp_challenge_ack_limit 系统变量决定 , 默认值是 1000 , 也就是 1s 内最多允许 1000 个 Challenge ACK 报文 。
接下来使用 sysctl 将这个值改小为 1 , 如下所示 。
sudo sysctl -w net.ipv4.tcp_challenge_ack_limit="1"这样理论上在一秒内多次发送一个 Challenge ACK 包 , 接下来使用 scapy 在短时间内发送 5 次 SYN 包 , 看看内核是否只会回复一个 ACK 包 , scapy 的脚本如下所示 。
send(IP(dst="10.211.55.10")/TCP(sport=50718,dport=9090,seq=10,flags='S'), loop=0, count=5)tcpdump 抓包结果如下 。
03:40:30.970682 IP 10.211.55.20.50718 > 10.211.55.10.9090: Flags [S], seq 10, win 8192, length 003:40:30.970771 IP 10.211.55.10.9090 > 10.211.55.20.50718: Flags [.], ack 3219267426, win 227, options [nop,nop,TS val 45146923 ecr 1094540820], length 003:40:30.974889 IP 10.211.55.20.50718 > 10.211.55.10.9090: Flags [S], seq 10, win 8192, length 003:40:30.975004 IP 10.211.55.20.50718 > 10.211.55.10.9090: Flags [S], seq 10, win 8192, length 003:40:30.978643 IP 10.211.55.20.50718 > 10.211.55.10.9090: Flags [S], seq 10, win 8192, length 003:40:30.981987 IP 10.211.55.20.50718 > 10.211.55.10.9090: Flags [S], seq 10, win 8192, length 0可以看到确实是只对第一个 SYN 包回复了一个 ACK 包 , 其它的四个 SYN 都没有回复 ACK 。
RST 攻击RST 攻击也称为伪造 TCP 重置报文攻击 , 通过伪造 RST 报文来关闭掉一个正常的连接 。
源 IP 地址伪造非常容易 , 不容易被伪造的是序列号 , RST 攻击最重要的一点就是构造的包的序列号要落在对方的滑动窗口内 , 否则这个 RST 包会被忽略掉 , 达不到攻击的效果 。
下面我们用实验演示不在滑动窗口内的 RST 包会被忽略的情况 , 完整的代码见:rst_out_of_window.pkt
+0 < S 0:0(0) win 32792 +0 > S. 0:0(0) ack 1 <...>+.1 < . 1:1(0) ack 1 win 65535 +0 accept(3, ..., ...) = 4// 不在窗口内的 RST+.010 < R. 29202:29202(0) ack 1 win 65535// 如果上面的 RST 包落在窗口内 , 连接会被重置 , 下面的写入不会成功+.010 write(4, ..., 1000) = 1000 // 断言服务端会发出下面的数据包+0 > P. 1:1001(1000) ack 1 <...>【ESTABLISHED状态的连接收到 SYN 会回复什么?】执行上面的脚本 , 抓包的结果如下 , 完整的包见:rst_out_of_window.pcap
ESTABLISHED状态的连接收到 SYN 会回复什么?文章插图
抓包文件中的第 5 个包可以看到 , write 调用成功 , 1000 字节发送成功 , write 调用并没有收到 RST 包的影响 。
下面来介绍两个工具 , 利用 RST 攻击的方式来杀掉一条连接 。
工具一:tcpkill 工具使用及原理介绍Centos 下安装 tcpkill 命令步骤如下
yum install epel-release -yyum install dsniff -y实验步骤: 1、机器 c2(10.211.55.10) 启动 nc 命令监听 8080 端口 , 充当服务器端 , 记为 B
nc -l 80802、机器 c2 启动 tcpdump 抓包
sudo tcpdump -i any port 8080 -nn -U -vvv -w test.pcap