Tag: Flash
2013
04.16

Summary

I found a reflected XSS vulnerability in JW Player 5. The developers at LongTail Video have released JW Player 6, which is not vulnerable to this issue. They do not plan to update JW Player 5 to mitigate this vulnerability; I would encourage people to discontinue using JW Player 5 or manually patch/build their own version as a result.

How does it work?

I was aware of a previous vulnerability in JW Player 5 which the developers had attempted to patch. The original issue is documented in the LongTail Video Trac as Ticket 1626; the problem was that the playerReady parameter to the SWF accepted an arbitrary string and used it as a callback function to ExternalInterface.call. That behavior is roughly equivalent to calling eval on the value of the playerReady parameter and allowed for XSS and other badness. There are two relevant diffs, which made changes as follows:

  • 2164: Instead of an arbitrary callback string, the callback string may only contain alpha-numeric characters and periods.
  • 2165: Instead of a callback string containing only alpha-numeric characters and periods, the callback string can have any characters except for curly braces and parentheses.

So, the challenge for exploitation was to find a way to execute JavaScript without parentheses or braces. Turns out this was really easy[1], [2]: I used the following code (the comment was needed because of the context in which the code was being executed):

1
document.location=window.name+'//'+

I could then embed arbitrary JavaScript into window.name by convincing users to click on links with ‘target’ attributes I specified.

Proof of Concept

A proof of concept is available at sandboxing.me. The JavaScript executes in the context of the player’s domain, not in the context of sandboxing.me.

How can it be patched

  1. Discontinue use of JW Player 5. Upgrade to JW Player 6 or use another player.
  2. If you would like to build your own SWF, you can apply the changes to src/com/longtailvideo/jwplayer/player/JavascriptAPI.as from revision 2267. This disables the use of dynamic callbacks for playerReady altogether. If you rely on a custom playerReady callback, you will need to modify your JavaScript; you will need to declare a function on your page called playerReady which in turn calls your custom function.

Disclosure Timeline

  • December 28th, 2012, 11:10 AM: Contacted LongTail Video via their support form with details of the vulnerability.
  • December 28th, 2012, 11:39 AM: Received reply asking me to upgrade to JW Player 6.
  • December 28th, 2012, 5:52 PM: Sent reply asking for clarification about the end-of-life status of JW Player 5 and whether a patch would be released.
  • December 29th, 2012: Received response from developer: “There may be a 5.11 version out to address some of these issues, but since they are already fixed in V6, 5.10 might be the last version of the V5 player.”
  • April 16th, 2013: Published this blog post
2012
05.17

Summary

Nathan Partlan and I discovered and reported vulnerabilities in two common Flash applets, SWFUpload and Plupload. SWFUpload’s developers have not released a fix for the XSS issue identified. Plupload’s developers have released v1.5.4 to address the identified CSRF issue.

Both of these applets are present in Wordpress installations. These vulnerabilities were addressed as part of Wordpress 3.3.2.

Vulnerability #1: XSS in SWFUpload (CVE-2012-3414)

The latest version of SWFUpload (ActionScript code available here) contains the following code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Get the movie name
this.movieName = root.loaderInfo.parameters.movieName;

// **Configure the callbacks**
// The JavaScript tracks all the instances of SWFUpload on a page.  We can access the instance
// associated with this SWF file using the movieName.  Each callback is accessible by making
// a call directly to it on our instance.  There is no error handling for undefined callback functions.
// A developer would have to deliberately remove the default functions,set the variable to null, or remove
// it from the init function.
this.flashReady_Callback         = "SWFUpload.instances[\"" + this.movieName + "\"].flashReady";
this.fileDialogStart_Callback    = "SWFUpload.instances[\"" + this.movieName + "\"].fileDialogStart";
this.fileQueued_Callback         = "SWFUpload.instances[\"" + this.movieName + "\"].fileQueued";
this.fileQueueError_Callback     = "SWFUpload.instances[\"" + this.movieName + "\"].fileQueueError";
this.fileDialogComplete_Callback = "SWFUpload.instances[\"" + this.movieName + "\"].fileDialogComplete";

this.uploadStart_Callback        = "SWFUpload.instances[\"" + this.movieName + "\"].uploadStart";
this.uploadProgress_Callback     = "SWFUpload.instances[\"" + this.movieName + "\"].uploadProgress";
this.uploadError_Callback        = "SWFUpload.instances[\"" + this.movieName + "\"].uploadError";
this.uploadSuccess_Callback      = "SWFUpload.instances[\"" + this.movieName + "\"].uploadSuccess";

this.uploadComplete_Callback     = "SWFUpload.instances[\"" + this.movieName + "\"].uploadComplete";

this.debug_Callback              = "SWFUpload.instances[\"" + this.movieName + "\"].debug";

this.testExternalInterface_Callback = "SWFUpload.instances[\"" + this.movieName + "\"].testExternalInterface";
this.cleanUp_Callback            = "SWFUpload.instances[\"" + this.movieName + "\"].cleanUp";
this.buttonAction_Callback       = "SWFUpload.instances[\"" + this.movieName + "\"].buttonAction";

Each of those callbacks is used as the first parameter to ExternalInterface.call, which executes JavaScript in the context of the current page. Since movieName is derived from user input (a Flash parameter) and a Flash applet can be loaded directly (with parameters in the URL), the Flash applet allows for reflected cross-site scripting. For sites where the applet is hosted on the same domain as the main website, this is a serious security concern.

At this point, I’m not aware of a patched version of the applet source (let me know in the comments if there is one!). My suggestion would be to filter the movieName parameter so that only alpha-numeric characters are allowed.

Proof of Concept: http://demo.swfupload.org/v220/swfupload/swfupload.swf?movieName=%22%5d%29;}catch%28e%29{}if%28!self.a%29self.a=!alert%281%29;//

Vulnerability #2: CSRF in Plupload (CVE-2012-3415)

The Plupload applet called Security.allowDomain('*') to allow the applet to be used from any domain (so it could be served from S3, for instance). That meant people could interact with the Plupload applet from any other site on the Internet by embedding it on a page and using JavaScript. But due to the way the same-origin policy works in Flash, the applet could still make requests back to the domain on which it was hosted. In addition, people can specify the full URL for an upload request via JavaScript and the result of that request (ie: the HTML of the resulting page) is passed back via JavaScript to the embedding page.

So, if an attacker could convince a target to interact with the applet (by selecting a single file to be uploaded), the attacker could make a request to the domain that the applet was hosted on and read back the full response. That could disclose CSRF tokens or other sensitive information. This issue was especially important for Wordpress installations, where Plupload applets are hosted inside of the wp-includes directory by default.

The issue was resolved by removing the call to Security.allowDomain('*') by default.

Conclusion

Third-party Flash applets are vulnerable to many of the same sorts of attacks as other parts of web applications. However, they are often included in sites without a proper understanding of the security risks.

Update (08/01/2012): I’ve updated the post to include the CVE identifiers assigned to these vulnerabilities.

2010
12.31

Yesterday, I ran across a very interesting XSS vulnerability involving Flash embeds and Wordpress.com. The vulnerable code is now patched (even during the holidays, Automattic’s response time was stellar), so here are all the juicy details. ;-)

In the interest of security, Wordpress.com limits what HTML elements its users are allowed to post on their blogs. Anyone who’s interested can read about those limits on the Wordpress.com site. However, to allow users to embed different types of content (i.e. videos, music, etc), Wordpress.com supports a series of “shortcodes.” These codes are typically created for trusted websites (i.e. YouTube) and allow users to embed content without using HTML directly.

It turns out that VodPod, one of the websites with a Wordpress.com shortcode, provides a way to embed third party content. It does so by generating a URL like http://widgets.vodpod.com/w/video_embed/ExternalVideo.12345 which 301 redirects to your content hosted elsewhere. The Wordpress.com shortcode, when parsed, becomes an embed tag using the VodPod URL. Your browser will happily follow the redirect, allowing any SWF to be displayed within a Wordpress.com blog.

Now, under normal circumstances, that wouldn’t be an issue. These days, just the act of embedding a Flash applet on your page doesn’t cause security issues. However, there was a tiny issue with the HTML that Wordpress.com generated for embeds from VodPod. I’ve reproduced the bad embed code below:

1
2
3
4
5
6
7
<embed
src='http://widgets.vodpod.com/w/video_embed/ExternalVideo.12345'
type='application/x-shockwave-flash'
AllowScriptAccess='always'
pluginspage='http://www.macromedia.com/go/getflashplayer'
wmode='transparent'
flashvars='' width='425' height='350' />

The problem? The embed tag contained AllowScriptAccess='always'. According to Adobe’s documentation, that meant the embedded SWF could execute JavaScript in the context of the page it was being displayed on. Coupled with the ability to embed arbitrary SWFs from third parties, it made an XSS attack against Wordpress.com possible.

So, I shot off an email to Automattic’s security email address with the details: I received a reply very quickly and the vulnerability was patched (by changing the value for AllowScriptAccess to sameDomain) within a few hours. A very happy ending to this holiday tale. :)