# Pwn Heap Intro * [Reference: BambooFox PWN Advanced 系列](https://www.youtube.com/watch?v=u1D5vdXZPDk) * 如果內容有錯,歡迎提出討論 --- * 在 OS 中有學過,一個程式的變數,如果是一般的宣告變數會被放在 stack 中,而動態宣告的變數則會存放在 heap * heap 的 allocator 在不同 OS 或是 libc 中有不同的處理,以下是針對 **glibc 的 ptmalloc** 解釋 --- * 宣告變數時,根據你請求的空間大小不同,會有不同的機制去處理 * ![](https://hackmd.io/_uploads/SJQpXmYfa.png) * <128KB 會從 heap 拿空間 * 空間不夠時使用 sys_brk 擴增區域 * \>=128KB 會從 mmap 拿空間 * 一些相關的專有名詞 * Arena * 管理 Heap 的資料結構 * 通常 1 個 Thread 只有一個 Arena * Heap * 連續的記憶體空間 * 一個 Heap 只會存在一個 Arena 中 * Chunk * 分配給程式的記憶體 * 一個 Heap 會有一堆 Chunk --- ## Chunk * 可分成三種類型 * in-use * free * top * heap 最後未使用的區域 * 對齊 `0x10`,即使你要的空間不到也會補齊 * Header * 前一個 Chunk 的 Size * 自己的 Size * 由於 Size 一定是 `0x10` 的倍數,後面 4bits 根本用不到,所以其中三個被拿去下面的用途 * A: 是否在 main arena 裡面 * 這邊只討論 single thread,所以假設都是 `0` * M: 是 mapp 出來的還是 heap * 這邊只討論 heap,所以假設都是 `0` * P: 前一個 chunk 是否被使用 * top chunk 一定是 `1`,因為如果是 `0` top chunk 就會跟前一個合併 * Data 就接在 Header 後面 ## free * free 一個 chunk 之後,該 chunk 的 Data 區段會變成放 * fd * bk * fd 和 bk 就是雙向 linked list 的兩個指標,用於回收桶 bin 中 * 將下一個 chunk 的 header 中寫下 `prev size` 方便回收 * 並且將 P 欄位改成 `0`,表示該 chunk 沒在用了 --- * bin 分為五種 * ![](https://hackmd.io/_uploads/BktYo7YMp.png) * tcache 和 fast bin 其實只是 single linked-list,因此只有 fd 在使用,bk 作為其他用途 * 一個 Thread 只有一個 tcache * unsorted bin 像是 small bin 和 large bin 的暫存空間 * ![](https://hackmd.io/_uploads/S1Sf-4tzT.png) ## GEF Commands * 在 CTF 實戰中,常常需要在 GDB 中印出 heap 資料來驗證想法 * 在原生的 GDB 中沒辦法直接看到這些資訊 * 裝了 GEF 插件後,使用 `heap` 就會提示能夠印出那些資料 * ![](https://hackmd.io/_uploads/HJeXpQtza.png) * 一個 Chunk 的例子 * ![](https://hackmd.io/_uploads/B1H4aXYfT.png) * 第一個 `0x190` 為保留給 tcache 的空間 * 我另外要了 `0x10` `0x10` `0x10` `0x20` 等四個空間 * 剩下的就是 Arena 的剩餘空間 ## UAF * Free 後如果沒有將 pointer 清空,可能造成不可預期的錯誤 * 範例 ``` ... b = malloc(0x10); free(b); *b = (long)&buf; long* c = malloc(0x10); long* d = malloc(0x10); ``` * 假設本來就有一個 chunk A 位於 tcache 之中,我們 free 掉 `b` 之後,長這樣 * ![](https://hackmd.io/_uploads/SkTuXEYfp.png) * 但 `b` 又繼續被使用,而 fd 位於 chunk 的 data 區段,因此 fb 被指向了 `buf` 的位址 * ![](https://hackmd.io/_uploads/rJB074tGa.png) * 而我們 allocate 新的空間時,(如果條件是 tcache)是從 tcache 的 linked-list 依序抓進來 * `c` 會拿到 `b` 的 chunk * `d` 則是拿到 `buf` 的位址