XSS與字元編碼的那些事兒 ---科普文

wyzsk發表於2020-08-19
作者: 0x_Jin · 2013/10/21 14:25

目錄


0x00:基本介紹
0x01:html實體編碼
0x02:新增的實體編碼 實體編碼變異以及瀏覽器的某些工作原理!
0x03:javascript編碼
0x04:base64編碼
0x05:閒扯

0x00基本介紹


提起XSS 想到的就是插入字元字元編碼與各種解析了!

這也就是各種xss編碼外掛跟工具出世的原因!之前不懂瀏覽器是如何對我們編碼過的程式碼進行解析的時候就是一頓亂插!

各種編碼 各種插 沒把編碼還原就算了 還原了就算運氣好!後來到PKAV經過二哥和短短的調教後才算是弄清楚了一點編碼與解析方面的知識!

現在也算是運用自如了把!

現在介紹一下在xss中最經常用到的編碼

html實體編碼(10進位制與16進位制):

如把尖括號編碼[ < ]  -----> html十進位制: &#60;  html十六進位制:&#x3c;

javascript的八進位制跟十六進位制:

如把尖括號編碼[ < ]  -----> js八進位制:\74  js十六進位制:\x3c

jsunicode編碼:

如把尖括號編碼[ < ]  ----->jsunicode:\u003c

url編碼 base64編碼:

如把尖括號編碼[ < ]  -----> url: %3C  base64: PA==

0x01 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="&#97;&#108;&#101;&#114;&#116;&#40;&#49;&#41;">

原code:

<img src="x" onerror="alert(1)">

這裡我用的是html十進位制編碼 也可以使用十六進位制的html實體編碼!

但是為什麼這裡我沒有用jsunicode 以及 js八進位制跟js十六進位制呢!

瀏覽器是不會在html標籤裡解析js中的那些編碼的!所以我們在onerror=後面放js中的編碼是不會解析 你放進去是什麼 解析就是什麼!

大多數網站是不會&#號的,如果過濾了怎麼辦呢?

那麼再來講一下另外一個案例:  enter image description here

原始碼如下:  enter image description here

頁面中的Go按鈕中包含一個a標籤 輸入的值會存在於a標籤的href屬性中,href中用了javascript偽協議,可以在href跳轉時執行js程式碼!

所以造成了xss!

我們提交的值如下:

wooyun%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>

ps:在之前說了html標籤中識別html實體編碼,並且會在html頁面載入時會對編碼進行解碼!那麼&#x27 已經是單引號了 但是並不會閉合! 然後在點選過程中執行javascript程式碼 這個時候由於html裡&#x27被解析成單引號但是沒閉合 這個時候js被執行 這個我們提交的在html載入時解析成了字串單引號但是不能閉合之前的引號 因為現在是把我們提交的編碼了的單引號 當成字串來顯示 但是現在他是存在於a標籤中的href裡的 href連結裡的地址是javascript偽協議,我們現在點選的時候 會執行裡面的程式碼 關鍵來了 這個時候我們之前被當做字串的單引號 被再次解析 這個時候就沒任何過濾規則來過濾它 程式也沒那麼智慧 之前當做字串的單引號起作用了 javascript不知道他是個字串 它只知道瀏覽器解析成了什麼 他就帶入進去!就在這個時候我們的字串單引號就成功的閉合了!當點選go時 我們的程式碼執行!

上面這個例子講了html編碼 以及特殊情況下的編碼那麼再講下當你的輸入點存在於script標籤中的時候!我們就應該用js中的編碼了!

既然知道是如何解析的了 那麼便又有了以下新的想法!

0x02 新增的實體編碼,變異以及瀏覽器的某些工作原理


通常程式做 XSS 防禦的時候會考慮到一些 HTML 編碼的問題,會攔截或轉義 " \ 這樣的東西 那麼我的雙引號跟尖括號就被攔截了!

但基礎這種黑名單方式可能出現的問題:

1. 不認識 HTML5 新增的實體命名編碼,如

&colon; => [冒號]
&NewLine; => [換行]





case: <a href="javasc&NewLine;ript&colon;alert(1)">click</a>

2.對 HTML 編碼的解析規則不夠熟悉,就像十進位制和十六進位制編碼的分號是可以去掉的。

還有,數字編碼前面加「0」,這也是一條很好的繞過 WAF 的向量。

如下圖(我去掉了後面的分號 另外在每個數字前加了一個零):  enter image description here

數字前面是可以加多個0的 閒的蛋疼的基友可以自己試下!

<a href="javasc&NewLine;ript&colon;alert(1)">click</a> 

這句程式碼能夠執行麼?

不知道那些不是很清楚瀏覽器工作原理的基友,在最開始有沒有懷疑這段程式碼能不能執行!

起碼我最開始 懷疑過!即使編碼被解析回來了 換行了還能執行麼!

當時就去問了我的好基友 XX大神[一位跟短短一樣擁有著跟常用不一樣的思維 在我們看來是很不同於正常人的人]

然後大神給了我一份比較詳細的瀏覽器工作原理 很長很長!

我就把最主要的copy下來貼上吧!

解析器-詞法分析器 Parser-Lexer combination

解析可以分為兩個子過程——語法分析及詞法分析

詞法分析就是將輸入分解為符號,符號是語言的詞彙表——基本有效單元的集合。對於人類語言來說,它相當於我們字典中出現的所有單詞。

語法分析指對語言應用語法規則。

解析器一般將工作分配給兩個元件——詞法分析器(有時也叫分詞器)負責將輸入分解為合法的符號,解析器則根據語言的語法規則分析文件結構,從而構建解析樹,詞法分析器知道怎麼跳過空白和換行之類的無關字元。

然後我的理解是這樣的:

<a href="javasc&NewLine;ript&colon;alert(1)">click</a>

首先html編碼被還原出來 然後就成了換行 跟冒號

<a href="javasc
ript:alert(1)">click</a>  

為什麼換行後還能夠執行 是因為瀏覽器中的解析器中詞法分析器 起的作用會跳過空白跟換行之類的無效字元。

然後就構造成了一個完整的語句

<a href="javascript:alert(1)">click</a> 

程式碼執行!

看完那些之後瞬間心裡覺得原來跟原理性相關的東西真的很重要!能夠讓你寫 xss payload更加靈活!

0x03 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來演示吧!  enter image description here

看到了把 經過js的解碼 我們的程式碼又還原回來了 並且注入到了網頁中!這時候程式碼執行!成功彈窗!

在js中是可以用jsunicode js16進位制 js8進位制的!

為什麼這裡不用16進位制 跟unicode編碼!是因為 八進位制的相對而言最短!

在xss中字元數的長短 也是一個很重要的問題!越短越好!

在asp的站中插XSS程式碼的時候,儲存型 會因為你資料庫中欄位的長度不夠

而存不進去 然後報錯!這種情況經常發生!所有養成用最少的字元 來達到你的目的 是最好的!

既然提到了js中的十六進位制編碼 跟js中的unicode編碼 那麼也上兩張圖吧!

十六進位制在js中是\x[16hex] 來表示的 如:< \x3center image description here

大家看到跟八進位制的用法也是一樣的!只不過多了一個字元X 雖然我很喜歡這個字元 但是我更喜歡八進位制的短小精悍!

下面再說說jsunicode編碼:

他的表示方式是這樣的:\uxxxx \uxxx < 轉碼後: /u003c

上圖:  enter image description here

0x04 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)>

然後成功彈窗!

如下圖:

enter image description here  在iframe裡也同樣可以使用!大家自己測試把!

0x05 閒扯


web前端的世界真的太難讓人捉摸透!

其實好多阻擋在面前的就是那些原理性的東西!懂了就好了!

看著二哥挖掘反射型xss 讓我感覺很像js程式碼審計!

用二哥的話來說,首先你js的功底得比寫js的人功力要高 然後你就比較容易挖掘到xss!所以我感覺js比xss來說相當重要!二哥一直寫了六七年的js 才練就今天的功力!所以我特別堅信這句話!

一般測試xss首先我會先測試一些反射型!提交幾個非法字元 然後看過濾成什麼了!然後再開啟chrome console 然後再追蹤當前網頁中 以及網頁所引用檔案中的一些關鍵字!比如這個輸入框的id =xxxx 然後我就一直追蹤下去!如果某個陣列 或者變數 的值把它傳入進去了 然後就一直追蹤下去 一直找到源頭!把程式碼都看一邊 如果能繞過的話 自己在chrome稍稍除錯下就能挖掘出來了!

當然這種方法也是二哥教!二哥跟短短一直都是我膜拜的物件!短短跟我講了講 瀏覽器的解析,二哥講了 dom的渲染 js的解析以及等等 說不完的一些技巧!

頓時趕腳 挖掘XSS是那麼的容易!

XSS Encode外掛打包

END

本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!

相關文章