Open XML标签解析类漏洞分析思路

 

前言

不久前在网上看到一篇别人对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.dlloffice 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,以将msxml5mxsml6中的函数名进行对应,如下:

一番比对后,可以得到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闭合标签的缺失导致在解析完FontTagList.TagObjLevel值并未减1,而TagObjLevel-2的值随后会被传入漏洞触发前的GetTagObjectByIndex函数,导致本应获取OleObject对应的TagObject,却获取了Font对应的TagObject,从而为类型混淆创造了条件。

整个过程的图示如下,其中黑色为正常解析逻辑,红色为混淆发生时的解析逻辑:

font闭合标签存在的情况下,解析完font的闭合标签后,会对TagList.TagObjLevel执行减1操作。对TagListTagObjLevel下内存访问断点,可以得到执行TagObjLevel1的栈回溯如下:

通过偏移可以定位到执行TagList.TagObjLevel1的代码如下(灰色语句)

最后再提一下如何获取OleObjectFont这类对象的大小,很简单,开启页堆即可,下图中的usersize即为对象的申请大小,office 2007下分布是0x1000x4c

 

CVE-2015-1641之再调试

既然CVE-2017-11826可以用上述思路进行调试,CVE-2015-1641作为它的姊妹漏洞,当然也可以。CVE-2015-1641也是在解析Open XML标签时产生的类型混淆漏洞,它的类型混淆发生在SmartTag标签和customXML标签之间。

首先来了解一下这两个标签对应的数据结构:

漏洞发生处的伪码如下:

整个过程的图示如下,其中绿色为正常解析逻辑,橙色为混淆发生时的解析逻辑,数字代表解析顺序:

先调试一下正常customXML时的解析逻辑:

接下来以经典触发场景为例对smartTag混淆时的两次任意地址写进行解释:

windbg中可观察到两轮拷贝如下:

最终,msvcr71.dll的两个函数地址被改写,原本FlsGetValue指针处被改为如下地址,紧随的MSVCR71!exit函数指针也被改写为其他值。

随后的ROPShellCode分析在参考链接的其他文章里面已经写得很清楚了,本文不再过多分析。

 

修复策略

由于两个漏洞漏洞发生时的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-1641ms15-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/

 

(完)