tcpdump--详解

 

1. tcpdump介绍

1.1 官方man手册

帮助手册

1.2 维基百科

tcpdump 是一个运行在命令行下的嗅探工具。它允许用户拦截和显示发送或收到过网络连接到该计算机的TCP/IP和其他数据包。tcpdump 是一个在BSD许可证下发布的自由软件。

tcpdump 适用于大多数的类Unix系统 操作系统:包括Linux、Solaris、BSD、Mac OS X、HP-UX和AIX 等等。在这些系统中,tcpdump 需要使用libpcap这个捕捉数据的库。其在Windows下的版本称为WinDump;它需要WinPcap驱动,相当于在Linux平台下的libpcap.

1.3 百度百科

TCPDump可以将网络中传送的数据包完全截获下来提供分析。它支持针对网络层、协议、主机、网络或端口的过滤,并提供and、or、not等逻辑语句来帮助你去掉无用的信息。

2. 参数详解

2.1 图示

lALPGpqNbM0WWbbNAgbNBDc_1079_518.png_720x720q90g.jpg

2.2 option 可选参数

 

  • -n:不把ip转化成域名,直接显示 ip,避免执行 DNS lookups 的过程,速度会快很多
  • -nn:不把协议和端口号转化成名字,速度也会快很多。
  • -N:不打印出host 的域名部分.。比如,,如果设置了此选现,tcpdump 将会打印'nic' 而不是 'nic.ddn.mil'.
  • -w :参数后接一个以 .pcap 后缀命令的文件名,就可以将 tcpdump 抓到的数据保存到文件中。
  • -v:产生详细的输出. 比如包的TTL,id标识,数据包长度,以及IP包的一些选项。同时它还会打开一些附加的包完整性检测,比如对IP或ICMP包头部的校验和。
  • -vv:产生比-v更详细的输出. 比如NFS回应包中的附加域将会被打印, SMB数据包也会被完全解码。(摘自网络,目前我还未使用过)
  • -vvv:产生比-vv更详细的输出。比如 telent 时所使用的SB, SE 选项将会被打印, 如果telnet同时使用的是图形界面,其相应的图形选项将会以16进制的方式打印出来(摘自网络,目前我还未使用过)
  • -t:在每行的输出中不输出时间
  • -tt:在每行的输出中会输出时间戳
  • -ttt:输出每两行打印的时间间隔(以毫秒为单位)
  • -tttt:在每行打印的时间戳之前添加日期的打印(此种选项,输出的时间最直观)
  • -i:指定要过滤的网卡接口,如果要查看所有网卡,可以 -i any
  • -Q:选择是入方向还是出方向的数据包,可选项有:in, out, inout
  • -l : 基于行的输出,便于你保存查看,或者交给其它工具分析
  • -q : 简洁地打印输出。即打印很少的协议相关信息, 从而输出行都比较简短.
  • -c : 捕获 count 个包 tcpdump 就退出
  • -s :  tcpdump 默认只会截取前 96 字节的内容,要想截取所有的报文内容,可以使用 -s number, number 就是你要截取的报文字节数,如果是 0 的话,表示截取报文全部内容。
  • -C:file-size,tcpdump 在把原始数据包直接保存到文件中之前, 检查此文件大小是否超过file-size. 如果超过了, 将关闭此文件,另创一个文件继续用于原始数据包的记录. 新创建的文件名与-w 选项指定的文件名一致, 但文件名后多了一个数字.该数字会从1开始随着新创建文件的增多而增加.
  • -W:与-C选项一起使用,这会将创建的文件数量限制为指定的数量,并从头开始覆盖文件,从而创建“旋转”缓冲区。此外,它将使用足够的前导0命名文件,以支持最大数量的文件,从而使它们能够正确排序。

2.3 过滤参数

2.3.1 基于IP地址过滤:host

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

$ tcpdump host 192.168.1.109

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

# 根据源ip进行过滤
$ tcpdump -i eth0 src 192.168.1.109
# 根据目标ip进行过滤
$ tcpdump -i eth0 dst 192.168.1.109

2.3.2 基于网段进行过滤:net

若你的ip范围是一个网段,可以直接这样指定

$ tcpdump net 192.168.1.0/200

网段同样可以再细分为源网段和目标网段

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

2.3.3 基于端口进行过滤:port

使用 port 就可以指定特定端口进行过滤

$ tcpdump port 80

端口同样可以再细分为源端口,目标端口

# 根据源端口进行过滤
$ tcpdump src port 80
# 根据目标端口进行过滤
$ tcpdump dst port 80

如果你想要同时指定两个端口你可以这样写

$ tcpdump port 80 or port 443

但也可以简写成这样

$ tcpdump port 80 or 443

对于httphttps的常见端口也可以写成这样

$ tcpdump tcp port http

2.3.4 基于协议进行过滤:proto

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

若你只想查看 tcp的包,可以直接这样写

$ tcpdump tcp

 

2.3.5 基本IP协议的版本进行过滤

当你想查看 tcp 的包,你也许会这样子写

$ tcpdump tcp

这样写不够准确,因为有IPv4和IPv6(数字 6 表示的是 tcp 在ip报文中的编号)

$ tcpdump 'ip proto tcp'
# example-1
$ tcpdump ip proto 6
# example-2
$ tcpdump 'ip protochain tcp'
# example-3
$ tcpdump ip protochain 6

而如果是 IPv6 的 tcp 包 ,就这样写

$ tcpdump 'ip6 proto tcp'
# example-1
$ tcpdump ip6 proto 6
# example-2
$ tcpdump 'ip6 protochain tcp'
# example-3 
$ tcpdump ip6 protochain 6

2.4 组合过滤

2.4.1 根据IP和port过滤

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

$ tcpdump src 108.69.207.22 and dst port 3359

 

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

$ tcpdump 'src 108.69.207.22 and (dst port 3359 or 8888)'

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

  • 等于,不等和值相等:=、!=、==

2.4.2 根据其他关键字过滤

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

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

 

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

$ tcpdump '( if=eth0 and proc =openvpn ) || (if != eth0 and dir=in)'

2.4.3 根据数据包大小过滤

若你想查看指定大小的数据包,也是可以的

$ tcpdump less 64 
$ tcpdump greater 128 
$ tcpdump <= 256

2.4.4 根据 mac 地址进行过滤

如下:

$ tcpdump ether host [ehost]
$ tcpdump ether dst    [ehost]
$ tcpdump ether src    [ehost]

2.4.5 根据数据内容进行过滤

获取到请求方式为GET的数据包

注:以下理解来自于google

$ 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[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    -->  G
0x45   -->   69    -->  E
0x54   -->   84    -->  T
0x20   -->   32    -->  空格

 

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

3. 输出理解

随便看一行的输出内容

11:08:03.779056 IP 192.168.1.109.41234 > 108.69.212.96.26778: Flags [.], ack 3751226663, win 5574, length 0

 

  1. 第一列:时间,11时08分03秒779056
  2. 第二列:网络协议为IP
  3. 第三列:发送方的IP和port,IP为192.168.1.109,端口为41234
  4. 第四列:箭头 >, 表示数据流向
  5. 第五列:接收方的IP和port,IP为108.69.212.96,端口为26778
  6. 第六列:数据包内容,包括Flags 标识符,seq 号,ack 号,win 窗口,数据长度 length,其中 [.] 表示没有Flag,更多标识符内容看下面介绍

 

TCP 报文 Flags,有以下几种:

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

4. 实例

注:以下例子摘自:https://fuckcloudnative.io/posts/tcpdump-examples/

4.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:'

4.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'

4.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 : 按照数值大小逆向排序

4.4 抓取 DNS 请求和响应

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

$ tcpdump -i any -s0 port 53

4.5 提取 HTTP POST 请求中的密码

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

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

4.6 提取 HTTP 请求的 URL

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

$ tcpdump -s 0 -v -n -l | egrep -i "POST /|GET /|Host:"
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章