【漏洞分析】CVE-2017-0283:Windows Uniscribe远程代码执行漏洞分析

https://p1.ssl.qhimg.com/t012fe2507b16e374a0.png

译者:myswsun

预估稿费:130RMB

投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿


0x00 前言

上个“补丁星期二”,修复了一个名为“USP10!MergeLigRecords中的Windows Uniscrible 字体处理堆破环”的RCE漏洞。多天后,谷歌Project Zero团队的Mateusz Jurczyk发布了一个带有PoC的报告。在那个Windows库中同时存在了8个漏洞中,我选了这个最严重的漏洞来分析。


0x01 重现

在Windows字体查看器中打开压缩包Poc.zip中的字体文件,显示"quick brown fox text" ,但是没有崩溃。我是在Windows 7 x64中测试:

1. 解压PoC

2. 在系统中安装signal_sigsegv_313372b5_210_42111ccffd2e10aba8b5e6ba45289ef3.ttf(或者包中任何其他的TTF)

3. 运行notepad

4. 选择格式->字体…>[字体] 4000 Tall 和 [脚本] Arabic

立即会崩溃:

http://p4.qhimg.com/t019cf57b7d36dd5a1d.png

调用堆栈:

http://p1.qhimg.com/t01eb33b83c9627ec63.png


0x02 PoC的分析

通常应该浏览PoC,并且试图在深入调试之前理解它的payload,通过了解数据的布局将节约大量时间。因此我在网上搜索了原始的TTF文件。我观察两个文件之间的不同,以便定位到恶意构造的字体属性。比较显示了一个常见的结构体。然而,使用一个自动化fuzzer,得到太多可疑的属性。这非常耗时,我不得不放弃。


0x03 分析官方补丁

提取和分析官方补丁是下一步该做的事。因此让我们看一下。

漏洞版本是1.626.7601.23688版本的usp10.dll,被补丁1.626.7601.23807代替。文件大小大约一致(788KB),使用BingDiff找到了733个函数。其中有个是崩溃调用堆栈中的一个。首先检查这些函数中的不同,因为补丁经常会在漏洞调用之前检查输入数据。第一个(USP10!MergeLigRecords)来自立即崩溃的上下文,它是一样的。下一个(USP10!LoadTTOArabicShapeTables)显示了修改。下图左边的是老的(漏洞),右边是新的(补丁)。

http://p8.qhimg.com/t0175a1259882b11729.png

我们能看见有漏洞的调用MergeLigRecords在一个循环中。

http://p1.qhimg.com/t01f01dcfa586ba15db.png

http://p4.qhimg.com/t01f605f837dd27eddb.png

http://p9.qhimg.com/t01b0784b5c33b4651b.png

在循环中,补丁只有一个重要的修改,是上图灰色的cmp-jnz代码块。这就是补丁吗?目前为止,分析有限,还无法确定(rsp+var_9C)的比较是什么意思,但是很明显,通过新增的代码块能比老版本判断更精确。

现在唯一的方式就是调试了。因此我们启动WinDbg,并附加到notepad进程。我们设置3个断点。一个是有漏洞的MergeLigRecords,一个在ttoGetTableInfo调用之前,还有个在其之后。ttoGetTableInfo调用是有趣的,因为它有两个结构体参数TTOOutput和TTOInput。灰色中if块检查TTOOutput的属性(rsp+var_9C)是否为4,如果不匹配退出循环。因此我们感兴趣的是ttoGetTableInfo中rsp+var_9C是否改变了并且和MergeLigRecords中的崩溃有什么关系。在F5和点击PoC之前,我们还需要定位补丁版本中的rsp+var_9C属性。

http://p3.qhimg.com/t019174feec4e79c51f.png

我们看到,在老的LoadTTOArabicShapeTables中有个名为rsp+var_A4的引用(在下面的代码段中解析为@rsp+34)。

现在我们能观察我们的断点

http://p1.qhimg.com/t0119ccc8f5cdd36865.png

在头两个中,var_A4的值是0004,没有改变。USP10!MergeLigRecords调用执行没有崩溃。

http://p7.qhimg.com/t014c6fe0ccc658ea4a.png

在第3个中,var_A4通过ttoGetTableInfo调用改变了,从0004变为了0001,并且MergeLigRecords崩溃了。

http://p2.qhimg.com/t018fec642c35ef708e.png

此时,我们得出结论,灰色的cmp-jnz块能阻止崩溃,因此我们找到了补丁。


0x04 0patch补丁

目前为止,我们合起来看,所有的内容都在上述灰色部分,下面是我制作的.0pp文件。

http://p4.qhimg.com/t01517a9115a0c66f41.png

当把官方补丁转成0patch补丁时,我使用了之前文中描述的"jump condition piggy-backing"技术。很方便,官方补丁是jnz退出有问题的循环,我们的0patch也是这个位置。我将它放在原始jnz前面。由于缺少空格(jnz只有2个字节,我们需要5字节跳转到我们的补丁代码),我不得不将它放于ttoGetTableInfo调用之前,0patch Agent将使用5字节跳转代替。补丁的第一条指令是替换为原始的ttoGetTableInfo。接下来是来自官方补丁的检查。首先是var_A4和4比较以检查循环是否要继续,否则保存ttoGetTableInfo的结果的eax置为1,因此test eax, eax会设置跳转标志(zf=0),jnz将退出循环。

在使用0patch Builder编译了.0pp文件之后,补丁就可用了,PoC将不再崩溃。我们的团队测试了PoC.zip中的其他ttf文件,所有的都不会崩溃。然而,需要注意的是这个补丁只覆盖了在重现场景中的执行过程。LoadTTOArabicShapeTablesthere的比较中,有另一个jnz灰色块被添加到usp10.dll中,存在类似的循环。但是因为没有公开的PoC可以触发,在0patch中我们不会覆盖它。0patch的安全使用方式是覆盖测试完全的补丁。

(完)