tcpdump 详细使用指南(请尽情食用)

参考

  • Tcpdump 示例教程 超级棒!

  • Tcpdump Examples

  • [译]tcpdump 示例教程

  • Linux 网络命令必知必会之 tcpdump,一份完整的抓包指南请查收!

  • Linux tcpdump命令

  • 一份快速实用的 tcpdump 命令参考手册

  • 全网最详细的 tcpdump 使用指南

0. 总览

tcpdump 是一款强大的网络抓包工具,它使用 libpcap 库来抓取网络数据包,这个库在几乎在所有的 Linux/Unix 中都有。熟悉 tcpdump 的使用能够帮助你分析调试网络数据,本文将通过一个个具体的示例来介绍它在不同场景下的使用方法。不管你是系统管理员,程序员,云原生工程师还是 yaml 工程师,掌握 tcpdump 的使用都能让你如虎添翼,升职加薪。

tcpdump 核心参数图解

tcpdump 详细使用指南(请尽情食用)_第1张图片

  1. option 可选参数:将在后边一一解释。
  2. proto 类过滤器:根据协议进行过滤,可识别的关键词有: tcp, udp, icmp, ip, ip6, arp, rarp,ether,wlan, fddi, tr, decnet
  3. type 类过滤器:可识别的关键词有:host, net, port, portrange,这些词后边需要再接参数。
  4. direction 类过滤器:根据数据流向进行过滤,可识别的关键字有:src, dst,同时你可以使用逻辑运算符进行组合,比如 src or dst

参数列表

设置不解析域名提升速度
-n 不把ip转化成域名,直接显示 ip,避免执行 DNS lookups 的过程,速度会快很多
-nn 不把协议和端口号转化成名字,速度也会快很多。
-N 不打印出host 的域名部分.。比如,,如果设置了此选现,tcpdump 将会打印’nic’ 而不是 ‘nic.ddn.mil’.
过滤指定网卡的数据包
-i 指定要过滤的网卡接口,如果要查看所有网卡,可以 -i any
过滤特定流向的数据包
-Q 选择是入方向还是出方向的数据包,可选项有:in, out, inout,也可以使用 --direction=[direction] 这种写法
常用的一些参数
-A 以ASCII码方式显示每一个数据包(不显示链路层头部信息). 在抓取包含网页数据的数据包时, 可方便查看数据
-l 基于行的输出,便于你保存查看,或者交给其它工具分析
tcpdump -nn -A -s1500 -l | egrep -i 'User-Agent:|Host’
通过 egrep 可以同时提取用户代理和主机名(或其他头文件):
-q 简洁地打印输出。即打印很少的协议相关信息, 从而输出行都比较简短.
-c 捕获 count 个包 tcpdump 就退出
-s tcpdump 默认只会截取前 96 字节的内容,要想截取所有的报文内容,可以使用 -s numbernumber 就是你要截取的报文字节数,如果是 0 的话,表示截取报文全部内容。
-S 使用绝对序列号,而不是相对序列号
-C file-size,tcpdump 在把原始数据包直接保存到文件中之前, 检查此文件大小是否超过file-size. 如果超过了, 将关闭此文件,另创建一个文件继续用于原始数据包的记录. 新创建的文件名与-w 选项指定的文件名一致, 但文件名后多了一个数字.该数字会从1开始随着新创建文件的增多而增加. file-size的单位是百万字节(nt: 这里指1,000,000个字节,并非1,048,576个字节, 后者是以1024字节为1k, 1024k字节为1M计算所得, 即1M=1024 * 1024 = 1,048,576)
-F 使用file 文件作为过滤条件表达式的输入, 此时命令行上的输入将被忽略.
过滤结果输出到文件
-w 使用 -w 参数后接一个以 .pcap 后缀命令的文件名,就可以将 tcpdump 抓到的数据保存到文件中。使用 wireshark 打开此文件便可进行分析 tcpdump icmp -w icmp.pcap
-r 从文件中读取数据,读取后,我们照样可以使用上述的过滤器语法进行过滤分析。 tcpdump icmp -r all.pcap
对输出内容进行控制的参数
-D 显示所有可用网络接口的列表
-e 每行的打印输出中将包括数据包的数据链路层头部信息
-E 揭秘IPSEC数据
-L 列出指定网络接口所支持的数据链路层的类型后退出
-Z 后接用户名,在抓包时会受到权限的限制。如果以root用户启动tcpdump,tcpdump将会有超级用户权限。
-d 打印出易读的包匹配码
-dd 以C语言的形式打印出包匹配码.
-ddd 以十进制数的形式打印出包匹配码
控制详细内容的输出
-v 产生详细的输出. 比如包的TTL,id标识,数据包长度,以及IP包的一些选项。同时它还会打开一些附加的包完整性检测,比如对IP或ICMP包头部的校验和。
-vv 产生比-v更详细的输出. 比如NFS回应包中的附加域将会被打印, SMB数据包也会被完全解码。(摘自网络,目前我还未使用过)
-vvv 产生比-vv更详细的输出。比如 telent 时所使用的SB, SE 选项将会被打印, 如果telnet同时使用的是图形界面,其相应的图形选项将会以16进制的方式打印出来(摘自网络,目前我还未使用过)
控制时间的显示
-t 在每行的输出中不输出时间
-tt 在每行的输出中会输出时间戳
-ttt 输出每两行打印的时间间隔(以毫秒为单位)
-tttt 在每行打印的时间戳之前添加日期的打印(此种选项,输出的时间最直观)
显示数据包的头部
-x 以16进制的形式打印每个包的头部数据(但不包括数据链路层的头部)
-xx 以16进制的形式打印每个包的头部数据(包括数据链路层的头部)
-X 以16进制和 ASCII码形式打印出每个包的数据(但不包括连接层的头部),这在分析一些新协议的数据包很方便。
-XX 以16进制和 ASCII码形式打印出每个包的数据(包括连接层的头部),这在分析一些新协议的数据包很方便。

过滤规则组合

有编程基础的同学,对于下面三个逻辑运算符应该不陌生了吧

  • and:所有的条件都需要满足,也可以表示为 &&
  • or:只要有一个条件满足就可以,也可以表示为 ||
  • not:取反,也可以使用 !

举个例子,我想需要抓一个来自10.5.2.3,发往任意主机的3389端口的包

$ tcpdump src 10.5.2.3 and dst port 3389

当你在使用多个过滤器进行组合时,有可能需要用到括号,而括号在 shell 中是特殊符号,因为你需要使用引号将其包含。例子如下:

$ tcpdump 'src 10.0.2.4 and (dst port 3389 or 22)'

而在单个过滤器里,常常会判断一条件是否成立,这时候,就要使用下面两个符号

  • =:判断二者相等
  • ==:判断二者相等
  • !=:判断二者不相等

当你使用这两个符号时,tcpdump 还提供了一些关键字的接口来方便我们进行判断,比如

  • if:表示网卡接口名、
  • proc:表示进程名
  • pid:表示进程 id
  • svc:表示 service class
  • dir:表示方向,in 和 out
  • eproc:表示 effective process name
  • epid:表示 effective process ID

比如我现在要过滤来自进程名为 nc 发出的流经 en0 网卡的数据包,或者不流经 en0 的入方向数据包,可以这样子写

$ tcpdump "( if=en0 and proc =nc ) || (if != en0 and dir=in)"

内容输出结构

21:26:49.013621 IP 172.20.20.1.15605 > 172.20.20.2.5920: Flags [P.], seq 49:97, ack 106048, win 4723, length 48

从上面的输出来看,可以总结出:

  1. 第一列:时分秒毫秒 21:26:49.013621
  2. 第二列:网络协议 IP
  3. 第三列:发送方的ip地址+端口号,其中172.20.20.1是 ip,而15605 是端口号
  4. 第四列:箭头 >, 表示数据流向
  5. 第五列:接收方的ip地址+端口号,其中 172.20.20.2 是 ip,而5920 是端口号
  6. 第六列:冒号
  7. 第七列:数据包内容,包括Flags 标识符,seq 号,ack 号,win 窗口,数据长度 length,其中 [P.] 表示 PUSH 标志位为 1,更多标识符见下面

理解 Flag 标识符

截取数据只是第一步,第二步就是理解这些数据,下面就解释一下 tcpdump 命令输出各部分的意义。

21:27:06.995846 IP (tos 0x0, ttl 64, id 45646, offset 0, flags [DF], proto TCP (6), length 64)
    192.168.1.106.56166 > 124.192.132.54.80: Flags [S], cksum 0xa730 (correct), seq 992042666, win 65535, options [mss 1460,nop,wscale 4,nop,nop,TS val 663433143 ecr 0,sackOK,eol], length 0

21:27:07.030487 IP (tos 0x0, ttl 51, id 0, offset 0, flags [DF], proto TCP (6), length 44)
    124.192.132.54.80 > 192.168.1.106.56166: Flags [S.], cksum 0xedc0 (correct), seq 2147006684, ack 992042667, win 14600, options [mss 1440], length 0

21:27:07.030527 IP (tos 0x0, ttl 64, id 59119, offset 0, flags [DF], proto TCP (6), length 40)
    192.168.1.106.56166 > 124.192.132.54.80: Flags [.], cksum 0x3e72 (correct), ack 2147006685, win 65535, length 0

最基本也是最重要的信息就是数据报的源地址/端口和目的地址/端口,上面的例子第一条数据报中,源地址 ip 是 192.168.1.106,源端口是 56166,目的地址是 124.192.132.54,目的端口是 80> 符号代表数据的方向。

此外,上面的三条数据还是 tcp 协议的三次握手过程,第一条就是 SYN 报文,这个可以通过 Flags [S] 看出。下面是常见的 TCP 报文的 Flags:

  • [S] : SYN(开始连接)
  • [.] : 没有 Flag
  • [P] : PSH(推送数据)
  • [F] : FIN (结束连接)
  • [R] : RST(重置连接)

而第二条数据的 [S.] 表示 SYN-ACK,就是 SYN 报文的应答报文。

示例

基础过滤

# 1. 基于IP地址过滤
# 根据源ip进行过滤
$ tcpdump -i eth2 src 192.168.10.100

# 根据目标ip进行过滤
$ tcpdump -i eth2 dst 192.168.10.200

# 2. 基于网段进行过滤:net
$ tcpdump net 192.168.10.0/24
# 根据源网段进行过滤  可以理解为 ip 的前缀
$ tcpdump src net 192.168

# 根据目标网段进行过滤
$ tcpdump dst net 192.168

# 示例
$ tcpdump -i ens160  src net 10.10
17:11:59.473114 IP 10.10.2.238.55742 > master01.cluster.local.ssh: Flags [.], ack 14604, win 2028, options [nop,nop,TS val 1375892214 ecr 4001186014], length 0
17:11:59.473188 IP master01.cluster.local.ssh > 10.10.2.238.55742: Flags [.], seq 20844:23340, ack 1, win 501, options [nop,nop,TS val 4001186225 ecr 1375892214], length 2496
17:11:59.489447 IP 10.10.2.50.ideafarm-door > 10.10.1.21.41714: Flags [.], ack 149, win 128, length 0
17:11:59.498194 IP 10.10.2.238.55742 > master01.cluster.local.ssh: Flags [.], ack 15852, win 2048, options [nop,nop,TS val 1375892216 ecr 4001186042], length 0
17:11:59.498231 IP master01.cluster.local.ssh > 10.10.2.238.55742: Flags [.], seq 23340:24588, ack 1, win 501, options [nop,nop,TS val 4001186250 ecr 1375892216], length 1248
17:11:59.539698 IP 10.10.2.33.etcd-client > 10.10.2.49.45720: Flags [.], ack 3363427380, win 1432, options [nop,nop,TS val 3296084139 ecr 1511276523], length 0
17:11:59.539699 IP 10.10.2.33.etcd-client > 10.10.2.49.45130: Flags [.], ack 2489720301, win 801, options [nop,nop,TS val 3296084139 ecr 1511276523], length 0
# 可看出筛选出 所有 1 段的源 ip 包,也可以理解为前缀符合 10.10.1
$ tcpdump -i ens160  src net 10.10.1
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens160, link-type EN10MB (Ethernet), capture size 262144 bytes
17:13:23.179904 IP 10.10.1.21.41714 > 10.10.2.50.ideafarm-door: Flags [P.], seq 3089274228:3089274265, ack 2296379143, win 3507, length 37
17:13:23.199903 IP 10.10.1.21.41714 > 10.10.2.50.ideafarm-door: Flags [P.], seq 37:74, ack 54, win 3507, length 37
17:13:23.386367 IP 10.10.1.21.41714 > 10.10.2.50.ideafarm-door: Flags [P.], seq 74:111, ack 210, win 3507, length 37
17:13:23.596409 IP 10.10.1.21.41714 > 10.10.2.50.ideafarm-door: Flags [P.], seq 111:148, ack 279, win 3507, length 37

# 3. 基于端口进行过滤:port
$ tcpdump port 8088
# 根据源端口进行过滤
$ tcpdump src port 8088

# 根据目标端口进行过滤
$ tcpdump dst port 8088

# 想要同时指定两个端口你可以这样写
$ tcpdump port 80 or port 8088

# 想抓取的不再是一两个端口,而是一个范围,一个一个指定就非常麻烦了,此时你可以这样指定一个端口段
$ tcpdump portrange 8000-8080
$ tcpdump src portrange 8000-8080
$ tcpdump dst portrange 8000-8080

# 对于一些常见协议的默认端口,我们还可以直接使用协议名,而不用具体的端口号 比如 http == 80,https == 443 等
$ tcpdump tcp port http

# 4. 基本IP协议的版本进行过滤
# 当你想查看 tcp 的包,你也许会这样子写
$ tcpdump tcp

# ip 根据版本的不同,可以再细分为 IPv4 和 IPv6 两种,如果你只指定了 tcp,这两种其实都会包含在内。
# 那有什么办法,能够将 IPv4 和 IPv6 区分开来呢?
# 如果是 IPv4 的 tcp 包 ,就这样写
$ tcpdump 'ip proto tcp'

# 而如果是 IPv6 的 tcp 包 ,就这样写
$ tcpdump 'ip6 proto tcp'

过滤组合

# 1. 通常情况下,如果不指定网络接口, tcpdump 在运行时会选择编号最低的网络接口,一般情况下是 eth0,不过因系统不同可能会有所差异。
$ tcpdump
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
16:15:05.051896 IP blog.ssh > 10.0.3.1.32855: Flags [P.], seq 2546456553:2546456749, ack 1824683693, win 355, options [nop,nop,TS val 620879437 ecr 620879348], length 196

# 2. 可以用 -i 标记来指定网络接口。在大多数 Linux 系统上,any 这一特定的网络接口名用来让 tcpdump 监听所有的接口。我发现这在排查服务器(拥有多个网络接口)的问题特别有用,尤其是牵扯到路由的时候。
$ tcpdump -i any
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
16:45:59.312046 IP blog.ssh > 10.0.3.1.32855: Flags [P.], seq 2547763641:2547763837, ack 1824693949, win 355, options [nop,nop,TS val 621343002 ecr 621342962], length 196

# 3. 通常情况下, tcpdump 会尝试查找和转换主机名和端口号。
$ tcpdump
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
16:15:05.051896 IP blog.ssh > 10.0.3.1.32855: Flags [P.], seq 2546456553:2546456749, ack 1824683693, win 355, options [nop,nop,TS val 620879437 ecr 620879348], length 196

# 4. 可以通过 -n 标记关闭这个功能。我个人总是使用这个标记,因为我喜欢使用 IP 地址而不是主机名,主机名和端口号的转换经常会带来困扰。但是,知道利用 tcpdump 转换或者不转换的功能还是相当有用的,特别是有些时候,知道源流量(source traffic)来自哪个服务器是相当重要的。
# -n 参数  不会讲数据包中的 ip 转换为域名,可以看出,上面没指定 -n 显示为 blog.ssh,指定了 -n 参数 显示为 10.0.3.246.22(ip为 10.0.3.246,端口为22)
# 同理 -nn 是 不进行域名和端口名的转换,显示 ip 和 端口
$ tcpdump -n
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
16:23:47.934665 IP 10.0.3.246.22 > 10.0.3.1.32855: Flags [P.], seq 2546457621:2546457817, ack 1824684201, win 355, options [nop,nop,TS val 621010158 ecr 621010055], length 196

# 5. tcpdump 的详细信息有三个等级,你可以通过在命令行增加 v 标记的个数来获取更多的信息。通常我在使用 tcpmdump 的时候,总是使用最高等级的详细信息,因为我希望看到所有信息,以免后面会用到。
# -c 表示抓取一个完整的数据包就退出
$ tcpdump -vvv -c 1
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
16:36:13.873456 IP (tos 0x10, ttl 64, id 121, offset 0, flags [DF], proto TCP (6), length 184)
    blog.ssh > 10.0.3.1.32855: Flags [P.], cksum 0x1ba1 (incorrect -> 0x0dfd), seq 2546458841:2546458973, ack 1824684869, win 355, options [nop,nop,TS val 621196643 ecr 621196379], length 132

# 6. 指定抓包大小, 此处为只获取包的前 100 字节
$ tcpdump  -s 100

# 7. 指定抓包数量  抓10个包就退出
$ tcpdump  -c 10

# 8. 过滤指定端口
# 这里使用 and 操作符告诉 tcpdump 只输出端口号是 22 和 60738 的数据包
# and 或者 && 都可以。我个人倾向于两个都使用,特别要记住在使用 && 的时候,要用单引号或者双引号包住表达式。在 BASH 中,你可以使用 && 运行一个命令,该命令成功后再执行后面的命令。通常,最好将表达式用引号包起来,这样会避免不预期的结果,特别当过滤器中有一些特殊字符的时候
$ tcpdump  -nvvv -i any -c 3 port 22 and port 60738
或 $ tcpdump -nvvv -i any -c 3 port 22 and port 60738
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
18:05:54.069403 IP (tos 0x10, ttl 64, id 64401, offset 0, flags [DF], proto TCP (6), length 104)
    10.0.3.1.60738 > 10.0.3.246.22: Flags [P.], cksum 0x1b51 (incorrect -> 0x5b3c), seq 917414532:917414584, ack 1550997318, win 353, options [nop,nop,TS val 622541691 ecr 622538903], length 52
18:05:54.072963 IP (tos 0x10, ttl 64, id 13601, offset 0, flags [DF], proto TCP (6), length 184)
    10.0.3.246.22 > 10.0.3.1.60738: Flags [P.], cksum 0x1ba1 (incorrect -> 0xb0b1), seq 1:133, ack 52, win 355, options [nop,nop,TS val 622541692 ecr 622541691], length 132
18:05:54.073080 IP (tos 0x10, ttl 64, id 64402, offset 0, flags [DF], proto TCP (6), length 52)
    10.0.3.1.60738 > 10.0.3.246.22: Flags [.], cksum 0x1b1d (incorrect -> 0x1e3b), seq 52, ack 133, win 353, options [nop,nop,TS val 622541692 ecr 622541692], length 0

# 9. 查找两个端口号的流量
# 可以用 or 或者 || 操作符来过滤结果。在这个例子中,我们使用 or 操作符去截获发送和接收端口为 80 或 443 的数据流。这在 Web 服务器上特别有用,因为服务器通常有两个开放的端口,端口号 80 表示 http 连接,443 表示 https。
$ tcpdump -nvvv -i any -c 20 'port 80 or port 443'
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
18:24:28.817940 IP (tos 0x0, ttl 64, id 39930, offset 0, flags [DF], proto TCP (6), length 60)
    10.0.3.1.50524 > 10.0.3.246.443: Flags [S], cksum 0x1b25 (incorrect -> 0x8611), seq 3836995553, win 29200, options [mss 1460,sackOK,TS val 622820379 ecr 0,nop,wscale 7], length 0
18:24:28.818052 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 40)
    10.0.3.246.443 > 10.0.3.1.50524: Flags [R.], cksum 0x012c (correct), seq 0, ack 3836995554, win 0, length 0
18:24:32.721330 IP (tos 0x0, ttl 64, id 48510, offset 0, flags [DF], proto TCP (6), length 475)
    10.0.3.1.60374 > 10.0.3.246.80: Flags [P.], cksum 0x1cc4 (incorrect -> 0x3a4e), seq 580573019:580573442, ack 1982754038, win 237, options [nop,nop,TS val 622821354 ecr 622815632], length 423
18:24:32.721465 IP (tos 0x0, ttl 64, id 1266, offset 0, flags [DF], proto TCP (6), length 52)
    10.0.3.246.80 > 10.0.3.1.60374: Flags [.], cksum 0x1b1d (incorrect -> 0x45d7), seq 1, ack 423, win 243, options [nop,nop,TS val 622821355 ecr 622821354], length 0
18:24:32.722098 IP (tos 0x0, ttl 64, id 1267, offset 0, flags [DF], proto TCP (6), length 241)
    10.0.3.246.80 > 10.0.3.1.60374: Flags [P.], cksum 0x1bda (incorrect -> 0x855c), seq 1:190, ack 423, win 243, options [nop,nop,TS val 622821355 ecr 622821354], length 189
18:24:32.722232 IP (tos 0x0, ttl 64, id 48511, offset 0, flags [DF], proto TCP (6), length 52)
    10.0.3.1.60374 > 10.0.3.246.80: Flags [.], cksum 0x1b1d (incorrect -> 0x4517), seq 423, ack 190, win 245, options [nop,nop,TS val 622821355 ecr 622821355], length 0

# 10. 查找两个特定端口和来自特定主机的数据流
# 前面的例子用来排查多端口的协议问题,是非常有效的。如果 Web 服务器的数据流量相当大, tcpdump 的输出可能有点混乱。我们可以通过增加 host 参数进一步限定输出。在这种情况下,我们通过把 or 表达式放在括号中来保持 or 描述。
$ tcpdump -nvvv -i any -c 20 '(port 80 or port 443) and host 10.0.3.169'
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
18:38:05.551194 IP (tos 0x0, ttl 64, id 63169, offset 0, flags [DF], proto TCP (6), length 60)
    10.0.3.169.33786 > 10.0.3.246.443: Flags [S], cksum 0x1bcd (incorrect -> 0x0d96), seq 4173164403, win 29200, options [mss 1460,sackOK,TS val 623024562 ecr 0,nop,wscale 7], length 0
18:38:05.551310 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 40)
    10.0.3.246.443 > 10.0.3.169.33786: Flags [R.], cksum 0xa64a (correct), seq 0, ack 4173164404, win 0, length 0
18:38:05.717130 IP (tos 0x0, ttl 64, id 51574, offset 0, flags [DF], proto TCP (6), length 60)
    10.0.3.169.35629 > 10.0.3.246.80: Flags [S], cksum 0x1bcd (incorrect -> 0xdf7c), seq 1068257453, win 29200, options [mss 1460,sackOK,TS val 623024603 ecr 0,nop,wscale 7], length 0
18:38:05.717255 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 60)
    10.0.3.246.80 > 10.0.3.169.35629: Flags [S.], cksum 0x1bcd (incorrect -> 0xed80), seq 2992472447, ack 1068257454, win 28960, options [mss 1460,sackOK,TS val 623024603 ecr 623024603,nop,wscale 7], length 0
18:38:05.717474 IP (tos 0x0, ttl 64, id 51575, offset 0, flags [DF], proto TCP (6), length 52)
    10.0.3.169.35629 > 10.0.3.246.80: Flags [.], cksum 0x1bc5 (incorrect -> 0x8c87), seq 1, ack 1, win 229, options [nop,nop,TS val 623024604 ecr 623024603], length 0



# tcpdump 绝对不是只能抓 TCP 数据包。它还可以用来获取其他类型的数据包,例如 ICMP、 UDP 和 ARP 包。下面是一些简单的例子,说明 tcpdump 可以截获非 TCP 数据包
# ICMP 数据包
$ tcpdump -nvvv -i any -c 2 icmp
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
20:11:24.627824 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto ICMP (1), length 84)
    10.0.3.169 > 10.0.3.246: ICMP echo request, id 15683, seq 1, length 64
20:11:24.627926 IP (tos 0x0, ttl 64, id 31312, offset 0, flags [none], proto ICMP (1), length 84)
    10.0.3.246 > 10.0.3.169: ICMP echo reply, id 15683, seq 1, length 64
# UDP 数据包
$ tcpdump -nvvv -i any -c 2 udp
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
20:12:41.726355 IP (tos 0xc0, ttl 64, id 0, offset 0, flags [DF], proto UDP (17), length 76)
    10.0.3.246.123 > 198.55.111.50.123: [bad udp cksum 0x43a9 -> 0x7043!] NTPv4, length 48
        Client, Leap indicator: clock unsynchronized (192), Stratum 2 (secondary reference), poll 6 (64s), precision -22
        Root Delay: 0.085678, Root dispersion: 57.141830, Reference-ID: 199.102.46.75
          Reference Timestamp:  3622133515.811991035 (2014/10/12 20:11:55)
          Originator Timestamp: 3622133553.828614115 (2014/10/12 20:12:33)
          Receive Timestamp:    3622133496.748308420 (2014/10/12 20:11:36)
          Transmit Timestamp:   3622133561.726278364 (2014/10/12 20:12:41)
            Originator - Receive Timestamp:  -57.080305658
            Originator - Transmit Timestamp: +7.897664248
20:12:41.748948 IP (tos 0x0, ttl 54, id 9285, offset 0, flags [none], proto UDP (17), length 76)
    198.55.111.50.123 > 10.0.3.246.123: [udp sum ok] NTPv4, length 48
        Server, Leap indicator:  (0), Stratum 3 (secondary reference), poll 6 (64s), precision -20
        Root Delay: 0.054077, Root dispersion: 0.058944, Reference-ID: 216.229.0.50
          Reference Timestamp:  3622132887.136984840 (2014/10/12 20:01:27)
          Originator Timestamp: 3622133561.726278364 (2014/10/12 20:12:41)
          Receive Timestamp:    3622133618.830113530 (2014/10/12 20:13:38)
          Transmit Timestamp:   3622133618.830129086 (2014/10/12 20:13:38)
            Originator - Receive Timestamp:  +57.103835195
            Originator - Transmit Timestamp: +57.103850722

1. 基本语法和使用方法

tcpdump 的常用参数如下:

$ tcpdump -i eth0 -nn -s0 -v port 80
  • -i : 选择要捕获的接口,通常是以太网卡或无线网卡,也可以是 vlan 或其他特殊接口。如果该系统上只有一个网络接口,则无需指定。
  • -nn : 单个 n 表示不解析域名,直接显示 IP;两个 n 表示不解析域名和端口。这样不仅方便查看 IP 和端口号,而且在抓取大量数据时非常高效,因为域名解析会降低抓取速度。
  • -s0 : tcpdump 默认只会截取前 96 字节的内容,要想截取所有的报文内容,可以使用 -s numbernumber 就是你要截取的报文字节数,如果是 0 的话,表示截取报文全部内容。
  • -v : 使用 -v-vv-vvv 来显示更多的详细信息,通常会显示更多与特定协议相关的信息。
  • port 80 : 这是一个常见的端口过滤器,表示仅抓取 80 端口上的流量,通常是 HTTP。

额外再介绍几个常用参数:

  • -p : 不让网络接口进入混杂模式。默认情况下使用 tcpdump 抓包时,会让网络接口进入混杂模式。一般计算机网卡都工作在非混杂模式下,此时网卡只接受来自网络端口的目的地址指向自己的数据。当网卡工作在混杂模式下时,网卡将来自接口的所有数据都捕获并交给相应的驱动程序。如果设备接入的交换机开启了混杂模式,使用 -p 选项可以有效地过滤噪声。
  • -e : 显示数据链路层信息。默认情况下 tcpdump 不会显示数据链路层信息,使用 -e 选项可以显示源和目的 MAC 地址,以及 VLAN tag 信息。例如:
$ tcpdump -n -e -c 5 not ip6

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on br-lan, link-type EN10MB (Ethernet), capture size 262144 bytes
18:27:53.619865 24:5e:be:0c:17:af > 00:e2:69:23:d3:3b, ethertype IPv4 (0x0800), length 1162: 192.168.100.20.51410 > 180.176.26.193.58695: Flags [.], seq 2045333376:2045334484, ack 3398690514, win 751, length 1108
18:27:53.626490 00:e2:69:23:d3:3b > 24:5e:be:0c:17:af, ethertype IPv4 (0x0800), length 68: 220.173.179.66.36017 > 192.168.100.20.51410: UDP, length 26
18:27:53.626893 24:5e:be:0c:17:af > 00:e2:69:23:d3:3b, ethertype IPv4 (0x0800), length 1444: 192.168.100.20.51410 > 220.173.179.66.36017: UDP, length 1402
18:27:53.628837 00:e2:69:23:d3:3b > 24:5e:be:0c:17:af, ethertype IPv4 (0x0800), length 1324: 46.97.169.182.6881 > 192.168.100.20.59145: Flags [P.], seq 3058450381:3058451651, ack 14349180, win 502, length 1270
18:27:53.629096 24:5e:be:0c:17:af > 00:e2:69:23:d3:3b, ethertype IPv4 (0x0800), length 54: 192.168.100.20.59145 > 192.168.100.1.12345: Flags [.], ack 3058451651, win 6350, length 0
5 packets captured

显示 ASCII 字符串

-A 表示使用 ASCII 字符串打印报文的全部数据,这样可以使读取更加简单,方便使用 grep 等工具解析输出内容。-X 表示同时使用十六进制和 ASCII 字符串打印报文的全部数据。这两个参数不能一起使用。例如:

$ tcpdump -A -s0 port 80

抓取特定协议的数据

后面可以跟上协议名称来过滤特定协议的流量,以 UDP 为例,可以加上参数 udp 或 protocol 17,这两个命令意思相同。

$ tcpdump -i eth0 udp
$ tcpdump -i eth0 proto 17

同理,tcp 与 protocol 6 意思相同。

抓取特定主机的数据

使用过滤器 host 可以抓取特定目的地和源 IP 地址的流量。

$ tcpdump -i eth0 host 10.10.1.1

也可以使用 srcdst 只抓取源或目的地:

$ tcpdump -i eth0 dst 10.10.1.20

将抓取的数据写入文件

使用 tcpdump 截取数据报文的时候,默认会打印到屏幕的默认输出,你会看到按照顺序和格式,很多的数据一行行快速闪过,根本来不及看清楚所有的内容。不过,tcpdump 提供了把截取的数据保存到文件的功能,以便后面使用其他图形工具(比如 wireshark,Snort)来分析。

-w 选项用来把数据报文输出到文件:

$ tcpdump -i eth0 -s0 -w test.pcap

行缓冲模式

如果想实时将抓取到的数据通过管道传递给其他工具来处理,需要使用 -l 选项来开启行缓冲模式(或使用 -c 选项来开启数据包缓冲模式)。使用 -l 选项可以将输出通过立即发送给其他命令,其他命令会立即响应。

$ tcpdump -i eth0 -s0 -l port 80 | grep 'Server:'

组合过滤器

过滤的真正强大之处在于你可以随意组合它们,而连接它们的逻辑就是常用的 与/AND/&&或/OR/||非/not/!

and or &&
or or ||
not or !

2. 过滤器

关于 tcpdump 的过滤器,这里有必要单独介绍一下。

机器上的网络报文数量异常的多,很多时候我们只关系和具体问题有关的数据报(比如访问某个网站的数据,或者 icmp 超时的报文等等),而这些数据只占到很小的一部分。把所有的数据截取下来,从里面找到想要的信息无疑是一件很费时费力的工作。而 tcpdump 提供了灵活的语法可以精确地截取关心的数据报,简化分析的工作量。这些选择数据包的语句就是过滤器(filter)!

Host 过滤器

Host 过滤器用来过滤某个主机的数据报文。例如:

$ tcpdump host 1.2.3.4

该命令会抓取所有发往主机 1.2.3.4 或者从主机 1.2.3.4 发出的流量。如果想只抓取从该主机发出的流量,可以使用下面的命令:

$ tcpdump src host 1.2.3.4

Network 过滤器

Network 过滤器用来过滤某个网段的数据,使用的是 CIDR 模式。可以使用四元组(x.x.x.x)、三元组(x.x.x)、二元组(x.x)和一元组(x)。四元组就是指定某个主机,三元组表示子网掩码为 255.255.255.0,二元组表示子网掩码为 255.255.0.0,一元组表示子网掩码为 255.0.0.0。例如,

抓取所有发往网段 192.168.1.x 或从网段 192.168.1.x 发出的流量:

$ tcpdump net 192.168.1

抓取所有发往网段 10.x.x.x 或从网段 10.x.x.x 发出的流量:

$ tcpdump net 10

和 Host 过滤器一样,这里也可以指定源和目的:

$ tcpdump src net 10

也可以使用 CIDR 格式:

$ tcpdump src net 172.16.0.0/12

Proto 过滤器

Proto 过滤器用来过滤某个协议的数据,关键字为 proto,可省略。proto 后面可以跟上协议号或协议名称,支持 icmp, igmp, igrp, pim, ah, esp, carp, vrrp, udp tcp。因为通常的协议名称是保留字段,所以在于 proto 指令一起使用时,必须根据 shell 类型使用一个或两个反斜杠(/)来转义。Linux 中的 shell 需要使用两个反斜杠来转义,MacOS 只需要一个。

例如,抓取 icmp 协议的报文:

$ tcpdump -n proto \\icmp
# 或者
$ tcpdump -n icmp

Port 过滤器

Port 过滤器用来过滤通过某个端口的数据报文,关键字为 port。例如:

$ tcpdump port 389

3. 理解 tcpdump 的输出

截取数据只是第一步,第二步就是理解这些数据,下面就解释一下 tcpdump 命令输出各部分的意义。

21:27:06.995846 IP (tos 0x0, ttl 64, id 45646, offset 0, flags [DF], proto TCP (6), length 64)
    192.168.1.106.56166 > 124.192.132.54.80: Flags [S], cksum 0xa730 (correct), seq 992042666, win 65535, options [mss 1460,nop,wscale 4,nop,nop,TS val 663433143 ecr 0,sackOK,eol], length 0

21:27:07.030487 IP (tos 0x0, ttl 51, id 0, offset 0, flags [DF], proto TCP (6), length 44)
    124.192.132.54.80 > 192.168.1.106.56166: Flags [S.], cksum 0xedc0 (correct), seq 2147006684, ack 992042667, win 14600, options [mss 1440], length 0

21:27:07.030527 IP (tos 0x0, ttl 64, id 59119, offset 0, flags [DF], proto TCP (6), length 40)
    192.168.1.106.56166 > 124.192.132.54.80: Flags [.], cksum 0x3e72 (correct), ack 2147006685, win 65535, length 0

最基本也是最重要的信息就是数据报的源地址/端口和目的地址/端口,上面的例子第一条数据报中,源地址 ip 是 192.168.1.106,源端口是 56166,目的地址是 124.192.132.54,目的端口是 80> 符号代表数据的方向。

此外,上面的三条数据还是 tcp 协议的三次握手过程,第一条就是 SYN 报文,这个可以通过 Flags [S] 看出。下面是常见的 TCP 报文的 Flags:

  • [S] : SYN(开始连接)
  • [.] : 没有 Flag
  • [P] : PSH(推送数据)
  • [F] : FIN (结束连接)
  • [R] : RST(重置连接)

而第二条数据的 [S.] 表示 SYN-ACK,就是 SYN 报文的应答报文。

4. 例子

下面给出一些具体的例子,每个例子都可以使用多种方法来获得相同的输出,你使用的方法取决于所需的输出和网络上的流量。我们在排障时,通常只想获取自己想要的内容,可以通过过滤器和 ASCII 输出并结合管道与 grep、cut、awk 等工具来实现此目的。

例如,在抓取 HTTP 请求和响应数据包时,可以通过删除标志 SYN/ACK/FIN 来过滤噪声,但还有更简单的方法,那就是通过管道传递给 grep。在达到目的的同时,我们要选择最简单最高效的方法。下面来看例子。

提取 HTTP 用户代理

从 HTTP 请求头中提取 HTTP 用户代理:

$ tcpdump -nn -A -s1500 -l | grep "User-Agent:"

通过 egrep 可以同时提取用户代理和主机名(或其他头文件):

$ tcpdump -nn -A -s1500 -l | egrep -i 'User-Agent:|Host:'

只抓取 HTTP GET 和 POST 流量

抓取 HTTP GET 流量:

$ tcpdump -s 0 -A -vv 'tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420'

也可以抓取 HTTP POST 请求流量:

$ tcpdump -s 0 -A -vv 'tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x504f5354'

注意:该方法不能保证抓取到 HTTP POST 有效数据流量,因为一个 POST 请求会被分割为多个 TCP 数据包。

上述两个表达式中的十六进制将会与 GET 和 POST 请求的 ASCII 字符串匹配。例如,tcp[((tcp[12:1] & 0xf0) >> 2):4] 首先会 确定我们感兴趣的字节的位置(在 TCP header 之后),然后选择我们希望匹配的 4 个字节。

提取 HTTP 请求的 URL

提取 HTTP 请求的主机名和路径:

$ tcpdump -s 0 -v -n -l | egrep -i "POST /|GET /|Host:"

tcpdump: listening on enp7s0, link-type EN10MB (Ethernet), capture size 262144 bytes
	POST /wp-login.php HTTP/1.1
	Host: dev.example.com
	GET /wp-login.php HTTP/1.1
	Host: dev.example.com
	GET /favicon.ico HTTP/1.1
	Host: dev.example.com
	GET / HTTP/1.1
	Host: dev.example.com

提取 HTTP POST 请求中的密码

从 HTTP POST 请求中提取密码和主机名:

$ tcpdump -s 0 -A -n -l | egrep -i "POST /|pwd=|passwd=|password=|Host:"

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on enp7s0, link-type EN10MB (Ethernet), capture size 262144 bytes
11:25:54.799014 IP 10.10.1.30.39224 > 10.10.1.125.80: Flags [P.], seq 1458768667:1458770008, ack 2440130792, win 704, options [nop,nop,TS val 461552632 ecr 208900561], length 1341: HTTP: POST /wp-login.php HTTP/1.1
.....s..POST /wp-login.php HTTP/1.1
Host: dev.example.com
.....s..log=admin&pwd=notmypassword&wp-submit=Log+In&redirect_to=http%3A%2F%2Fdev.example.com%2Fwp-admin%2F&testcookie=1

提取 Cookies

提取 Set-Cookie(服务端的 Cookie)和 Cookie(客户端的 Cookie):

$ tcpdump -nn -A -s0 -l | egrep -i 'Set-Cookie|Host:|Cookie:'

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on wlp58s0, link-type EN10MB (Ethernet), capture size 262144 bytes
Host: dev.example.com
Cookie: wordpress_86be02xxxxxxxxxxxxxxxxxxxc43=admin%7C152xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxfb3e15c744fdd6; _ga=GA1.2.21343434343421934; _gid=GA1.2.927343434349426; wordpress_test_cookie=WP+Cookie+check; wordpress_logged_in_86be654654645645645654645653fc43=admin%7C15275102testtesttesttestab7a61e; wp-settings-time-1=1527337439

抓取 ICMP 数据包

查看网络上的所有 ICMP 数据包:

$ tcpdump -n icmp

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on enp7s0, link-type EN10MB (Ethernet), capture size 262144 bytes
11:34:21.590380 IP 10.10.1.217 > 10.10.1.30: ICMP echo request, id 27948, seq 1, length 64
11:34:21.590434 IP 10.10.1.30 > 10.10.1.217: ICMP echo reply, id 27948, seq 1, length 64
11:34:27.680307 IP 10.10.1.159 > 10.10.1.1: ICMP 10.10.1.189 udp port 59619 unreachable, length 115

抓取非 ECHO/REPLY 类型的 ICMP 数据包

通过排除 echo 和 reply 类型的数据包使抓取到的数据包不包括标准的 ping 包:

$ tcpdump 'icmp[icmptype] != icmp-echo and icmp[icmptype] != icmp-echoreply'

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on enp7s0, link-type EN10MB (Ethernet), capture size 262144 bytes
11:37:04.041037 IP 10.10.1.189 > 10.10.1.20: ICMP 10.10.1.189 udp port 36078 unreachable, length 156

抓取 SMTP/POP3 协议的邮件

可以提取电子邮件的正文和其他数据。例如,只提取电子邮件的收件人:

$ tcpdump -nn -l port 25 | grep -i 'MAIL FROM\|RCPT TO'

抓取 NTP 服务的查询和响应

$ tcpdump dst port 123

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
21:02:19.112502 IP test33.ntp > 199.30.140.74.ntp: NTPv4, Client, length 48
21:02:19.113888 IP 216.239.35.0.ntp > test33.ntp: NTPv4, Server, length 48
21:02:20.150347 IP test33.ntp > 216.239.35.0.ntp: NTPv4, Client, length 48
21:02:20.150991 IP 216.239.35.0.ntp > test33.ntp: NTPv4, Server, length 48

抓取 SNMP 服务的查询和响应

通过 SNMP 服务,渗透测试人员可以获取大量的设备和系统信息。在这些信息中,系统信息最为关键,如操作系统版本、内核版本等。使用 SNMP 协议快速扫描程序 onesixtyone,可以看到目标系统的信息:

$ onesixtyone 10.10.1.10 public

Scanning 1 hosts, 1 communities
10.10.1.10 [public] Linux test33 4.15.0-20-generic #21-Ubuntu SMP Tue Apr 24 06:16:15 UTC 2018 x86_64

可以通过 tcpdump 抓取 GetRequestGetResponse

$ tcpdump -n -s0  port 161 and udp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on wlp58s0, link-type EN10MB (Ethernet), capture size 262144 bytes
23:39:13.725522 IP 10.10.1.159.36826 > 10.10.1.20.161:  GetRequest(28)  .1.3.6.1.2.1.1.1.0
23:39:13.728789 IP 10.10.1.20.161 > 10.10.1.159.36826:  GetResponse(109)  .1.3.6.1.2.1.1.1.0="Linux testmachine 4.15.0-20-generic #21-Ubuntu SMP Tue Apr 24 06:16:15 UTC 2018 x86_64"

切割 pcap 文件

当抓取大量数据并写入文件时,可以自动切割为多个大小相同的文件。例如,下面的命令表示每 3600 秒创建一个新文件 capture-(hour).pcap,每个文件大小不超过 200*1000000 字节:

$ tcpdump  -w /tmp/capture-%H.pcap -G 3600 -C 200

这些文件的命名为 capture-{1-24}.pcap,24 小时之后,之前的文件就会被覆盖。

抓取 IPv6 流量

可以通过过滤器 ip6 来抓取 IPv6 流量,同时可以指定协议如 TCP:

$ tcpdump -nn ip6 proto 6

从之前保存的文件中读取 IPv6 UDP 数据报文:

$ tcpdump -nr ipv6-test.pcap ip6 proto 17

检测端口扫描

在下面的例子中,你会发现抓取到的报文的源和目的一直不变,且带有标志位 [S][R],它们与一系列看似随机的目标端口进行匹配。当发送 SYN 之后,如果目标主机的端口没有打开,就会返回一个 RESET。这是 Nmap 等端口扫描工具的标准做法。

$ tcpdump -nn

21:46:19.693601 IP 10.10.1.10.60460 > 10.10.1.199.5432: Flags [S], seq 116466344, win 29200, options [mss 1460,sackOK,TS val 3547090332 ecr 0,nop,wscale 7], length 0
21:46:19.693626 IP 10.10.1.10.35470 > 10.10.1.199.513: Flags [S], seq 3400074709, win 29200, options [mss 1460,sackOK,TS val 3547090332 ecr 0,nop,wscale 7], length 0
21:46:19.693762 IP 10.10.1.10.44244 > 10.10.1.199.389: Flags [S], seq 2214070267, win 29200, options [mss 1460,sackOK,TS val 3547090333 ecr 0,nop,wscale 7], length 0
21:46:19.693772 IP 10.10.1.199.389 > 10.10.1.10.44244: Flags [R.], seq 0, ack 2214070268, win 0, length 0
21:46:19.693783 IP 10.10.1.10.35172 > 10.10.1.199.1433: Flags [S], seq 2358257571, win 29200, options [mss 1460,sackOK,TS val 3547090333 ecr 0,nop,wscale 7], length 0
21:46:19.693826 IP 10.10.1.10.33022 > 10.10.1.199.49153: Flags [S], seq 2406028551, win 29200, options [mss 1460,sackOK,TS val 3547090333 ecr 0,nop,wscale 7], length 0
21:46:19.695567 IP 10.10.1.10.55130 > 10.10.1.199.49154: Flags [S], seq 3230403372, win 29200, options [mss 1460,sackOK,TS val 3547090334 ecr 0,nop,wscale 7], length 0
21:46:19.695590 IP 10.10.1.199.49154 > 10.10.1.10.55130: Flags [R.], seq 0, ack 3230403373, win 0, length 0
21:46:19.695608 IP 10.10.1.10.33460 > 10.10.1.199.49152: Flags [S], seq 3289070068, win 29200, options [mss 1460,sackOK,TS val 3547090335 ecr 0,nop,wscale 7], length 0
21:46:19.695622 IP 10.10.1.199.49152 > 10.10.1.10.33460: Flags [R.], seq 0, ack 3289070069, win 0, length 0
21:46:19.695637 IP 10.10.1.10.34940 > 10.10.1.199.1029: Flags [S], seq 140319147, win 29200, options [mss 1460,sackOK,TS val 3547090335 ecr 0,nop,wscale 7], length 0
21:46:19.695650 IP 10.10.1.199.1029 > 10.10.1.10.34940: Flags [R.], seq 0, ack 140319148, win 0, length 0
21:46:19.695664 IP 10.10.1.10.45648 > 10.10.1.199.5060: Flags [S], seq 2203629201, win 29200, options [mss 1460,sackOK,TS val 3547090335 ecr 0,nop,wscale 7], length 0
21:46:19.695775 IP 10.10.1.10.49028 > 10.10.1.199.2000: Flags [S], seq 635990431, win 29200, options [mss 1460,sackOK,TS val 3547090335 ecr 0,nop,wscale 7], length 0
21:46:19.695790 IP 10.10.1.199.2000 > 10.10.1.10.49028: Flags [R.], seq 0, ack 635990432, win 0, length 0

过滤 Nmap NSE 脚本测试结果

本例中 Nmap NSE 测试脚本 http-enum.nse 用来检测 HTTP 服务的合法 URL。

在执行脚本测试的主机上:

$ nmap -p 80 --script=http-enum.nse targetip

在目标主机上:

$ tcpdump -nn port 80 | grep "GET /"

GET /w3perl/ HTTP/1.1
GET /w-agora/ HTTP/1.1
GET /way-board/ HTTP/1.1
GET /web800fo/ HTTP/1.1
GET /webaccess/ HTTP/1.1
GET /webadmin/ HTTP/1.1
GET /webAdmin/ HTTP/1.1

抓取 DNS 请求和响应

向 Google 公共 DNS 发起的出站 DNS 请求和 A 记录响应可以通过 tcpdump 抓取到:

$ tcpdump -i wlp58s0 -s0 port 53

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on wlp58s0, link-type EN10MB (Ethernet), capture size 262144 bytes
14:19:06.879799 IP test.53852 > google-public-dns-a.google.com.domain: 26977+ [1au] A? play.google.com. (44)
14:19:07.022618 IP google-public-dns-a.google.com.domain > test.53852: 26977 1/0/1 A 216.58.203.110 (60)

抓取 HTTP 有效数据包

抓取 80 端口的 HTTP 有效数据包,排除 TCP 连接建立过程的数据包(SYN / FIN / ACK):

$ tcpdump 'tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)'

将输出内容重定向到 Wireshark

通常 Wireshark(或 tshark)比 tcpdump 更容易分析应用层协议。一般的做法是在远程服务器上先使用 tcpdump 抓取数据并写入文件,然后再将文件拷贝到本地工作站上用 Wireshark 分析。

还有一种更高效的方法,可以通过 ssh 连接将抓取到的数据实时发送给 Wireshark 进行分析。以 MacOS 系统为例,可以通过 brew cask install wireshark 来安装,然后通过下面的命令来分析:

$ ssh root@remotesystem 'tcpdump -s0 -c 1000 -nn -w - not port 22' | /Applications/Wireshark.app/Contents/MacOS/Wireshark -k -i -

例如,如果想分析 DNS 协议,可以使用下面的命令:

$ ssh root@remotesystem 'tcpdump -s0 -c 1000 -nn -w - port 53' | /Applications/Wireshark.app/Contents/MacOS/Wireshark -k -i -

抓取到的数据:

tcpdump 详细使用指南(请尽情食用)_第2张图片

-c 选项用来限制抓取数据的大小。如果不限制大小,就只能通过 ctrl-c 来停止抓取,这样一来不仅关闭了 tcpdump,也关闭了 wireshark。

找出发包最多的 IP

找出一段时间内发包最多的 IP,或者从一堆报文中找出发包最多的 IP,可以使用下面的命令:

$ tcpdump -nnn -t -c 200 | cut -f 1,2,3,4 -d '.' | sort | uniq -c | sort -nr | head -n 20

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on enp7s0, link-type EN10MB (Ethernet), capture size 262144 bytes
200 packets captured
261 packets received by filter
0 packets dropped by kernel
    108 IP 10.10.211.181
     91 IP 10.10.1.30
      1 IP 10.10.1.50
  • cut -f 1,2,3,4 -d ‘.’ : 以 . 为分隔符,打印出每行的前四列。即 IP 地址。
  • sort | uniq -c : 排序并计数
  • sort -nr : 按照数值大小逆向排序

抓取用户名和密码

本例将重点放在标准纯文本协议上,过滤出于用户名和密码相关的报文:

$ tcpdump port http or port ftp or port smtp or port imap or port pop3 or port telnet -l -A | egrep -i -B5 'pass=|pwd=|log=|login=|user=|username=|pw=|passw=|passwd=|password=|pass:|user:|username:|password:|login:|pass |user '

抓取 DHCP 报文

最后一个例子,抓取 DHCP 服务的请求和响应报文,67 为 DHCP 端口,68 为客户机端口。

$ tcpdump -v -n port 67 or 68

tcpdump: listening on enp7s0, link-type EN10MB (Ethernet), capture size 262144 bytes
14:37:50.059662 IP (tos 0x10, ttl 128, id 0, offset 0, flags [none], proto UDP (17), length 328)
    0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 00:0c:xx:xx:xx:d5, length 300, xid 0xc9779c2a, Flags [none]
	  Client-Ethernet-Address 00:0c:xx:xx:xx:d5
	  Vendor-rfc1048 Extensions
	    Magic Cookie 0x63825363
	    DHCP-Message Option 53, length 1: Request
	    Requested-IP Option 50, length 4: 10.10.1.163
	    Hostname Option 12, length 14: "test-ubuntu"
	    Parameter-Request Option 55, length 16: 
	      Subnet-Mask, BR, Time-Zone, Default-Gateway
	      Domain-Name, Domain-Name-Server, Option 119, Hostname
	      Netbios-Name-Server, Netbios-Scope, MTU, Classless-Static-Route
	      NTP, Classless-Static-Route-Microsoft, Static-Route, Option 252
14:37:50.059667 IP (tos 0x10, ttl 128, id 0, offset 0, flags [none], proto UDP (17), length 328)
    0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 00:0c:xx:xx:xx:d5, length 300, xid 0xc9779c2a, Flags [none]
	  Client-Ethernet-Address 00:0c:xx:xx:xx:d5
	  Vendor-rfc1048 Extensions
	    Magic Cookie 0x63825363
	    DHCP-Message Option 53, length 1: Request
	    Requested-IP Option 50, length 4: 10.10.1.163
	    Hostname Option 12, length 14: "test-ubuntu"
	    Parameter-Request Option 55, length 16: 
	      Subnet-Mask, BR, Time-Zone, Default-Gateway
	      Domain-Name, Domain-Name-Server, Option 119, Hostname
	      Netbios-Name-Server, Netbios-Scope, MTU, Classless-Static-Route
	      NTP, Classless-Static-Route-Microsoft, Static-Route, Option 252
14:37:50.060780 IP (tos 0x0, ttl 64, id 53564, offset 0, flags [none], proto UDP (17), length 339)
    10.10.1.1.67 > 10.10.1.163.68: BOOTP/DHCP, Reply, length 311, xid 0xc9779c2a, Flags [none]
	  Your-IP 10.10.1.163
	  Server-IP 10.10.1.1
	  Client-Ethernet-Address 00:0c:xx:xx:xx:d5
	  Vendor-rfc1048 Extensions
	    Magic Cookie 0x63825363
	    DHCP-Message Option 53, length 1: ACK
	    Server-ID Option 54, length 4: 10.10.1.1
	    Lease-Time Option 51, length 4: 86400
	    RN Option 58, length 4: 43200
	    RB Option 59, length 4: 75600
	    Subnet-Mask Option 1, length 4: 255.255.255.0
	    BR Option 28, length 4: 10.10.1.255
	    Domain-Name-Server Option 6, length 4: 10.10.1.1
	    Hostname Option 12, length 14: "test-ubuntu"
	    T252 Option 252, length 1: 10
	    Default-Gateway Option 3, length 4: 10.10.1.1

5. 总结

本文主要介绍了 tcpdump 的基本语法和使用方法,并通过一些示例来展示它强大的过滤功能。将 tcpdump 与 wireshark 进行组合可以发挥更强大的功效,本文也展示了如何优雅顺滑地结合 tcpdump 和 wireshark。如果你想了解更多的细节,可以查看 tcpdump 的 man 手册。

你可能感兴趣的:(k8s排错及配置,linux工具,环境配置,tcpdump,网络,linux)