Ret2text(源程序中存在system及/bin/sh)
控制程序执行程序本身已有的的代码(.text)。栈溢出,存在system()函数以及”/bin/sh”字符串。通过溢出将返回地址修改为system函数的地址,再将/bin/sh作为函数的参数进行调用,如此便可以得到一个shell。其中32位程序和64位程序由于函数形参的存储调用存在差别,故利用方式也会不同。
32位程序
在32位的程序中,形参存储在栈上并且是按从右到左的顺序进行存放,形参结束后存储的是函数的返回地址,接着是函数的地址。
函数调用过程中栈帧的变化
以下为栈溢出调用system函数过程中栈的变化。
其中call函数与直接用eip指向函数地址的区别
call函数的调用中存在两步,
- 首先将后面的代码,即是下一条指令的地址入栈(保护现场)
- 将调用函数的地址给到EIP执行
从call函数的执行可以看出会自动的将下一指令的地址入栈以保持栈的平衡,call的函数执行完成后会能恢复,所以当直接将函数地址赋给EIP时就需要手动的入栈一个返回地址以维持栈的平衡。
64位程序:
由于在64位程序中六个参数依次保存在RDI,RSI,RDX,RCX,R8和 R9中,如果还有更多的参数的话才会保存在栈上。如下
通过以上流程即是可以通过寻找我们需要的指令地址及字符串地址进行利用链的构造最后成功getshell。这既是要求在上述情况中存在调用system函数的情况并且能够在其中找到字符串/bin/sh才能进行利用。
以下使用一个在程序作为例题进行分析
例题:
获取附件
使用checksec检查是否开启了保护
发现是一个32位的程序,只开启了NX,即是栈不可执行
使用IDA32位进行分析
使用shift+F12得到如上所示的页面
其中存在/bin/sh,但现在需要一个函数调用它才能执行命令
首先双击echo Hello World
使用ctrl+x查看引用的函数
使用F5进行反汇编
发现存在vulnerable_function函数,双击进入发现存在read函数可以利用
查看buf的长度,双击char buf进入buf变量的栈空间
发现buf的长度为0x88字节
加上ebp的长度4字节,(32位程序地址为32位,所占存储空间为4字节)
即是buf只用88字节,使用read函数输入的空间有100,超过了buf的长度,可造成栈溢出覆盖掉返回地址即可执行代码
因为前面存在了调用system函数,跳转到该函数,后面跟上该函数参数的地址即可
查看system的地址,回到主函数的汇编代码,此处使用call调用了一个system
地址为:0x0804849e