Hacking Team攻击代码分析Part 3 : 字体0day漏洞

安全 黑客攻防 漏洞
为了在IE和Chrome上绕过其沙盒机制完全控制用户系统,Hacking Team还利用了一个Windows中的内核驱动: Adobe Font Driver(atmfd.dll)中存在的一处字体0day漏洞,实现权限提升并绕过沙盒机制。

前言

为了在IE和Chrome上绕过其沙盒机制完全控制用户系统,Hacking Team还利用了一个Windows中的内核驱动: Adobe Font Driver(atmfd.dll)中存在的一处字体0day漏洞,实现权限提升并绕过沙盒机制。

该0day漏洞可以用于WindowsXP~Windows 8.1系统,X86和X64平台都受影响,在Hacking Team泄露的源码中我们发现了该漏洞的详细利用代码。在利用Flash漏洞获得远程代码执行权限后,Hacking Team经过复杂的内核堆操作准备后,加载一个畸形的OTF字体文件,再调用Atmfd中的相关接口触发处理字体文件过程的漏洞,最后获得任意次数的任意内核地址读写权限,接着复制Explorer.exe的token到当前进程,并清除本进程的Job来实现沙盒逃逸。

Chrome 43版本以上默认对沙盒内进程使用DisallowWin32k机制关闭了所有win32k相关调用,因此不受这个漏洞的影响。

下面是该漏洞的具体分析,本文分析来自360Vulcan Team的pgboy:

1. 漏洞分析

通过分析漏洞利用的源码我们看到,该漏洞在加载字体完成后利用NamedEscape函数的0x2514命令来触发关键操作

通过跟踪NamedEscape我们可以找到存在于atmfd.dll里面漏洞点:

以下是笔者测试机器上atmfd的版本(win7 32bit):

相关触发漏洞的callback代码如下:

F5之后的callback代码

这个Callback被外层函数循环调用写入缓存:

我们可以看到,这里参数a3是一个有符号的16位数,当a3>0x8000的时候,movsx会将其扩展成0xffff8xxx,因此下面的写操作就变成了堆上溢,会往给出的缓存地址的前面写入。这是一个典型的由于符号溢出引发的堆上溢漏洞。

了解了漏洞的原理后,我们来继续分析OTF文件是如何触发该问题的,通过调试结合Adobe的文档我们可以知道,是在处理OTF文件中CFF表的Charset过程引发的问题。

我们可以通过T2F Analyzer来观察这个被加载的OTF字体文件的格式。见下图:

 

1

 

显而易见,样本OTF文件中构造了超长的Charset,然后通过NamedEscape函数的0x2514命令来获取Charset的时候,就会触发到上面描述的触发点,引发符号溢出。

2.漏洞利用

我们从头再看一下漏洞利用的流程,整个流程主要分这么几个部分:

1. 找到内核字体对象的地址

由于内核字体内存的布局无法直接被Ring3代码探知,利用代码中使用了一个特殊的技巧来实现获得内核字体对象的地址,在利用代码中,先加载字体,然后立刻创建一个Bitmap对象,再连续多次加载这个字体,由于win32k和atmfd中共用了内存堆处理函数,因此会导致Bitmap对象和字体对象是正好相邻的。

由于Bitmap这类user/gdi对象的实际内核地址可以通过映射到Ring3的GdiSharedHandleTable获得,因此这样也就可以间接获得攻击代码加载到内核的字体对象的范围。

最后,由于NamedEscape函数调用atmfd设备的0x250A号命令可以指定对象的地址,并校验字体对象的有效性同时将字体对象读出来,因此攻击代码结合Bitmap定位和NamedEscape的0x250a指令,就可以准确获取字体对象的地址,相关的代码如下:

2. 触发漏洞,实现写入Bitmap对象

攻击代码首先会分配多个0xb000大小的对象,然后找到9个相邻的Bitmap对象并释放中间的3个,这样就在内核win32k堆内存中留下了0xb000*3= 0x21000大小的空洞,接着攻击代码调用NameDEscape-atmfd的0x2514号命令来读取超长的Charset,触发漏洞。

在这个NamedEscape调用到atmfd过程中,会分配内核对象来复制一份输入的缓存,这里攻击代码将输入的缓存大小设置为0x20005,由于页对齐的原因,这里正好可以占住上面我们说到的0x21000大小的空洞内存。

这样在最终符号溢出时,就会写入到这块Buffer上面未被释放的Bitmap对象中,这就通过精确地堆操作完成了将这个符号溢出导致的缓存上溢转换到对已控制的Bitmap对象的写入。

这个转化的流程如下图所示:

 

2

 

3. 将Bitmap写入转换为内核任意地址读写

在第2步我们讲到这里可以通过操作字体接口,将OTF文件的Charset处理的符号溢出漏洞转换为覆盖Bitmap对象内存的操作,这里我们来看看Bitmap对象在win32k中是如何组织的:它实际是一个 SURFACE对象,结构如下:

其中,Address0其实是指向Bitmap中BitsBuffer的指针,我们可以通过SetBitmapBits函数来操作BitsBuffer指向的内存,可以写入bitmap对象的SURFACE内核结构后,攻击代码就可以通过控制Address0来实现任意地址读写。

在攻击代码中,使用了两个Bitmap对象,一个Bitmap用来控制读写地址,另一个Bitmap2用来进行实际读写,我们将Bitmap2作为读写地址控制器,将其pBitsBuffer指向实现实际读写的Bitmap的pBitsBuffer的地址,这样就可以实现多次稳定的任意地址读写。

也就是说,我们通过对Bitmap2进行 SetBitmapBits,设置实际读写的 Bitmap的pBitsBuffer为我们想要读写的地址,然后就可以通过进行实际读写的Bitmap的GetBitmapBits和SetBitmapBits来实现对指定地址的读写了,如图所示:

 

3

 

我们看到,在攻击代码中,首先创建了一个假的Bitmap对象,然后将这个对象写到字体的Charset中:

上面的攻击代码中,则将这个假的Bitmap对象的address0,也就是pBitsBuffer设置成了进行实际读写的bitmap的pBitsBuffer的地址。所以这个假的Bitmap对象就是我们上面提到的控制读写地址的Bitmap2。

最后下面就是完整的利用这个方式实现的任意内核地址的读(arbread)和写(arbwrite)代码:

3.修复内核堆

由于漏洞是在上溢过程中进行的对前一个对象写入,必然会对内核堆造成破坏,所以必须要修复内核堆的结构,这样才能实现在进程退出,对象被释放时不会造成系统蓝屏崩溃,详细的修复代码可以参考源码中触发利用点之后的操作,篇幅关系就不在这里完全列出了。

4.实现权限提升

在实现了内核任意地址写入功能后,权限提升过程就比较简单了,攻击代码通过遍历内核进程表找到explore.exe的进程token,直接将explore的token对象的地址写入到当前进程的token中,并清除进程的Job对象,来实现最终完全绕过各类沙盒的保护功能。

由于权限提升过程中完全使用了DKOM的方式,没有进行内核代码执行,因此也绕过了Windows8以上系统中的SMEP内核保护功能。

我们在分析这个漏洞的过程中,发现目前Hacking Team版本的漏洞利用代码还是存在一些问题的,由于最终的提权代码直接从Explore复制的token对象,会导致该token对象的引用计数出现问题,当系统关机、注销,或者Explore.exe异常结束,最终导致Explore.exe进程退出时,可能会导致引用错误的token对象,引发系统蓝屏崩溃,这是这个利用不够优美的地方。

责任编辑:蓝雨泪 来源: 奇虎360公司技术博客
相关推荐

2015-07-08 10:35:17

2015-07-14 10:53:19

Hacking Tea0Day漏洞

2015-07-08 13:36:24

2015-07-15 12:50:27

微软IE11

2015-07-14 11:00:16

2022-03-25 13:41:55

漏洞网络攻击Quantum(量子

2011-02-28 09:34:55

2011-08-26 11:44:01

2009-07-06 13:15:07

2013-12-02 14:50:25

2021-10-06 13:48:50

0day漏洞攻击

2013-05-23 10:48:14

EPATHOBJ 0d0day漏洞

2015-09-23 13:38:42

2015-05-20 16:34:14

2015-07-14 10:33:19

2013-05-24 14:02:42

2021-04-26 10:09:11

0Day漏洞Google Chro

2021-07-27 11:01:02

Windows

2021-04-13 16:40:18

0Day漏洞远程代码

2022-03-30 09:09:39

漏洞网络安全网络攻击
点赞
收藏

51CTO技术栈公众号