Archive for April 16th, 2008

When I started implementing NoScript's Anti-XSS filters, about one year ago, they were admittedly over-zealous, detecting too many false positives.

But a lot of work has been done since then, and today I'm very proud of the Injection Checker component, which is capable of spotting reflective XSS attacks, no matter how exotic or obfuscated they are, with extreme accuracy and the lowest false positive rate.
A sla.ckers thread entirely dedicated to hacking NoScript has not gone much far (special thanks to Gareth Heyes, by the way, for the few issues he actually found). On the other hand, the engine became smart enough to recognize syntactically valid JSON as innocuous and let it pass through, while any Web IDS out there would just scream fire.

Hence the very few (3 in 3 months) false positive reports I received recently brought me to investigate the sites, rather than NoScript's behavior, and the finding have been quite interesting...

CNN: Vulnerable by Design

A NoScript user complains about popups on cnn.com triggering XSS warnings, and wants to know how to disable them.
I answer as I always do, asking him to open the Error Console and send me the lines starting with "[NoScript XSS]", which detail the URLs where the problems happen and the filtering actions taken by NoScript. In his case,

[NoScript XSS] Sanitized suspicious request.
Original URL [http://www.cnn.com/cnn_adspaces/dart_ads/2007/12/21/orbitz.html
?clk=http://ads.cnn.com/event.ng/Type%3dclick%26FlightID%3d103458
%26AdID%3d160329%26TargetID%3d1095%26Values%3d1588%26Redirect%3d
&imp=%3Cimg%20src%3D%22http%3A//ads.cnn.com%3A80/event.ng/Type%3Dcount%26ClientType
%3D2%26AdID%3D160329%26FlightID%3D103458%26TargetID%3D1095%26SiteID%3D1588
%26EntityDefResetFlag%3D0%26Segments%3D730%2C2592%2C2743%2C3030%2C3285%2C6298%2C8463
%2C8796%2C9496%2C9779%2C9781%2C9853%2C10381%2C13153%2C13760%2C14173%2C14248
%2C14401%2C14402%2C14734%2C14735%2C14736%2C14757%2C14758%2C14760%2C14863%2C14864
%2C14879%2C14887%2C14960%2C14961%2C15022%2C15031%2C15032%2C15033%26Targets%3D1095
%2C2742%2C1515%2C24516%2C26849%2C28114%26Values%3D30%2C46%2C50%2C60%2C72
%2C84%2C90%2C100%2C110%2C150%2C682%2C917%2C1067%2C1285%2C1557%2C1588
%2C1601%2C1604%2C1678%2C1735%2C1815%2C2677%2C4405%2C4413%2C4418%2C4438
%2C37353%2C47181%2C47458%2C49282%2C49553%2C49657%2C49935%2C52263%2C52508%2C52897
%2C54681%2C54738%2C54765%2C55058%2C55059%2C55695%26RawValues%3D
%26random%3Dkxauis%2CbdWjwiovNwhlK%22%20width%3D1%20height%3D1%20border%3D0%3E
&rand=kxauis,bdWjwiovNwhlK]

Careful readers already noticed the weird imp parameter, which can be unescaped into

<img src="http://ads.cnn.com:80/event.ng/Type=count&ClientType=2&
[...]random=kxauis,bdWjwiovNwhlK" width=1 height=1 border=0>

Ehy, they're passing HTML fragments around in query parameters... no wonder NoScript cries. But they're the CNN, they surely know what they're doing and won't allow arbitrary injections, will they? Let's look at the code, perhaps we'll learn some new best practice:

<script language="javascript"><!--

//SCRIPT TO PARSE PASSED VALUES

var clk;
var imp;
var rand;
var urlQuery = ( location.search ) ? location.search : '';
var queryString = (( urlQuery != '' ) && ( location.search.charAt( 0 ) == '?' )) ? urlQuery.substring( 1 ) : urlQuery;
var pairs = queryString.split("&");

Thanks for this wonderful tip on how to write

var pairs = location.search.replace(/^\?/, '').split("&");

in a maintenable and readable form! Let's dig for other treasures...

for (i=0; i < pairs.length; i++) {

var pos = pairs[i].indexOf('=');
if (pos == -1) continue;
var argname = pairs[i].substring(0, pos);
var value = pairs[i].substring(pos+1);

Right, one

split()

per script is enough: let's revert to good old string manipulation, especially in loops!

if(argname == "clk") {
clk = value;
clk = unescape(clk);
}
if (argname == "imp") {
imp = value;
}
if(argname == "rand") {
rand = value;
}
}

Mmm, they're clearly parsing query parameters into variables. Wonder what they want to do with them?

//SCRIPT TO WRITE CLIENT CODE WITH CLICKTHRU

document.write("<IFRAME SRC='http://ad.doubleclick.net/adi/N2870.cnn/B2094897;sz=720x300;click="+
clk+";ord="+rand+
"?' WIDTH=720 HEIGHT=300 MARGINWIDTH=0 MARGINHEIGHT=0 HSPACE=0 VSPACE=0 FRAMEBORDER=0 SCROLLING=no BORDERCOLOR='#000000'>");
document.write("</IFRAME><br><br>");

Ahem, were clk and rand entity-escaped? Looks like they already put a couple of XSS insertion points here...
But the best part has to come yet:

//SCRIPT TO WRITE $SMARTCOUNT$

imp = unescape(imp);
document.write(imp);
-->
<script language="javascript">

Ouch, $SMARTCOUNT$ is the <img> code above (likely a tracking image), ant it gets injected verbatim inside the page!

So, to recap, CNN advertising system intentionally uses XSS to insert Web Bugs, and calls this clever solution Smart Count!

CeBIT: Even More Vulnerable by Design

For those who don't know it, "CeBIT is the world's largest trade fair showcasing digital IT and telecommunications solutions for home and work environments".

Date: 17 Feb 2008 19:52:43 +0100
Subject: XSS false positive on CEBIT.DE

Hi,

I experienced problems using noscript on http://www.cebit.de/ when
registering tickets online. Just try to login as a test. Even when
allowing JS in Noscript it still complains about loading insecure
content. Will be an issue for quite a lot german users in the next month.

Thanks for your great work!

Greetings from Germany,
Jan

Date: 17 Feb 2008 20:12:01 +0100
Subject: Re: XSS false positive on CEBIT.DE [NoScript]

Hi Jan,

it's not a false positive.
The registration system is quite brain damaged, using XSS to communicate back and forth.
Whoever implemented it, has no idea of what web security is.

The "false positive" URL is

http://www.cebit.de/suche/registrationController.html?backval=
%3Chtml%3E%0A+%3Chead%3E%0A++%3Cscript+language%3D%22javascript%22%3E
%0A++++try+%7B%0A+++++if+%28parent.callback_login%29+%7B
%0A++++++parent.callback_login%28%27-1%27%29%3B%0A+++++%7D
%0A++++%7D+catch+%28e%29+%7B%0A++++++alert%28e%29%3B
%0A++++%7D%0A++%3C%2Fscript%3E%0A+%3C%2Fhead%3E
%0A+%3Cbody%3E%0A+%3C%2Fbody%3E%0A%3C%2Fhtml%3E%0A

or, unescaped:

http://www.cebit.de/suche/registrationController.html?backval=
<html><head><script language="javascript">
try { if (parent.callback_login) { parent.callback_login('-1'); } }
catch (e) { alert(e); } </script></head>
<body></body></html>

As you can see it's a whole web page, including script, posted as a "backval" variable to be injected, smelling a gaping vulnerability.

Just try this "classic" PoC:

http://www.cebit.de/suche/registrationController.html?backval=
<script>alert(document.cookie)</script>

So, NoScript is absolutely right and they need to fix their site as soon as possible.

Cheers
--
Giorgio

Date: 17 Feb 2008 20:32:35 +0100
Subject: Re: XSS false positive on CEBIT.DE [NoScript]

Hi,

ok you are right. Its braindead. Sorry, I did not really check it! Looks quite exploitable. I will inform cebit and later the press (heise.de).

Greetings,
Jan

Opening http://www.cebit.de/ with cebit.de in your NoScript whitelist still triggers (rightful) XSS notifications because of a full web page embedded in the query string.
The only difference now is that an extra parameter called

code

has been added: from a cursory inspection, it seems they're checking some hash of the HTML (probably stored in session) before inserting. A poor patch for a sublimely poor design...

TypePad: OK, Shit Just Happens

Date: 15/04/2008 22.17
Subject: NoScript Bug

You guys make NoScript, right?
[...]
You might want to add ^http://www.typepad.com/t/comments$ to the
default Anti-XSS Protection exceptions. It's ridiculously common and
it always triggers an "unsafe reload" but you can't post to TypePad
blogs without allowing it and I don't think it's actually harmful.

- Matt

From a philosophical point of view, TypePad stands way better than CNN and CeBIT: at least they seem to know XSS is dangerous and don't "use" it by design.
However that very URL is vulnerable at first shot, and it may even be a persistent injection (I didn't verify, because the test blog was moderated).
Considering that it's "ridiculously common", I do think it's "actually harmful".

Conclusion

Given the current sensitivity/accuracy balance of NoScript's Injection Checker, I'm unlikely to add any new default XSS Protection exception: I'm actually more inclined to remove the three original ones.
But if you're the owner of a ridiculously popular "web property" and you feel you deserve a XSS filtering exemption, feel free to contact InformAction's sales department and request a quotation for a full "NoScript Certified" Package (vulnerability scanning + web security assessment + code audit + weekly test annual subscription). It's gonna be ridiculously expensive and no, Scanless PCI definitely cannot surrogate ;)

Bad Behavior has blocked 3532 access attempts in the last 7 days.