Tcpdump&Wireshark 再学习与理解
常用参数:
-w 文件名,可以把报文保存到文件;
-c 数量,可以抓取固定数量的报文,这在流量较高时,可以避免一不小心抓取过多报文;
-s 长度,可以只抓取每个报文的一定长度,后面我会介绍相关的使用场景;
-n,不做地址转换(比如 IP 地址转换为主机名,port 80 转换为 http);
-v/-vv/-vvv,可以打印更加详细的报文信息;
-e,可以打印二层信息,特别是 MAC 地址;
-p,关闭混杂模式。所谓混杂模式,也就是嗅探(Sniffing),就是把目的地址不是本机地址的网络报文也抓取下;
-X,使用ASCII显示报文内容
通过tcptrace 工具(需要单独安装),读取报文:
tcptrace -b test.pcap
用例记录:
# 使用偏移量的方法,抓取TLS 握手阶段的 Client Hello 报文
tcpdump -w file.pcap 'dst port 443 && tcp[20]==22 && tcp[25]==1'
:: 相关解释
dst port 443:这个最简单,就是抓取从客户端发过来的访问 HTTPS 的报文。
tcp[20]==22:这是提取了 TCP 的第 21 个字节(因为初始序号是从 0 开始的),由于 TCP 头部占 20 字节,TLS 又是 TCP 的载荷,那么 TLS 的第 1 个字节就是 TCP 的第 21 个字节,也就是 TCP[20],这个位置的值如果是 22(十进制),那么就表明这个是 TLS 握手报文。
tcp[25]==1:同理,这是 TCP 头部的第 26 个字节,如果它等于 1,那么就表明这个是 Client Hello 类型的 TLS 握手报文。
# 用偏移量方法,写一个 tcpdump 抓取 TCP SYN 包的过滤表达式
tcpdump 'tcp[13]&2 != 0'
# 如果要指定只抓取 SYN 包而不抓取 SYN+ACK,可以用下面的表达式
tcpdump 'tcp[13]|2 = 2'
# 过滤出 TCP RST 报文(TCPDUMP 预定义)
tcpdump -w file.pcap 'tcp[tcpflags]&(tcp-rst) != 0'
# 偏移量的写法
tcpdump -w file.pcap 'tcp[13]&4 != 0'
# 查看端口80的数据包内容
tcpdump port 80 -X
# 读取报文内容示例
tcpdump -r file.pcap 'tcp[tcpflags] & (tcp-rst) != 0'
# 过滤报文并进行转存示例
tcpdump -r file.pcap 'tcp[tcpflags] & (tcp-rst) != 0' -w rst.pcap
# 抓包时间如何长一点 -s 参数 size
tcpdump -s 74 -w file.pcap
二层:帧头是 14 字节
三层:IP 头是 20 字节
四层:TCP 头是 20~40 字节
如果你明确地知道这次抓包的重点是传输层,那么理论上,对于每一个报文,你只要抓取到传输层头部即可,也就是前 14+20+40 字节(即前 74 字节)
# 如果确定问题是在 IP 层,tcpdump 命令如何写,可以做到既找到 IP 层的问题,又节约抓包文件大小呢?
tcpdump -s 36(计算字节为34+2[Linux cooked capture v1 占用2字节]) -w file.pcap
在 tcpdump 里,对于 any 这个接口,它在输出帧头的时候用了一种叫 Linux cooked capture v1 的格式,这个格式的长度是 16 个字节,而以太网帧是 14 字节。这就造成了 2 个字节的差异,也就是按原先的 34 字节去抓取就不够了,所以要扩大到 36 字节才可以抓到完整的 IP 头部。
# 指定抓包时间端,并且过滤重传包除开序列1的示例
frame.time >="Jan 08, 2024 08:30:00" and frame.time <="Jan 08, 2024 08:35:00" and ip.src_host == X.X.X.X and tcp.flags.reset eq 1 and !(tcp.seq_raw eq 1 and tcp.ack_raw eq 1)
# 寻找指定的TCP 裸序列号的报文
tcp.seq_raw eq 3322242815
# 怎么知道抓包文件是在哪一端抓取的?
要搞清楚这一点也很简单,我们可以利用 IP 的 TTL 属性。显然,无论是哪一端,它的报文在发出时,其 TTL 就是原始值,也就是 64、128、255 中的某一个。而对端报文的 TTL,因为会经过若干个网络跳数,所以一般都会比 64、128、255 这几个数值要小一些。
# 在 Linux 中,还有一个内核参数也是关于握手的,net.ipv4.tcp_synack_retries。你知道这个参数是用来做什么的吗?
man tcp
然后搜索 tcp_synack_retries 就可以了,也就是这个部分:
tcp_synack_retries (integer; default: 5; since Linux 2.2)The maximum number of times a SYN/ACK segment for a passive TCP connection will be retransmitted. This number should not be higher than 255.
也就说,这是 TCP 回复 SYN+ACK 后等不到 ACK 时,需要重试的次数。
# 如果要在 Wireshark 中搜索到挥手阶段出现的 RST+ACK 报文,那么这个过滤器该如何写呢?
tcp.flags.ack eq 1 and tcp.flags.reset eq 1
# 利用 TCP 的载荷本身的特征去找到对应的报文 (其他类型的以此类推)
tcp contains "id=abcdafeafeagfeagfaraera1242dfea" frame contains "id=abcdafeafeagfeagfaraera1242dfea" ip contains "id=abcdafeafeagfeagfaraera1242dfea" http contains "id=abcdafeafeagfeagfaraera1242dfea"