富文字儲存型XSS的模糊測試之道

wyzsk發表於2020-08-19
作者: 我是小號 · 2016/03/11 16:31

0x00 背景


憑藉烏雲漏洞報告平臺的公開案例資料,我們足以管中窺豹,跨站指令碼漏洞(Cross-site Script)仍是不少企業在業務安全風險排查和修復過程中需要對抗的“大敵”。

XSS可以粗分為反射型XSS和儲存型XSS,當然再往下細分還有DOM XSS, mXSS(突變XSS), UXSS(瀏覽器內的通用跨站指令碼)。其中一部分解決方法較為簡便,使用htmlspecialchars()對HTML特殊符號做轉義過濾,經過轉義的輸入內容在輸出時便無法再形成瀏覽器可以解析的HTML標籤,也就不會形成XSS漏洞。

p1 (圖:htmlspecialchars函式的轉義規則)

但網站做大了,總有一些業務,比如郵件內容編輯、日誌帖子類編輯釋出等功能時,需要授權給使用者自定義連結、改變字型顏色,插入影片圖片,這時就不得不需要需要引入HTML富文字實現相應功能。之前提到,htmlspecialchars()這樣把所有特殊符號做轉義處理的過濾辦法,這是就英雄無用武之地,因為HTML標籤全部被過濾了,那之前提到的這些使用者可以自定義功能又該如何實現?

一個問題總有它的解決辦法,所以基於白/黑名單防禦思想的富文字內容過濾器應運而生,並很快被應用到了對抗富文字儲存型XSS的前沿。它的任務就是根據內建的正規表示式和一系列規則,自動分析過濾使用者提交的內容,從中分離出合法和被允許的HTML,然後經過層層刪除過濾和解析最終展示到網頁前端使用者介面來。這樣既不影響網站的安全性,也不會妨礙到使用者自定義富文字內容功能的實現。

道高一尺魔高一丈,經過一些前期的手工測試和側面從烏雲公開的漏洞報告中瞭解,大多數網站的富文字過濾器採用“黑名單”的設計思想。這也為我們使用模糊測試來自動化挖掘富文字儲存型XSS提供了可能性。

p2 (圖:某國內知名郵箱的富文字過濾器基於“黑名單”設計邏輯)

與此同時,本文的主角,“強制發掘漏洞的利器”-- 模糊測試(Fuzzing Test),相信各位一定不會陌生。無論是在二進位制還是在WEB端的黑盒測試中都有它立功的身影,從客戶端軟體漏洞的挖掘到WEB端弱口令的爆破,本質上都可以認為是一種模糊測試。

結合富文字過濾器“黑名單”的實現邏輯,接下來,本文將主要探討這類富文字儲存型跨站指令碼的模糊測試之道。將模糊測試這一強大的漏洞挖掘武器透過精細的打磨,挖掘出大量的潛在缺陷。

0x01 找準目標,事半功倍


要進行模糊測試,首先要找準目標。知道目標有哪些地方有富文字編輯器,又有哪些種類,進一步推測其是否基於“黑名單”思想,是否可以進行自動化的模糊測試。才可以讓我們接下來要進行的模糊測試,發揮出事半功倍的效果

並不是所有允許使用者提交自定義內容的地方,都允許使用者自定義富文字,如果網站已經在後端對所有提交的內容做了htmlspecialchars()的過濾,就意味著所有提交的內容都會被轉義,也就不存在模糊測試的必要了。比如:

p3

烏雲漏洞報告平臺的評論回覆區域,後端的實現邏輯就是不允許使用者傳入富文字內容,對所有使用者輸入的內容做了htmlspecialchars()的過濾。也就是說,如果你傳入類似:

#!js
<script>alert(1);</script>    =>  &lt;script&gt;alert(1);&lt;/script&gt;&nbsp;

這時無論你使用何種高大上的XSS Vector,都無濟於事,被轉義以後的內容,無法對構成XSS跨站指令碼。

富文字編輯器也分很多種,比如基於HTML標籤形式的富文字編輯器(Ueditor、Fckeditor),自定義富文字標籤形式(Markdown, UBB),在國內外各大網站都有使用。模糊測試萬變不離其宗,你有了一把鋒利的斧頭,你無論用什麼方式砍柴,本質相同。只是有時候是類似Ueditor的編輯器,在進行模糊測試的時候,可能會更加方便容易。

p4 (圖:百度Ueditor)

0x02 模糊測試框架


就好像寫字之前你必須有一隻筆,砍柴前必須有一把斧子一樣,在開始針對富文字過濾器展開模糊測試之前,你必須得有一個可以自動生成Payload的模糊測試框架。無論使用JavaScript、PHP、Python還是更加小眾亦或是高階的語言,模糊測試框架的中心思想就是,透過拼接思想動態生成大量的供模糊測試使用的Payload。對網站富文字編輯器的模糊測試,稍不同於對瀏覽器XSS Filter或者是對DOM特性的模糊測試,不過我們還是可以參考一些已經在網際網路上公開的XSS Filter Fuzzer的現成程式碼,加以修改,為我所用,這裡就不再贅述。

所以,在開始更深一步的模糊測試方案設計之前,請選擇自己得心應手的一種程式設計語言,參考現成的XSS Filter Fuzzer,編寫出一個或簡單或複雜的模糊測試框架。

p5 (圖:基於拼接思想動態生成XSS Fuzzing Test Payload的框架程式碼)

0x03 模糊測試模板


有了框架,就好比有了手槍,現在我們需要給它裝上“子彈”-- 模糊測試模板。一個模糊測試模板的好壞,很大程度上決定了,之後我們是否能夠高效的測試出富文字編輯器中潛在的缺陷,從而發掘出大量的儲存型XSS構造姿勢。而在設計自己的模糊測試模板時,主要需要考慮三點:邊界、進位制編碼和字符集。

先來說說邊界問題。以下面簡單的HTML程式碼為例:

#!html
<span class=”yyy onmouseover=11111” style="width:expression(alert(9));"></span>

上述HTML標記語言文字傳給後端富文字編輯器的時候,程式會如何過濾和解析?也許是這樣的:首先匹配到<span,進入其屬性值過濾的邏輯,首先是否含有高危的on開頭的事件屬性,發現存在onmouseover但被”,”包裹,作為class屬性的屬性值,所以並不存在危險,於是放行;接著分析style屬性,其中有高危關鍵詞”expression()”,又有括弧特殊符號,所以直接清除過濾。

上述過濾流程的實現,很大程度依賴於後端透過正則匹配進行的HTML標籤中的邊界分析。透過對“邊界”的判定,類似class=”yyyy onmouserover=11111” 的屬性及其值才會被放行,因為雖然onmouserover=11111雖然是高危的事件屬性,但存在於=””中,沒有獨立成一個HTML屬性,也就不存在風險。所以在上面的例子中,=””就是邊界,<span中的尖括號也是邊界,空格也可以說成一種邊界。所以,形象一點說,一段HTML程式碼的邊界位置很有可能是下面這樣的:

#!html
[邊界]<span[邊界]class=[邊界]yyy[邊界]>[邊界]</span[邊界]>

所以如果是類似style="width:expr/*”*/esion(alert(9));"屬性和屬性值呢?程式又該如何確定邊界?是style="a:expr/*”還是style="a:expr/*”*/ession(alert(9));"?

當後端富文字過濾程式遇到這樣,略微複雜的選擇題時,如果其後端規則設計的過於簡單,就很有可能導致把不該過濾的過濾掉,而把非法的內容放行,從而我們可以構造出儲存型XSS。打亂HTML邊界,讓後端富文字過濾器陷入選擇窘境,這是我們設計模糊測試模板的原則之一。有哪些內容可能會導致富文字內容過濾器出現邊界判斷問題?

(1)特殊HTML符號,透過這類明顯的符號,過濾器就可以到HTML標籤及其屬性,但這些符號錯誤的時候出現在了錯誤的地點,往往會釀成大禍,如:

=, ”, ’, :, ;, >, <, 空格, /,

(2)過濾器會過濾刪除的內容,我們在邊界填充下面這些元素,過濾器盲目刪除,很有可能導致原本無害的屬性值,掙脫牢籠,成為惡意的屬性和屬性值,如:

expression, alert, confirm, prompt, <script>,<iframe>

(3)不可列印字元,如:

\t、\r、\n、\0等不可列印字元

綜上,現在我們已經可以用Fuzzer生成一個下面這樣的Payload。幸運的話,或許已經可以繞過一些後端邏輯簡單的富文字過濾器了,示例如下:

#!html
<<<span/class=/yyyy onmouseover=11111/style="a:exp/*”>*/resion(1);"></span>

當然,除了邊界區分問題,富文字過濾器面對著另外兩個勁敵,特殊的進位制字元編碼和千奇百怪的字符集。

我們先來說說字元編碼,類似\x22,\40,&#x22;等一系列進位制編碼,直接當作文字內容傳遞給後端富文字過濾器,如果處理的辦法?解密後過濾?直接輸出?經驗告訴我們,不少過濾器在處理類似特殊的進位制編碼時,往往會在進位制編碼的特殊HTML符號面前摔個人仰馬翻。於是,像下面這樣一段看似無害化的Payload,在富文字過濾器自作聰明的解密過後,變成了一段跨站指令碼:

#!html
前:<span class=”yyy &#x22;onmouseover=alert(1);//”></span>
 =>
後:<span class=”yyy“ onmouseover=alert(1);//”></span>

接下來,我們再來說說千奇百怪的字符集,不少富文字編輯器在處理類似“㊗”的unicode字元時,會將字元轉化成<img>標籤,所以在mramydnei報告的一個騰訊郵箱儲存型XSS中,一段無害的Payload逆襲成了有害的跨站指令碼:

#!html
前:<style x="㊗" y="Fuzzitup {}*{xss:expression(alert(document.domain))}">
 =>
後:<style x="<IMG src=" https:="" res.mail.qq.com="" zh_cn="" htmledition="" images="" emoji32="" 3297.png"="">" y="Fuzzitup {}*{xss:expression(alert(document.domain))}"></style>

0x04 模糊測試實戰


正所謂“磨刀不誤砍柴工”,在進行模糊測試實戰之前,我建議,對富文字過濾器的大改過濾規則和實現原理手動測試一番,瞭解哪些HTML標籤允許被使用,有哪些關鍵詞出現就會被刪除,又有哪些Payload會觸發網站存在的WAF,在之後的測試中,針對目標網站“個性化”的修改模糊測試模板。

講到這裡,相信你已經大概瞭解富文字跨站指令碼模糊測試了,不過模糊測試的威力究竟如何呢?我們用例項來做論證:

0x05 寫在最後


模糊測試只是自動化強制發現漏洞的一個重要手段,就像自動化漏洞掃描器一樣。我們並不能完全依靠它,在測試過程中,對過濾器結果進行適時的分析,對模糊測試模板做出合理的改進,不僅能提高模糊測試的效率,還能夠幫助我們挖掘到更多潛在的設計缺陷。畢竟,機器終究是“死板”的,而人是“靈活”的。

富文字跨站指令碼測試之道,就是細緻的模糊測試結果分析,加上對模糊測試模板的不斷打磨,人與機器的結合,才會打造出一把真正的“神器”。

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

相關文章