溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何通過欺騙性的React元素實現(xiàn)XSS

發(fā)布時間:2021-12-18 15:18:06 來源:億速云 閱讀:196 作者:柒染 欄目:安全技術(shù)

這篇文章給大家介紹如何通過欺騙性的React元素實現(xiàn)XSS,內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。

相關(guān)角色介紹

HackerOne 是一個安全響應(yīng)和漏洞賞金的平臺,口號是「從頭開始 (構(gòu)建),并把安全作為頭等大事」。創(chuàng)建 HackerOne 的團(tuán)隊包括了幾名安全工程師和滲透測試人員,因此,能夠在他們的網(wǎng)站上發(fā)現(xiàn)漏洞,我感到非常興奮。

React 是一個流行的 JavaScript 庫,用于構(gòu)建用戶界面。

我是 Trello(一個團(tuán)隊協(xié)作應(yīng)用)的一名開發(fā)人員,并且負(fù)責(zé)運營 Trello 在 HackerOne 上的漏洞賞金項目。偶爾,我也會嘗試在我使用的應(yīng)用中發(fā)現(xiàn)安全問題。

背景

這個問題是由我以前針對 HackerOne 的另外一個 XSS 漏洞,一個暫定還未公開披露的報告以及一個CSP繞過漏洞而引起的。

發(fā)送非法的 JSON 數(shù)據(jù)

當(dāng)我在尋找安全問題時,我花費了大量的時間嘗試創(chuàng)建「意外」的情況。一個網(wǎng)站要求我填寫名字,我給它發(fā)送一些 HTML。他們要求我填寫 URL,我給他們一個 URL,其中包含了一堆的引號,換行符,空字符等等。你明白我的意思了吧。

瀏覽 HackerOne 網(wǎng)站時,我查看了一些發(fā)送的 AJAX 請求,注意到其中的一些請求將復(fù)雜的 JSON 對象作為請求體來發(fā)送,例如:

{
state: "open",
substate: "triaged",
report_ids: [ 49652, 46916 ],
reply_action: "change-state",
reference: "http://danlec.com"
}

我嘗試發(fā)送類似的請求,并將某些字段設(shè)置為我認(rèn)為無效的類型。例如,在期望的參數(shù)類型是數(shù)字的地方,發(fā)送一個字符串類型的值 danlec?;蛘咴谕ǔ?yīng)該發(fā)送字符串類型的地方,發(fā)送一個數(shù)組。例如:

{
state: { "foo": "danlec", "bar": 42 },
substate: 3.2,
report_ids: [ "xyzzy", 46916 ],
reply_action: [2, "change-state"],
reference: { "a": 1, b: ["2"] }
}

不出意外地,這些值幾乎普遍被拒絕了,或者被轉(zhuǎn)換為適當(dāng)類型的值(例如,{ 'foo': 'bar' } 可能會轉(zhuǎn)換為字符串類型'{ "foo" => "bar" }')。

然而,在有些地方,錯誤類型的值并沒有直接被拒絕,而是從服務(wù)器返回。也就是說,似乎錯誤類型的值被存儲了,并在后續(xù)的 API 調(diào)用的響應(yīng)中被返回了。

我發(fā)現(xiàn)了兩個例子,一個是名為 reference 的字段,被用來對報告進(jìn)行分類。另一個是名為 data 的字段,該字段與觸發(fā)器條件關(guān)聯(lián)。

不幸的是,盡管這絕對是奇怪的,但實際上這些錯誤類型的值被安全地渲染到頁面上了。我無法立即想到利用此行為的方法。我將其添加到有潛力進(jìn)行深度挖掘的 bug 列表中。

幾乎放棄

在接下來的一周中,我不斷重試這個 bug。我嘗試了幾種不同的值,雖然我無法做任何的壞事,但我確實注意到有些值被奇怪地渲染了。

通常,像"foo"這樣的字符串值將被渲染為類似于

<span>foo</span>

我注意到當(dāng)該值改為一個數(shù)組時,比如 ["foo", "bar"],它會被渲染為

<span><span>foo</span><span>bar</span></span>

甚至更令人興奮的是,當(dāng)使用 { foo: "bar" } 之類的對象時,在渲染時,foo 被包含在了 span 元素的 react-id 屬性中,例如

<span react-id="…1.2.3.foo.…">bar</span>

我肯定能對最終渲染出來的 DOM 元素產(chǎn)生一些影響,但是負(fù)責(zé)渲染的代碼在內(nèi)容凈化(對非法字符進(jìn)行轉(zhuǎn)義)方面做得很好。我仍然無法利用它做任何不好的事情。

我已經(jīng)準(zhǔn)備要把這個 bug 提交了,并定義為「它是個奇怪的東西,很可能是一個 bug,但沒有任何安全隱患」。但是我決定最后一次嘗試,看看是否可以通過單步調(diào)試負(fù)責(zé)渲染元素的客戶端代碼來找到任何東西。

單步調(diào)試 minified JS

在錯誤類型的值被渲染的地方設(shè)置了斷點之后,我開始逐步調(diào)試所有代碼,來看看是否有什么有趣的事情可以為我所用。大多數(shù)字符都被壓縮了(minified JS 文件中,變量名通常會被替換成隨機單個字符),所以并不總是很清楚到底發(fā)生了什么,但是當(dāng)我看到錯誤類型的值被傳遞給這個函數(shù)時:

l.isValidElement = function(e) {
var t = !(!e || !e._isReactElement);
return t
}

我開始變得興奮。(這是安全性研究中真正有趣的部分,你知道自己發(fā)現(xiàn)了一些不好的東西,現(xiàn)在你只需要弄清楚它到底能有多糟糕)

我已向自己證明了,我可以使 e 變成任何我想要輸入的 JSON 值。所以,不需要任何技巧,便可以創(chuàng)建一個對象并且將其_isReactElement 的值設(shè)置為 true,這似乎可以告訴客戶端我創(chuàng)建的這個對象是一個「有效的元素」。

一旦我添加_isReactElement,和其他幾個鍵(_store,type,props),我創(chuàng)建的對象會使用一種完全不同的渲染方式,這種方式最終會檢查 dangerouslySetInnerHTML 屬性?,F(xiàn)在有了一個看起來很有趣的屬性可被操作。

顯然,該屬性名稱正試圖警告我,包含原始 HTML 是很危險的。但是,當(dāng)然,我對于將 dangerouslySetInnerHTML 屬性添加到偽造的 React 元素中沒有任何的不安。一旦該屬性設(shè)置好之后,render 方法會渲染出我傳入的 HTML 片段,允許任意 HTML 注入,XSS 等。

漏洞利用已實現(xiàn)!

那么……這里實際上發(fā)生了什么?

當(dāng)我使 XSS 正常工作后,就會回退一步來弄清楚實際發(fā)生了什么。HackerOne 使用 React,結(jié)果證明 React 的 createElement 方法有一個參數(shù),期望接受的值是一個 React 節(jié)點,可以是字符串(對于簡單的文本內(nèi)容)或者是數(shù)組,或者是 React 元素。

還記得我是怎么注意到有時我的輸入會被渲染成多個 span 嗎?

我嘗試從控制臺運行一些 React 方法,結(jié)果很清楚實際發(fā)生了什么:

> React.renderToString(React.createElement("span", null, "abc"))

"<span data-reactid=".7" data-react-checksum="-876606633">abc</span>"

> React.renderToString(React.createElement("span", null, ["abc"]))

"<span data-reactid=".8" data-react-checksum="-171174425">
<span data-reactid=".8.0">abc</span></span>"

> React.renderToString(React.createElement("span", null,
{ foo: "bar" }))

"<span data-reactid=".a" data-react-checksum="1979389930">
<span data-reactid=".a.$foo:0">bar</span></span>"

HackerOne 的客戶端代碼中,假定它傳遞的值始終是一個字符串,但是我能夠讓它傳遞我特意構(gòu)造的 JSON 對象,并且通過設(shè)置正確的屬性,使 React 認(rèn)為它正在渲染一個元素。

dangerouslySetHTML 是一個特殊的非 DOM 屬性,用于提供插入原始 HTML 到元素中的這種功能,這正是像我這樣的 XSSer 所尋找的。

我使用的是完整的 JSON 對象,而不是 HackerOne 期望的字符串,類似于

{
_isReactElement: true,
_store: {},
type: "body",
props: {
dangerouslySetInnerHTML: {
__html:
"<h2>Arbitrary HTML</h2>
<script>alert('No CSP Support :(')</script>
<a href='http://danlec.com'>link</a>"
}
}
}

在控制臺上渲染這個 JSON 對象:

> React.renderToString(React.createElement("span", null,
{ _isReactElement: true, …}))

"<span data-reactid=".9" data-react-checksum="-1151650166">
<body data-reactid=".9.0"><h2>Arbitrary HTML</h2>
<script>alert('No CSP Support :(')</script>
<a href='http://danlec.com'>link</a></body></span>"

關(guān)于如何通過欺騙性的React元素實現(xiàn)XSS就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI