SQL Server DBaaS Vulnerability: Decrypting System Code & Exfiltrating User Data

Comments 0

Share to social media

Security in cloud environments is both challenging and fascinating, particularly for Database-as-a-Service (DBaaS) offerings like Amazon RDS, GCP CloudSQL and Alibaba ApsaraDB RDS. The cloud vendor acts as the system administrator, managing the operating system, patching, and backups, while the user manages their data and databases.

To uphold this managed experience and protect the platform’s integrity, each vendor implements strict access controls, effectively removing the customer’s ability to access high-privilege system roles like sysadmin or internal databases. The core idea is simple: limit what users can do and see to protect the underlying infrastructure and other tenants.

They say:

Google CloudSQL – “The sysadmin role is not supported. Therefore, you cannot run system stored procedures that require the sysadmin role.”

Amazon RDS – “To deliver a managed service experience, Amazon RDS does not provide shell access to DB instances, and it restricts access to certain system procedures and tables that require advanced privileges.”

Alibaba ApsaraDB RDS – “SQL Server as a Platform as a Service (PaaS) service does not provide instance-level access permissions.”

This article explores a serious flaw in this security model – a SQL Injection vulnerability in sys.sp_help_spatial_geography_histogram that allowed a standard user on managed SQL Server instances (AWS, GCP, Alibaba, Azure) to completely bypass these restrictions, gain access to privileged user data, and decrypt the source code of internal management stored procedures.

It was fixed in SQL Server 2022 CU20 (KB5063814), but this article explains how the exploit worked and the process of eliminating it.

Encrypted Modules for Each Vendor: What Are They?

Each vendor instance includes an internal database (rdsadmin on AWS, gcloud_cloudsqladmin on GCP and rdscore on Alibaba). This is a system database created and managed by the vendor to host internal stored procedures and configuration tables necessary for the managed environment (e.g., handling backups, configuration changes, and maintenance).

There are some specific modules (stored procedures, functions or triggers) created to help automate SQL Server tasks. Those modules can exist on master, msdb or in an internal database.

Following is the current list (as per today 2025-10-29) of encrypted modules for each vendor:

AWS

Result:

GCP

Result:

Alibaba

Result:

These modules are encrypted for several crucial reasons:

  • Security & IP Protection: Protecting internal implementation logic and proprietary methods.
  • Prevent Abuse or Tampering: Procedures that wrap privileged operations must remain tamper-proof.
  • Compliance and Platform Integrity: Maintaining strict control over internal tools in a shared managed environment.

Bypassing Standard Security Measures

As is well known, there are many tools and scripts that can decrypt a module on SQL Server. They all require running high-privilege code to read the encrypted data from the SQL Server system table sys.sysobjvalues (which stores the encrypted code as a binary value called imageval).

The most common options to read data from sys.sysobjvalues are blocked:

  1. Dedicated Administrator Connection (DAC): DAC is often used to read this table, but it is not available on Amazon RDS for SQL Server.
  2. DBCC PAGE: This command, used by tools like SQL Prompt, requires the user to be part of the sysadmin role, which is not available.

Since standard high-privilege methods are blocked, we must find an internal loophole. In this article, we’ll adapt a technique described by Paul White, a friend and my favorite MSSQL geek.

SQL Injection: A Privileged Entry Point

SQL Injection (SQLi) remains one of the most critical and widespread web application vulnerabilities, but its presence in a system stored procedure in a cloud environment presents a far more severe threat. SQLi is fundamentally an attack where untrusted input is treated as executable code.

When this occurs within a highly privileged context, such as a built-in SQL Server system procedure, the attacker inherits the elevated permissions of that procedure, regardless of their own limited database role.

In a typical Amazon RDS setup, a customer’s admin user has high rights within their own databases but is specifically restricted from accessing the core rdsadmin database or performing instance-level privileged actions.

The discovery of a SQLi vulnerability in a system procedure breaks this boundary entirely, giving the user an unprecedented level of control.

The Vulnerability: Bypassing Privilege Boundaries

The vulnerability resided in the internal MSSQL stored procedure sys.sp_help_spatial_geography_histogram. This procedure is intended for analyzing data distribution within geography data type columns, a specialized feature in SQL Server that deals with spatial data. Because spatial features are niche, this specific procedure likely escaped the rigorous security testing applied to more commonly used system components.

The key to the exploit lies in the dynamic T-SQL query execution logic at the end of the procedure. The procedure is designed to construct and execute a query string, stored in the local variable @query.

Crucially, this dynamic string is built using the user-supplied column name, @colname, which is not properly sanitized or quoted using functions like QUOTENAME().

The code for the procedure is the following:

An attacker can terminate the column name context using a single quote, inject arbitrary SQL code, and then use the rest of the dynamic query string as a closing comment (–). Because the procedure runs with high internal permissions, the injected code is executed with those same elevated rights, allowing it to perform privileged operations.

The Injection Technique

To explore this, we first demonstrate simple code injection and use a global temporary table (##Tmp) to retrieve the output, as the original query will fail:

For instance, if you run this in a AWS RDS user database, it is probably going to fail with the following message:

But, don’t worry, although it looks like it failed, the injected code worked just fine:

Result:

This demonstrates that the injected code was executed successfully.

Reading sys.sysobjvalues

To decrypt the stored procedure, we need the [imageval] from the database’s sys.sysobjvalues table. Since the column name length is limited (128 characters), we use a two-step injection: first, storing the injection code in another temporary table, and second, executing it:

Result:

Now, with the binary [imageval] data, we can proceed with the decryption using Paul White’s technique.

Note: Any login with permission to run sys.sp_help_spatial_geography_histogram could explore this. No special or elevated permissions are required.

Decryption in Action

The decryption process relies on the fact that SQL Server uses the RC4 algorithm with a key derived from the database’s Family GUID, the object ID, and the sub-object ID of the encrypted module.

For more info about this, check out Paul White’s (a.k.a. Mr. TraceFlag, Mr. QueryOptimizer, Mr. Internals, Mr. Windbg) article.

Step 1: Create the Temporary Table with [imageval]

Step 2: RC4 Functions

First, we need the T-SQL functions to implement the RC4 algorithm. This should be executed in a database where you have permission to create objects (e.g., your primary database).

Step 3: Decrypt the Code

We can now compute the key and perform the decryption:

AWS – rds_set_database_online

And the full source code for rds_set_database_online is revealed:

It is interesting to observe that AWS also uses dynamic code execution, but it’s not vulnerable to this type of injection as they are properly quoting the @name variable using QUOTENAME().

You could do the same to decrypt the code from other vendors, like:

GCP – gcloudsql_rotate_tde_certificate

Result:

Alibaba – sp_rds_free_proc_cache

Result:

The Extent of the Compromise – Access to User Data

In my opinion, this breach is a huge deal. As we saw, an attacker can read sys.sysobjvalues with elevated permissions, and can also access vast amounts of system data that is normally restricted. This goes far beyond just decrypting stored procedures.

Reveal Data from Restricted Tables

The attacker could also reveal data for a table it doesn’t have access to by exploiting the stats stream data stored on the imageval column of sys.sysobjvalues. The statistics stream often contains samples of data and strings from the table being sampled.

For instance, let’s envisage the following scenario:

Result:

Now, let’s consider you have a login, that only has access to a specific DB. Access to SensitiveData db is not allowed:

If you login as AppLogin and try to read data from the SensitiveData database, you’ll receive an error saying you don’t have access to it – so far so good:

Result (Access Denied):

But, we do have access to sysobjvalues in the SensitiveData database, so let’s inject a code using sp_help_spatial_geography_histogram and read data from this table. Notice the injected code is reading table from SensitiveData db:

By parsing the hexadecimal statistics data (imageval) for the sysobjvalues table, we can extract human-readable strings, effectively bypassing the permission restriction.

Let’s create a function to help us parse the imageval hex:

Now, we can use this function to reveal the data from the statistic:

Result (revealing sensitive data from UserInfo table):

This technique successfully reveals data from ANY database in the instance that are meant to be entirely hidden from the attacker.

Read Password Hashes

Standard security restricts access to password hashes for logins, as per the documentation:

In SQL Server, any SQL Server authentication login can see their own login name, and the sa login. To see other logins, the principal requires ALTER ANY LOGIN, VIEW SERVER SECURITY DEFINITION, or a permission on the login.

To view the contents of the password_hash column, CONTROL SERVER is required. Starting with SQL Server 2022 (16.x), VIEW ANY CRYPTOGRAPHICALLY SECURED DEFINITION permission is required.

If we try to read data from sql_logins, we’ll get the following:

Result (Standard):

However, since we can read the underlying privileged table (sys.sysxlgns), we can find the hidden password hashes (pwdhash):

Result (Privileged):

This exposes the password hashes for the RDS internal user (rdsa) and the customer’s primary login (admin).

A user with access to login hashes can now go ahead and try to crack it using hashcat or something similar, as demonstrated here by Vlad Drumea.

Conclusion & Key Takeaways

This analysis reveals a critical example of how a seemingly minor SQL injection flaw in a niche system procedure can lead to a complete compromise of the security boundary in a managed cloud database environment. The technique demonstrated allowed for three major security impacts:

  1. Full decryption of system code, exposing the proprietary logic and security checks.
  2. Access to hidden data using statistics from any user database in the instance.
  3. Exposure of login credentials, the password hashes for all accounts.

For database administrators, this exploit highlights the subtle but profound security risks that exist in the overlap between vendor-managed infrastructure and user-accessible databases. While vendors try to maintains a secure platform, a single vulnerability in a high-privilege system object can unravel complex security layers.

Key Takeaways

  • A SQL Server DBaaS vulnerability allowed standard users on AWS RDS, GCP CloudSQL, and Alibaba ApsaraDB to access system tables and decrypt vendor-protected procedures.
  • The exploit relied on a dynamic SQL flaw in the system stored procedure sys.sp_help_spatial_geography_histogram.
  • Only users with standard privileges could trigger the exploit — no sysadmin access was required.
  • The issue was patched in SQL Server 2022 CU20 (KB5063814); all managed DBaaS providers applied vendor-specific mitigations.
  • DBaaS users should monitor vendor security bulletins, enforce least privilege, and apply patches promptly to prevent similar attacks.

Note 1: This specific vulnerability in sys.sp_help_spatial_geography_histogram was already fixed by Microsoft. This vulnerability led to CVE-2025-47954 and CVE-2025-53727 and the fix was released on KB5063814, a security update for SQL Server 2022 CU20.

Note 2: Azure SQL database was also vulnerable, but, once I reported it, Microsoft was very quick to fix it and since there is no option to setup an instance using an old version of SQL, this vulnerability is not exploitable anymore.

Frequently Asked Questions (FAQ)

  • Which platforms were affected by this vulnerability?
    The vulnerability impacted AWS RDS for SQL Server, GCP CloudSQL for SQL Server, and Alibaba ApsaraDB RDS for SQL Server. Azure SQL Database was not affected.
  • What part of SQL Server was exploited?
    The exploit targeted the system stored procedure sys.sp_help_spatial_geography_histogram, which allowed standard users to execute dynamic SQL and access internal system tables.
  • Could attackers escalate privileges to sysadmin?
    No – the vulnerability allowed access to system tables and decryption of procedures but did not grant full sysadmin privileges.
  • How can users mitigate this vulnerability?
    Apply the SQL Server 2022 CU20 (KB5063814) patch and follow vendor-specific updates. Enforce least privilege, monitor unusual activity, and review access to sensitive tables.
  • Are there other risks for DBaaS users?
    Similar risks exist whenever system stored procedures expose dynamic SQL. Regular patching, monitoring, and careful privilege assignment reduce risk across DBaaS platforms.
  • Is this vulnerability relevant for on-premises SQL Server?
    Only SQL Server 2022 instances using the affected stored procedure are vulnerable. Standard on-premises versions not running the specific procedure or older versions may not be affected.

Load comments

About the author

Fabiano Amorim

See Profile

Fabiano Amorim is a Data Platform MVP since 2011 that loves to conquer complex, challenging problems—especially ones that others aren’t able to solve. He first became interested in technology when his older brother would bring him to his work meetings at the age of 14. With over a decade of experience, Fabiano is well known in the database community for his performance tuning abilities. When he isn’t working, he loves to read and spend time with his family.

Fabiano Amorim's contributions