資安 pwn 技術研究所:Heap pwn 篇 (4) – 技術方法

談到方法,例如傳統 stack pwn 會有 buffer overflow、format string、ROP 之類的方法和技術。而 heap pwn 則和 stack pwn 有著一系列很不同的方法。這篇做個列表,方便檢索。各方法的詳細,在此不贅。可查找 reference 中的連結參考。

~ 基本功 ~

名稱概念目的參考
Double Free1. Free 了兩次同一個 pointer
2. 然後 alloc 時,這個 pointer 就會被 alloc 兩次。
3. free 其中一個,剩下的便可以有個 editable freed chunk。
Editable Freed Chunk
Heap Consolidation1. 修改 chunk metadata,使它以為是一個 freed chunk。
2. 調用 free(..),使 consolidation 發生
3. 再 alloc,便會多一個 pointer 指向同一個 chunk。
4. 同 double free:都是有個 editable freed chunk。
Editable Freed Chunk
Use After Free純粹將一個 free(..) 的 pointer 寫入資料Editable Freed Chunk
Unlink將兩個 freed chunk 的 FD BK 改寫,達到 arbitrary write 的效果Arbitrary Alloc
Arbitrary Write
Off By One字串寫入時溢出 1 byte。導致在 heap 上可以偽造下一節的 prev_inuse,使到偽造出 freed 效果。然後導致prev_size 可用;但也可以偽造 prev_size。prev_inuse overwrite (faked free)
prev_size overwrite
https://ctf-wiki.org/pwn/linux/user-mode/heap/ptmalloc2/off-by-one/
Heap Grooming /
also aka “Heap Feng Shui"
原意是指出 alloc / free 都是可預測的有效控制 alloc / free 來自 BlackHat 2007 發佈
https://www.blackhat.com/presentations/bh-europe-07/Sotirov/Presentation/bh-eu-07-sotirov-apr19.pdf
Fake Chunk
偽造節
在 stack 或用其他變數偽造成 chunk 格式。Arbitrary Alloc
Arbitrary Write
Editable Freed Chunk

~ 元素技 ~

名稱概念目的
Fast bin Attack利用 fastbin 的 single linked-list 原理。改寫 FD 指向目的地址。然後 fastbin alloc 就會派出了目的地址。Arbitrary Alloc
Unsorted bin Attack利用 unsortedbin 的 doubly linked-list 原理。改寫 FD BK。然後 unsorted bin alloc 就會派出目的地址。Arbitrary Alloc
Large bin Attack類似 fastbin 和 unsortedbin attacks。有不同的是,largebin 會按大小排列擺放。所以當有個新的 freed chunk 排入時,就會有個 arbitrary write 動作。Arbitrary Alloc
Arbitrary Write
Tcache Attack和 fastbin attack 類似。Arbitrary Alloc

~ 組合技 ~

名稱概念目的參考
House of Spirit用 Fake Chunk 偽造節,再調用 free(..)。再 alloc 就會派出這個偽造節。Arbitrary Alloc
House of Lore類似 House of Spirit。不過是連結到 small bin / large bin 的 FD BK pointer 上。同樣 alloc 就會派出去。Arbitrary Alloc
House of Force改寫 heap wilderness value;再 alloc 一個很大的 block 作對位作用。然後下一個 alloc 就會派出 arbitrary alloc,例如 Stack Alloc 或 BSS Alloc。Arbitrary Alloc
House of Einherjar類似 House of Spirit 和 House of Lore。不同的是利用向後合併。用一個 controlled chunk 控制節地址上接駁了目的地址。然後改寫了 metadata,致使 free(..) 的時候觸發向後合併 consolidation。然後 alloc.就會派出目的地址。Arbitrary Alloc
House of Rabbit和 House of Lore 很像,不過是用 fastbin FD pointer。fastbin 是 single linked-list。
改寫 FD 為目的地址後,alloc 一個大於 0x10000 (64K) 的節,觸發 fastbin consolidation;fastbin 就會進入 unsorted bin。然後是 unsorted bin attack。
Arbitrary Allochttps://www.kn0sky.com/?p=d22edd6b-7d44-4bd9-baea-bdecc73a8da2
House of Orange主要原理是在沒有 free(..) 的情況下,用 top chunk release 來模擬 free(..)。方法是當 top chunk 不足以 alloc,就會調用 brk,舊的 trunk 就會被 free 到 unsorted bin。然後是 unsorted bin attack。Arbitrary Allochttps://ctf-wiki.org/pwn/linux/user-mode/heap/ptmalloc2/house-of-orange/
House of Roman是個很複雜的組合技。
用 Fake Chunk 偽造節 free 了進入 unsorted bin。然後修改 FD 和 malloc,使 malloc_hook 寫為 main_arena+88.
再將 malloc_hook 最低三字節改寫 one_gadget。調用 free(..) 或 malloc(..) 兩次,就會依次取得 malloc_printerr 和 get_shell。
Shellhttps://www.kn0sky.com/?p=761e0f77-6a76-44a9-a0d6-52d647d9e249

https://ctf-wiki.org/pwn/linux/user-mode/heap/ptmalloc2/house-of-roman/
House of Pig是個很複雜的組合技。用 largebin attack, tcache stashing unlink attack,可以得到 getshell。有不少限制,而且不易用;通常可以用較簡單的方式取代。Shellhttps://www.anquanke.com/post/id/242640#h2-3
House of Storm是很複雜的組合技。用 unsortedbin attack,將 BK 指向目的地址 addr。然後 largebin attack 將 BK 指向 addr+0x10;BK_nextsize 指向 addr-0x20+3.
然後 alloc 0x50 就會取得目的地址。
Arbitrary Allochttps://www.kn0sky.com/?p=195d505e-1310-4e6d-b9cd-20eadd7200b9
其實還有
House of Kiwi
House of Emma
House of Apple
House of Banana
House of Water
House of Tangerine
House of Botcake
House of Mind
House of gods
House of Prime
House of Chaos
普遍技術研究較少提及。未能盡錄。
這 House of xx 傳統,改名最初來自這個帖

https://github.com/Malformation/Notes/blob/master/MallocMaleficarum.txt

概念啟發來自這本書

https://en.wikipedia.org/wiki/Malleus_Maleficarum

~ Reference ~

https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_rabbit/
https://ctf-wiki.org/pwn/linux/user-mode/heap/ptmalloc2/house-of-rabbit/
https://guyinatuxedo.github.io/43-house_of_orange/house_orange_exp/index.html

《資安 pwn 不正常技術研究所》系列:

資安 pwn 技術研究所:Heap pwn 篇 (3) – Free 與 alloc 流程

~ 檢查 ~

Free 之前,會用一系列的 check 檢查:

  1. chunk 是對齊 2*SIZE_SZ 的整數倍
    • 同前文:在 64-bit 環境下,SIZE_SZ=8;32-bit 環境下 SIZE_SZ=4。
  2. free 是可行的。例如不是太小、太大、不對齊,或越過了程式的邊界的地址空間。
  3. chunk 是在 arena 的址址空間內。
  4. chunk 不是已標記成 freed。這是檢查下一個 chunk 的 PREV_INUSE bit。

~ Free 演算法 ~

Free 的演算法如下所示:

  1. 如果 pointer 為 null,則不用運行 free;
  2. 將 chunk 變成 free 狀態(但未必會將下一個 chunk 的 PREV_ISUSE 設為 0,視乎哪一個 bin)
  3. 做上面的 sanity check 檢查;
  4. 若可以放進 tcache bin,就放進去;除非滿了七個,就繼續往下面;
  5. 如果 IS_MAPPED=1,那麼是要 munmaped;
  6. 否則就要取得 thread heap lock,然後做下面步驟;
  7. 若可以放進 fast bin,就放進去;
  8. 若 chunk 大於 64KB,就將 fastbin 都放進 unsorted bin;
  9. 若前一個 chunk 是 freed,那麼就會向前合併。若下一個 chunk 是 freed,那麼就會向後合併;然後放進 unsorted bin;
  10. 若是處於邊界,就會做 trimming,而不會進入 bin;
  11. 若以上皆不是,就會標籤為 freed,然後放進 unsorted bin。
  12. 完。

~ malloc 演算法 ~

malloc 演算法如下所示:

  1. 若 tcache bin 有適用的 chunk,就用;
  2. 若 size 是大到需要用 mmap,就用;
  3. 否則就要取得 thread heap lock,然後做下面步驟;
  4. 檢查 fastbin 和 small bin
    • 若 fastbin 有,就用;
    • 否則,若 small bin 有,就用;
    • 有可能將 chunk 升級進 tcache bin
  5. 檢查 unsorted bin
    • 將 fast bin 的都解放進 unsorted bin
    • 若 unsorted bin 有,就用,而且停下;否則,就將檢查到的 unsorted bin chunk 放進 small 或 large bin;
    • 有可能將 unsorted bin chunk 升級進 tcache bin
  6. 檢查 large bin
    • 若 size 是符合 large bin,就檢查 large bin;同樣,有,就用;
  7. 造出新 chunk
    • 若以上都不符合,就嘗試從 top of the heap 取得;
    • 若 top of the heap 不夠大,就運行 sbrk 以增大;
    • 若 top of the heap 不能增大(即 sbrk 失敗),就運行 mmap 以取得 chunk;
  8. 若以上都不合,則回傳 NULL

《資安 pwn 不正常技術研究所》系列:

資安 pwn 技術研究所:Heap pwn 篇 (2) – 各種 bin 格式

bin 是個 array。共有 126 個 bin。如上圖。即共有:

  1. 62 個 small bin
  2. 63 個 large bin
  3. 1 個 unsorted bin
  4. 10 個 fastbin
  5. 64 個 tcache bin per thread

~ small bin ~

  1. small bin 是整齊排好的
  2. 從最小的 兩個「2*SIZE_SZ」單位開始,每個 ID 遞增一個單位。
    • 同前文:在 64-bit 環境下,SIZE_SZ=8;32-bit 環境下 SIZE_SZ=4。
    • 所以 32-bit 下,small bin 1 是 2*2*4=16;64-bit 下 small bin 1 是 2*2*8=32。
    • 之後每個遞增 2×4=8 (32 bit) 或 2×8=16 (64 bit)
    • 最大的為 63*2*4=504 (32 bit) 或 63*2*8=1008 (64 bit)
    • 例如 32-bit 0x10=16 是進入 small bin 1,加上 metadata 為 size=0x20

~ large bin ~

large bin 是有不同大小。如上圖。

~ unsorted bin ~

以上三個是基本機制:

  1. 先進入 unsorted bin。
  2. 到 malloc 在 unsorted bin 尋找時,若符合的 chunk 它就會直接用;若不符合的 chunk 它就會整理到 small bin 或 large bin中。而永遠都只有一個 small bin 或 large bin 符合任何一個 size。
  3. 若 free 當中合併了,或釋放了,都會進入 unsorted bin。
  4. 然後加上了下面 fastbin 的機制

~ fastbin 機制 ~

  1. fastbin 有 10 個。大小時和頭十個 small bin 一樣。
    • 32-bit 下,fast bin 1 是 2*2*4=16;64-bit 下 fast bin 1 是 2*2*8=32。
    • 32-bit 下,fast bin 10 是 11*2*4=88;64-bit 下 fast bin 1 是 11*2*8=176。
    • 例如 32-bit 0x10=16 是進入 fast bin 1,加上 metadata 為 size=0x20
  2. fastbin 的方式,是沒有真正 freed。它的下一個 chunk 的 PREV_INUSE 仍為 1。
  3. fastbin 內的 chunk 因為沒有真正 freed,所以也不會合併
  4. 因為沒有合併,所以不需要 double linked-list。fastbin 內只是一個 single linked-list。

~ tcache bin 機制 ~

  1. tcache bin 是用來處理 multi-threading 中的 race condition、lock 之類的資源浪費或問題。是可以加速程式的運行效率。
  2. tcache bin 有 64 個 (per thread)。每個 bin 最多有 7 個 chunk。
    • 64 bit 的由最小的 24,遞增 16,至 1032 (63×16 + 24)(0 – 24 size 都進入 tcache bin 1,例如 0x10=16 是進入 tcache bin 1)
    • 32 bit 的由最小的 12,遞增 8,至 516 (63×8 + 12)
  3. 若 tcache bin 滿了,則會流動到其他 bin

~ Reference ~

Part 2: Understanding the GLIBC Heap Implementation
https://azeria-labs.com/heap-exploitation-part-2-glibc-heap-free-bins/

Glibc Malloc Principle
https://www.openeuler.org/en/blog/wangshuo/Glibc%20Malloc%20Principle/Glibc_Malloc_Principle

《資安 pwn 不正常技術研究所》系列:

資安 pwn 技術研究所:Heap pwn 篇 (1) – Chunk 格式

~ Heap Pwn 方法論 ~

講到研究 heap pwn,和其他 vulnerability 研究題目不同的是,不是由漏洞和方法開始;很重要的是要先明白內部格式。有幾個知道是 pre-requisite,是需要預先知道的:

  1. Chunk 格式
  2. Assign 和 Free 的過程,和對 Chunk 的影響
  3. 不同的 Bin 的情況

會包括這篇在內,連續用幾篇的篇幅先解釋這些。然後才可以進入 vulnerability 和相關方法的討論。
值得留意的是 Heap Pwn 方法的用處只屬 Researcher 或 CTF 比賽用途。不建議作其他用途。

~ malloc_chunk 格式 ~

struct malloc_chunk { // below size assumed 64-bit systems
   INTERNAL_SIZE_T         prev_size;  // 8 bytes, size of previous chunk (if free)
   INTERNAL_SIZE_T         size;            // 8 bytes, size in bytes, including overhead
   struct malloc_chunk* fd;  // 8 bytes, double linked-list.  used only if freed
   struct malloc_chunk* bk; // 8 bytes, same
   struct malloc_chunk* fd_nextsize; // 8 bytes, double linked-list.  used only if freed, and only large blocks.
   struct malloc_chunk* bk_nextsize; // 8 bytes, same
} // 48 bytes in total

講解下幾個成員變數:

  1. prev_size:如果上一個 chunk 是 freed,那麼是它的 size。否則就會是上一個 chunk 的一部份,會重疊了。
    • INTERNAL_SIZE_T = typedef unsigned long size_t = 8 bytes on 64-bit machines
  2. size:現在的 chunk 的大小。
    • 必然是 2*SIZE_SZ 的整數倍。在 64-bit 環境下,SIZE_SZ=8;32-bit 環境下 SIZE_SZ=4。
    • 而且最後 3 個 bit 是狀態標籤:
      • NON_MAIN_ARENA:標記 chunk 是來自 main arena。
      • IS_MMAPPED:標記 chunk 是來自 mmap。
      • PREV_INUSE:標記上一個 chunk 是 assigned (1) 或 freed (0)。
    • 因為就算是 32-bit 底下,2*SIZE_SZ = 8。所以 size 最小都會是 0x1000。即是,最後 3 個 bit 必然不用。
  3. fd, bk
    • 若是 freed:這會是在 bin 鏈結串列中,指向上一個和下一個 free chunk。
    • 若是 assigned:這會是使用者使用的空間,即是資料空間的一部份。
  4. fd_nextsize, bk_nextize
    • 若是 freed:僅用於 large bin;指向前一個和後一個和當前 chunk 不同大小的 chunk。
    • 若是 assigned:這會是使用者使用的空間,即是資料空間的一部份。

~ Reference ~

Glibc Malloc Principle
https://www.openeuler.org/en/blog/wangshuo/Glibc%20Malloc%20Principle/Glibc_Malloc_Principle

Tut09: Exploiting Heap Allocators
https://tc.gts3.org/cs6265/2019/tut/tut09-02-advheap.html

The Heap: How to exploit a Heap Overflow – bin 0x15
https://www.youtube.com/watch?v=TfJrU95q1J4

Heap exploitation, glibc internals and nifty tricks.
https://blog.quarkslab.com/heap-exploitation-glibc-internals-and-nifty-tricks.html

《資安 pwn 不正常技術研究所》系列:

資安 pwn 技術研究所:基本篇 (4) – shellcode 例子

~ 32-bit 代碼 ~

global _start
section .text

_start:
  ; int execve(...)
  xor   ecx,ecx                                      ; ecx = 0
  mul   ecx                                            ; eax, ecx = 0
  mov   al,11                                          ; execve syscall
  push  ecx                                           ; string NULL
  push  0x68732F2F                           ; "//sh"
  push  0x6E69622F                           ; "/bin"
  mov   ebx, esp                                   ; ebx point to /bin/sh\0
  int   0x80                                            ; trigger

~ 編譯 ~

$ nasm -f elf32 shell_sh.asm
$ ld -m elf_i386 shell_sh.o -o shell_sh
$ ./shell_sh

~ 64-bit 代碼 ~

global _start
section .text

_start:
  ; int execve(...)
  xor   rdx,rdx     ; rdx = 0
  mov   qword rbx, '//bin/sh'
  shr   rbx, 0x8
  push  rbx
  mov   rdi, rsp
  push  rax
  push  rdi
  mov   rsi, rsp
  mov   al, 0x3b
  syscall

~ 編譯 ~

$ nasm -f elf64 shell_sh.asm
$ ld shell_sh.o -o shell_sh
$ ./shell_sh

《資安 pwn 不正常技術研究所》系列:

資安 pwn 技術研究所:基本篇 (3) – 編譯與連結

用圖說明。

《資安 pwn 不正常技術研究所》系列:

資安 pwn 技術研究所:基本篇 (2) – ELF 格式

~ Magic Number ~

ELF 檔的頭四位為 7F 45 4C 46,即 127,E,L,F。

~ 節表 ~

解釋
.text程式節
.data資料節:已初始化的全域變數或局部靜態變數
.rodata惟讀資料節:惟讀變數和字串常數
.bss未初始化的全域變數和局部靜態變數
.comment版本控制資訊,例如 compile version
.debug_XXDWARF 格式的 debug info
.strtabstring table
.shstrtab節名的 string table
.symtabsymbol table
.dynamicld.so 使用的動態連結資訊
.dynstr動態連結的 string table
.dynsym動態連結的 symbol table
.gotGOT (global offset table):保存全域變數引用的地址
.got.pltGOT:保存函數引用的地址
.pltPLT (procedure linkage table):for lazy binding
.hash符號 hash table
.rela.dyn變數的動態重定位表
.rela.plt函數的動態重定位表
.rel.text / .rela.text靜態重定位表
.rel.XX / .rela.XX其他節的靜態重定位表
.note.XX額外的編譯資訊
.eh_frame用於操作異常的 frame unwind 資訊
.init / .fini程式初始化和終止的程式

《資安 pwn 不正常技術研究所》系列:

資安 pwn 技術研究所:基本篇 (1) – 地址地圖

開初用一篇解釋下地址地圖。用圖說明。

《資安 pwn 不正常技術研究所》系列:

資安 pwn 技術研究所:簡介

有一直研究 pwn 技術。用個分類寫下筆記和分享。

pwn 的分類,是資安技術中,的 Binary Exploitation 類別。都是些很少人和通常都是資深技術人士才曉得的技術。

pwn 的一般程度都是專家才用到。一般例如 stack overflow、ROP、buffer overflow、format string 那些。在這博客欄內這些基本技術就不寫了。

這欄目是在 pwn 進階的研究 heap pwn 的途中,想用個地方寫下研究心得而設。

《資安 pwn 不正常技術研究所》系列: