Home » PoCs for two SQL Injection vulnerabilities fixed in SQL Server 2022 GDR KB5063814

PoCs for two SQL Injection vulnerabilities fixed in SQL Server 2022 GDR KB5063814

by Vlad Drumea
2 comments 8 minutes read

In this post I demo two PoCs for SQL injection vulnerabilities fixed in SQL Server 2022 CU20 GDR KB5063814.

This August’s Patch Tuesday came with a security patch for SQL Server 2022, 2019, 2017, and 2016.

The number of SQL injection vulnerabilities caught my attention and I decided to see what system stored procedures have changed to see if I can find anything useful.

System stored procedures changed as part of the security patch

To identify the system stored procedures changed in the security patch, I’ve used the similar process like the one in my post about comparing system object changes between SQL Server 2025 and 2022.

Procedure nameCode size changes
sp_help_spatial_geometry_histogramlines: 0; characters:-17
sp_dbmmonitorupdatelines: 0; characters:-5
sp_spaceusedlines: 6; characters:137
sp_set_trident_data_locationlines: 12; characters:475
sp_discover_trident_tablelines: 16; characters:495
sp_help_spatial_geography_histogramlines: 0; characters:-17

If you’re curious, I’ve dumped the object definitions for the new and modified objects.
You can find them in my blog’s GitHub repo.

What was SQL injection again?

Short detour for anyone not familiar with SQL injection.
The logic behind the vulnerability is that a user-provided input (think of a search term in your report’s filter) isn’t properly handled in the code and, if crafted in a specific way, can lead to other code, besides the query from your report, being executed against the database.

Target stored procedures

In this case I’ll be focusing on the two spatial-related stored procedures:

Both stored procedures are fairly similar in terms of input parameters.

I’ll be honest with you, dear reader, I’ve never bothered learning about spatial data in SQL Server, so this is the first time I actually do something with spatial data types.

sp_help_spatial_geometry

The MS Learn example execution of this stored procedure looks like this:


The vulnerable part

Comparing the two versions of the stored procedure’s DDL in SSMS 21 reveals something interesting at line 65.

In case the image doesn’t help, the pre-GDR version looks like this (added line breaks to make it easier to read):

The post-GDR version looks like this:

The interesting part, and actual cause of the SQL injection vulnerability is the fact that, in the unpatched version, the @colname variable is directly concatenated to the rest of the query.

This means that it can be a viable avenue for SQL injection.

Not so fast

I can’t just exploit this by executing the stored procedure with your usual SQL injection payloads like ' OR 1=1 --

There are some restrictions to what I can do to successfully exploit this:

  1. The data type of @colname is SYSNAME, which is the equivalent of NVARCHAR(128). So, 128 characters to work with.
  2. There is a check to validate that the provided value for @colname is an actual column that uses the GEOMETRY data type.
  3. The payload needs to also include the required values in order for the CROSS APPLY with sys.PlanarGridCoverage to work.

The T-SQL that validates the column name looks like this:


Building the payload

This case is a bit more interesting because due to the limitations described in points 2 and 3, the payload is actually a column in a table.

The table definition looks like this (yes, it is based on the example table from the MS Learn article):

You’ll notice the first column looks a bit strange, that’s because the part before the first ; is what’s needed to ensure that the query that’s part of the original code executes successfully, SELECT @@SERVERNAME; is the stand-in for our malicious code, and -- comments out the rest of the original query that has been replaced by the first part of the payload.

And, yes, you can get pretty creative with column names as long as you’re using square brackets.

The third column, named fake_col, is required to ensure that the version of the CROSS APPLY modified by the payload column will execute successfully.
Otherwise, if the column fake_col wouldn’t exist in the TownSites_SQLi table, the stored procedure would end up complaining that the column does not exist when the dynamic T-SQL is executed.

The following code will output how the final version of the query will look like with the payload.

I took some liberties with the way the table name is handled, but it doesn’t change the relevant part.

The resulting T-SQL will look like this (I’ve added a line break before the CROSS APPLY):

Note how the string from the column got injected (duh) inside the query, replacing the legitimate part with the payload and then commenting out the rest to avoid execution failures.

Executing the payload

Executing the following T-SQL will result in a second result set being returned with the name of the SQL Server instance.

SSMS result sets first result set is empty, the second one is the instance name

The first (legitimate) result set is empty because my payload table doesn’t have any records in it.

And the second result set is the one returned by the additional T-SQL being executed due to the SQL injection vulnerability.

At this point, you can drop the table.


sp_help_spatial_geography_histogram

The MS Learn example execution of this stored procedure looks like this:

In this case, it’s a bit simpler since it doesn’t require so many input values.

The vulnerable part is similar.
Pre-GDR version:

Post-GDR:


Building the payload

The important part here is that the data type of the payload column is the type required by sp_help_spatial_geography_histogram.
Which is GEOGRAPHY instead of the previously required GEOMETRY.


Executing the payload

Executing this T-SQL will result in a second result set containing the SQL Server instance name and version:


What the actual fix does

The change in the patched versions consists of applying the QUOTENAME() function to the @colname parameter in order to wrap the provided value in square brackets.
This neutralizes any potential SQL injection payload.

Here’s a quick example on a SQL Server 2022 CU20 instance with the GDR patch applied.

Notice that the second result set is no longer returned

Conclusion

This was a fun little exercise in finding and exploiting the SQL injection vulnerabilities in SQL Server’s system stored procedures that were addressed in KB5063814.

Also, it’s a lot easier to figure out the appropriate SQL injection payloads when you can see the code 😀

You may also like

2 comments

Fabiano September 24, 2025 - 16:23

did you noticed the ack to me on the CVEs 🙂 …
https://msrc.microsoft.com/update-guide/en-US/vulnerability/CVE-2025-53727
https://msrc.microsoft.com/update-guide/en-US/vulnerability/CVE-2025-47954

You’re faster than me to disclosure it ;P

Aaa, btw, congrats and thank you for the great content in the blog!

Regards
Fabiano

Reply
Vlad Drumea September 24, 2025 - 20:33

Hi Fabiano,
Thank you for the comment and for the kind words!
Unfortunately, I did not notice (until now when I checked again).
Awesome work finding these vulnerabilities!

Reply

Leave a Comment

* By using this form you agree with the storage and handling of your data by this website.

This site uses Akismet to reduce spam. Learn how your comment data is processed.