Windows内存安全保护机制
Windows内存安全保护机制
GS编译技术
-
早期的内存攻击方式主要以栈上的攻击为主,Windows操作系统为了针对栈溢出漏洞而引入一个对策——GS编译保护技术。
-
GS编译保护技术是通过编译时添加相关代码而实现的,在VisualStudio7.0及之后的版本中默认都开启了GS编译保护
-
在VisualStudio7.0及之后的版本中默认都开启了 GS编译保护
-
原理:
- 使用GS编译技术编译出来的程序,在每个函数的入口处和出口出都会额外添加一段代码,它是用于检测栈中内容
的随机值.
- 退出函数时检测该值是否被修改,若被修改则认为存在栈
溢出,否则认为没有发生栈溢出.
绕过技术简介
- 利用未被GS保护的内存模块
- 覆盖虚函数表
- 覆盖SHE
- 替换掉存在.data段中的cookie值
利用未被GS保护的内存模块
对于GS机制只有在缓冲区大小大于4字节的函数中才存在,那么攻击者就可以寻找缓冲区大小不大于4字节的函数,这些函数中本身就是没有使用GS编译技术来保护的,可以用来绕过GS编译技术
覆盖虚函数表
虚函数通过预设的一个虚函数指针变量来寻址,那么攻击者控制了这个指针后,就可以在函数调用的时候将程序跳转到攻击代码上
覆盖SHE
SEH句柄用于指向异常处理函数,这个句柄被存在SecurityCookie的上方,这使得攻击者不需要覆盖到SecurityCookie就可以修改SEH句柄指向的位置
替换掉存在.data段中的cookie值
将.data段的备份数据也同时改成用来覆盖SecurityCookie的值,那么就可以绕过检测
SEH安全校验机制
-
由上面所讲发现可以通过覆盖SEH的方法绕过GS编译的保护。所以WindowsXPSP2及后续版本的操作系统中,微软引入了一种SEH的安全校验机制——SafeSEH。
-
在VisualStudio2003及后续版本的开发环境中都默认启用了SafeSEH机制
-
原理
在编译过程中创建一个SafeSEH表SafeSEH主要检测用于处理SEH的句柄函数是否处在之前创建好的SafeSEH表中,从而判断调用的句柄函数的地址是否安全。
绕过方式简介
-
利用未启用SafeSEH的模块进行绕过
攻击者可以通过寻找程序中加载的未启用SafeSEH技术的模块来绕过它
-
利用加载内存模块外的地址进行绕过
一个程序被加载的时候,内存中除了常见的exe和dll模块以外,还会存在一些其他的映射文件,而当异常处理函数指针指向这些地址时,是不会进行有效性验证的,如果攻击者从这些空间中可以找到一些类似jmp esp这样的跳转指令,就可以简单控制程序流程
-
覆盖虚函数表
同前
-
利用堆地址覆盖SEH SafeSEH允许其异常处理句柄位于除栈空间之外的非映像页面。攻击者可以利用这一点,将shellcode写在堆空间中 ,再覆盖SEH链表的地址。使程序异常处理句柄指向堆空间,就可以绕过SafeSEH的检测了
SEH覆盖保护(SEHOP)
-
之前提到的针对SEH的攻击方式,攻击者将其中一个SEH结构中的异常处理函数地址,覆盖为攻击代码的地址,再使程序发生异常,从而执行攻击代码为了进一步保护SEH的安全,windows操作系统又提出了新的机制——SEHOP
-
原理 在需要处理SHE请求时进行如下检测:
1.所有SEH结构体必须存在栈上
2. 所有SEH结构体必须四字节对齐
3.所有SEH结构体中处理异常的函数必须不在栈上
4.检测整个SEH链中最后一个结构体,其next指针必须指向0xffffffff,且其异常处理函数必须是
ntdll!FinalExceptionHandler
5.攻击者将SEH指针劫持到堆空间中运行shellcode。
6.有了SEHOP机制以后,由于ASLR的存在,攻击者很难将伪造的SEH链表的最后一个节点指到
ntdll!FinalExceptionHandler上所以在检测最后一个节点的时候会被SEHOP机制发现异常
利用方式简介
-
攻击返回地址
这种攻击方式与SafeSEH部分原理类似,在程序存在SEHOP机制时绕开SHE,对返回地址进行常规攻击。
-
攻击虚函数 利用未启用SEHOP的模块进行绕过伪造SEH链表事实上绕过SEHOP机制最重要的一环就是将伪造的SEH链表的末尾句柄指向FinalExceptionHandler函数。但这种攻击方式有一个非常重要的前提就是程序不能开启ASLR机制。不然攻击者将无法或很难获得FinalExceptionHandler的真实地址。
数据执行保护(DEP)
-
程序在运行的过程中,数据和代码是同时存放在内存中的。程序运行过程中通过RIB寄存器(64位)来访问代码,通过RSP/RBP等寄存器来访问数据。寄存器本身并不知道它自己所存放的数据要被当作代码来执行还是被当作数据来读写攻击者将rip劫持到栈上,它也会将栈上的内容按照代码来执行
-
原理
去掉用于存储数据的内存页的执行权限来防止数据被作为代码执行
绕过方式简介
-
利用ret2libc绕过DEP
ret2libc是returntolibc的缩写,其中libc是操作系统中提供的c语言的函数库。
ret2libc是一种通过retn指令在库函数中寻找可用代码的攻击方式。由于其所有代码都是从libc中找到的,所以不存在不可执行的问题
-
利用可写可执行内存绕过DEP
有些程序可能由于配置的问题或者其他原因,在进程中存在可读可写可执行的区域。比如一些简单的加壳程序,程序在编译时将代码进行加密,在运行时解密.这也导致程序需要对这些存放加密程序的代码段开放写权限,以便自身对其进行解压。如果攻击者可以将shellcode写入这部分空间中并劫持流程,就可以绕过DEP。
加载地址随机化(ASLR)
几乎所有的漏洞利用方法都需要有明确的地址作为跳转的目的地。 针对这种现象,windows操作系统提出了加载地址随机化技术,即在为程序赋予虚拟地址的时候不再 使用固定的地址,而是使用随机的基址。
-
原理
在进行虚拟地址的映射时,选用随机的基址
攻击未启用ASLR的模块
-
利用部分覆盖进行定位内存地址绕过ASLR地址随机化也并不是完全的随机化
64位的操作系统,前32bit是固定不变的,后16bit也是固定不变的。只有第33bit到第48bit会随机变化,即对于一个地址0x123456789abcdef0,只有0x9abc这一段地址会发生改变。那么对于攻击者,如果在修改地址的时候只修改最后的16bit,攻击者在最后16bit变化的地址中寻找可用的shellcode,从而绕过ASLR。
-
利用HeapSpray技术定位内存地址
HeapSpray攻击技术要求攻击者能够控制单次申请的堆块的大小,所以基本上只有在支持动态语言脚本(如JavaScript,ActionScript等)的程序中才能使用HeapSpray技术。
堆喷射要通过申请一个很大的堆空间来存放shellcode,这段内存的大小通常在200M左右。为了增加shellcode被命中的概率,通常攻击者都会在shellcode前填充大量的无意义代码,这些代码被称为SlideCode。SlideCode通常会使用0x0c0c
0x0c0c0c0c这个地址的位置大约在192M左右,这也就是前面提到的申请200M左右内存的原因。
0x0c0c这条指令对应的汇编指令是or al,0ch。这条指令与0x90的NOP指令类似,在的执行不会对程序产生影响攻击者将某个类变量的虚表指针指向0x0c0c0c0c以后,这个类进行任何的函数调用都会跳转到0x0c0c0c0c
控制防护流(CFG)
-
控制流防护是从windows8.1update 3及以上版本中开始默认启用的一种安全机制
-
在Windows中,会用到call eax这类指令。攻击者可以通过篡改寄存器eax的值来修改指令流
-
原理
在编译过程中,编译器将间接函数调用的目的地址保存在GuardCFFunction Table中。在执行间接调用函数之前,会检查跳转的这些地址是否存在于表里,使系统函数中的这些间接调用指令不会被攻击者利用。
利用方式简介
- 修改检测函数指针(GOT表)
- 在最新版本windows中,加入了一个新的保护机制,用来检测该指针指向的地址,从而导致该种利用方式失效了