上篇给大家介绍关于Windows上地址空间布局随机化防御机制的分析(上),这篇文章介绍了在Windows上实施的地址空间布局随机化的一些历史,并探讨了Windows实施的一些功能和局限性。
将32位程序重新编译为64位程序,以使地址空间布局随机化更有效
尽管Windows的64位版本已经成为主流十多年了,但32位版本的使用者仍然很多。有些程序确实需要保持与第三方插件的兼容性,比如web浏览器。有时,开发团队认为程序所需的内存远远少于4 GB,因此32位代码可以节省空间。甚至Visual Studio在支持构建64位应用程序之后,在一段时间内还仍然支持32位应用程序。
实际上,从32位代码切换到64位代码会产生很小但可观察到的安全性好处。原因是随机化32位地址的能力是有限的。至于具体原因,请观察图1中32位x86内存地址的分解方式。更多详细信息,请参见“物理地址扩展”。
内存地址分为多个组件,其中只有一些可以在运行时轻松随机化
操作系统不能简单地将地址的任意位随机化,在页面部分(0到11位)中随机分配偏移量将打破程序对数据对齐的假设。页面目录指针(位30和31)也不能被更改,因为第31位是为内核保留的,而第30位被物理地址扩展用作存储体交换技术,以寻址2 GB以上的RAM,这使得32位地址中的14位不能被随机化。
实际上,Windows只尝试随机化32位地址中的8位。这些是位从16到23,只影响地址的页目录条目和页表条目部分。因此,在暴力情况下,攻击者可能仅用256次猜测就能猜出EXE的基本地址。
将ASLR应用于64位二进制文件时,Windows能够随机分配地址的17-19位(具体取决于它是DLL还是EXE)。图2显示了对于64位代码,可能的基址数量以及相应的暴力猜测数量如何显着增加,这可以使端点保护程序或系统管理员可以在攻击发生之前检测出攻击。
将32位代码重新编译为64位会大大增加可供地址空间布局随机化选择的基本地址数量
总结起来就是:
1. 必须处理不可信数据的软件应该始终编译为64位,即使它不需要使用大量内存,也可以充分利用地址空间布局随机化。
在暴力攻击中,地址空间布局随机化使攻击64位程序的难度比攻击完全相同程序的32位版本的难度至少高了512倍。
2. 即使是64位ASLR也会受到暴力攻击,防御者必须集中精力检测暴力攻击,或者避免出现暴力攻击可行的情况。
假设攻击者每秒可以对一个脆弱的系统进行十次暴力尝试。在通常的情况下,由于多个实例正在运行,目标进程保留在同一地址,攻击者会在不到一分钟的时间内发现32位程序的基地址,而在数小时内就会发现64位程序的基地址。64位暴力攻击会产生更多的干扰,但是管理员或安全软件需要注意并采取行动。除了使用64位程序来提高地址空间布局随机化的效率外,系统还应避免重新生成崩溃程序,以避免让攻击者发现基址,为了以防万一最好强制重新启动,因此应保证进程崩溃后多次刷新地址空间。
3. 针对32位和64位版本的程序开发概念验证攻击的研究人员应首先关注32位,只要32位程序仍然有效,针对程序的32位变体的概念验证攻击就可能更容易开发。由此产生的攻击可能更可行且更有说服力,从而导致供应商更快地修补程序。
Windows 10会比Windows 7更频繁地重用随机基址,这在某些情况下可能会使它变得容易受到攻击
请注意,即使Windows系统必须确保一个DLL或EXE的多个实例都在相同的基址加载,系统也不需要在卸载DLL或EXE的最后一个实例时跟踪基址。如果DLL或EXE再次被加载,它可以获得一个新的基地址,这是我们在使用Windows 7时观察到的行为。Windows 10可以以不同的方式工作,即使在DLL或EXE的最后一个实例被卸载后,它也可能至少在短时间内保持相同的基址,与DLL相比,EXE更是如此。在多进程调试器下重复启动命令行程序时,可以观察到这一点。但是,如果将该程序复制到新文件名然后启动,它将收到一个新的基地址。同样,如果经过了足够长的时间,该程序将加载到其他基址。当然,重新启动会为所有DLL和EXE生成新的基地址。
总结起来就是:除了每次启动随机化外,不要对Windows ASLR保证做任何假设。特别是,每当加载给定EXE或DLL的第一个实例时,不要依赖Windows 7的行为来随机分配新的地址空间。不要以为Windows天生就能以任何方式防止针对地址空间布局随机化的暴力攻击,特别是对于32位进程,在这种情况下,暴力攻击可能需要256次或更少的猜测。
Windows 10对地址空间布局随机化的利用更加积极,甚至对不与地址空间布局随机化兼容的exe和dll也能进行有效防护,这可能使地址空间布局随机化的应用范围更大
Windows Vista和Windows 7是最早支持地址空间布局随机化的系统,因此地址空间布局随机化在设计之初在兼容性方面进行了一些权衡。具体来说,这些旧的实现不会将地址空间布局随机化应用于没有标记为与地址空间布局随机化兼容的映像,也不允许地址空间布局随机化将地址推送到4 GB边界以外。如果一个映像没有选择加入地址空间布局随机化,这些Windows版本将继续使用首选的基本地址。
可以使用Microsoft的增强缓解经验工具包(通常称为EMET)进一步强化Windows 7,以更积极地将地址空间布局随机化应用于甚至未标记为与它兼容的映像。 Windows 8引入了更多功能,可将ASLR应用于不兼容地址空间布局随机化的映像,以更好地使堆分配随机化,并增加64位映像的熵位数。
总结起来就是:
1. 确保程序项目使用正确的链接器标记来选择最积极的地址空间布局随机化实现,并且不使用任何削弱地址空间布局随机化的链接器标记。
如下表所示,链接器标记可能会影响地址空间布局随机化应用到映像的方式。请注意,对于Visual Studio 2012及更高版本,“+”标记在默认情况下已经启用,并且只要不使用“-”标记,就会使用最佳的地址空间布局随机化实现。使用Visual Studio 2010或更早版本(可能是出于兼容性原因)的开发人员需要检查链接器支持的标记,以及默认情况下启用的标记。
链接器标记可能会影响如何将ASLR应用到映像
2. 启用强制性地址空间布局随机化和自下而上的随机化,Windows 8和Windows 10包含一些可选的功能,可在未标记为与地址空间布局随机化兼容的映像上强制被启用,并随机分配虚拟内存分配,以便重新建立基础的映像来获得随机基址。当EXE与ASLR兼容,但它使用的某个dll不兼容时,这是很有用的。防御者应该使这些特性能够更广泛地应用地址空间布局随机化,而且重要的是,它有助于发现任何剩余的不兼容地址空间布局随机化的程序,以便可以对其进行升级或替换。
ASLR将整个可执行映像重新定位为一个单元
ASLR通过选择一个随机偏移量来重定位可执行映像,并将其应用于映像中与它的基本地址相关的所有地址。也意味着:如果EXE中的两个函数位于地址0x401000和0x401100,那么即使在重新定位映像之后,它们之间仍然保持0x100字节的距离。很明显,这很重要,因为x86代码中普遍存在相对调用和jmp指令。同样,无论位于何处,位于0x401000处的函数将与映像的基本地址保持0x1000字节的距离。同样,如果两个静态变量或全局变量在映像中相邻,则在应用地址空间布局随机化后它们仍将保持相邻。相反,堆栈和堆变量以及内存映射文件不是映像的一部分,可以随意随机分配,而不需要考虑选择的基址。
总结起来就是:
1. 可执行映像中仅一个指针的泄漏就可以暴露整个映像的随机地址。
ASLR最大的限制和烦人之处在于,一些看似无害的特性,如调试日志消息或堆栈跟踪会泄漏映像中的指针,从而成为漏洞。如果攻击者拥有相同程序或DLL的副本,并且可以触发它产生相同的泄漏,那么他们可以计算地址空间布局随机化和地址空间布局随机化之前指针之间的差异来确定随机化前后的偏移量。然后,攻击者可以将该偏移量应用到其攻击有效载荷中的每个指针,以绕过地址空间布局随机化。防御者应该培训软件开发人员关于指针暴露漏洞的知识,以便他们认识到这个漏洞的严重性,并且作为软件开发生命周期的一部分,定期评估软件的这些漏洞。
2. 某些类型的内存损坏漏洞超出了ASLR能够保护的范围。
并不是所有的内存损坏漏洞都需要直接实现远程代码执行,比如有这样一个程序,它包含一个缓冲区变量,用于从网络中接收不可信的数据,以及一个标记变量,该变量位于其后的内存中。标记变量包含一些位,这些位指定用户是否已登录以及该用户是否为管理员。如果程序在接收缓冲区的末尾写入数据,则“标记变量将被覆盖,攻击者可以同时设置已登录和is-admin标记。由于攻击者无需知道或写入任何内存地址,因此地址空间布局随机化不会阻止攻击。只有当另一种强化技术(如编译器强化标志)重新排序变量,或者更好地使变量在程序中的位置独立移动时,此类攻击才会被阻止。
总结
地址空间布局随机化是针对内存破坏漏洞的核心防御措施,这篇文章介绍了在Windows上实施的地址空间布局随机化的一些历史,并探讨了Windows实施的一些功能和局限性。通过阅读这篇文章,防御者可以熟知如何构建程序来更好地利用地址空间布局随机化和Windows中提供的其他功能。不过地址空间布局随机化的防御机制也不是完美的,攻击者可以利用地址空间布局随机化的限制,例如只在每次重启时应用地址空间随机化和将整个映像重新定位为一个单元随机化,从而使用暴力和指针泄漏攻击来绕过地址空间随机化的防护。
本文翻
转载请注明:IT运维空间 » 安全防护 » 关于Windows上地址空间布局随机化防御机制的分析(下)
发表评论