栏目

首页 首页 黑科技查看内容

利用 ROP技术绕过DEP保护

最近更新| 发布者: 站长-黑杰克| 查看: |

本来打算有空闲了专门针对软件漏洞写一个系列专题,其中必不可少要介绍ROP技术以及如何过DEP保护。但是,近日有学弟问起ROP技术的原理,那就择日不如撞日,先写一篇关于如何制作ROP链过DEP保护的文章。

关于 DEP保护

(1)为什么要有DEP保护

溢出攻击的本质在于现代计算机对数据和代码没有明确区分这一先天性缺陷。因为我们可以将代码放置于数据区段,转而让系统去执行,这样就可能导致各种溢出攻击。

为了弥补这一先天性缺陷,微软从 XP SP2开始推出了数据执行保护(Data   ExecutionPrevention,DEP)。

(2)DEP保护的原理

首先明确,我们进行各种溢出攻击的目的是什么?不就是让软件(系统)去执行我们构造的shellcode吗?不管什么溢出,我们的shellcode都是放在程序的数据区段。一言蔽之,溢出的利用就是在数据段将shellcode当作代码来执行。

现在微软提供了 DEP保护,将程序的数据段标记为不可执行。当我们要在数据段执行shellcode时,CPU就会抛出异常,从而转向异常处理,而不会执行shellcode。

(3)DEP保护的类型

在32位计算机上,系统设置了两种DEP保护,用以指明对哪些进程或服务进行保护。

第一种为Option:默认选项,仅对Windows的系统组件和服务进行保护。

第二种为Opout:对列表以外的所有程序和服务启用DEP。如果列表为空,则表明对所有程序和服务进行DEP保护!

在Windows XP下,我的电脑->属性->高级->设置->数据执行保护,有DEP设置页面,如1所示。

利用 ROP技术绕过DEP保护 网络安全 第1张

补充说明:

(1)Windows7下的路径是:控制面板->系统和安全->系统->高级系统设置;Windows7版本不同,路径不同,但都在“高级系统设置栏”中。

(2)如果想让自己编写的程序受到 DEP保护,可以在 VS中进行设置。VS2010中,DEP保护选项为右击项目->属性->链接->高级。

关于  ROP

ROP,面向返回的编程(Return-oriented Programming,ROP),是一种新型的机遇代码复用技术的攻击。攻击者从已有的库或可执行文件中提取指令片段,构建恶意代码!对于ROP技术,我总结为三句话:

(1)ROP通过ROP链实现有序汇编指令的执行。

(2)ROP链由一个个ROP小配件(相当于一个小节点)组成!

(3)ROP小配件由“目的执行指令+retn指令组成”!

那么什么是ROP小配件?ROP小配件就是一个指向“汇编指令+retn指令”的地址。比如现在有个 ROP小配件想实现ebx加  1,那么这个ROP小配件的指令组合应该是:inc  ebx+retn。这时我们就在当前内存中寻找。假设找到0x7ffa1122处恰好是incebx+retn指令组合,那么这个ROP小配件就是:0x7ffa1122。

缓冲区溢出中,最常见的就是栈溢出。如果我们找到一个栈溢出漏洞,然后写了exp去攻击靶机;如果靶机中的目标程序受到 DEP保护,尽管能溢出成功,但根本无法去执行shellcode。这是因为我们的shellcode大部分在栈中(其实也可以放在内存数据区段的其它部分,比如堆);但不管是栈,还是堆,有了DEP保护,其上面的数据是不能执行的!但是,如果我们使用ROP技术,就可以完美解决了。秉承实践先行,理论验证的原则,下面我们直接动手利用ROP链绕过DEP保护!在实践过程中,大家可以自己去调试、理解!

构造 ROP链绕过  DEP保护

实验环境如下:

靶机系统:Windows XP SP3,FTPServer.exe,Procexp.exe,Immunity Debugger。

攻击机系统:操作系统随意,有python环境即可。

实验简介:FTPServer.exe是一款轻量级的 FTP服务端软件,其 user命令存在缓存区

出漏洞。procexp.exe是一款强大的进程查看软件,可以看到进程是否使用  DEP保护。

Immunity Debugger一款基于OD的调试器,实现与python的完美结合。

首先,我们在不开启 DEP保护的情况下,在 XP上成功溢出并获取反连 shell。接着,开启 DEP保护,看能否成功溢出(应该是不能成功溢出!);最后,使用ROP技术绕过  DEP,在开启DEP保护的情况下成功溢出!

(1)没有 DEP保护,成功溢出

在我们的系统中,默认以 Option方式开启 DEP,即仅对 Windows的系统组件和服务进行保护,而我们所选的 FTPServer.exe不是系统组件或服务,所以默认状态下   FTPServer进程是不开启DEP保护的,如图2所示。从中可知:系统进程,如explorer.exe是默认开启DEP的;而FTPServer是不开启的。

利用 ROP技术绕过DEP保护 网络安全 第2张

如何编写exp不是本文的重点。这里我们用一个python写的exp:FreeFloat.py来利用FTPServer.exe上的栈溢出!(此exp来自于/exploits/15689/)。但这个exp在我的XP系统不能运行,经过调试分析,发现将eip覆盖成万能跳转地址0x7ffa4512即可!靶机上运行FTPServer.exe,如图3说是所示;攻击机运行FreeFloat.py,实施溢出攻击,如图3所示。

利用 ROP技术绕过DEP保护 网络安全 第3张

利用 ROP技术绕过DEP保护 网络安全 第4张

溢出成功!接下来可以连接4444端口验证漏洞利用是否成功。使用telnet命令:

telnet192.168.13.1304444,如图4所示。从中可以看出,在没有开启DEP保护的情况下,FTPServer.exe的栈溢出漏洞被成功利用!

利用 ROP技术绕过DEP保护 网络安全 第5张

.

(2)开启 DEP保护,溢出失败

默认状态下FTPServer进程是不受DEP保护的,但我们可以使用Opout选项,让所有进程都受DEP保护。修改之后,重启方可生效!

重启之后,发现所有进程都受DEP保护,包括FTPServer进程!如图5所示。

利用 ROP技术绕过DEP保护 网络安全 第6张

仍然使用FreeFloat.py对FTPServer进行攻击,如图6所示。

利用 ROP技术绕过DEP保护 网络安全 第7张

溢出成功,但漏洞利用成功了吗?使用telnet一试便知,如图7所示。

利用 ROP技术绕过DEP保护 网络安全 第8张

可以发现连接失败,漏洞并没有成功利用。切回到靶机系统,发现程序崩溃,如图8所示。

利用 ROP技术绕过DEP保护 网络安全 第9张

如果调试漏洞多了,从错误提示框就能看出是DEP保护造成的。因为我们的EIP是用万能跳转地址“0x7ffa4512”(jmpesp)覆盖的。在0x7ffa4512下硬件访问断点,重新攻击,发现程序停在如图9所示的位置处。

利用 ROP技术绕过DEP保护 网络安全 第10张

从栈中数据可以看出我们的溢出是完全成功的,但由于有DEP保护,栈上的数据并不能被执行,反而触发异常,造成程序退出!

这个程序崩溃在0x7ffa4512处,是由于此地址本身就是一个内存数据区域;如果换成其他jmp esp就应该崩溃在0x90909090处!大家可以自己实践验证!总之,由于DEP保护的开启,我们的漏洞利用失败!下面就要想办法绕过DEP!

(3)利用 ROP链绕过  DEP保护

①绕过DEP保护的思路

对于绕过DEP的思路,无外乎两个:

新建一个新的可执行的内存区域,然后将shell复制进去。一般使用VirtualAlloc,HeapCreate函数先建立可执行堆,然后使用memcpy等函数将shellcode复制进去。

使用   Windows API直接关闭     (停用   )DEP保护!这类函数一般有SetProcessDEPPolicy()、NtSetInformationProcess()和VirtualProtect。

具体选择哪个思路,哪个函数,要视具体情况而定,如图10所示。

利用 ROP技术绕过DEP保护 网络安全 第11张

对于以上两个思路,不管哪个我们都得调用 API函数,而且这些函数必须要我们能控制、能构造!这就是 ROP链要做的!

ROP链的作用就是用一连串ROP小配件实现这些函数的调用并转到shellcode上。那么,ROP链是怎样实现这些函数的调用的呢?我们通过实际例子来说明。

②实战绕过DEP保护

由于 SetProcessDEPPolicy()函数最简单,所以我们调用此函数来关闭  DEP保护,然后转到我们的 shellcode上去。

使用!mona rop–m  msvcrt.dll命令寻找模版。

第一步:使用Immunity Debugger加载FTPServer;

第二步:在命令行中键入!mona rop–m  msvcrt.dll,如图11所示。

利用 ROP技术绕过DEP保护 网络安全 第12张

-m的意思是在哪个模块中寻找 ROP模版;也可以–m  user32.dll;默认是在所有模块中寻找。为什么选择msvcrt.dll呢?(思考一下,本无定数!)命令执行完,在ImmunityDebugger的安装目录下寻找rop_chain.txt文件,其中就有各个函数、各个语言的模版!我们选择 SetProcessDEPPolicy()函数、python版!如图  12所示。

利用 ROP技术绕过DEP保护 网络安全 第13张

其实很多时候,这个模版是可以直接拷到exp中使用的,不过这个模版恰好不行。不行也好,我们可以做一些最本质的分析!

在rop_chain.txt文件中,往前翻,发现如图13所示的内容。

利用 ROP技术绕过DEP保护 网络安全 第14张

为什么会给出这些寄存器呢?

其实ROP链的目的就是去构造寄存器中的数值,然后使用pushad指令将这些值全部压入堆栈中,这样就可以调用SetProcessDEPPolicy()函数,从而关闭DEP保护!

有人会问,为什么寄存器要这样布置?

首先我们明确pushad指令的特点。Pushad是将所有寄存器的值入栈,其入栈顺序是eax、ebx一直到edi,将图13中的值依次入栈,而出栈是先入后出!

在使用pushad指令入栈前,esp指向shellcode。所以,esp上面的寄存器(栈中)ebp就必须是指向SetProcessDEPPolicy()函数的函数地址,这样才能保证在函数调用完后,转到esp中,从而执行我们的shellcode。根据函数调用规则,ebx就应该是函数参数。

于 edi和 esi,则必须是 retn指令,什么也不干,只是为了让程序向下(栈中)执行到SetProcessDEPPolicy()的函数调用。谁让它们在ebp寄存器的上面(栈中)。

最后,不要忘了还有eip寄存器;这时我们可以用任意一个带retn指令的ROP小配件来覆盖 eip;这里我们用 pop ebx +retn小配件来覆盖,也可以直接用 retn指令地址去覆盖!

从模版中可以看到构造ebx的ROP小配件有了,构造edi的ROP小配件有了;就剩下构造ebp、esi和纯retn小配件。还有,由于自己习惯问题,我不喜欢使用模版中的pushad+addal0x0ef+retn这样的小配件,而比较倾向pushad+retn。这样,我们的模版就有了,具体如下:

#retn

#pop ebp+retn

#SetProcessDEPPolicy()函数地址

传给寄存器ebp

#pop ebx +retn

#0x00000000

#pop edi +retn

#retn

传给寄存器ebx

传给寄存器edi

传给寄存器esi

#pop esi +retn

#retn

#pushad+retn

之所以没有SetProcessDEPPolicy()函数地址,是因为SetProcessDEPPolicy()函数在kernel32.dll中,没在msvcrt.dll中。这里有个小技巧:使用!monarop– mkernel32.dll在这个kernel32.dl库中找模版,然后就可以看到SetProcessDEPPolicy()函数的地址,之后复制出来!在我的系统中,SetProcessDEPPolicy()函数的地址是0x7c862144。

③寻找模版中没有的小配件

现在还没有纯retn、pop ebp+retn、pop esi+retn和pushad+retn小配件!

下面我们使用!mona find命令来精确寻找。比如我们知道retn的机器码是0xc3,就可以使用图 14中的命令来寻找。然后在 Immunity Debugger安装目录下,打开   find.txt文件,其中就有所有retn指令的地址,我们选择0x77bfad6a。

利用 ROP技术绕过DEP保护 网络安全 第15张

接下来我们可以使用相同的命令寻找pop ebp+retn、pop esi+retn和pushad+retn的小配件。机器码如下:
 

 pop ebp+retn的机器码:0x5D  0xC3

  pop esi+retn的机器码:0x5E  0xC3

  pushad+retn的机器码:0x60  0xC3(这个小配件在全部模块中搜索的)

最终我们选择:

0x77bebb47指向pop  ebp+retn

0x77bf3181指向pop  esi+retn

0x77d23ad9user32.dll中)指向pushad+retn

④打造自己的ROP链

构造每个寄存器的小配件都有了,下面就该打造ROP链了。

在构造整个链的过程中,会遇到很多问题,而且可能每个人遇到的问题都不一样,所以这里我只说如何去做!

先打造一个初步的模型,然后不断用Immunity Debugger加载调试,分析出现的问题。

我们的目的只有一个:成功构造寄存器——让 ebx为 0;ebp为 SetProcessDEPPolicy()函数地址;edi和esi都是指向retn的地址。

最终构造的ROP链如图15所示。

利用 ROP技术绕过DEP保护 网络安全 第16张

之所以ebx不用0x00000000,是因为服务器接受数据会截断!即0x00是badchar,我们必须避免出现,所以用0xffffffff+1来代替!最终目的还是让ebx==0。

运行 FreeFloat-AntiDEP.py,发现在有 DEP保护情况下,仍然能够成功利用漏洞,如图16和图17所示。

利用 ROP技术绕过DEP保护 网络安全 第17张

利用 ROP技术绕过DEP保护 网络安全 第18张

其实在选择是以SetProcessDEPPolicy(),还是以VirtualProtect()为例进行讲解ROP链的时候,我有所犹豫。很明显,SetProcessDEPPolicy()函数最简单,最易懂;但VirtualProtect()函数更具实用性。尤其在后面遇到一些“持久DEP”保护时,SetProcessDEPPolicy()函数可能就不能发挥作用了,此时我们就不得不选择VirtualProtect()函数。

但考虑到这仅仅是一篇入门文章,所以我们以最简单易懂为目的,故选择了SetProcessDEPPolicy()函数。

总结与思考

其实仔细思考,构造  ROP链就是对各个寄存器的构造!而对各个寄存器构造的目的是调用绕过函数和转到 shell,所以我们构造 ROP链绕过   DEP的思路就是:构造  ROP链->构造各个寄存器(参数、函数地址、转到 shell)->调用绕过 DEP的函数。为什么我们能利用 ROP绕过  DEP保护呢? 

在试验中我们发现,有  DEP保护时,尽管不能成功利用漏洞,但溢出是成功的。也就是说,我们能控制栈上的数据布局,这样就有机可乘——可以将这些栈上数据布置成ROP小配件,并用此来关闭 DEP保护!
ROP小配件为何能实现指令的一个接一个的执行呢?

这有两个原因:一是这些  ROP小配件只是指向可执行段的地址,真正的指令在这些地址中,而这些指令不受 DEP保护限制;二是利用  retn指令的特性。当执行  retn指令时,CPU会做两个动作:esp处的地址(当前栈地址)被传到  eip中,并被执行;然后  esp+4n。这样就可以在执行完一个 ROP小配件后,顺利执行下一个  ROP小配件!(思考:为什么每个   ROP小配件后要有一个retn指令!)

 



文章由天启科技原创,抄袭必究,转载请注明:
本文地址:http://www.goodgoodhack.com/heikejishu/2432.html
文章由天启科技站长黑杰克原创,免费学习黑客技术,业务联系站长QQ9326665

最新视频