x01 前言
CVE-2017-11826
据说是 360 在 2017 年 9 月底发现的一个关于 XML 格式解析的一个漏洞,之后微软在10
月份发布了关于CVE-2017-11826
的补丁,补丁地址:https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2017-11826
- 该漏洞的成因是由于在解析闭合元素时,没有对元素的完整性做出判断,导致将当前元素的嵌套关系加上
1
。这样的话wwlib
模块在处理闭合标签时,会错误的使用父级元素w:name
属性+44
的地址进行虚函数调用,攻击者通过修改w:name
属性,就可以进行任意地址调用。 - 受影响的
Office
版本。
x02 调试环境
- 操作系统:Windows 7 + VMware
- 调试工具:x64dbg
- 漏洞样本:POC(提取码:lxx6)
x03 调试分析
- 从
GitHub
上下载关于CVE-2017-11826
漏洞的文件夹,解压后发现包括解压过的docx
文件、README
文件、俄文文档,俄文文档没有仔细看,好像是关于漏洞利用的。
- 包含漏洞的
XML
文件为document.xml
,文件在word
路径下。打开document.xml
文件,分析后发现<w:font>
标签使用了</o:idmap>
标签进行闭合,而<w:font>
标签的w:name
属性有点奇怪,可能是用于控制某一个地址的值。
- 将解压过的
docx
文档重新压缩,之后使用注册表附加调试器准备调试。
- 附加完成之后打开含有漏洞的文档,运行后触发异常,其中
call [ecx+4]
指令是利用虚函数表调用虚函数,而ecx
为虚函数表指针,通过wwlib.41249DA0
函数返回。
- 查看堆栈调用,发现用于处理
XML
格式的msxml
模块,msxml
模块通过间接调用wwlib
模块去协助解析XML
格式。暂且将wwlib.3161309E
函数定为漏洞函数。
- 对漏洞函数下记录断点后查看日志内容,发现漏洞函数被调用了
6
次,结合document.xml
文件中的标签元素分析漏洞函数很有可能是用于解析元素标签的,至于解析的是什么,目前还不清楚。
- 选取最后一次调用漏洞函数的
esp
下条件断点,分析漏洞函数处理流程。
- 函数断下后从传入的参数可以发现,
esi
可能是储存标签信息的数据结构。
- 单步进入该函数,在如图所示的位置会取出元素的嵌套关系,此时
<o:idmap>
标签已经插到了w:font
标签的后面(以":"
符号为分隔符)。而<w:font>
标签在未闭合的情况插入了<o:idmap>
标签,说明嵌套关系已经被错误的解析。
- 调试到
0x31613084
地址时发现会调用wwlib.31249DA0
函数,经过分析后发现该函数的返回值和异常处的虚函数表调用有关,所以进入这个函数看看。
- 通过分析发现该函数对
ecx
和edx
做了一些简单的计算,算法为[[ecx]+8]*edx + [[ecx]+C] + [ecx]
,计算结果为0x0751D140
;而ecx
是由esi
传入,edx
又等于[[esi]]
,所以算法变为[[esi]+8]*([[esi]]-2) + [[esi]+C] + [esi]
,由传入的esi
控制,经过后面的分析可以得出[[esi]]
其实就是当前元素的嵌套等级。
- 调用完
wwlib.31249DA0
后会将[[0x0751D140+44]+44]
地址的值作为虚函数表指针进行虚函数调用,进而触发异常。如图所示可以看出[0x0751D140+44]
地址被覆盖成了<w:font>
元素的w:name
属性,所以攻击者通过修改<w:font>
标签的w:name
属性就可以做到调用任意地址。
- 接下来更改样本中的
document.xml
文件,手动添加</w:font>
闭合标签,看看是否会触发异常。
- 在漏洞函数处断下,这时的嵌套等级为 5。
- 之后通过
wwlib.31249DA0
计算虚函数调用地址为0x075098F4
。由于嵌套等级为5
,所以计算出的结果为F4
(4C*(5 - 2) + 10
),之前的为140
(4C*(6 - 2) + 10
)。
- 虚函数调用后程序并没有触发异常。
x04 分析 msxml 模块处理步骤
- 为了快速了解
msxml
模块的处理流程,对调用堆栈中的所有msxml
模块函数下记录断点,查看日志。
- 从日志中可以发现漏洞函数的调用都是通过
sub_78887830
函数中的call [ebx+200]
的指令实现的,但是倒数第二个漏洞函数的调用却没有经过call [ebx+200]
而是直接跳到了MSO
模块。
- 对倒数第二个漏洞函数下断点。断下后分析堆栈调用,发现
msxml.78887830
函数中的call [ecx+20]
的指令也会调用漏洞函数。
- 这样的话函数调用流程图就能分析出来了,函数调用流程如下图所示:
- 下面根据
msxml.78887830
函数的最后一次调用,简单分析call [ebx+200]
下的函数链调用。
- 在
msxml.78887830
函数开头会将元素标签对象储存在ebx
中,元素标签对象储存当前解析元素的信息,主要是元素的嵌套关系,嵌套等级等。
- 向下调试后发现
msxml.788872F7
函数会获取<w:font>
元素的w:name
属性字符的指针。
- 而下面的
msxml.78887335
函数会获取o:idmap
元素字符的指针
- 获取完
o:idmap
元素字符的指针后,调用msxml.788872F7
函数解析o:idmap
元素,在内存窗口可以看出字符指针已经指向了incer
的位置,说明已经把idmap
标签解析出来了。
- 之后调用
msxml.788873F0
计算元素的嵌套等级,可以看出元素的嵌套等级计算出为6
,但此时元素的嵌套等级依旧是5
,还没有更新为6
。
- 在将
[ebx+1e8]
赋值给eax
之后,发生了跳转,从而跳过了call [ecx+20]
的调用转而进行call [ebx+200]
的调用。
- 调用的函数为
mso.32751CAA
,其实MSO
模块的函数调用没有太大的作用,只是给后面wwlib
模块的做间接处理。
- 到达
0x32751D5C
的位置后执行call [ecx+20]
指令调用sub_3277FAC0
函数,此时esi = [esi+60]
。
- 接着
sub_3277FAC0
函数中会执行call [eax+10]
指令调用wwlib.3127D3FB
。
- 进入
wwlib.3127D3FB
函数之后继续向下调试,此时[[esi+b14]]
的地址中储存着元素的嵌套关系。
- 之后调用完
wwlib.3127E6B3
函数后会进行一个判断,如果ebx
等于0x80004001
就跳转。
- 跳转完成之后调用漏洞函数,下面的流程刚刚已经分析过了。
- 根据上面调试分析的结果对其中几个位置下记录断点。查看日志可以发现
msxml.78887830
函数会逐一对元素进行解析,当解析到<idmap>
标签时嵌套关系为5
。
- 但是在异常处嵌套关系为
6
,对最后一次调用msxml.78887830
函数下断点,查看嵌套关系是何时变为6
的。
- 重新运行后断下,此时嵌套关系为
5
。
- 当调试到
wwlib.3127D3FB
函数中的0x3128E3AD
位置时,嵌套关系变为了6
,说明wwlib.312C6142
函数更新了嵌套关系。
- 接着分析一下
w:name
属性是何时被复制的。通过对漏洞异常处的分析发现w:name
属性储存在元素对象中,通过对元素对象储存w:name
位置下写入断点发现在WWLIB.sub_3127D3FB
函数中会调用wwlib.3127E773
函数复制w:name
到元素对象当中,之后漏洞函数中会把w:name
属性取出来进行虚函数表调用。
- 需要注意的是再上面的分析中该跳转并没有实现,也就是说这里在复制完
w:name
属性之后直接返回了。而判断跳转的值是由wwlib.3127E6B3
返回的,进入该函数,分析后发现在函数末尾处会将0x80004001
赋值给eax
,在这之前会以0x3149BFA3
作为基址,以eax * 4
做为偏移地址进行调用,而eax
是通过[ebp-1c]
传进来的,对该位置下记录断点后查看日志。
- 根据日志可以发现当
[ebp+1c]
的值为0xFFFF
时才会调用漏洞函数。而且解析<w:font>
标签前调用一次,解析<o:idmap>
标签后调用一次。
- 之后把
<o:idmap>
标签删除,再对比日志信息。
- 可以发现只有在
<w:font>
标签解析前才会将此值设置为0xFFFF
,所以这一个值可能是用于判断元素是否闭合。
x05 总结
- 当
msxml.78887830
函数解析到<w:font>
标签时,会误以为标签已经闭合,从而将<w:font>
标签的w:name
属性(假如有的话)添加到对象之中,同时更新元素的嵌套关系(嵌套关系变为6
),导致最后使用call [ecx+4]
进行虚函数表调用时虚表指针被错误的覆盖成了w:name
属性中的数据触发了异常。
关于 CVE-2017-11826 的漏洞分析到此结束,如有错误,欢迎指正