SQL Server is more than just a database—it's a powerful platform that can be leveraged by attackers for system access, persistence, and code execution. While organizations focus on protecting their valuable data, they often overlook the inherent capabilities within SQL Server that make it an attractive target for adversaries looking to establish footholds in Microsoft environments.
This blog explores the offensive capabilities built into SQL Server and provides defenders with practical detection strategies. We'll examine how attackers can abuse stored procedures, CLR assemblies, modify the registry, and maintain persistence—all while potentially evading common monitoring controls. Additionally, we'll provide attack simulations and security content that security practitioners can immediately leverage in their environments.
But before we dive into attack techniques and detection methods, let's understand the fundamental components that make SQL Server such a versatile tool for both administrators and attackers alike.
When assessing SQL Server security risks, it's essential to understand the powerful built-in procedures that can be leveraged by both administrators and attackers. Two critical categories deserve special attention: system stored procedures (sp_) and extended stored procedures (xp_). These procedures provide administrative functionality but can present significant security risks when misused or left unnecessarily enabled. Before examining these procedures in detail, let's first understand the default security context in which SQL Server operates.
In SQL Server, the service account—commonly NT SERVICE\MSSQLSERVER for default instances—is configured with the principle of least privilege to enhance security. By default, this account has limited permissions, particularly concerning system-level operations like modifying the Windows registry. This restriction ensures that even if an adversary gains control over SQL Server, their ability to alter critical system configurations is constrained.
However, while direct registry modifications are restricted, the service account retains the capability to execute commands via tools like PowerShell or the command prompt. This means that an attacker could still run scripts or commands, potentially leading to unauthorized actions or data exfiltration.
It's important to note that the service account's permissions can be modified. For instance, if SQL Server is configured to run under a more privileged account, such as LocalSystem, it would inherit broader system access, including extensive registry modification capabilities. Therefore, it's crucial to carefully manage and monitor the service account's permissions to maintain a secure environment.
In summary, while the default configuration of the SQL Server service account limits certain high-risk actions like registry edits, it still allows command execution through PowerShell or CMD. Administrators should remain vigilant, ensuring that service accounts operate with the minimum necessary privileges and that any elevation of these privileges is justified and monitored.
OLE Automation Procedures allow SQL Server to interact with the Windows operating system via COM objects, enabling file manipulation, registry modifications, and network requests. While designed for automation, these procedures introduce significant security risks when enabled. Attackers can abuse them to execute arbitrary commands, create backdoors, or establish persistence—all without needing xp_cmdshell.
System stored procedures, prefixed with `sp_`, are Transact-SQL procedures that come built into SQL Server. These procedures are stored in the `master` database and can be executed from any database. They serve various administrative and information-gathering purposes.
These are standard system procedures with legitimate administrative uses, though some can be misused in certain contexts when excessive permissions are granted.
Extended stored procedures, prefixed with `xp_`, are particularly sensitive from a security perspective because they can interact with the operating system outside of SQL Server's normal boundaries. These procedures are actually compiled DLL files (xpstar.dll, for example) that run as external code.
`xpstar.dll` is a system DLL in SQL Server that implements many of the built-in extended stored procedures. Think of it as the "manager" for extended stored procedure functionality.
# Default path (varies by SQL Server version) C:\Program Files\Microsoft SQL Server\MSSQL15.MSSQLSERVER\MSSQL\Binn\xpstar.dll |
EXEC xp_cmdshell 'whoami' |
These stored procedures introduce various risks that attackers can exploit for execution, persistence, and reconnaissance.
Attackers use these functions to execute commands, establish persistence, and gather intel on SQL Server and the underlying system. Disabling unnecessary procedures and monitoring for suspicious executions are key to reducing risk.
After understanding the risks associated with stored procedures, it's important to identify what’s enabled in your SQL environment and explore additional execution mechanisms. Attackers frequently leverage extended procedures, startup procedures, and SQL CLR for persistence, privilege escalation, and OS-level execution. Here we will dive deeper and take a more hands on approach to identifying and learning more about SQL procedures. Note that this is not exhaustive and we will reference outside projects to assist with learning more as necessary. If you don’t have a lab environment yet with SQL, feel free to read through first and follow along again using SQLSSTT with the SQL Server Management Studio.
To enumerate all extended stored procedures (xp_*) in a SQL Server instance:
USE master; GO SELECT name AS ProcedureName, type_desc AS ObjectType, create_date, modify_date FROM sys.all_objects WHERE type = 'X' -- 'X' indicates extended stored procedures AND name LIKE 'xp_%' ORDER BY name;
|
There are 53 enabled on this database in my test environment:
Figure 1: extended properties in SQL, Splunk 2025
For a full database-wide enumeration across all databases:
DECLARE @sql NVARCHAR(MAX); SET @sql = N'';
SELECT @sql += 'USE [' + name + ']; SELECT ''' + name + ''' AS DatabaseName, name AS ProcedureName, type_desc AS ObjectType FROM sys.all_objects WHERE type = ''X'' AND name LIKE ''xp_%''; ' FROM sys.databases;
EXEC sp_executesql @sql;
|
Figure 2: Query all databases at once, Splunk 2025
Many xp_* procedures provide system-level access, and defenders should feel comfortable in knowing how to identify risky or unnecessary procedures in their environment.
SQL Server allows procedures to automatically execute at startup, making them a prime target for persistence. Attackers can use this feature to ensure malicious code runs each time the SQL service starts.
To check for enabled startup procedures:
EXEC sp_configure 'show advanced options', 1; RECONFIGURE; EXEC sp_configure 'scan for startup procs'; |
Figure 3: Viewing startup procedures, Splunk 2025
To list currently enabled startup procedures:
SELECT * FROM sys.objects WHERE type = 'P' AND OBJECTPROPERTY(object_id, 'ExecIsStartup') = 1;
|
Figure 4: Stored procedures in SQL, Splunk 2025
As outlined in “Hacking SQL Server Stored Procedures – Part 3: SQL Injection,” here is another way to query the stored procedures:
-- Select stored procedures from master database SELECT ROUTINE_CATALOG,SPECIFIC_SCHEMA,ROUTINE_NAME,ROUTINE_DEFINITION FROM MASTER.INFORMATION_SCHEMA.ROUTINES ORDER BY ROUTINE_NAME
|
Figure 4: Stored procedures in SQL with command, Splunk 2025
If an attacker gains access to SQL Server, they can add a malicious stored procedure to startup, ensuring code execution even after reboots.
SQL Server provides built-in procedures that allow modification of Windows registry settings and file creation. These can be used for persistence, privilege escalation, or configuration changes.
Let’s take writing to the Windows Registry as an example:
EXEC xp_regwrite 'HKEY_LOCAL_MACHINE', 'SOFTWARE\Microsoft\Windows\CurrentVersion\Run', 'SQLBackdoor', 'REG_SZ', 'C:\Windows\System32\cmd.exe /c calc.exe';
|
Note that the process to modify the registry will be sqlservr.exe.
Figure 5: Default NT SERVICE\MSSQLSERVER account blocked from editing registry, Splunk 2025
Note here that by default the NT SERVICE\MSSQLSERVER service account does not have permissions to write to the registry and would 1. Need to be modified to an account that does or 2. Need another method to modify the registry, such as xp_cmdshell.
Registry modifications and file writes allow stealthy persistence mechanisms within SQL Server, and defenders should log and alert on usage of these procedures.
SQL Server Common Language Runtime (CLR) allows developers to execute .NET code inside the database engine. While useful for extending functionality, it can also be abused by attackers to execute arbitrary system commands, bypass security controls, or create stealthy persistence mechanisms. CLR assemblies run within the security context of SQL Server itself, making them particularly dangerous as they can bypass restrictions, access resources available to the SQL Server, and provide persistence mechanisms that often escape regular monitoring. This combination of privileged execution context and reduced visibility makes SQL CLR a high-value target for attackers with database access.
To check if SQL CLR is enabled:
EXEC sp_configure 'show advanced options', 1; RECONFIGURE; EXEC sp_configure 'clr enabled'; |
Figure 6: CLR Disabled in SQL, Splunk 2025
To enable SQL CLR (requires sysadmin privileges):
EXEC sp_configure 'show advanced options', 1; RECONFIGURE; EXEC sp_configure 'clr enabled', 1; RECONFIGURE; |
Figure 7: Enabling CLR in SQL, Splunk 2025
Figure 8: Validating CLR is enabled, Splunk 2025
Starting with SQL Server 2017, Microsoft implemented stricter CLR security with the `clr strict security` setting enabled by default. This means assemblies must meet one of the following requirements:
An adversary with sufficient privileges has two main paths to load malicious assemblies:
Path 1: Adding to Trusted Assemblies
-- Generate hash of the assembly DECLARE @hash VARBINARY(64); SELECT @hash = HASHBYTES('SHA2_512', CONVERT(VARBINARY(MAX), (SELECT * FROM OPENROWSET(BULK 'C:\path\to\evil.dll', SINGLE_BLOB) AS Contents)) );
-- Add to trusted assemblies EXEC sys.sp_add_trusted_assembly @hash, N'EvilAssembly, version=1.0.0.0, culture=neutral, publickeytoken=null'; |
Path 2: Enable Unsafe CLR
-- Enable unsafe CLR sp_configure 'clr strict security', 0; GO RECONFIGURE; GO |
Loading and Using CLR Assemblies
Once the security requirements are met, an assembly can be loaded:
CREATE ASSEMBLY EvilCLR FROM 'C:\path\to\evil.dll' WITH PERMISSION_SET = UNSAFE; |
The binary will need to be on disk.
Then you can create stored procedures that reference the assembly:
CREATE PROCEDURE [dbo].[cmd_exec] @cmd NVARCHAR(4000) AS EXTERNAL NAME [EvilCLR].[StoredProcedures].[cmd_exec]; |
NetSPI provided another very detailed blog, “Attacking SQL Server CLR Assemblies,” that walks readers through these steps in more detail using a custom DLL.
After understanding SQL Server's key components like stored procedures, CLR capabilities, and execution paths, it's important to validate our detection strategies through practical testing. Let's explore some common attack techniques and how to simulate them safely in a test environment. These tests will help defenders verify their monitoring controls and understand the adversary's perspective.
To help defenders validate their monitoring controls and understand adversary tradecraft, we can use tools like SQL Server Security Testing Tool (SQLSSTT). SQLSSTT is a basic PowerShell-based security testing framework that helps identify common misconfigurations, vulnerabilities, and potential attack vectors in SQL Server environments.
SQLSSTT provides comprehensive testing capabilities, including:
The tool is designed to help blue teams understand:
To get started, install SQL in a lab environment and then begin testing with SQLSSTT and/or SQL Server Management Studio. In addition, we will walk through the combined utilities with SequelEyes.
To begin our testing, we will utilize Atomic Red Team T1105 test number 32.
This test has a prerequisite to install SQLCmd.exe via Winget, or you may manually download it direct.
Once the prerequisite is installed, run the following:
Invoke-AtomicTest T1105 -TestNumber 32 |
Figure 9: Atomic Red Team Test T1105
Upon success, the T1105.zip will be written to c:\.
Before we continue, let’s summarize what we’ve done:
Effective monitoring of SQL Server environments requires visibility into both database and operating system-level activities. The security content described below focuses on using Windows Application Event Log for SQL events as it provides critical visibility into configuration changes, stored procedure executions, and other potential attack vectors without requiring complex database auditing configurations. Splunk offers several options for comprehensive SQL monitoring: the Splunk Add-on for Microsoft SQL Server collects and normalizes SQL Server logs, while Splunk DB Connect enables direct database queries for deeper visibility. By leveraging these tools along with the detection rules below, security teams can identify suspicious SQL Server activities early in the attack chain, before adversaries can establish persistence or execute malicious code.
This detection identifies when critical SQL Server configuration options are modified, including "Ad Hoc Distributed Queries," "external scripts enabled," "Ole Automation Procedures," "clr enabled," and "clr strict security." These features can be abused by attackers for various malicious purposes, e.g.:
Enabling these features could indicate attempts to gain code execution or perform reconnaissance through SQL Server.
`wineventlog_application` EventCode=15457 | rex field=EventData_Xml "<Data>(?<config_name>[^<]+)</Data><Data>(?<new_value>[^<]+)</Data><Data>(?<old_value>[^<]+)</Data>" | where config_name IN ("Ad Hoc Distributed Queries", "external scripts enabled", "Ole Automation Procedures", "clr enabled", "clr strict security") | rename host as dest | eval change_type=case( old_value="0" AND new_value="1", "enabled", old_value="1" AND new_value="0", "disabled", true(), "modified" ) | eval risk_score=case( change_type="enabled", 90, change_type="disabled", 60, true(), 70 ) | eval risk_message="SQL Server critical procedure ".config_name." was ".change_type." on host ".dest.", which may indicate attempts to gain code execution or perform reconnaissance" | stats count min(_time) as firstTime max(_time) as lastTime by dest EventCode config_name change_type risk_message risk_score | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`
|
Figure 10: Windows SQL Server Critical Procedures Enabled, Splunk 2025
This detection identifies potentially suspicious usage of Invoke-Sqlcmd PowerShell cmdlet, which can be used for database operations and potential data exfiltration. The detection looks for suspicious parameter combinations and query patterns that may indicate unauthorized database access, data theft, or malicious database operations. Threat actors may prefer using PowerShell Invoke-Sqlcmd over sqlcmd.exe as it provides a more flexible programmatic interface and can better evade detection.
Figure 11: Windows PowerShell Invoke-Sqlcmd Execution, Splunk 2025
This detection helps hunt for changes to SQL Server configuration options that could indicate malicious activity. It monitors for modifications to any SQL Server configuration settings, allowing analysts to identify potentially suspicious changes that may be part of an attack, such as enabling dangerous features or modifying security-relevant settings.
`wineventlog_application` EventCode=15457 | rex field=EventData_Xml "<Data>(?<config_name>[^<]+)</Data><Data>(?<new_value>[^<]+)</Data><Data>(?<old_value>[^<]+)</Data>" | rename host as dest | eval change_type=case( old_value="0" AND new_value="1", "enabled", old_value="1" AND new_value="0", "disabled", true(), "modified" ) | eval risk_score=case( change_type="enabled", 90, change_type="disabled", 60, true(), 70 ) | eval risk_message="SQL Server ".config_name." was ".change_type." on host ".dest | stats count min(_time) as firstTime max(_time) as lastTime by dest EventCode config_name change_type risk_message risk_score | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`
|
Figure 12: Windows SQL Server Configuration Option Hunt, Splunk 2025
This analytic detects when SQL Server loads DLLs to execute extended stored procedures. This is particularly important for security monitoring as it indicates the first-time use or version changes of potentially dangerous procedures like xp_cmdshell, sp_OACreate, and others. While this is a legitimate operation, adversaries may abuse these procedures for execution, discovery, or privilege escalation.
`wineventlog_application` EventCode=8128 | rex field=EventData_Xml "<Data>(?<dll_name>[^<]+)</Data><Data>(?<dll_version>[^<]+)</Data><Data>(?<procedure_name>[^<]+)</Data>" | rename host as dest | eval dll_category=case( dll_name=="xpstar.dll", "Extended Procedures", dll_name=="odsole70.dll", "OLE Automation", dll_name=="xplog70.dll", "Logging Procedures", true(), "Other") | stats count as execution_count, values(procedure_name) as procedures_used, latest(_time) as last_seen by dest dll_name dll_category dll_version | sort - execution_count
|
Figure 13: Windows SQL Server Extended Procedure DLL Loading Hunt, Splunk 2025
This detection identifies when a startup procedure is registered or executed in SQL Server. Startup procedures automatically execute when SQL Server starts, making them an attractive persistence mechanism for attackers. The detection monitors for suspicious stored procedure names and patterns that may indicate malicious activity, such as attempts to execute operating system commands or gain elevated privileges.
`wineventlog_application` EventCode=17135 | rex field=EventData_Xml "<Data>(?<startup_procedure>[^<]+)</Data>" | rename host as dest | eval risk_score=case( match(lower(startup_procedure), "xp_|sp_|cmdshell|shell|exec"), 90, true(), 70 ) | eval risk_message="SQL Server startup procedure ''".startup_procedure."'' was launched on host ".dest | stats count min(_time) as firstTime max(_time) as lastTime by dest EventCode startup_procedure risk_message risk_score | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`
|
Figure 14: Windows SQL Server Start Procedure, Splunk 2025
This detection identifies when the xp_cmdshell configuration is modified in SQL Server. The xp_cmdshell extended stored procedure allows execution of operating system commands and programs from SQL Server, making it a high-risk feature commonly abused by attackers for privilege escalation and lateral movement.
`wineventlog_application` EventCode=15457 | rex field=EventData_Xml "<Data>(?<config_name>[^<]+)</Data><Data>(?<new_value>[^<]+)</Data><Data>(?<old_value>[^<]+)</Data>" | rename host as dest | where config_name="xp_cmdshell" | eval change_type=case( old_value="0" AND new_value="1", "enabled", old_value="1" AND new_value="0", "disabled", true(), "modified" ) | eval risk_score=case( change_type="enabled", 90, change_type="disabled", 60, true(), 70 ) | eval risk_message="SQL Server xp_cmdshell was ".change_type." on host ".dest | stats count min(_time) as firstTime max(_time) as lastTime by dest EventCode config_name change_type risk_message risk_score | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`
|
Figure 15: xp_cmdshell enabled, disabled, Splunk 2025
This detection identifies potentially suspicious usage of sqlcmd.exe, focusing on command patterns that may indicate data exfiltration, reconnaissance, or malicious database operations. The detection looks for both short-form (-X) and long-form (--flag) suspicious parameter combinations, which have been observed in APT campaigns targeting high-value organizations. For example, threat actors like CL-STA-0048 have been known to abuse sqlcmd.exe for data theft and exfiltration from compromised MSSQL servers. The detection monitors for suspicious authentication attempts, output redirection, and potentially malicious query patterns that could indicate unauthorized database access or data theft.
Figure 16: Windows SQLCmd Execution, Splunk 2025
This analytic detects instances where the sqlservr.exe process spawns a command shell (cmd.exe) or PowerShell process. This behavior is often indicative of command execution initiated from within the SQL Server process, potentially due to exploitation of SQL injection vulnerabilities or the use of extended stored procedures like xp_cmdshell.
| tstats `security_content_summariesonly` count min(_time) as firstTime max(_time) as lastTime from datamodel=Endpoint.Processes where Processes.parent_process_name="sqlservr.exe" `process_cmd` OR `process_powershell` by Processes.dest Processes.user Processes.parent_process Processes.parent_process_name Processes.process_name Processes.process Processes.process_id Processes.original_file_name Processes.parent_process_id | `drop_dm_object_name(Processes)` | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`
|
Figure 17: Windows SQLServr Spawning Shell, Splunk 2025
This blog helps security analysts, blue teamers and Splunk customers identify and defend against SQL attack techniques that can lead to system access, persistence, and code execution. By understanding these offensive capabilities, security teams can better protect their SQL Server environments against adversaries seeking to establish backdoors or gain elevated privileges. You can implement the detections described in this blog using the Enterprise Security Content Updates app or the Splunk Security Essentials app. To view the Splunk Threat Research Team's complete security content repository, visit research.splunk.com.
Any feedback or requests? Feel free to put in an issue on Github and we’ll follow up. Alternatively, join us on the Slack channel #security-research. Follow these instructions If you need an invitation to our Splunk user groups on Slack.
We would like to thank Michael Haag for authoring this post and the entire Splunk Threat Research Team for their contributions: Jose Hernandez, Patrick Bareiss, Lou Stella, Bhavin Patel, Eric McGinnis, Nasreddine Bencherchali, Teoderick Contreras and Rod Soto.
The world’s leading organizations rely on Splunk, a Cisco company, to continuously strengthen digital resilience with our unified security and observability platform, powered by industry-leading AI.
Our customers trust Splunk’s award-winning security and observability solutions to secure and improve the reliability of their complex digital environments, at any scale.