Practical Blind-Error Based SQL Injection

Its me again! So in the previous post I talked about Blind-Error Based injection and basically showed the select query you can use to conditionally force errors while still leaking content from the database. This all happened from within a MySQL prompt, not much use to those who want to see the attack in action. Here I'm going to do just that, show you a practical example of the attack against an actual web application.

I'll be using the mod_security challenge set up by spiderlabs a about year ago. It may still ring all the mod_sec alarms but the purpose is not to threaten mod_sec---not yet---instead to show what the attack would look like in full swing.

So before we start leaking information, its good to make sure we have the right query form and that we are injecting the query the right way, no syntax mistakes here!

Here's a screen shot of me doing this:
Making sure I have the correct query form
The omnibar is quite small in the screenshot so I'll dump the payload here for you to see: || row(1,1)=(select count(*),count(*) from information_schema.TABLES)
 you can click on it to give it a go.
Anyway so we know that we can inject with out any worries or obstructions, lets find out what an error indication looks like, I do this by forcing a grouping key error, like so:
The application indicates a grouping-key error like this, we know that because the previous query had no syntax errors the only problem with this could be the grouping key
So every time we see this piece of text on the screen, we know that we successfully forced an error---successfully forcing errors is something you'll only find hackers trying to do lols---, we can now move on to extracting data.

I'll need convince you that this works so I'll retrieve something that you can verify yourself, for instance the letter 'a' like i did in the previous post.

And here we go extracting the first bit of 'a':
this indicates that the first bit is 1
It logs an additional error but thats no biggy its still telling us exactly what we want to hear. This just indicated that the first bit is 1, here's the payload for those of us with normal eye sight:||%20row(1,1)%3E(select%20count(*),char(109)%20from%20information_schema.TABLES%20group%20by%20(select%20case%20when%20substring(bin(ascii(substring((select%20char(97)),1,1))),1,1)=TRUE%20THEN%20floor(rand(0)*2)%20ELSE%201%20END))
and just the augmented query on its own is:
|| row(1,1)=(select count(*),char(109) from information_schema.TABLES group by (select case when substring(bin(ascii(substring((select char(97)),1,1))),1,1)=TRUE THEN floor(rand(0)*2) ELSE 1 END)) 
we need to do this seven times and then look at what we've extracted to verify the information, brace yourself more screen shots are coming:
bit#2 = 1

bit#3 = 0

bit#4 = 0

and finally the last bit#7:

So after all that we know that the data's binary value is 1100001 here's solid proof that we just extracted an 'a':

And that's that, I'll be following up this post with more variants of this attack, e.g how to force other kinds of error's in case you have a problem getting indication of a group-by error for some reason.

Thanks for reading! ;)

Popular posts from this blog

The Science of Google Dorking