以前堆栈溢出在的WINDOWS系统中一直都是安全问题的核心,其中覆盖seh的技术早为人熟知。Safeseh是一项保护和检测和防止堆栈中的seh被覆盖而导致利用的技术。
Safeseh是VISTA的新技术吗?
Safeseh并不是VISTA的新技术,Safeseh是xp sp2就已经引入的技术。但是由于Safeseh需要.net的编译器编译的image才支持,而xp sp2系统自身所带的库和执行程序都是非.net的编译器编译的,所以使得Safeseh在xp sp2上只能成为聋子的耳朵,xp sp2下,堆栈溢出只要覆盖seh的地址就能轻松饶过所有的保护机制。因此在xp sp2时代,关于Safeseh的研究从来不被重视,甚至对他的机理研究都存在很多错误,认为Safeseh只是屏蔽了数据段的地址,只要是库函数空间地 址就是被许可的,一些Safeseh的操作被误解读成函数地址保护的操作。
为什么VISTA下Safeseh才开始发威VISTA自身带的系统库。
程序99%以上是用.net的编译器编译的,.net的编译器默认编译时候就会在 IMAGE里产生对Safeseh的支持。因此VISTA下的应用加载的系统库几乎全是带有Safeseh支持的IMAGE,堆栈溢出发生时覆盖这些支持 Safeseh模块的SEH都能被检查出来,使得覆盖堆栈中的SEH地址的技术不再可用。
Safeseh的实现过程
Safeseh本身的原理很简单,就是在编译器生成二进制IMAGE的时候,把所有合法的SEH函数的地址解析出来,在IMAGE里生成一张合法的SEH函数表,用于异常处理时候进行严格的匹配检查。基本过程如下(XP SP2和VISTA一样):
加载过程:加载IMAGE时,定位和读出合法SEH函数表的地址(如果该IMAGE是不支持Safeseh的,则这个SEH函数表的地址为0),使用shareuser内存中的一个随机数加密。
将加密的SEH函数表的加密地址,IMAGE的开始地址,IMAGE的长度,合法SEH函数的个数 作为一条记录放入ntdll的加载模块数据内存中。
异常处理过程:
根据堆栈中SEH的地址,确认是否属于一个IMAGE的地址空间。
如果属于
读取ntdll的加载模块数据内存对应的“SEH函数表的加密地址,IMAGE的开始地址,IMAGE的长度,合法SEH函数的个数"记录 读出shareuser内存中的一个随机数,解密SEH函数表的加密地址,读出真实的SEH函数表地址。
如果该地址不为0,代表该IMAGE支持Safeseh根据合法SEH函数的个数,依次计算合法合法SEH函数的地址并和当前SEH地址进行比较,如果符合执行SEH函数,如果全不符合则不执行当前SEH指定的地址,跳出不执行。
如果该地址为0,代表该IMAGE不支持Safeseh,只要该内存属于该IMAGE.code范围内的代码都可以执行。
如果不属于
检测该地址的内存特征。一般属于内核空间的未加载用户数据地址可以执行(但是其实等效于无法执行的,这块不可能加载用户数据,可能是MS为了迷惑一些研究者吧,看见代码能跳转到如0xcccccccc地址上,以为能饶过Safeseh。)
VISTA下的Safeseh的安全性
Safeseh是非常强悍的,如果一个进程加载的所有模块都是支持Safeseh的 image,覆盖seh获得利用就根本不可能。至少VISTA下99%的系统库是支持Safeseh的image。而xp sp2 99%的系统库是不支持Safeseh的image,因此Safeseh虽然是xp sp2就开始使用的技术,但应该算是在VISTA下才开始发挥作用的技术。当然如果进程存在一个不支持Safeseh的IMAGE就等于整个 Safeseh的机制失效,不过由于VISTA下支持进程空间随机技术,可以深层抵御这种情况下的seh覆盖利用。
当然一个思路是:是否可以通过覆盖shareuser内存中的随机数字和ntdll的SEH函数表的加密地址使得计算出来的SEH函数表的地址为0饶过Safeseh的保护。不过这很困难,因为要达到这个目的除非存在下面的情况:
情况A:知道shareuser内存中加密随机数,并能修改SEH加密地址,则需要知道ntdll加载的地址(随每次启动不同),且能通过漏洞获取shareuser内存中加密随机数,通过计算获得为0的加密地址再写入到SEH加密地址中。
情况B:知道SEH加密地址的数值,并能修改shareuser内存中加密随机数,则需要知道ntdll加载的地址(随每次启动不同),且能通过漏洞获取SEH加密地址的数字,通过计算获得为0的加密KEY,再写入到shareuser内存中。
情况C:需要知道ntdll加载的地址,并能够改写修改SEH加密地址和shareuser内存中加密随机数。以上3种情况都需要特定的复合条件,很难具备。
可能的问题
依然存在着一些可能的问题。
第一就是支持Safeseh需要.net的编译器支持,且程序所有加载的IMAGE都需要支持Safeseh,否则容易导致失效【www.hitidc.com】,但依然有大量的第三方程序和库不是使用.net编译的。
第二就是我使用的.net 2003只对c++的windows应用的默认编译中就支持Safeseh安全特性,在.net的应用编译中,对于运行时生成的托管代码,即使打开安全选 项也不会支持一些安全特性,不知道.net 2005或者MS是否有最新的支持VISTA的.net出来。