Virtual Network---tcpdump抓包高阶用法

Virtual Network—tcpdump抓包高阶用法

前言

tcpdump 是网络抓包的常用工具,基本的使用都已经很熟悉了,本篇主要记录tcpdump 的高阶用法,旨在应用于vxlan、gre、ipip等类型封装报文,大流量场景下精确抓包过滤条件,保证环境安全 等场景;

封装报文的抓包过滤

在现在SDN 定义网络大行其道的今天,各种overlay 虚拟网络下,报文的封装,外层、内层报文已经是非常常见的场景了,这对我们抓包就提出了要求,在一般云网络运维场景下,外层报文都是物理机(宿主机)的ip地址,实际通信的源/目的地址 都是被封装到了内层报文中,这样在使用tcpdump 进行过滤抓包的时候,如果选择使用外层报文ip 进行过滤,则会抓取到近乎全部的流量,对于大流量节点,这个行为是不可接受的,很容易对服务器产生过大压力,影响性能。

目前比较常见的封装报文的技术有VxLAN和隧道(gre、ipip等),其中vxlan是通过udp协议进行封装的,隧道方式是通过ip层封装的;具体的封装原理和报文样式 这里就不描述了,不同场景和产品的封装的内部还是会有所区别,这里只是着重记录tcpdump 应该如果直接过滤内层报文,即过滤包头信息;

首先了解如何从包头过滤信息

proto[x:y]          : 过滤从x字节开始的y字节数。比如ip[2:2]过滤出3、4字节(第一字节从0开始排)
proto[x:y] & z = 0  : proto[x:y]和z的与操作为0
proto[x:y] & z !=0  : proto[x:y]和z的与操作不为0
proto[x:y] & z = z  : proto[x:y]和z的与操作为z
proto[x:y] = z      : proto[x:y]等于z

操作符 : >, <, >=, <=, =, !=

操作值都是16进制

那么对于gre隧道模式下,gre隧道是通过IP层进行的报文封装,那么从ip层过滤信息,就可以写成ip[30:4] 即代表ip层第31位起,向后4 byte,这里的值都是16进制,就可以写为:ip[30:4]=0xAC100009

这里0xAC100009 就是16进制的ip(172.16.0.9),可以使用在线工具进行转换;

构造出的tcpdump命令就是:

# 过滤内层报文ip 地址为 AC100009 
tcpdump -i any -nne -vv 'ip[30:4]=0xAC100009' -w XXXXX.pcapng

这里的内部偏移位数,是和报文封装逻辑强相关的,报文封装时,就会定义内层报文中源ip 的偏移量是多少,内层报文中一般都会包含 五元组即源ip,源port,目的ip,目的port,协议;

根据定义的规则就可以拼接出对应的tcpdump命令,例如:

tcpdump -i any -nne -vv 'ip[30:4]=0xAC100009 and ip[27:1]=0x6 and ip[34:4]=0xAC10000C and ip[40:2]=8080 ' -w XXXXXX.pcapng

还有一点需要注意的是这里的内层报文的偏移量要如何计算得到,比如gre隧道是ip层封装内层报文,那ip层头部开始是第0位,向后偏移;

同理如果是vxlan报文,那就是从udp头部开始计数,类似udp[16:4];忽略前面的数据链路层、物理层等信息;

报文精确过滤

实现报文的精确过滤,原理是和报文封装根据内层报文过滤是一样的,都是通过过滤包头信息,进行条件筛选判断达到目的。

下面将一些常见的场景举例如下,如果有特殊要求,可以自行根据报文位数进行构造命令;

端口范围:

(tcp[0:2] > 1500 and tcp[0:2] < 1550) or (tcp[2:2] > 1500 and tcp[2:2] < 1550)

tcp portrange 1501-1549

过滤协议头

过滤 tcp SYN 消息包:

'tcp[tcpflags] & (tcp-syn) != 0'

过滤 tcp SYN/ACK 消息包:

'tcp[tcpflags] & (tcp-syn|tcp-ack) != 0'

常用的 tcp 标记:

tcp-fin, tcp-syn, tcp-rst, tcp-push, tcp-ack, tcp-urg, tcp-ece, tcp-cwr

源端口大于1024的TCP数据包:

'tcp[0:2] > 1024'

注意要用引号引起来。

过滤 HTTP

# 0x4745 为"GET"前两个字母"GE",0x4854 为"HTTP"前两个字母"HT"。
tcpdump  -XvvennSs 0 -i eth0 tcp[20:2]=0x4745 or tcp[20:2]=0x4854 

过滤 GET 请求:

'tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420'

上面的 0x47455420'GET ' 的 16 进制:

>>> list(map(hex, [ord(x) for x in 'GET ']))
['0x47', '0x45', '0x54', '0x20']

过滤 POST 请求:

'tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x504f5354 && tcp[((tcp[12:1] & 0xf0) >> 2) + 4:1] = 0x20'

>>> list(map(hex, [ord(x) for x in 'POST ']))
['0x50', '0x4f', '0x53', '0x54', '0x20']

过滤 PUT 请求:

'tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x50555420'

>>> list(map(hex, [ord(x) for x in 'PUT ']))
['0x50', '0x55', '0x54', '0x20']

过滤 PATH 请求:

'tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x50415443 && tcp[((tcp[12:1] & 0xf0) >> 2) + 4:2] = 0x4820'

>>> list(map(hex, [ord(x) for x in 'PATCH ']))
['0x50', '0x41', '0x54', '0x43', '0x48', '0x20']

之所以拆分成了多个条件是因为 tcpdump: data size must be 1, 2, or 4

过滤 DELETE 请求:

'tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x44454c45 && tcp[((tcp[12:1] & 0xf0) >> 2) + 4:2] = 0x5445 && tcp[((tcp[12:1] & 0xf0) >> 2) + 6:1] = 0x20'

>>> list(map(hex, [ord(x) for x in 'DELETE ']))
['0x44', '0x45', '0x4c', '0x45', '0x54', '0x45', '0x20']

过滤 HEAD 请求:

'tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x48454144 && tcp[((tcp[12:1] & 0xf0) >> 2) + 4:1] = 0x20'

>>> list(map(hex, [ord(x) for x in 'HEAD ']))
['0x48', '0x45', '0x41', '0x44', '0x20']

过滤 OPTIONS 请求:

'tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x4f505449 && tcp[((tcp[12:1] & 0xf0) >> 2) + 4:4] = 0x4f4e5320'

>>> list(map(hex, [ord(x) for x in 'OPTIONS ']))
['0x4f', '0x50', '0x54', '0x49', '0x4f', '0x4e', '0x53', '0x20']

过滤 HTTP 响应 (HTTP/1.):

'tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x48545450 && tcp[((tcp[12:1] & 0xf0) >> 2) + 4:2] = 0x2f31 && tcp[((tcp[12:1] & 0xf0) >> 2) + 6:1] = 0x2e'

HTTP request header && body && response header && body:

'(((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)'

自动生成 HTTP 相关过滤规则的脚本: https://www.wireshark.org/tools/string-cf.html

上面的规则可以通过括号和操作符进行各种组合,从而组合出复杂的过滤规则。

sudo tcpdump host 192.168.8.3 -Avv
sudo tcpdump dst host baidu.com and dst port 80 -i eth0 -vv
sudo tcpdump dst host baidu.com and not dst port 80 -i eth0 -vv
sudo tcpdump dst host baidu.com and not \(dst port 80 or dst port 443\) -i en0 -vv
sudo tcpdump dst host baidu.com and 'tcp[tcpflags] & (tcp-syn) != 0'

-c参数对于运维人员来说也比较常用,因为流量比较大的服务器,靠人工CTRL+C还是抓的太多,甚至导致服务器宕机,于是可以用-c参数指定抓多少个包。

time tcpdump -nn -i eth0 'tcp[tcpflags] = tcp-syn' -c 10000 > /dev/null
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章