今天要給大家介紹的一個 Unix 下的一個 網路數據採集分析工具,也就是我們常說的抓包工具。 與它功能類似的工具有 wireshark ,不同的是,wireshark 有圖形化界面,而 tcpdump 則只有命令行。 由於我本人更習慣使用命令行的方式進行抓包,因此今天先跳過 wireshark,直接 ...
今天要給大家介紹的一個 Unix 下的一個 網路數據採集分析工具,也就是我們常說的抓包工具。
與它功能類似的工具有 wireshark ,不同的是,wireshark 有圖形化界面,而 tcpdump 則只有命令行。
由於我本人更習慣使用命令行的方式進行抓包,因此今天先跳過 wireshark,直接給大家介紹這個 tcpdump 神器。
這篇文章,我肝了好幾天,藉助於Linux 的 man 幫助命令,我把 tcpdump 的用法全部研究了個遍,才形成了本文,不誇張的說,應該可以算是中文里把 tcpdump 講得最清楚明白,並且還最全的文章了(至少我從百度、谷歌的情況來看),所以本文值得你收藏分享,就怕你錯過了,就再也找不到像這樣把 tcpdump 講得直白而且特全的文章了。
在講解之前,有兩點需要聲明:
- 第三節到第六節里的 tcpdump 命令示例,只為了說明參數的使用,並不一定就能抓到包,如果要精準抓到你所需要的包,需要配合第五節的邏輯邏輯運算符進行組合搭配。
- 不同 Linux 發行版下、不同版本的 tcpdump 可能有小許差異, 本文是基於 CentOS 7.2 的 4.5.1 版本的tcpdump 進行學習的,若在你的環境中無法使用,請參考
man tcpdump
進行針對性學習。
1. tcpdump 核心參數圖解
大家都知道,網路上的流量、數據包,非常的多,因此要想抓到我們所需要的數據包,就需要我們定義一個精準的過濾器,把這些目標數據包,從巨大的數據包網路中抓取出來。
所以學習抓包工具,其實就是學習如何定義過濾器的過程。
而在 tcpdump 的世界里,過濾器的實現,都是通過一個又一個的參數組合起來,一個參數不夠精準,那就再加一個,直到我們能過濾掉無用的數據包,只留下我們感興趣的數據包。
tcpdump 的參數非常的多,初學者在沒有掌握 tcpdump 時,會對這個命令的眾多參數產生很多的疑惑。
就比如下麵這個命令,我們要通過 host
參數指定 host ip 進行過濾
$ tcpdump host 192.168.10.100
主程式
+ 參數名
+ 參數值
這樣的組合才是我們正常認知裡面命令行該有的樣子。
可 tcpdump 卻不走尋常路,我們居然還可以在 host 前再加一個限定詞,來縮小過濾的範圍?
$ tcpdump src host 192.168.10.100
從字面上理解,確實很容易理解,但是這不符合編寫命令行程式的正常邏輯,導致我們會有所疑慮:
-
除了 src ,dst,可還有其它可以用的限定詞?
-
src,host 應該如何理解它們,叫參數名?不合適,因為 src 明顯不合適。
如果你在網上看到有關 tcpdump 的博客、教程,無一不是給你一個參數組合,告訴你這是實現了怎樣的一個過濾器?這樣的教學方式,很容易讓你依賴別人的文章來使用 tcpdump,而不能將 tcpdump 這樣神器消化,達到靈活應用,靈活搭配過濾器的效果。
上面加了 src 本身就顛覆了我們的認知,你可知道在 src 之前還可以加更多的條件,比如 tcp, udp, icmp 等詞,在你之前的基礎上再過濾一層。
$ tcpdump tcp src host 192.168.10.100
這種參數的不確定性,讓大多數人對 tcpdump 的學習始終無法得其精髓。
因此,在學習 tcpdump 之前,我覺得有必要要先讓你知道:tcpdump 的參數是如何組成的?這非常重要。
為此,我畫了一張圖,方便你直觀的理解 tcpdump 的各種參數:
- option 可選參數:將在後邊一一解釋。
- proto 類過濾器:根據協議進行過濾,可識別的關鍵詞有: tcp, udp, icmp, ip, ip6, arp, rarp,ether,wlan, fddi, tr, decnet
- type 類過濾器:可識別的關鍵詞有:host, net, port, portrange,這些詞後邊需要再接參數。
- direction 類過濾器:根據數據流向進行過濾,可識別的關鍵字有:src, dst,同時你可以使用邏輯運算符進行組合,比如 src or dst
proto、type、direction 這三類過濾器的內容比較簡單,也最常用,因此我將其放在最前面,也就是 第三節:常規過濾規則一起介紹。
而 option 可選的參數非常多,有的甚至也不經常用到,因此我將其放到後面一點,也就是 第四節:可選參數解析
當你看完前面六節,你對 tcpdump 的認識會上了一個臺階,至少能夠滿足你 80% 的使用需求。
你一定會問了,還有 20% 呢?
其實 tcpdump 還有一些過濾關鍵詞,它不符合以上四種過濾規則,可能需要你單獨記憶。關於這部分我會在 第六節:特殊過濾規則 里進行介紹。
2. 理解 tcpdump 的輸出
2.1 輸出內容結構
tcpdump 輸出的內容雖然多,卻很規律。
這裡以我隨便抓取的一個 tcp 包為例來看一下
21:26:49.013621 IP 172.20.20.1.15605 > 172.20.20.2.5920: Flags [P.], seq 49:97, ack 106048, win 4723, length 48
從上面的輸出來看,可以總結出:
- 第一列:時分秒毫秒 21:26:49.013621
- 第二列:網路協議 IP
- 第三列:發送方的ip地址+埠號,其中172.20.20.1是 ip,而15605 是埠號
- 第四列:箭頭 >, 表示數據流向
- 第五列:接收方的ip地址+埠號,其中 172.20.20.2 是 ip,而5920 是埠號
- 第六列:冒號
- 第七列:數據包內容,包括Flags 標識符,seq 號,ack 號,win 視窗,數據長度 length,其中 [P.] 表示 PUSH 標誌位為 1,更多標識符見下麵
2.2 Flags 標識符
使用 tcpdump 抓包後,會遇到的 TCP 報文 Flags,有以下幾種:
[S]
: SYN(開始連接)[P]
: PSH(推送數據)[F]
: FIN (結束連接)[R]
: RST(重置連接)[.]
: 沒有 Flag (意思是除上面四種類型外的其他情況,有可能是 ACK 也有可能是 URG)
3. 常規過濾規則
3.1 基於IP地址過濾:host
使用 host
就可以指定 host ip 進行過濾
$ tcpdump host 192.168.10.100
數據包的 ip 可以再細分為源ip和目標ip兩種
# 根據源ip進行過濾
$ tcpdump -i eth2 src 192.168.10.100
# 根據目標ip進行過濾
$ tcpdump -i eth2 dst 192.168.10.200
3.2 基於網段進行過濾:net
若你的ip範圍是一個網段,可以直接這樣指定
$ tcpdump net 192.168.10.0/24
網段同樣可以再細分為源網段和目標網段
# 根據源網段進行過濾
$ tcpdump src net 192.168
# 根據目標網段進行過濾
$ tcpdump dst net 192.168
3.3 基於埠進行過濾:port
使用 port
就可以指定特定埠進行過濾
$ tcpdump port 8088
埠同樣可以再細分為源埠,目標埠
# 根據源埠進行過濾
$ tcpdump src port 8088
# 根據目標埠進行過濾
$ tcpdump dst port 8088
如果你想要同時指定兩個埠你可以這樣寫
$ tcpdump port 80 or port 8088
但也可以簡寫成這樣
$ tcpdump port 80 or 8088
如果你的想抓取的不再是一兩個埠,而是一個範圍,一個一個指定就非常麻煩了,此時你可以這樣指定一個埠段。
$ tcpdump portrange 8000-8080
$ tcpdump src portrange 8000-8080
$ tcpdump dst portrange 8000-8080
對於一些常見協議的預設埠,我們還可以直接使用協議名,而不用具體的埠號
比如 http == 80,https == 443 等
$ tcpdump tcp port http
3.4 基於協議進行過濾:proto
常見的網路協議有:tcp, udp, icmp, http, ip,ipv6 等
若你只想查看 icmp 的包,可以直接這樣寫
$ tcpdump icmp
protocol 可選值:ip, ip6, arp, rarp, atalk, aarp, decnet, sca, lat, mopdl, moprc, iso, stp, ipx, or netbeui
3.5 基本IP協議的版本進行過濾
當你想查看 tcp 的包,你也許會這樣子寫
$ tcpdump tcp
這樣子寫也沒問題,就是不夠精準,為什麼這麼說呢?
ip 根據版本的不同,可以再細分為 IPv4 和 IPv6 兩種,如果你只指定了 tcp,這兩種其實都會包含在內。
那有什麼辦法,能夠將 IPv4 和 IPv6 區分開來呢?
很簡單,如果是 IPv4 的 tcp 包 ,就這樣寫(友情提示:數字 6 表示的是 tcp 在ip報文中的編號。)
$ tcpdump 'ip proto tcp'
# or
$ tcpdump ip proto 6
# or
$ tcpdump 'ip protochain tcp'
# or
$ tcpdump ip protochain 6
而如果是 IPv6 的 tcp 包 ,就這樣寫
$ tcpdump 'ip6 proto tcp'
# or
$ tcpdump ip6 proto 6
# or
$ tcpdump 'ip6 protochain tcp'
# or
$ tcpdump ip6 protochain 6
關於上面這幾個命令示例,有兩點需要註意:
- 跟在 proto 和 protochain 後面的如果是 tcp, udp, icmp ,那麼過濾器需要用引號包含,這是因為 tcp,udp, icmp 是 tcpdump 的關鍵字。
- 跟在ip 和 ip6 關鍵字後面的 proto 和 protochain 是兩個新面孔,看起來用法類似,它們是否等價,又有什麼區別呢?
關於第二點,網路上沒有找到很具體的答案,我只能通過 man tcpdump
的提示, 給出自己的個人猜測,但不保證正確。
proto 後面跟的 <protocol>
的關鍵詞是固定的,只能是 ip, ip6, arp, rarp, atalk, aarp, decnet, sca, lat, mopdl, moprc, iso, stp, ipx, or netbeui 這裡面的其中一個。
而 protochain 後面跟的 protocol 要求就沒有那麼嚴格,它可以是任意詞,只要 tcpdump 的 IP 報文頭部里的 protocol 欄位為 <protocol>
就能匹配上。
理論上來講,下麵兩種寫法效果是一樣的
$ tcpdump 'ip && tcp'
$ tcpdump 'ip proto tcp'
同樣的,這兩種寫法也是一樣的
$ tcpdump 'ip6 && tcp'
$ tcpdump 'ip6 proto tcp'
4. 可選參數解析
4.1 設置不解析功能變數名稱提升速度
-n
:不把ip轉化成功能變數名稱,直接顯示 ip,避免執行 DNS lookups 的過程,速度會快很多-nn
:不把協議和埠號轉化成名字,速度也會快很多。-N
:不列印出host 的功能變數名稱部分.。比如,,如果設置了此選現,tcpdump 將會列印'nic' 而不是 'nic.ddn.mil'.
4.2 過濾結果輸出到文件
使用 tcpdump 工具抓到包後,往往需要再藉助其他的工具進行分析,比如常見的 wireshark 。
而要使用wireshark ,我們得將 tcpdump 抓到的包數據生成到文件中,最後再使用 wireshark 打開它即可。
使用 -w
參數後接一個以 .pcap
尾碼命令的文件名,就可以將 tcpdump 抓到的數據保存到文件中。
$ tcpdump icmp -w icmp.pcap
4.3 從文件中讀取包數據
使用 -w
是寫入數據到文件,而使用 -r
是從文件中讀取數據。
讀取後,我們照樣可以使用上述的過濾器語法進行過濾分析。
$ tcpdump icmp -r all.pcap
4.4 控制詳細內容的輸出
-v
:產生詳細的輸出. 比如包的TTL,id標識,數據包長度,以及IP包的一些選項。同時它還會打開一些附加的包完整性檢測,比如對IP或ICMP包頭部的校驗和。-vv
:產生比-v更詳細的輸出. 比如NFS回應包中的附加域將會被列印, SMB數據包也會被完全解碼。(摘自網路,目前我還未使用過)-vvv
:產生比-vv更詳細的輸出。比如 telent 時所使用的SB, SE 選項將會被列印, 如果telnet同時使用的是圖形界面,其相應的圖形選項將會以16進位的方式列印出來(摘自網路,目前我還未使用過)
4.5 控制時間的顯示
-t
:在每行的輸出中不輸出時間-tt
:在每行的輸出中會輸出時間戳-ttt
:輸出每兩行列印的時間間隔(以毫秒為單位)-tttt
:在每行列印的時間戳之前添加日期的列印(此種選項,輸出的時間最直觀)
4.6 顯示數據包的頭部
-x
:以16進位的形式列印每個包的頭部數據(但不包括數據鏈路層的頭部)-xx
:以16進位的形式列印每個包的頭部數據(包括數據鏈路層的頭部)-X
:以16進位和 ASCII碼形式列印出每個包的數據(但不包括連接層的頭部),這在分析一些新協議的數據包很方便。-XX
:以16進位和 ASCII碼形式列印出每個包的數據(包括連接層的頭部),這在分析一些新協議的數據包很方便。
4.7 過濾指定網卡的數據包
-i
:指定要過濾的網卡介面,如果要查看所有網卡,可以-i any
4.8 過濾特定流向的數據包
-Q
: 選擇是入方向還是出方向的數據包,可選項有:in, out, inout,也可以使用 --direction=[direction] 這種寫法
4.9 其他常用的一些參數
-
-A
:以ASCII碼方式顯示每一個數據包(不顯示鏈路層頭部信息). 在抓取包含網頁數據的數據包時, 可方便查看數據 -
-l
: 基於行的輸出,便於你保存查看,或者交給其它工具分析 -
-q
: 簡潔地列印輸出。即列印很少的協議相關信息, 從而輸出行都比較簡短. -
-c
: 捕獲 count 個包 tcpdump 就退出 -
-s
: tcpdump 預設只會截取前96
位元組的內容,要想截取所有的報文內容,可以使用-s number
,number
就是你要截取的報文位元組數,如果是 0 的話,表示截取報文全部內容。 -
-S
: 使用絕對序列號,而不是相對序列號 -
-C
:file-size,tcpdump 在把原始數據包直接保存到文件中之前, 檢查此文件大小是否超過file-size. 如果超過了, 將關閉此文件,另創一個文件繼續用於原始數據包的記錄. 新創建的文件名與-w 選項指定的文件名一致, 但文件名後多了一個數字.該數字會從1開始隨著新創建文件的增多而增加. file-size的單位是百萬位元組(nt: 這裡指1,000,000個位元組,並非1,048,576個位元組, 後者是以1024位元組為1k, 1024k位元組為1M計算所得, 即1M=1024 * 1024 = 1,048,576) -
-F
:使用file 文件作為過濾條件表達式的輸入, 此時命令行上的輸入將被忽略.
4.10 對輸出內容進行控制的參數
-D
: 顯示所有可用網路介面的列表-e
: 每行的列印輸出中將包括數據包的數據鏈路層頭部信息-E
: 揭秘IPSEC數據-L
:列出指定網路介面所支持的數據鏈路層的類型後退出-Z
:後接用戶名,在抓包時會受到許可權的限制。如果以root用戶啟動tcpdump,tcpdump將會有超級用戶許可權。-d
:列印出易讀的包匹配碼-dd
:以C語言的形式列印出包匹配碼.-ddd
:以十進位數的形式列印出包匹配碼
5. 過濾規則組合
有編程基礎的同學,對於下麵三個邏輯運算符應該不陌生了吧
- and:所有的條件都需要滿足,也可以表示為
&&
- or:只要有一個條件滿足就可以,也可以表示為
||
- not:取反,也可以使用
!
舉個例子,我想需要抓一個來自10.5.2.3
,發往任意主機的3389埠的包
$ tcpdump src 10.5.2.3 and dst port 3389
當你在使用多個過濾器進行組合時,有可能需要用到括弧,而括弧在 shell 中是特殊符號,因為你需要使用引號將其包含。例子如下:
$ tcpdump 'src 10.0.2.4 and (dst port 3389 or 22)'
而在單個過濾器里,常常會判斷一條件是否成立,這時候,就要使用下麵兩個符號
=
:判斷二者相等==
:判斷二者相等!=
:判斷二者不相等
當你使用這兩個符號時,tcpdump 還提供了一些關鍵字的介面來方便我們進行判斷,比如
- if:表示網卡介面名、
- proc:表示進程名
- pid:表示進程 id
- svc:表示 service class
- dir:表示方向,in 和 out
- eproc:表示 effective process name
- epid:表示 effective process ID
比如我現在要過濾來自進程名為 nc
發出的流經 en0 網卡的數據包,或者不流經 en0 的入方向數據包,可以這樣子寫
$ tcpdump "( if=en0 and proc =nc ) || (if != en0 and dir=in)"
6. 特殊過濾規則
5.1 根據 tcpflags 進行過濾
通過上一篇文章,我們知道了 tcp 的首部有一個標誌位。
tcpdump 支持我們根據數據包的標誌位進行過濾
proto [ expr:size ]
-
proto
:可以是熟知的協議之一(如ip,arp,tcp,udp,icmp,ipv6) -
expr
:可以是數值,也可以是一個表達式,表示與指定的協議頭開始處的位元組偏移量。 -
size
:是可選的,表示從位元組偏移量開始取的位元組數量。
接下來,我將舉幾個例子,讓人明白它的寫法,不過在那之前,有幾個點需要你明白,這在後面的例子中會用到:
1、tcpflags 可以理解為是一個別名常量,相當於 13,它代表著與指定的協議頭開頭相關的位元組偏移量,也就是標誌位,所以 tcp[tcpflags] 等價於 tcp[13] ,對應下圖中的報文位置。
2、tcp-fin, tcp-syn, tcp-rst, tcp-push, tcp-ack, tcp-urg 這些同樣可以理解為別名常量,分別代表 1,2,4,8,16,32,64。這些數字是如何計算出來的呢?
以 tcp-syn 為例,你可以參照下麵這張圖,計算出來的值 是就是 2
由於數字不好記憶,所以一般使用這樣的“別名常量”表示。
因此當下麵這個表達式成立時,就代表這個包是一個 syn 包。
tcp[tcpflags] == tcp-syn
要抓取特定數據包,方法有很多種。
下麵以最常見的 syn包為例,演示一下如何用 tcpdump 抓取到 syn 包,而其他的類型的包也是同樣的道理。
據我總結,主要有三種寫法:
1、第一種寫法:使用數字表示偏移量
$ tcpdump -i eth0 "tcp[13] & 2 != 0"
2、第二種寫法:使用別名常量表示偏移量
$ tcpdump -i eth0 "tcp[tcpflags] & tcp-syn != 0"
3、第三種寫法:使用混合寫法
$ tcpdump -i eth0 "tcp[tcpflags] & 2 != 0"
# or
$ tcpdump -i eth0 "tcp[13] & tcp-syn != 0"
如果我想同時捕獲多種類型的包呢,比如 syn + ack 包
1、第一種寫法
$ tcpdump -i eth0 'tcp[13] == 2 or tcp[13] == 16'
2、第二種寫法
$ tcpdump -i eth0 'tcp[tcpflags] == tcp-syn or tcp[tcpflags] == tcp-ack'
3、第三種寫法
$ tcpdump -i eth0 "tcp[tcpflags] & (tcp-syn|tcp-ack) != 0"
4、第四種寫法:註意這裡是 單個等號,而不是像上面一樣兩個等號,18(syn+ack) = 2(syn) + 16(ack)
$ tcpdump -i eth0 'tcp[13] = 18'
# or
$ tcpdump -i eth0 'tcp[tcpflags] = 18'
tcp 中有 類似 tcp-syn 的別名常量,其他協議也是有的,比如 icmp 協議,可以使用的別名常量有
icmp-echoreply, icmp-unreach, icmp-sourcequench,
icmp-redirect, icmp-echo, icmp-routeradvert,
icmp-routersolicit, icmp-timx-ceed, icmp-paramprob,
icmp-tstamp, icmp-tstampreply,icmp-ireq,
icmp-ireqreply, icmp-maskreq, icmp-maskreply
5.2 基於包大小進行過濾
若你想查看指定大小的數據包,也是可以的
$ tcpdump less 32
$ tcpdump greater 64
$ tcpdump <= 128
5.3 根據 mac 地址進行過濾
例子如下,其中 ehost 是記錄在 /etc/ethers 里的 name
$ tcpdump ether host [ehost]
$ tcpdump ether dst [ehost]
$ tcpdump ether src [ehost]
5.4 過濾通過指定網關的數據包
$ tcpdump gateway [host]
5.5 過濾廣播/多播數據包
$ tcpdump ether broadcast
$ tcpdump ether multicast
$ tcpdump ip broadcast
$ tcpdump ip multicast
$ tcpdump ip6 multicast
7. 如何抓取到更精準的包?
先給你拋出一個問題:如果我只想抓取 HTTP 的 POST 請求該如何寫呢?
如果只學習了上面的內容,恐怕你還是無法寫法滿足這個抓取需求的過濾器。
在學習之前,我先給出答案,然後再剖析一下,這個過濾器是如何生效的,居然能讓我們對包內的內容進行判斷。
$ 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 = 0001
-
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 報文首部里的數據偏移,請先點擊這個前往我的上一篇文章,搞懂數據偏移的意義,否則我保證你這裡會絕對會聽懵了。
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 認為這就是我們所需要抓的數據包,將其輸出到我們的終端屏幕上。
8. 抓包實戰應用例子
8.1 提取 HTTP 的 User-Agent
從 HTTP 請求頭中提取 HTTP 的 User-Agent:
$ tcpdump -nn -A -s1500 -l | grep "User-Agent:"
通過 egrep
可以同時提取User-Agent 和主機名(或其他頭文件):
$ tcpdump -nn -A -s1500 -l | egrep -i 'User-Agent:|Host:'
8.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'
註意:該方法不能保證抓取到 HTTP POST 有效數據流量,因為一個 POST 請求會被分割為多個 TCP 數據包。
8.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 : 按照數值大小逆向排序
8.4 抓取 DNS 請求和響應
DNS 的預設埠是 53,因此可以通過埠進行過濾
$ tcpdump -i any -s0 port 53
8.5 切割 pcap 文件
當抓取大量數據並寫入文件時,可以自動切割為多個大小相同的文件。例如,下麵的命令表示每 3600 秒創建一個新文件 capture-(hour).pcap
,每個文件大小不超過 200*1000000
位元組:
$ tcpdump -w /tmp/capture-%H.pcap -G 3600 -C 200
這些文件的命名為 capture-{1-24}.pcap
,24 小時之後,之前的文件就會被覆蓋。
8.6 提取 HTTP POST 請求中的密碼
從 HTTP POST 請求中提取密碼和主機名:
$ tcpdump -s 0 -A -n -l | egrep -i "POST /|pwd=|passwd=|password=|Host:"
8.7 提取 HTTP 請求的 URL
提取 HTTP 請求的主機名和路徑:
$ tcpdump -s 0 -v -n -l | egrep -i "POST /|GET /|Host:"
8.8 抓取 HTTP 有效數據包
抓取 80 埠的 HTTP 有效數據包,排除 TCP 連接建立過程的數據包(SYN / FIN / ACK):
$ tcpdump 'tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)'
8.9 結合 Wireshark 進行分析
通常 Wireshark
(或 tshark)比 tcpdump 更容易分析應用層協議。一般的做法是在遠程伺服器上先使用 tcpdump
抓取數據並寫入文件,然後再將文件拷貝到本地工作站上用 Wireshark
分析。
還有一種更高效的方法,可以通過 ssh 連接將抓取到的數據實時發送給 Wireshark 進行分析。以 MacOS 系統為例,可以通過 brew cask install wireshark
來安裝,然後通過下麵的命令來分析:
$ ssh root@remotesystem 'tcpdump -s0 -c 1000 -nn -w - not port 22' | /Applications/Wireshark.app/Contents/MacOS/Wireshark -k -i -
例如,如果想分析 DNS 協議,可以使用下麵的命令:
$ ssh root@remotesystem 'tcpdump -s0 -c 1000 -nn -w - port 53' | /Applications/Wireshark.app/Contents/MacOS/Wireshark -k -i -
抓取到的數據:
-c
選項用來限制抓取數據的大小。如果不限制大小,就只能通過 ctrl-c
來停止抓取,這樣一來不僅關閉了 tcpdump,也關閉了 wireshark。
到這裡,我已經將我所知道的 tcpdump 的用法全部說了一遍,如果你有認真地看完本文,相信會有不小的收穫,掌握一個上手的抓包工具,對於以後我們學習網路、分析網路協議、以及定位網路問題,會很有幫助,而 tcpdump 是我推薦的一個抓包工具。
9. 參考文章
- FreeBSD Manual Pages About tcpdump
- Linux tcpdump命令詳解
- 一份快速實用的 tcpdump 命令參考手冊
- 超詳細的網路抓包神器 tcpdump 使用指南
- [譯]tcpdump 示例教程
- [英]tcpdump 示例教程