歡迎來到 黑吧安全網 聚焦網絡安全前沿資訊,精華內容,交流技術心得!

對 libssh2 整數溢出漏洞 (CVE-2019-17498)的分析

來源:本站整理 作者:佚名 時間:2019-11-07 TAG: 我要投稿

0x01 漏洞挖掘
在2019年3月18日,Canonical Ltd.的Chris Coulson披露了libssh2中的九個漏洞(CVE-2019-3855至CVE-2019-3863)。這些漏洞已在libssh2 v1.8.1中修復。當時,我的同事Pavel Avgustinov注意到,修復漏洞的報告在LGTM上引入了多個新告警。這些告警是由于像下面的代碼:
 if((p_len = _libssh2_get_c_string(&buf, &p))
問題出現在_libssh2_get_c_string返回 -1是一個error code,但是p_len沒有符號,因此錯誤條件將被忽略。libssh2團隊已經在后面的的報告中修復了這些問題,但是它促使我們仔細查看代碼以查看其包含明顯錯誤的漏洞。我們很快發現了這個用于邊界檢查的函數:
 int _libssh2_check_length(struct string_buf *buf, size_t len)
 {
     return ((int)(buf->dataptr - buf->data) len - len)) ? 1 : 0;
 }
此函數的問題在于強制轉換int可能會溢出。左側的強制轉換是安全的,因為的字段buf是受信任的值,但是右側的強制轉換是不安全的,因為的值len是不受信任的。創建漏洞利用exp并非難事,該漏洞利用使值len大于繞過此溢出檢查buf->len + 0x80000000。可以在GitHub上找到PoC 。
我后來了解到,該問題_libssh2_check_length是在1.8.2版發布后在主要開發分支上引入的,因此漏洞范圍檢查在1.8.2版中不存在。不幸的是,版本1.8.2不包含任何邊界檢查,因此PoC仍然有效。在1.8.2版中,漏洞的源位置是kex.c:1675。問題在于其中p_len包含一個不受信任的值,因此后續的讀取s可能會超出范圍。因為_libssh2_check_length在1.8.2版中不存在,所以不需要將值p_len大于0x80000000觸發漏洞。這意味著較小的值len可以觸發越界讀取,該漏洞更有可能被利用來實現遠程信息泄露。
0x02  negative error codes 轉換為 unsigned
當我和我的同事正在查看漏洞補丁報告時,我們注意到一種常見的錯誤模式,其中將negative error返回值強制轉換為unsigned。這是一個非常容易犯的錯誤,并且它沒有被編譯器警告所](https://godbolt.org/z/CvqwDm)捕獲。所以我寫了這個簡單的查詢來查找漏洞實例:
 import cpp
 import semmle.code.cpp.dataflow.DataFlow
 import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
 
 from Function f, FunctionCall call, ReturnStmt ret, DataFlow::Node source, DataFlow::Node sink
 where call.getTarget() = f
 and ret.getEnclosingFunction() = f
 and ret.getExpr().getValue().toInt()
查詢代碼如下:
 r_len = _libssh2_get_c_string(&buf, &r);
 if(r_len
該查詢會返回負整數常量的函數。例如,_libssh2_get_c_string在773行上執行此操作,然后,它將查找對該函數的調用,這些調用返回值并將其轉換為無符號類型。
0x03 觸發漏洞
漏洞的源位置是packet.c:480:
 if(message_len
值datalen不受信任,因為它是由遠程SSH服務器控制的。例如,如果使用datalen == 11,則減法將溢出并且的邊界檢查message_len無效。message_len是一個32位無符號整數,它也由遠程SSH服務器控制,因此這可能導致在第485行上越界讀取:
 language_len =
     _libssh2_ntohu32(data + 9 + message_len);
越界讀取通常只會導致分段錯誤,但是LIBSSH2_DISCONNECT在 第499行的調用中也有可能導致其他類型的問題:
 if(session->ssh_msg_disconnect) {
     LIBSSH2_DISCONNECT(session, reason, message,
                        message_len, language, language_len);
 }
取決于libssh2庫的使用方式,因為session->ssh_msg_disconnect是一個回調函數,默認情況下為null,但可以由該庫的用戶設置(通過調用libssh2_session_callback_set)。
我編寫了一個 漏洞PoC ,其中惡意SSH服務器使用datalen == 11和返回斷開連接消息message_len == 0x41414141,會導致libssh2因分段錯誤而崩潰。
0x04 libssh2中整數溢出的變體分析
我在2019年6月底之前寫了關于libssh2的最后一篇博客文章。為了準確了解該博客文章的技術細節,我需要回過頭來再看一下libssh2代碼。我注意到許多粗心的邊界檢查代碼,例如上述錯誤。
變體分析是關于漏洞的所有變體,并在可能的情況下,創建可在多個代碼庫之間重用的查詢。但是我的目標集中在libssh2和我發現的漏洞上。
當我向供應商報告安全漏洞時,通常會嘗試在報告中包括兩點:
1. 一個漏洞的PoC。
2. 一個QL查詢,它標識了我認為存在漏洞的的所有代碼位置。
QL查詢和PoC有幾個好處:
1. 如果代碼中包含幾個非常相似的錯誤,那么我可以編寫一個列舉所有漏洞的查詢。
2. 該查詢使我能夠輕松地檢查漏洞是否已修復(在90天的最后期限即將到期時,這非常方便)。
3. 我可以將QL查詢及其結果列表作為單個URL包括在內,這對我來說很方便,希望對接收者也很方便。
編寫PoC通常需要大量工作,因此,如果存在多個非常相似的漏洞,那么我通常只為其中一個編寫PoC。我的感覺是,一個PoC足以證明安全影響是真實的。下面的查詢針對此用例進行了調整,該查詢的目的不是在libssh2中找到所有整數溢出漏洞,而且由于查詢中編碼了某些libssh2特定的細節,它也不會擴展到其他代碼庫。
 /**
  * @kind path-problem
  */
 
 import cpp
 import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
 import semmle.code.cpp.dataflow.TaintTracking
 import DataFlow::PathGraph
 
 class Config extends DataFlow::Configuration {
   Config() { this = "_libssh2_ntohl bounds check overflow" }
 
   override predicate isSource(DataFlow::Node source) {

[1] [2]  下一頁

【聲明】:黑吧安全網(http://www.nkppsz.live)登載此文出于傳遞更多信息之目的,并不代表本站贊同其觀點和對其真實性負責,僅適于網絡安全技術愛好者學習研究使用,學習中請遵循國家相關法律法規。如有問題請聯系我們,聯系郵箱[email protected],我們會在最短的時間內進行處理。
  • 最新更新
    • 相關閱讀
      • 本類熱門
        • 最近下載
        秒速时时彩骗局