블로그로 돌아가기
Tools

SQLMap: Automated SQL Injection Testing Guide

Why the injection technique in the first result sets the pace of the whole engagement, how to test the request the app actually accepted, and which flags will damage a live system.

Semih Kilic March 9, 2026 6 min read

What sqlmap does that a manual test does not

You can find a SQL injection by hand: put a quote in a parameter, watch the page break, work out the query behind it. sqlmap does that too, but the reason to reach for it is not detection — it is the part after detection. Once it confirms an injectable parameter, it fingerprints the database, works out how to read data through the specific flaw it found, and enumerates schemas and tables without you writing a single UNION SELECT. The tedious, error-prone part is the part it automates.

That is also why it is dangerous to point casually at a live system. sqlmap is not a scanner that looks and leaves; by default it will extract data, and with the wrong flag it will try to run commands on the host. Everything below assumes you have written authorisation for the target, and the last section is about staying inside that authorisation.

The first command, and reading its answer

sqlmap -u "https://target.example.com/product?id=1"

That tests the id parameter and nothing else. sqlmap sends a series of crafted values and watches how the responses differ — a payload that changes the page one way, its logical opposite that changes it back. What you are waiting for is a line like:

[INFO] GET parameter 'id' is 'MySQL >= 5.6 AND time-based blind' injectable

Read that carefully, because it tells you two things that shape everything after. The DBMS — MySQL here — decides which enumeration commands are available. And the technique — time-based blind — decides how slow the rest of your session will be. A UNION-based injection returns data in the page and is fast. A time-based blind injection extracts data one bit at a time by making the database sleep, and dumping a large table that way can take hours. If sqlmap reports only a time-based flaw, that is not a warning you can ignore; it is the pace of the entire engagement.

Injection points beyond the query string

Most parameters worth testing are not in the URL.

POST body

sqlmap -u "https://target.example.com/login" \ --data="username=admin&password=test"

A specific parameter, when the request has many

sqlmap -u "https://target.example.com/search" \ --data="q=shoes&sort=price&page=2" -p q

An authenticated session — the injection is usually behind the login

sqlmap -u "https://target.example.com/account?tab=orders" \ --cookie="session=8f3a...; role=user"

A value inside a header, marked with *

sqlmap -u "https://target.example.com/" \ --headers="X-Forwarded-For: 1.1.1.1*"

The single most useful input, though, is not a flag at all. Capture the real request in Burp or your browser's dev tools, save it to a file, and hand sqlmap the whole thing:

sqlmap -r request.txt

Now sqlmap tests with the exact headers, cookies and body the application already accepted. This solves the most common "it works by hand but sqlmap finds nothing" problem, which is almost always a missing header, a CSRF token, or a session cookie that the manual test had and the tool did not.

Level and risk: the two dials that matter

sqlmap -u URL --level=1 --risk=1    # the default
sqlmap -u URL --level=3 --risk=2    # a reasonable step up
sqlmap -u URL --level=5 --risk=3    # everything, including the payloads that can hurt

--level (1–5) widens where sqlmap looks: higher levels test more parameters, and crucially, levels 2 and 3 start testing cookies and headers that the default leaves alone. --risk (1–3) changes what it sends. This is the dial to respect. Risk 3 includes OR-based boolean payloads, and an OR-based injection into an UPDATE statement can match every row in a table — which on a live application means editing every record, not reading one. The default of --level=1 --risk=1 is not timidity; it is what you run against a system you cannot afford to damage.

Raise the level first when detection is coming up empty. Raise the risk only when you understand what the extra payloads do and the target can absorb the consequence.

Enumeration, from database down to rows

Once a parameter is confirmed injectable, you walk down the tree:

sqlmap -r request.txt --dbs                       # which databases exist
sqlmap -r request.txt -D shopdb --tables          # tables in one of them
sqlmap -r request.txt -D shopdb -T users --columns# columns in one table
sqlmap -r request.txt -D shopdb -T users \
  -C username,password_hash --dump                # just the columns you need

Notice the last command names two columns. The instinct is --dump on the whole table, or worse --dump-all across every database. Over a time-based blind injection that is the difference between a two-minute extraction and one that runs overnight and gets you noticed. Take the schema first, decide what actually proves the finding — usually a handful of rows and the columns that show the data is real — and pull only that. A penetration test demonstrates access; it does not need to exfiltrate the customer table to do so.

--current-user, --current-db, --is-dba and --passwords answer "how bad is this" quickly and cheaply, and they are a better opening move than dumping anything.

When there is a WAF in the way

A web application firewall that blocks obvious payloads is common, and sqlmap has room to work around it — legitimately, on a target you are authorised to test.

sqlmap -r request.txt --random-agent
sqlmap -r request.txt --tamper=space2comment,between --random-agent
sqlmap -r request.txt --delay=1 --safe-url=https://target.example.com/ --safe-freq=10

Tamper scripts rewrite payloads into forms a filter may not recognise — space2comment replaces spaces with inline comments, between rewrites > comparisons, and there are dozens more for specific filters. --random-agent avoids the default sqlmap user-agent that many WAFs block on sight. And --delay with --safe-url/--safe-freq slows the session and periodically hits a harmless page, which both reduces load and makes the traffic look less like a machine hammering one endpoint. This is evasion in the service of a sanctioned test; the same techniques against a system you do not own are simply an attack.

The commands to think twice about

sqlmap -r request.txt --os-shell       # command execution on the DB host
sqlmap -r request.txt --file-read="/etc/passwd"
sqlmap -r request.txt --sql-shell       # an interactive SQL prompt

--os-shell is where sqlmap stops reading the database and starts trying to run operating-system commands on the server behind it — by writing a payload to disk, abusing a stored procedure, or a similar path depending on the DBMS. When it works it is the strongest possible demonstration of impact. It is also the loudest thing in the tool, it writes files to the target, and it will trip any monitoring worth the name. On a real engagement, run it only when the rules of engagement explicitly permit command execution, and know that "explicitly permit" means it is written in the scope document, not that nobody said you couldn't.

Sessions, batch mode, and not repeating work

sqlmap -r request.txt --batch                     # take the default at every prompt
sqlmap -r request.txt --dbs --flush-session       # start clean, ignore the cache

sqlmap caches what it learns in a per-target session file, so a second run does not re-detect an injection it already found — it picks up where it left off. --batch answers every interactive prompt with the sensible default, which is what you want in a script or a long enumeration you don't intend to babysit. Reach for --flush-session only when you have changed something about the target or the test and want sqlmap to stop trusting its cache.

A short checklist before you run it in anger

  • The target is in a written scope, and data extraction (and, separately, command execution) is permitted by that document.
  • You are testing with -r request.txt from a real captured request, so authentication and headers match.
  • You start at --level=1 --risk=1 and raise deliberately, not reflexively.
  • You enumerate the schema before dumping, and dump the columns that prove the finding rather than the whole database.
  • You practise against a deliberately vulnerable app first — DVWA, OWASP Juice Shop, or the testphp.vulnweb.com target Acunetix publishes for exactly this — before you touch anything real.

Running it without the local install

sqlmap is a Python tool and installs cleanly, and running it yourself is a fine way to work. If you would rather not manage a Python environment and a WAF-evasion toolkit on your own machine, CyberSec Pro runs sqlmap from a browser: you fill in the target and options on a form, see the exact command before it runs, and the output streams back as it happens. The scan executes server-side in a dedicated container, one process per job, and credentials you supply for an authenticated test are held in memory for that job and never written to the database, logs or backups.

Whichever way you run it, the discipline is the same. Read the technique in the first result, enumerate before you dump, and never send a risk-3 payload at something you cannot afford to break.

#sqlmap#sql-injection#web-security#penetration-testing