Introduction
Surely one of the best-known vulnerabilities, and one that has been around for a long time, SQL injection is still wreaking havoc in 2024. It is featured in many of our pentest reports every year.
Furthermore, compared to 2022, in 2023, SQL injection vulnerabilities were identified as CVEs 2159 times. And in the latest OWASP Top 10, which lists the most critical and common vulnerabilities in web applications, they rank third.
Depending on the case, an SQL injection can be tedious to exploit to assess its impact. Fortunately, high-quality tools developed by the open-source community, such as sqlmap, make the task much easier.
In this article, we’ll review the principle of SQL injections and give an exhaustive presentation of how sqlmap works, using concrete examples.
Comprehensive Guide to Sqlmap
A Quick Reminder about SQL Injections (SQLi)
First of all, what does SQL mean? “Structured Query Language” is a computer language used to communicate with a database and manipulate stored data.
The vast majority of web applications use SQL to query their database. However, depending on the implementation, SQL injection-type vulnerabilities, commonly known as “SQLi”, can emerge.
What is an SQLi?
SQL injection is an attack used to manipulate the relational databases of a web application, such as MySQL, Oracle Database or Microsoft SQL Server. This should not be confused with NoSQL injections, which are attacks used to manipulate non-relational databases such as MongoDB or CouchDB.
For example, consider the following piece of PHP code:
The first line shows that the $id variable takes the value of the id parameter in the URL. However, this $id variable is concatenated directly in the SQL query on the next line.
As the id parameter can be manipulated by any user, an attacker can inject SQL code into the id parameter of the URL and perform a multitude of actions on the web application database.
For example, to ensure injection, the attacker could inject a 5-second delay into the id parameter of the URL:
On the server side, the SQL query will be as follows:
The server will therefore take 5 seconds to respond, confirming the SQL injection.
Impact of an SQLi
In most cases, the impact of an SQL injection is critical. If the database user has sufficient access rights, as is often the case, an SQLi allows an attacker to exfiltrate the entire database from the web application and sometimes even gain control of the server.
What are the Different Types of SQLi and How Can They be Prevented?
There are several types of SQL injection. This depends on the point of injection and the technique used to exploit the injection. Below is a non-exhaustive list of SQLi types:
- UNION-based
- Boolean-based blind
- Error-based
- Stacked queries
- Time-based blind
The best way to protect against SQL injections is to use “prepared Statements”, which define the structure of the SQL query before incorporating the variables.
This way, if a variable is controlled by an attacker, the latter will not be able to inject itself into the SQL query, as its structure will already have been defined beforehand. For more information and case studies on SQL injections in general, please refer to our detailed article: SQL injections (SQLi): principles, impacts, exploitations and security best practices.
How does Sqlmap Work?
Although it is possible to exploit a SQL injection and exfiltrate the contents of a database manually, it is much simpler and quicker to write and use a script.
Even better, if you don’t want to reinvent the wheel and want to be even more efficient, sqlmap will be there to help you.
What is Sqlmap?
Sqlmap is an open-source tool that automates the detection and exploitation of SQL injections. It is a very comprehensive tool offering a multitude of features and options that can go as far as compromising the SQL server if conditions allow.
Before going any further, it is important to note that sqlmap potentially generates a lot of traffic and that its use is illegal without authorisation from the owner of the system tested.
Exploiting an SQLi with Sqlmap
During a penetration test, sqlmap is generally used after an SQLi has been identified. This ensures that traffic is not generated for nothing. There are then several steps to follow to exploit SQL injection in the classic way.
Let’s look at it step by step.
Finding a payload that suits the type of SQLi
The first step is to find a payload that is suitable for the type of SQLi and that will be used to exfiltrate the database in the following steps.
Command:
The “-r” option tells sqlmap the file containing the HTTP request which contains the injection point. If the location of the injection point is known to the attacker, as it is the case in this example, it can be specified by adding an asterisk to the precise location where the SQL injection is to take place:
Here, the attacker knows that an SQL injection is possible in the value of the “TrackingId” cookie.
Note that it is also possible to use the “-u” option instead to specify a URL if SQL injection is possible in a URL parameter.
Result:
After testing several payloads, sqlmap finally found the type of SQL injection:
Here, the type of SQL injection is a “stacked query time-based blind”, i.e. it is possible to exfiltrate data by playing with delays, as it is impossible to obtain the result of the SQL injection directly. Also, the injection is carried out with a new query after the original, hence the “stacked query”.
At the same time, sqlmap has also identified the database system used, which is PostgreSQL. With this information, sqlmap can now use payloads that respect the injection type and database system to exfiltrate data.
Exfiltrating database names
The second step is to exfiltrate the database names. This step can be done at the same time as the first one to save time.
Command:
To enumerate the databases, add the “-dbs” option.
Result:
Here, only one database has been found, the “public” database.
Listing the table names
In the third step, now that we know the name of the database, we can list the names of the tables.
Command:
The “-D” option specifies the name of the database, in this case “public”, and the “-tables” option is used to enumerate the names of the tables present in the “public” database.
Result:
Two tables were found, “tracking” and “users”. The second table looks interesting and may contain data relating to the platform’s users.
Choosing an interesting table
The fourth step is to choose an interesting table to dig into. To do this, we list its columns.
Command:
The “-T” option is used to specify the “users” table and the “-columns” option to list the column names.
Result:
Listing the table data
For the fifth and final step, now that we have an overview of the “users” table, we can choose to enumerate all the data in the table or just the data in certain columns. In our case, we are enumerating the data in the “username” and “password” columns.
Command:
With the “-C” option, we choose our columns separated by a comma. The “-dump” option is used to exfiltrate the table data.
Result:
So, we’ve managed to exfiltrate the name and password of every user on the platform using sqlmap.
Using Sqlmap to retrieve system information
To go further and establish a better understanding of the environment under attack, it is always interesting to retrieve information linked to the database system. With sqlmap, you can retrieve:
- The system user currently using the database
- Whether or not the current system user has the DBA (Data Base Administrator) role
- The host name
- All system users of the database
- The privileges of all system users
Below are the commands used to retrieve this information and their results:
System user currently using the database
Command:
Result:
Is the current system user DBA?
Command:
Result:
Host name
Command:
Result:
List of system users in the database
Command:
Result:
Privileges of the database’s system users
Command:
Result:
Sources of the labs on Portswigger
Exploiting blind SQL injections with Sqlmap
SQL injection results are often not returned in response, as in the case of blind sql injections. So how does sqlmap manage to exfiltrate the data?
If an SQL injection is of the blind type, you need to find a condition that returns a different server response depending on whether it is true or false. For example, in the case of a Boolean blind SQLi, the server will respond in a different way if a Boolean condition in the injected query is false:
If the server does respond differently, it is possible to exploit this and retrieve the database names character by character, then the tables, then the columns and finally the data.
With the following injection, for example, if we keep our example of injection in the product ID, we can find out whether the first character of the password for the user “administrator” in the “password” column of the “users” table is equal to “5” or not:
The complete server-side query will therefore be:
As the password does start with “5”, the server responds differently than if we had entered another number or letter instead.
We can move on to the next characters by incrementing the second parameter of the SQL SUBSTRING() function. Note that this method works because we know that the database system is PostgreSQL and that the type of SQLi is a boolean-based blind.
The power of sqlmap lies in its ability to automate and consider most cases of SQL injection. The sqlmap tool is very complete and is useful for exploiting many other types of SQL injection, not just blinds. In the next section, we’ll look at some of sqlmap’s many “advanced” options, as well as the “tampers” notion.
Sqlmap advanced options
It’s no exaggeration to say that sqlmap is a complete SQLi tool. Try displaying the full help with the “-hh” option and you will already have an idea of the power of this tool.
In this section, we list some options that may come in handy during a pentest, but don’t limit yourself to them, we strongly recommend you explore the many nuances of this tool for yourself.
–proxy=
To understand exactly what sqlmap is sending, it is possible to view each request sent and its response by specifying a proxy. For example, you can pass all the traffic generated by sqlmap through Burp Suite.
This can be used to understand and resolve cases where sqlmap is not working as expected by seeing directly how the server responds to requests sent by sqlmap.
–delay=
Rate limiting is sometimes implemented on some web applications.
The heavy traffic generated by sqlmap can activate alerts on the server which will block any new requests from us. To go around this problem, you can use the “–delay” option, which specifies a delay in seconds between each request sent by sqlmap.
By playing with this delay, you can potentially bypass rate limiting, but data exfiltration will take longer.
–force-ssl
When the server does not accept the use of the HTTP protocol and you specify a request file with the “-r” option, the “–force-ssl” option allows you to force the use of HTTPS on requests sent.
This is a simple option, but an important one to add to your command for secure data exfiltration.
–threads=
If you know that the server can handle a lot of traffic, it is a good idea to increase the number of threads in your sqlmap command to retrieve data more quickly. Be careful, however, not to overuse this as it could cause the SQL server to crash.
–dbms=
For optimisation reasons, if you know the database system used by the SQL server, it is possible to specify it to sqlmap. This reduces the time taken to detect the type of SQLi, as sqlmap will only test payloads linked to the DBMS specified.
–level=
The “–level” option is used to specify to sqlmap the completeness of the tests to be performed. The value goes from 1 to 5, it being 1 by default. The higher the value, the greater the number of payloads tested.
This is a practical option for complex cases of SQL injection. If sqlmap doesn’t find an injection payload the first time, it is a good idea to increase the value of this option.
–risk=
Like the previous option, the “–risk” option can be used to specify an accepted risk level from 1 to 3. The higher the value, the greater the number of payloads injected by sqlmap, but also the greater the risk.
Depending on the location of the injection in the original SQL query, increasing the risk can lead to unwanted data modifications. By default, this value is set to 1.
–string=
In the case of boolean-based SQL injections, it is possible to specify to sqlmap a character string to look for in the server response if the injected condition is true.
As we saw earlier, in the case of a boolean-based blind, the server response is different if the injected condition is true or false. If it’s true, the difference can be as simple as a string of characters in the server response, which is why it is a good idea to specify it in sqlmap.
–technique=
It is possible to specify to sqlmap the type of payloads to be tested and their order. An SQL injection can be of several different types and can, for example, be a boolean-based blind and a time-based blind at the same time.
However, a boolean-based blind payload will be quicker to exploit than a time-based blind payload. Using the “–technique” option, you can tell sqlmap what type of SQLi to search and find for.
Below are the values that the option can take and what they mean:
- B: Boolean-based blind
- E: Error-based
- U: Union query-based
- S: Stacked queries
- T: Time-based blind
- Q: Inline queries
You can choose to put only one value or all of them in a specific order, which sqlmap will follow. The default order is: BEUSTQ.
–file-read=
On some database systems, such as MySQL, PostgreSQL or Microsoft SQL Server, it sometimes happens that the database user has sufficient rights to read files on the system. With the “–file-read” option, you can specify the path of the file to be retrieved.
–os-cmd=
As with the previous option, the “–os-cmd” option is used to execute a command on the SQL server. This option only works on MySQL, PostgreSQL or Microsoft SQL Server DBMS and the database user must have sufficient rights.
–flush-session
By default, when you use sqlmap on a target, it creates a session relating to the target which it keeps in memory on your machine.
So, if you give sqlmap the same query, it will be able to continue exploiting the SQLi straight away, as it will have all the necessary information already in memory (payload, database structure already found, etc.) and it will not need to start from the beginning.
If, on the other hand, you want sqlmap to start from scratch on your target, use this option once to delete the saved session.
–tamper=
This option extends sqlmap’s flexibility. With this option, you can specify one or more scripts which modify the payload before it is sent to the target.
In the following section, we will develop the notion of tamper scripts and look at a few concrete examples.
For more information on all the sqlmap options, please refer to the wiki.
Sqlmap tampers scripts
Tampers scripts are scripts used to modify the payloads sent by sqlmap to bypass some applications filters or WAF set up. For example, a web application could very well forbid the use of spaces on a user entry.
Once the auditor has identified an SQL injection in this same entry, he will need to find a way of bypassing this filter to exploit the SQL injection. This is where tampers scripts can be used. There are scripts already implemented by sqlmap that the user can utilize, but it is entirely possible to create your own for unique situations.
To list the tampers scripts already implemented by sqlmap, use the following command:
Among the sixty or so tampers already available, we can mention a few:
space2comment.py
This script replaces all spaces in a payload with comments such as “/**/”. This way, by opening and closing a comment immediately, it can be interpreted as a space by some database systems. This script can therefore be used to bypass simple “anti-SQLi” filters implemented by some web applications that would only block user entries containing spaces
randomcase.py
The “randomcase.py” script can be used to change the case of all SQL keywords, such as “SELECT”, “WHERE” and so on. For example, “SELECT” can become “SelEcT”. Some application filters or WAFs check that there are no SQL keywords in user entries to protect against SQL injections. However, if this filter is poorly implemented, changing the case can potentially bypass the protection.
equaltolike.py
This script changes all the “=” signs in a payload to the equivalent “LIKE” to bypass application filters that prevent the use of the equal sign in user input.
It is important to note that these scripts can be used at the same time to bypass several filters at once.
Conclusion
Sqlmap is an essential tool for anyone wanting to detect and exploit SQL injections. It provides a range of functions that can meet both basic and more advanced needs. All these qualities make it a powerful tool, essential for pentesters.
Author: Lorenzo CARTE – Pentester @Vaadata