[翻译]使用二进制比较发现Windows内核内存泄露bugs
翻译:https://googleprojectzero.blogspot.com/2017/10/using-binary-diffing-to-discover.html
补丁比较是比较相同代码的两次构建(一个已知有脆弱性,一个包含修补)的常用技术。通常通过该技术来发现措辞含糊的漏洞公告背后的技术细节,弄清漏洞根本原因、攻击代码和可能的攻击变种。近些年,该方法吸引了大量研究【1】【2】【3】,并且开发出了许多工具【4】【5】【6】,该方法在利用1-day漏洞攻击未及时打补丁用户上体现了价值。对于可以很容易地逆向的软件,已公布补丁的脆弱性被攻击者利用是不可避免的。
同样,若一个产品同时有多个版本在市面上,二进制比较也可以被用来发现它们之间的差异。比如Windows操作系统,当前微软还支持的版本有Windows 7、8和10。并且,当前Windows7在桌面市场仍然占有近50%的份额。微软对较新的版本引入和许多架构上的安全加固和补丁。这让旧版本系统的用户很不安全,使得他们可以被软件缺陷的脆弱性攻击,这些脆弱性可以简单地通过定位不同版本系统对应代码的微妙变化发现。
在后面的文章里,我们会展示如果通过二进制比较发现一个0-day例子,这是一个用户模式程序的未初始化内核内存泄露bug。这类bug在本地提权中很有用,也可以获取内核地址空间中存储的敏感数据。如果对这类bug不熟悉,我们建议你先看一下今年REcon和BlackHat上的演讲Bochspwn Reloaded【9】。
捕捉memset调用
大多数内核内存泄露发送的原因是将一大块内存区域复制到用户模式时内存未初始化,这块内存可能是结构、联合体、数组或它们的结合。发生这种情况意味着,内核向ring-3程序提供了比有效数据更多的内容,可能的原因是:被编译器插入的填充部分,未使用的结构/联合体,为可变长度内容提供的固定长度大数组。这类脆弱性的修复工作通常只是换一个小的内存空间,原来的代码行为被完全保留,并且还要加一个memset调用来初始化输出内存以保证它不包含无关的数据。这使得通过逆向工程识别这类补丁非常容易。
当对https://bugs.chromium.org/p/project-zero/issues/detail?id=1267&desc=2(Bochspwn发现的位于win32k!NtGdiGetGlyphOutline的Windows内核池内存泄露)进行粗略分析时,我意识到这个bug只在Windows7和8中存在,微软已经在Windows10中已经将其在内部修复。下图显示修复前后代码的不同,由Hex-Rays反编译,由Diaphora进行二进制比较:

Windows10中补丁的特征非常明显(在syscall的顶层处理过程中一个新的memset调用),我猜测在老版本内核中会有其它相似的问题在新版本中被微软默默修复。为了验证这个猜测,我决定在Windows7和Windows10中比较所有顶层syscall处理函数(如以Nt作为前缀的函数,位于内核和图形子系统中)中memset的数量,然后在Windows8.1和Windows10间进行一样的比较。原理上这是个非常简单地分析,一个很简单地分析方法就可以得到期望的结果,我决定在IDA反汇编产生的代码列表上执行比较。
执行比较时,我很快发现内核中的内存清0操作都被编译为三种模式的一种:
- 直接调用memset

- 使用rep stosd指向以内联的形式实现

- 一系列展开的mov指令

最常见的两种情况(memset和rep stosd)都被Hex-Rays反编译为对memset的调用。
不幸的是,使用一个被清0的寄存器执行一系列mov指令没有被Hex-Rays识别为调用memset,所幸这种情况很少,所以在后续人工处理误报前可以忽略。最终,为了容易些,我决定基于反编译后的.c文件进行代码比对而不是反汇编文件。
获得最后结果的完整操作步骤如下,我们分别对Windws7/10和Windoes8.1/10各执行一次:
- 使用Hex-Rays同时反编译Windows7和Windows8.1的ntkrnlpa.exe和win32k.sys为.c文件,对Windows10下的ntoskrnl.exe、tm.sys、win32kbase.sys、win32kfull.sys执行相同操作。
- 提取调用memset的内核函数列表(调用次数也考虑),按字母排序
- 对两个列表进行普通的字符比较,选出在Windows中调用memset次数更多的函数
- 过滤上一步的输出,只保留在旧版本(Windows7或Windows8.1)存在的函数。
最后得到的结果统计如下:
| ntoskrnl functio |
ntoskrnl syscall handlers | win32k function | win32k syscall handlers | |
| Windows 7 vs. 10 | 153 | 8 | 89 | 16 |
| Windows 8.1 vs. 10 | 127 | 5 | 67 | 11 |
注意:上传附件及图片大小不得大于30M。
⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途。
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。
