仔細想想這系列文章幾乎都在介紹 Web 相關漏洞,好像該來點記憶體相關的東西(?)
不過在記憶體上的漏洞利用,筆者比較熟悉 PHP 和瀏覽器引擎 XDDD,接下來應該主要會講這兩個。
讓我以最不繞彎子的方法講解通用的 Heap (動態記憶體分配) 在 漏洞利用 (Binary Exploitation) 當中的常見攻擊手法
學一下 llm 文體,不緊張,文章是我本人寫的
在現實世界寫程式時,我們時常根本不確定接下來傳入的資料量到底會多大,或者可能會有多筆變數,但在做幾次處理後就不會再使用。
這時如果每次都(以 C 為例)開個新固定大小的變數 char c[0x10000];,將會導致程式占用過多系統記憶體資源,而我們又不需要那麼多東西。
所以才有了我們的動態記憶體 (Heap) 概念!
不論是大家常寫程式用的 libc、Golang/PHP 等程式語言、還是接下來要介紹的瀏覽器引擎,它們都有設計各自的一套動態記憶體機制。儘管在儲存資料的方法和內容、結構、乃至防護機制上都有些微出入,常見的漏洞和攻擊方法都是相同的!
通常會有 alloc 和 free 兩種動作,分別是 alloc(SIZE) 向 memory poll 申請一段新(指定 SIZE 大小)的記憶體塊並回傳它的地址指針;free(POINTER) free 掉該指針指向的動態記憶體塊。
而取得的記憶體塊結構通常是:
alloc (allocate) 後
|Metadata: 包含長度/類別|
|該記憶體段儲存的資料 |
free 後則成為 chunk (切小塊記憶體),並且被放進 bin (可以想像成回收桶,在下次 allocate 相似大小的記憶體時直接使用,就不用再向 memory pool 申請一次!)
這些 chunk 則會被用 Linked List 結構,每塊被 free 的chunk 都會指向前一塊被 free 的 chunk 之地址!
所以 chunk 結構會變成:
|pointer 指向下一塊 chunk|Metadata: 包含長度/類別|
| 該記憶體段儲存的資料(有些時候就是清空了) |
接下來開始講攻擊!
又稱為 UAF,假設有一塊變數 a 指向一塊 heap 而後面被 free 成為 chunk 後,後面的程式不論因為本來流程還是人為使用,又再使用了一次 a 這個變數而前面並沒有將變數 a 的指針清空,將導致裡面的內容是別的變數重疊的。
原因很簡單,畢竟 a 被 free,放進 bin 後成為一塊 chunk,而後面有個大小相近的 b 又重新 allocate 了這塊 chunk 重新使用,那因為變數 a 尚未清空指針,b 又開始寫入內容,那就會導致 a, b 指向同一塊 memory 導致變數內容實際重疊。
同一塊 heap 被 free 兩次,導致在 bin 中同一塊記憶體地址被放入紀錄兩次,那下兩次有 b, c 兩個變數都 alloc 一段大小相近的記憶體使用時會變成 b, c 指向同一段記憶體段,導致他們倆間的內容會是互相竄改的。
跟 Buffer Overflow 一樣,相近的 Heap 如果讀入過量資料會導致可以 Overflow 覆蓋掉下一塊 chunk 內容、導致 Heap 結構損毀、或者覆蓋掉本來儲存的指針資訊等等地。
接著我們明天來看看瀏覽器架構吧!