How-to make yourself a SYSADMIN on Microsoft SQL Server (exploit)

 

Within Microsoft SQL Server databases, some fixed server-level roles are defined, providing a certain level of access and functionality. The role with the highest access and functionality is the SYSADMIN role. Only privileged users or administrators within the company are granted this role.

 

Eddy Van Heghe, one of our experienced Microsoft SQL DBA’s, discovered a small exploit, however. Via this exploit every user can grant the SYSADMIN role (or other roles) to themselves when several specific criteria are met:

 

  1. The TRUSTWORTHY database option should be ON. This option indicates whether the Microsoft SQL instances trusts the database and its content or not.
  2. The database owner has server role SYSADMIN or SERVERADMIN or SECURITYADMIN granted.
  3. The user who wants to make use of this “exploit”, has database_owner rights inside the database or ddl_admin right with impersonate rights granted.

When all criteria are met, the user can get the SYSADMIN role granted after creating and executing following stored procedure (myHackingUser is the user account to which the SYSADMIN role should be granted off-course):

USE myDBWithTrustworthySetOn
GO
CREATE PROCEDURE sp_MakeMeSysadmin
WITH EXECUTE AS OWNER
AS
EXEC sp_addsrvrolemember 'myHackingUser','sysadmin'
GO

--execute the new procedure with any user who has execute rights inside the database
EXEC sp_ sp_MakeMeSysadmin

How to avoid possible exploits?

To detect if one of your Microsoft SQL databases is vulnerable for this exploit, the following statement can be executed:

IF EXISTS(select 1 FROM sys.server_principals r
INNER JOIN sys.server_role_members m
ON r.principal_id = m.role_principal_id
INNER JOIN sys.server_principals p
ON p.principal_id = m.member_principal_id
INNER JOIN sys.databases d
ON SUSER_SNAME(d.owner_sid) = p.name
WHERE is_trustworthy_on = 1
AND d.name NOT IN ( 'msdb' )
AND r.type = 'R'
AND (r.name = N'sysadmin' or r.name = N'serveradmin' or r.name = N'securityadmin')
)
BEGIN
SELECT SUSER_SNAME(owner_sid) AS DBOWNER,
d.name AS DATABASENAME
FROM sys.server_principals r
INNER JOIN sys.server_role_members m
ON r.principal_id = m.role_principal_id
INNER JOIN sys.server_principals p
ON p.principal_id = m.member_principal_id
INNER JOIN sys.databases d
ON SUSER_SNAME(d.owner_sid) = p.name
WHERE is_trustworthy_on = 1
AND d.name NOT IN ( 'msdb' )
AND r.type = 'R'
AND (r.name = N'sysadmin' or r.name = N'serveradmin' or r.name = N'securityadmin')
END

Now to solve:

  1. In case one or more databases are vulnerable, you should ask yourself if those databases really need to have the TRUSTWORTHY option ON or not? If not needed, just disable this option (OFF).
  2. If the TRUSTWORTHY option should be ON, does the database owner really needs to have the SYSADMIN/SERVERADMIN/SECURITYADMIN role granted? This should not be the case, so you should revoke those server-level roles from the database owner.

With special thanks to Eddy Van Heghe for discovery and investigation of this exploit!

Having troubles finding vulnerable Microsoft SQL databases after reading this article? Don’t know if you can just revoke the server-level role from the database owner? Or just need some help for your Microsoft SQL Server instances? Just ask us for more information or help with this exploit and the solutions.