MS08-042漏洞解析:检测恶意Word文档的技术指南

本文详细解析MS08-042 Word漏洞的利用原理,提供使用010 Editor二进制模板检测恶意.doc文件的具体方法,包括流解析、标志位检查和智能标签结构验证等技术细节。

MS08-042:理解与检测特定Word漏洞

几周前我们发布了题为“如何解析.doc文件格式”的博客文章。今天的博文将展示如何利用该信息检查.doc文件是否被特殊构造以利用MS08-042——这是今日安全更新中解决的漏洞之一。该漏洞已在真实世界中被利用,因此我们认为发布更多信息以帮助防御者的益处大于攻击者了解这一已公开漏洞的风险。今天我们发布关于该漏洞的信息,并讨论几种帮助分析文档的工具。

对.doc文件进行碎片整理

等等——碎片整理不是只用于文件系统吗?没错,但如果您记得我们对复合二进制格式的讨论,它可以被描述为文件中的文件系统。复合二进制格式的特性之一是流可以在文件中碎片化。上次我们讨论了使用API从.doc文件中提取感兴趣的流。这次我们将讨论如何读取.doc文件本身并检测利用该漏洞的尝试。我们的技术仅适用于未碎片化的文件。您可以通过阅读复合二进制格式规范了解这些文件中的碎片化工作原理。

关于十六进制编辑器的快速说明

虽然您可以使用任何喜欢的十六进制编辑器进行分析,但在我们的示例中将使用SweetScape Software的010 Editor v3。我们选择此编辑器是因为其二进制模板功能,非常适合检测该漏洞的潜在利用。

读取WordDocument流

对要分析的.doc文件进行碎片整理后,打开WordDocument流,查看偏移0xA处的16位值,并检查第10位(用0x200进行AND操作)。如果该位为0,则我们将使用0Table流,否则使用1Table流。

接下来,查看从WordDocument流偏移0x42A开始的两个DWORD。第一个是xTable流中的偏移量,第二个是长度。如果长度为0,则我们感兴趣的结构不存在于该文件中,因此它不是为利用MS08-042而构造的。否则,请继续阅读以了解我们如何使用偏移量确定文件是否恶意。

为简化操作,下一节我将使用010二进制模板的示例。您可以在本文附件中找到完整模板。在我们的010二进制模板中,在解析复合二进制格式的部分之后,我们循环遍历流寻找名为WordDocument的流。找到后,我们记录要使用的xTable流以及刚才讨论的偏移量和长度:

 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
// 循环遍历所有流寻找感兴趣的流
for( dwCtr = 0; exists( stDir[dwCtr] ); ++dwCtr )
{
   // Memcmp不比较任意内存,只比较字符串...
   if(    stDir[dwCtr].wCbEleName     ==  14
       && stDir[dwCtr].strEleName[ 0] ==  48   // 0
       && stDir[dwCtr].strEleName[ 1] ==  84   // T
       && stDir[dwCtr].strEleName[ 2] ==  97   // a
       && stDir[dwCtr].strEleName[ 3] ==  98   // b
       && stDir[dwCtr].strEleName[ 4] == 108   // l
       && stDir[dwCtr].strEleName[ 5] == 101   // e
       && stDir[dwCtr].strEleName[ 6] ==   0 )
   {
      dwTableStream[0] = dwCtr;
      dwTableStrLen[0] = stDir[dwCtr].dwSizeLow;

      if( dwTableStrLen[0] < OleHeader.dwMiniStrMax )
      {
         qwTableStrOffset[0] = MiniSectOffset( stDir[dwTableStream[0]].dwStartSect );
      }
      else
      {
         qwTableStrOffset[0] = SectOffset( stDir[dwTableStream[0]].dwStartSect );
      }
<snip>}

// 确定使用哪个表流
FSeek( qwWordStrOffset + 0xA );
WORD Flags;
local uint iWhichTableStream = (Flags & 0x200) >> 9;

// 从WordDocument流获取表流中的偏移量和结构长度
FSeek( qwWordStrOffset + 0x42A );
DWORD fcSttbfBkmkFactoid;
DWORD lcbSttbfBkmkFactoid;

if( lcbSttbfBkmkFactoid == 0 )
{
   Printf( "Clean document.\n" );
   Printf( "This document doesn't contain any smart tags.\n" );
   Warning( "Clean document." );
   Exit( 0 );
}
</snip>

最后,读取xTable流

如果我们已经进行到这一步,说明我们已经正确解析了.doc文件,并确定xTable流中存在智能标签结构。现在我们需要检查表流中的结构,因此我们将在二进制模板中定义该结构。您还可以看到我们测试哪个值以检测潜在利用:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
typedef struct
{
   WORD wWordCount;
   byte bOtherData[12];
   if( wWordCount < 6 )
   {
      Printf( "This document is malicious!\n" );
      Warning( "This document is malicious!" );
      Exit( 2 );
   }
} SMARTTAG <optimize=false>;

typedef struct
{
   WORD wAlwaysFFFF;
   WORD wNumSmartTags;
   WORD wExtraData;
} SMARTTAGSECTION <optimize=false>;
</optimize=false></optimize=false>

最后,我们需要实际读取SMARTTAGSECTION结构,然后读取它告诉我们的所有SMARTTAG结构:

1
2
3
4
5
6
7
FSeek( qwTableStrOffset[iWhichTableStream] + fcSttbfBkmkFactoid );
SMARTTAGSECTION stSmartTagSection;
for( dwCtr = 0; dwCtr < stSmartTagSection.wNumSmartTags; ++dwCtr )
{
   SMARTTAG stSmartTag;
   FSeek( startof( stSmartTag ) + ( stSmartTag.wWordCount + 1 ) * sizeof( WORD ) );
}

具有WordCount < 6的智能标签设置了漏洞发生的条件,但除非文档中存在其他导致Word中止加载文档的损坏,否则实际上不会触发漏洞。由于良性的.doc文件不应具有WordCount < 6的智能标签,我们的检测逻辑已完成!您将在附件的二进制模板中找到封装的此逻辑。

当然,能够检测利用漏洞的尝试不能替代安装安全更新!我们强烈建议您尽快安装MS08-042。

  • 安全漏洞研究与防御博客团队 文章按“原样”提供,不提供任何担保,也不授予任何权利。 CVE-2008-2244.bt
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计