0CTF/TCTF Finals Baby Heap 18.04, freenote2018 writeup
Baby Heap 18.04
機能
起動すると以下のように機能を選択できる。
===== Baby Heap 18.04 ===== 1. Allocate 2. Update 3. Delete 4. View 5. Exit Command:
各機能は、
1. Allocate
0x1 ~ 0x58までのサイズでmallocを実行できる。取得された領域はmemsetによって取得したサイズ分0埋めされる。ポインタは、bss上にある配列でサイズ、管理フラグと共に保管される。2. Update
指定したindexの領域へ、サイズを指定して書き込みを行える。サイズはAllocateで指定したサイズ+1
まで指定できる。off-by-one overflow3. Delete
指定したindexをfreeする。管理フラグを0にする。4. View
指定したindexの領域を、Allocateした時のサイズ分だけwriteで出力する。
方針
Update
でoff-by-one overflowがあるので、直下のチャンクのサイズを任意の値にすることができる。
まずは、チャンクのoverlapを起こし、address leakを行う。heapのアドレスは簡単に取ることできるが、この問題の環境はubuntu 18.04でありglibc 2.27である。つまりtcacheが有効になっている。tcacheが有効な環境では、サイズが0x420以上のチャンクをfreeすれば、そのチャンクはunsorted binに入り、fd/bkにmain_arenaを指すポインタが置かれる。あとはこのアドレスを出力させればいい、
制御の奪取はとても簡単で、tcacheには、繋がっているチャンクのサイズの確認が一切なく、fake chunkのサイズに該当する部分がどのような値であろうと問題なく動作する。__free_hook
を指すようにtcacheのfdを書き換えて、mallocするだけで、__free_hook
を指す領域を取得できる。
exploit
0CTF/TCTF 2018 Finals Baby Heap 18.04 pwn · GitHub
freenote2018
機能
選択肢は以下の5つ。
1. init a note 2. edit a note 3. free a note 4. show a note 5. exit
各機能は以下の通りである。
init a note
指定したサイズでmallocを実行できる。サイズの制限は0x1 ~ 0x100となっている。確保した領域のポインタはbss上にある配列でポインタと一緒に管理される。edit a note
index指定で1で取得した領域へ書き込みができる。書き込みできるサイズは、initした時のサイズと同じであり、overflowはない。free a note
index指定で指定した領域をfreeできる。free後にポインタをNULL埋めしないため、double freeできる。shoe a note
選択肢として存在するだけで、何もしない(表示もしない)
freeしたポインタがそのまま残っており、editとfreeで何度でも指定することができる。ただし、address leakに使えそうな機能が存在しない。
方針
最近読んで覚えていたので、以下の手法を使った。 House_of_Roman.md · GitHub
手法の概要は、unsortedbinに繋がるチャンクをfastbinsの方へforgeし、さらにチャンクのfdのmain_arena辺りを指すポインタをpartialで書き換えることで、__malloc_hook
付近を指すように書き換えてfastbin attackを成立させる。これで__malloc_hook
付近を覆うようにmallocで取得できる。
さらに、__malloc_hook
へunsortedbin attackによってlibcのアドレスを書き込み、partialで下位3byteを書き換えることで、one gadget RCEのアドレスを作る、といったものである。当然だが、brute forceが必要であり提案者は12bit分だと言っている(体感だともっと悪い気がする)。
今回のバイナリでは、
- initでmallocはするが書き込みeditと別になっている
- UAFによるfd辺りの書き換えがeditで容易にできる
- double freeによってfastbin attackが用意である といった感じで都合が良い。
exploit
12bit brute forceが必要となる。