每個應用程式都依賴電腦記憶體儲存與執行程式碼。記憶體漏洞(Memory Vulnerabilities) 利用應用程式記憶體管理上的瑕疵,造成非預期行為——攻擊者最終可能注入並執行自己的指令。
記憶體漏洞主要出現在開發者必須自行管理記憶體的語言(C、C++)。Ruby、Python、PHP、Java 等有自動記憶體管理的語言相對較不易發生,但若它們本身用 C 寫成,仍可能因底層出錯而被影響。
本章只是入門,僅介紹兩類:緩衝區溢位(Buffer Overflow) 與 越界讀取(Read Out of Bounds)。深入研究可參考:
- Hacking: The Art of Exploitation(Jon Erickson)
- A Bug Hunter’s Diary(Tobias Klein)
Buffer Overflow(緩衝區溢位)#
原理#
當應用程式寫入超過配置記憶體大小的資料時,就發生緩衝區溢位。輕則行為不可預期,重則攻擊者可控制溢位的位元組執行任意程式碼。
C 中常見發生點:
- 修改記憶體的函式:
strcpy()、memcpy() - 配置記憶體的函式:
malloc()、calloc()
範例#
#include <string.h>
int main() {
char src[16] = "hello world";
char dest[16];
strcpy(dest, src);
printf("src is %s\n", src);
printf("dest is %s\n", dest);
return 0;
}"hello world" 長 11 字元 + null byte = 12 bytes,落在 16 bytes 內,正常輸出兩個變數。
但如果擴充到 16 字元:
char src[17] = "hello world!!!!!";
char dest[16];
strcpy(dest, src);src 配置 17 bytes(含 null)但 dest 只配 16 bytes。strcpy 把 17 bytes 複製進 dest,多出來的 null byte 溢位到 src 第一個位元組——導致 src 印出來變成空字串。
64 位元系統的最小記憶體配置是 16 bytes(32 位元為 8 bytes)。即使你只宣告
char dest[12],編譯器仍會配置 16 bytes,因此"hello world!"(13 bytes)不會觸發溢位——這個對齊細節常讓 bug 難以重現。
Read Out of Bounds(越界讀取)#
允許攻擊者讀取超出指定記憶體邊界的資料,可能洩漏敏感內容(例如金鑰、session、密碼)。
Heartbleed(CVE-2014-0160)#
最著名的越界讀取案例:OpenSSL 的 Heartbeat 功能。
- 客戶端送出帶有
length參數的 heartbeat 請求 - 伺服器根據
length配置回應緩衝區而非實際訊息大小 - 攻擊者可送 100 bytes 訊息但聲稱 1000 bytes → 伺服器回 100 bytes 訊息 + 900 bytes 任意記憶體內容
該記憶體可能包含私鑰、session token、明文密碼——而所有資料都不需登入即可拉到。
案例 1:PHP ftp_genlist() Integer Overflow#
- 難度:高
- 回報來源:https://bugs.php.net/bug.php?id=69545/ ↗
- 回報日期:2015-04-28
- 獎金:$500
漏洞描述#
PHP 雖管理記憶體,但語言本身用 C 寫成。研究者 Max Spelsberg 在 PHP FTP 擴充模組的 ftp_genlist() 函式找到 buffer overflow:用 unsigned int 追蹤資料大小與行數。
unsigned int在 32 位元機器上最大值是2^32 - 1≈ 4GB。攻擊者送出超過2^32bytes,計數器溢位歸零,後續 buffer 配置就崩盤。
PoC:用 PHP 啟動 FTP 伺服器、Python 用戶端送入 2^32 + 1 bytes,FTP 伺服器當機。
Takeaways#
即便目標主程式不是 C/C++,只要底層用 C 實作(PHP、Python、Ruby 的 native extension),仍可能藏有 buffer overflow。盯住有變數長度檢查省略的地方。
案例 2:Python Hotshot Module#
- 難度:高
- 回報來源:http://bugs.python.org/issue24481 ↗
- 回報日期:2015-06-20
- 獎金:$500
漏洞描述#
Python 的 hotshot 是 profile 模組的 C 寫成版本。研究者 John Leitch 找到 memcpy() 用法:
memcpy(self->buffer + self->index, s, len);self->buffer是固定長度s由攻擊者提供,可任意長度memcpy不檢查目的地大小
攻擊者傳入長度大於 self->buffer 的字串即可造成寫入越界。
Takeaways#
找 buffer overflow 的固定戰術:搜尋
strcpy()、memcpy()、strcat()呼叫,逆向追 source 與 destination 的長度檢查是否存在。
案例 3:Libcurl Read Out of Bounds#
- 難度:高
- 回報來源:http://curl.haxx.se/docs/adv_20141105.html ↗
- 回報日期:2014-11-05
- 獎金:$1,000
漏洞描述#
libcurl 在 curl_easy_duphandle 函式裡複製 POST 資料時有兩個問題:
- 以 C 字串方式處理 POST body:libcurl 預期資料以 null byte 結尾——若 POST body 中沒有 null byte,會繼續讀直到遇到一個,造成讀過頭;若中間有 null byte,又會誤判結束
- 複製後未更新讀取指標:在「複製完」與「真正送出」之間,原本記憶體可能被清空或重新利用——攻擊者可能把不該送出的內容塞進 POST
Takeaways#
cURL 是極穩定的元件,但仍會有 bug。任何牽涉複製記憶體的功能都是高優先檢查目標。記憶體 bug 不易找,但鎖定常見易錯函式仍是務實切入點。
章末總結#
- 記憶體漏洞輕則洩漏資料、重則任意程式執行
- 自動管理記憶體的語言(Python、Ruby、PHP)相對安全,但底層 C 實作仍可能受影響
- Buffer overflow 集中在:寫入、複製、配置記憶體的呼叫
- Read out of bounds 集中在:讀長度由攻擊者控制的場景(如 Heartbeat、HTTP 解析)
- 找這類漏洞需要記憶體管理知識,建議閱讀專門書籍補強