關於OpenSSL「心臟出血」漏洞的分析

2021-06-21 11:22:27 字數 3048 閱讀 8270

ttp:

當我分析gnutls的漏洞的時候,我曾經說過,那不會是我們看到的最後乙個tls棧上的嚴重bug。然而我沒想到這次openssl的bug會如此嚴重。

openssl「心臟出血」漏洞是乙個非常嚴重的問題。這個漏洞使攻擊者能夠從記憶體中讀取多達64 kb的資料。一些安全研究員表示:

無需任何特權資訊或身份驗證,我們就可以從我們自己的(測試機上)偷來x.509證書的私鑰、使用者名稱與密碼、聊天工具的訊息、電子郵件以及重要的商業文件和通訊等資料。

這一切是如何發生的呢?讓我們一起從**中一**竟吧。

請看ssl/dl_both.c,漏洞的補丁從這行語句開始:

int            

dtls1_process_heartbeat(ssl *s)

ssl3_record;

每條sslv3記錄中包含乙個型別域(type)、乙個長度域(length)和乙個指向記錄資料的指標(data)。我們回頭去看dtls1_process_heartbeat:

/* read type and payload length first */

hbtype = *p++;

n2s(p, payload);

pl = p;

sslv3記錄的第乙個位元組標明了心跳包的型別。巨集n2s從指標p指向的陣列中取出前兩個位元組,並把它們存入變數payload中——這實際上是心跳包載荷的長度域(length)。注意程式並沒有檢查這條sslv3記錄的實際長度。變數pl則指向由訪問者提供的心跳包資料。

這個函式的後面進行了以下工作:

unsigned char *buffer, *bp;

int r;

/* allocate memory for the response, size is 1 byte

* message type, plus 2 bytes payload length, plus

* payload, plus padding

*/buffer = openssl_malloc(1 + 2 + payload + padding);

bp = buffer;

所以程式將分配一段由訪問者指定大小的記憶體區域,這段記憶體區域最大為 (65535 + 1 + 2 + 16) 個位元組。變數bp是用來訪問這段記憶體區域的指標。

/* enter response type, length and copy payload */

*bp++ = tls1_hb_response;

s2n(payload, bp);

memcpy(bp, pl, payload);

巨集s2n與巨集n2s幹的事情正好相反:s2n讀入乙個16 bit長的值,然後將它存成雙位元組值,所以s2n會將與請求的心跳包載荷長度相同的長度值存入變數payload。然後程式從pl處開始複製payload個位元組到新分配的bp陣列中——pl指向了使用者提供的心跳包資料。最後,程式將所有資料發回給使用者。那麼bug在**呢?

如果使用者並沒有在心跳包中提供足夠多的資料,會導致什麼問題?比如pl指向的資料實際上只有乙個位元組,那麼memcpy會把這條sslv3記錄之後的資料——無論那些資料是什麼——都複製出來。

很明顯,sslv3記錄附近有不少東西。

說實話,我對發現了openssl「心臟出血」漏洞的那些人的宣告感到吃驚。當我聽到他們的宣告時,我認為64 kb資料根本不足以推算出像私鑰一類的資料。至少在x86上,堆是向高位址增長的,所以我認為對指標pl的讀取只能讀到新分配的記憶體區域,例如指標bp指向的區域。儲存私鑰和其它資訊的記憶體區域的分配早於對指標pl指向的記憶體區域的分配,所以攻擊者是無法讀到那些敏感資料的。當然,考慮到現代malloc的各種神奇實現,我的推斷並不總是成立的。

當然,你也沒辦法讀取其它程序的資料,所以「重要的商業文件」必須位於當前程序的記憶體區域中、小於64 kb,並且剛好位於指標pl指向的記憶體塊附近。

修復**中最重要的一部分如下:

/* read type and payload length first */

if (1 + 2 + 16 > s->s3->rrec.length)

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 */

pl = p;

這段**幹了兩件事情:首先第一行語句拋棄了長度為0的心跳包,然後第二步檢查確保了心跳包足夠長。就這麼簡單。

我們能從這個漏洞中學到什麼呢?

我是c的粉絲。這是我最早接觸的程式語言,也是我在工作中使用的第一門得心應手的語言。但是和之前相比,現在我更清楚地看到了c語言的侷限性。

從gnutls漏洞和這個漏洞出發,我認為我們應當做到下面三條:

花錢請人對像openssl這樣的關鍵安全基礎設施進行安全審計;

為這些庫寫大量的單元測試和綜合測試;

開始在更安全的語言中編寫替代品。

考慮到使用c語言進行安全程式設計的困難性,我不認為還有什麼其他的解決方案。我會試著做這些,你呢?

作者簡介:sean是一位關於如何把事兒幹好的軟體工程師。現在他在squadron工作。squadron是乙個專為saas應用程式準備的配置與發布管理工具。

測試版本的結果以及檢測工具:

openssl 1.0.1 through 1.0.1f (inclusive) are vulnerable

openssl 1.0.1g is not vulnerable

openssl 1.0.0 branch is not vulnerable

openssl 0.9.8 branch is not vulnerable

OpenSSL 「心臟滴血」漏洞

漏洞描述 openssl 軟體存在 心臟出血 漏洞,該漏洞使攻擊者能夠從記憶體中讀取多達 64 kb 的資料,造成資訊洩露。漏洞危害 可被用來獲取敏感資料,包括會話 session cookie 賬號密碼等。修復方案 以下為各系統的修復方案供您參考 第一步 debian ubuntu apt get...

用OSSIM平台輕鬆發現「心臟出血」漏洞

用ossim平台輕鬆發現 心臟出血 漏洞 心臟出血 漏洞作為目前網際網路中存在的最為嚴重網路安全漏洞,者借助 心臟出血 漏洞可以獲取使用者上網的賬戶 密碼以及網上交易等眾多敏感資訊,因此我們必須提前測試並對這類漏洞進行修復,從而保證網上交易的安全。下文介紹如何用ossim平台來檢測 心臟出血 漏洞的...

用OSSIM平台輕鬆發現「心臟出血」漏洞

用ossim平台輕鬆發現 心臟出血 漏洞 心臟出血 漏洞作為目前網際網路中存在的最為嚴重網路安全漏洞,者借助 心臟出血 漏洞可以獲取使用者上網的賬戶 密碼以及網上交易等眾多敏感資訊,因此我們必須提前測試並對這類漏洞進行修復,從而保證網上交易的安全。下文介紹如何用ossim平台來檢測 心臟出血 漏洞的...