1. 程式人生 > >OpenSSL嚴重安全漏洞CCS

OpenSSL嚴重安全漏洞CCS

     繼之前爆出的“心臟出血”漏洞後,openSSL再被爆出另一個嚴重漏洞,最初在開源中國看到文章時把CCS看成了CSS,囧~~

“OpenSSL 的 ChangeCipherSpec 處理再報嚴重安全漏洞,該漏洞使得攻擊者可以攔截惡意中間節點加密和解密資料,同時迫使使用弱金鑰的SSL客戶端暴露在惡意節點。” 

借用文章裡的CCS注入的圖:

下面翻譯漏洞發現者的部落格:“我是如何發現CCS注入攻擊的”.

原文地址:http://ccsinjection.lepidum.co.jp/blog/2014-06-05/CCS-Injection-en/index.html

什麼是CCS注入漏洞

   在客戶端和服務端握手階段,OpenSSL協議不合時宜地接受密碼更換說明(ChangeCipherSpec :CCS),而產生了該漏洞。而且,從第一個版本的OpenSSL起,這個漏洞就一直存在。


   如圖,在握手階段需要兩次傳送ChangeCipherSpec訊息,OpenSSL也確實是按照正確的時間傳送CCS,然而,CCS訊息卻可以在其他時間裡被接收。攻擊者就可以利用這一行為解密或者修改傳輸通道里的資料。

發現漏洞有多難

    造成CCS漏洞16年沒有被發現的原因是OpenSSL實現缺少全面的程式碼審查(code reviews)。如果審查者有一定的TLS和SSL開發經驗,那麼他們就應該能自己發現這個問題。

   模糊測試也許很有效,但歷史經驗表明,擁有TLS/SSL開發經驗對發現OpenSSL安全問題尤為重要:

   CVE-2004-0079是Codenomicon發現CCS漏洞,也是第一個CCS漏洞。 之後

Fix null-pointer assignment in do_change_cipher_spec() revealed被加入到OpenSSL中以修補這個漏洞。這個方法保證了CCS只在有新的密碼產生後才被接收,然而這個新的密碼在伺服器端請求連線是就產生了,所有該方法並不能真正地防止CCS注入。

   DTLS: SegFault if ChangeCipherSpec is received before ClientHello

  這個漏洞是因為在DTLS握手階段太早地接收CCS訊息,造成了分段錯誤。針對CCS時序驗證也並沒有很好滴被解決

DTLS fragment retransmission bug

    OpenSSL的第 #1950 補丁修改了帶漏洞。

   該補丁增加了對不可預測報文衝排序的驗證,解決了DTLS握手中的CCS時序問題。進一步分析該補丁可以發現,一個非計算的主金鑰被用來加密,這個值被告知是從未被初始化的記憶體中讀取的,不能使用隨機值。然而事實是:這個值是一串空位元序列,如果這個問題被及早發現,這個CCS攻擊的可能性將大大降低。

正確實現CCS有多難?

    答案是:非常簡單!   只需要保證CCS的傳送和接收順序都按照上圖中的協議流程進行。然而這裡包含了一個意外:CCS訊息的序列標識和其他握手訊息的序列標識不是同一種類型。RFC的解釋如下:

   Note:          To help avoid pipeline stalls, ChangeCipherSpec is
                 an independent SSL Protocol content type, and is not
                 actually an SSL handshake message.
   draft-ietf-tls-ssl-version3-00 §5.5

     我認為,這個決定就是導致CCS脆弱性的根源。根據RFC給出的解釋,CCS使用獨立的序列標識(也就是說CCS不算是真正的SSL握手訊息)是為了避免“流水線停頓”(pipeline stall)。這就使得TLS/SSL的握手階段需要非常複雜的同步機制:首先,OpenSSL協議需要等待握手過程進行到合適的階段;其次,協議需要去檢查握手階段在結束之前是否接受到CCS訊息。

   詳細地,當接收到CCS訊息時,需要檢驗以下三個情況:(*)

  • 握手過程是否進行到合適階段,例如是否是在握手結束之前收到
  • 握手過程沒有其他片段
  • 下一個訊息是否完成

    更需要小心的是你還得檢查下面兩個情況(詳見Alert attack.):

  • 沒有警告片段
  • 沒有心跳片段

    RFC估計是想表達出下面兩個顧慮:

  • 避免CCS被夾雜在其他握手片段裡傳輸。
  • 為了避免流水線停頓,伺服器和客戶端都需要傳送CCS訊息。

我是如何發現這個漏洞的

    “心臟出血”漏洞暴露後,大家都在討論和研究如何避免類似這種的bug,單元測試、程式碼分析、fork and rewrite cleanly, improve API, not to reinvent malloc, 結合C以外的其他語言進行測試,這些技術都被用來測試OpenSSL的安全性。

    ATS就是其中一種比較受歡迎的測試語言。我思考過,用Coq(形式化驗證管理系統) 來驗證ATS寫的TLS/SSL。證明協議的安全性是一個巨大的工作,雖然它不會有助於實現安全,我一直在嘗試一些方法能夠清楚明瞭地展示協議實現的正確性。

     我的目標是:

  • 直譯器(parsers)和輸出機(printers)能完美耦合
  • 輸出機能被正確實現
  • 狀態機的行為用謂詞表示

   考慮*標識的三個情況,我開始關注CCS上的狀態轉換,CCS狀態轉換是狀態機裡最複雜的部分。

   隨後,檢查當前實現是否正確考慮到這些情況。我發現除了OpenSSL,大多數的實現多多少少都考慮到了。OpenSSL沒有考慮這些情況,OpenSSL也就有CCS漏洞!


第一次翻譯,有什麼不當之處,希望指出。