系統安全與漏洞利用

堆積溢位(heap overflow)

當程式需要一塊大小要到執行期才知道的記憶體時,它用 malloc() 向配置器要,拿回堆積上的一個區塊(這裡的堆積是動態配置的記憶體「區段」,不是堆積資料結構/優先佇列)。堆積溢位就是寫過某個 malloc 來的區塊尾端,塗掉配置器擺在它正後方的東西——那可能是另一個還活著的物件,也可能是配置器自己的簿記資料。

其機制取決於被溢出區塊旁邊放著什麼。像 glibc 那樣的配置器,會把小型控制結構——區塊大小欄位、自由串列指標、使用中旗標——實體地緊鄰它們所管理的資料擺放,常放在每個區塊前後的標頭裡(邊界標籤)。如果你溢出區塊 A,你可以損毀緊接其後的區塊 B 的中繼資料:改寫 B 記錄的大小,或者在 B 被釋放後,覆蓋配置器存在 B 裡用來把它串進自由串列的前向/後向指標。經典的利用接著濫用 free() 或下一次 malloc():當配置器用攻擊者控制的指標去解除串接或重新串接某個區塊時,可被誘騙把攻擊者選定的值寫到攻擊者選定的位址——把緩衝區溢位變成任意寫入。覆蓋相鄰物件的資料或函式指標,則是第二條、往往更簡單的路徑。

它之所以重要,是因為堆積存放著程式中長壽而有趣的狀態——物件、字串、被剖析的輸入——而那裡的溢位完全繞過堆疊金絲雀。誠實的提醒:堆積的佈局遠比堆疊難以預測,所以實務上的堆積利用通常需要「堆積整理」(heap grooming,安排各次配置讓目標物件剛好落在可溢出物件之後),而現代配置器加入了完整性檢查(安全解串接、指標亂數化)正是為了讓中繼資料攻擊更困難。

char *a = malloc(16); char *b = malloc(16); // b 在堆積上可能就坐在 a 的標頭之後 memcpy(a, input, 64); // 64 > 16:溢進 b 的區塊標頭與資料 // 損毀 b 的大小欄位,可讓 free(b) / 下一次 malloc() 寫入攻擊者的位元組

溢出區塊 a 觸及區塊 b 的配置器中繼資料——堆積中繼資料損毀的種子。

請對照配置器章節:邊界標籤與自由串列正是被損毀的中繼資料;配置器的「安全解串接」檢查存在的目的就是擊敗這個攻擊,而不是效能特性。

又稱
heap-based buffer overflowheap metadata corruption堆積緩衝區溢位堆積中繼資料損毀