“噩梦公式漏洞”: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即是漏洞函数。
既然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 | C:\Users\Sunxiaokong>rtfobj -s all D:\桌面\CVE-2017-11882\exploit.rtf |
可以看到,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 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 | FONT record (8): |
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()
指令地址即可稳定地完成漏洞利用。