OD: Protection for Heap in Windows

微软在堆中也增加了一些安全校验操作,使得原本是不容易的堆溢出变得困难重重:

* PEB Random:在 Windows XP SP2 之后,微软不再使用固定的 PEB 基址 0x7FFDF000,而是使用具有一定随机性的基址,从而影响了 DWORD SHOOT 对 PEB 中函数的攻击。

* Safe Unlink:微软改写了操作双向链表的代码,在卸载 free list 中的堆块时更加小心。SP2 在进行删除操作时,提前验证堆块的完整性,以防止 DWORD SHOOT:

 1 int safe_remove(ListNode * node)
 2 {
 3         if( (node->blink->flink==node)&&(node->flink->blink==node) )
 4         {
 5             node -> blink -> flink = node -> flink;
 6             node -> flink -> blink = node -> blink;
 7             return 1;
 8         } else {
 9             // raise exception
10             return 0;
11         }
12 }

* Heap Cookie:与栈中类似,堆中也引入了 cookie,用于检测堆溢出的发生。cookie 布置在堆首中原堆块的 segment table 的位置,占 1 字节:

OD: Protection for Heap in Windows

* 元数据加密:Windows Vista 及后续版本的系统中开始使用这项措施。块首中的一些重要数据在保存时会与一个 4 字节的随机数进行异或加密,使用时再异或解密。这样就不能直接破坏这些数据了。

堆的研究者之一 Matt Conover 在 CanSecWest 04 的演讲议题 Windows Heap Exploitation (Win2K SP0 through WinXP SP2) 中,针对 PEB random 机制,指出变动只是在 0x7FFDF000 ~ 0x7FFD4000 之间,随机区间不大,在多线程状态下容易被预测出来。

而 Heap Cookie 只占 1 字节,在研究其生成随机的算法之后仍存在破解可能。

对于 Safe Unlink 也有人找到了一些破解思路。

但这些突破的思路要在 XP SP2 之后成功实施并利用,需要十分苛刻的条件,堆溢出变得难如登天。

 

溢出堆中的数据

但堆保护措施是对堆的各个关键数据结构进行保护,对堆中的数据不提供保护,所以攻击的第一个思路,是溢出堆中存放的关键数据结构:重要变量、数据、函数指针…

 

利用 chunk 重设大小攻击堆

Safe Unlink 是从 FreeList[n] 上拆卸 chunk 时对双向链表进行验证,但是,将一个 chunk 插入到 FreeList[n] 时没有进行校验!如果能伪造一个 chunk 并将其插入到 FreeList[n] 上就可以造成某种攻击。如下两种情况会发生插入操作:

1  内存释放后 chunk 不再被使用时。
2  当 chunk 的内存空间大于申请的大小,剩余的空间会被建成一个新的 chunk 链入链表中。

上述第二种情况提供了可以利用的机会。先考虑申请 chunk 的过程,从 FreeList[] 上申请空间的过程如下:

1  将 FreeList[0] 上最后一个 chunk 与申请的大小进行比较,如果 chunk 的大小 ≥ 申请的大小,则继续分派,否则扩展空间(若超大堆块链表无法满足分配,则扩展堆)
2  从 FreeList[0] 的第一个 chunk 依次检测,直到找到第一个符合要求的 chunk,然后卸载
3  分配好空间后,如果 chunk 有剩余空间,剩余空间会建成新的 chunk 并插入到链表中

这个过程中,第一各情况没有机会,第二种情况有 Safe Unlink 进行保护。但 Safe Unlink 存在一个问题:即使 Safe Unlink 检测到 chunk 结构被破坏,还是会允许后续的一些操作,如重设 chunk 大小。

OD: Protection for Heap in Windows

上一篇:C#中如何判断一个字符是汉字


下一篇:【YBTOJ】【POJ 1821】Fence