Monday, 16 July 2012

NoNoScript : ByPassing NoScript's XSS filters via Error Basd SQLi

NoScript is a firefox add-on or `extension' in charge of stopping reflected XSS attacks. It operates by inspecting and auditing responses---much like other XSS filters---AND requests made by browsers.

Largely NoScript provides a great service, and manages to stop most attacks provided that the injection data is recognizable in the requests---meaning both POST and GET requests. Though because of how it works, when injection data
is not recognizable in requests, NoScript---and for that matter no other XSS filters---will be able to detect the attacks. This largely happens when data is injected in encrypted/hashed/encoded* format.  

granted some encodings are accounted for in NoScript and other XSS filters, don't expect to get around the best XSS filters known to man by simply %-encoding your injection data!

One example of a XSS attack where payloads are injected in a way that is not
recognizable to NoScript is in SQL injections. Namely Error Based SQL injection. The following demonstration will show you how to beat NoScript using
MySQL error based injection.

Please note this only works after the user has given the domain permissions to execute javascript. The bypass here does not affect how NoScript denies javascript execution, but how it detects reflected XSS attacks, in "trusted"  domains.

If you don't know how Error Based injection works you can check out some of the these articles, before proceeding.
I assume at this point you guys all have the 411 on Error Based SQL injection especially with MySQL.

NoScript will stop most run of the mill Error Based SQL injection attacks, to prove this I'll show you some attack vectors and their results.

for the purposes of this demonstration i'll be showing you the attacks using DVWA [] I've always found it handy :)

The first vector I tried was one that would work in most injection attacks because requires that you are injecting inside the WHERE/INSERT--or for that matter anywhere a select statement can occur---clause without the need for UNION-ing on the SELECT you want to perform. It also requires no knowledge of the database structure and very basic permissions to perform.

if you're just finding out about SQL injection, what I just said means that this attack vector works in most run of the mill injection vulnerabilities. When trying to determine whether something is injectable you need to determine what kind of query and where in the query you find yourself injecting statements before you can begin exploiting your target. Anyway cracking on...

It looks like this:'||row(1,1)>(select count(*),concat((select XSS_payload),floor(rand()*2))x from (select 1 union select 2)a group by x limit 0,1) || '1'='a

Where XSS_payload would be something like:
<script>alert("Problem NoScript?");</script>
which I would encode---you could probably use other encoding that MySQL knows about---for simplicity I'm using hex:
select hex('<script>alert("Problem NoScript?");</script>');
which is:
 3C7363726970743E616C657274282250726F626C656D204   E6F5363726970743F22293B3C2F7363726970743E
you obviously need to pass this back into ascii using the `cast' function in MySQL, so that the web application will echo it back in the response and execute the javascript. So in its full glory the attack will look like this:'||row(1,1)>(select count(*),concat((select cast(0x3C7363726970743E616C657274282250726F626C656D2 04E6F5363726970743F22293B3C2F7363726970743E as char)),floor(rand()*2))x from (select 1 union select 2)a group by x limit 0,1) || '1'='a
The following screen shot shows how NoScript responds to a similar attack,
The request that NoScript blocks here is almost exactly the same as the one above except I'm trying to enumerate the username of the database connection.'||row(1,1)>(select count(*),concat(user(),floor(rand()*2))x from (select 1 union select 2)a group by x limit 0,1) || '1'='a
You will find that for the purposes of the demonstration its actually the same

Why is NoScript blocking this? Because NoScript actually does contain some anti-SQLi tech, the word 'union' in the query above is setting off the alarms.

So i re-hashed the vector, by removing the need to select from a derived table,
---`(select 1 union select 2)a'.I created collisions in grouping key by selecting from the information_schema.TABLES table. Any known table will do as long as it has at least one or two rows.

I've come across some hairy situations where the DB admin had denied select queries to the information_schema database (*_*)

The attack then looked like this:'||row(1,1)>(select count(*),concat((select cast(0x3C7363726970743E616C657274282250726F626C656D2 04E6F5363726970743F22293B3C2F7363726970743E as char)),floor(rand()*2))x from information_schema.TABLES a group by x limit 0,1) || '1'='a
And the result?

and we can see that NoScript actually runs the javascript!

please note:
I demonstrated the attacks a few hours before writing this post, and used screen shots from the events in this post, the attack vectors in the post i had to recreate myself, so if there are things like syntax errors or chars missing here and there I apologize. I'm quite confident that the attack vectors in the post will work fine though. I just thought I'd mention this for the sake of honesty.

How about adding proper protection agains SQLi in no script? or maybe a separate extension all together? Just a thought!

NoScript has fixed this issue, the latest development build is available at: