{ /* Serialize access. */ mutex_t mutex; /* Flags (formerly in max_fast). */ int flags; /* Fastbins */ mfastbinptr fastbinsY[NFASTBINS]; /* Base of the topmost chunk -- not otherwise kept in a bin */ mchunkptr top; /* The remainder from the most recent split of a small request */ mchunkptr last_remainder; /* Normal bins packed as described above */ mchunkptr bins[NBINS * 2 - 2]; /* Bitmap of bins */ unsigned int binmap[BINMAPSIZE]; /* Linked list */ struct malloc_state *next; /* Linked list for free arenas. Access to this field is serialized by free_list_lock in arena.c. */ struct malloc_state *next_free; /* Number of threads attached to this arena. 0 if the arena is on the free list. Access to this field is serialized by free_list_lock in arena.c. */ INTERNAL_SIZE_T attached_threads; /* Memory allocated from the system in this arena. */ INTERNAL_SIZE_T system_mem; INTERNAL_SIZE_T max_system_mem; };
• Allocated chunk • Free chunk • Top chunk • size alignment • 0x10的倍數,malloc 0x18會拿到 0x20 的⼤⼩。 • 整個chunk佔記憶體⼤⼩為 header(0x10) + data user data user data chunk header Top chunk chunk chunk header 0x10
chunk 則同時為它的 data。 • size • chunk size with 3 flags • PREV_INUSE(P):上⼀個 chunk 是否使⽤中 • IS_MMAPED(M):chunk 是否透過 mmap 出來的 • NON_MAIN_ARENA(N):該 chunk 是否不屬於 main arena user data prev_size/data size N M P
則為它的 data。 • size • 連續記憶體下⼀塊的 P flag 為0 • fd:指向同⼀ bin 中的前⼀塊 chunk (linked list) • bk:指向同⼀ bin 中的後⼀塊 chunk (linked list) user data fd bk prev_size/data size N M P
>= 1024 bytes (0x400) • 63 bins • 細節可以參考 source code • header • fd_nextsize • bk_nextsize user data prev_size/data size N M fd fd_nextsize bk_nextsize P bk
chunk size ⼤於 fast bin 時,不會直接放到對應的 bin 裡,會先丟到 unsorted bin 中。 • malloc fast bin size ⼤⼩時會先去 fast bin list 裡找,若沒有則會⾄ unsorted bin 找,如找到⼀樣⼤⼩則回傳,若無但找到⼤⼩⼤於所需⼤⼩的 chunk 則切割回傳, 剩下的部分會丟回 unsorted bin,若都沒有則從 top chunk 切出來回傳。
free 的流程,使得不同的 chunk 發⽣重疊 (heap overlap) 的情形。 • 假設 chunk A 的 data 與 chunk B 的不可寫部分重疊 • chunk B 可能是⼀個 struct,有如 char* data pointer,亦或是 function pointer,則可以透過 chunk A 來偽造,overwrite data pinter 達到任意讀寫,overwrite function pinter 則可以 hijack control flow。 • 可以更進⼀步偽造 chunk header,偽造 heap chunk,玩弄記憶體管理機制。
A ) • malloc( 0x28 ) • malloc( 0x88 ) • malloc( 0x48 ) • free( B ) • free( C ) • malloc( 0x258 ) A 0x31 B 0x91 0x51 D 0x21 E chunk C 是 small bin 檢查上⼀塊是否 inuse (P) 上⼀塊是是 free chunk 根據 prev_size 合併 C 0x160 0x100
pointer等, 因都位於 chunk B 的 data 可以透過 chunk B 來 overwrite, 達到任意讀寫等。 • 或是進⼀步偽造 heap,如把 D free 掉 overwrite fd, 玩 fastbin attack等等 A 0x31 0x261 B 0x51 D PWNED ☠
• P 的下⼀個的上⼀個要是 P • P 的上⼀個的下⼀個要是 P /* Take a chunk off a bin list */ #define unlink(AV, P, BK, FD) { FD = P->fd; BK = P->bk; if (__builtin_expect (FD->bk != P || BK->fd != P, 0)) \ malloc_printerr (check_action, "corrupted double-linked list", P, AV); else { FD->bk = BK; BK->fd = FD;