JSON rendering in Internet Explorer
In the world of Web2.0 and mash web applications, security researchers come across more and more XSS vulnerabilities that are reflected in non HTML responses.
For example, JSON responses are becoming more and more common, but exploiting XSS vectors in those pages is considered theoretical because browsers pop up the file download dialog instead of rendering the response when the returned content-type is application/json or application/javascript.
There are a few known methods to indirectly exploit these issues:
1. Attacking the JSON parsing mechanism:
Some applications use JS evaluation functions in order to create an object from the returned JSON content. If the attacker is able to inject, for example, a quote sign, he can break out of the JS string surrounding the value and exploit the XSS through the eval function. For example:
"name":"Foo "+alert(/XSS/.source)+"Bar"
2. Waiting for document.write:
Some applications will write parts of the data returned in the JSON response to the DOM. An attacker can inject HTML content into the JSON response that will be rendered once the application writes it to the page. For example:
"name":"Foo <img src=x onerror=alert(/XSS/.source)>Bar"
Although the previous methods will work, they have a few limitations:
Not all applications have the logical flow needed in order to exploit these attacks.
Some applications use client side filtering that will prevent them from running.
After thorough research on alternative ways to exploit these types of vulnerabilities, we have discovered a way to render JSON responses in IE by direct browsing.
The way IE decides what content-type will be used for a specific response is as follows: (As discovered by Black-Box research)
The suggested (server supplied) content-type is searched for in the windows registry for the corresponding CLSID, in order to find the correct handler for that response.
If the suggested content-type is found, IE will consider that to be the final content-type.
If the suggested content-type however is not found, IE will attempt to figure out the content-type based on the file extension and other vectors.
JSON responses generally use the content-type application/json, the problem is that the default mime type list of Internet Explorer does not include that mime-type, in fact it does not include any JSON mime type whatsoever.
Example scenario while browsing to a link which returns JSON content:
User browses to http://attacker.site/json.php
Internet Explorer searches the windows registry (HKCR\MIME\Database\Content Type\) for the returned content-type (application/json). Not found.
Internet Explorer searches the windows registry (HKCU\Software\Classes\) for the file extension (.php) Not found.
Internet Explorer prompts the file download dialog.
From this scenario we can conclude that in cases where the server returns content-types that are unknown to Internet Explorer, the file extension (in addition to other factors not covered here) dictates the final content-type that will be used.
In order to force IE to render JSON responses, the file extension in the URL must be set to something that IE consider as text/html (.htm or .html).
The way most web servers parse the path from a request is this:
The user requests the page http://www.some.site/html/pages/page.php?id=1
The server starts to search for the requested resource at the pre-defined path of the web server (for example /var/www/)
The server searches for the path requested by the user one entity at a time (starting from left).
The server finds that /html/pages/page.php is an executable file and stops the search (executable means that the server has some handler that correlates to that file type; in this case the PHP engine).
The rest of the path (id=1) is then passed as a parameter (GET) to PHP.
Most server side languages (.Net, PHP, Python, Perl
) accept another type of parameter to be passed from the URL: Path-Info.
Unlike the GET parameter, in which the delimiter value is the question mark sign (?), path-info uses the slash sign (/) as its delimiter.
For example the previous path for page.php can be expanded into having a path-info:
http://site.com/html/pages/page.php/user=2?id=1
[scheme]://[domain][path]/[path-info]?[get-query]
Once an attacker combines path-info with IE's way of considering content-type values, a wide method of exploiting JSON responses for XSS is achievable.
Consider the following scenario:
The attacker found a reflected XSS in a web application.
When browsing to "http://www.some.site/page.php?user=bla<img onerror=alert(1) src=x>bla" Internet Explorer pops up the file download dialog (explained in the beginning of this document).
The attacker now adds the value ".html" as a path-info to the URL
The attacker now browses to: http://www.some.site./page.php/.html?user=blah<img onerror=alert(1) src=x>blah
The server returns the same page (containing XSS) with same content-type (application/json)
Internet Explorer searches the windows registry for the application/json content-type and cannot find it.
This is the point where Internet Explorer uses the file extension of the URL to determine the content-type of the response, only this time the extension IE sees is .html!
Internet Explorer finds the matching content-type for .html files to be text/html, renders the response and fires up the XSS.
Impact:
Client side, tested successfully on:
Internet Explorer 6
Internet Explorer 7
Internet Explorer 8
Internet Explorer 9Server side, tested successfully on:
IIS 5.1 (ASPX , PHP)
IIS 6 (ASPX , PHP)
IIS 7.5 (ASPX , PHP)
Apache/2.2.14 (PHP)
Remediation:
Client side:
The following registry key will add the content-type application/json and a corresponding CLSID
[HKEY_CLASSES_ROOT\MIME\Database\Content Type\application/json]
"CLSID"="{3050f4d8-98B5-11CF-BB82-00AA00BDCE0B}"Server side:
In order to remediate this issue in the server side, beyond the normally recommended sanitization of user supplied inputs, we recommend turning off support of Path-Info.