从两次DOMPurify绕过探索绕过xss过滤器之法
字数 2092 2025-08-30 06:50:11
DOMPurify绕过技术深度解析:从命名空间混淆到DOM Clobbering
前言
在Web安全领域,XSS(跨站脚本)攻击是最常见的安全威胁之一。虽然使用成熟的XSS过滤器如DOMPurify是防御XSS的有效手段,但理解其绕过技术对于安全研究人员和开发者都至关重要。本文将深入探讨两种主要的DOMPurify绕过技术:命名空间混淆/MXSS和DOM Clobbering。
核心概念
1. 命名空间(Namespace)混淆
HTML文档中存在三种命名空间,元素在不同命名空间中的解析方式各不相同:
- HTML命名空间:标准HTML元素
- SVG命名空间:SVG相关元素
- MathML命名空间:数学标记元素
关键点:
<style>在HTML中被当作文本,但在SVG或MathML中被当作HTML- 命名空间混淆常发生在MXSS(突变XSS)后,浏览器第二次解析时命名空间发生改变
2. MXSS(突变XSS)
MXSS使过滤器在清理用户payload时变得困难,因为相同的解析器连续解析两次payload会产生不同结果。
简单示例:
</form><form id="inner">
第一次解析时位置会被纠正,第二次解析时因form不能嵌套而删除form,导致DOM树突变。
3. <caption>的突变机制
<caption>元素有特殊的解析行为:
- 解析器找到
<caption>开始标记时,会从开放元素堆栈中弹出元素,直到弹出<caption>元素 - 后续内容会被弹出
<table>,不考虑标签的命名空间
突变示例:
<style>本来是svg命名空间的
<a id= 被当作html
</style> 被当作属性
突变后:
<a id=成为文本</style>闭合<style>- 恶意``暴露
4. 节点扁平化(Node Flattening)
当嵌套标签达到上限(512层)时,浏览器会进行扁平化处理:
- 将第513层的内容提取出来
- 被扁平化元素的命名空间保持不变
- 扁平化后的
<a>标签不会被弹出(正常情况下嵌套的<a>会被弹出)
DOM Clobbering技术
基本原理
DOM Clobbering利用HTML元素污染JavaScript命名空间:
- 通过
id或name属性可以直接在JavaScript中访问元素<div id="test"></div> <script>console.log(test); // 输出DOM元素</script> - 特殊标签(
<embed>,<form>, ``,<object>)的name属性也可以直接访问
关键特性
-
无法覆盖已存在的全局变量:如
window.name -
特殊标签返回值:
<base>和<a>返回URL值- 会隐式触发
toString()调用
-
多层级污染:
- 多个同名id时,Chrome返回HTMLCollection
- 可用于污染
form.attributes等属性
-
iframe污染:
<iframe name="test" src="..."></iframe> <script> setTimeout(() => { console.log(test); // iframe的window对象 }, 100); </script> -
document污染:
- ``,
<form>,<embed>等元素可以污染document属性 - 甚至可以污染
document.cookie
- ``,
DOMPurify绕过实例分析
1. DOMPurify 3.1.0绕过
技术组合:
<caption>突变- 节点扁平化
Payload结构:
<table><caption></caption></table>
绕过过程:
- 使用
<table>抑制<caption>的弹出 - 通过扁平化将
<caption>弹出 - 下次解析时将恶意代码(``)弹入HTML命名空间
- DOMPurify不会将
</style>识别为标签,从而绕过过滤
2. DOMPurify 3.1.1绕过
新增防御:
- 深度嵌套检测(MAX_NESTING_DEPTH)
- 超过深度限制强制删除节点
绕过技术:
-
DOM Clobbering劫持parentNode:
- 利用HTMLFormElement特性:浏览器自动将带有name属性的子元素挂载到父form对象
- 导致
f.parentNode返回undefined,破坏深度计数
-
组合
<form>突变:- 第一次解析后嵌套一层
<form> - 再次劫持parentNode重新计数
- 达到255*3=765层,触发扁平化
- 第一次解析后嵌套一层
完整绕过流程:
- DOMPurify首次解析,修正
<form>结构并嵌套一层<form> - 通过DOM Clobbering两次重新计数
- 触发扁平化,弹出
<caption> - 浏览器第二次解析,将恶意代码弹入HTML命名空间
防御措施与后续修复
DOMPurify的后续修复主要包括:
- 拦截DOM Clobbering攻击
- 增加正则表达式匹配MXSS模式
- 注意:过度依赖正则可能引入新的问题
总结
通过分析这两次DOMPurify绕过,我们可以得出以下XSS过滤器绕过的通用思路:
-
利用解析差异:
- 命名空间混淆
- MXSS突变
- 浏览器与过滤器的解析不一致
-
污染关键属性:
- DOM Clobbering污染过滤器使用的变量
- 劫持parentNode等关键属性
-
组合多种技术:
- 如同时使用节点扁平化和DOM Clobbering
- 分层绕过不同防御机制
理解这些技术不仅有助于发现和修复安全漏洞,也能帮助开发者更安全地设计和使用XSS过滤器。