【学习笔记】tcpdump+Wireshark抓包(2)

1. TLS

我们学过 HTTP 明文,这个TLS 可以当成:同一件事,只是内容被锁进保险箱里了。

之前 curl http://www.example.com 时:

  • 连的是 80 端口
  • Wireshark 里能直接看到 GET / HTTP/1.1200 OK

如果改成 https://

  • 连的是 443 端口
  • 数据先 加密,再放进 TCP
  • Wireshark 看不到 GET 和网页,只能看到 TLS 和 Application Data

HTTP: 明信片,谁都能读

HTTPS: 封信封,里面写了什么抓包看不到

TLS: 就是那只信封和锁

1.1 抓包 + 查看

终端 1:开始抓 443

bash 复制代码
sudo tcpdump -i any -nn -s 0 -w ~/Desktop/https-beginner.pcap port 443

只抓 443,比抓全部包干净很多。

终端 2:关掉代理,访问 HTTPS

bash 复制代码
unset http_proxy https_proxy HTTP_PROXY HTTPS_PROXY all_proxy ALL_PROXY

curl -v https://www.example.com

curl 之后会出现一个ip,大概在如下位置:

用Wireshark打开刚刚的这个.pcap包,然后在顶部过滤刚刚你查出来的这个IP。

可以看到如下三个点:

  • Protocol 多是 TLS 或 TLSv1.2 / TLSv1.3
  • Source/Destination 是你的电脑和 example 服务器来回
  • 端口 一边是自己,另一边是 443

总过程为4段:

  • No.8--10 TCP 三次握手(先接通 443)
  • No.11--20 TLS 握手(商量加密、交换证书、切换密文)
  • No.21--34 加密传数据(Application Data,里面是 HTTP)
  • No.35--39 TCP 四次挥手(断开连接)

1.2 找 TLS 握手

包号 过程
11 Client Hello:你开始 TLS 握手,声明访问 www.example.com(SNI)
14 TCP ACK:服务器确认收到 Client Hello
15 Server Hello + Change Cipher Spec:服务器选定加密方式,并通知后续改用密钥加密
16--17 服务器继续发握手内容(证书、握手结束等,TLS 1.3 中常已加密或打包)
18--19 你发 TCP ACK,确认收到服务器握手数据
20 Change Cipher Spec:你这边也切换为加密通信,TLS 握手基本完成

这一阶段: 在 TCP 之上建立 HTTPS 安全通道,还没传(或刚开始传)业务网页数据。

过滤条件再加一个 tls.handshake 。

直接看Info字段:

Info 谁发给谁 白话解释
Client Hello 你 → 服务器 我想用 HTTPS 连你,我支持这些加密方式
Server Hello 服务器 → 你 好,我们用这一种加密

|-----------------------------|---------|-----------------|
| Certificate | 服务器 → 你 | 这是我的证书,证明我是正规网站 |
| Server Hello Done | 服务器 → 你 | 我这边说完了 |
| Client Key Exchange 等 | 你 → 服务器 | 交换密钥(细节可先不管) |
| Change Cipher Spec | 双方 | 后面开始加密 |
| Encrypted Handshake Message | 双方 | 加密的握手收尾 |

Client Hello 包:

SNI 里通常是访问的域名。

含义:虽然 HTTP 还没开始传,但客户端会先告诉服务器「我要访问 www.example.com」。

这是 HTTPS 抓包里少数还能直接看到域名的字段之一。

此时还没有传 HTTP GET,只是在商量怎么加密。

Change Cipher Spec(切换加密)

含义: 通知对方:

从下一刻起,后面数据都用刚商量好的密钥加密

就像双方说好密码后说:好,从现在开始用这套密码说话。

界面上可能写 Version: TLS 1.2 (0x0303),这是兼容写法,你这次整体仍是 TLS 1.3,不用纠结这个显示。

1.3 加密业务数据

包号 过程
21、22、23、25、27--30、33、34 Application Data:加密的 HTTP 请求、响应和网页内容
24、26、31、32 TCP ACK:确认上面数据已收到

这一阶段: 真正的 HTTPS 访问发生在这里。里面是 GET、200 OK、HTML,但被 TLS 加密,Wireshark 只能显示 Application Data。

1.4 和 HTTP 明文对照

之前学过的 HTTP(80 端口)

bash 复制代码
TCP 三次握手
↓
明文 HTTP GET(Wireshark 直接看到)
↓
明文 HTTP 200 OK + HTML(Wireshark 直接看到)
↓
TCP 四次挥手

现在的 HTTPS(443 端口)

bash 复制代码
TCP 三次握手(和 HTTP 一样,还是 TCP)
↓
TLS Client Hello / Server Hello / Certificate...(多出来的 TLS 握手)
↓
TLS Application Data(加密的 GET,看不见)
↓
TLS Application Data(加密的 200 OK + HTML,看不见)
↓
TCP 四次挥手

多出来的就是 TLS 握手 + 全程加密。

2. tcpdump常见命令

1. 基础结构

bash 复制代码
sudo tcpdump [选项] [过滤表达式]

抓包一般要 sudo。不写过滤表达式 = 抓所有流量(噪音大,初学建议加过滤)。

2. 最常用选项

选项 含义 示例
-i any 指定网卡,any 为所有网卡 tcpdump -i en0
-w 文件.pcap 保存到文件(给 Wireshark) -w ~/Desktop/out.pcap
-r 文件.pcap 读已有 pcap(不抓新包) tcpdump -r out.pcap
-c 数字 抓满 N 个包就停 -c 100
-n 不把 IP 转成主机名 输出更快、更干净
-nn 不把 IP、端口转成名字 推荐常用

打开已存在的 .pcap 包进行查看,如 ping-gateway.pcap 。

步骤 1:终端中 只看 ICMP

bash 复制代码
tcpdump -r ~/Desktop/ping-gateway.pcap -nn icmp

你应该看到类似:

bash 复制代码
10.2.73.219 > 10.2.72.1: ICMP echo request
10.2.72.1 > 10.2.73.219: ICMP echo reply

顺便看一下加 -nn 和不加 -nn 的区别。

中间可能夹杂 unreachable 报错,正常。

步骤 2:终端中 只看和网关有关的

bash 复制代码
tcpdump -r ~/Desktop/ping-gateway.pcap -nn host 10.2.72.1

只保留和 10.2.72.1 有关的包,噪音少很多。

bash 复制代码
# 出现类似如下结果
reading from PCAP-NG file /Users/liyijun/Desktop/ping-gateway.pcap
13:53:35.444034 IP 10.2.73.219 > 10.2.72.1: ICMP echo request, id 4782, seq 0, length 64
13:53:35.453132 IP 10.2.72.1 > 10.2.73.219: ICMP echo reply, id 4782, seq 0, length 64
13:53:36.449209 IP 10.2.73.219 > 10.2.72.1: ICMP echo request, id 4782, seq 1, length 64
13:53:36.454207 IP 10.2.72.1 > 10.2.73.219: ICMP echo reply, id 4782, seq 1, length 64
13:53:37.454194 IP 10.2.73.219 > 10.2.72.1: ICMP echo request, id 4782, seq 2, length 64
13:53:37.477599 IP 10.2.72.1 > 10.2.73.219: ICMP echo reply, id 4782, seq 2, length 64
13:53:38.456592 IP 10.2.73.219 > 10.2.72.1: ICMP echo request, id 4782, seq 3, length 64
13:53:38.468613 IP 10.2.72.1 > 10.2.73.219: ICMP echo reply, id 4782, seq 3, length 64

在Wireshark中其实就是如下的过滤条件(之前演示过,很好理解):

bash 复制代码
icmp
ip.addr == 10.2.72.1
icmp && ip.addr == 10.2.72.1

如果要捕捉指定端口 ,在tcpdump里直接使用 port 端口号 就行。

比如打开之前捕捉百度dns解析过程的文件进行演示:

bash 复制代码
tcpdump -r ~/Desktop/dns-test.pcap -nn port 53    
bash 复制代码
# 结果如下                         
reading from PCAP-NG file /Users/liyijun/Desktop/dns-test.pcap
15:34:16.634264 IP 10.2.73.219.57470 > 10.2.255.2.53: 8489+ A? www.baidu.com. (31)
15:34:16.648031 IP 10.2.255.2.53 > 10.2.73.219.57470: 8489* 3/0/0 CNAME www.a.shifen.com., A 110.242.69.21, A 110.242.70.57 (138)

但是在Wireshark里不能直接用port字段,需要指定是tcp还是udp,dns是udp,所以要输入的过滤条件是:

bash 复制代码
udp.port == 53

若tcp也要,那就在顶部同时过滤:

bash 复制代码
udp.port == 53 || tcp.port == 53

|-----------------------|---------------|------------|
| -v / -vv / -vvv | 更详细输出 | 终端直接看时用 |
| -A | 以 ASCII 显示包内容 | 看明文 HTTP 等 |
| -X | 十六进制 + ASCII | 比 -A 更全 |
| -s 0 | 抓完整包(默认可能截断) | 生产环境建议加上 |

-s 0 是 tcpdump 的抓包长度选项,意思是每个包都完整抓取,不截断。

  • -s:snaplen,单个包最多抓多少字节
  • 0:不限制,抓整包

常见用法:

bash 复制代码
sudo tcpdump -i any -nn -s 0 -w ~/Desktop/capture.pcap

抓包存文件时习惯加上 -s 0,保证 pcap 里是完整包。读已有文件用 -r 时一般不需要再加 -s 0

3. 常见抓包组合(可直接复制)

抓所有包,存文件

bash 复制代码
sudo tcpdump -i any -w ~/Desktop/all.pcap

只抓某种协议的包,如 ICMP(ping)

cpp 复制代码
sudo tcpdump -i any icmp -w ~/Desktop/ping.pcap

只抓 50 个包( -c 选项后面加数字)

bash 复制代码
sudo tcpdump -i any -c 50 -w ~/Desktop/test.pcap

终端直接看,不存文件(如 ping )

bash 复制代码
sudo tcpdump -i any -nn icmp

抓完整包 + 不解析名字

bash 复制代码
sudo tcpdump -i any -nn -s 0 -w ~/Desktop/full.pcap

4. 过滤表达式(重点)

按主机

和某 IP 有关的所有包(源或目的)

bash 复制代码
sudo tcpdump -i any host 10.2.72.1

只抓源是该 IP

bash 复制代码
sudo tcpdump -i any src host 10.2.73.219

只抓目的是该 IP

bash 复制代码
sudo tcpdump -i any dst host 172.66.147.243

按网段

整个网段

bash 复制代码
sudo tcpdump -i any net 10.2.73.0/24

按端口

端口 80(HTTP)

bash 复制代码
sudo tcpdump -i any port 80

端口 443(HTTPS)

bash 复制代码
sudo tcpdump -i any port 443

源端口 / 目的端口

bash 复制代码
sudo tcpdump -i any src port 57872

sudo tcpdump -i any dst port 80

按协议

bash 复制代码
sudo tcpdump -i any tcp

sudo tcpdump -i any udp

sudo tcpdump -i any icmp

组合(与 / 或 / 非)

某 IP 的 TCP

bash 复制代码
sudo tcpdump -i any host 172.66.147.243 and tcp

80 或 443

bash 复制代码
sudo tcpdump -i any port 80 or port 443

排除某 IP

bash 复制代码
sudo tcpdump -i any not host 127.0.0.1

某 IP 的 HTTP(端口80)

bash 复制代码
sudu tcpdump -i any host 172.12.32.78 and port 80

TCP 标志(进阶)

SYN 包(握手第一步)

sudo tcpdump -i any 'tcptcpflags & tcp-syn != 0'

SYN 且非 ACK(纯 SYN)

sudo tcpdump -i any 'tcptcpflags & tcp-syn != 0 and tcptcpflags & tcp-ack == 0'


5. 读已有 pcap

读文件并过滤

bash 复制代码
tcpdump -r 文件路径/文件名.pcap port 80

读文件,只看前 20 个

bash 复制代码
sudo tcpdump -r 文件路径/文件名.pcap -c 20

读文件,ASCII 显示 HTTP

bash 复制代码
tcpdump -r ~/Desktop/tcp-http.pcap -A port 80

6. tcpdump 与 Wireshark 过滤对照

目的 tcpdump Wireshark
某 IP host 10.2.72.1 ip.addr == 10.2.72.1
源 IP src host 10.2.73.219 ip.src == 10.2.73.219
端口 80 port 80 tcp.port == 80
只要 TCP tcp tcp
只要 ICMP icmp icmp
只要 DNS port 53 dns

3. Wireshark 常见显示过滤器

显示过滤器只在已经抓好的 pcap 里筛选,不改变抓包内容。语法错了会红色,对了是绿色。

1. 逻辑运算符

符号 含义 示例
&&and 并且 tcp and port 80
` or`
!not not arp

2. IP 相关

源或目的包含该 IP

bash 复制代码
ip.addr == 10.2.73.21

源 IP

bash 复制代码
ip.src == 10.2.73.21

目的 IP

bash 复制代码
ip.des == 10.2.34.56

某网段(部分版本支持)

bash 复制代码
ip.addr == 10.2.73.0/24

3. 端口与协议

过滤协议的话直接输入就行:

bash 复制代码
tcp # 所有 TCP
udp # 所有 UDP
icmp # 所有 ICMP
dns # DNS
http # HTTP(明文)
tls # TLS/HTTPS

过滤端口需要指定协议:

bash 复制代码
tcp.port == 80 # TCP 端口 80
tcp.port == 443 # HTTPS
tcp.srcport == 57872 # 源端口
tcp.dstport == 80 # 目的端口
udp.port == 53 # DNS 端口

4. TCP 标志(握手 / 挥手 / 异常)

  • 含 SYN:tcp.flags.syn == 1
  • 含 ACK:tcp.flags.ack == 1
  • 含 FIN(挥手):tcp.flags.fin == 1
  • RST(连接被拒或重置):tcp.flags.reset == 1
  • 纯 SYN(握手第 1 步):tcp.flags.syn == 1 && tcp.flags.ack == 0
  • SYN+ACK(握手第 2 步):tcp.flags.syn == 1 && tcp.flags.ack == 1

5. DNS

  • 下面的 qry 专门指 query 部分 的字段
  • 只显示 查询域名里包含 baidu 的 DNS 包:dns.qry.name contains "baidu"
  • 只显示 DNS 查询里,域名完全等于 www.example.com 的包:dns.qry.name == "www.example.com"
  • 只要 query:dns.flags.response == 0
  • 只要 response:dns.flags.response == 1

6. HTTP(明文)

  • http
  • http.request # 只要请求
  • http.response # 只要响应
  • 只看请求方法为 GET:http.request.method == "GET"
  • Host 头包含 example 的请求或响应:http.host contains "example"
  • 只看 HTTP 响应状态码是 200 的包:http.response.code == 200
  • 4xx、5xx 错误:http.response.code >= 400

7. HTTPS / TLS

  • tls
  • Client Hello: tls.handshake.type == 1
  • Server Hello:tls.handshake.type == 2
  • tcp.port == 443 && tls

8. Wireshark 实用操作(非过滤,但常用)

操作 作用
右键包 → Follow → TCP Stream 看一次 TCP 会话完整内容
右键包 → Follow → HTTP Stream 看 HTTP 请求+响应全文
Statistics → Conversations 看哪些 IP/端口通信最多
点击包 → Response in frame / Request in frame 跳到配对的请求/响应

4. 按场景选命令(速查)

场景 tcpdump 抓包 Wireshark 查看
ping 网关 tcpdump -i any icmp -w ping.pcap icmp && ip.addr == 网关IP
DNS 查询 tcpdump -i any port 53 -w dns.pcap dns
HTTP 访问 tcpdump -i any port 80 -w http.pcap tcp.port == 80 然后 http
HTTPS 访问 tcpdump -i any port 443 -w https.pcap tcp.port == 443 然后 tls
排查连不上 tcpdump -i any host 目标IP -w fail.pcap tcp.flags.reset == 1
减少噪音 抓包时就加 host / port !ip.addr == 127.0.0.1