纠正错误 添加实例

tcpdump

抓包工具,用于捕获和分析网络流量

补充说明

tcpdump是一个用于捕获和分析网络流量的命令行工具。它是网络管理员用于排除网络问题和安全测试的最常用的工具之一。使用tcpdump,你不仅可以捕获TCP协议的流量,还可以捕获非TCP协议的流量,如UDP,ARP或ICMP。捕获的数据包可以写入文件或标准输出。tcpdump命令的最强大的特性之一是它可以使用过滤器,只捕获你感兴趣的数据。

适用的Linux版本

tcpdump在大多数Linux发行版和macOS上默认安装。如果你的电脑没有安装tcpdump,可以通过下面方式来安装:

sudo apt install tcpdump
sudo yum install tcpdump
sudo dnf install tcpdump
sudo pacman -S tcpdump

命令语法

tcpdump [options] [proto] [dir] [type]

options 是可选参数选项,其他参数选项都属于过滤器,主要分为三类:

选项

设置不解析域名提升速度

过滤结果输出到文件

使用 tcpdump 工具抓到包后,往往需要再借助其他的工具进行分析,比如常见的 wireshark 。

而要使用wireshark ,我们得将 tcpdump 抓到的包数据生成到文件中,最后再使用 wireshark 打开它即可。

使用 -w 参数后接一个以 .pcap 后缀命令的文件名,就可以将 tcpdump 抓到的数据保存到文件中。

$ tcpdump icmp -w icmp.pcap

从文件中读取包数据

使用 -w 是写入数据到文件,而使用 -r 是从文件中读取数据。

读取后,我们照样可以使用上述的过滤器语法进行过滤分析。

$ tcpdump icmp -r all.pcap

控制详细内容的输出

控制时间的显示

显示数据包的头部

过滤指定网卡的数据包

过滤特定流向的数据包

其他常用的一些参数

对输出内容进行控制的参数

过滤规则

网络流量的数据包非常多,要抓到我们所需要的数据包,就需要我们定义一个精准的过滤器,把这些目标数据包,从巨大的数据包网络中抓取出来。所以学习抓包工具,其实就是学习如何定义过滤器的过程。

过滤器也可以简单地分为三类:

例如使用 host 就可以指定 host ip 进行过滤

$ tcpdump host 192.168.10.100

数据包的 ip 可以再细分为源ip和目标ip两种

# 根据源ip进行过滤
$ tcpdump -i eth2 src 192.168.10.100

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

可以同时使用多个过滤器,使用逻辑表达式进行拼接

举个例子,我想需要抓一个来自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 还提供了一些关键字的接口来方便我们进行判断,比如

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

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

理解 tcpdump 的输出

tcpdump 的输出格式总体上为:

系统时间 源主机.端口 > 目标主机.端口 数据包参数

以 TCP 的三次握手过程为例

06:35:05.274759 IP 172.20.20.1.58563 > 172.18.0.2.3306: Flags [S], seq 2597376001, win 65535, options [mss 1460], length 0
06:35:05.275132 IP 172.18.0.2.3306 > 172.20.20.1.58563: Flags [S.], seq 1153192404, ack 2597376002, win 29200, options [mss 1460], length 0
06:35:05.275464 IP 172.20.20.1.58563 > 172.18.0.2.3306: Flags [.], ack 1, win 65535, length 0

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

  1. 第一列:时分秒毫秒 06:35:05.274759
  2. 第二列:网络协议 IP
  3. 第三列:发送方的 ip 地址+端口号,其中 172.20.20.1 是 ip,而 58563 是端口号
  4. 第四列:箭头 >, 表示数据流向
  5. 第五列:接收方的 ip 地址+端口号,其中 172.18.0.2 是 ip,而 3306 是端口号
  6. 第六列:冒号
  7. 第七列:数据包内容,包括 Flags 标识符,seq 号,ack 号,win 窗口,数据长度 length 等

常见的 TCP 报文 Flags有以下几种:

示例

抓取某主机的数据包

抓取主机 172.18.82.173 上所有收到(DST_IP)和发出(SRC_IP)的所有数据包

tcpdump host 172.18.82.173

抓取经过指定网口 interface ,并且 DST_IP 或 SRC_IP 是 172.18.82.173 的数据包

tcpdump -i eth0 host 172.18.82.173

筛选 SRC_IP,抓取经过 interface 且从 172.18.82.173 发出的包

tcpdump -i eth0 src host 172.18.82.173

筛选 DST_IP,抓取经过 interface 且发送到 172.18.82.173 的包

tcpdump -i eth0 dst host 172.18.82.173

抓取主机 200.200.200.1 和主机 200.200.200.2 或 200.200.200.3 通信的包

tcpdump host 200.200.200.1 and \(200.200.200.2 or 200.200.200.3\)

抓取主机 200.200.200.1 和除了主机 200.200.200.2 之外所有主机通信的包

tcpdump ip host 200.200.200.1 and ! 200.200.200.2

抓取某端口的数据包

抓取所有端口,显示 IP 地址

tcpdump -nS

抓取某端口上的包

tcpdump port 22

抓取经过指定 interface,并且 DST_PORT 或 SRC_PORT 是 22 的数据包

tcpdump -i eth0 port 22

筛选 SRC_PORT

tcpdump -i eth0 src port 22

筛选 DST_PORT

tcpdump -i eth0 dst port 22

比如希望查看发送到 host 172.18.82.173 的网口 eth0 的 22 号端口的包

[root@by ~]# tcpdump -i eth0 -nnt dst host 172.18.82.173 and port 22 -c 1 -vv
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
IP (tos 0x14, ttl 114, id 27674, offset 0, flags [DF], proto TCP (6), length 40)
    113.98.59.61.51830 > 172.18.82.173.22: Flags [.], cksum 0x7fe3 (correct), seq 19775964, ack 1564316089, win 2053, length 0

抓取某网络(网段)的数据包

抓取经过指定 interface,并且 DST_NET 或 SRC_NET 是 172.18.82 的包

tcpdump -i eth0 net 172.18.82

筛选 SRC_NET

tcpdump -i eth0 src net 172.18.82

筛选 DST_NET

tcpdump -i eth0 dst net 172.18.82

抓取某协议的数据包

tcpdump -i eth0 icmp
tcpdump -i eth0 ip
tcpdump -i eth0 tcp
tcpdump -i eth0 udp
tcpdump -i eth0 arp

复杂的逻辑表达式抓取过滤条件

对于复杂的过滤器表达式,为了逻辑清晰,可以使用 (),不过默认情况下,tcpdump 会将 () 当做特殊字符,所以必须使用 '' 来消除歧义。

抓取经过 interface eth0 发送到 host 200.200.200.1 或 200.200.200.2 的 TCP 协议 22 号端口的数据包

tcpdump -i eth0 -nntvv -c 10 '((tcp) and (port 22) and ((dst host 200.200.200.1) or (dst host 200.200.200.2)))'

抓取经过 interface eth0, DST_MAC 或 SRC_MAC 地址是 00:16:3e:12:16:e7 的 ICMP 数据包

tcpdump -i eth0 '((icmp) and ((ether host 00:16:3e:12:16:e7)))' -nnvv

抓取经过 interface eth0,目标网络是 172.18 但目标主机又不是 172.18.82.173 的 TCP 且非 22 号端口号的数据包

tcpdump -i eth0 -nntvv '((dst net 172.18) and (not dst host 172.18.82.173) and (tcp) and (not port 22))'

抓取流入 interface eth0,host 为 172.18.82.173 且协议为 ICMP 的数据包

tcpdump -i eth0 -nntvv -P in host 172.18.82.173 and icmp

抓取流出 interface eth0,host 为 172.18.82.173 且协议为 ICMP 的数据包

tcpdump -i eth0 -nntvv -P out host 172.18.82.173 and icmp

结合 Wireshark 进行分析

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

把所有 80 端口的数据导出到文件。

tcpdump -w capture_file.pcap port 80

读取文件 capture_file.pcap 里的数据报文,显示到屏幕上。

tcpdump -nXr capture_file.pcap host host1

.pcap 格式的文件需要用 wireshark、Snort 等工具查看,使用 vimcat 会出现乱码。

提取 HTTP 请求的信息

从 HTTP 请求头中提取 HTTP 的 User-Agent:

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

通过 egrep 可以同时提取User-Agent 和主机名(或其他头文件):

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

抓取 HTTP GET 请求包:

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

# or

$ tcpdump -vvAls0 | grep 'GET'

可以抓取 HTTP POST 请求包:

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

# or

$ tcpdump -vvAls0 | grep 'POST'

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

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

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

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

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

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

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

找出发包数最多的 IP

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

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

注意事项

$ tcpdump -i ens3 '(dst port 80 or dst port 443) and src port 22'

而不是这样的表达式:

$ tcpdump -i ens3 dst port 80 or dst port 443 and src port 22

因为后者的逻辑是捕获目标端口为80,或者目标端口为443且源端口为22的数据包,这可能不是你想要的结果。