前 言
很多白帽子在挖掘XSS漏洞的時候,往往會遇到一個問題,就是明明發現這裡的過濾有缺陷,但是就是沒法成功的進行構造利用。可能會由於自身對XSS繞過的局限性思維,往往只會反覆的去嘗試各種不同 payload代碼,寄希望於其中某一個可以繞過過濾。但是在遇到強有力的XSS防禦措施下,往往只能是竹籃打水一場空。
鑑於這種情況,這裡主要分3個章節來簡單的分享一些XSS繞過思路。
【第一節】 限制了字符(白名單的方式)
【第二節】 限制了字符(黑名單的方式)
【第三節】 限制了字符長度
前面講過了【第一節】 限制了字符(白名單的方式)
下面聊一聊【第二節】 限制了字符(黑名單的方式)
所謂的黑名單,就是不允許某些指定的字符輸入,其他非限制的內容都可以通過,相對白名單策略,雖然白名單更加安全些,但是往往白名單會誤殺正常業務,所以只能針對性的部署,而不能進行多個業務統一的部署。黑名單的策略,顯然這一方面更具有優勢,缺點就是防禦規則常常會被繞過。一般的XSS-WAF規則用的都是黑名單策略。
這裡直入正題,說說以下幾種情況。
一富文本環境
所謂的富文本環境,就是指可以直接寫入各種標籤符號的一個環境。比如郵件、空間、編輯器等,這些位置採用的基本都是黑名單策略。
這裡說說常見的幾種情況:
1 黑名單過濾危險標籤和事件。
比如直接過濾<script> 、 <iframe> 、 <object>等危險標籤,以及onload、onerror、onclick等危險事件,有的也會直接粗暴的過濾掉script之類的關鍵字。
這種情況我們可以嘗試以下幾種方法:
1.1 大小寫繞過
比如標籤寫成 <sCript> <SCRIPT>這樣,關鍵字script寫成sCRIPT之類。事件也和關鍵字的方法差不多,嘗試用Onload ONLOAD之類的大小寫去繞過,不過事件類的過濾,這種方法一般都沒啥用。一般情況過濾了onxxx的話99%都會注意大小寫問題。
1.2 開口標籤
寫成<script 或者 <script src=xxx? 這樣子,由於語義解析問題和瀏覽器html代碼補全機制,這種方法在以前是可以幹掉很多富文本的規則的,現在隨著安全的發展,相對也不是太好用了。
1.3 其他非黑名單標籤和事件
嘗試一些不在黑名單中的標籤,比如<a><img>之類,事件一般是先嘗試下onxxx這樣,如果發現沒有被過濾,那麼這種情況一般都是過濾了常見的onload、onerror、onclick之類的事件,我們可以找一些不常見的事件去嘗試繞過,比如ontouchstart就是觸摸觸發,這種在手機、平板設備上面的觸發率還是比較高的。<a>標籤可以嘗試<a href=javascript:alert(1)>xx</a>這樣去測試,如果對script關鍵字有過濾的話,再用大小寫混淆或者html編碼進行繞過嘗試。
1.4 靈活利用過濾規則。
比如發現某處會將<script>或者onload過濾為空,那麼就可以直接嘗試用 <scri<script>pt>、o<script>nload、oonloadnload的方式去繞過。以前這個方法用的還是比較多的,現在很多程序已經考慮到這點,基本都會進行循環過濾和語義分析,所以這個姿勢已經不太能過一些大廠的規則了。
二輸出在js代碼中
1 過濾單引號、等號的時候
在js環境中,方法相對靈活很多,比如單引號過濾,很多時候可以用反單引號。
括號很多時候也可以用反單引號去替換。
如上,自己再控制臺試試就知道了。
其實單引號,等號這些有一個比較常用的處理方法,就是用String.fromCharCode
需要寫入一個外部js文件,也可以用這種方法。
但是要注意,這裡String.fromCharCode輸出的結果是字符串,需要執行的話,還需要給最外層加一個eval
這樣就會直接將字符串作為js代碼去執行了。
或者不用String.fromCharCode用atob函數也可以,或者用其他的這種可逆的編碼、加密函數都是可以的。
2 不僅過濾了單引號、等號,還過濾了圓括號、eval的情況
上面的方法在進行js環境中,的黑名單過濾繞過特別實用,但是有人就會問了,你這方法需要用eval和括號,如果把這些也都過濾掉了呢。其實括號的問題,前面已經提到過了,是可以用反單引號去替換的,eval的話,這種可以嘗試其他的函數去繞過,比如用Function或者constructor配合js模板字符串的寫法。
或者用constructor都是可以的
具體這個是什麼原理,這裡大概給解釋下。
具體細節這是js的模板字符串的特性,以前發過的XSS相關文章中也提到過很多次了,這裡就不再具體展開細講了,有興趣的可以自行百度去了解下。
可能看到上面的演示會有人說你這裡的payload裡面還是有等號啊,其實這種base64加密後面的等號是可以控制的,比如用alert(1)加密發現有等號,就寫成或者alert(1);var aaa=1;之類的改變字符其長度,直到沒有了等號就行了,這裡主要是提供一個思路和方法。
三漏洞案例
某網站儲存型XSS(過濾了尖括號/圓括號/單引號)
漏洞詳情:
經過測試後發現,該漏洞點過濾了常見的script關鍵字,還有尖括號 >< ,單引號 ' ,圓括號 ) ( 不過經過一番測試,繞過了這些過濾,成功彈窗。
payload:
代碼執行流程如下圖箭頭所示:
這裡做下簡單的說明,為什麼payload要這麼寫呢?
1 由於過濾了尖括號><,所以只能在input標籤內部構造,input標籤最好用的xss事件就是onfocus了;
2 由於過濾了圓括號(),所以用 location=url編碼 的這種模式可以將括號寫為%28 %29;
3 由於過濾了單引號',所以location='alert%271%28'這樣就不能用了,所以利用this.name進行傳值;
4 script關鍵字有過濾,所以用sCript大小寫混淆繞過;
基本就這樣了吧,綜上就可以得出上面的payload了~
總 結
不管是白名單還是黑名單,還是以後會講到的長度限制的XSS繞過,其實萬變不離其宗,都是利用代碼特性和代碼邏輯進行的一些構造而已。
文章其實主要是探討的繞過思路,作者認為對於XSS繞過這個問題上,思路還是比較重要的。相比很多人喜歡收集一堆payload,然後一個個的去反覆嘗試,其實了解了這些payload的構造思路的話,往往只需要測試一些特殊字符,就大概心裡有數了。