Contents

Linux中使用TCPDUMP嗅探数据包

1. 概述

在本文中,我们将研究Linux 中的工具tcpdump。特别是,我们将学习如何在 Linux 环境中使用tcpdump捕获网络数据包。

2. tcpdump

2.1. tcpdump简介

tcpdump 是 Linux 中的网络数据包嗅探器工具。本质上,它在接口上侦听并转储通过该接口的任何数据包。通过转储,我们将能够更深入地了解通过节点的数据包。

2.2. 安装

要在基于 Debian 的 Linux(例如 Ubuntu)中安装tcpdump ,我们可以使用apt-get 命令:

$ sudo apt-get update
$ sudo apt-get install -y tcpdump

或者,我们可以在 CentOS 等基于 RHEL 的 Linux 上使用yum执行安装:

$ sudo yum update
$ sudo yum install -y tcpdump

2.3. 一般语法

通常,tcpdump的语法可以表示为命令后跟选项列表和表达式:

tcpdump [OPTIONS] [expression]

OPTIONS参数是一个可选的标志列表,我们可以指定这些标志来改变tcpdump的不同方面。此外,expression是一个强大的结构,允许用户通过不同的属性进一步过滤数据包。

2.4. 基本用法

让我们使用默认配置运行tcpdump ,不带任何标志或表达式:

$ tcpdump
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
10:33:18.583077 IP 927e94ccde39.54226 > 192.168.65.4.53: 39122+ AAAA? www.blogdemo.com. (34)
10:33:18.583082 IP 927e94ccde39.36545 > 192.168.65.4.53: 53932+ A? www.blogdemo.com. (34)
10:33:18.583450 IP 927e94ccde39.38845 > 192.168.65.4.53: 61341+ PTR? 4.65.168.192.in-addr.arpa. (43)
10:33:18.623951 IP 192.168.65.4.53 > 927e94ccde39.36545: 53932 3/0/0 A 104.26.12.74, A 172.67.72.45, A 104.26.13.74 (82)
10:33:18.624004 IP 192.168.65.4.53 > 927e94ccde39.54226: 39122 3/0/0 AAAA 2606:4700:20::ac43:482d, AAAA 2606:4700:20::681a:c4a, AAAA 2606:4700:20::681a:d4a (118)
10:33:18.624381 IP 927e94ccde39.35182 > 104.26.12.74.80: Flags [S], seq 3026253548, win 64240, options [mss 1460,sackOK,TS val 3916952268 ecr 0,nop,wscale 7], length 0
10:33:18.668779 IP 104.26.12.74.80 > 927e94ccde39.35182: Flags [S.], seq 452853775, ack 3026253549, win 65535, options [mss 1460,wscale 2,eol], length 0
10:33:18.668809 IP 927e94ccde39.35182 > 104.26.12.74.80: Flags [.], ack 1, win 502, length 0
10:33:18.668873 IP 927e94ccde39.35182 > 104.26.12.74.80: Flags [P.], seq 1:81, ack 1, win 502, length 80: HTTP: GET / HTTP/1.1
10:33:18.671819 IP 104.26.12.74.80 > 927e94ccde39.35182: Flags [.], ack 81, win 65535, length 0
10:33:18.691618 IP 104.26.12.74.80 > 927e94ccde39.35182: Flags [P.], seq 1:610, ack 81, win 65535, length 609: HTTP: HTTP/1.1 301 Moved Permanently
10:33:18.691628 IP 927e94ccde39.35182 > 104.26.12.74.80: Flags [.], ack 610, win 501, length 0

当我们不指定接口时,tcpdump将监听系统接口列表中编号最低的接口。在本例中,它选择eth0作为监听接口。然后,它捕获并打印以控制通过接口的任何数据包。

从输出中,我们可以看到每一行中网络数据包的详细信息。让我们更深入地研究一个示例数据包转储:

10:33:18.583077 IP 927e94ccde39.54226 > 192.168.65.4.53: 39122+ AAAA? www.blogdemo.com. (34)

从输出中,我们可以确定捕获此数据包的时间。除此之外,我们知道这个数据包是一个IP数据包,因为协议显示在时间戳旁边。

此外,我们从转储中得知此数据包源自端口54226上的主机927e94ccde39,并且它正向端口53上的**192.168.65.4发送。

3. 网络接口选项

3.1. 列出系统接口

我们可以使用*-D*标志查询系统上可用的接口列表 :

$ tcpdump -D
1.eth0 [Up, Running]
2.eth1 [Up, Running]
3.lo [Up, Running, Loopback]
4.any (Pseudo-device that captures on all interfaces) [Up, Running]
5.bluetooth-monitor (Bluetooth Linux Monitor) [none]
6.nflog (Linux netfilter log (NFLOG) interface) [none]
7.nfqueue (Linux netfilter queue (NFQUEUE) interface) [none]
8.tunl0 [none]
9.ip6tnl0 [none]

正如我们所见,tcpdump还显示了每个接口的状态。除了实际的网络接口之外,tcpdump还创建了一个名为*“any”的伪设备。**通过侦听这个伪设备any*,tcpdump将捕获通过所有接口的数据包。**

3.2. 指定接口

在具有多个接口的系统上,我们可以使用*-i*标志选择要收听的接口

$ tcpdump -i wlan0

上面的命令在接口wlan0上启动tcpdump。此外,我们可以使用伪设备any捕获所有接口的数据包:

$ tcpdump -i any

4. 格式化时间戳

在每个数据包转储输出中,tcpdump在第一列附加一个时间戳以指示捕获数据包的时间。tcpdump支持使用*-t*标志格式化此时间戳输出。

4.1. 抑制时间戳信息

为了防止tcpdump打印任何时间戳信息,我们可以指定-t*标志*:

$ tcpdump -t
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
IP centos-box.intra.40600 > 927e94ccde39.443: Flags [P.], seq 1584919446:1584919451, ack 1644285291, win 502, options [nop,nop,TS val 1654074382 ecr 2691638716], length 5
IP 927e94ccde39.443 > centos-box.intra.40600: Flags [.], ack 5, win 510, options [nop,nop,TS val 2693653313 ecr 1654074382], length 0

4.2. 以纪元时间打印时间戳

我们还可以使用*-tt*标志在纪元(1970 年 1 月 1 日 00:00:00 UTC)之后以秒为单位打印时间戳:

$ tcpdump -tt
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), capture size 262144 bytes
1615623341.099481 IP centos-box.intra.40600 > 927e94ccde39.443: Flags [P.], seq 1584919451:1584919456, ack 1644285291, win 502, options [nop,nop,TS val 1654246252 ecr 2693653313], length 5
1615623341.099494 IP 927e94ccde39.443 > centos-box.intra.40600: Flags [.], ack 5, win 510, options [nop,nop,TS val 2693825183 ecr 1654246252], length 0

从输出中,我们可以观察到时间戳分辨率下降到微秒级别。

4.3. 在时间增量中打印时间戳

我们可以使用*-ttt*标志根据增量输出时间戳。具体来说,tcpdump将在每一行打印当前转储和上一个转储之间的时间差:

$ tcpdump -ttt
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), capture size 262144 bytes
 00:00:00.000000 IP centos-box.intra.40600 > 927e94ccde39.443: Flags [P.], seq 1584919456:1584919461, ack 1644285291, win 502, options [nop,nop,TS val 1654379130 ecr 2693825183], length 5
 00:00:00.000014 IP 927e94ccde39.443 > centos-box.intra.40600: Flags [.], ack 5, win 510, options [nop,nop,TS val 2693958061 ecr 1654379130], length 0

在上面的示例中,我们可以很容易地推断出第一个和第二个数据包之间的时间差为 14 微秒。

4.4. 打印带日期的时间戳

最后,我们可以使用*-tttt*标志打印时间戳和日期:

$ tcpdump -tttt
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), capture size 262144 bytes
2021-03-13 08:20:05.370345 IP centos-box.intra.40600 > 927e94ccde39.443: Flags [P.], seq 1584919461:1584919466, ack 1644285291, win 502, options [nop,nop,TS val 1654510522 ecr 2693958061], length 5
2021-03-13 08:20:05.370400 IP 927e94ccde39.443 > centos-box.intra.40600: Flags [.], ack 5, win 510, options [nop,nop,TS val 2694089454 ecr 1654510522], length 0

5. 将数据包转储保存到文件

tcpdump还提供了几个标志,允许我们将数据包转储写入文件。

5.1. 写入文件

要将数据包转储写入文件,我们可以使用标志-w*后跟文件名*:

$ tcpdump -w packet-captured.pcap

当我们将转储写入文件时,tcpdump将不再将转储打印到标准输出。

5.2. 限制每个文件的大小

我们可以使用-C*标志限制每个文件的大小*。该标志接受一个整数值,表示每个文件的大小限制(以百万字节为单位):

$ tcpdump -w out.pcap -C 2

在上面的示例中,tcpdump会将捕获的数据包写入文件out.pcap中。一旦文件大小达到 2MB,此后每增加 2MB,它会将后续数据包保存到新文件out.pcap1out.pcap2out.pcap3等中。

5.3. 按时间间隔旋转保存文件

使用-G*标志,tcpdump以指定的时间间隔将转储保存到新文件中*。例如,我们可以每五秒轮换一次保存文件:

$ tcpdump -w out-%Y%m%d-%H%M%S.pcap -G 5

在上面的示例中,我们根据strftime 格式动态命名我们的文件。如果文件名指定为每个指定时间间隔不变,则先前的保存文件将被覆盖

6. 以监控模式运行

在 IEEE 802.11 WiFi 接口上,监控模式 允许接口捕获在无线通道上接收到的所有数据包。此外,它甚至可以在不关联或链接到特定接入点的情况下嗅探数据包。

要在监控模式下的接口上运行tcpdump ,我们可以使用-I*标志*:

$ tcpdump -I

但是,请注意并非所有接口都支持监控模式。如果我们尝试在不支持它的接口上运行监控模式,tcpdump将输出一条错误消息:

$ tcpdump -i eth0 -I
tcpdump: eth0: That device doesn't support monitor mode

7. 其他有用的选项

7.1. 抑制地址查找

默认情况下,tcpdump会自动解析主机地址的名称。这可能是不可取的,因为它会导致 DNS 查找的网络开销。我们可以使用*-n*标志抑制查找:

$ tcpdump -n

7.2. 数据包方向

tcpdump捕获接口的传入和传出流量。我们可以使用-Q标志后跟方向值inoutinout来捕获特定方向的数据包**。例如,我们可以只捕获接口eth0上的传出数据包:

$ tcpdump -i eth0 -Q out

7.3. 打印包号

我们可以使用*-#标志使tcpdump*在每个输出行中显示数据包编号:

$ tcpdump -#
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
    1  10:33:50.254707 IP 927e94ccde39.55667 > 192.168.65.4.53: 36710+ AAAA? www.blogdemo.com. (34)
    2  10:33:50.254897 IP 927e94ccde39.49841 > 192.168.65.4.53: 19808+ A? www.blogdemo.com. (34)
    3  10:33:50.255044 IP 927e94ccde39.58436 > 192.168.65.4.53: 37800+ PTR? 4.65.168.192.in-addr.arpa. (43)

正如我们所见,每条输出行现在都有一个数字。该数字按顺序运行,并提供到目前为止捕获的数据包数量的指示。

8. 表情

除了我们可以使用的无数选项标志外,tcpdump还提供了一组我们可以指定为最终参数的语法 。使用表达式,我们可以构建一个规则集,该规则集将根据数据包的属性(例如协议)过滤数据包。

8.1. 语法结构

通常,表达式由原语和限定符组成:

[qualifier...] qualifier primitive [and|or|not] [primitive...]

基元通常是 number 或 string。这些原语本身没有意义。为了赋予这些原语以意义,我们将在它们之前加上一个或多个限定词

语法中有三种不同的限定符——即typedirproto。类型限定符指定原语的类型。例如,如果原语80与类型**port一起指定,则原语值80代表端口号80type限定符的可能值为hostnetportportrange如果没有指定类型限定符,则假定值host用于表达式。

限定符dir指定数据包的方向。此限定符的一些可能值是srcdstsrc 或 dst以及src 和 dst

除此之外,限定符proto代表要匹配的数据包的协议。此限定符的可能值包括etheripip6arptcpudp

最后,语法还包含诸如andornot 之类的词,它们允许我们组合原语来构建复杂的表达式。它们的符号表示如*&&||* ,和*!*也被表达式解析器识别。

让我们看一些例子。

8.2. 按主机过滤数据包

过滤数据包的最简单方法之一是按其主机进行过滤。具体来说,我们可以使用host语法捕获与特定主机关联的数据包

$ tcpdump 'host www.blogdemo.com'

上面的命令只会转储来自或去往www.blogdemo.com 的数据包。

8.3. 按端口过滤数据包

我们还可以使用限定符端口按端口号过滤数据

$ tcpdump 'port 80'

上面的命令只捕获来自或去往端口 80 的任何数据包。此外,我们可以使用srcdst指定方向。例如,如果我们只想捕获源字段为端口 80 的数据包,我们可以在表达式前加上src

$ tcpdump 'src port 80'

除此之外,限定符portrange允许我们指定我们希望从中捕获数据包的端口号范围

$ tcpdump 'portrange 80-90'

使用上面的表达式,tcpdump捕获任何落在 80 到 90 端口范围内的数据包。

8.4. 按网络过滤数据包

使用net限定符,我们可以根据数据包所属的网络过滤数据包。例如,我们可以捕获来自192.168.0.1/16网络的数据包:

$ tcpdump 'net 192.168'

当我们省略最后两个字节时,tcpdump会自动将网络掩码*/16*应用于网络。

也可以使用掩码限定符显式指定网络掩码:

$ tcpdump 'net 192.168.0.1 mask 255.255.0.0'

这两个不同的表达式最终构造了相同的过滤器。

8.5. 按协议过滤数据包

要按协议过滤数据包,我们可以使用限定符proto后跟协议名称。例如,我们可以只转储 UDP 数据包:

$ tcpdump 'proto udp'

该工具为更常见的协议提供了一些快捷方式,例如tcpudp和 icmp。例如,上面的命令可以只用tcp表达式重写:

$ tcpdump 'udp'

8.6. 其他有用的表达方式

使用语法lessgreater,我们可以根据数据包长度过滤数据包。例如,只抓取长度小于 40 的数据包:

$ tcpdump 'less 40'

另一方面,仅捕获长度大于 40 的数据包:

$ tcpdump 'greater 40'

我们可以使用限定符inbound和 outbound按方向过滤数据包,而不是使用标志。例如,要仅捕获传入的数据包,我们可以使用 inbound语法:

$ tcpdump 'inbound'

同样,我们可以使用语法outbound只转储传出数据包:

$ tcpdump 'outbound'

8.7. 逻辑语法

tcpdump支持诸如andornot 之类的逻辑结构,这让我们可以构建更复杂的规则集。例如,我们可以构建一个过滤器,只捕获来自主机www.blogdemo.com www.google.com 的流量:

$ tcpdump 'src host www.blogdemo.com or www.google.com'

此外,我们可以构建一个过滤器,使用and运算符在端口 443 上捕获来自www.blogdemo.com 的数据包:

$ tcpdump 'host www.blogdemo.com and port 443'

最后,not运算符可用于对表达式取反。例如,我们可以捕获除来自192.168.0.1/16网络的数据包之外的所有数据包:

$ tcpdump 'not net 192.168'