CVE-2017-11882 漏洞复现

“噩梦公式漏洞”:CVE-2017-11882 Microsoft Office Word 栈溢出漏洞

这是一个存在于Word的数学公式模块EQNEDT.EXE的一个栈溢出漏洞, 这里对本漏洞进行了简单的复现。

分析环境

操作系统 Windows 7 x64
漏洞软件 Microsoft office word 2010
反编译器 IDA Pro
调试器Debugger Windbg
进程分析工具 Process Moniter、Process Hacker
样本POC来源 https://github.com/embedi/CVE-2017-11882/tree/master/example

POC分析

从样本POC出发,分析行为

https://github.com/embedi/CVE-2017-11882/tree/master/example获得一个可弹出计算器的样本POC。用Microsoft word 2010直接打开就能弹出计算器。

Process Moniter捕获从打开样本POC到弹出计算器期间的进程信息,用Process Hacker查看到计算器进程的PID,然后在Process Moniter中查看到相应的进程树

可以看到,并不是WINWORD.EXE最终调用的计算器,而是一个由系统服务方式启动的,叫做EQNEDT32.EXE的进程唤起的计算器

因此,EQNEDT32.EXE应该就是存在漏洞并被利用来弹出计算器的模块了。

POC调试

EQNEDT32.EXE模块为公式编辑器,它并不是作为WINWORD.EXE的子进程形式存在的,而是以系统服务的方式单独存在的一个进程,且由于年代久远,没有开启任何漏洞缓解及保护措施。

根据进程监控中看到的路径C:\Program Files\Common Files\Microsoft Shared\EQUATION\EQNEDT32.EXE打开EQNEDT32.EXE,用Windbg附加。查找资料可知Windows下一些创建进程的API函数,如CreateProcess()ShellExcute()WinExec()(WinExec应该是对CreateProcess

做了封装的)等,对这些可能的函数下断点后打开POC样本,在WinExec()断了下来。

查看参数,是通过cmd.exe /c calc.exe 用cmd.exe打开的calc.exe,和我们在进程监控中看到的行为是一致的。

栈回溯定位漏洞

查看栈回溯

可以看到,当前栈帧的返回地址是00430c18

再上一层返回地址是004218e4,查看这个地址前的call指令,并不是到Call WinExec()函数那里的,因此可以猜测函数的执行流已经被篡改,可能是通过栈溢出覆写了返回地址

如果是返回地址被覆写,那么可以猜测当前栈帧情况如下,ret addr 2被覆写成Call WinExec()指令地址,Func3即是漏洞函数。

image-20191209101332190

既然ret_addr_2被篡改了无法获取,那么可以通过再上一层函数Func2的返回地址ret_addr_1来定位漏洞函数,栈回溯中的第二层返回地址004218e4即为ret_addr_1(即Func1中的地址)

Func1 call Func2 :

Func 2 call Func3 :

因此,这里的漏洞函数(Func3)应该就是sub_41160F,在这下断点,单步调试,可以找到溢出点:

如上图中的汇编代码,循环复制时,复制的字节数为C * 4 = 0x30字节,而目的地址距离栈帧基地址的距离为[edi] - [ebp] = 0x28字节,发生溢出,可以覆盖掉返回地址,反编译后可以看到,是strcpy()函数导致的漏洞。可以看到esi寄存器指向的内存块,前面是cmd.exe /c calc.exe,在返回地址的位置则将返回地址覆盖成了call WinExec()指令的地址0x00430c12。同时,查看ebp后的栈空间,可以看到栈中返回地址后位置的值为esi寄存器中的值(上层函数调用当前函数时),正好是cmd.exe /c calc.exe...的字符串指针,在retn到call WinExec()指令地址时,会作为参数,从而弹出计算器。

在样本POC中可以找到对应的payload

污点追踪

定位一下样本RTF文件中对应溢出的数据内容。

rtfobj将样本rtf中嵌入的OLE对象解压下来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
C:\Users\Sunxiaokong>rtfobj -s all D:\桌面\CVE-2017-11882\exploit.rtf
rtfobj 0.55 on Python 2.7.17 - http://decalage.info/python/oletools
THIS IS WORK IN PROGRESS - Check updates regularly!
Please report any issue at https://github.com/decalage2/oletools/issues

===============================================================================
File: 'D:\\\xd7\xc0\xc3\xe6\\CVE-2017-11882\\exploit.rtf' - size: 8368 bytes
---+----------+---------------------------------------------------------------
id |index |OLE Object
---+----------+---------------------------------------------------------------
0 |000000FEh |format_id: 2 (Embedded)
| |class name: 'Equation.3'
| |data size: 3072
| |MD5 = 'b17312bc0e9d77ceb7a69ada7417e7db'
| |CLSID: 0002CE02-0000-0000-C000-000000000046
| |Microsoft Equation 3.0 (Known Related to CVE-2017-11882 or
| |CVE-2018-0802)
| |Possibly an exploit for the Equation Editor vulnerability
| |(VU#421280, CVE-2017-11882)
---+----------+---------------------------------------------------------------
Saving file embedded in OLE object #0:
format_id = 2
class name = 'Equation.3'
data size = 3072
saving to file D:\桌面\CVE-2017-11882\exploit.rtf_object_000000FE.bin
md5 b17312bc0e9d77ceb7a69ada7417e7db

可以看到,class name 为Equation.3,用olebrowse对它进行分析,该类型OLE对象中内嵌了Equation Native数据流(MTEF byte stream)

MTEF参考资料:

MathType MTEF v.3 (Equation Editor 3.x)

Pase MathType MTEF data from OLE binary string

MTEF data is saved as the native data format of the object. Whenever an equation object is to be written to an OLE “stream”, a 28- byte header is written, followed by the MTEF data. The C struct for this header is as follows:

1
2
3
4
5
6
7
8
9
10
11
>  struct EQNOLEFILEHDR {
> WORD cbHdr; // length of header, sizeof(EQNOLEFILEHDR) = 28 bytes
> DWORD version; // hiword = 2, loword = 0
> WORD cf; // clipboard format ("MathType EF")
> DWORD cbObject; // length of MTEF data following this header in bytes
> DWORD reserved1; // not used
> DWORD reserved2; // not used
> DWORD reserved3; // not used
> DWORD reserved4; // not used
> };
>

可见,前28字节是一个数据流的头部,然后后面紧随5字节是MTEF头部

再后面则是MTEF的记录(Record),样本中的08 5A 5A ....是一条font记录

1
2
3
4
5
6
7
FONT record (8):
Consists of:

tag (8)
[tface] typeface number
[style] 1 for italic and/or 2 for bold
[name] font name (null-terminated)
Description Size (byte) Value Comment
Tag 1 0x8 标识这个font记录
tface 1 0x5a
style 1 0x5a
name 任意长度,以null byte结尾 “cmd.exe /c calc.exe AAAAAAAAAAAAAAAAAAAAAAAA”+0x00430c12 可溢出,覆盖返回地址

因此,可以判断出导致溢出的数据字段即为font类型记录的name字段。

小结

由于EQNEDT32.EXE在解析Equation.3 OLE对象中的MTEF数据流里的font类型记录时,没有对font name的长度进行判断,将其复制入0x28大小的栈空间时可发生溢出,并可覆盖返回地址。由于存在漏洞的EQNEDT32.EXE年代久远,没有开启ASLR、GS等漏洞缓解措施,只需要简单的将返回地址覆盖成同模块内的call WinExec()指令地址即可稳定地完成漏洞利用。

0%