小錯誤引發大危機——心臟出血到底是什么?
心臟出血漏洞可以追根溯源到開源代碼庫OpenSSL里的一行代碼上。本文將告訴你心臟出血的工作原理、利用狀況以及怎樣修復未打補丁的服務器。
2014年4月,心臟出血漏洞進入了公眾視野,該漏洞為攻擊者提供了前所未有的敏感信息獲取途徑,并且成千上萬的網絡服務器上存在心臟出血漏洞,就連雅虎這樣的網絡巨頭也在此列。
開源代碼庫OpenSSL中的一個漏洞是引發心臟出血的罪魁禍首,該漏洞使用了傳輸層安全協議(TLS)和加密套接字協議層(SSL)協議。通過這個漏洞,簡而言之,惡意用戶可以很容易地誘騙一個脆弱的網絡服務器發送用戶名和密碼等敏感信息。
心臟出血漏洞的工作原理
要了解心臟出血(CVE-2014-0160)的工作原理,你必須對TLS/SSL協議的運作模式和內存存儲信息的方式有些許的認識。
TLS / SSL協議的一個重要組成部分被稱為“心跳”。從本質上講,心跳就是兩臺電腦互相通信從而讓對方知道它們仍然相連,即使用戶沒有下載或上傳任何東西。每過一段時間,一方會發送一個加密的數據到另一臺電腦上,這被稱為心跳請求。第二臺電腦會回復同樣的加密數據,來證明連接仍然存在。至關重要的是,心跳請求里包含自己的長度信息。
舉個例子,如果你正在翻閱你的雅虎郵箱,但是在一段時間內沒有進行加載信息到操作,網頁瀏覽器可能會給雅虎的服務器發送一個信號,該信號本質上是“這是一個40KB的消息,你如果能獲得它,把它發回給我”(請求信號可以最多可以達到64KB)。雅虎的服務器收到消息時,會分配一個內存緩沖區(一個物理內存區域用以存儲信息),該區域的存儲空間和心跳請求信號里的長度一致,即40KB。接下來,它會存儲請求信號的加密數據到內存緩沖區,然后讀取數據并將其發送回你的瀏覽器。
這是“心跳”的理想工作方式。心臟出血漏洞的出現是因為,OpenSSL的心跳功能缺少了一個至關重要的安全維護手段:計算機接受心跳請求時從不檢查該請求和它聲稱的內容是否一致。如果請求說自身的長度是40KB,但其實只有20KB,接收電腦會預留40KB的內存緩沖區,然后只存儲實際接受的20KB數據,然后發送回20KB的原數據和接下來20KB的未知內容內存。這額外的20KB的數據就是攻擊者從網站服務器中提取的信息。
這是操作的關鍵部分。即使計算機處理過某些信息,這些信息會留在內存緩沖區直到新的信息出現并覆蓋它。如果你是攻擊者,你沒有辦法提前知道剛剛從服務器獲取的20KB里究竟有什么,但是你可以推測出一些可能。這些信息有可能是胡言亂語或者無用而繁瑣的東西,也有可能是SSL私鑰,這會把服務器的安全通信暴露給攻擊者(這個可能性很小,但是卻是攻擊者的最高追求)。更常見的是,攻擊者可能會獲得用戶名和密碼,服務器上的應用或服務收集并保存了這些信息,這將給予攻擊者登錄和訪問渠道。
蘭德爾·門羅的網絡漫畫xkcd因為將復雜的科學概念通過淺顯易懂的形式表達而出名,門羅尤其擅長就計算機領域的問題作畫。這個2014年誕生的漫畫很好地總結了心臟出血漏洞是怎樣簡單而高效地運作的。
心臟出血錯誤代碼
導致心臟出血漏洞的編程錯誤可以歸于一行代碼:
- memcpy(bp, pl, payload);
memcpy()是復制數據的命令。bp是被復制的數據的存儲區域,pl是被復制的數據的來源,payload是被復制的數據長度。問題在于,該命令沒有檢驗pl復制的數據是否和payload給予的長度相符。
諷刺的是,OpenSSL是開源軟件。任何人都可以查看代碼,大概幾百人曾訪問過這段代碼,但是沒有人注意到相當基本的編碼錯誤。
心臟出血的利用狀況
我們至今不知道,在心臟出血廣為人知前,是否有利用該漏洞的現實攻擊。很可能早在2013年被某些安全公司偵測到的攻擊就是基于該漏洞的,有人甚至認為這些攻擊是由政府安全部門發起的。
在2014年4月心臟出血漏洞被公開后,企業爭先恐后地更新了系統。但是黑客仍然能夠在一些情況下利用該漏洞。一起對社區衛生系統的攻擊被歸咎于心臟出血漏洞,結果是病人數據被大量竊取,與之類似的是加拿大稅務署數以百計的社會身份號碼被盜。
如何修復心臟出血漏洞
心臟出血剛被揭露不久,OpenSSL就發布了補丁,而且百分之八九十的受影響服務器及時更新了補丁,但是,總會有些對你來說至關重要的服務器多年來從未進行合適的升級,因此,在你不明了某個服務器是否已經安全的情況下,不妨做個測試。Pentest-tools.com有一個免費的網絡測試,你可以輸入一個URL來檢測服務器是否已經正確地修復了該漏洞。
修補心臟出血漏洞的方式是更新最新的OpenSSL版本,你可以在官網上獲取相關鏈接。
因為OpenSSL是開源的,以下是修復過的代碼,感興趣的話你可以讀一下:
- * Read type and payload length first */
- if (1 + 2 + 16 > s->s3->relent)
- return 0;
- /* silently discard */
- hbtype = *p++;
- n2s(p, payload);
- if (1 + 2 + payload + 16 > s->s3->rrec.length)
- return 0;
- /* silently discard per RFC 6520 sec. 4 */
- ppl = p;
代碼的第一部分的功能是確定心跳請求的大小不是0KB,不然可能會出錯。第二部分用來檢驗心跳的長度是否和它聲稱的相符。
如果你發現自己控制的某臺服務器已經暴露在該漏洞下有一段時間,你需要做的就不僅僅是更新OpenSSL的代碼了。例如,你應該改變SSL證書服務器,因為它們可能已經被無聲無息地滲透了。此外,較為麻煩但重要的是:服務器上保有賬戶信息的用戶應該更改密碼。
【本文是51CTO專欄作者“”李少鵬“”的原創文章,轉載請通過安全牛(微信公眾號id:gooann-sectv)獲取授權】