前言
不久前在网上看到一篇别人对CVE-2017-11826的分析文章,遂将该文认真阅读了一番,看的过程中联系到去年底看过的一篇《重装上阵-office攻击来袭》,深感之前分析CVE-2017-11826时并没有分析得很清楚,于是这两天又重新调试了这个漏洞,此过程中把CVE-2015-1641也一并重新分析了一下。
本文记录了对该类Open XML标签解析漏洞的分析技巧和我重新分析这两个漏洞的过程。
以下环境如无特殊说明,均为windows 7 x86 + office 2007(wwlib 12.0.4518.1014)
有趣的msxml动态库
去年飞塔写过一篇分析CVE-2017-11826的文章,里面利用msxml6.dll的相关函数监控xml解析标签的思路给我留下了深刻的印象。office 2007解析Open XML标签的模块是msxml5.dll,office 2010解析Open XML标签的模块是msxml6.dll,有趣的是,微软没有提供msxml5的符号文件,却提供了msxml6的符号文件。
根据飞塔的分析文章,在解析Open XML的标签时,msxml6会调用到如下函数:
其中Scanner::GetTokenValueQName函数的目的是获取标签名称(例如:标签名称会是w:body)
StringPtr定义如下:
我们看一下msxml6下的Reader::ParseElementN函数(部分):
于是可以在上述位置下断点,飞塔下的断点是这样的:
bp msxml6!Reader::ParseElementN+0x6a “.echo Parsing XML tag:;r $t0=ebp-20;dc @@c++(((StringPtr*)@$t0)->pwh) l@@c++(((StringPtr*)@$t0)->n/2); gc”
也可以这样:
bp msxml6!Reader::ParseElementN+0x6a “du poi(ebp-20) lpoi(ebp-1c); gc”
都是在Scanner::GetTokenValueQName调用完成后查看qname对应的字符串的值,一般这个值即为某一个需要解析的标签。
以在office 2010下调试cve-2015-1641为例,输出的部分结果如下:
可以清楚地看到发生崩溃前解析的4个标签,用TOTALCMD等工具在文档中进行定位,即可快速锁定漏洞触发的位置:
但一般我在调试漏洞时都首选office 2007,如何解决msxml5的符号问题呢?可以用bindiff工具进行diff,以将msxml5与mxsml6中的函数名进行对应,如下:
一番比对后,可以得到msxml5中的Reader::IncrementElementDepth函数(部分):
可以看到msxml5里面存储xml标签的本地变量与msxml6并不一样,在msxml5中断点需修正如下:
bp msxml5+87894 "du poi(ebp-1c) lpoi(ebp-18); gc"
下面是在office 2007下对cve-2017-11826的调试结果:
可以清晰地看到漏洞触发前解析到的若干标签,用TOTALCMD等工具在文档中进行定位,即可快速锁定漏洞触发的位置:
另外如果还需要看标签的解析深度,飞塔给了另外一个断点:
bp msxml6!Reader::ParseElementN+0x32 “.printf “Current element depth: %d\n”, @@c++(((Reader*)@ecx)->_ulCurrentElementDepth); gc”
关于@@C++表达式的用法参考 https://blogs.msdn.microsoft.com/debuggingtoolbox/2008/03/04/special-command-using-c-and-poi-with-cc-expressions/
对于office 2010,实际可简化为如下:
bp msxml6!Reader::ParseElementN+0x32 ".printf "Current element depth: %d\n", @@c++(this->_ulCurrentElementDepth); gc"
本质是在调用Reader::IncrementElementDepth后查看存储当前标签解析深度的成员:
在msxml5内,由于没有符号,所以需要先确定变量的偏移:
在Reader__IncrementElementDepth执行完后后下断点可看到当前tag的解析深度:
bp msxml5+87862 ".printf "Current element depth: %d\n", poi(ecx+1e0); gc"
在office 2007下如下2个断点,得到如下输出:
这样一来,在office 2007/office 2010上调试这类漏洞时就可以对标签的解析名称和解析层级进行监控了。
CVE-2017-11826之再调试
现在回过头看自己之前调试11826的文章,觉得写得并不好。第一,对标签解析的监控断点写得太繁琐;第二,关键数据结构没有分析清楚;另有一些低级错误。本小节将对前文的上述三点进行改进和补充。
这里特别感谢goabout2同学写的11826的调试文章,看完他的文章后我对相关结构体茅塞顿开,下面进行说明。
先点出CVE-2017-11826的漏洞成因,现在大家都知道这是一个类型混淆漏洞,也知道是Font对象和OleObject对象发生了类型混淆,我们来从结构体层面对此次因font标签未闭合导致的混淆进行说明:
wwlib.dll在解析xml标签时会维护一个类似如下的内存结构(DeleteObj名称源自《重装上阵-office攻击来袭》):
注意,每个TagObject的大小在不同情况下可能会发生变化,TagObjectSize会在TagList头部指定。在CVE-2017-11826的漏洞触发前,获取的TagObject的大小在office 2007 下为0x4c(office 2010下为0x5c)。
这是CVE-2017-11826漏洞发生处的伪码,黄色高亮部分为其调用的GetObjectByIndex函数:
先来看一下font标签正常闭合时的数据解析情况:
再看一下font标签缺乏闭合标签时的数据解析情况:
由上面的说明已知,TagList.TagObjLevel代表了TagList.TagObjectArr数组中的成员数量。Font闭合标签的缺失导致在解析完Font后TagList.TagObjLevel值并未减1,而TagObjLevel-2的值随后会被传入漏洞触发前的GetTagObjectByIndex函数,导致本应获取OleObject对应的TagObject,却获取了Font对应的TagObject,从而为类型混淆创造了条件。
整个过程的图示如下,其中黑色为正常解析逻辑,红色为混淆发生时的解析逻辑:
在font闭合标签存在的情况下,解析完font的闭合标签后,会对TagList.TagObjLevel执行减1操作。对TagList的TagObjLevel下内存访问断点,可以得到执行TagObjLevel减1的栈回溯如下:
通过偏移可以定位到执行TagList.TagObjLevel减1的代码如下(灰色语句):
最后再提一下如何获取OleObject和Font这类对象的大小,很简单,开启页堆即可,下图中的usersize即为对象的申请大小,office 2007下分布是0x100和0x4c。
CVE-2015-1641之再调试
既然CVE-2017-11826可以用上述思路进行调试,CVE-2015-1641作为它的姊妹漏洞,当然也可以。CVE-2015-1641也是在解析Open XML标签时产生的类型混淆漏洞,它的类型混淆发生在SmartTag标签和customXML标签之间。
首先来了解一下这两个标签对应的数据结构:
漏洞发生处的伪码如下:
整个过程的图示如下,其中绿色为正常解析逻辑,橙色为混淆发生时的解析逻辑,数字代表解析顺序:
先调试一下正常customXML时的解析逻辑:
接下来以经典触发场景为例对smartTag混淆时的两次任意地址写进行解释:
在windbg中可观察到两轮拷贝如下:
最终,msvcr71.dll的两个函数地址被改写,原本FlsGetValue指针处被改为如下地址,紧随的MSVCR71!exit函数指针也被改写为其他值。
随后的ROP与ShellCode分析在参考链接的其他文章里面已经写得很清楚了,本文不再过多分析。
修复策略
由于两个漏洞漏洞发生时的TagObject都为0x4c大小,且都具有如下结构:
所以CVE-2015-1641和CVE-2017-11826的修复方案都是在调用GetTagObjectByIndex取出对应的TagObject之后,将DeleteObj与正确的DeleteObj函数指针进行比较,如不相同就直接退返回。CVE-2015-1641的补丁比较的是正确的customXML DeleteObj函数指针与当前DeleteObj指针;CVE-2017-11826的补丁比较的是正确OleObject DeleteObj函数指针与当前DeleteObj函数指针。
可见后面如果再出现这类漏洞,还会是一样的修复方案。
参考链接
《office CVE-2017-11826杂谈》 http://www.cnblogs.com/goabout2/p/8186018.html
《CVE-2017-11826 Exploited in the Wild with Politically Themed RTF Document》 https://www.fortinet.com/blog/threat-research/cve-2017-11826-exploited-in-the-wild-with-politically-themed-rtf-document.html
《CVE-2017-11826 漏洞分析》 https://paper.seebug.org/435/
《重装上阵-office攻击来袭》 2017滴滴安全大会paper
《CVE-2017-11826漏洞分析、利用及动态检测》 https://www.anquanke.com/post/id/87122
《CVE-2015-1641(ms15-033)漏洞分析与利用》 https://weiyiling.cn/one/cve_2015_1641_ms15-033
《word类型混淆漏洞(CVE-2015-1641)分析》 http://www.freebuf.com/vuls/81868.html
《Word类型混淆漏洞原理分析(CVE-2015-1641)》 http://www.freebuf.com/vuls/92962.html
《Special Command: Using ??, @@c++() and poi() with C/C++ Expressions》 https://blogs.msdn.microsoft.com/debuggingtoolbox/2008/03/04/special-command-using-c-and-poi-with-cc-expressions/