笔者最近重新研究了一下 office 下 ActiveX 控件堆喷射的相关细节,在此过程中对遇到的一个cve-2015-1642 poc进行了复现,在本文的最后,笔者探索了 ActiveX 控件堆喷射的部分原理,提出了一种比较简单的 ActiveX 控件堆喷射检测思路,实践证明该方式可以准确检出这类堆喷射。
office
ActiveX
cve-2015-1642
由于笔者能力有限,不足之处还请读者斧正。
cve-2015-1642 被公布时为在野利用状态(0day)
漏洞细节首先是由 @yongchuank 在 2015.8.17 公布的,具体见:
@yongchuank
2015.8.17
1a6K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6D9j5h3u0K6i4K6u0W2L8i4N6J5K9h3&6X3L8%4y4W2j5%4g2J5K9i4c8&6i4K6u0W2j5$3!0E0i4K6u0r3j5h3c8$3K9i4y4G2M7X3W2W2M7#2)9J5c8X3#2A6j5%4u0G2M7$3!0X3N6q4)9J5k6r3!0X3k6X3W2U0k6g2)9J5k6r3y4@1j5i4y4C8M7%4W2E0j5X3!0D9i4K6u0V1N6i4y4W2i4K6u0V1j5h3k6@1k6i4u0Q4x3X3c8X3M7X3g2W2i4K6u0V1N6Y4g2D9L8X3g2J5j5h3u0A6L8r3W2@1P5g2)9J5c8R3`.`.
随后,NCC Group 公司的 @d0mzw 在 2015.10.30 公开了这个漏洞的进一步细节,并在文章内详细讨论了 office 内存破坏漏洞借助堆喷射进行利用的具体细节,作者还仔细讨论了office堆喷射的许多细节和通用利用编写方式。
NCC Group
@d0mzw
2015.10.30
c98K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2F1j5$3y4Y4M7X3!0#2M7q4)9J5k6i4c8J5N6i4y4@1i4K6u0r3N6h3E0Q4x3V1k6G2N6i4u0Q4x3X3c8J5k6i4y4W2j5i4u0U0K9q4)9J5c8Y4g2F1k6r3g2J5M7%4c8S2L8X3c8A6L8X3N6Q4x3X3c8E0K9h3y4J5L8%4y4G2k6Y4c8Q4x3X3c8%4L8%4u0V1i4K6u0V1L8$3I4W2i4K6u0V1k6i4S2H3L8r3!0A6N6q4)9J5k6s2m8J5K9h3#2A6N6r3W2$3k6i4y4Q4x3V1j5`.
接着,玄武实验室的 Danny__Wei 在 2015.11.28 在自己的博客上公开了这个漏洞的poc,公开的poc是一段 C# 代码,poc构造思路基本遵循了 NCC Group 的文章。
Danny__Wei
2015.11.28
C#
bfaK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6h3y4F1j5X3I4G2k6%4y4Q4x3X3g2U0L8$3#2Q4x3V1k6p5j5h3&6F1P5g2)9J5k6q4N6W2K9g2)9J5c8Y4m8Q4x3V1j5#2x3o6l9K6x3K6l9J5i4K6u0W2K9s2c8E0L8l9`.`.
笔者最近对 office 下 ActiveX 控件堆喷射的细节进行了进一步研究,研究过程中再次遇到上述材料,因此决定复现一下相关poc。
对 office UAF 漏洞的利用是比较少见的,因为重用内存时占位的时机不好控制。这个漏洞触发后恰好有一段时机可以用来占位,所以值得研究一下。这篇文章还解决了一个问题:可以借助字符串申请申请任意大小的内存块,这在UAF利用时是非常有用的,一般产生UAF时,相应的对象大小往往比较小,所以如何在 office 内进行任意大小内存的申请也就显得尤其重要。
office UAF
office 下的堆喷射技巧,历史上有若干漏洞样本都曾采用过。例如 cve-2013-3906/cve-2015-1641/cve-2015-1642/cve-2016-7193/cve-2017-11826,有资料表明 cve-2015-2424 这个0day也用到了堆喷射,这一点需要进一步考证。
cve-2013-3906/cve-2015-1641/cve-2015-1642/cve-2016-7193/cve-2017-11826
cve-2015-2424
上述几个借助堆喷射的漏洞,其漏洞类型分别如下:
cve-2013-3906 整数溢出
cve-2013-3906
cve-2015-1641 类型混淆
cve-2015-1641
cve-2015-1642 UAF
cve-2016-7193 数组越界写
cve-2016-7193
cve-2017-11826 类型混淆
cve-2017-11826
这里我们来研究一下 cve-2015-1642,笔者遇到的第一个问题是如何编译 Danny__Wei 的poc代码,这看着是一段 C# 代码,在经过若干探索后,笔者用 VS2010 新建了一个 C# 的窗体应用程序,如下:
VS2010
随后在窗口上添加一个按钮控件:
双击按钮,即来到了 button1_Click 函数中,此时将 Danny__Wei 的代码全部拷贝进来即可,拷贝完代码后,会有些对象类型不认识,此时我们需要添加对 MSCOMCTL.OCX 动态库和 Microsoft.Office.Interop.Word.dll 动态库的引用,具体的方法如下:
button1_Click
MSCOMCTL.OCX
Microsoft.Office.Interop.Word.dll
笔者的电脑装有若干版本的VS,所以这两个动态库可以通过 Listary 等工具搜到,将其拷贝到工程目录下,选中后点击确定即可,成功引入后,可以看到引用列表里面多了如下两个库:
Listary
最后添加所需的头文件即可:
此时我们就可以编译生成该poc了(确保你的机器上装有 office,笔者的机器上装的是 office 2010)。
office 2010
编译完成后,双击 .exe 文件,出现一个窗口,点击上面的按钮就可以生成poc了(test.docx):
.exe
test.docx
此时这个 test.docx 还不是一个漏洞样本,它只带有堆喷射和 0x60 大小的内存占位功能。关于如何在此基础上构造一个 cve-2015-1642 的漏洞样本,@d0mzw 在他的文章里面写的很清楚:
0x60
笔者在此思路上用 7z 打开了生成的 docx 文件,并将 activeX1.xml 的 clsid 换成了漏洞的 clsid:44F9A03B-A3EC-4F3B-9364-08E0007F21DF。此时我们就有了一个“理论上”可以劫持 eip 到 0xC0DEC0DE 的 cve-2015-1642 样本。
7z
docx
activeX1.xml
clsid
clsid:44F9A03B-A3EC-4F3B-9364-08E0007F21DF
eip
0xC0DEC0DE
为什么说“理论上”呢?因为读者如果自己实验的话,就会发现这个poc很不稳定,构造的样本在没有打补丁的环境中 crash 是没有问题的,但是笔者试了几次后发现我们并未劫持到 eip。
接下来我们通过调试并改造poc代码来初步实现对eip的劫持,本文不讨论利用编写,利用编写请参考笔者的另一篇文章:
https://bbs.pediy.com/thread-221792.htm
我们先删除堆喷射部分,构造一个只触发 cve-2015-1642 的样本,看一下崩溃现场是否和相关文章里面描述的相同(当然,如果读者比较懒,那么VT也有一个现成的 cve-2015-1642 crash poc,有条件的可以自己下载,md5: 8b7d1680d8aeb1d0d822ee33777671ab)
md5: 8b7d1680d8aeb1d0d822ee33777671ab
笔者调试时某次的 crash 现场如下,可以看到这是一个典型的UAF,且 crash 现场和 @d0mzw 的基本一致(请注意 @yongchuank 的crash现场并不是这里,笔者在 office 2013 下开启页堆后的崩溃现场依然是下面这个,读者请以实际调试的情况为准)
office 2013
现在笔者有一个问题:我不知道被释放前 eax 对象的内存大小为多少。我们来下个断点看一下:
eax
到这里,我们已经知道被释放的对象大小为 0x60.
现在,让我们来整理一下思绪,这个UAF如果要成功利用,所构造的文档在执行是需要满足哪些最简条件?
我们先来检视一下 @d0mzw 文章中提供的思路:
我们再来看一下 Danny__Wei 代码中对上述思路的实现,可以发现如果实际执行顺序为从下到上的话,和上述文章的思路完全一样:
顾名思义,DefragmenHeap 函数的作用是整理内存,实际内存申请时可能申请 0x60 大小的内存,占用的是稍微大一点的内存块,这个函数的作用就是把那些内存块先使用完,从而让系统分配精准的 0x60 大小的内存块,以便提高占位的有效性。
DefragmenHeap
到这里,笔者脑海里的问题是:
我们借助调试器来探究一下上述问题。
要回答第1个问题,我们需要清楚以下几点:
笔者先回答a:显然,tabArrayB[j].Buttons.Add().ToolTipText = objAllocB/objAllocB/chunk; 这几处代码执行时存在一个统一的内存申请点。其次,每个 ActiveX[x].bin 文件在被映射到 office 进程空间时,还有一次统一的内存申请点,笔者将这部分的讨论放到本文最后。
tabArrayB[j].Buttons.Add().ToolTipText = objAllocB/objAllocB/chunk;
ActiveX[x].bin
关于 objAllocB/objAllocB/chunk 的申请,我们可以在堆喷射完的 winword 进程找一个对应堆块的指针,在只开启堆分配用户态栈回溯( +ust )的情况下可以观察到如下输出:
objAllocB/objAllocB/chunk
winword
+ust
再回答b:借助上面得到的信息,笔者下了如下断点进行观察:
从上面的日志可以观察到:实际执行时 chunk 块(fffe0)的内存是最先申请的,随后是 DefragmenHeap 和 ReplaceHeap 中对 objAllocA/objAllocB 的申请,在不考虑字符串内容的情况下,这两个函数的执行顺序笔者并不关心。实际测试发现把 DefragmenHeap 函数中的 objAllocB 内存申请数量进一步增加,将 ReplaceHeap 函数删除,也可以实现正常占位。
chunk
fffe0
ReplaceHeap
objAllocA/objAllocB
objAllocB
接下来我们通过调试器来回答第2个问题:这个UAF在释放内存和重用内存之间的时间差够大吗?利用有足够的时间在这个时间区间内占用被释放的 0x60 大小的内存吗?
既然是UAF,调试时必须定位到 Free 在哪里?Reuse 在哪里?被释放的 0x60 字节内存是否成功被利用代码中申请的对象成功占位。
Free
Reuse
Danny__Wei 提供的poc在笔者的环境中并不能顺利完成占位,我们来借助调试器看一下究竟发生了什么:
根据上述观察,笔者推测利用代码中对 0x60 大小的字符串申请次数太少,于是笔者将 DefragmenHeap 函数的代码做了略微修改,如下:
同时在 button1_Click 函数进行了如下更改:
再次生成样本,笔者这次替换 activeX34.xml 中的 clsid 为漏洞 clsid,再次打开样本,在调试器中观察如下:
activeX34.xml
最后回答第3个问题,根据上面的代码已经知道,笔者在 DefragmenHeap 函数中一共用了80个大小为0x60字节的字符串去占位被释放的对象。这个视环境不同而异,读者可以按需自行调整。
通过上述调试,笔者成功借助公开资料和调试器劫持了 cve-2015-1642 样本的控制流,在此基础上就可以写出这个漏洞的 RCE 利用。这个漏洞比较好的一点就是我们可以在UAF之间对内存进行成功占位,对 office 来说这类可以成功利用的 UAF 还是比较少的。
在本文的最后,笔者单独讨论一下 office ActiveX控件堆喷射时的内存申请细节,这个问题实际上涉及一个更一般的问题:如何准确检出 office 堆喷射样本?也即,如何在动态执行过程中对 cve-2013-3906/cve-2015-1641/cve-2015-1642/cve-2016-7193/cve-2017-11826 这类漏洞样本的堆喷射行为进行准确标定。
office ActiveX
每个 ActiveX[x].bin 文件在被映射到 office 进程空间时,有一处统一的内存申请点。
这里笔者以手头的某个自己构造的 cve-2015-1641 样本为例,为方便起见,我将负责堆喷射的 docx 文档单独抽取出来,抽取的 docx 文档内用1个 activeX1.bin 文件外加 40 个 activeX[x].xml 文件进行堆喷射。
activeX1.bin
40
activeX[x].xml
关于这部分的更多细节可以参考这篇文章:
c64K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2Y4M7X3g2&6K9r3q4@1K9r3q4U0K9$3g2J5i4K6u0W2L8X3g2@1i4K6u0r3i4K6y4r3M7q4)9K6c8o6V1I4x3b7`.`.
其中 activeX1.bin 的大小为 0x20500 字节:
为 0x20500
以下调试环境仍为 windows7 sp1 x86 + office 2010 + windbg
windows7 sp1 x86 + office 2010 + windbg
笔者在调试器中( +ust )将文档打开,查找满足上述大小的堆块:
笔者在上述栈回溯信息中注意到了两个函数:ole32!CMemBytes::WriteAt 和 ole32!CMemBytes::SetSize。我们用 IDA 定位到 mso.dll(14.0.1063.1000) 中的相应调用点来看一下:
ole32!CMemBytes::WriteAt
ole32!CMemBytes::SetSize
mso.dll(14.0.1063.1000)
我们来看一下 ole32!CMemBytes::WriteAt 的伪代码,其中灰色调用处调用了 ole32!CMemBytes::SetSize 函数:
我们再来看一下 ole32!CMemBytes::SetSize 的伪代码,可以看到里面确实调用了 GlobalReAlloc 函数。
GlobalReAlloc
到这里,笔者有若干问题:
我们先来探索第1个问题。
我们对 mso.dll 的上述调用点下断点,看一下每次调用的具体函数是什么:
mso.dll
通过日志可以观察到这个地方每次调用的都是 ole32!CMemBytes::WriteAt 函数。
分析到此处,笔者突然记起自己之前写过的一篇文章,里面谈到了在 office 2010 下借助 msxml6.dll 的符号打印解析的xml标签的断点,相关文章见:
msxml6.dll
320K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2S2L8Y4q4#2j5h3&6C8k6g2)9J5k6h3y4G2L8g2)9J5c8Y4m8G2M7%4c8Q4x3V1k6A6k6q4)9J5c8U0p5H3x3K6l9^5x3l9`.`.
我们来看一下 ole32!CMemBytes::WriteAt 函数是在解析到哪个标签时被调用的:
可以看到正是解析到 ax:ocx 标签后,开始调用 ole32!CMemBytes::WriteAt 映射 ActiveX 控件的内存。
ax:ocx
接下来看一下第2个和第3个问题,我们来看一下 ole32!CMemBytes::WriteAt 的声明:
再次下断点,在函数调用前输出参数看一下:
可以观察到每次调用 ole32!CMemBytes::WriteAt 函数时待写入数据的大小(cb)都为 0x1000,偏移(ulOffset)则按 0x1000 的顺序递增。由此笔者合理推断 ActiveX 控件在被映射到内存时,是按每次 0x1000 的大小被写入的,所以调用 ole32!CMemBytes::WriteAt 处应该位于一处循环内,我们看一下相关调用点的伪代码,果然如此:
cb
0x1000
ulOffset
现在让我们在第1次调用 ole32!CMemBytes::WriteAt 时断下,看一下写入的数据是什么?
可以看到写入的数据正是ole头部,并且在随后写入了 ActiveX[1].bin 控件的其余数据。
ActiveX[1].bin
分析到这里,笔者想知道目的地址在哪里,既然有一个 ulOffset,那么肯定有一个 base,我们能通过上述数据得到 base 吗?答案是肯定的。
base
在 ole32!CMemBytes::WriteAt 函数中,调用完 ole32!CMemBytes::SetSize 后,有一处 memcpy 操作,这里就是在往新扩大的 0x1000 内存拷贝数据,其中第一个参数就是通过 base[offset] 来寻址的,笔者在寻找的就是这个 v5, 可以看到 v5 是通过如下调用得到的:
memcpy
base[offset]
v5
看来 v5 是间接通过 CMemBytes 对象指针得到的,我们来看一下 GlobalLock 函数的实现:
CMemBytes
GlobalLock
可以看到在 GlobalLock 函数中,返回的值其实就是对传入的参数做了一次解引用,原来如此。
现在我们还需要搞清楚 CMemBytes 对象及其相关对象的结构体,幸运的是 IDA 已经给出了相关的结构体定义:
我们的目的就是通过 CMemBytes 对象指针去解析到 v5 对应的地址,所以我们可以将断点修正如下:
上面的日志是一次完整的从 offset=0 到 offset=0x20500 的过程(中间省略了大量重复日志),笔者注意到 base_addr 地址在中间发生过改变,笔者猜测一开始的地址在内存增长过程中可能大小不过,于是将之前已拷贝的数据拷贝到了一块更大的内存,并继续增长,这应该和 GlobalReAlloc 函数的实现有关,这里不再深究。
offset=0
offset=0x20500
base_addr
分析到这里,原则上笔者可以写出一个监控 office ActiveX 堆喷射总内存申请大小的实时 windbg 脚本,但是实际使用时发现带有伪寄存器的脚本执行的速度太慢,该脚本仅供参考。
由于笔者的日常工作涉及到沙箱检测技术的开发,所以我试着将上述调试结论融入沙箱的检测框架。通过累加堆喷射内存大小,并与预先准备的阈值(以下为75MB)进行比较,从而判断一个 office 样本是否有 ActiveX 控件异常堆喷射行为。笔者对 cve-2013-3906/cve-2015-1641/cve-2015-1642/cve-2016-7193/cve-2017-11826 常见攻击样本进行检测,获得了非常好的检出效果。
75MB
这里笔者给出若干漏洞的样本以及对应的检出日志,供读者参考:
由于 office 中一定还存在其他内存破坏漏洞,笔者预计未来仍然会有类似的利用手法出现,这些利用在针对旧版本 office(office 2007/office 2010) 的攻击中还是非常稳定的。
office(office 2007/office 2010)
由于微软 EMET 的 HeapSpray 检测方式只是简单的占坑,在新样本的检测中并没有非常好的效果。因此笔者在本文最后提供了一种较为简单的检测 office 堆喷射检测方式,供读者参考。
EMET
HeapSpray
《Microsoft Security Bulletin MS15-081 - Critical》64cK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6V1L8$3y4K6i4K6u0W2L8h3W2U0M7X3!0K6L8$3k6@1i4K6u0W2j5$3!0E0i4K6u0r3k6h3&6Q4x3X3c8#2M7#2)9J5c8Y4y4W2j5%4g2J5K9i4c8&6i4K6u0V1N6i4m8V1j5i4c8W2M7#2)9J5c8Y4y4W2j5%4g2J5K9i4c8&6j5Y4g2D9L8r3g2@1K9h3&6K6i4K6u0r3x3U0l9I4y4g2)9J5c8X3#2K6x3e0g2Q4x3X3b7H3z5o6p5`.
《Microsoft Office CTaskSymbol Use-After-Free Vulnerability》3d8K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6D9j5h3u0K6i4K6u0W2L8i4N6J5K9h3&6X3L8%4y4W2j5%4g2J5K9i4c8&6i4K6u0W2j5$3!0E0i4K6u0r3j5h3c8$3K9i4y4G2M7X3W2W2M7#2)9J5c8X3#2A6j5%4u0G2M7$3!0X3N6q4)9J5k6r3!0X3k6X3W2U0k6g2)9J5k6r3y4@1j5i4y4C8M7%4W2E0j5X3!0D9i4K6u0V1N6i4y4W2i4K6u0V1j5h3k6@1k6i4u0Q4x3X3c8X3M7X3g2W2i4K6u0V1N6Y4g2D9L8X3g2J5j5h3u0A6L8r3W2@1P5g2)9J5c8R3`.`.
《Understanding Microsoft Word OLE Exploit Primitives: Exploiting CVE-2015-1642 Microsoft Office CTaskSymbol Use-After-Free Vulnerability》58aK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2F1j5$3y4Y4M7X3!0#2M7q4)9J5k6i4c8J5N6i4y4@1i4K6u0r3N6h3E0Q4x3V1k6G2N6i4u0Q4x3X3c8J5k6i4y4W2j5i4u0U0K9q4)9J5c8Y4g2F1k6r3g2J5M7%4c8S2L8X3c8A6L8X3N6Q4x3X3c8E0K9h3y4J5L8%4y4G2k6Y4c8Q4x3X3c8%4L8%4u0V1i4K6u0V1L8$3I4W2i4K6u0V1k6i4S2H3L8r3!0A6N6q4)9J5k6s2m8J5K9h3#2A6N6r3W2$3k6i4y4Q4x3V1j5`.
《CVE-2015-1642 POC》c27K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6h3y4F1j5X3I4G2k6%4y4Q4x3X3g2U0L8$3#2Q4x3V1k6p5j5h3&6F1P5g2)9J5k6q4N6W2K9g2)9J5c8Y4m8Q4x3V1j5#2x3o6l9K6x3K6l9J5i4K6u0W2K9s2c8E0L8l9`.`.
《Spraying the heap in seconds using ActiveX controls in Microsoft Office》858K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2Y4M7X3g2&6K9r3q4@1K9r3q4U0K9$3g2J5i4K6u0W2L8X3g2@1i4K6u0r3i4K6y4r3M7q4)9K6c8o6V1I4x3b7`.`.
《结合一个野外样本构造一个cve-2016-7193弹计算器的利用》https://bbs.pediy.com/thread-221792.htm
《Open XML标签解析类漏洞分析思路》656K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2S2L8Y4q4#2j5h3&6C8k6g2)9J5k6h3y4G2L8g2)9J5c8Y4m8G2M7%4c8Q4x3V1k6A6k6q4)9J5c8U0p5H3x3K6l9^5x3l9`.`.
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课