您当前的位置: 首页 > 

合天网安实验室

暂无认证

  • 1浏览

    0关注

    748博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

DOM破坏攻击学习

合天网安实验室 发布时间:2020-04-16 10:39:33 ,浏览量:1

01

前言

最近看到好多师傅都已经学习过了DOM Clobbering Attack,因此自己也来学习一波。

 

02

0x01 简介

DOM最初诞生的时候没有一个很好的标准,以至于各个浏览器在实现的过程中会支持DOM的一些怪异行为,而这些行为可能会导致DOM Clobbering的发生浏览器可能会将各种DOM元素的name和id属性添加为document的属性或页面的全局变量,这会导致覆盖掉document原有的属性或全局变量,或者劫持一些变量的内容。

 

测试环境 Chrome 80.0.3987.132

 

03

0x02 简单的例子

1.对象创建

测试代码如下:




    
    DOM Clobbering Attack





    console.log(test1);
    console.log(test2);
    console.log(window.test1);
    console.log(window.test2);
    console.log(document.test1);
    console.log(document.test2);



打印的结果如下:

通过上面的结果,可以看出来HTML标签中的id属性值被当做全局变量,name属性值被当成document的属性,这也就是为什么上面有一行输出undefined的原因。

 

2.方法的覆盖

测试代码如下:




    
    DOM Clobbering Attack





    console.log(document.getElementById);
    console.log(document.getElementById("form"))



结果如下:

通过上面的输出结果显示我们可以通过name属性覆盖document中的内置方法。

 

3.通过标签的层级关系构造变量的层级关系

测试代码如下:




    
    DOM Clobbering Attack



    
    



    


    console.log(test1);
    console.log(test1.test2);
    console.log(test1.test3);
    console.log(test4['name']);
    console.log(test5['id']);
    console.log(document.body);
    console.log(document.body.firstChild);



结果如下:

通过上面的结果我们看到,可以通过多层覆盖的方式,覆盖Window和document下的对象。

 

04

0x03 javascript Scope

由于DOM Clobbering Attack的攻击中有很多的地方用到了javascript的作用域链,因此我们可以来了解一下:

 

1.全局作用域:

在javascript中全局作用域一般是window(nodejs是global)。

 

2.显示声明:




    
    DOM Clobbering Attack



    var testValue=123;
    var testFunc=function () {
        console.log("DOM");
    };
    console.log(window.testValue); // 123
    console.log(window.testFunc); // function(){console.log("DOM")}



3.隐式声明:

不带有声明关键字的变量,js会默认帮你声明一个全局变量:




    
    DOM Clobbering Attack



    function foo(value) {
        result=value+1;
        return result;
    }
    foo(1);
    console.log(window.result); // 2



变量result被挂载到了window对象上了。

 

4.块级作用域:

在 ES6 之前,是没有块级作用域的概念的。如果你有 C++ 或者 Java 经验,想必你对块级作用域并不陌生:

for (var i=0;i p.match(/Element$/))
.map(p => window[p])
.filter(p => p && p.prototype && p.prototype.toString !== Object.prototype.toString)

我们可以得到两个对象:

HTMLAreaElement()和HTMLAnchorElement (),这两个标签的toString会直接返回他的href属性。




    
    DOM Clobbering Attack



    
        console.log(test1.toString()); // https://www.baidu.com



结合上面的两个问题,我们会构造如下payload:


  

但是test1.test2是undefined,这是因为元素会变成的属性,但标签并不会。


    



    console.log(test1.test2); // undefined

我们可以通过构造一个HTMLCollection来解决问题,例如:

click1!
click2!


    console.log(test1)

返回的集合如下所示:

HTMLCollection(2) [a#test1, a#test1, test1: a#test1]
length: 2
0: a#test1
1: a#test1
test1: a#test1
__proto__: HTMLCollection

HTMLCollection可以通过index访问,同时可以使用id访问,并且可以使用name访问,例如:

click1!
click2!


    console.log(test1.test2); //click2!

因此上面的问题得到解决,通过构造如下payload:

``



    if (window.test1.test2) {
        eval(''+window.test1.test2)
    }

成功执行。

 

2.确定DOM元素间的关系

我们把两个HTML元素相邻放置,分别为其分配一个ID,然后检查第一个元素是否具有第二个元素的属性。代码如下:

  const log = [];
    const html = ["a", "abbr", "acronym", "address", "applet", "area", "article", "aside", "audio", "b", "base", "basefont", "bdi", "bdo", "bgsound", "big", "blink", "blockquote", "body", "br", "button", "canvas", "caption", "center", "cite", "code", "col", "colgroup", "command", "content", "data", "datalist", "dd", "del", "details", "dfn", "dialog", "dir", "div", "dl", "dt", "element", "em", "embed", "fieldset", "figcaption", "figure", "font", "footer", "form", "frame", "frameset", "h1", "head", "header", "hgroup", "hr", "html", "i", "iframe", "image", "img", "input", "ins", "isindex", "kbd", "keygen", "label", "legend", "li", "link", "listing", "main", "map", "mark", "marquee", "menu", "menuitem", "meta", "meter", "multicol", "nav", "nextid", "nobr", "noembed", "noframes", "noscript", "object", "ol", "optgroup", "option", "output", "p", "param", "picture", "plaintext", "pre", "progress", "q", "rb", "rp", "rt", "rtc", "ruby", "s", "samp", "script", "p", "select", "shadow", "slot", "small", "source", "spacer", "span", "strike", "strong", "style", "sub", "summary", "sup", "svg", "table", "tbody", "td", "template", "textarea", "tfoot", "th", "thead", "time", "title", "tr", "track", "tt", "u", "ul", "var", "video", "wbr", "xmp"];
    div=document.createElement('div');
    for(let i=0; i
setTimeout(()=>alert(a.b.c.d),500)

上面用到了setTimeout设置一个定时器是为了保证iframe框架的加载完成。我们可以利用style/link来加载外部样式表来造成延迟:


@import '//portswigger.net';

alert(a.b.c.d)

06

0x05 攻击实例

1. clobbering to enable XSS lab

实验之前先看一个简单的例子:

 

    window.onload = function(){
        let someObject = window.someObject || {};
        let script = document.createElement('script');
        script.src = someObject.url;
        document.body.appendChild(script);
    };

这个实验就有点类似下面这个例子:

 

通过查看源代码我们可以看到这个文件:loadCommentsWithDomClobbering.js,我们可以看到下面的获取图片src的代码:

let defaultAvatar = window.defaultAvatar || {avatar: '/resources/images/avatarDefault.svg'}
let avatarImgHTML = '';
let divImgContainer = document.createElement("div");
divImgContainer.innerHTML = avatarImgHTML

avatar的默认值是/resources/images/avatarDefault.svg,我们可以通过覆盖window.defaultAvatar来实现xss,构造的payload如下:


插入的标签如下:

为什么我们要把闭合前面的"编码为",因为cid是没有这个协议的,因此不会对"进行url编码。这样在解码时"就变成了控制字符"改变页面结构。

然后再评论一次,刷新全局变量,加载loadCommentsWithDomClobbering.js即可导致xss。

2.Clobbering attributes lab

 实验之前我们先来看一个例子:




    
    DOM Clobbering Attack






    
    




    // 遍历DOM树,不需要关注这个函数
    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();
        }
    }


    // 过滤用户提交的HTML代码,如果包含onclick, onerror,删掉该属性(attribute)
    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);
    }



payload如下:

Click me

由于attributes被覆盖导致执行到payload的form时跳过for循环跳过黑名单,成功执行xss。

 

跟上面一样我们先看看loadCommentsWithHtmlJanitor.js的代码。

// Sanitize attributes
for (var a = 0; a < node.attributes.length; a += 1) {
    var attr = node.attributes[a];


    if (shouldRejectAttr(attr, allowedAttrs, node)) {
        node.removeAttribute(attr.name);
        // Shift the array to continue looping.
        a = a - 1;
    }
}

结合上面的例子我们可以通过构造的形式来绕过。

 

根据题目的要求,需要访问触发,并且通过参考资料得知利用tabindex属性和form的onfocus来执行xss。

 

因此构造如下:


但是我们要解决这个lab需要提交到该漏洞利用的漏洞服务器,而且用户直接点击是不会触发xss的,因此我们要构造一个在评论后主动访问并且加上#x,为了等待评论完成我们需要延迟一下,因此构造下面的payload:


直接提交完成lab。

07

0x06 总结

现在一般可以xss的地方都会有过滤,因此当我们xss不了的时候我们是不是可以考虑一下DOM Clobbering Attack呢?

 

08

0x07参考链接

http://d1iv3.me/2018/04/11/DOM-Clobbering-Attack/

https://juejin.im/post/5abb99e9f265da2392366824

https://wonderkun.cc/2020/02/15/DOM%20Clobbering%20Attack%E5%AD%A6%E4%B9%A0%E8%AE%B0%E5%BD%95/

https://portswigger.net/research/dom-clobbering-strikes-back

https://xz.aliyun.com/t/7346

https://portswigger.net/web-security/dom-based/dom-clobbering

WebGoat之XSS

http://hetianlab.com/expc.do?ce=bda568d3-a31c-49ef-ba3e-a4c7d4ee1d0a

(由于html和js都是解释执行的,如果对用户的输入过滤不够严格,导致用户输入一些html或者js代码被浏览器执行)

点击阅读原文做实验。

关注
打赏
1665306545
查看更多评论
立即登录/注册

微信扫码登录

0.1743s