一:查看幫助選項
tcpdump --help
Usage: tcpdump [-aAbdDefhHIJKlLnNOpqStuUvxX#] [ -B size ] [ -c count ]
[ -C file_size ] [ -E algo:secret ] [ -F file ] [ -G seconds ]
[ -i interface ] [ -j tstamptype ] [ -M secret ] [ --number ]
[ -Q|-P in|out|inout ]
[ -r file ] [ -s snaplen ] [ --time-stamp-precision precision ]
[ --immediate-mode ] [ -T type ] [ --version ] [ -V file ]
[ -w file ] [ -W filecount ] [ -y datalinktype ] [ -z postrotate-command ]
[ -Z user ] [ expression ]
選項的解釋:
-a:嘗試將網絡和廣播地址轉換成名稱;
-c<數據包數目>:收到指定的數據包數目後,就停止進行傾倒操作;
-d:把編譯過的數據包編碼轉換成可閱讀的格式,並傾倒到標準輸出;
-dd:把編譯過的數據包編碼轉換成C語言的格式,並傾倒到標準輸出;
-ddd:把編譯過的數據包編碼轉換成十進制數字的格式,並傾倒到標準輸出;
-e:在每列傾倒資料上顯示連接層級的文件頭;
-f:用數字顯示網際網絡地址;
-F<表達文件>:指定內含表達方式的文件;
-i<網絡界面>:使用指定的網絡截面送出數據包;
-l:使用標準輸出列的緩衝區;
-n:不把主機的網絡地址轉換成名字;
-N:不列出域名;
-O:不將數據包編碼最佳化;
-p:不讓網絡界面進入混雜模式;
-q :快速輸出,僅列出少數的傳輸協議信息;
-r<數據包文件>:從指定的文件讀取數據包數據;
-s<數據包大小>:設置每個數據包的大小;
-S:用絕對而非相對數值列出TCP關聯數;
-t:在每列傾倒資料上不顯示時間戳記;
-tt: 在每列傾倒資料上顯示未經格式化的時間戳記;
-T<數據包類型>:強制將表達方式所指定的數據包轉譯成設置的數據包類型;
-v:詳細顯示指令執行過程;
-vv:更詳細顯示指令執行過程;
-x:用十六進制字碼列出數據包資料;
-w<數據包文件>:把數據包數據寫入指定的文件。
注意:查看更多的信息,可以用命令:man tcpdump
或者網址:https://www.tcpdump.org/tcpdump_man.html
二:用法
- 直接啓動 tcpdump 將監視第一個網絡接口所有流過的數據包
tcpdump
- 監控某一網絡接口的數據包
tcpdump -i enp0s3
- 過濾主機
3.1 抓取所有經過enp0s3,目的或源地址是 192.168.1.101 的網絡數據
tcpdump -i enp0s3 host 192.168.1.101
3.2 指定源地址
tcpdump -i enp0s3 src host 192.168.1.101
3.3 指定目的地址
tcpdump -i enp0s3 dst host 192.168.1.101
3.4 截獲主機192.168.1.101 和主機192.168.1.102 或192.168.1.103的通信
tcpdump -i enp0s3 host 192.168.1.101 and \(192.168.1.102 or 192.168.1.103 \)
3.5 如果想要獲取主機192.168.1.101除了和主機192.168.1.102之外所有主機通信的ip包,使用命令:
tcpdump ip host 192.168.1.101 and !192.168.1.102
- 過濾端口
4.1 抓取所有經過 enp0s3,目的或源端口是22的網絡數據
tcpdump -i enp0s3 port 22
4.2 指定源端口
tcpdump -i enp0s3 src port 22
4.3 指定目的端口
tcpdump -i enp0s3 dst port 22
- 網絡過濾
tcpdump -i enp0s3 net 192.168
tcpdump -i enp0s3 src net 192.168
tcpdump -i enp0s3 dst net 192.168
6:協議過濾
tcpdump -i enp0s3 arp
tcpdump -i enp0s3 ip
tcpdump -i enp0s3 tcp
tcpdump -i enp0s3 udp
tcpdump -i enp0s3 icmp
7:常用表達式
非 : ! or "not" (without the quotes)
且 : && or "and"
或 : || or "or"
7.1: 抓取目的地址是192.168.1.254或192.168.1.200端口是80的TCP數據
tcpdump '((tcp) and (port 80) and ((dst host 192.168.1.254) or (dst host 192.168.1.200)))'
當然上也可以像之前的加上指定網卡 -i enp0s3
tcpdump -i enp0s3 '((tcp) and (port 80) and ((dst host 192.168.1.254) or (dst host 192.168.1.200)))'
7.2: 抓取目標MAC地址是00:01:02:03:04:05的ICMP數據
tcpdump ‘((icmp) and ((ether dst host 00:01:02:03:04:05)))’
可以加上具體網卡
7.3:抓取目的網絡是192.168,但目的主機不是192.168.1.200的TCP數據
tcpdump '((tcp) and ((dst net 192.168) and (not dst host 192.168.1.200)))'
三:高級過濾包頭#
當我們繼續之前,必須瞭解tcp/ip包頭的頭部信息
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
操作符:
> : greater 大於
< : lower 小於
>= : greater or equal 大於或者等於
<= : lower or equal 小於或者等於
= : equal 等於
!= : different 不等於
第一次在這地方看見這個你可能不是很清楚
當然,在深入理解過濾頭部包,首先要了解協議頭是很重要的
- IP頭部:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version| IHL |Type of Service| Total Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identification |Flags| Fragment Offset |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Time to Live | Protocol | Header Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Destination Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding | <-- optional
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| DATA ... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
我們只考慮IPv4協議
- IP 選項設置
“一般”的IP頭是20字節,但IP頭有選項設置,不能直接從偏移21字節處讀取數據。IP頭有個長度字段可以知道頭長度是否大於20字節。
+-+-+-+-+-+-+-+-+
|Version| IHL |
+-+-+-+-+-+-+-+-+
通常第一個字節的二進制值是:01000101,分成兩個部分:
0100 = 4 表示IP版本 0101 = 5 表示IP頭32 bit的塊數,5 x 32 bits = 160 bits or 20 bytes
如果第一字節第二部分的值大於5,那麼表示頭有IP選項。
下面介紹兩種過濾方法(第一種方法比較操蛋,可忽略)
2.1. 比較第一字節的值是否大於01000101,這可以判斷IPv4帶IP選項的數據和IPv6的數據。
01000101十進制等於69,計算方法如下(小提示:用計算器更方便)
0 : 0 \
1 : 2^6 = 64 \ 第一部分 (IP版本)
0 : 0 /
0 : 0 /
-
0 : 0 \
1 : 2^2 = 4 \ 第二部分 (頭長度)
0 : 0 /
1 : 2^0 = 1 /
64 + 4 + 1 = 69
如果設置了IP選項,那麼第一自己是01000110(十進制70),過濾規則:
tcpdump 'ip[0] > 69'
當然可以加上網卡選項:-i enp0s3
IPv6的數據也可以匹配,第二種方法
2.2 位操作
0100 0101 : 第一字節的二進制
0000 1111 : 與操作
<=========
0000 0101 : 結果
正確的過濾方法
tcpdump 'ip[0] & 15 > 5'
或者
tcpdump 'ip[0] & 0x0f > 5'
我用了16進制掩碼.
That’s rather simple, if you want to:
- keep the last 4 bits intact, use 0xf (binary 00001111)
- keep the first 4 bits intact, use 0xf0 (binary 11110000)
2.3 分片標記 -Exercise: Is DF bit (don’t fragment) set?
當發送端的MTU大於到目的路徑鏈路上的MTU時就會被分片
分片信息在IP頭的第七和第八字節:
Bit 0: 保留,必須是0
Bit 1: (DF) 0 = 可能分片, 1 = 不分片
Bit 2: (MF) 0 = 最後的分片, 1 = 還有分片
Fragment Offset字段只有在分片的時候才使用。
要抓帶DF位標記的不分片的包,第七字節的值應該是:
01000000 = 64
tcpdump 'ip[6] = 64'
2.4 抓分片包
a:匹配MF,分片包
tcpdump 'ip[6] = 32'
b:匹配分片和最後分片
tcpdump '((ip[6:2] > 0) and (not ip[6] = 64))'
測試分片可以用下面命令:
ping -M want -s 3000 192.168.1.101
2.5 匹配小於ttl的數據報
TTL字段在第九字節,並且正好是完整的一個字節,TTL最大值是255,二進制爲11111111。
可以來驗證下,我們試着制定一個特需的ttl長度爲 256
$ ping -M want -s 3000 -t 256 192.168.1.200
ping: ttl 256 out of range
TTL 字段:
+-+-+-+-+-+-+-+-+
| Time to Live |
+-+-+-+-+-+-+-+-+
在網關可以用下面的命令看看網絡中誰在使用traceroute
tcpdump 'ip[8] < 5'
- 更多的過濾
tcp報文的基本結構
TCP 頭
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Acknowledgment Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data | |C|E|U|A|P|R|S|F| |
| Offset| Res. |W|C|R|C|S|S|Y|I| Window |
| | |R|E|G|K|H|T|N|N| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Checksum | Urgent Pointer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3.1 抓取源端口大於1024的TCP數據包
tcpdump 'tcp[0:2] > 1024'
or
tcpdump 'tcp src portrange 1025-65535'
3.2 匹配TCP數據包的特殊標記
TCP標記定義在TCP頭的第十四個字節
+-+-+-+-+-+-+-+-+
|C|E|U|A|P|R|S|F|
|W|C|R|C|S|S|Y|I|
|R|E|G|K|H|T|N|N|
+-+-+-+-+-+-+-+-+
在TCP 3次握手中,兩個主機是如何交換數據
1、源端發送 SYN
2、目標端口應答 SYN,ACK
3、源端發送 ACK
- 只抓取SYN包,第十四字節是二進制的00000010,也就是十進制的2
tcpdump 'tcp[13] = 2'
- 抓取 SYN,ACK (00010010 or 18)
tcpdump 'tcp[13] = 18'
- 抓取SYN或者SYN-ACK
tcpdump 'tcp[13] & 2 = 2'
我們使用了掩碼,它會返回任何事情,當ACK是二進制設置時候
讓我們看看下面的例子(SYN-ACK)
00010010 : SYN-ACK packet
00000010 : mask (2 in decimal)
==========
00000010 : result (2 in decimal)
- 抓取PSH-ACK
tcpdump 'tcp[13] = 24'
- 抓所有包含FIN標記的包(FIN通常和ACK一起,表示幽會完了,回頭見)
tcpdump 'tcp[13] & 1 = 1'
- 抓取RST
tcpdump 'tcp[13] & 4 = 4'
TCP標記值:
tcp-fin, tcp-syn, tcp-rst, tcp-push, tcp-push, tcp-ack, tcp-urg
- 抓取TCP標誌位
實際上有一個很簡單的方法過濾 flags(man pcap-filter and look for tcpflags)
tcpdump 'tcp[tcpflags] == tcp-ack'
- 抓取所有的包,用TCP-SYN 或者 TCP-FIN 設置
tcpdump 'tcp[tcpflags] & (tcp-syn|tcp-fin) != 0
下圖表示了TCP各狀態轉換的標記
tcpdump 提供了常用的字段偏移名字:
icmptype (ICMP類型字段)
icmpcode (ICMP符號字段)
tcpflags (TCP標記字段)
ICMP類型值有:
icmp-echoreply, icmp-unreach, icmp-sourcequench, icmp-redirect, icmp-echo, icmp-routeradvert, icmp-routersolicit,
icmp-timxceed, icmp-paramprob, icmp-tstamp, icmp-tstampreply, icmp-ireq, icmp-ireqreply, icmp-maskreq, icmp-maskreply
4: SMTP 數據過濾
我們將弄一個匹配任意包的過濾,這個包包括 “MAIL”
你可以用網址 http://www.easycalculation.com/ascii-hex.php 把ASCII轉化爲 十六進制, 也可以用python來轉化
$ python -c 'print "MAIL".encode("hex")'
4d41494c
所以 “MAIL” 的十六進制是:0x4d41494c
那麼規則就是
tcpdump '((port 25) and (tcp[20:4] = 0x4d41494c))'
這是一個包的例子
# tshark -V -i eth0 '((port 25) and (tcp[20:4] = 0x4d41494c))'
Capturing on eth0
Frame 1 (92 bytes on wire, 92 bytes captured)
Arrival Time: Sep 25, 2007 00:06:10.875424000
[Time delta from previous packet: 0.000000000 seconds]
[Time since reference or first frame: 0.000000000 seconds]
Frame Number: 1
Packet Length: 92 bytes
Capture Length: 92 bytes
[Frame is marked: False]
[Protocols in frame: eth:ip:tcp:smtp]
Ethernet II, Src: Cisco_X (00:11:5c:X), Dst: 3Com_X (00:04:75:X)
Destination: 3Com_X (00:04:75:X)
Address: 3Com_X (00:04:75:X)
.... ...0 .... .... .... .... = IG bit: Individual address (unicast)
.... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
Source: Cisco_X (00:11:5c:X)
Address: Cisco_X (00:11:5c:X)
.... ...0 .... .... .... .... = IG bit: Individual address (unicast)
.... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
Type: IP (0x0800)
Internet Protocol, Src: 62.163.X (62.163.X), Dst: 192.168.X (192.168.X)
Version: 4
Header length: 20 bytes
Differentiated Services Field: 0x00 (DSCP 0x00: Default; ECN: 0x00)
0000 00.. = Differentiated Services Codepoint: Default (0x00)
.... ..0. = ECN-Capable Transport (ECT): 0
.... ...0 = ECN-CE: 0
Total Length: 78
Identification: 0x4078 (16504)
Flags: 0x04 (Don't Fragment)
0... = Reserved bit: Not set
.1.. = Don't fragment: Set
..0. = More fragments: Not set
Fragment offset: 0
Time to live: 118
Protocol: TCP (0x06)
Header checksum: 0x08cb [correct]
[Good: True]
[Bad : False]
Source: 62.163.X (62.163.X)
Destination: 192.168.X (192.168.XX)
Transmission Control Protocol, Src Port: 4760 (4760), Dst Port: smtp (25), Seq: 0, Ack: 0, Len: 38
Source port: 4760 (4760)
Destination port: smtp (25)
Sequence number: 0 (relative sequence number)
[Next sequence number: 38 (relative sequence number)]
Acknowledgement number: 0 (relative ack number)
Header length: 20 bytes
Flags: 0x18 (PSH, ACK)
0... .... = Congestion Window Reduced (CWR): Not set
.0.. .... = ECN-Echo: Not set
..0. .... = Urgent: Not set
...1 .... = Acknowledgment: Set
.... 1... = Push: Set
.... .0.. = Reset: Not set
.... ..0. = Syn: Not set
.... ...0 = Fin: Not set
Window size: 17375
Checksum: 0x6320 [correct]
[Good Checksum: True]
[Bad Checksum: False]
Simple Mail Transfer Protocol
Command: MAIL FROM:<wguthrie_at_mysickworld--dot--com>\r\n
Command: MAIL
Request parameter: FROM:<wguthrie_at_mysickworld--dot--com>
- HTTP數據過濾
http請求開始格式
GET / HTTP/1.1\r\n (16 bytes counting the carriage return but not the backslashes !)
“GET ” 十六進制是 47455420
tcpdump 'tcp[32:4] = 0x47455420'
HTTP數據(從man tcpdump 看到的例子)
打印所有源或目的端口是80, 網絡層協議爲IPv4, 並且含有數據,而不是SYN,FIN以及ACK-only等不含數據的數據包.(ipv6的版本的表達式可做練習)
tcpdump 'tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)'
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
ip[2:2] = | Total Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+-+-+-+-+-+-+-+-+
ip[0] = |Version| IHL |
+-+-+-+-+-+-+-+-+
+-+-+-+-+-+-+-+-+
ip[0]&0xf = |# # # #| IHL | <-- that's right, we masked the version bits
+-+-+-+-+-+-+-+-+ with 0xf or 00001111 in binary
+-+-+-+-+
| Data |
tcp[12] = | Offset|
| |
+-+-+-+-+
- SSH過濾
我們看看ssh server
OpenSSH 常常應答一些內容,比如"SSH-2.0-OpenSSH_3.6.1p2", 這第一個4 bytes (SSH-)的十六進制值是 0x5353482D
tcpdump 'tcp[(tcp[12]>>2):4] = 0x5353482D'
如果我們想要找到老版本的OpenSSH的任意鏈接
這時候OpenSSH服務器應答的內容:比如 “SSH-1.99…”
tcpdump '(tcp[(tcp[12]>>2):4] = 0x5353482D) and (tcp[((tcp[12]>>2)+4):2] = 0x312E)'
- UDP頭
0 7 8 15 16 23 24 31
+--------+--------+--------+--------+
| Source | Destination |
| Port | Port |
+--------+--------+--------+--------+
| | |
| Length | Checksum |
+--------+--------+--------+--------+
| |
| DATA ... |
+-----------------------------------+
如果我們想要過濾,我們可以用下面的方法
tcpdump udp dst port 53
- ICMP頭
這裏本來顯示一張圖片,可是原文圖片沒有正確顯示,如實我找了一個圖,如下
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Code | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unused |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Internet Header + 64 bits of Original Data Datagram |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
在ICMP報文中,我們經常過濾 type(1 byte)和code(1 byte)
下圖是ICMP報文中 Type ,我們經常用到的幾個值:
0 Echo Reply [RFC792] 回顯應答報文
3 Destination Unreachable [RFC792] 目的不可達
4 Source Quench [RFC792] 源冷卻報文
5 Redirect [RFC792] 重定向報文
8 Echo [RFC792] 請求回顯報文
11 Time Exceeded [RFC792] 超時報文
如果我們要過濾報文 type = 4
tcpdump 'icmp[0] = 4'
如我我們僅僅是要找到ICMP 的回顯 應答報文,同時 ID是500。
tcpdump -i eth0 '(icmp[0] = 0) and (icmp[4:2] = 0x1f4)'
References
tcpdump man page : http://www.tcpdump.org/tcpdump_man.html
Conversions: http://easycalculation.com/hex-converter.php
Filtering HTTP requests: http://www.wireshark.org/tools/string-cf.html
Filtering data regardless of TCP options: http://www.wireshark.org/lists/wireshark-users/201003/msg00024.html