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