0x01常用編碼
html實體編碼(10進制與16進制):
如把尖括號編碼[ < ] -----> html十進制: < html十六進制:<
javascript的八進制跟十六進制:
如把尖括號編碼[ < ] -----> js八進制:\74 js十六進制:\x3c
jsunicode編碼:
如把尖括號編碼[ < ] ----->jsunicode:\u003c
url編碼 base64編碼:
如把尖括號編碼[ < ] -----> url: %22 base64: Ig==
0x02 html實體編碼
html實體編碼本身存在的意義是防止與HTML本身語義標記的沖突。
但是在XSS中卻成為了我們的一大利器,但是也不能盲目的使用!
html中正常情況只識別:html10進制,html16進制!
現在介紹一下我們應該如何在xss過程中靈活的使用各種編碼呢?
比如現在你的輸出點在這:
<img src="[代碼]">
在這里過濾了script < > / \ http: 以及各種危險字符 比如創建一個html節點什么的!
有的站只允許你引用一個img文件夾里的圖片 但是圖片是你可以控的 可以通過抓包來修改的!
我們如果想加載外部js 或者一個xss平台的鈎子我們應該怎么寫呢?
那么我們可以在這里 閉合雙引號 寫事件:
onerror=[html language="實體編碼"][/html][/html]
比如我現在彈個窗:
<img src="x" onerror="alert(1)">
原code:
<img src="x" onerror="alert(1)">
這里我用的是html十進制編碼 也可以使用十六進制的html實體編碼!
但是為什么這里我沒有用jsunicode 以及 js八進制跟js十六進制呢!
瀏覽器是不會在html標簽里解析js中的那些編碼的!所以我們在onerror=后面放js中的編碼是不會解析 你放進去是什么 解析就是什么!
大多數網站是不會&#號的,如果過濾了怎么辦呢?
那么再來講一下另外一個案例:
頁面中的Go按鈕中包含一個a標簽 輸入的值會存在於a標簽的href屬性中,href中用了javascript偽協議,可以在href跳轉時執行js代碼!
所以造成了xss!
我們提交的值如下:
%26%23x27,alert(1)%2b%26%23x27
由於頁面對單引號 & 符號 以及 #符號過濾!但是html中可以識別html實體編碼!但是實體編碼是由&#組成!
這個時候&#已經被過濾 我們只能通過url編碼來對 & # 兩個符號進行編碼!再讓瀏覽器解碼成 &# 然后拼接x27 最后就成為了單引號的html16進制編碼!
解碼后:我們的提交值為:
',alert(1)'
href代碼為:
<a href="javascript:location='./3.3.php?offset='+document.getElementById('pagenum').value+'&searchtype_yjbg=yjjg&searchvalue_yjbg='">GO</a><a href="javascript:location='./3.3.php?offset='+document.getElementById('pagenum').value+'&searchtype_yjbg=yjjg&searchvalue_yjbg='">GO</a>
ps:在之前說了html標簽中識別html實體編碼,並且會在html頁面加載時會對編碼進行解碼!那么' 已經是單引號了 但是並不會閉合! 然后在點擊過程中執行javascript代碼 這個時候由於html里'被解析成單引號但是沒閉合 這個時候js被執行 這個我們提交的在html加載時解析成了字符串單引號但是不能閉合之前的引號 因為現在是把我們提交的編碼了的單引號 當成字符串來顯示 但是現在他是存在於a標簽中的href里的 href鏈接里的地址是javascript偽協議,我們現在點擊的時候 會執行里面的代碼 關鍵來了 這個時候我們之前被當做字符串的單引號 被再次解析 這個時候就沒任何過濾規則來過濾它 程序也沒那么智能 之前當做字符串的單引號起作用了 javascript不知道他是個字符串 它只知道瀏覽器解析成了什么 他就帶入進去!就在這個時候我們的字符串單引號就成功的閉合了!當點擊go時 我們的代碼執行!
上面這個例子講了html編碼 以及特殊情況下的編碼那么再講下當你的輸入點存在於script標簽中的時候!我們就應該用js中的編碼了!
既然知道是如何解析的了 那么便又有了以下新的想法!
0x03 新增的實體編碼與瀏覽器的工作原理
通常程序做 XSS 防御的時候會考慮到一些 HTML 編碼的問題,會攔截或轉義 " \ 這樣的東西 那么我的雙引號跟尖括號就被攔截了!
但基礎這種黑名單方式可能出現的問題:
1. 不認識 HTML5 新增的實體命名編碼,如
: => [冒號]

 => [換行]
case: <a href="javasc
ript:alert(1)">click</a>
2.對 HTML 編碼的解析規則不夠熟悉,就像十進制和十六進制編碼的分號是可以去掉的。
還有,數字編碼前面加「0」,這也是一條很好的繞過 WAF 的向量。
數字前面是可以加多個0的
<a href="javasc
ript:alert(1)">click</a>
這句代碼能夠執行么?
不知道那些不是很清楚瀏覽器工作原理的朋友,在最開始有沒有懷疑這段代碼能不能執行!
起碼我最開始 懷疑過!即使編碼被解析回來了 換行了還能執行么!
解析器-詞法分析器Parser-Lexer combination
解析可以分為兩個子過程——語法分析及詞法分析
詞法分析就是將輸入分解為符號,符號是語言的詞匯表——基本有效單元的集合。對於人類語言來說,它相當於我們字典中出現的所有單詞。
語法分析指對語言應用語法規則。
解析器一般將工作分配給兩個組件——詞法分析器(有時也叫分詞器)負責將輸入分解為合法的符號,解析器則根據語言的語法規則分析文檔結構,從而構建解析樹,詞法分析器知道怎么跳過空白和換行之類的無關字符。
然后我的理解是這樣的:
<a href="javasc
ript:alert(1)">click</a>
首先html編碼被還原出來 然后就成了換行 跟冒號
<a href="javasc
ript:alert(1)">click</a>
為什么換行后還能夠執行 是因為瀏覽器中的解析器中詞法分析器 起的作用會跳過空白跟換行之類的無效字符。
然后就構造成了一個完整的語句
<a href="javascript:alert(1)">click</a>
代碼執行!
看完那些之后瞬間心里覺得原來跟原理性相關的東西真的很重要!能夠讓你寫 xss payload更加靈活!
0x04 javascript編碼
javascript中只識別幾種編碼:Jsunicode js8進制 js10進制
就拿下面這個例子來講吧!
第一種情況 你輸入的值存入某個變量 然后最后出現在某個能把字符串當做js代碼來執行的函數里!
如:
eval() setTimeout() setInterval()
以上都是會將字符串當做js代碼執行的函數! 如果是以下情況:
var search = "可控點"; document.getElementById().innerHTML=search;
以上情況很多都是出現在你搜索后 然后顯示的 你所查詢的關鍵字
如果過濾了 <> ' " & % 等等這些!然后再輸出到頁面上!
按理說這樣是安全了!但是我們把輸入的值改成 jsunicode 編碼
如 我們改成 <img src=x onerror=alert(1)> 然后進行js八進制編碼 然后服務器端接受后 經過過濾器 沒有發現該過濾的就進入到了innerHTML中
現在我們來看看 輸出是什么效果!
我就用chrome console來演示吧!
看到了把 經過js的解碼 我們的代碼又還原回來了 並且注入到了網頁中!這時候代碼執行!成功彈窗!
在js中是可以用jsunicode js16進制 js8進制的!
為什么這里不用16進制 跟unicode編碼!是因為 八進制的相對而言最短!
在xss中字符數的長短 也是一個很重要的問題!越短越好!
在asp的站中插XSS代碼的時候,存儲型 會因為你數據庫中字段的長度不夠
而存不進去 然后報錯!這種情況經常發生!所有養成用最少的字符 來達到你的目的 是最好的!
既然提到了js中的十六進制編碼 跟js中的unicode編碼 那么也上兩張圖吧!
十六進制在js中是\x[16hex] 來表示的 如:< \x3c
大家看到跟八進制的用法也是一樣的!只不過多了一個字符X 雖然我很喜歡這個字符 但是我更喜歡八進制的短小精悍!
下面再說說jsunicode編碼:
他的表示方式是這樣的:\uxxxx \uxxx < 轉碼后: /u003c
上圖:
0x05 base64編碼
到目前為止 我遇到使用base64編碼的情況 大多數是這樣!
<a href="可控點"> <iframe src="可控點">
在這種情況下 如果過濾了<> ' " javascript 的話 那么要xss可以這樣寫 然后利用base64編碼!
<a href="data:text/html;base64, PGltZyBzcmM9eCBvbmVycm9yPWFsZXJ0KDEpPg==">test</a>
這樣當test A鏈接點擊時 就會以data協議 頁面以html/text的方式解析 編碼為base64 然后單點擊a鏈接時 base64的編碼就被還原成我們原本的
<img src=x onerror=alert(1)>
然后成功彈窗!
如下圖: