【CTF】Heap Exploitation(Part 1 - Overview, UAF)
Heap Exploitation
預備知識
- 需要注意glibc的版本
- 知道典型的Memory layout
- 記憶體計算
1. Heap
Overview
- 跟資料結構的Heap不同
- 存動態資料的記憶體區段
- 在Memory中由低往高生長
Allocator
- Linux中由glibc實作
- dlmalloc (Doug Lea Malloc) - General-purpose allocator
- ptmalloc (Per-thread malloc) - glibc
- jemalloc - FreeBSD / Firefox / Facebook…
- tcmalloc - Google / Golang / Chrome…
malloc
- dynamic memory allocator
第一次呼叫 malloc
|
|
- 程式執行中free掉記憶體後不會馬上還給系統,會由glib代管
Chunk
- glibc做記憶體管理的資料結構
- malloc分配的空間單位,分配出來的大小必須對齊0x10
- Ex: malloc(0x15) -> 得到大小 0x20 + 0x10(header) 的chunk
- 依大小分類,發生free時會放到linked list中,這個linked list稱為bin
- fastbin (<64B)
- smallbin (<512B)
- largebin (>=512B)
- unsortedbin (如果free的chunk大小>64B,先放到這裡一段時間後再加到對應的bin)
- 種類
- Allocated Chunk
- prev_size: 如果前一個chunk是free的,就存前一個chunk的大小
- size: 這個chunk的大小 + Status flag(最後3個bit)(因為0x10 padding,後面4bit可以不存)
- bit 0: PREV_INUSE: 前一個chunk是否正被使用
- bit 1: IS_MMAPPED: 是否是mmap分配的
- bit 2: NON_MAIN_ARENA: 是否不是main arena
- User Data
- Free Chunk
- prev_size
- size
- fd: 指標指向下一個chunk
- bk: 指標指向上一個chunk
- fd_nextsize: 下一個largebin的指標
- bk_nextsize: 上一個largebin的指標
- Data
- Top Chunk
- prev_size
- size: 還剩多少空間
- Allocated Chunk
|
|
bin
- Linked list
- 在free掉一個chunk時,會把這個chunk放到對應的bin中
- tcache
- fastbin
- Single Linked list
- size < 64B
- 存在mfastbinptr fastbinsY[NFASTBINS]
- 最多8個
- LIFO(Last In First Out)
- smallbin
- Circular Doubly Linked list
- size < 512B
- FIFO
- bins[1:64]
- largebin
- Circular Doubly Linked list
- size >= 512B
- FIFO
- free chunk 多了 fd_nextsize和bk_nextsize指標指向下一個和上一個 large chunk
- 每個bin中chunk大小不固定,存的時候會sort,大的放前面,小的放後面
- bins[64:126]
- unsortedbin
- Circular Doubly Linked list
- LIFO
- malloc會先把要free的、大於64B的chunk先放到這裡整理,再放到對應的bin中
- bins[0:0]
Main arena header
|
|
- 存在bss section
2. Exploitation
- 即使保護機制全開也能攻擊
- 目標是改到fd
Unlink
- 為了避免chunk太碎,free的時候會檢查周圍的chunk是否為free然後merge
- 早期版本(libc-2.23? 大概2004年以前)不會檢查fd、bk、size是否正常,可以做unlink attack
- 現在多了這段檢查,繞過很麻煩,已經很難打了,除非沒更新
|
|
Use After Free
- 記憶體被釋放後還被使用
三種情況:
- 使用nullptr,結果崩潰
- 釋放後沒有其他進程使用,可能繼續正常運作
- 釋放後有其他進程使用,造成亂七八糟的結果
釋放後沒有設為nullptr的指標稱為 dangling pointer
- 當free(p),chunk被放到對應bin
- q = malloc(N),如果N跟p chunk的大小一樣,記憶體位址會是剛剛free的p chunk的位址
- p是dangling pointer,如果繼續用,結果不可預期
Double Free
當一個fastbin chunk被free,fd變成nullptr,第二次free,libc會檢查有沒有 free(A);free(A);的情況(old == p)
繞過:不要讓double free chunk在fastbin第一個
free(A) -> free(B) -> free(A)
然後malloc一樣大小的空間,會拿到 chunk A,隨便寫東西進去就能蓋掉fd(Create a fake chunk)