tcpdump是一個用於截取網絡分組,並輸出分組內容的工具,簡單說就是數據包抓包工具。tcpdump憑藉強大的功能和靈活的截取策略,使其成爲Linux系統下用於網絡分析和問題排查的首選工具。
tcpdump提供了源代碼,公開了接口,因此具備很強的可擴展性,對於網絡維護和入侵者都是非常有用的工具。tcpdump存在於基本的Linux系統中,由於它需要將網絡界面設置爲混雜模式,普通用戶不能正常執行,但具備root權限的用戶可以直接執行它來獲取網絡上的信息。因此係統中存在網絡分析工具主要不是對本機安全的威脅,而是對網絡上的其他計算機的安全存在威脅。
一、概述
顧名思義,tcpdump可以將網絡中傳送的數據包的“頭”完全截獲下來提供分析。它支持針對網絡層、協議、主機、網絡或端口的過濾,並提供and、or、not等邏輯語句來幫助你去掉無用的信息。
二、選項介紹
-A 以ASCII格式打印出所有分組,並將鏈路層的頭最小化。
-c 在收到指定的數量的分組後,tcpdump就會停止。
-C 在將一個原始分組寫入文件之前,檢查文件當前的大小是否超過了參數file_size 中指定的大小。如果超過了指定大小,則關閉當前文件,然後在打開一個新的文件。參數 file_size 的單位是兆字節(是1,000,000字節,而不是1,048,576字節)。
-d 將匹配信息包的代碼以人們能夠理解的彙編格式給出。
-dd 將匹配信息包的代碼以c語言程序段的格式給出。
-ddd 將匹配信息包的代碼以十進制的形式給出。
-D 打印出系統中所有可以用tcpdump截包的網絡接口。
-e 在輸出行打印出數據鏈路層的頭部信息。
-E 用spi@ipaddr algo:secret解密那些以addr作爲地址,並且包含了安全參數索引值spi的IPsec ESP分組。
-f 將外部的Internet地址以數字的形式打印出來。
-F 從指定的文件中讀取表達式,忽略命令行中給出的表達式。
-i 指定監聽的網絡接口。
-l 使標準輸出變爲緩衝行形式,可以把數據導出到文件。
-L 列出網絡接口的已知數據鏈路。
-m 從文件module中導入SMI MIB模塊定義。該參數可以被使用多次,以導入多個MIB模塊。
-M 如果tcp報文中存在TCP-MD5選項,則需要用secret作爲共享的驗證碼用於驗證TCP-MD5選選項摘要(詳情可參考RFC 2385)。
-b 在數據-鏈路層上選擇協議,包括ip、arp、rarp、ipx都是這一層的。
-n 不把網絡地址轉換成名字。
-nn 不進行端口名稱的轉換。
-N 不輸出主機名中的域名部分。例如,‘nic.ddn.mil‘只輸出’nic‘。
-t 在輸出的每一行不打印時間戳。
-O 不運行分組分組匹配(packet-matching)代碼優化程序。
-P 不將網絡接口設置成混雜模式。
-q 快速輸出。只輸出較少的協議信息。
-r 從指定的文件中讀取包(這些包一般通過-w選項產生)。
-S 將tcp的序列號以絕對值形式輸出,而不是相對值。
-s 從每個分組中讀取最開始的snaplen個字節,而不是默認的68個字節。
-T 將監聽到的包直接解釋爲指定的類型的報文,常見的類型有rpc遠程過程調用)和snmp(簡單網絡管理協議;)。
-t 不在每一行中輸出時間戳。
-tt 在每一行中輸出非格式化的時間戳。
-ttt 輸出本行和前面一行之間的時間差。
-tttt 在每一行中輸出由date處理的默認格式的時間戳。
-u 輸出未解碼的NFS句柄。
-v 輸出一個稍微詳細的信息,例如在ip包中可以包括ttl和服務類型的信息。
-vv 輸出詳細的報文信息。
-w 直接將分組寫入文件中,而不是不分析並打印出來。
三、指令操作
tcpdump
普通情況下,直接啓動tcpdump將監視第一個網絡接口上所有流過的數據包。
監視指定網絡接口的數據包
tcpdump -i eth1
如果不指定網卡,默認tcpdump只會監視第一個網絡接口,一般是eth0,我的阿里雲是雙網卡,eth0是內網網卡,eth1纔是外網網卡。所以一般要指定 -i eth1
抓取所有經過eth1,目的或源地址是192.168.1.1的網絡數據
tcpdump -i eth1 host 192.168.1.1
指定源地址
tcpdump -i eth1 src host 192.168.1.1
指定目的地址
tcpdump -i eth1 dst host 192.168.1.1
2.過濾端口
抓取所有經過eth1,目的或源端口是25的網絡數據
tcpdump -i eth1 port 25
指定源端口
tcpdump -i eth1 src port 25
指定目的端口
tcpdump -i eth1 dst port 25
3.網絡過濾
tcpdump -i eth1 net 192.168tcpdump -i eth1 src net 192.168
tcpdump -i eth1 dst net 192.168
4.協議過濾
tcpdump -i eth1 arptcpdump -i eth1 ip
tcpdump -i eth1 tcp
tcpdump -i eth1 udp
tcpdump -i eth1 icmp
5.常用表達式
非 : ! or "not" (去掉雙引號)且 : && or "and"
或 : || or "or"
抓取所有經過eth1,目的地址是192.168.1.254或192.168.1.200端口是80的TCP數據
tcpdump -i eth1 '((tcp) and (port 80) and ((dst host 192.168.1.254) or (dst host 192.168.1.200)))'
抓取所有經過eth1,目標MAC地址是00:01:02:03:04:05的ICMP數據
tcpdump -i eth1 '((icmp) and ((ether dst host 00:01:02:03:04:05)))'
抓取所有經過eth1,目的網絡是192.168,但目的主機不是192.168.1.200的TCP數據
tcpdump -i eth1 '((tcp) and ((dst net 192.168) and (not dst host 192.168.1.200)))'
四、高級包頭過濾
首先了解如何從包頭過濾信息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
操作符 : >, <, >=, <=, =, !=
IP頭
本文只針對IPv4。
2.IP選項設置了嗎?
“一般”的IP頭是20字節,但IP頭有選項設置,不能直接從偏移21字節處讀取數據。IP頭有個長度字段可以知道頭長度是否大於20字節。
通常第一個字節的二進制值是:01000101,分成兩個部分:
0100 = 4 表示IP版本 0101 = 5 表示IP頭32 bit的塊數,5 x 32 bits = 160 bits or 20 bytes
如果第一字節第二部分的值大於5,那麼表示頭有IP選項。
下面介紹兩種過濾方法:
a. 比較第一字節的值是否大於01000101,這可以判斷IPv4帶IP選項的數據和IPv6的數據。
01000101十進制等於69
如果設置了IP選項,那麼第一自己是01000110(十進制70),過濾規則:
tcpdump -i eth1 'ip[0] > 69'
當然這種過濾有問題,因爲前四位不確定是0100,ipv6的話是0110。所以用位操作比較好。
b. 位操作
0100 0101 : 第一字節的二進制
0000 1111 : 與操作
<=========
0000 0101 : 結果
正確的過濾方法
tcpdump -i eth1 'ip[0] & 15 > 5'
或者
tcpdump -i eth1 'ip[0] & 0x0f > 5'
3.分片標記
當發送端的MTU大於到目的路徑鏈路上的MTU時就會被分片,這段話有點拗口,權威的請參考《TCP/IP詳解》。
分片信息在IP頭的第七和第八字節:
Bit 0: 保留,必須是0
Bit 1: (DF) 0 = 可能分片, 1 = 不分片
Bit 2: (MF) 0 = 最後的分片, 1 = 還有分片
13位片偏移 字段只有在分片的時候才使用。
要抓帶DF位標記的不分片的包,第七字節的值應該是:
01000000 = 64
tcpdump -i eth1 'ip[6] = 64'
4.抓分片包
匹配MF,分片包
tcpdump -i eth1 'ip[6] = 32'
最後分片包的開始3位是0,但是有Fragment Offset字段。
匹配分片和最後分片
tcpdump -i eth1 '((ip[6:2] > 0) and (not ip[6] = 64))'
測試分片可以用下面的命令:
ping -M want -s 3000 192.168.1.1
5.匹配小TTL
TTL字段在第九字節,並且正好是完整的一個字節,TTL最大值是255,二進制爲11111111。
可以用下面的命令驗證一下:
$ ping -M want -s 3000 -t 256 192.168.1.200
ping: ttl 256 out of range
8位生存時間
tcpdump -i eth1 'ip[8] < 5'
6.抓大於X字節的包
大於600字節
tcpdump -i eth1 'ip[2:2] > 600'
TCP頭
抓取源端口大於1024的TCP數據包
tcpdump -i eth1 'tcp[0:2] > 1024'
只抓SYN包,第十四字節是二進制的00000010,也就是十進制的2
tcpdump -i eth1 'tcp[13] = 2'
tcpdump -i eth1 'tcp[13] = 18'
tcpdump -i eth1 'tcp[13] & 2 = 2'
用到了位操作,就是不管ACK位是啥。
抓PSH-ACK
tcpdump -i eth1 'tcp[13] = 24'
抓所有包含FIN標記的包
tcpdump -i eth1 'tcp[13] & 1 = 1'
抓RST
tcpdump -i eth1 'tcp[13] & 4 = 4'
所以要抓取帶過濾信息的tcp/ip包還是需要對tcp/ip基本結構比較瞭解纔行。
time tcpdump -nn -i eth0 'tcp[tcpflags] = tcp-syn' -c 10000 > /dev/null
上面的命令計算抓10000個SYN包花費多少時間,可以判斷訪問量大概是多少。