0x00 前言
在過(guò)去幾周中,F(xiàn)ortiGuard Labs一直在研究帶有SVG(Scalable Vector Graphics)圖像的Web應(yīng)用。根據(jù)研究結(jié)果,我們找到了Web應(yīng)用中的一些常見(jiàn)問(wèn)題。在本文中,我們簡(jiǎn)要介紹了SVG的特點(diǎn)以及針對(duì)SVG圖像的常見(jiàn)攻擊面。
根據(jù)之前的研究結(jié)果,我們梳理了一些常見(jiàn)的SVG攻擊方式,如下所示:
- 跨站腳本(Cross-Site Scripting)
- html注入
- XML實(shí)體:“Billion Laughs”攻擊(針對(duì)XML文檔解析器的一種DoS攻擊)
- DoS(拒絕服務(wù)):新型SVG “Billion Laughs”攻擊。
0x01 SVG簡(jiǎn)介
SVG的全稱(chēng)為 Scalable Vector Graphics(可縮放矢量圖),是一種基于XML的二維矢量圖格式,支持交互性及動(dòng)畫(huà)展示。SVG圖像及具體行為由XML文本文件定義,可以通過(guò)任何文本編輯器以及繪圖軟件來(lái)創(chuàng)建并編輯。目前所有主流web瀏覽器都支持渲染SVG圖像。
來(lái)觀察一個(gè)示例,更好理解SVG圖像。如下圖所示,我們編寫(xiě)了一些代碼來(lái)渲染SVG圖像:

圖1. simple.svg代碼片段
將該圖像保存為simple.svg,然后直接打開(kāi),或者將其包含在img/image/object/embed HTML標(biāo)簽中,如下圖所示:

圖2. 通過(guò)代碼渲染圖像
圖1代碼渲染生成的圖像如圖2所示,這是rect元素,瀏覽器會(huì)在x, y (100, 100)(即寬度和高度)位置渲染一個(gè)紅色矩形。
0x02 使用SVG的攻擊場(chǎng)景
雖然SVG提供了較大的靈活性,可以方便創(chuàng)建更多的動(dòng)態(tài)web內(nèi)容,但同時(shí)也引入了一些安全風(fēng)險(xiǎn)。在下文中,我們將討論一些常見(jiàn)的攻擊向量,我們?cè)诨ヂ?lián)網(wǎng)上的一些主流站點(diǎn)上都觀察到過(guò)這些攻擊方式。
跨站腳本
我們可以通過(guò)腳本方式來(lái)訪(fǎng)問(wèn)并修改SVG文檔的任何內(nèi)容,這與HTML操作方式類(lèi)似。默認(rèn)的腳本語(yǔ)言為ECMAScript(與JAVAScript密切相關(guān)),每個(gè)SVG元素及屬性都對(duì)應(yīng)已定義的DOM(Document Object Model,文檔對(duì)象模型)對(duì)象。相關(guān)腳本被封裝在<script>元素中。
這意味著如果web服務(wù)器允許用戶(hù)上傳任意SVG圖像,就存在XSS(跨站腳本)安全風(fēng)險(xiǎn)。如下所示,我們將腳本存放在圖像中:

圖3. xss.svg代碼片段
將該圖像保存為xss.svg,然后直接打開(kāi),如下圖所示:

圖4. 直接訪(fǎng)問(wèn)該文件觸發(fā)XSS
如果將該文件鏈接到某個(gè)HTML頁(yè)面,訪(fǎng)問(wèn)該頁(yè)面也可以觸發(fā),如下圖所示:

圖5. 通過(guò)鏈接文件觸發(fā)XSS
JavaScript代碼會(huì)在瀏覽器上下文中執(zhí)行,這意味著攻擊者可以使用該文件執(zhí)行惡意行為,比如竊取用戶(hù)隱私信息等。
HTML注入
在某些情況下,XSS payload會(huì)被服務(wù)端過(guò)濾,然而我們依然能夠通過(guò)SVG圖像的特定功能來(lái)注入HTML代碼。如前文所述,SVG是基于XML的一種矢量圖,因此我們無(wú)法簡(jiǎn)單將HTML內(nèi)容放入其中,不然會(huì)破壞XML的語(yǔ)法。
為了避免這種情況,SVG提供了一個(gè)foreignObject元素,可以用來(lái)包含來(lái)自其他XML命名空間的元素。在瀏覽器上下文中,這部分?jǐn)?shù)據(jù)很可能采用(X)HTML形式。
來(lái)看一下html.svg圖像:

圖6. html.svg代碼片段
當(dāng)我們?cè)趂oreignObject內(nèi)添加一個(gè)body標(biāo)簽以及XHTML命名空間時(shí),可以使用xmlns屬性來(lái)聲明命名空間。采用這種方式,瀏覽器會(huì)將body標(biāo)簽及其所有子標(biāo)簽解析為屬于XHTML的元素。因此,我們可以將來(lái)自SVG的任意XHTML代碼渲染到頁(yè)面中:

圖7. HTML注入漏洞
這種方式可以運(yùn)行任意HTML代碼,意味著我們可以簡(jiǎn)單從SVG圖像中發(fā)起類(lèi)似釣魚(yú)、繞過(guò)同源策略、CSRF之類(lèi)的攻擊。
XML實(shí)體:Billion Laughs Attack
由于SVG是基于XML的矢量圖,因此可以支持Entity(實(shí)體)功能。Entity可以用來(lái)定義特殊字符的快捷方式,也可以聲明成內(nèi)部或外部實(shí)體。
我們可以通過(guò)如下方式聲明內(nèi)部Entity:
<!ENTITY entity-name "entity-value">
通過(guò)如下方式聲明外部Entity:
<!ENTITY entity-name SYSTEM "URI/URL">
如果解析文件的XML解析器存在脆弱性,那么我們就可以濫用外部Entity功能來(lái)泄露內(nèi)部數(shù)據(jù)。由于現(xiàn)在大家主要使用的都是現(xiàn)代瀏覽器,因此我們假設(shè)可用的解析器都經(jīng)過(guò)fuzzer的嚴(yán)格測(cè)試,因此沒(méi)那么容易被攻擊。在這個(gè)前提下,這里我們主要討論如何濫用內(nèi)部Entity。
entity.svg的內(nèi)部實(shí)現(xiàn)如下所示:

圖8. entity.svg代碼片段
如上圖所示,我們?cè)诘?行定義lab這個(gè)Entity,然后在SVG元素中調(diào)用該實(shí)體。結(jié)果如圖9所示:

圖9. lab實(shí)體被加載到頁(yè)面
一切非常順利,來(lái)嘗試另一個(gè)例子:entity_2.svg,如下圖所示:

圖10. entity_2.svg代碼片段
結(jié)果如下:

圖11. lab2實(shí)體被加載到頁(yè)面
如上圖所示,這里的文本內(nèi)容被重復(fù)渲染,這表明我們可以使用Entity標(biāo)簽發(fā)起“ Billion Laughs ”攻擊。
“ Billion Laughs ”攻擊是一種DoS(拒絕服務(wù))攻擊,目標(biāo)是XML文檔解析器。這種攻擊也被稱(chēng)之為XML炸彈或者指數(shù)實(shí)體攻擊。

圖12. billion_laughs.svg代碼片段
我們的瀏覽器在解析這個(gè) billion_laughs.svg數(shù)據(jù)時(shí),只花了4~5秒就能正常響應(yīng)。這是因?yàn)榇蠖鄶?shù)現(xiàn)代瀏覽器已經(jīng)能夠能應(yīng)付這種攻擊,可以在渲染過(guò)程中解決該問(wèn)題,因此不會(huì)造成安全風(fēng)險(xiǎn)。
拒絕服務(wù):新型SVG “Billion Laughs”攻擊
在上一節(jié)中,我們發(fā)現(xiàn)“ Billion Laughs ”攻擊可以延緩瀏覽器的處理速度,瀏覽器需要4~5秒才能應(yīng)付該攻擊。不幸的是,攻擊者還可以通過(guò)SVG圖像,發(fā)起另一種“ Billion Laughs ”攻擊,繞過(guò)這些防御措施。
這一次我們使用xlink:href來(lái)代替XML Entity。來(lái)看一下 xlink_laughs.svg所使用的payload:

圖13. xlink_laughs.svg代碼片段
xlink:href屬性以IRI(國(guó)際資源標(biāo)識(shí))方式定義了對(duì)某個(gè)資源的引用,該鏈接的具體含義需根據(jù)使用該鏈接的每個(gè)元素的上下文來(lái)決定。
<use>元素從SVG文檔中獲取節(jié)點(diǎn),然后將其復(fù)制到其他位置。
我們現(xiàn)在a0中定義circle元素,然后在a1、a2、a3……中通過(guò)xlink:href屬性調(diào)用<use>元素,通過(guò)這種方式反復(fù)克隆circle。結(jié)果如下圖所示:

圖14. 在解析惡意SVG時(shí),通過(guò)xlink:href發(fā)起“ Billion Laugh”攻擊
需要注意的是,在最壞的情況下,大多數(shù)現(xiàn)代瀏覽器在嘗試解析網(wǎng)站上的這張SVG圖像時(shí)可能會(huì)發(fā)生崩潰,或者至少會(huì)出現(xiàn)無(wú)響應(yīng)情況。
有趣的是,我們?cè)跍y(cè)試某些開(kāi)源SVG/XML過(guò)濾器時(shí),發(fā)現(xiàn)這些過(guò)濾器并不能正確捕捉到圖13所示的SVG圖像。因此,這種錯(cuò)誤格式的SVG圖像也可能造成DoS效果。
0x03 總結(jié)
SVG圖像更像HTML,而不單單是一張簡(jiǎn)單的圖像。因此,我們建議web開(kāi)發(fā)者盡可能不要以對(duì)象或者iframe形式加載任何SVG。Web管理員同樣應(yīng)當(dāng)限制可以上傳到站點(diǎn)的文件類(lèi)型。
此外,任何不可信的SVG圖像在被上傳到服務(wù)端前都必須經(jīng)過(guò)過(guò)濾處理,可以采取如下操作:
- 限制危險(xiǎn)標(biāo)簽,比如script、foreignObject等。
- 限制通過(guò)SVG圖像的外部鏈接加載資源。
- 限制SVG圖像內(nèi)的擴(kuò)展邏輯。
我們使用一些瀏覽器來(lái)直接打開(kāi)這些惡意SVG文件,對(duì)比結(jié)果如下圖所示:

大家可以訪(fǎng)問(wèn)我們的Github倉(cāng)庫(kù)下載本文使用的SVG樣本。
0x04 參考資料
[1] W3C, “Scalable Vector Graphics” https://www.w3.org/TR/SVG2/ (02 September, 2019)
[2] OWASP, “The Image that called me” https://www.owasp.org/images/0/03/Mario_Heiderich_OWASP_Sweden_The_image_that_called_me.pdf (02 September, 2019)
[3] Blackhat, “Exploiting Browsers without Image Parsing Bugs” https://www.blackhat.com/docs/us-14/materials/us-14-DeGraaf-SVG-Exploiting-Browsers-Without-Image-Parsing-Bugs.pdf (02 September, 2019)
原文鏈接:https://www.anquanke.com/post/id/190651