1. 程式人生 > 其它 >繞過詞法解析過程中的安全機制,防禦XSS攻擊!

繞過詞法解析過程中的安全機制,防禦XSS攻擊!

雨筍教育小編今日這篇分享:關於XSS漏洞攻擊的案例分析,本文除了概念介紹,還詳細舉了兩個案例,接下來就往下文看看吧!

通過使用基於HTML解析邏輯的特殊HTML標籤,可以實現跨站指令碼(XSS)攻擊,即使在使用詞法解析器過濾危險內容的情況下也是如此。利用這些型別的XSS漏洞的主要目標,就是讓淨化型詞法解析器將資料視為文字資料,而不是計算機指令(例如,JavaScript指令)。當HTML解析器和淨化型詞法解析器沒有以相同的方式解析資料時,就有可能導致這種型別的攻擊。

關鍵概念介紹

注意:對本文來說,我們假定讀者已經接觸過XSS(更準確的說是JavaScript注入)方面的知識,並且對HTML有基本的瞭解。要想了解更多的入門知識,請前往雨筍教育公眾號:雨筍君查閱

針對XSS漏洞的保護措施

實際上,針對XSS漏洞的保護措施有多種形式。比如,早期的防禦措施,就是利用正則表示式(regex)來檢查使用者輸入的“危險”字串。一個簡化的例子是,如果使用者提供的輸入包含

<script>

,那麼,就通過正則表示式找到該字串並將其刪除。然而,這種基於正則表示式的XSS保護措施經常出現失誤,因為可以通過各種方法構造出能夠順利繞過正則表示式的JavaScript程式碼串。對於上面的例子來說,只需將

<script>

中的一個字母變為大寫(如

<scRipt>

),就可以繞過這種過濾器,從而導致XSS攻擊。因此,我們不建議使用正則表示式過濾器來防禦XSS。所以,讓我們來談談更好的解決方案。上下文輸出編碼是另一種XSS保護形式,它會將特殊字元(如“<”和“>”)轉化為無害的HTML編碼輸出(例如,“

&lt;

”和“

&gt;

”)。這種形式的保護將使用者的輸入放在原始檔中,以確保所有可能導致JavaScript執行或HTML渲染的JavaScript或HTML可用字元都轉換為不危險的HTML實體編碼形式。這是處理在應用程式中呈現的使用者輸入的好方法;事實上,許多現代前端框架都會預設進行輸出編碼(例如,ReactJS和Angular)。然而,這種形式的保護會對應用程式施加某些限制,也就是禁止使用者使用某些支援富文字的HTML特性。如果使用者需要支援某些HTML特性,如圖片、連結和富文字等,那該怎麼辦呢?這就是詞法解析發揮作用的地方。

通過詞法解析防禦XSS攻擊

詞法解析是一種非常複雜的XSS防禦手段,因為它在執行額外的邏輯(如對資料進行分塊或編碼)之前,會評估資料是指令還是明文。抽象的說,詞法解析可以被描述為將使用者資料(即不危險的文字內容)與計算機指令(即JavaScript和某些危險的HTML標籤)分離開來的過程。在想讓使用者使用HTML子集的情況下,這種型別的解析可以用來確定哪些是允許的內容,哪些將被阻止或過濾掉。

上面所說的想讓使用者使用的HTML子集的例子,包括富文字編輯器、電子郵件客戶端、What-You-See-Is-What-You-Get(WYSIWYG)HTML編輯器,如TinyMCE或Froala,以及DOMPurify等淨化庫。在這些例子中,這種形式的詞法解析保護是非常常見的。

然而,當HTML解析器和淨化型詞法解析器不是以完全相同的方式處理資料時,就可以將詞法解析作為一種XSS保護形式。這篇文章主要討論在某些情況下,儘管有複雜的保護措施,但仍有可能通過利用HTML解析邏輯來欺騙詞法解析器,注入JavaScript程式碼。為了瞭解如何利用這些XSS問題,我們必須首先考察HTML是如何解析的;資料處理過程中的注意事項和特殊情況;以及淨化型解析器是如何工作的。

資料是如何流經HTML解析器的

要了解我們如何在一個對HTML輸入應用詞法解析的應用程式中實現XSS攻擊,我們首先必須看看HTML是如何被解析的,以及如何確定內容是資料還是指令。下圖展示的是HTML解析器的操作順序:現在,我們對這些步驟簡單加以說明:

網路階段:這個階段指的是將輸入作為位元組傳輸給解析器。

分詞器階段:分詞是進行詞法解析的地方。解析器將把文字資料與計算機指令分開。要做到這一點,分詞器將根據它遇到的元素在資料狀態之間切換上下文,並將值作為單詞返回。這將在“上下文狀態”部分詳細介紹。

樹形結構階段:從分詞器階段返回的單詞被放置在一個樹形結構中;每個樹形分支都被稱為一個節點。為了更清楚地瞭解它們在實踐中到底是什麼樣子的,讓我們來看看下面的HTML片段:<!DOCTYPE html><body><div>Hello World <ahref=https://bishopfox.com>Example</a></div></body>下圖顯示了這在文件物件模型(DOM)樹狀結構中的樣子。

作為攻擊者,他們的目標是在HTML解析的這個階段控制節點。正如我的導師黃老師曾經向我描述的那樣,如果你能控制一個節點的上下文和內容,就能發動XSS攻擊。

指令碼執行階段:這個階段是指通過JavaScript程式碼修改DOM的時候。關於這個階段的其他細節不在本文的討論範圍之內。

DOM階段:構建文件物件模型的處理的最終狀態。現在,我們已經對資料如何在HTML解析過程中流動以及資訊如何組織有了一個高層次的理解,這將在漏洞利用過程中發揮重要作用。## HTML解析器的上下文狀態在分詞階段,HTML解析器將把HTML元素分為不同類別的資料狀態,稱為“上下文狀態”。HTML規範中列出了上下文狀態的切換元素,具體如下:可以將HTML解析器的分詞階段的狀態設定為:

titletextarea將分詞器切換為RCDATA狀態。

stylexmpiframenoembednoframes將分詞器切換為RAWTEXT狀態。

script將分詞器切換為指令碼資料狀態。

noscript如果啟用了scripting標籤,則將分詞器切換到RAWTEXT狀態。否則,讓分詞器留在資料狀態。

plaintext將分詞器切換為PLAINTEXT狀態。

其他元素讓分詞器處於資料狀態。

下面介紹這些上下文狀態在實踐中的樣子。RCDATA示例:輸入:

<textarea><imgsrc=x></textarea>

輸出:

<textarea>&alt;img src=x&gt;</textarea>

輸出內容的快照:

DOM樹:

RAWTEXT示例輸入:

<xmp><imgsrc=x></xmp>

輸出:

<xmp><imgsrc=x></xmp>

輸出的螢幕截圖:

DOM樹:

資料示例:輸入:

<imgsrc=x>

輸出:

<imgsrc=x>

輸出內容的快照:

DOM樹:

請注意,資料狀態是唯一試圖載入影象的狀態。這是因為資料是一種計算機指令,而不是簡單的文字資料。重點提示:提供的不同元素可以通過切換資料的上下文狀態來改變這些元素中資料的解析和呈現方式。

名稱空間:外來內容以及利用意外的行為

瀏覽器的HTML解析器不僅可以理解HTML;它還可以在三種不同的名稱空間之間切換:HTML、MathML和SVG。在HTML解析過程中,如果遇到

<svg>或<math>

名稱空間元素(標籤),解析器會將上下文切換到相應的名稱空間。這種上下文切換對我們來說意味著解析器不再作為HTML進行解析,而是作為MathML或SVG進行解析。當HTML被嵌入到MathML/SVG中時,這種名稱空間的上下文切換會導致意想不到的行為,因為每個名稱空間都有自己獨特的元素,解析方式也略有不同。作為滲透測試人員,我們可以在某些情況下利用這種邏輯把解析器搞蒙圈,從而渾水摸魚發動XSS攻擊。這裡有一篇關於如何繞過DOMPurify的文章,其中對名稱空間的混淆進行了更深入的研究,包括前沿的研究和一個很棒例子。重點提示:當HTML解析器遇到MathML或SVG元素時,會將上下文切換到獨立的名稱空間,這可以用來讓解析器產生混淆。

淨化型詞法解析器的工作流程

為了利用淨化型詞法解析器,我們需要了解其工作的流程;概括來說,主要流程如下所示:

使用者提供的資料被瀏覽器的HTML解析器解析為HTML。

詞法解析器對資料進行分析和過濾。

瀏覽器的HTML解析器再次對資料進行解析。這個流程如下圖所示:

攻擊的目的就是提供相應的HTML來欺騙淨化解析器,使其相信所提供的輸入是無害的文字資料(RCDATA、PLAINTEXT或RAWTEXT),而它實際上是計算機指令(資料狀態)。這通常是可能做到的,原因有多個:HTML的設計之初,並沒有考慮到需要解析兩次;在最初的HTML解析器和解析解析器之間可能會出現細微的解析差異;淨化解析器通常會實現自己的處理邏輯。

測試案例1: TinyMCE XSS

TinyMCE是一個“所見即所得”(WYSIWYG)的HTML文字編輯器和JavaScript庫。它通常包含在第三方網站中,提供文字編輯功能,包括HTML文字。CVE-2020-12648(TinyMCE中的XSS漏洞)是由George Steketee和我發現的;在這裡,它將作為一個測試案例,演示在使用淨化型解析器的情況下,如何利用HTML解析警告來發動XSS攻擊。按照TinyMCE的介紹,XSS是通過以下payload實現的:

<iframe><textarea></iframe><imgsrc=""="alert(document.domain)">

這個payload之所以能夠成功,因為在分詞和DOM樹構造階段有一個安全問題。準確來說,當HTML被詞法解析器重新解析時,它在分配上下文狀態之前沒有正確考慮到元素的順序。

<iframe>

元素導致上下文狀態切換為RAWTEXT,這意味著

iframe

後面的資料被認為是沒有危害的,不需要進行過濾處理。這種上下文切換在

</iframe>

的關閉標籤處結束。然而,

<textarea>

元素也會令解析器切換到RCDATA上下文,即另一種形式的非危險文字資料。當HTML解析器處理

iframe

元素時,切換到RCDATA的上下文的指示就包含在這些元素中。這種包含是TinyMCE解析器沒有意識到的。當進行上述解析時,TinyMCE解析器實際上並沒有考慮正確的操作順序和上下文切換問題。因此,HTML解析器最終生成的DOM樹如下所示:

以上是TinyMCE的解析器“看走眼的”結果,實際的資料是這樣的:

請注意,具有活動內容事件的img元素位於DOM樹的文字上下文中;當進行詞法解析時,這將被視為沒有危害的,不會被剝離或進行編碼處理。由於textarea元素包含在iframe中,而img元素實際上並不在textarea元素中。因此,活動內容(JavaScript)將被執行,從而實現XSS。

測試案例2:Froala XSS

Froala是一個所見即所得(WYSIWYG)的HTML文字編輯器和JavaScript庫,其功能與TinyMCE類似。對於第二個測試案例,我們將審查作為這項研究的一部分而發現的一個XSS漏洞(CVE-2021-28114)。在這個CVE的公告中,詳細介紹瞭如何使用以下payload實現XSS:

<math><iframe><!--</iframe><img src =alert("XSS")>

在功能方面,這個payload與測試案例1中討論的TinyMCE XSS相同,但有一點需要注意:進入MathML名稱空間雖然會導致解析混亂,但是,這並不足以讓Froala的解析器徹底蒙圈。然而,由於Froala的解析器並不理解MathML名稱空間的標籤,因此,它會丟棄這些標籤,並繼續解析其餘的內容。這樣的結果是:對於HTML解析器建立的節點來說,其payload被限制為文字資料,具體如下面的樹結構所示:

然而,由於Froala的解析器遺漏了

<math>

元素,所以,它仍然會錯誤地將img元素的payload視為一個沒有任何危害的註釋。當JavaScript payload被最後階段的HTML解析器處理並放入DOM時,它將會:

其結果是,XSS payload將得到執行。通過檢查相應的原始碼,可以進一步看清這一點:

<iframe><!--</iframe> <img src="" ="alert(&quot;XSS&quot;)" style="" class="fr-ficfr-dii"> --&gt;

Froala解析器刪除了

<math>

元素,並添加了一個

-->

來結束它所認為的註釋。最後階段的HTML解析器將開頭的註釋視為是

iframe

元素中的,並將Froala解析器新增的、用於結束註釋的元素設定為RCDATA狀態,而不是把它看作一個有效的結束標籤,其結果是主動內容得以執行(XSS)。

預防措施

當實現允許使用者控制某些HTML元素的應用程式時,避免這些型別的錯誤的關鍵是,讓HTML的解析結果儘可能地接近其本意。在這樣做的時候,重要的是要考慮到元素的順序和嵌入元素的上下文。如果HTML解析器對一個節點的看法與淨化型解析器對一個節點的看法存在差異,那麼在詞法解析中就會出現這些XSS問題。當不需要MathML和SVG名稱空間元素時,最好將其列入黑名單,並將包含這些元素的請求全部丟棄(即不要繼續將資料寫入DOM)。

對於那些不建立這些型別的解決方案,而是將它們納入其應用程式的組織來說,一個好的補丁策略能在很大程度上緩解這種漏洞。同時,我們建議大家經常檢查這些庫的最新版本,並定期給它們打補丁。

除了程式碼/應用層面的安全防禦措施外,企業還應在應用程式中實施內容安全策略(CSP)。一個定義良好的CSP可以在瀏覽器定義的層面上阻止JavaScript注入,從而建立一種深入防禦的安全態勢。此外,CSP應避免某些危險的指令,如unsafe-inline或unsafe-eval,因為這些指令可以執行使用者定義的內聯JavaScript程式碼。

小結

即使對輸入進行了詞法解析,XSS仍有可能通過利用HTML解析和重新解析時的漏洞來實現,無論使用的是何種淨化庫。在測試這種型別的XSS時,建議用各種名稱空間和上下文切換元素對輸入進行模糊測試處理,記錄所有可疑的結果,並根據這些結果進行相應的處理。

更多漏洞分析、滲透測試技術學習可加v:進群 15386496074

*本文章僅供技術交流分享,請勿做未授權違法攻擊,雨筍教育不負任何責任。具體請參考《網路安全法》。