前言
接續昨天的 Educational Heap Exploitation,今天介紹的技巧在 glibc 2.29 中都已經被修復,不過其實大部分的 Linux distribution 都還沒使用 2.29,因此在撰寫 real world 的 exploit 時依然是很實用的技巧
Educational Heap Exploitation - part 2
1. unsafe_unlink.c
- 上一篇有提到早期的 heap 題會考 dlmalloc 的 unlink 造成任意位置寫入的用法,但在 ptmalloc 在 unlink 時加入了 circular check,已經無法使用
- ptmalloc unlink 的條件變成非常嚴苛,需要以下條件:
- 需要已知一個指向 heap 的變數 p,一般會需要 p 的位置,通常是在 bss 段
- 因此在 PIE enable 的程式幾乎無法利用,如果能 leak 了有其他更簡單的利用方式......
- p 需要存在 UAF,並且能修改 fd 和 bk
- 操作完 p 的值會變成
&p-0x18
,接著要能繼續對 p 寫兩次值,第一次改掉 p 指向的 address,第二次就造成任意位置寫入
- 接下來不能有任何 small bin 和 unsorted bin 的操作,否則程式通常會 abort
- 詳細原理請參考:https://www.slideshare.net/AngelBoy1/heap-exploitation-51891400
- 範例 code 存在 UAF 的漏洞,如果前一塊記憶體上的 chunk 有 bof 的問題也可以利用此方式,但前一個 chunk 不能是 freed 否則會一起被 merge
- 文件上寫可利用版本是 < 2.26,但避開觸發 tcache 之後應該還是能使用
2. poison_null_byte.c
- heap exploit 最典型的利用,在其他類型的 buffer 發生 null byte off-by-one 通常只能造成 crash,在 heap 上卻可以透過巧妙的排 heap 讓 chunk overlap 達到 RIP control
- 跟 overlapping_chunks.c 和 overlapping_chunks_2.c 達成類似的效果
- 最早看到相關的技術分析是由 Project Zero 揭露的 Ghost 漏洞所使用
- 詳細原理請參考:https://www.slideshare.net/AngelBoy1/advanced-heap-exploitaion
- 範例 code 的漏洞是真實用 null byte off-by-one 進行利用
-
a[real_a_size] = 0; // <--- THIS IS THE "EXPLOITED BUG"
- 文件上寫可利用版本是 < 2.26,但避開觸發 tcache 之後,到 2.28 之前還是能使用
- 2.29 增加 prev_size 要和上一塊 chunk size 大小相同的檢查,向後一塊做 unlink 造成 shrink chunk 已經不能用了
3. overlapping_chunks.c
- 與昨天的 overlapping_chunks_2.c 做法類似,但這次是加大 freed chunk 的 size 來達成 overlap
- 前一塊 chunk 不能是 freed 否則會觸發 unlink 造成 abort
- 範例 code 存在 UAF 的漏洞,如果前一塊記憶體上的 chunk 有 bof 的問題也可以利用此方式
- 文件上寫可利用版本是 < 2.26,但避開觸發 tcache 之後應該還是能使用
4. unsorted_bin_attack.c
- 改寫 unsorted bin 的 bk,下次 malloc 之後會在 bk + 8 的位置寫上 unsorted bin 的 address
- 無法控制寫入的內容,一般來說無法直接控制 RIP
- 比較常見的用法是講
global_max_fast
的值改掉,這樣後面所有 chunk 都會以 fastbin 的方式進行處理
- 2.29 後因為加入 unsorted bin 的 circular check 而無法使用
- 範例 code 存在 UAF 的漏洞,如果前一塊記憶體上的 chunk 有 bof 的問題也可以利用此方式
5. unsorted_bin_into_stack.c
- 與 unsorted bin attack 的原理一樣,但需要將 bk 指到偽造的 chunk
- 跟 fastbin_dup_into_stack.c 效果一樣,通常會用到的情境是想讓 heap bof 變成 stack bof 進行 ROP
6. large_bin_attack.c
- 有兩個利用前提:
- 需要可以修改 largebin 上的 data
- unsorted bin 要跟在 largebin 的後面
- 與 unsorted bin attack 達成的效果類似,通常也要後續的 heap 利用才能達成 RIP control
- 文件上寫可利用版本是 < 2.26,但避開觸發 tcache 之後應該還是能使用
0x10: PlaidCTF CTF 2015 Pwn 550 PlaidDB
解釋一下這篇現在才補的原因,當時想試試看在最新版的 glibc 2.29 有沒有辦法利用,在排除 tcache 的限制,在做 unlink 的時候怎麼樣都失敗 QQ 後來在做 Balsn CTF PlainNote
才發現 2.29 有對 unlink 做 harden ... QQ
這題 PlaidDB 應該是 heap 題正式進入血尿時代的開端...XD 概念是源自於 Project Zero 的技術文章 The poisoned NUL byte, 2014 edition (之前就有揭漏 off-by-one 的利用,但這邊講解得最清楚)
這題長得不像標準選單題的樣子,但其實差不多,只是變成透過 command 去操作功能,但逆向時痛苦的是在做儲存時不單純只是分配 heap,背後有用一個類似 RB tree 的 data structure 去儲存 chunk,因此這題要逆完程式的功能才有辦法開始排 heap
這題是實作了一個 database 的 service,每一筆資料表示一個 row
,row 的結構大致如下:
struct row {
char *key
int size
char *content
row *left
row *right
row *parent
bool is_leaf
}
database 支援的 command 如下:
-
GET
- allocate 一段放 key 的 heap buffer,用 key 去向 database query 內容,結束會 free 掉 heap buffer 不會保存
-
PUT
- 會先 allocate 大小為 0x38 的 row,再 allocate 8 byte 作為 key 的 buffer,最後根據輸入的 size 大小分配 content 的內容
- 輸入 key 時如果超過 8 byte 就會用
realloc
重新分配兩倍的空間
-
DUMP
-
DEL
- 跟
GET
類似,allocate 一段放 key 的 heap buffer,如果 match 到就會把對應的 row 給 free 掉
- 但如果沒有 match 到,前面 allocate 出來的 key buffer 會保存,可以用這個 bug (?) 來協助排 heap
這題的漏洞是在實作 input function 的地方存在 off-by-one 的問題,如果輸入的 key 長度剛好 match 目前 buffer size,就不會觸發 realloc
,但是會在結尾補 \0
,所有需要輸入 key 的地方都可以觸發
利用方式就是 2. poison_null_byte.c 提到的方式,在這就不再贅述,在 overlap chunk 之後,把 key 的 chunk 和 row 的 chunk 都落入可修改的範圍,就可以利用 DUMP
來 leak libc address
這題沒有 edit 的功能好用,因此 overlap 之後還是不好修改 chunk data,會需要利用 RB tree 做 node 搬移的功能,首先要把 row 偽造成以下的結構:
row->key = '/bin/sh'
row->size = 7
row->content = NULL
row->left = libc.sym['__free_hook']
row->right = libc.sym['__free_hook'] - 0x30
row->parent = libc.sym['__free_hook']
row->is_leaf = libc.sym['system']
這樣在觸發 DEL
的時候,__free_hook
就會被寫上 system
,下一次再 free 就可以執行 system("/bin/sh") 拿到 shell
必須說這題是很有 DEF CON CTF 風格的一題,整個程式被包裝成很 real world,除了排 heap 以外需要了解整個 PlaidDB 如何運作,這種題目跟現在常見的選單題是各有優劣,但這題會有大量時間需要 reverse 程式,如果是剛學習 heap exploit 的新手就不太適合做這題