[轉]HTTPS網路流量解密方法探索系列(一)
前言
分析網路流量總是繞不開HTTPS,因其廣泛使用甚至是強制使用逐漸被大眾熟知,在保證其安全的同時也提高了對流量進行研究的難度。目前解析HTTPS協議的文章很多,有很多不錯的文章可以帶著入門,老實說,HTTPS協議還是挺複雜的,尤其是握手交換金鑰的過程;雖然大部分的文章只是對協議握手的過程做了詳細的解析,卻很少涉及HTTPS網路資料包解密的部分,因此,本文即是從資料包層面,在知道私鑰的情況下,來一步一步看如何對HTTPS的內容進行解密。
正文
要對HTTPS網路資料包進行解密,其實是有一些工具是可以使用的,比如wireshark和ssldump,現在,先讓我們來看看這兩款工具如何使用,在手動對HTTPS的資料包進行解密。
1.wireshark解密HTTPS資料包
首先是wireshark,在wireshark介面上方,依次點選 編輯->首選項。
再點選Protocols 找到SSL,並進行必要配置:
先是對RSA keys list進行編輯,點選Edit完成配置,如下所示:
點選加號,依次配置(伺服器IP、目的埠、應用層協議、私鑰路徑)。然後對SSL debugfile進行配置,在這裡面,wireshark會打印出解密過程中的除錯資訊,非常有用,後文在進行手動解密的時候即是通過它發現的錯誤,按照前文配置到一個路徑下,配置完成點選ok後,可在wireshark主介面解密出通訊內容。
如圖所示,順利解出了HTTP的內容,在大呼神奇的同時,我們對它的解密過程卻一無所知,這其實是不利於學習的,所以本文即是來掃除這些盲點。下面我們再來看看ssldump工具的使用。
ssldump是一款Linux下的小工具,可直接用apt包管理工具安裝,目前最新版本是ssldump0.9b3(13年後就停止更新了,可以下載原始碼)。在shell中執行:
ssldump -Ad -k./private.pem -r ./ssl.pcap
該條命令會打印出部分的解密過程,如下圖所示:
從該圖中可以看到client/server產生的隨機數(random),加密的預主密碼(EncryptedPremaster secret),以及用到的加密套件,為:
TLS_RSA_WITH_AES_256_CBC_SHA
表示採用RSA進行身份認證和對稱金鑰交換,採用AES 256位對稱加密演算法,加密模式為CBC,採用SHA進行訊息認證。雖然工具已經解出了HTTP的請求內容,但是列印資訊中未打印出解密後的主密碼和對稱金鑰,因此,列印資訊沒有完整反映解密過程,這款工具在centos下還會出現core dumped錯誤,感覺不是太好用。
2.HTTPS協議簡介
雖然已經有不少的帖子非常詳細地介紹了HTTPS協議,但是本文依然選擇簡單介紹一下HTTPS協議,主要側重於對解密中要用到的引數進行說明。如下圖所示,為HTTPS完整握手的流程圖。
圖中完整地反映了HTTPS的握手過程,在此過程中,Client會同Server互動若干引數來協商對稱金鑰,用來對應用資料進行加解密。這裡筆者以TLS_RSA_WITH_AES_256_CBC_SHA這個密碼套件為例,講述整個解密過程。那麼,解密過程需用到的引數如下:
1.clientrandom 客戶端隨機數;
2.serverrandom 伺服器隨機數;
3.EncryptedPreMaster 加密的預備主密碼。
如上圖所示,解密的過程大致為:先用私鑰對Encrypted PreMaster Secret進行解密,得到decrypted PreMaster Secret;再用client random、server random、decrypted PreMaster 得到Master Secret;再用MasterSecret計算出訊息認證金鑰(key of MAC)、資料加密對稱金鑰和CSC模式用到的初始化向量值(iv),得到金鑰後即可對通訊內容進行解密了。看似過程很簡單,實際上只有實驗一把才會更好理解整個過程。
3.HTTPS網路資料包手動解密
在解密之前,需要說明的是,並不需要自己寫解密程式碼來完成資料的解密,有很多好用的工具可以完成這件事,我們需要做的是,把整個流程串起來即可。本文中所使用的解密工具為openssl,很強大的工具,用它完成非對稱加解密和對稱加解密是相當方便的。
實驗準備:本文的流量樣本採用的TLS1.0版本,雖然目前主流是用TLS1.2,但是這兩個版本基本框架一致,弄懂了前者,後者也是很好理解的,流程稍作改動同樣能完成解密;以學習為目的,從1.0開始是一個不錯的選擇。本文流量的加密套件採用RSA非對稱加密交換對稱金鑰引數,採用AES256對通訊流量進行加密。所有的實驗材料已上傳到github中。
那就正式開始吧,首先是在資料包中將client random,server random和Encrypted PreMaster的二進位制資料提取出來。如下圖所示,在wireshark中分別找到clienthello、serverhello、clientkey exchange資料包,選擇要匯出的欄位,點選滑鼠右鍵,選擇匯出分組位元組流,存成bin檔案,分別為client_random.bin、server_random.bin、premaster-encrypted.bin。
在Ubuntu中檢視結果,這三個二進位制檔案的內容分別為:
首先,是對premaster-encrypted.bin進行解密。利用已獲得的私鑰private.pem進行解密,解密命令為:
openssl pkeyutl -decrypt -in ./premaster-encrypted.bin -inkey ./private.pem -out premaster-decrypted.bin
如未報錯,代表執行成功,將解密的資料存入到premaster-decrypted.bin檔案中,用hexdump可檢視。
就得到解密後的預備主密碼,對於密碼專家來說,得到預備主密碼跟最後一步解密內容是等價的。但對於我們來說,還有幾步要折騰。
下一步,即是利用預備主密碼計算主密碼,在此過程中,還需利用clientrandom和serverrandom,用命令將client_random.bin,server_random.bin兩個檔案合併起來。
cat client_random.bin server_random.bin > random_cs.bin
用hexdump檢視有如下結果:
然後用偽隨機函式計算(PRF)計算主密碼,偽隨機函式計算程式需在windows下執行,命令如下。
.\PRF.exe--label "master secret" --length 48 --secret.\premaster-decrypted.bin --data .\random_cs.bin --output master-secret.bin
PRF.exe為網上分享的計算程式,源程式見這裡,本文的github中已作分享。利用這款程式就可得到主密碼檔案master-secret.bin,用hexdump檢視為:
這種計算主金鑰的方法存在漏洞,在TLS1.2版本中已做調整。接下來,就可以利用主密碼計算加密傳輸資料的對稱金鑰和其他引數了。在解密之前,需要用先生成random_sc.bin,如下:
cat server_random.bin client_random.bin > random_sc.bin
與上一個檔案不同的是client random和server random的順序不一樣,得到random_sc.bin。然後,同樣在windows下執行,命令如下:
.\PRF.exe--secret .\master-secret.bin --label "key expansion" --data.\random_sc.bin -n 136 -o key-expansion.bin
得到key-expansion.bin檔案,用hexdump檢視為:
這樣利用主密碼生成了6種資訊,分別是:
20位元組的訊息認證碼金鑰(客戶端→伺服器)
20位元組的訊息認證碼的金鑰(伺服器→客戶端)
32位元組的對稱密碼金鑰(客戶端→伺服器)
32位元組的對稱密碼的金鑰(伺服器→客戶端)
16位元組的對稱密碼的CBC模式所使用的初始化向量(客戶端→伺服器)
16位元組的對稱密碼的CBC模式所使用的初始化向量(伺服器→客戶端)
位元組數加起來剛好同key-expansion.bin檔案的位元組數吻合,在此,就得到了對稱加密時所使用的金鑰。客戶端到伺服器的對稱金鑰為:
a86b855b66c5dc18566879eb98e8a86b7c90c5564438f3af80b317dcb5a25747
現在我們就可以用它來解密客戶端到伺服器的應用資料內容。在正式解密前,我們先按照上述方法將客戶端到服務端的應用層資料提取成二進位制檔案,為client-request.bin,然後用如下命令進行解密:
openssl enc-aes-256-cbc -d -K $cs_key -iv $iv_value -in .\client-request.bin -out.\client-request-decrypted.bin
其中,$cs_key為客戶端到伺服器傳送訊息的金鑰,iv為上一個訊息內容中最後一個分組的值,iv的值僅憑這句話,不太好找,我也是試出來的。確定iv值的方法如下所示:
圖中第24個數據包為要解密的內容,上一個訊息指的是客戶端到伺服器方向的上一個訊息,也即是第20個包,最後一個分組的值為該資料包最後16個位元組,如下圖所示:
第20個數據包的最後一個分組,即iv就是: ed605d761378241c7add3c921022b268。需要說明的是,iv值的計算方法在TLS1.0版本存在漏洞,在TLS1.2版本中已做更改。得到iv就可執行解密命令,並將解密內容存在client-request-decrypted.bin檔案中,用hexdump和cat檢視:
如上圖所示,順利解出HTTP協議的請求內容,最後有一段亂碼,那是HMAC的值,做訊息認證用,感興趣的朋友可以自己去看訊息認證相關內容,這裡只需解出明文資料就行了。對於伺服器到客戶端的訊息,採用同樣的方法,也可以解出來,但用到的是伺服器到客戶端的金鑰。
大家照著這個流程可以很快地復現出來,但筆者在此過程中踩過很多坑,有時也不知道哪一步計算錯了,由於只要任何一部出錯,後面的都不對,挺折騰的。不過,要解決除錯問題,wireshark的debug檔案很有用,裡面把每一步需要計算的引數都打印出來了,部分結果如下圖所示:
client write key就是客戶端到伺服器的對稱加密金鑰,同我們計算的一樣。因此,可對照著debug檔案的結果,檢視哪一步算錯了,這可以幫助開發人員快速定位到問題。
既然手動能解出來,那下一步就是自動化實現了,這也不難,openssl提供有C和Python開發庫,複雜的密碼演算法不用我們來實現,呼叫API解密函式即可。在以後的系列篇中,即是完成自動解密程式,以及加上對TLS1.2的支援。
總結
HTTPS協議是比較複雜的一個協議,要想學習它,光看它的技術原理是不得要領的,本文也是筆者在對它學習的過程中產生。嘗試通過手動解密HTTPS資料包的過程是很有趣的,也能加強對HTTPS協議的理解。其中關於數字證書驗證和訊息認證本文沒有涉及,由讀者自己去研究了。對HTTPS協議的研究,大家如有其它的點,歡迎一起討論。