During a Red Team assesment, it’s important to be able to investigate and successfully exploit public but undisclosed bugs. In this case, I’m going to explain the methodology for analyzing and exploit an undisclosed bug on Kentico CMS, a .NET based enterprise CMS, let’s go!

Firts of all, let’s read the CVE description about the bug:

An issue was discovered in Kentico before 12.0.15. Due to a failure to validate 
security headers, it was possible for a specially crafted request to the staging 
service to bypass the initial authentication and proceed to deserialize 
user-controlled .NET object input. This deserialization then led to unauthenticated 
remote code execution on the server where the Kentico instance was hosted.

Ok so this bug it’s about a .NET unsafe deserialization bug before Kentico 12.0.15. From a black-box perspective it could be really time consuming to find all the unauthenticated endpoints and exploit them, so I will need to download a trial version. I was lucky as there were a Kentico 11 (which is vulnerable too) demo available to download… well, not really, but changing the version number when downloading from Kentico demo website just serves an older version of the CMS, let’s say that this is kind of an easter egg.

I also downloaded two hotfixes, available on Kentico website, this hotfixes are for 12.0.15 (the fixed version) and for 12.0.14 (the unfixed one), so we can apply “diff” over the DLLs and see which code changes between this two patches.

Reading a bit more about the vulnerability, I found it’s caused by an usafe SOAP deserialization:

 An XML encoded SOAP message within an element of the actual SOAP body was being 
 deserialized by a SOAP Action within the staging web service. The staging service 
 is used by the application to synchronize changes between different environments 
 or servers. 

Now I know I’m looking for a SoapFormatter .NET serializer/unserializer, half of the way done thanks to this description.

Software I used for this analysis:

  • JustAssembly for .NET DLLs diffing.
  • JustDecompile for .NET DLLs decompile to C# readable code and functions finding.
  • Kentico CMS hotfixes and Demo version for dynamic analysis and testing.

JustDecompile let’s you open a whole .NET compiled project and look for strings, functions, variables… I opened the DLLs contained inside 12.0.5 patch, they are at Kentico/Hotfix120_15/DLLs/NET461. Open JustDecompile, click on Open… > File(s)…, and select all the DLLs inside the folder.

Then, click on Search… and type SoapFormatter, it will look for SoapFormatter functions in the whole project. I had luck that there where only two uses of this function inside CMS.Synchronization.dll module, so it seems that this module is the vulnerable one.


This function is used inside StagingTaskData class, inside a wrapper Deserialize private method of this class.


Let’s compare the CMS.Synchorization.dll between 12.0.15 hotfix and 12.0.14 hotfix to look if this Deserialization method on StagingTaskData have any difference. To do that I used JustAssembly, it let you select two DLLs and it will diff it in a visual way and show you which functions changed.

diff diff

So it’s clear, this is the function we were looking for, on 12.0.15 (right), they added a middleware class which verifies the StagingTaskData object being received, instead of the raw string deserialization on 12.0.14 (left).

Well, it’s time to find were StagingTaskData objects are instantiated, JustDecompile lets you look for cross-references to classes to see where are they instantiated.


First match is on CMS.Synchronization.WSE3.dll module, on SyncClient and SyncServer classes, let’s open this module and those classes on JustDecompile to see what are they doing.

On SyncSever class, I find the ULR endpoint to reach its methods, so now I know how to reach a method that uses StagingTaskData, seems the right way.


Looking a bit deeper on SyncServer class methods, I found the ProcessSynchronizationTaskData method, which receives a SERIALIZED StagingTaskData object string as parameter, and instantiates, here we have our unauthenticated endpoint to deserialize an unsanitized object.


To test if we can reach this URL by default and also test if my assumtions were true, I’ll use the Kentico CMS 11 demo downloaded before. To reach the endpoint, let’s visit /SyncWebService/SyncServer and… oops! 404. Investigating on Kentico CMS API, I found it uses a baseURL for Staging service at /CMSPages/Staging/, so the final URL for the ASMX method is: /CMSPages/Staging/SyncServer.asmx/ProcessSynchronizationTaskData. This endpoint will receive the derialized object via POST request.

Let’s then generate a sample evil serialized XML SOAP object string using ysoserial.net with the ActivitySurrogateSelector as gadget and SoapFormatter as payload format.

POST /CMSPages/Staging/SyncServer.asmx/ProcessSynchronizationTaskData HTTP/1.1
Host: ...

stagingTaskData=<ysoserial.net payload here>

Hope you learned something more about .NET applications analysis, this was my first time analyzing a real-world .NET application from stratch to find a RCE bug, so everything was new for me.

Ping me if you find something wrong at gongarcialeon@gmail.com, bye!