必须动用已有的知识去解释新知识
实验目的
通过 packetdrill 测试 TCP 基础之三次挥手,本次构造模拟的是服务器端场景。
基础脚本
基础脚本为 TCP 三次握手,构造模拟的是服务器端场景,相关脚本说明详见。
# cat tcp_3wh_000.pkt0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3+0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0+0 bind(3, ..., ...) = 0+0 listen(3, 1) = 0+0 < S 0:0(0) win 10000 <mss 1460>+0 > S. 0:0(0) ack 1 <...>+0.01 < . 1:1(0) ack 1 win 10000+0 accept(3, ..., ...) = 4
对于 TCP 三次挥手,实际上就是第二个 ACK 和第三个 FIN 数据包进行了合并。为什么第二个 ACK 会延迟发送,简单来说是在收到第一个 FIN 数据包后,接收端会进入 pingpong 模式,也就不满足 quickack 模式,综合判断下不会立马发送 ACK ,最终就会 Delayed ACK,和之后的第三个 FIN 数据包一并发送。
和 TCP 四次挥手一样,首先发起 FIN 的可以是客户端,也可以是服务器端,以下分别模拟相关两种场景。
客户端测试
首先模拟客户端先注入 FIN 数据包,观察服务器端协议栈响应。
# cat tcp_3wh_001.pkt0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3+0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0+0 bind(3, ..., ...) = 0+0 listen(3, 1) = 0+0 < S 0:0(0) win 10000 <mss 1460>+0 > S. 0:0(0) ack 1 <...>+0.01 < . 1:1(0) ack 1 win 10000+0 accept(3, ..., ...) = 4+0.1 < F. 1:1(0) ack 1 win 10000#
由于脚本最后的语句仅是注入 FIN ,所以脚本一执行完后就结束了,而 tcpdump 捕获数据包时未看到明显的服务器端响应,相关数据包说明如下。
# packetdrill cat tcp_3wh_001.pkt## tcpdump -i any -nn port 8080tcpdump: data link type LINUX_SLL2tcpdump: verbose output suppressed, use -v[v]... for full protocol decodelistening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes22:50:50.514327 tun0 In IP 192.0.2.1.42457 > 192.168.29.218.8080: Flags [S], seq 0, win 10000, options [mss 1460], length 022:50:50.514355 tun0 Out IP 192.168.29.218.8080 > 192.0.2.1.42457: Flags [S.], seq 3091907294, ack 1, win 64240, options [mss 1460], length 022:50:50.524445 tun0 In IP 192.0.2.1.42457 > 192.168.29.218.8080: Flags [.], ack 1, win 10000, length 022:50:50.624530 tun0 In IP 192.0.2.1.42457 > 192.168.29.218.8080: Flags [F.], seq 1, ack 1, win 10000, length 022:50:50.624613 tun0 Out IP 192.168.29.218.8080 > 192.0.2.1.42457: Flags [F.], seq 1, ack 2, win 64239, length 022:50:50.624632 tun0 In IP 192.0.2.1.42457 > 192.168.29.218.8080: Flags [R.], seq 2, ack 1, win 10000, length 0#1. 前三个数据包为 TCP 三次握手数据包,略过。2. 第四个数据包为模拟注入的客户端 FIN 数据包。22:50:50.624530 tun0 In IP 192.0.2.1.42457 > 192.168.29.218.8080: Flags [F.], seq 1, ack 1, win 10000, length 0// 对应于脚本 +0.1 < F. 1:1(0) ack 1 win 10000 ,与之前间隔 100ms 后 < 输入数据包,packetdrill 根据此行脚本各字段值构造的 FIN 数据包,注入到内核协议栈。3. 最后两个数据包 FIN/ACK 和 RST/ACK22:50:50.624613 tun0 Out IP 192.168.29.218.8080 > 192.0.2.1.42457: Flags [F.], seq 1, ack 2, win 64239, length 022:50:50.624632 tun0 In IP 192.0.2.1.42457 > 192.168.29.218.8080: Flags [R.], seq 2, ack 1, win 10000, length 0// packetdrill 脚本之外产生的数据包,或者说预期之外的数据包。// 根据个人判断,在 packetdrill 脚本执行完毕后,socket 被强行关闭,如果有accept()的情况下,内核会发送 FIN/ACK 结束连接,没有accept()的情况下,则不会发送 FIN/ACK.// 最后一个为客户端所发送的 RST/ACK 结束连接,也像是 packetdrill 脚本默认构造,用于快速重置连接使用的。// 因此这两个数据包一般与 packetdrill 构建的测试脚本无关,分析时可省略。
在以上脚本最后增加 sleep 语句,使得脚本执行完不要退出。
# cat tcp_3wh_001.pkt0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3+0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0+0 bind(3, ..., ...) = 0+0 listen(3, 1) = 0+0 < S 0:0(0) win 10000 <mss 1460>+0 > S. 0:0(0) ack 1 <...>+0.01 < . 1:1(0) ack 1 win 10000+0 accept(3, ..., ...) = 4+0.1 < F. 1:1(0) ack 1 win 10000+0 `sleep 100`#
如下测试后,可观察到在客户端注入 FIN 数据包后,服务器端响应了 ACK 数据包。
注意,服务器端仅仅是响应了 ACK ,是因为这里并没有模拟调用 close(),所以就没有后续第三个 FIN 数据包的发送。
# packetdrill tcp_3wh_001.pkt脚本执行完后未退出,可见光标闪烁。# tcpdump -i any -nn port 8080tcpdump: data link type LINUX_SLL2tcpdump: verbose output suppressed, use -v[v]... for full protocol decodelistening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes12:50:27.494334 tun0 In IP 192.0.2.1.34499 > 192.168.38.155.8080: Flags [S], seq 0, win 10000, options [mss 1460], length 012:50:27.494361 tun0 Out IP 192.168.38.155.8080 > 192.0.2.1.34499: Flags [S.], seq 346908529, ack 1, win 64240, options [mss 1460], length 012:50:27.504436 tun0 In IP 192.0.2.1.34499 > 192.168.38.155.8080: Flags [.], ack 1, win 10000, length 012:50:27.604513 tun0 In IP 192.0.2.1.34499 > 192.168.38.155.8080: Flags [F.], seq 1, ack 1, win 10000, length 012:50:27.610030 tun0 Out IP 192.168.38.155.8080 > 192.0.2.1.34499: Flags [.], ack 2, win 64239, length 0#通过 ss 查询 TCP 连接状态为 CLOSE-WAIT。# ss -anto | grep 8080CLOSE-WAIT 1 0 192.168.210.130:8080 192.0.2.1:60155#之后通过 CTRL+C 可终止脚本运行,如下:# packetdrill tcp_3wh_001.pkt^Ctcp_3wh_001.pkt:13: error executing `sleep 100` command: got signal 2 (Interrupt)#再次通过 ss 查询 TCP 连接状态已经变成 LAST-ACK。# ss -anto | grep 8080LAST-ACK 1 1 192.168.210.130:8080 192.0.2.1:60155 timer:(on,348ms,3)#抓包结果如下,仅出现一个服务器发送的 FIN 数据包,与上面的 TCP 连接 LAST-ACK 对应。12:50:30.414159 ? Out IP 192.168.38.155.8080 > 192.0.2.1.34499: Flags [F.], seq 1, ack 2, win 64239, length 0
最后脚本增加服务器端 close 发送 FIN ,完成 TCP 三次挥手完整过程。
# cat tcp_3wh_002.pkt0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3+0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0+0 bind(3, ..., ...) = 0+0 listen(3, 1) = 0+0 < S 0:0(0) win 10000 <mss 1460>+0 > S. 0:0(0) ack 1 <...>+0.01 < . 1:1(0) ack 1 win 10000+0 accept(3, ..., ...) = 4+0.1 < F. 1:1(0) ack 1 win 10000+0 close(4) = 0+0 > F. 1:1(0) ack 2+0.01 < . 2:2(0) ack 2 win 10000#
# packetdrill tcp_3wh_002.pkt## tcpdump -i any -nn port 8080tcpdump: data link type LINUX_SLL2tcpdump: verbose output suppressed, use -v[v]... for full protocol decodelistening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes22:02:28.319674 tun0 In IP 192.0.2.1.46827 > 192.168.233.140.8080: Flags [S], seq 0, win 10000, options [mss 1460], length 022:02:28.319707 tun0 Out IP 192.168.233.140.8080 > 192.0.2.1.46827: Flags [S.], seq 3459722375, ack 1, win 65535, options [mss 1460], length 022:02:28.329813 tun0 In IP 192.0.2.1.46827 > 192.168.233.140.8080: Flags [.], ack 1, win 10000, length 022:02:28.429878 ? In IP 192.0.2.1.46827 > 192.168.233.140.8080: Flags [F.], seq 1, ack 1, win 10000, length 022:02:28.429915 ? Out IP 192.168.233.140.8080 > 192.0.2.1.46827: Flags [F.], seq 1, ack 2, win 65535, length 022:02:28.439993 ? In IP 192.0.2.1.46827 > 192.168.233.140.8080: Flags [.], ack 2, win 10000, length 022:02:28.440096 ? In IP 192.0.2.1.46827 > 192.168.233.140.8080: Flags [R.], seq 2, ack 2, win 10000, length 0#
服务器端测试
通过 close ,服务器端先发送 FIN 数据包,之后注入客户端 FIN 数据包,最后完成服务器端 ACK 。
# cat tcp_3wh_003.pkt0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3+0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0+0 bind(3, ..., ...) = 0+0 listen(3, 1) = 0+0 < S 0:0(0) win 10000 <mss 1460>+0 > S. 0:0(0) ack 1 <...>+0.01 < . 1:1(0) ack 1 win 10000+0 accept(3, ..., ...) = 4+0 close(4) = 0+0 > F. 1:1(0) ack 1+0.01 < F. 1:1(0) ack 2 win 10000+0 > . 2:2(0) ack 2 <..å.>#
执行脚本,并通过 tcpdump 捕获数据包,可观察到 TCP 三次挥手完整过程。
# packetdrill tcp_3wh_003.pkt## tcpdump -i any -nn port 8080tcpdump: data link type LINUX_SLL2tcpdump: verbose output suppressed, use -v[v]... for full protocol decodelistening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes22:05:45.899665 tun0 In IP 192.0.2.1.51661 > 192.168.18.58.8080: Flags [S], seq 0, win 10000, options [mss 1460], length 022:05:45.899693 tun0 Out IP 192.168.18.58.8080 > 192.0.2.1.51661: Flags [S.], seq 2001050617, ack 1, win 65535, options [mss 1460], length 022:05:45.909805 tun0 In IP 192.0.2.1.51661 > 192.168.18.58.8080: Flags [.], ack 1, win 10000, length 022:05:45.909913 tun0 Out IP 192.168.18.58.8080 > 192.0.2.1.51661: Flags [F.], seq 1, ack 1, win 65535, length 022:05:45.920001 tun0 In IP 192.0.2.1.51661 > 192.168.18.58.8080: Flags [F.], seq 1, ack 2, win 10000, length 022:05:45.920031 tun0 Out IP 192.168.18.58.8080 > 192.0.2.1.51661: Flags [.], ack 2, win 65535, length 022:05:45.920164 tun0 In IP 192.0.2.1.51661 > 192.168.18.58.8080: Flags [R.], seq 2, ack 2, win 10000, length 0#1. 前三个数据包为 TCP 三次握手数据包,略过。2. 第四个数据包为服务器 close 所发出的 FIN 数据包。22:05:45.909913 tun0 Out IP 192.168.18.58.8080 > 192.0.2.1.51661: Flags [F.], seq 1, ack 1, win 65535, length 0// 对应于脚本 +0 > F. 1:1(0) ack 1 ,close 关闭连接,预期服务器协议栈发出 FIN 。3. 第五个数据包为注入的客户端 FIN 数据包。22:05:45.920001 tun0 In IP 192.0.2.1.51661 > 192.168.18.58.8080: Flags [F.], seq 1, ack 2, win 10000, length 0// 对应于脚本 +0.01 < F. 1:1(0) ack 2 win 10000 ,为客户端关闭连接所发送的 FIN,此处模拟合并了第二个 ACK 。4. 第六个数据包为服务器的 ACK 数据包。22:05:45.920031 tun0 Out IP 192.168.18.58.8080 > 192.0.2.1.51661: Flags [.], ack 2, win 65535, length 0// 对应于脚本 +0 > . 2:2(0) ack 2 <...>,预期服务器收到客户端的 FIN 所发送的 ACK 确认。5. 最后一个数据包 RST/ACK22:05:45.920164 tun0 In IP 192.0.2.1.51661 > 192.168.18.58.8080: Flags [R.], seq 2, ack 2, win 10000, length 0// packetdrill 脚本之外产生的数据包,或者说预期之外的数据包。// 客户端所发送的 RST/ACK 结束连接,如前所述是 packetdrill 脚本默认构造,用于快速重置连接使用的。// 因此这个数据包一般与 packetdrill 构建的测试脚本无关,分析时可省略。
往期推荐
推荐站内搜索:最好用的开发软件、免费开源系统、渗透测试工具云盘下载、最新渗透测试资料、最新黑客工具下载……




还没有评论,来说两句吧...