概述
前面两次栈溢出只是让我们学习原理,是最简单、最基本的栈溢出问题,一般的pwn题不会这么简单,溢出一次就可以到位。今天我们就做第一步进阶,正式进入ROP。
就我目前理解的ROP,就是要通过连续多次栈溢出,利用其原有的gadget(可以叫做代码片段),构造一次系统调用,调用execve()函数,就相当于获得了一个shell。首先我们要知道,系统调用的中断号是0x80,而execve的功能号是11,也就是16进制的0xb。所以在进行系统调用(即执行INT 80H这条语句)之前,我们先要构造出调用execve()函数所需要的参数。
首先,需要将EAX寄存器的内容赋值为0xb,因为系统调用的功能号是默认存储到EAX寄存器当中的,而且我们上面说了,execve()函数的功能号是0xb,所以第一步要先给EAX赋值。然后,将EBX寄存器的内容赋值为"bin/sh"字符串所在的地址,就如下面的0x80BE408.
除此之外,还要将ECX和EDX的内容置零。以上就是调用execve()函数所需要的条件,总结起来就是下面几条语句。
mov eax,0xb
mov ebx,["bin/sh"]
mov ecx,0
mov edx,0
int 80
=>execve("bin/sh")
因为代码中基本不可能会出现这样连续的语句,所以我们需要通过连续的栈溢出,使这样的gadget(代码片段)能够连续执行,从而达到我们目的。下面就是我们要构造的栈内容。
int 0x80 address |
0 |
pop_edx_ret address |
0 |
pop_ecx_ret address |
"bin/sh" address |
pop_ebx_ret address |
0xb |
pop_eax_ret address |
|
接下来我们就去具体完成一个题目。
经典开头,使用checksec命令查看一下文件类型和权限。
发现是32位程序,小端模式,而且栈不可执行。和以前一样,我们先调试,查看一下覆写掉main函数的return address需要多少个字节的垃圾数据。
0x98-0x2c+4=112个字节数据。接下来我们就需要找我们要用到的gadget的地址了。
我们通过筛选的方式,找到可用的gadget,这里我们pop eax_ret选用0x80bb196
同样的方式找一个可用的pop_ebx_ret,这里我们选用0x806eb90
找到中断的地址0x8049421.
然后就是去寻找"bin/sh"的地址,我们可以去ida里面寻找,通过shift+F12再ctrl+F搜索
或者也可以再ubuntu下使用pwntools工具进行查找
找到以上的数据,我们的参数就已经凑齐了,接下来就可以去编写攻击脚本啦
执行以上脚本,我们就可以成功的获取到shell啦!
ROPgadget --binary ret2syscall --only "pop|ret" | grep ebx/
/ROPgadget工具 --binary ret2.. 指明二进制文件 --only "",要搜索内容 grep输出带有其后第一个参数的内容
flat()函数//接收一个列表参数,列表每一项转换成字节型数据,并且不足一个字的自动补齐
最后
以上就是背后溪流为你收集整理的栈溢出的第一步进阶——ROP返回导向编程的全部内容,希望文章能够帮你解决栈溢出的第一步进阶——ROP返回导向编程所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复