Exploit编写系列教程第十篇:用ROP束缚DEP-酷比魔方
译:看雪论坛-dragonltx-2010-9-20介绍
为什么脸上会长斑在我完成我前面的exploit相关教程之后三个月,我最终找了些时间和精力来开始写一篇新的文章。
在前面的教程中,我已经解释了基于栈溢出的基础和怎样执行任意的代码。我讨论了direct ret溢出,基于SEH的exploit,Unicode和其他的字符限制条件,运用调试器插件来加速exploit 的开发,怎样绕过常用的内存保护机制和怎样写你自己的shellcode。
然而第一个教程是写来引导人们学习exploit开发的基础,从乱写开始(主要是为了照顾那些不懂exploit开发的人们),你很可能发现最近的教程大体上继续在这些基础上下功夫,并且需要牢固的asm知识,创造力的思想,和一些exploit写作的经验。
今天的教材是不一样的。我将继续在我们已经在前面的教程中见过和学到的知识上更上一步。这需要一些一些要求:
1、你需要掌握基于栈溢出的利用技术(direct RET,SEH,等等)。我假设你已经具备了。
2、你需要一些asm知识。不要担心。即使你的知识只是能够明白特定指令的作用,你也将可能读懂这篇
教程。但是当你想自己打造自己的rop exploit/应用rop技术,当你需要完成一个特定的任务时,你需要能够写asm/认出asm指令。总之,在某种程度上,你能够在写rop 链和写通用的shellcode之间进行比较,因此我猜你已经有了一定水准的asm编写水平。
3、你需要知道怎样用Immunity Debugger。设置断点,单步执行,修改寄存器和栈上的值。
4、你需要知道栈是如何工作的,数据是怎样入栈的,出栈的,寄存器是怎样工作的并且怎样使寄存器和栈之间互相影响。这是开始写ROP所必须的。
5、如果你没有掌握基于栈溢出利用的基础,那么这文章不适合你。我将试着解释并且尽可能好的写出所有的步骤,但是为了避免以一篇很长的文章结束,我将会假设你知道基于栈溢出的原理和利用方法。
在这系列的文章6中lan.be:8800/index.php/2009/09/21/exploit-writing-tutorial-part-6-bypassing-stack-cookies-safeh-hw-dep-and-aslr/,我已经解释了一些技术来绕过内存保护系统。今天,我将精心阐述这些保护机制中的一个,叫做DEP。(更确切地说,我将讨论硬件DEP(NX/XD)和怎样绕过它)。在教程6中你可以读到,有2中主要的保护机制...首先,开发者能够利用很多技术(安全编码,栈cookies,safeh,等等)。大多数的编译器和链接器现在默认使用这些特征(除了“安全编码”,这不是课程的一个特征),这是很不错的。很悲哀,还有相当多数量的应用程
序没有利用保护措施,依靠其他的保护机制。我想你会同意还有很多的开发者没有将安全编码应用到他们的所有代码中。更重要的是(是事情更糟),一些开发者开始依靠OS的保护机制(看下面),并且不关心安全编码。
这将我们带到保护的第二层,所有最近版本的Windows操作系统的一部分:ASLR(地址空间布局随机化)和DEP(数据执行保护)。
ASLR将使栈,堆,模块基地址随机化,使它很难被“预测”(甚至硬编码)地址/内存位置,因此,使黑客很难打造可靠的exploit。DEP(在这个教程里我指硬件DEP)将会基本上阻止代码在栈上执行(这是所有前面教程所做的)。
ASLR和DEP的结合已经证明了在大多数情况下是有效的(但是,今天你将会学到的,在特定环境下还是可以被绕过的)。
简言之,应用程序bug/缓冲区溢出不会自动魔幻地消失,将会不可能消失,并且编译器/链接器不是一直对所有的模块都适用。这意味着ASLR和DEP是我们最后的防御层。ASLR 和DEP是所有最近OS的一部分,因此,很自然地可以看到攻击/绕过这两种保护机制已经成为黑客和研究者的重要目标。
表白文案在教程里用来绕过DEP的技术不是最新的技术。它基于ret-to-libc的思想并且被烙上“ROP”的印记,是“Return Oriented Programming”的简称。
云英语怎么读
我已经在教程6中讨论了ret-to-libc的思想,实际上,在教程6中解释的NtSetInformationProcess技术是ROP的一个例子。
在过去的几年/几月,用ROP绕过DEP的新技术已经写出来了。这个教程做的就是简单地将所有的信息聚集起来并且解释他们是怎样用来在win32系统上绕过EDP的。
在看DEP是什么,怎样绕过它之前,有一件很重要的事要记住::
在所有的前面教程中,我们的shellcode(包括定位代码等等)是放在栈或者堆上,并且试着用可靠的方法来跳到代码处并执行。
由于硬件DEP的使用,我们不能再栈上执行一条指令。你可以在栈上弹入并且弹出数据,但是我们不能跳到栈中执行代码。在没有绕过/禁掉DEP时不行。
记住。芦组词
Win32世界中的硬件DEP
硬件DEP利用了在DEP兼容的CPU的NX(“无执行页保护”,AMD规格)或者XD(“不能执行”,intel规格)位,并且将特定部分的内存(只能包含数据,比如说默认堆,栈,内存池)标记为不可执行。
当尝试在一个DEP保护的数据页执行代码时,将会发生访问拒绝(STATUS_ACCESS_VIOLATION(0xc0000005))。在大部分情况下,这会导致进程结束(没有处理的异常)。事实上,当一个开发者决定他想允许代码在一个特定的内存页中运行,他将不得不分配内存然后标记为可执行。
清淡食物有哪些在Windows XP SP2和Windows Server2003SP1引入了硬件DEP的支持,并且是这两种版本之后的所有Windows操作系统的一部分。
DEP作用在每个虚拟内存页面并且会改变PTE(页表入口点)上的一位来标记页面。
为了使OS用这个特征,处理器必须运行在PAE模式(物理地址扩展)。幸运地,Windows 默认开启PAE。(64位的系统是知道“Address Windowing Extensions”(AWE),因此也不需要在64位上有一个分离的PAE内核)。
DEP在Windows操作系统中表现的方式是基于一个能够配置成下列值中的一个的环境:
●OptIn:只有有限的一些windows系统模块/二进制程序是受DEP保护的。
错位节拍一个土一个旦●OptOut:所有在Windows系统上的程序,进程,服务都是受保护的,除了在例外列表中的进程。
●AlwaysOn:所有在Windows系统上的程序,进程,服务都是受保护的。没有例外。
●AlwaysOff:DEP被关掉。
除了这四个模式之外,MS实现了一种叫做“永久的DEP”机制,用SetProcessDEPPolicy (PROCESS_DEP_ENABLE)来确保进程是启用DEP的。在Vista(并且之后的)上,这个“永久”的标记是自动对所有的可执行文件(用/NXCOMPAT选项)设置的。当标记被设置,那么改变DEP策略可能只能用SetProcessDEPPolicy技术(看后面)。
你可以在/en-us/library/bb736299(VS.85).aspx和/b/michael_howard/archive/2008/01/29/new-nx-apis-added-to-windows-vista-sp1-windows-xp-sp3-and-windows-rver-2008.aspx找到更多有关SetProcessDEPPolicy的信息。
对不同版本的Windows操作系统的默认设置是:
●Windows XP SP2,XP SP3,Vista SP0:OptIn(XP SP3也有永久的DEP)
●Windows Vista SP1:OptIn+AlwaysOn(+永久的DEP)
●Windows7:OptOut+AlwaysOn(永久的DEP)
●Windows Server2003SP1和更高的:OptOut
●Windows Server2008和更高的:OptOut+AlwaysOn(+永久的DEP)
在XP和2003rver上,DEP行为可以通过boot.ini的参数来改变。只要简单地在这行的
(这里“policy”可以是OptIn,OptOut,AlwaysOn或者AlwaysOff)
在Vista/Windows2008/Windows7,你能用bcdedit命令来改变设置:
你可以通过运行“bcdedit”来得到目前的状态然后看下nx的值
一些关于硬件DEP的链接:
●/kb/875352
●en.wikipedia/wiki/Data_Execution_Prevention
●/en-us/library/aa366553(VS.85).aspx
绕过DEP--构建模块
正如在介绍中陈述的,当硬件DEP启用时,你不能只是跳到你的在栈上的shellcode,因为它不会执行。相反,它将会触发一个访问违例并且很可能会结束进程。
在那个的顶部,每个特殊的DEP设置(OptIn,OptOut,AlwaysOn,AlwaysOff)和永久的DEP 的影响(或者缺席)将需要一个特殊的方法和技术。
因此,我们的选择是什么?
好的,由于我们不能在栈上执行我们自己的代码,我们唯一能做的事是从已经加载的模块中执行现有的指令/调用现有的函数,然后用栈上的数据作为这些函数/指令的参数。
这些现有的函数会提供给我们这些选择
●执行命令(举个例子,WinExec-典型的“ret-to-libc)
●将包含你的shellcode的页面(例如栈)标记为可执行(如果可以通过主动的DEP策略来使它运行执行)然后跳到那里
●将数据拷贝到可执行区域然后跳到那里(我们可能要分配内存然后首先将那个区域标记为可执行)
●在运行shellcode之前改变当前进程的DEP设置
当前的主动的DEP策略和设置将几乎支配你不得不在某些情况下用来绕过DEP的技术。
一个需要一直有效的技术是典型的“ret-to-libc”。你需要能够执行简单的命令,用现有的Windows API调用(如WinExec),但是用这个很难精巧地制作“真正的”shellcode。
因此我们要看得远点。我们真的需要绕过/推翻/改变DEP设置然后使我们的自定义shellcode运行。幸运地,标记页面可执行/改变DEP策略设置/等等都能通过Windows OS 的native API/函数调用。
因此,这很简单吧?
是也不是。
当我们要绕过DEP,我们要调用一个Windows API(我将会在后面更进一步描述这些Windows API的细节)。
那个API的参数必须在寄存器或者栈中。为了将这些参数放在它们应该在的地方,我们很可能要写一些自定义代码。
想想。
如果给定的API函数的一个参数比如是shellcode的地址,那么你不得不动态产生/计算这个地址,然后将它放在栈上的正确位置。你不能硬编码,因为这将会不可靠(或者,如果缓
冲区不能处理null字节并且其中的一个参数需要null字节,那么你就不能再你的缓冲区里硬编码那个值)。用一些短小的shellcode来产生值也不能成功,因为...DEP启用。
问题:我们如何得到栈上的这些参数
回答:用自定义代码
在栈上的自定义代码,无论如何,是不能执行的,DEP会阻止那个发生。
不相信我?那我们来试下在教程1里的那个老而好的Easy RM to MP3Convertor exploit。没有DEP(OptIn)
有DEP(OptOut)自古英雄出少年
或者,在调试器中可以看到的(启用DEP-OptOut),就在shellcode的第一条指令将要执行(就在jump esp的后面):Movie