堆積利用筆記
建議先找出各種版本的 glibc source 的檢視器
heap feng shui
前置概念
-
bins 用來組織記憶體 free chunk,chunk 代表可分配 (Free Chunk) 或 使用中 (In-use Chunk ) 的記憶體區塊1 ,當中 bin 又是透過 linked list 構成,並且根據大小可以分成以下幾類2
-
tcache
- in heap
-
fastbins
- In
mfastbinptr fastbinsY[NFASTBINS]
stored inmalloc_state
tcache_prethread_struct
- 7 chunks
- FILO
- In
-
in
mchunkptr bins[]
stored inmalloc_state
-
smallbins
- FIFO
bins[1:63]
-
largebins
bins[63:126]
-
unsortedbins:
- FILO
bins[0:0]
(1-bin)- unsorted bin
- malloc 會從 unsorted bin 進行整理 glibc-2.31 malloc.c#L3728
-
-
-
free chunk:
- fd (forward): 下個 chunk
- bk (back): 上個 chunk
-
chunk 在
malloc()
分配出來並且對其 0x10,在free()
時加入 bins 2 -
object 於記憶體的相關概念
-
realloc() 重新再分配一塊記憶體
- Calloc() 重新分配一個清空的記憶體
Calloc()
這個會把記憶體的內容清掉,所以沒辦法用來 leak 東西
幾個重點
bin_at(m, i)
用於定址 bintypedef struct malloc_state *mstate
- 這個會作為
av
傳入各種參數 struct malloc_state
mchunkptr bins[]
bins 是好幾個mchunkptr
所組成typedef struct malloc_chunk* mchunkptr
- 這個會作為
malloc_state
我懶得畫圖
反正他們會串再一起
heap info
Libc 是透過 _heap_info
下去紀錄資料,Arena 保存 heap 的狀態
- 會保存 mstate (arena)
- 透過 linked list 串起來
size
當前 heap 的大小mprotect_size
可以讀寫 的大小- Char pad[] 做 alignment
- 而 Main thread 沒有 _heap_info ,因此很少用到
Chunk
Heap 預設透過 mmap 先分配一段大小,滿了之後 glibc 根據大小
- malloc(size), size >= 0x20000 會在 mmap 一塊記憶體
- 如果一般大小的 chunk ,當可用的 heap 空間太小的話反之會透過 brk syscall 來擴展
boundary tag [knuth]
prev_size 為了增加效率
- 如果是 allocated chunk,就會給前一個存資料。
- 反之存 free chunk size
Size bit 有四個未的 bit
- N bit
- NON_MAIN_ARENA
- M bit
- IS_MMAPPED
- 是否為 mmap chunk,也就是 SIZE >= 0x20000
- P bit
- PREV_INUSE
Bin
初始化 bin malloc.c#L1794,可以看到它實際上是 malloc_chunk 的結構,但是 bin_at 每次移動 0x10
所以可以看到類似這樣的記憶體
┌─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐
│ fd │ bk │ fd │ bk │ fd │ bk │ fd │ bk │
└─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┘
在 gdb 下面可以看到 bin->fd = bin->bk = bin
,並且 &fd-0x10 可以對應到 chunk 的 prev_size 的位置,初始化的時候 fd 和 bk 都指向自己
0x00007f0000000bf0│+0x0010: 0x000055000000b0d0
0x00007f0000000bf8│+0x0018: 0x000055000000aae0
0x00007f0000000c00│+0x0020: 0x00007f0000000bf0
0x00007f0000000c08│+0x0028: 0x00007f0000000bf0
0x00007f0000000c10│+0x0030: 0x00007f0000000c00
0x00007f0000000c18│+0x0038: 0x00007f0000000c00
0x00007f0000000c20│+0x0040: 0x00007f0000000c10
0x00007f0000000c28│+0x0048: 0x00007f0000000c10
0x00007f0000000c30│+0x0050: 0x00007f0000000c20
Unsorted Bin
Free 之後一率放到 unsorted bin, 之後才有機會放入 small bin large bin
為了了解 heap 的運作機制,這邊寫了幾個範例可以使用 gdb 進行分析 practice/pwn/allocator
┌───────────────────────────────────────────────────────────────────────────────────────┐
│ malloc_state aka arena │
│ ┌─────────┬─────────┬─────────┬─────────┐ ┌─────────┬─────────┬─────────┬─────────┐ │
│ │prev_size│ size │ fd │ bk │ │prev_size│ size │ fd │ bk │ │
│ └─────────┴─────────┴───┬─────┴────┬────┘ └─────────┴─────────┴───┬─────┴────┬────┘ │
│ ▲ ▲ │ │ ▲ ▲ │ │ │
│ │ │ │ │ │ │ │ │ │
└──┼─┼────────────────────┼──────────┼─────────┼─┼────────────────────┼──────────┼──────┘
│ │ │ │ │ │ │ │
│ │ ┌──────────┐ │ │ │ │ ┌──────────┐ │ │
│ │ ┌──►│prev_size │◄──┘ │ │ │ ┌►│prev_size │◄──┘ │
│ │ │ │size │ │ │ │ │ │size │ │
│ │ │ │fd ├─┐ │ │ │ │ │fd ├─┐ │
└─┼─┼───┤bk │ │ │ └─┼───┼─┤bk │ │ │
│ │ │ │ │ │ │ │ │ │ │ │
│ │ │payload │ │ │ │ │ │payload │ │ │
│ │ │ │ │ │ │ │ │ │ │ │
│ │ └──────────┘ │ │ │ │ └──────────┘ │ │
│ │ │ │ │ │ │ │
│ │ ┌──────────┐ │ │ │ │ ┌──────────┐ │ │
│ │ ┌►│prev_size │◄┘ │ │ │ │prev_size │◄└────────────┘
│ │ │ │size │ │ │ │ │size │
│ │ │ │fd ├─┐ │ └───┼─┤fd │
│ └─┼─┤bk │ │ │ └─┤bk │
│ │ │ │ │ │ │ │
│ │ │payload │ │ │ │payload │
│ │ │ │ │ │ │ │
│ │ └──────────┘ │ │ └──────────┘
│ │ │ │
│ │ ┌──────────┐ │ │
│ │ │prev_size │◄└────────────┘
│ │ │size │
└───┼─┤fd │
└─┤bk │
│ │
│payload │
│ │
└──────────┘
Small Bin
Large bin
- 內含 subbin 有多種不同 size 的 bin
- 並且透過 fd_nextsize 和 bk_nextsize 將每個串起來
Tools 工具
- Villoc 將 heap 變化可視化轉成 html 檔案檢視,可以即時顯示 (使用
|&
運算元) - 自己寫的工具,串接 gef ,尚未公開發佈。
保護機制
新版(幾版?)的 ptmalloc 要實踐 unlink attack,因為在 Consolidation 會去檢查 fd 與 bk 是否正常,因此繞過這個機制蠻麻煩的。
glibc 2.29 之後 unsorted bin 已經有許多緩解機制,unlink 基本上 glibc 打不太動的了
small bin unlink 會跑到 unsorted bin 然後設定好的 ptr 就會爛掉。
漏洞利用
- Use After Free UAF
- Heap Overflow
- Heap Spraying 堆噴射/記憶體塗鴉
Use After Free
釋放後,嘗試複寫原始地址,因為原始空間已被空閒了下來了可以重新分配。
習題
- UAF
- hackme.inndy.tw
- 68 raas
- pwnable.tw
- hacknote
- practice/uaf.cpp
- 這個就是簡單做 vtable hijacking,獲取相同大小同一塊之後,去偽造 vtable 達成攻擊。
- AIS3 EOF2022 myfs-1, myfs-2, myfs-3
- RARCTF 2021 Unintended
- hackme.inndy.tw
參見
-
精華文章必讀
- pwn的艺术浅谈(二):linux堆相关 包含前置知識 chunk 以及各種漏洞與利用方法
- how2heap 可以搭配 pwn的艺术浅谈 學習
- PWN之堆内存管理 關於記憶體的前置知識
-
chunk
- Overview of Malloc 這篇感覺也很清楚 對於理解 In-use Chunk 與 Free Chunk
- Heap Exploit 學習筆記 該文概敘了 linux glibc 記憶體配置等概念。
- Pwn学习笔记4:heap布局
-
參見 針對多執行緒環境設計的 Memory allocator 的 bins 區段,以及 你所不知道的 C 語言:記憶體管理、對齊及硬體特性,對於理解記憶體管理機制很有幫助。 ↩︎
-
Angel Boy Heap Exploitation 推薦參閱該份簡報 ↩︎ ↩︎
CTF Vulnerability Heap PWN