0x00 背景
最近遇到一個雙重編碼繞過過濾的xss漏洞,成功在大佬的指點下彈出成功之后記錄一下學習。
0x01 URL編碼
一個URL的形式如下:
foo://example.com:8042/over/there?name=ferret#nose
協議 域名 端口 路徑 search參數 hash參數
通常來說,如果某種文本需要編碼,說明他並不適合傳輸。原因多種多樣,或壓縮尺寸,或隱藏隱私數據……
對於URL來說,之所以要進行編碼,一方面是因為URL中有些字符會引起歧義。例如,URL參數字符串中使用key=value鍵值對這樣的形式來傳參,鍵值對之間以&符號分隔,如/s?name=chen&city=beijing。但是這個時候如果value字符串包含了=或者&,那么服務器解析肯定會出錯,因此必須將引起歧義的&和=符號進行編碼。
另一方面,因此URL編碼采用的是ASCII碼,這也就是說你不能在Url中包含任何非ASCII字符,例如中文。否則如果客戶端瀏覽器和服務端瀏覽器支持的字符集不同的情況下,中文可能會造成問題。
Javascript中對於URL編碼主要有以下幾個函數:
escape(string):該方法不會對 ASCII 字母和數字進行編碼,也不會對下面這些 ASCII 標點符號進行編碼: * @ - _ + . / 。其他所有的字符都會被轉義序列替換。
escape("http://www.xxx.com/My first/a?name=chen&city=beijing")======>>>>>> http%3A//www.xxx.com/My%20first/a%3Fname%3Dchen%26city%3Dbeijing
encodeURI(string):該方法不會對 ASCII 字母和數字進行編碼,也不會對這些 ASCII 標點符號進行編碼: - _ . ! ~ * ' ( ) 。該方法的目的是對 URI 進行完整的編碼,因此對以下在 URI 中具有特殊含義的 ASCII 標點符號,encodeURI() 函數是不會進行轉義的:;/?:@&=+$,#
encodeURI("http://www.xxx.com/My first/a?name=chen&city=beijing")========>>>>>> http://www.xxx.com/My%20first/a?name=chen&city=beijing
encodeURIComponent(string):該方法不會對 ASCII 字母和數字進行編碼,也不會對這些 ASCII 標點符號進行編碼: - _ . ! ~ * ' ( ) 。其他字符(比如 :;/?:@&=+$,# 這些用於分隔 URI 組件的標點符號),都是由一個或多個十六進制的轉義序列替換的。
encodeURIComponent("http://www.xxx.com/My first/a?name=chen&city=beijing")=======>>>>>> http%3A%2F%2Fwww.xxx.com%2FMy%20first%2Fa%3Fname%3Dchen%26city%3Dbeijin
0x02 URL雙重編碼
那么為什么需要雙重編碼呢?因為以上未討論value為中文的情況。
首先,在前端頁面准備參數的時候,需要對中文參數進行encode處理:
var url = '/?page_name='+encodeURI(encodeURI("測試")); window.open(url);
后端處理:String starName = java.net.URLDecoder.decode(request.getParameter("page_name"),"UTF-8");
<Connector port="80" protocol="HTTP/1.1" redirectPort="8449" connectionTimeout="20000"/>
<Connector port="80" protocol="HTTP/1.1" redirectPort="8449" connectionTimeout="20000" URIEncoding="UTF-8"/>
0x03 URL編碼與XSS
XSS原理這里就不講了。這里直接使用自己遇到的一個反射性xss的例子,問題參數出在url的search參數上。
首先是是在搜索框中插入尖括號,可以看到這是在黑名單之中的:
然后輸入正常的查詢字段發現會被編碼並使用get方式進行提交,所以就在對應的參數后面進行提交,還是首先測試尖括號的url編碼是否被過濾,經過測試發現經過一次URL編碼的%3c依舊會被過濾,但是經過二次URL編碼的%253c就能夠在搜索框與頁面正常顯示:
這里就通過查看源代碼和查看元素發現都被正常解析了,這也意味着可以出發XSS了,一個觸發點時搜索框中,一個觸發點時搜索[<]的中括號里面。
這里繼續嘗試在搜索的中括號進行XSS,將payload <img src=1 onerror=alert(1)>進行2次URL編碼如下:%253Cimg%2520src%253D1%2520onerror%253Dalert%25281%2529%253E
可以看到<img>標簽被正確解析了,但是onerror 的alert卻沒有被觸發,所以后台對於alert應該是有防護的,這里嘗試雙寫繞過即可觸發:
還有一個觸發點就是在輸入框利用引號閉合,增加onclick或者onmouseover等事件進行觸發。
0x04 繞過原理
首先就是瀏覽器在前端與后端都有過濾措施。
首先前端在輸入框對於輸入的參數校驗是很嚴格的,對於未經編碼與經過編碼的特殊符號都能夠做到完整過濾,但是卻使用了get進行提交,導致攻擊者可以任意修改url參數進行繞過前端驗證。
其次后端的驗證對於非法字符的檢測與過濾機制就太不嚴格了,當我們傳輸只經過一次URL編碼的payload時,后台可以經過解碼可以檢測出敏感輸入,但是在經過2次URL編碼的時候就無法檢測出惡意的符號內容。
參考鏈接:
https://blog.csdn.net/zmx729618/article/details/51381655
https://www.cnblogs.com/longling2344/p/5476785.html
https://blog.csdn.net/zhxtpray/article/details/52440076