天天看點

為什麼我抓不到baidu的資料包

作者:Java聯盟盟主

最近,有位讀者問起一個奇怪的事情,他說他想抓一個baidu.com的資料包,體驗下看包的樂趣。

但卻發現“抓不到”,這就有些奇怪了。

我來還原下他的操作步驟。

首先,通過ping指令,獲得通路百度時會請求哪個IP。

$ ping baidu.com
PING baidu.com (39.156.66.10) 56(84) bytes of data.
64 bytes from 39.156.66.10 (39.156.66.10): icmp_seq=1 ttl=49 time=30.6 ms
64 bytes from 39.156.66.10 (39.156.66.10): icmp_seq=2 ttl=49 time=30.6 ms
64 bytes from 39.156.66.10 (39.156.66.10): icmp_seq=3 ttl=49 time=30.6 ms
複制代碼           

從上面的結果可以知道請求baidu.com時會去通路39.156.66.10。

于是用下面的tcpdump指令進行抓包,大概的意思是抓eth0網卡且ip為39.156.66.10的網絡包,儲存到baidu.pcap檔案中。

$ tcpdump -i eth0 host 39.156.66.10 -w baidu.pcap
複制代碼           

此時在浏覽器中打開baidu.com網頁。或者在另外一個指令行視窗,直接用curl指令來模拟下。

$ curl 'https://baidu.com'
複制代碼           

按理說,通路baidu.com的資料包肯定已經抓下來了。

然後停止抓包。

再用wireshark打開baidu.pcap檔案,在過濾那一欄裡輸入http.host == "baidu.com"。

此時發現,一無所獲。

為什麼我抓不到baidu的資料包

這是為啥?

到這裡,有經驗的小夥伴,其實已經知道問題出在哪裡了。

為什麼沒能抓到包

這其實是因為他通路的是HTTPS協定的baidu.com。HTTP協定裡的Host和實際發送的request body都會被加密。

正因為被加密了,是以沒辦法通過http.host進行過濾。

但是。

雖然加密了,如果想篩選還是可以篩的。

HTTPS握手中的Client Hello階段,裡面有個擴充server_name,會記錄你想通路的是哪個網站,通過下面的篩選條件可以将它過濾出來。

tls.handshake.extensions_server_name == "baidu.com"
複制代碼           
為什麼我抓不到baidu的資料包

此時選中其中一個包,點選右鍵,選中Follow-TCP Stream。

為什麼我抓不到baidu的資料包

這個TCP連接配接的其他相關封包全都能被展示出來。

為什麼我抓不到baidu的資料包

從截圖可以看出,這裡面完整經曆了TCP握手和TLS加密握手流程,之後就是兩段加密資訊和TCP揮手流程。

可以看出18号和20号包,一個是從端口56028發到443,一個是443到56028的回包。

一般來說,像56028這種比較大且沒啥規律的數字,都是用戶端随機生成的端口号。

而443,則是HTTPS的伺服器端口号。

HTTP用的是80端口,如果此時對着80端口抓包,也會抓不到資料。

粗略判斷,18号和20号包分别是用戶端請求baidu.com的請求包和響應包。

點進去看會發現URL和body都被加密了,一無所獲。

那麼問題就來了。有沒有辦法解密裡面的資料呢?

有辦法。我們來看下怎麼做。

解密資料包

還是先執行tcpdump抓包

$ tcpdump -i eth0 host 39.156.66.10 -w baidu.pcap
複制代碼           

然後在另外一個指令行視窗下執行下面的指令,目的是将加密的key導出,并給出對應的導出位址是/Users/xiaobaidebug/ssl.key。

$ export SSLKEYLOGFILE=/Users/xiaobaidebug/ssl.key
複制代碼           

然後在同一個指令行視窗下,繼續執行curl指令或用指令行打開chrome浏覽器。目的是為了讓curl或chrome繼承這個環境變量。

$ curl 'https://baidu.com'
或者
$ open -a Google\ Chrome #在mac裡打開chrome浏覽器
複制代碼           

此時會看到在/Users/xiaobaidebug/下會多了一個ssl.key檔案。

這時候跟着下面的操作修改wireshark的配置項。

為什麼我抓不到baidu的資料包

找到Protocols之後,使勁往下翻,找到TLS那一項。

為什麼我抓不到baidu的資料包

将導出的ssl.key檔案路徑輸入到這裡頭。

為什麼我抓不到baidu的資料包

點選确定後,就能看到18号和20号資料包已經被解密。

為什麼我抓不到baidu的資料包

此時再用http.host == "baidu.com",就能過濾出資料了。

為什麼我抓不到baidu的資料包

到這裡,其實看不了資料包的問題就解決了。

但是,新的問題又來了。

ssl.key檔案是個啥?

這就要從HTTPS的加密原理說起了。

HTTPS握手過程

HTTPS的握手過程比較繁瑣,我們來回顧下。

先是建立TCP連接配接,畢竟HTTP是基于TCP的應用層協定。

在TCP成功建立完協定後,就可以開始進入HTTPS階段。

HTTPS可以用TLS或者SSL啥的進行加密,下面我們以TLS1.2為例。

總的來說。整個加密流程其實分為兩階段。

第一階段是TLS四次握手,這一階段主要是利用非對稱加密的特性各種交換資訊,最後得到一個"會話秘鑰"。

第二階段是則是在第一階段的"會話秘鑰"基礎上,進行對稱加密通信。

為什麼我抓不到baidu的資料包

我們先來看下第一階段的TLS四次握手是怎麼樣的。

第一次握手:

  • Client Hello:是用戶端告訴服務端,它支援什麼樣的加密協定版本,比如 TLS1.2,使用什麼樣的加密套件,比如最常見的RSA,同時還給出一個用戶端随機數。

第二次握手:

  • Server Hello:服務端告訴用戶端,伺服器随機數 + 伺服器證書 + 确定的加密協定版本(比如就是TLS1.2)。

第三次握手:

  • Client Key Exchange: 此時用戶端再生成一個随機數,叫 pre_master_key 。從第二次握手的伺服器證書裡取出伺服器公鑰,用公鑰加密 pre_master_key,發給伺服器。
  • Change Cipher Spec: 用戶端這邊已經擁有三個随機數: 用戶端随機數,伺服器随機數和pre_master_key,用這三個随機數進行計算得到一個"會話秘鑰"。此時用戶端通知服務端,後面會用這個會話秘鑰進行對稱機密通信。
  • Encrypted Handshake Message:用戶端會把迄今為止的通信資料内容生成一個摘要,用"會話秘鑰"加密一下,發給伺服器做校驗,此時用戶端這邊的握手流程就結束了,是以也叫Finished封包。

第四次握手:

  • Change Cipher Spec:服務端此時拿到用戶端傳來的 pre_master_key(雖然被伺服器公鑰加密過,但伺服器有私鑰,能解密獲得原文),集齊三個随機數,跟用戶端一樣,用這三個随機數通過同樣的算法獲得一個"會話秘鑰"。此時伺服器告訴用戶端,後面會用這個"會話秘鑰"進行加密通信。
  • Encrypted Handshake Message:跟用戶端的操作一樣,将迄今為止的通信資料内容生成一個摘要,用"會話秘鑰"加密一下,發給用戶端做校驗,到這裡,服務端的握手流程也結束了,是以這也叫Finished封包。

四次握手中,用戶端和服務端最後都擁有三個随機數,他們很關鍵,我特地加粗了表示。

第一次握手,産生的用戶端随機數,叫client random。

第二次握手時,伺服器也會産生一個伺服器随機數,叫server random。

第三次握手時,用戶端還會産生一個随機數,叫pre_master_key。

這三個随機數共同構成最終的對稱加密秘鑰,也就是上面提到的"會話秘鑰"。

為什麼我抓不到baidu的資料包

你可以簡單的認為,隻要知道這三個随機數,你就能破解HTTPS通信。

而這三個随機數中,client random 和 server random 都是明文的,誰都能知道。而pre_master_key卻不行,它被伺服器的公鑰加密過,隻有用戶端自己,和擁有對應伺服器私鑰的人能知道。

是以問題就變成了,怎麼才能得到這個pre_master_key?

怎麼得到pre_master_key

伺服器私鑰不是誰都能拿到的,是以問題就變成了,有沒有辦法從用戶端那拿到這個pre_master_key。

有的。

用戶端在使用HTTPS與服務端進行資料傳輸時,是需要先基于TCP建立HTTP連接配接,然後再調用用戶端側的TLS庫(OpenSSL、NSS)。觸發TLS四次握手。

這時候如果加入環境變量SSLKEYLOGFILE就可以幹預TLS庫的行為,讓它輸出一份含有pre_master_key的檔案。這個檔案就是我們上面提到的/Users/xiaobaidebug/ssl.key。

為什麼我抓不到baidu的資料包

但是,雖然TLS庫支援導出key檔案。但前提也是,上層的應用程式在調用TLS庫的時候,支援通過SSLKEYLOGFILE環境觸發TLS庫導出檔案。實際上,也并不是所有應用程式都支援将SSLKEYLOGFILE。隻是目前常見的curl和chrome浏覽器都是支援的。

SSLKEYLOGFILE檔案内容

再回過頭來看ssl.key檔案裡的内容。

# SSL/TLS secrets log file, generated by NSS
CLIENT_RANDOM 5709aef8ba36a8eeac72bd6f970a74f7533172c52be41b200ca9b91354bd662b 09d156a5e6c0d246549f6265e73bda72f0d6ee81032eaaa0bac9bea362090800174e0effc93b93c2ffa50cd8a715b0f0
CLIENT_RANDOM 57d269386549a4cec7f91158d85ca1376a060ef5a6c2ace04658fe88aec48776 48c16429d362bea157719da5641e2f3f13b0b3fee2695ef2b7cdc71c61958d22414e599c676ca96bbdb30eca49eb488a
CLIENT_RANDOM 5fca0f2835cbb5e248d7b3e75180b2b3aff000929e33e5bacf5f5a4bff63bbe5 424e1fcfff35e76d5bf88f21d6c361ee7a9d32cb8f2c60649135fd9b66d569d8c4add6c9d521e148c63977b7a95e8fe8
CLIENT_RANDOM be610cb1053e6f3a01aa3b88bc9e8c77a708ae4b0f953b2063ca5f925d673140 c26e3cf83513a830af3d3401241e1bc4fdda187f98ad5ef9e14cae71b0ddec85812a81d793d6ec934b9dcdefa84bdcf3
複制代碼           

這裡有三列。

第一列是CLIENT_RANDOM,意思是接下來的第二列就是用戶端随機數,再接下來的第三列則是pre_master_key。

但是問題又來了。

這麼多行,wireshark怎麼知道用哪行的pre_master_key呢?

wireshark是可以獲得資料封包上的client random的。

比如下圖這樣。

為什麼我抓不到baidu的資料包

注意上面的用戶端随機數是以 "bff63bbe5"結尾的。

同樣,還能在資料封包裡拿到server random。

為什麼我抓不到baidu的資料包

此時将client random放到ssl.key的第二列裡挨個去做比對。

就能找到對應的那一行記錄。

為什麼我抓不到baidu的資料包

注意第二列的那串字元串,也是以 "bff63bbe5"結尾的,它其實就是前面提到的client random。

再取出這一行的第三列資料,就是我們想要的pre_master_key。

那麼這時候wireshark就集齊了三個随機數,此時就可以計算得到會話秘鑰,通過它對資料進行解密了。

反過來,正因為需要用戶端随機數,才能定位到ssl.key檔案裡對應的pre_master_key是哪一個。而隻有TLS第一次握手(client hello)的時候才會有這個随機數,是以如果你想用解密HTTPS包,就必須将TLS四次握手能抓齊,才能進行解密。如果連接配接早已經建立了,資料都來回傳好半天了,這時候你再去抓包,是沒辦法解密的。

總結

  • 文章開頭通過抓包baidu的資料包,展示了用wireshark抓包的簡單操作流程。
  • HTTPS會對HTTP的URL和Request Body都進行加密,是以直接在filter欄進行過濾http.host == "baidu.com"會一無所獲。
  • HTTPS握手的過程中會先通過非對稱機密去交換各種資訊,其中就包括3個随機數,再通過這三個随機數去生成對稱機密的會話秘鑰,後續使用這個會話秘鑰去進行對稱加密通信。如果能獲得這三個随機數就能解密HTTPS的加密資料包。
  • 三個随機數,分别是用戶端随機數(client random),服務端随機數(server random)以及pre_master_key。前兩個,是明文,第三個是被伺服器公鑰加密過的,在用戶端側需要通過SSLKEYLOGFILE去導出。
  • 通過設定SSLKEYLOGFILE環境變量,再讓curl或chrome會請求HTTPS域名,會讓它們在調用TLS庫的同時導出對應的sslkey檔案。這個檔案裡包含了三列,其中最重要的是第二列的client random資訊以及第三列的pre_master_key。第二列client random用于定位,第三列pre_master_key用于解密。
原文連結:https://juejin.cn/post/7165737844613316638

繼續閱讀