tcpdump详解

一、直观查看tcpdump命令的各种参数:

 

 

1、option可选参数:命令的参数选项

2、proto类过滤器:根据协议进行过滤,可识别的关键词有:udp、icmp、tcp、ip、ip6、arp、rarp、ether、wlan、fddi、tr、decnet

3、type类过滤器:可识别的关键词有:host、net、port、portrange,这些词后面需要再接参数

4、direction类过滤器:根据数据流向进行过滤,可识别的关键字有:src、dst,同时你可以使用逻辑运算符进行组合,比如:src or dst

二、理解tcpdump的输出:

2.1 输出内容结构:

以tcp报文为例:

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

2.2Flags标识符:

使用tcpdump抓包后,会遇到的tcp报文Flags,有以下几种:

    • [S] : SYN(开始连接)
    • [P] : PSH(推送数据)
    • [F] : FIN (结束连接)
    • [R] : RST(重置连接)
    • [.] : 没有 Flag,由于除了 SYN 包外所有的数据包都有ACK,所以一般这个标志也可表示 ACK

三、常规过滤规则:

3.1 基于IP地址过滤:host

$ tcpdump host 192.168.56.3

#指定host ip进行过滤

 

$tcpdump -i enp0s8 src 192.168.56.3

#根据源地址进行过滤

 

$tcpdump -i enp0s8 dst 192.168.56.3

#根据目的地址进行过滤

3.2基于网段进行过滤:net

$tcpdump net 192.168.56.0/24

#指定网段进行过滤

 

 $tcpdump src net 192.168.56.0/24

#指定源网段进行过滤

 

$tcpdump dst net 192.168.56.0/24

#指定目的网段进行过滤

 

3.3基于端口过滤:port

 

$tcpdump port 8088

#指定端口过滤

 

$tcpdump src port 8088

#指定源端口过滤

 

$tcpdump dst port 8088

#指定目的端口过滤

 

$tcpdump port 8088 or port 1080

$tcpdump port 8088 or 1080

#同时指定两个端口

 

$tcpdump portrange 1080-8080

#指定端口范围选择

 

$tcpdump src portrange 1080-8080

#指定源端口范围选择

 

$tcpdump dst portrange 1080-8080

#指定目的端口范围选择

 

$tcpdump port http(tcpdump tcp port https)

#常见的协议可以使用协议名(http:80,https:443)

 

3.4 基于协议进行过滤:Proto

常见网络协议有:tcp、udp、icmp、http、ip、ipv6等

$tcpdump  icmp

 

protocol 可选值:ip, ip6, arp, rarp, atalk, aarp, decnet, sca, lat, mopdl, moprc, iso, stp, ipx, netbeui

 

3.5 基于协议版本进行过滤

例如抓ipv4的tcp报文:(数字6表示的是tcp在ip报文中的编号)

tcpdump ip proto 6 

tcpdump 'ip proto tcp'                      //tcpdump  'ip && tcp'

tcpdump 'ip protochain tcp'

tcpdump ip protochain 6           

//2和3实现不了

 

抓取ipv6的tcp报文:

tcpdump ip6 proto 6

tcpdump 'ip6 proto tcp'                 //tcpdump 'ipv6 && tcp'

tcpdump 'ip6 protochain tcp'

tcpdump ip6 protochain 6

//2和3实现不了

注:

1、跟在proto和protochain后面的如果是tcp,udp,icmp,那么过滤器需要用引号包含,这是因为tcp,udp,icmp是tcpdump的关键字。(个人实践:后面加关键字并无法使用)

2、跟在ip和ip6关键字后面的proto和protochain是两个新面孔,看起来用法类似,他们是否等价:

  proto后面只能跟固定的关键字: ip, ip6, arp, rarp, atalk, aarp, decnet, sca, lat, mopdl, moprc, iso, stp, ipx,netbeui;

  protochain没有那么严格,只要是tcpdump的ip报文头部里的protocol字段为<protocol>就能匹配上。

四、可选参数解析:

4.1设置不解析域名提升速度

  • -n: 不把ip转化成域名,直接显示ip,避免执行DNS lookups的过程,速度会快很多
  • -nn:不把协议和端口转化成名字,速度会快很多
  • -N:不打印出host的域名部分。比如,如果设置此选项,将会‘192’而不是‘192.168.56.1’

4.2过滤结果输出的文件

tcpdump的抓包结果输出为.pcap文件,给其他工具进行分析:wireshark;

$tcpdump  icmp  -w icmp.pcap

 

4.3 从文件读取包数据

$tcpdump  icmp  -r icmp.pcap

 

4.4控制详细内容的输出

  • -v:产生详细的输出,比如包的ttl,id标识,数据包长度,以及IP包的一些选项。同时它还会打开一些附加的包完整性检测,比如对ip或icmp包头部的校验和
  • -vv:产生比-v更详细的输出。比如NFS回应包中的附加域将会被打印,SMB数据包也会被完全解码。
  • -vvv:产生比-vv更详细的输出,比如telnet时所使用的SB,SE选项将会被打印,如果telnet同时使用的是图形界面,其相应的图形选项将会以16进制的方式打印出来。

 

4.5 控制时间的输出

  • -t:在每行的输出中不输出时间戳
  • -tt:在每行的输出中会出书时间戳
  • -ttt:输出每两行打印的时间间隔(以毫秒为单位)
  • -tttt:在每行打印的时间戳之前添加日期的打印(输出时间更直观)

 

 

4.6 显示数据包的头部

  • -x:以16进制的形式打印每个包的头部数据(但不包括数据链路层的头部)
  • -xx:以16进制的形式打印每个包的头部数据(包括数据链路层的头部)
  • -X:以16进制和ASCII码形式打印出每个包的数据(但不包括数据链路层的头部)
  • -XX:以16进制和ASCII码形式打印出每个包的数据(包括数据链路层的头部)

 

4.7 过滤指定网卡的数据包

  • -i:指定要过滤的网卡接口,如果要查看所有网卡,可以-i any

 

4.8 过滤特定流向的数据包

  • -Q:选择是入方向还是出方向的数据包,可以选项有:in,out,inout,也可以使用--direction=[direction],这种写法

 

4.9 其他常用的一些参数

  • -A:以ASCII码方式显示每一个数据包(不显示链路层头部信息),在抓取包含页面数据的数据包时,可方便查看数据
  • -l:基于行的输出,便于你保存查看,或者交给其它工具分析
  • -q:简洁地打印输出。且打印很少的协议相关信息,从而输出行都比较简短
  • -c:捕获count个包tcpdump就退出
  • -s:tcpdump默认只会截取前96个字节的内容,要想截取所有的报文内容,可以使用-s number,number就是你要截取的报文字节数,如果是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文件作为过滤文件表达式的输入,此时命令行上的输入将被忽略。

 

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

  • -D:显示所有可用网络接口的列表( tcpdump -D)
  • -e:每行的打印输出中将包括数据包的数据链路层头部信息
  • -E:揭秘IPSEC数据
  • -L:列出指定网络接口所支持的数据链路层的类型后退出
  • -Z:后接用户名,在抓包时会受到权限的限制,如果以root用户启动tcpdump,tcpdump将会是超级用户的权限。
  • -d:打印出易读的包匹配码
  • -dd:以C语言的形式打印出包匹配码
  • -ddd:以十进制数的形式打印出包匹配码

五、过滤规则组合

5.1逻辑运算符:

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

 

例子:

 tcpdump -ni any src 192.168.56.3 and icmp

//抓取源地址为192.168.56.3且为icmp协议

 

 tcpdump -i any "src 192.168.56.3 and (icmp or port 22)"

//抓取源地址为192.168.56.3且为icmp协议或22端口的报文

 

5.2 条件判断

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

 

tcpdump提供了关键字进行判断:

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

 

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

//过滤来自进程号为nc,发出的流经en0网卡的数据包,或者不流经en0的入方向数据包

六、特殊过滤规则

6.1 根据 tcpflags 进行过滤

通过上一篇文章,我们知道了 tcp 的首部有一个标志位。

            TCP 报文首部

tcpdump 支持我们根据数据包的标志位进行过滤:

 

proto [ expr:size ]

 

proto:可以是熟知的协议之一(如ip,arp,tcp,udp,icmp,ipv6)

expr:可以是数值,也可以是一个表达式,表示与指定的协议头开始处的字节偏移量。

size:是可选的,表示从字节偏移量开始取的字节数量。

 

接下来,我将举几个例子,让人明白它的写法,不过在那之前,有几个点需要你明白,这在后面的例子中会用到:

1、tcpflags 可以理解为是一个别名常量,相当于 13,它代表着与指定的协议头开头相关的字节偏移量,也就是标志位,所以 tcp[tcpflags] 等价于 tcp[13] ,对应下图中的报文位置。

 

 

2、tcp-fin, tcp-syn, tcp-rst, tcp-push, tcp-ack, tcp-urg 这些同样可以理解为别名常量,分别代表 1,2,4,8,16,32,64。这些数字是如何计算出来的呢?

以 tcp-syn 为例,你可以参照下面这张图,计算出来的值 是就是 2

 

由于数字不好记忆,所以一般使用这样的“别名常量”表示。

因此当下面这个表达式成立时,就代表这个包是一个 syn 包。

tcp[tcpflags] == tcp-syn

要抓取特定数据包,方法有很多种。

 

下面以最常见的 syn包为例,演示一下如何用 tcpdump 抓取到 syn 包,而其他的类型的包也是同样的道理。

据我总结,主要有三种写法:

1、第一种写法:使用数字表示偏移量

$ tcpdump -i eth0 "tcp[13] & 2 != 0"

 

2、第二种写法:使用别名常量表示偏移量

$ tcpdump -i eth0 "tcp[tcpflags] & tcp-syn != 0"

 

3、第三种写法:使用混合写法

$ tcpdump -i eth0 "tcp[tcpflags] & 2 != 0"# or$ tcpdump -i eth0 "tcp[13] & tcp-syn != 0"

 

如果我想同时捕获多种类型的包呢,比如 syn + ack 包:

1、第一种写法

$ tcpdump -i eth0 'tcp[13] == 2 or tcp[13] == 16'

 

2、第二种写法

$ tcpdump -i eth0 'tcp[tcpflags] == tcp-syn or tcp[tcpflags] == tcp-ack'

 

3、第三种写法

$ tcpdump -i eth0 "tcp[tcpflags] & (tcp-syn|tcp-ack) != 0"

 

4、第四种写法:注意这里是 单个等号,而不是像上面一样两个等号,18(syn+ack) = 2(syn) + 16(ack)

$ tcpdump -i eth0 'tcp[13] = 18'# or$ tcpdump -i eth0 'tcp[tcpflags] = 18'

 

tcp 中有 类似 tcp-syn 的别名常量,其他协议也是有的,比如 icmp 协议,可以使用的别名常量有:icmp-echoreply, icmp-unreach, icmp-sourcequench, icmp-redirect, icmp-echo, icmp-routeradvert,icmp-routersolicit, icmp-timx-ceed, icmp-paramprob, icmp-tstamp, icmp-tstampreply,icmp-ireq, icmp-ireqreply, icmp-maskreq, icmp-maskreply

 

6.2 基于包大小进行过滤

指定查看数据包的大小

$ tcpdump less 32

$ tcpdump greater 64

$ tcpdump <= 128

 

 

6.3 根据 mac 地址进行过滤

例子如下,其中 ehost 是记录在 /etc/ethers 里的 name

$ tcpdump ether host [ehost]

$ tcpdump ether dst [ehost]

$ tcpdump ether src [ehost]

 

6.4 过滤通过指定网关的数据包

$ tcpdump gateway [host]

 

6.5 过滤广播/多播数据包

$ tcpdump ether broadcast

$ tcpdump ether multicast

$ tcpdump ip broadcast

$ tcpdump ip multicast

$ tcpdump ip6 multicast

 

七、如何抓取到更精确的包

先给你抛出一个问题:如果我只想抓取 HTTP 的 POST 请求该如何写呢?

如果只学习了上面的内容,恐怕你还是无法写法满足这个抓取需求的过滤器。

在学习之前,我先给出答案,然后再剖析一下,这个过滤器是如何生效的,居然能让我们对包内的内容进行判断。

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

命令里的可选参数,在前面的内容里已经详细讲过了。这里不再细讲。

 

本节的重点是引号里的内容,看起来很复杂的样子。

将它逐一分解,我们只要先理解了下面几种用法,就能明白

  • tcp[n]:表示 tcp 报文里 第 n 个字节
  • tcp[n:c]:表示 tcp 报文里从第n个字节开始取 c 个字节,tcp[12:1] 表示从报文的第12个字节(因为有第0个字节,所以这里的12其实表示的是13)开始算起取一个字节,也就是 8 个bit。查看 tcp 的报文首部结构,可以得知这 8 个bit 其实就是下图中的红框圈起来的位置,而在这里我们只要前面 4个bit,也就是实际数据在整个报文首部中的偏移量。

 

 

  • &:是位运算里的 and 操作符,比如 0011 & 0010 = 0010
  • >>:是位运算里的右移操作,比如 0111 >> 2 = 0011
  • 0xf0:是 10 进制的 240 的 16 进制表示,但对于位操作来说,10进制和16进制都将毫无意义,我们需要的是二进制,将其转换成二进制后是:11110000,这个数有什么特点呢?前面个 4bit 全部是 1,后面4个bit全部是0,往后看你就知道这个特点有什么用了。

 

分解完后,再慢慢合并起来看:

1、tcp[12:1] & 0xf0 其实并不直观,但是我们将它换一种写法,就好看多了,假设 tcp 报文中的 第12 个字节是这样组成的 10110000,那么这个表达式就可以变成 10110110 && 11110000 = 10110000,得到了 10110000 后,再进入下一步。

2、tcp[12:1] & 0xf0) >> 2 :如果你不理解 tcp 报文首部里的数据偏移,请先点击这个前往我的上一篇文章,搞懂数据偏移的意义,否则我保证你这里会绝对会听懵了。

tcp[12:1] & 0xf0) >> 2 这个表达式实际是 (tcp[12:1] & 0xf0) >> 4 ) << 2 的简写形式。所以要搞懂 tcp[12:1] & 0xf0) >> 2 只要理解了(tcp[12:1] & 0xf0) >> 4 ) << 2 就行了 。

 

从上一步我们算出了 tcp[12:1] & 0xf0 的值其实是一个字节,也就是 8 个bit,但是你再回去看下上面的 tcp 报文首部结构图,表示数据偏移量的只有 4个bit,也就是说 上面得到的值 10110000,前面 4 位(1011)才是正确的偏移量,那么为了得到 1011,只需要将 10110000 右移4位即可,也就是 tcp[12:1] & 0xf0) >> 4,至此我们是不是已经得出了实际数据的正确位置呢,很遗憾还没有,前一篇文章里我们讲到 Data Offset 的单位是 4个字节,因为要将 1011 乘以 4才可以,除以4在位运算中相当于左移2位,也就是 <<2,与前面的 >>4 结合起来一起算的话,最终的运算可以简化为 >>2

 

至此,我们终于得出了实际数据开始的位置是 tcp[12:1] & 0xf0) >> 2 (单位是字节)。

 

找到了数据的起点后,可别忘了我们的目的是从数据中打到 HTTP 请求的方法,是 GET 呢 还是 POST ,或者是其他的?

有了上面的经验,我们自然懂得使用 tcp[((tcp[12:1] & 0xf0) >> 2):4] 从数据开始的位置再取出四个字节,然后将结果与 GET (注意 GET最后还有个空格)的 16进制写法(也就是 0x47455420)进行比对。

0x47 --> 71 --> G0x45 --> 69 --> E0x54 --> 84 --> T0x20 --> 32 --> 空格

如果相等,则该表达式为True,tcpdump 认为这就是我们所需要抓的数据包,将其输出到我们的终端屏幕上。

 

八、抓包实战应用例子

8.1 提取 HTTP 的 User-Agent

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

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

 

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

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

 

8.2 抓取 HTTP GET 和 POST 请求

抓取 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 数据包。

 

8.3 找出发包数最多的 IP

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

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

 

cut -f 1,2,3,4 -d '.' : 以 . 为分隔符,打印出每行的前四列。即 IP 地址。

sort | uniq -c : 排序并计数

sort -nr : 按照数值大小逆向排序

 

8.4 抓取 DNS 请求和响应

DNS 的默认端口是 53,因此可以通过端口进行过滤

$ tcpdump -i any -s0 port 53

 

8.5 切割 pcap 文件

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

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

 

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

 

8.6 提取 HTTP POST 请求中的密码

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

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

 

8.7 提取 HTTP 请求的 URL

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

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

 

8.8 抓取 HTTP 有效数据包

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

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

 

8.9 结合 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 -

抓取到的数据:

 

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

到这里,我已经将我所知道的 tcpdump 的用法全部说了一遍,如果你有认真地看完本文,相信会有不小的收获,掌握一个上手的抓包工具,对于以后我们学习网络、分析网络协议、以及定位网络问题,会很有帮助,而 tcpdump 是我推荐的一个抓包工具。

 

posted @ 2021-12-28 12:43  Day__Day_Up  阅读(358)  评论(0编辑  收藏  举报