目录
toString
One Level
Two Level
Three Level
More
Dom Clobbering:就是⼀种将 HTML 代码注⼊⻚⾯中以操纵 DOM 并最终更改⻚⾯上 JavaScript ⾏为的技术
DOM Clobbering中的操作也是根据JavaScript行为的层级来分为一层、两层、三层和更多
toString
我们通过以下代码进行fuzz去获取可以通过toString方法将转换成字符串的标签。这些标签的属性值是能够控制的,因此我们也就不再是获取无用的标签了,而是变成了获取到我们想要的字符串
Object.getOwnPropertyNames(window)
.filter(p => p.match(/Element$/))
.map(p => window[p])
.filter(p => p && p.prototype && p.prototype.toString
!== Object.prototype.toString)
这段代码主要是对 window
对象的属性进行一系列操作:
Object.getOwnPropertyNames(window)
获取window
对象的所有自身属性的名称。- 然后通过
filter
方法筛选出名称以Element$
结尾的属性。 - 接着通过
map
方法将这些属性对应的值提取出来。 - 最后再通过
filter
方法进一步筛选出那些值存在且有原型且原型的toString
方法不同于Object.prototype.toString
的元素。
我们得到了两种标签对象:HTMLAreaElement(<area>)&HTMLAnchorElement(<a>),这两个标签对象,我们都可以利用href
属性来进行字符串转换
One Level
当JavaScript的行为只有一层时,只需要简单的使用id或name属性来定义该名称,即可在JavaScript进行执行时对该变量覆盖,如
Two Level
当JavaScript的行为为两层时,需要两层嵌套才能覆盖
需要注意:内外层使用id还是name,需要取决标签之间的层级关系
在双id属性的情况下,可以使用以下来嵌套双层标签:
- form->button
- form->fieldset
- form->image
- form->img
- form->input
- form->object
- form->output
var log=[];
var 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","section","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 "], logs = [];
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'));
可以修改代码去获取id和name之间标签的层级关系
Three Level
当JavaScript的行为为三层时,需要构造同名称的同级标签,在其中一同级目录标签同时具有id
和name
属性,然后在其中再嵌套一个子标签。
这样在定位x
时,返回是数组,即HTMLCollection
。HTMLCollection
是可以通过name
作为索引进行查找的。所以x.y
才会定位到第一个form标签。所以当定位到z
时,就成功为三层了。
More
三层以上的层级,需要用到iframe
与srcdoc
来配合使用
<body>
<iframe name=a srcdoc="<iframe name=b srcdoc='<a id=c name=d href=cid:Clobbered></a><a id=c>' >">
</iframe>
<script>setTimeout(()=>alert(a.b.c.d),500)</script>
</body>
因为需要等待所有的iframe
加载完毕我们才能获得这个层级关系,所以需要⽤到延时,不⽤延时也可以通过⽹络请求来进⾏延缓
<iframe name=a srcdoc="
<iframe srcdoc='<a id=c name=d href=cid:Clobbered>test</a><a id=c>' name=b>">
</iframe>
<style>@import 'http://example.com';</style>
<script>
alert(a.b.c.d)
</script>
需要注意:如果没有延时或者延缓,可能会导致iframe
加载不全,导致undefined
只使用a
返回的是最外层iframe
标签的srcdoc
属性,a.b
返回内层iframe
标签的srcdoc
属性,到a.b.c
时,返回的才是HTMLCollection
最内层的标签也可以转换成form标签和output标签的嵌套