前言
最近看到好多师傅都已经学习过了DOMClobberingAttack,因此自己也来学习一波。
0x01简介
DOM最初诞生的时候没有一个很好的标准,以至于各个浏览器在实现的过程中会支持DOM的一些怪异行为,而这些行为可能会导致DOMClobbering的发生浏览器可能会将各种DOM元素的name和id属性添加为document的属性或页面的全局变量,这会导致覆盖掉document原有的属性或全局变量,或者劫持一些变量的内容。
测试环境Chrome80.0..
0x02简单的例子
1.对象创建
测试代码如下:
打印的结果如下:
通过上面的结果,可以看出来HTML标签中的id属性值被当做全局变量,name属性值被当成document的属性,这也就是为什么上面有一行输出undefined的原因。
2.方法的覆盖
测试代码如下:
结果如下:
通过上面的输出结果显示我们可以通过name属性覆盖document中的内置方法。
3.通过标签的层级关系构造变量的层级关系
测试代码如下:
结果如下:
通过上面的结果我们看到,可以通过多层覆盖的方式,覆盖Window和document下的对象。
0x03javascriptScope
由于DOMClobberingAttack的攻击中有很多的地方用到了javascript的作用域链,因此我们可以来了解一下:
1.全局作用域:
在javascript中全局作用域一般是window(nodejs是global)。
2.显示声明:
3.隐式声明:
不带有声明关键字的变量,js会默认帮你声明一个全局变量:
变量result被挂载到了window对象上了。
4.块级作用域:
在ES6之前,是没有块级作用域的概念的。如果你有C++或者Java经验,想必你对块级作用域并不陌生:
从上面的结果来看,说明var声明的变量,在for循环之后仍然保存在这个作用域里,而for(){}仍然在全局作用域里,因此var声明的变量在全局作用域里。
我们可以通过let(或const用来声明常量)来声明变量,实现块级作用域。
除了上面的几种作用域外还有语法作用域,动态作用域等,就不赘述了感兴趣的参考下面的链接。
0x04攻击方法
1.为了分析DOMClobbering漏洞,假设如下代码:
如果我们想利用DomClobbering技巧来执行任意的js,需要解决两个问题:
1)利用html标签的属性id,很容易在window对象上创建任意的属性,但是我们能在新对象上创建新属性吗?
2)怎么控制DOMelements被强制转为string之后的值,大多数的dom节点被转为string后是[objectHTMLInputElement]。
我们可以用前面的例子来解决第一个问题:
我们可以用下面的一段代码来枚举,html存在的所有标签,然后检查其dom节点对象有没有实现toString方法,或者是继承于Object.ptototype。如果是继承自Object.prototype,那么很有可能只会返回[objectSomeElement]
Object.getOwnPropertyNames(window)
.filter(p=p.match(/Element$/))
.map(p=window[p])
.filter(p=pp.prototypep.prototype.toString!==Object.prototype.toString)
我们可以得到两个对象:
HTMLAreaElement(area)和HTMLAnchorElement(a),这两个标签的toString会直接返回他的href属性。
结合上面的两个问题,我们会构造如下payload:
但是test1.test2是undefined,这是因为input元素会变成form的属性,但a标签并不会。
我们可以通过构造一个HTMLCollection来解决问题,例如:
返回的集合如下所示:
HTMLCollection可以通过index访问,同时可以使用id访问,并且可以使用name访问,例如:
因此上面的问题得到解决,通过构造如下payload:
成功执行。
2.确定DOM元素间的关系
我们把两个HTML元素相邻放置,分别为其分配一个ID,然后检查第一个元素是否具有第二个元素的属性。代码如下:
constlog=[];
consthtml=[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,