Heartbleed: OpenSSL密碼與加密密鑰泄露漏洞剖析
此次名為Heartbleed的OpenSSL漏洞引發了極其惡劣的影響,而為此暫時切斷互聯網連接肯定也不算什么理想的解決方案。僅僅由于廣泛使用的加密機制中存在一丁點微小缺陷,如今任何家伙都能輕松潛入存在漏洞的系統——包括銀行HTTPS服務器以及個人VPN——并瘋狂竊取密碼、登陸cookie、個人加密密鑰等等。
現在已經是2014年了,安全保障工作為何仍然如此不堪?
只需一份利用Metasploit引擎的簡單腳本外加短短幾秒鐘,惡意人士即可從依賴于OpenSSL 1.0.1到1.0.1f版本進行TLS加密的系統內存中提取到敏感數據。根據我們掌握的情況,這一漏洞影響到的網站約為五十萬個、占總體受信網站中的17.5%,此外任何使用上述OpenSSL版本的客戶端軟件、郵件服務器、聊天服務等也都在受影響范圍之內。
本周一開始已經有不少熱門網絡服務陸續針對這一漏洞發布修復補丁;大家可以利用相關工具檢查自己的系統是否已經中招(當然,風險要由各位自己承擔),同時也別忘了為自己已經受到感染的系統安裝OpenSSL修復補丁。除此之外,我們還需要更改密碼、轉儲會話cookie并對數據風險加以評估。
如果大家還不了解Heartbleed是怎么回事,這里提供概括描述:
這項嚴重缺陷(CVE-2014-0160)的產生是由于未能在memcpy()調用受害用戶輸入內容作為長度參數之前正確進行邊界檢查。攻擊者可以追蹤OpenSSL所分配的64KB緩存、將超出必要范圍的字節信息復制到緩存當中再返回緩存內容,這樣一來受害者的內存內容就會以每次64KB的速度進行泄露。大家可以點擊此處獲取修復補丁,需要強調的是此次問題遠比蘋果前一陣子曝出的安全問題嚴重得多。
問題源自TLS Heartbeat擴展
這一漏洞藏身于OpenSSL的TLS Heartbeat擴展當中:這是一項持續作用型功能,其中一個連接端會向另一端發送任意數據的有效負載,對方則發回對應數據的精確副本以確保傳輸過程一切正常。根據官方提供的標準說明,Heartbeat信息在C語言中表現為以下形式:
這條HeartbeatMessage通過SSL3_RECORD結構——一種SSL/TLS通信基礎構建塊——進行傳輸。SSL3_RECORD中的關鍵性字段如下所示,其中length代表接收到的HeartbeatMessage內容為多少字節、data則為指向該HeartbeatMessage的指針。
更明確地進行解釋,SSL3記錄中的data指向接收到的HeartbeatMessage的起始位置,而length代表接收到的HeartbeatMessage的字節數量。與此同時,HeartbeatMessage中的payload length代表被發回的隨意有效負載的字節數量。
發出HeartbeatMessage的一方對payload length擁有控制權,不過正如我們所看到,SSL3_RECORD中的length字段并沒有經過驗證、而這一狀況就成了攻擊者實現內存溢出絕佳機會。
以下圖表顯示了相關攻擊活動的工作原理:
請注意:其中并不包含填充字節
在上面的例子中,攻擊者在發出的HeartbeatMessage當中包含了僅為1字節的有效負載,這一情況也被反映在了SSL3的length記錄當中;不過payload length字段要求有效負載長度應該為65535字節。受害者忽略了SSL3記錄,轉而從內存接收到的HeartbeatMessage起始處開始讀取65535字節的數據并將其復制到緩存當中,最終以合適的長度發送回攻擊者處。由于包含大量額外字節,上圖中紅色單元格所示即為可能導致信息泄露的數據部分。
從代碼角度分析
以下代碼為OpenSSL對HeartbeatMessage輸入內容的處理方式,其中p為指向該信息起始處的指針:
這樣一來,信息類型就被體現在hbtype變量當中,該指針由1字節開始遞增,而n2s()宏將長度為16-bit的Heartbeat有效負載寫入到payload變量中并將該指針增加到2字節。接下來,pl又成為指向這部分有效負載內容的指針。
舉例來說,一條Heartbeat信息中的payload length為65535字節,即:一條接收到的Heartbeat中最多可能包含64KB有效負載。代碼必須將輸入的HeartbeatMessage以副本形式發送回去,從而保證緩存區擁有足夠的空間來保存64KB有效負載、1字節信息類型、2字節有效負載長度外加部分填充字節,具體結構如前所述。
它會利用以下代碼創建HeartbeatMessage回復結構,其中bp為指向HeartbeatMessage回復起始位置的指針:
因此這部分代碼會將響應類型寫入到緩存起始位置、遞增緩存指針、利用s2n()宏向內存中寫入16-bit payload長度并以2字節為單位遞增緩存指針,而后將payload的字節數量從接收到的有效負載中復制到用于回復的有效負載發送內容中。
請注意,payload由攻擊者全面控制,而且64KB也足以容納大量信息。假如由攻擊者發送的HeartbeatMessage只擁有1字節有效負載,而且其payload length又與實際情況不符,那么以上代碼中的memcpy()就會在接收到的HeartbeatMessage之外從起始處讀取受害者的內存進程。
而這部分內存很可能包含其它意義重大的信息,例如密碼內容或者來自其它客戶端的加密信息等。
事實上,盡管我們了解到雅虎已經對其系統進行了修復,但該公司仍然發布了如下建議:
請不要登陸雅虎網站。目前OpenSSL漏洞Heartbleed允許攻擊者提取用戶名以及簡單密碼信息!
— Mark Loman (@markloman),2014年4月8號
修復手段
OpenSSL 1.0.1g中的補丁從本質上講就是一項邊界檢查,旨在利用SSL3結構(s3->rrec)中的正確長度記錄描述輸入的HeartbeatMessage。
OpenSSL是在2011年12月31號星期六午夜期間耗時61分鐘完成TLS Heartbeat項目源代碼提交工作的。如今我們所承受的各種威脅可謂一場姍姍來遲的安全風暴。