软件防御:缓解堆损坏漏洞 | MSRC博客
安全研究与防御团队
作者: swiat / 2013年10月29日 / 11分钟阅读
堆损坏漏洞是微软目前通过安全更新解决的最常见漏洞类型。这些漏洞通常由编程错误导致,使得攻击者能够越界写入堆缓冲区(空间问题)或将堆分配对象置于意外状态(如释放后使用,时间问题)。随着时间的推移,攻击者已开发出多种技术来利用各类堆损坏漏洞。
自Windows XP Service Pack 2起,微软开始引入对Windows堆管理器的加固更改,旨在提高利用堆损坏漏洞的难度。本文将回顾一些用于利用和缓解堆损坏漏洞的通用方法,并重点介绍Windows 8和Windows 8.1中为进一步复杂化利用而实施的加固更改。
堆损坏利用的今昔对比
在之前的博客文章中,我们涵盖了从Windows XP到Windows 7的基于堆的利用和缓解技术的历史。该文章显示,在Windows Vista之前,大多数关于堆损坏利用技术的研究集中在破坏堆元数据上,以实现更强大的利用原语(如将任意值写入内存中的任何位置)。攻击者专注于破坏堆元数据的原因之一是它始终存在,因此可以实现与应用无关(通用)的利用技术。
Windows Vista的发布通过大量堆加固更改改变了堆利用的格局,这些更改解决了当时已知的几乎所有堆元数据损坏利用技术。由于Windows Vista的加固更改,攻击者已将其重点转向依赖于破坏存储在堆上的应用特定数据的利用技术。例如,攻击者会尝试使用堆损坏漏洞来破坏堆上对象的C++虚拟表指针,或破坏堆分配数组的基址或长度字段,以实现读取或写入内存中任何位置的能力。
堆损坏缓解措施
Windows 8和Windows 8.1中的堆管理器在先前Windows版本的加固更改基础上,引入了新的安全特性,不仅缓解了元数据损坏技术,还缓解了依赖于破坏应用特定数据的较不通用技术。这些新安全特性可分为以下威胁类别:堆完整性检查、防护页和分配顺序随机化。Windows 8中引入的所有安全特性均已由Windows 8.1继承。
堆完整性检查
Windows 8和Windows 8.1中的堆管理器包括许多新的完整性检查,旨在检测堆元数据损坏并在检测到损坏时安全终止应用程序。本节描述了一些已添加的重要完整性检查。
-
移除全能异常处理块:先前版本的Windows堆在某些认为异常非致命的情况下使用全能异常处理块。这有可能使攻击者在某些情况下更容易利用堆损坏问题,特别是允许攻击者多次尝试攻击。因此,这些全能块已从Windows 8的堆中移除,意味着此类异常现在会导致应用程序安全终止。
-
HEAP句柄无法再释放:HEAP句柄是用于维护与给定堆关联状态的内部数据结构。在Windows 8之前,攻击者可以使用基于堆的内存损坏漏洞强制堆释放HEAP句柄数据结构。之后,攻击者可以强制堆重新分配先前存储HEAP句柄状态的内存。这反过来允许攻击者破坏内部堆元数据,包括某些函数指针字段。Windows 8堆通过防止HEAP句柄被释放来缓解此攻击。
-
HEAP CommitRoutine由全局密钥编码:HEAP句柄数据结构包括一个名为CommitRoutine的函数指针字段,当堆中的内存区域被提交时调用。从Windows Vista开始,该字段使用随机值编码,该随机值也作为字段存储在HEAP句柄数据结构中。虽然这缓解了仅对CommitRoutine函数指针的简单损坏,但并未缓解攻击者可以同时损坏CommitRoutine和存储编码密钥字段的情况。Windows 8堆通过使用全局密钥而非存储在HEAP句柄数据结构中的密钥来编码CommitRoutine函数指针,从而缓解此攻击。
-
扩展块头验证:Windows堆返回的每个堆分配都有一个头,描述分配的大小、标志和其他属性。在某些情况下,Windows堆可能将分配标记为具有扩展块头,这告知堆存在与分配关联的额外元数据。在先前版本的Windows中,攻击者可以破坏分配的头,使其看起来好像具有扩展块头。然后攻击者可以利用此强制堆释放程序当前正在使用的另一个分配。Windows 8堆通过对扩展块头执行额外验证以确保其正确性来缓解此攻击。
-
块若已忙则无法分配:安全研究人员提出的一些攻击依赖于重新分配程序已在使用的内存(例如[3])。这允许攻击者破坏使用中的堆分配状态,如C++对象,从而获得指令指针的控制权。Windows 8堆通过在即将分配时验证分配是否未被标记为使用中(“忙”)来缓解此攻击。如果块被标记为使用中,堆会采取措施安全终止进程。
-
编码的FirstAllocationOffset和BlockStride:[4]中提出的利用技术之一涉及破坏堆元数据(FirstAllocationOffset和BlockStride),这些元数据由低碎片堆(LFH)用于计算子段内分配的地址。通过破坏这些字段,攻击者可以欺骗堆返回子段边界之外的地址,并可能启用对其他使用中堆分配的损坏。Windows 8.1中的堆管理器通过编码FirstAllocationOffset和BlockStride字段来限制攻击者确定性控制LFH计算分配地址的能力,从而解决此攻击。
防护页
Windows 8堆更好地保护应用数据和堆元数据的方法之一是通过使用防护页。在此上下文中,防护页是不可访问的内存页,如果应用程序尝试读取或写入,将导致访问冲突。在堆内的某些类型的子区域之间放置防护页有助于分区堆并局部化可能发生的任何内存损坏。
在理想设置中,Windows堆将以类似于全页堆验证的方式将所有分配封装在防护页中。不幸的是,出于性能原因,这种类型的保护不可行。相反,Windows 8堆使用防护页来隔离堆内的某些类型的子区域。具体来说,为以下类型的子区域启用防护页:
- 大分配:当应用程序尝试分配大于512K(32位)或1MB(64位)的内存时,内存分配请求直接传递给虚拟内存分配器,并且大小更新为分配额外空间用于防护页。这确保所有大分配都有尾随防护页。
- 堆段:Windows堆分配大块内存,称为堆段,随着应用程序分配内存而划分。Windows 8堆在分配所有堆段时添加尾随防护页。
- 最大大小的子段:每个堆段可能包含一个或多个子段,由前端分配器(低碎片堆或LFH)用于分配相同大小的块。一旦达到给定大小块分配的某个阈值,LFH将开始分配最大大小的子段,这些子段包含给定大小可能的最大块数。Windows 8堆向最大大小的子段添加尾随防护页。对于32位应用程序,防护页以概率方式插入,以最小化消耗的虚拟地址空间量。
分配顺序随机化
攻击者在利用堆缓冲区溢出时依赖的行为之一是需要有一种可靠地将某些堆分配彼此相邻定位的方法。这一要求源于攻击者需要知道必须写入多少字节才能破坏堆上的目标分配(同时最小化对堆的附带损害,这可能导致应用程序及因此攻击终止)。攻击者通常尝试通过通常称为堆按摩或堆规范化的技术来确保分配立即彼此相邻。这些技术尝试将堆带入新分配相对于彼此放置在所需位置的状态。
在Windows 8中,向LFH添加了一项新的安全特性,随机化分配顺序。这意味着即使攻击者尝试规范化堆后,通过LFH进行的分配也不再保证立即彼此相邻放置。这具有防止攻击者可靠假设包含目标对象的分配将位于他们能够溢出的分配之后的效果。虽然攻击者可能尝试通过破坏更多数据或分配更多目标对象来提高攻击的可靠性,但他们冒着通过破坏其他堆状态 destabilize 进程或通过访问防护页导致进程终止的风险,如前一节所述。这是几个缓解措施协同工作的一个好例子:没有一个本身是万无一失的,但结合起来它们导致成功攻击的要求越来越复杂。
尽管分配顺序随机化有助于使堆的内部布局非确定性,但其效果有限。首先,Windows堆的性能至关重要,因为它被绝大多数在Windows上运行的应用程序用作通用内存分配器。作为此的副作用,分配顺序随机化目前仅限于随机化单个LFH子段内的分配(这占应用程序进行的大多数分配)。这意味着后端分配没有固有的熵,因此可能受到确定性分配模式的影响,如[5]所述。除了性能之外,分配顺序随机化的有效性也存在固有限制。如果攻击者可以读取堆内存的内容,他们可能能够克服随机化的影响。类似地,分配顺序随机化并非设计用于强烈缓解与对象生命周期问题相关的堆漏洞,如释放后使用漏洞。这是因为攻击者通常能够分配足够数量的替换对象以克服分配顺序随机化的影响。我们将在本系列后面讨论一些其他针对解决释放后使用问题的缓解措施,这些措施越来越受到利用编写者的青睐。
结论
Windows 8和Windows 8.1中对Windows堆管理器进行的加固更改旨在使利用堆损坏漏洞更加困难和昂贵。这是通过向堆使用的元数据添加额外完整性检查、通过使用防护页保护存储在堆上的应用数据以及通过随机化分配顺序来实现的。这些缓解措施并未使堆损坏漏洞无法利用,但它们确实对开发利用所需的时间以及利用的可靠性产生影响。这两个因素在决定攻击者是否会为漏洞开发利用方面发挥作用。话虽如此,堆损坏漏洞是我们通过安全更新解决的最常见漏洞类别,这一事实意味着我们未来可能会继续看到对堆漏洞新利用技术的额外研究。因此,我们将继续寻找方法来加固Windows堆,以进一步增加为堆损坏漏洞开发可靠利用的难度。
- Matt Miller
参考文献
[1] Ben Hawkes. Attacking the Vista Heap. Black Hat USA. Aug, 2008.
[2] Ben Hawkes. Attacking the Vista Heap. Ruxcon. Nov, 2008.
[3] Chris Valasek. Modern Heap Exploitation using the Low Fragmentation Heap. SyScan Taipei. Nov, 2011.
[4] Chris Valasek. Windows 8 Heap Internals. Black Hat USA. Aug, 2012.
[5] Zhenhua Liu. Advanced Heap Manipulation in Windows 8. Black Hat Europe, Mar, 2013.