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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章