1 基础环境准备
1.1 Pull Docker 镜像
sudo docker pull alpine:3.8
1.2 运行容器
$ sudo docker run -d --name ctn-1 alpine:3.8 sleep 3600d$ sudo docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES233bc36bde4b alpine:3.8 "sleep 3600d" 1 minutes ago Up 14 minutes ctn-1
$ sudo docker exec -it ctn-1 sh
# ifconfigeth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:09 inet addr:172.17.0.9 Bcast:0.0.0.0 Mask:255.255.0.0
1.3 安装 tcpdump
/ # apk update
/ # apk add tcpdump
2 HTTP/TCP 抓包
2.1 HTTP 请求:下载测试页面
/ # wget http://example.comConnecting to example.com (93.184.216.34:80)index.html 100% |*****************************| 1270 0:00:00 ETA
-
域名查找:通过访问 DNS 服务查找 example.com 服务器对应的 IP 地址 -
TCP 连接参数初始化:临时端口、初始序列号的选择等等 -
客户端(容器)通过 TCP 三次握手协议和服务器 IP 建立 TCP 连接 -
客户端发起 HTTP GET 请求 -
服务器返回 HTTP 响应,包含页面数据传输 -
如果页面超过一个 MTU,会分为多个 packet 进行传输(后面会看到,确实超过 MTU 了) -
TCP 断开连接的四次挥手
2.2 抓包:打到标准输出
wget http://example.com
,能看到如下类 似的输出。为了方便后面的讨论,这里将一些字段去掉了,并做了适当的对齐:/ # tcpdump -n -S -i eth0 host example.com1 02:52:44.513700 IP 172.17.0.9.41038 > 93.184.216.34.80: Flags [S] , seq 3310420140, length 02 02:52:44.692890 IP 93.184.216.34.80 > 172.17.0.9.41038: Flags [S.], seq 1353235534, ack 3310420141, length 03 02:52:44.692953 IP 172.17.0.9.41038 > 93.184.216.34.80: Flags [.] , ack 1353235535, length 04 02:52:44.693009 IP 172.17.0.9.41038 > 93.184.216.34.80: Flags [P.], seq 3310420141:3310420215, ack 1353235535, length 74: HTTP: GET / HTTP/1.15 02:52:44.872266 IP 93.184.216.34.80 > 172.17.0.9.41038: Flags [.] , ack 3310420215, length 06 02:52:44.873342 IP 93.184.216.34.80 > 172.17.0.9.41038: Flags [.] , seq 1353235535:1353236983, ack 3310420215, length 1448: HTTP: HTTP/1.1 200 OK7 02:52:44.873405 IP 172.17.0.9.41038 > 93.184.216.34.80: Flags [.] , ack 1353236983, length 08 02:52:44.874533 IP 93.184.216.34.80 > 172.17.0.9.41038: Flags [P.], seq 1353236983:1353237162, ack 3310420215, length 179: HTTP9 02:52:44.874560 IP 172.17.0.9.41038 > 93.184.216.34.80: Flags [.] , ack 1353237162, length 010 02:52:44.874705 IP 172.17.0.9.41038 > 93.184.216.34.80: Flags [F.], seq 3310420215, ack 1353237162, length 011 02:52:45.053732 IP 93.184.216.34.80 > 172.17.0.9.41038: Flags [.] , ack 3310420216, length 012 02:52:45.607825 IP 93.184.216.34.80 > 172.17.0.9.41038: Flags [F.], seq 1353237162, ack 3310420216, length 013 02:52:45.607869 IP 172.17.0.9.41038 > 93.184.216.34.80: Flags [.] , ack 1353237163, length 0
-
-n
:打印 IP 而不是 hostname,打印端口号而不是协议(例如打印 80 而不是 http) -
-S
:打印绝对时间戳 -
-i eth0
:指定从 eth0 网卡抓包 -
host example.com
:抓和 example.com 通信的包(双向)
2.3 抓包:存文件
-w
命令可以将抓到的包写到文件,注意这和用重定向方式将输出写到文件是不同的。后者写的只是标准输出打印的 LOG,而 -w
写的是原始包。/ # tcpdump -i eth0 host example.com -w example.pcap
^C
13 packets captured
13 packets received by filter
0 packets dropped by kernel
tcpdump
或者 wireshark
之类的网络流量分析工具打开。3 流量分析:tcpdump
3.1 每列说明
-
packet 时间戳,例如 02:52:44.513700
表示抓到这个包的时间是** 02 时 52 分 44 秒 513 毫秒** -
packet 类型,这里是 IP
包 -
源 (SRC) IP 和端口,目的 (DST) IP 和端口 -
packet TCP flags,其中 -
S
表示syn
包 -
.
表示ack
包 -
F
表示fin
包 -
P
表示push
包(发送正常数据) -
序列号(seq) -
应答号(ack) -
包的 payload 长度 -
包的部分内容(ASCII)
3.2 三次握手(1~3)
-
client -> server: SYN -
server -> client: SYN+ACK -
client -> server: ACK
1 02:52:44.513700 IP 172.17.0.9.41038 > 93.184.216.34.80: Flags [S] , seq 3310420140, length 0
2 02:52:44.692890 IP 93.184.216.34.80 > 172.17.0.9.41038: Flags [S.], seq 1353235534, ack 3310420141, length 0
3 02:52:44.692953 IP 172.17.0.9.41038 > 93.184.216.34.80: Flags [.] , ack 1353235535, length 0
#1
包含以下信息:-
02:52:44.513700 时刻,客户端主动向 server(93.184.216.34)发起一个 SYN 请求,请求建立连接 -
客户端请求的服务端端口是 80(HTTP 服务默认 80 端口),客户端使用的是临时端口(大于 1024)41038 -
#1
序列号是 3310420140,这是客户端的初始序列号(客户端和服务端分别维护自己的序列号,两者没有关系;另外,初始序列号是系统选择的,一般不是 0) -
#1
length 为 0,因为 SYN 包不带 TCP payload,所有信息都在 TCP header
#2
的 ack 是 3310420140
,等于 #1
的 seq 加 1,这就说明,#2
是 #1
的应答包。-
TCP flags 为 S.
,即 SYN+ACK -
length 也是 0,说明没有 payload -
seq 为 1353235534
,这是服务端的初始序列号 -
到达 eth0 的时间为 02:52:44.692890
,说明时间过了18ms
#3
的 ack 等于 #2
的 seq 加 1,说明 #3
是 #2
的应答包。-
TCP flags 为 .
,即 ACK -
长度为 0,说明没有 TCP payload
3.3 正常数据传输
4 02:52:44.693009 IP 172.17.0.9.41038 > 93.184.216.34.80: Flags [P.], seq 3310420141:3310420215, ack 1353235535, length 74: HTTP: GET / HTTP/1.15 02:52:44.872266 IP 93.184.216.34.80 > 172.17.0.9.41038: Flags [.] , ack 3310420215, length 06 02:52:44.873342 IP 93.184.216.34.80 > 172.17.0.9.41038: Flags [.] , seq 1353235535:1353236983, ack 3310420215, length 1448: HTTP: HTTP/1.1 200 OK7 02:52:44.873405 IP 172.17.0.9.41038 > 93.184.216.34.80: Flags [.] , ack 1353236983, length 08 02:52:44.874533 IP 93.184.216.34.80 > 172.17.0.9.41038: Flags [P.], seq 1353236983:1353237162, ack 3310420215, length 179: HTTP9 02:52:44.874560 IP 172.17.0.9.41038 > 93.184.216.34.80: Flags [.] , ack 1353237162, length 0
-
#4
: client 向 server 发起 HTTP GET 请求,请求路径为根路径(/),这个 packet 长度为 74 字节 -
#5
: 发送了 ACK 包,对#4
进行确认 -
#6
: 发送了 1448 字节的数据给 client -
#7
: client 对 server 的#6
进行应答 -
#8
: server 向 client 端继续发送 179 字节数据 -
#9
: client 对 server 的#8
进行应答
3.4 四次挥手
-
client -> server: FIN (我们看到的是 FIN+ACK,这是因为这个 FIN 包除了正常的关闭连接功能之外,还被用于应答 client 发过来的前一个包) -
server -> client: ACK -
server -> client: FIN+ACK -
client -> server: ACK
10 02:52:44.874705 IP 172.17.0.9.41038 > 93.184.216.34.80: Flags [F.], seq 3310420215, ack 1353237162, length 011 02:52:45.053732 IP 93.184.216.34.80 > 172.17.0.9.41038: Flags [.] , ack 3310420216, length 012 02:52:45.607825 IP 93.184.216.34.80 > 172.17.0.9.41038: Flags [F.], seq 1353237162, ack 3310420216, length 013 02:52:45.607869 IP 172.17.0.9.41038 > 93.184.216.34.80: Flags [.] , ack 1353237163, length 0
4 流量分析:wireshark
-r
读取 pcap 文件,并以指定的格式输出包的信息,最后输出的内容 和上面看到的类似。我们上面的流量非常简单,所以看 tcpdump 的输出就够了。4.1 追踪 TCP 流
-
#1
在08:00:05.125
发送出去,请求建立连接 -
大约 1s
后,客户端仍然没有收到服务端的 ACK 包,触发客户端 TCP 超时重传 -
又过了大约 2s
,仍然没有收到 ACK 包,再次触发超时重传 -
这里其实还可以看出 TCP 重传的机制:指数后退,比如第一次等待 1s,第二次等 待 2s,第三次等待 4s,第四次 8s
4.2 过滤流
tcp.stream eq 1
,这其实就是其强大的过滤表达式。-
ip.addr == 192.168.1.1
过滤 SRC IP 或 DST IP 是192.168.1.1
的包 -
ip.src_host == 192.168.1.1 and ip.dst_host == 192.168.1.2
过滤 SRC IP 是192.168.1.1
,并且 DST IP 是192.168.1.2
的包 -
tcp.port == 80
源端口或目的端口是 80 的包 -
tcp.flags.reset == 1
过滤 TCP RST 包。先找到 RST 包,然后右键 Follow -> TCP Stream 是常用的排障方式 -
tcp.analysis.retransmission
过滤所有的重传包
4.3 导出符合条件的包
5 总结
热文推荐
原文始发于微信公众号(LemonSec):如何使用 tcpdump 抓包?如何用 tcpdump 和 wireshark 分析网络流量?
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论