之前我们一直在Linux平台上分析漏洞,那是因为对于绝大多数Hacker获得一个Linux平台更加容易,而且主流的服务器系统基本也都是Linux/Unix的;另外一个好处就是Linux提供了用户自定义的强大功能,我们可以根据需要编译汇编程序代码,关闭相应的安全保护机制,便于我们的研究学习。
然而现实中有影响力的漏洞大多是基于Windows系统,因此这节我们来介绍下Winodws系统上是安全保护机制,至于Windows上的漏洞分析,我们会在之后的恶意代码分析章节继续介绍。
理解SEH
Windows系统内存保护
Windows系统内存保护机制绕过简介
一般来说,触发漏洞会导致程序的崩溃,Windows中引入了SEH(Structured Exception Hadnling),即结构化异常处理机制,这种机制在源代码中一般是通过Try-Exception来实现的,比如像下面:
int main()
{
_try {
//可能出现异常崩溃的代码
}
_except(EXCEPTION_EXECUTE_HANDLER) {
//异常处理程序
}
return 0;
}
这种SEH结构在运行中主要通过添加一个EXCEPTION_REGISTRATION结构来实现,这个结构有两个成员:
prev:用于指向下一个SEH记录的指针;
handler:指向实际处理程序代码的指针;
其实Windows在原始的程序栈前面添加了一个异常处理结构,该结构由一系列的异常处理链表组成,这条链表的起始点总是放在TIB(Thread Information Block)的第一个成员中,在x86计算机中存储在FS:[0]寄存器中。链表的最后总是默认处理程序,这个默认处理程序的指针总是0xFFFFFFFF。具体结构如下图:
如果想全面探讨Windows下的安全保护机制,一定需要很大的篇幅,在这里我们仅对重要的做一个介绍,以起到抛砖引玉之用,感兴趣的朋友可以继续查询更多资料。
我们首先来介绍基于栈的缓冲区溢出检测(GS)的实现,这个机制的本质思想是在缓冲区溢出导致的覆盖位置设置一个标签值,该值具体位于所保存的EBP和RETN(EIP)地址的上方,当从函数返回时会检查这个标签值,看其是否被修改。由于其位于EBP上方,因此一档该值修改,则可以判定RETN也被修改,即发生了缓冲区溢出攻击。新的函数开场白如下:
push ebp
mov ebp, esp
sub esp, 24h ;这三步同正常的开场白一致
move ax, dword ptr [vuln!_security_cookie]
xor eax, ebp ;xor cookie with ebp
mov dword ptr [ebp - 4]
而对应的函数收场白也添加了cookie值的验证:
mov ecx, dword ptr [ebp - 4]
xor ecx, ebp ;if cookie or ebp changed
call vuln!_security_check_cookie(004012e8)
leave
ret
其实就是将安全cookie同ebp进行异或运算后存放在栈上,然后函数返回的时候取出安全cookie,再次与ebp进行异或测试是否同系统值匹配。一种改进是在这个基础上添加了一份参数副本,从而使得原始函数参数即使被覆盖也没用,具体结构如下:
SafeSEH主要是对SEH结构的保护机制,防止覆盖和使用存储在栈上的SEH结构。在触发异常时SafeSEH会进行以下几项检查:
确保异常记录位于当前线程的栈上;
确保处理程序指针没有回指栈;
确保处理程序已经在授权处理程序列表中登记;
确保处理程序位于可执行的内存映像中;
传统的堆漏洞攻击会覆盖对块首部,并视图创建一个伪造的块,当内存释放例程执行时可以使用该块在任意内存地址处写入任意4个字节。具体为:
安全移除:在进行移除前,操作系统会验证向前和向后指针指向的相同的块;
堆元数据cookie:在堆块首部存储一个1字节的cookie,当从空闲列表中移除之前先检查该值。Vista中在几个关键首部字段增加了XOR加密措施,并在使用前进行检查,以防止篡改。
DEP(Data Execution Prevention),即数据执行保护,阻止存放在堆、栈或数据内存中的代码执行,这一直以来都是安全操作系统设计的目标。2004年AMD在其CPU中提供了NX位,首次允许硬件识别内存页是否可执行并采取相应措施。Intel后来推出来了XD功能,实现了类似的功能。
ASLR(Address Space Layout Randomization),即地址空间随机化,思想时在进程使用的内存地址引入随机性,这样会使得攻击变得更加艰难。一些随机化有:
可执行映像采取255个随机位置之一;
DLL映像中,ntdll.dll随机加载到256个随机位置之一,然后其他的DLL文件随机加载到另一个随机位置;
栈:比其他内存区更加随机化;
堆:基本堆结构位于32个随机位置之一;
PEB(Process Enviroment Block,进程环境块)/TEB(Thread Enviroment Block,线程环境块)
但是应该注意到,由于Windows系统64KB内存页的限制,因此内存地址随机化时其中一些内存区的熵值较小,即随机化空间不大,因此可以利用蛮力破解。
安全的攻防总是一种竞赛的态势,交替发展。这部分我们来简要介绍下Windows下的保护绕过机制,重点是GS和ASLR的一些思路,主要在于启发大家的思路,网上有着更加 丰富的资料。
直接来介绍几种可能的思路:
猜测cookie值:由于GS保护机制使用了几个较弱的cookie源,因此攻击者可以对它们进行计算并进行预测\猜测cookie值,这种方式适合应用在本地系统攻击中;
覆盖调用函数指针:通过调用虚函数时调用方函数会讲对象或结构放在栈上,因此如果能够覆盖虚函数的vtable,然后创建伪造的vtable,那么就可以重定向虚函数并获得代码执行;
替换cookie:由于cookie的值写在.data区,而这个区是可写的,因此如果有任意内存写入权限,那么就可以覆盖该值;
覆盖SEH记录:GS机制并没有保护SEH,因此如果能够写入足够的数据覆盖SEH,并在函数收场白检查cookie之前触发异常,将执行流程导向SEH,那么就可以控制程序的执行。
绕开ASLR的最简单方式就是返回到那些没有链接ASLR保护机制的模块中,可以使用pvefindaddr工具的noasir选项列出所有没有链接ASLR的模块,比如MSVCR71.dll模块就没有受到ASLR的保护,我们可以返回到该模块。
** Refer: Gray Hat Hacking: The Ethical Hacker's Handbook, Third Edition **