Estimados amigos de Inseguros !!!
Hoy vengo a hablar de las enterprise apps de Entra ID, que es de esas cosas que están ahí desde el día uno del tenant y que nadie ha mirado nunca.
No porque alguien decidiera dejarlas así. No porque haya una política detrás. No porque se revisara en su momento y se aceptara el riesgo.
Simplemente están.
Y cuando llevas tres años de tenant, «están» quiere decir doscientas o trescientas aplicaciones de terceros con permisos sobre tus datos, consentidas una a una por gente de contabilidad que un martes probó una herramienta de firmas de correo.
Qué es exactamente una enterprise app y por qué importa
Rápido, que esto lo explica todo el mundo y no es el valor del post.
El app registration es el plano de la aplicación, y vive en el tenant de quien la fabrica. El enterprise app (o service principal, que es como lo vas a ver en Graph) es la instancia de ese plano dentro de tu tenant.
Cuando un usuario tuyo entra en una SaaS cualquiera con «Iniciar sesión con Microsoft» y acepta esa pantalla de permisos, lo que está haciendo es crear un service principal en tu directorio y regalarle acceso.
Eso es el consentimiento OAuth. Y aquí viene la parte que casi nunca se cuenta bien.
El ataque, que no es el que te imaginas
Todo el mundo explica esto como un problema de supply chain: «si hackean al proveedor, te hackean a ti». Vale, es cierto, pero es el escenario menos probable.
El ataque real se llama illicit consent grant, o consent phishing, y en MITRE lo tienes como T1528 – Steal Application Access Token.
El atacante no toca a tu proveedor. Registra su propia aplicación, en su propio tenant, gratis y en cinco minutos. Le pone un nombre creíble tipo «Secure Mail Backup» y le pide los permisos que le interesan: leer correo, leer ficheros, acceso offline.
Y luego te manda el enlace. Un enlace a login.microsoftonline.com.
Piensa un segundo en lo que eso significa:
- No hay dominio raro. Es el dominio legítimo de Microsoft, con su certificado bueno.
- No hay página falsa que clonar. Es la pantalla de consentimiento de verdad.
- El usuario se autentica de verdad y pasa su MFA de verdad. El MFA aquí no te protege de nada, porque el ataque no lo esquiva: lo usa.
- Cambiar la contraseña después no sirve para nada. El consentimiento sigue concedido.
El atacante se lleva un access token y un refresh token. Persistencia de meses. Y lo que viene después no son inicios de sesión sospechosos de usuario: son llamadas a Microsoft Graph desde un service principal. Tráfico API legítimo, con un token válido, que la mayoría de SOC´s no está mirando porque solo vigila los sign-ins de usuarios.
Cero malware. Cero ejecutable. Tu EDR no tiene nada que detectar.
Si esto te suena a teoría, mira lo que pasó con Midnight Blizzard contra el propio Microsoft en enero de 2024: entraron por un tenant de pruebas heredado sin MFA y el pivote hacia el correo corporativo fue una aplicación OAuth olvidada con acceso elevado. Una app que nadie había revisado.
¿Y si en vez de permisos delegados son permisos de aplicación? Pues entonces ya no hablamos del buzón de una persona. Hablamos de todos los buzones del tenant, sin usuario, sin sesión y funcionando a las tres de la mañana.
Qué te vas a encontrar cuando por fin mires
Esta es la parte que a mí me parece más honesta de contar, porque es la que se ve en campo.
Abres el inventario esperando veinte aplicaciones y te salen trescientas. Ese susto es sano.
Y no son todas iguales. Hay first-party de Microsoft, que es ruido de fondo. Hay SaaS de terceros consentidas por usuarios. Hay app registrations propias de scripts que montó un admin que ya no trabaja ahí. Hay apps multi-tenant de tu partner o tu MSP, que suelen ser las que más permisos tienen y las que nadie se atreve a tocar. Y hay huérfanas: el proveedor se cambió hace dos años, el service principal sigue vivo con todo intacto.
Los cuatro hallazgos que más me preocupan cuando reviso esto:
Permisos que son escalada directa a Global Admin. Hay un puñado de permisos de Graph que, concedidos como application permission, equivalen a entregar el tenant. RoleManagement.ReadWrite.Directory permite que la app se asigne a sí misma el rol de administrador global. AppRoleAssignment.ReadWrite.All le permite concederse cualquier otro permiso que le apetezca. Application.ReadWrite.All le permite añadir credenciales a otras aplicaciones, incluidas las gordas. Y esto no aparece por maldad, aparece porque alguien estaba depurando una integración, no le funcionaba, concedió algo amplio «de momento» y ese momento lleva dos años.
Client secrets eternos. Secretos sin caducidad, o con caducidad a 99 años, metidos en un script de PowerShell en un recurso compartido. Una app con Mail.ReadWrite de aplicación y su secreto en texto plano en una carpeta es acceso a todos los buzones para cualquiera que lea esa carpeta.
Los owners. Esta se salta todo el mundo. El propietario de una app registration puede añadirle credenciales nuevas. Si esa app tiene permisos elevados, el owner tiene de facto esos permisos… y no aparece en ninguna revisión de roles privilegiados, porque técnicamente no tiene ningún rol. Ruta de escalada preciosa y silenciosa (T1098.001, si la quieres mapear).
Tu Conditional Access no aplica. Toda esa política tan bonita que has montado va sobre usuarios. Un service principal autentica con su secreto desde cualquier IP del planeta y tu CA ni se entera. Existe Conditional Access for workload identities, sí, pero es licencia aparte y casi nadie lo tiene puesto — verifica tu licenciamiento antes de darlo por hecho, que esto Microsoft lo mueve cada poco.
El matiz, que aquí no vale el alarmismo
Que tengas trescientas enterprise apps no significa que estés comprometido. Casi seguro que no lo estás.
Significa que tienes superficie de ataque innecesaria y que no sabes responder a la pregunta importante, que es esta: si mañana te digo que una de esas apps es maliciosa, ¿sabes decirme si ha leído algo, cuándo y qué?
Ahí es donde casi todo el mundo se queda callado. Porque los sign-ins de service principal se retienen unos 30 días en Entra si no los exportas a Log Analytics o Sentinel. Llevas tres años sin mirar y solo puedes contar el último mes.
Cómo se limpia esto sin cargarte la nómina un martes
Lo primero, un aviso: no entres con la motosierra. El error clásico es deshabilitar cuarenta apps de golpe y tirar un proceso de negocio. Esto son semanas, no una tarde.
Inventario. Con Graph PowerShell sacas la foto. Yo empiezo por lo bruto, solo para el susto inicial:
Connect-MgGraph -Scopes "Application.Read.All","Directory.Read.All","AuditLog.Read.All"
# ¿Cuántas hay realmente?
(Get-MgServicePrincipal -All).Count
Y luego lo que de verdad importa, que son los permisos de aplicación concedidos:
$sps = Get-MgServicePrincipal -All
foreach ($sp in $sps) {
$roles = Get-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $sp.Id
foreach ($r in $roles) {
[PSCustomObject]@{
App = $sp.DisplayName
AppId = $sp.AppId
Recurso = (Get-MgServicePrincipal -ServicePrincipalId $r.ResourceId).DisplayName
PermisoId = $r.AppRoleId
}
}
}
Para los permisos delegados tiras de Get-MgOauth2PermissionGrant -All, y para los owners de Get-MgApplicationOwner. Te aviso de que los cmdlets del módulo Graph cambian de nombre y de comportamiento entre versiones más de lo que a uno le gustaría, así que pruébalo en tu tenant de laboratorio antes de lanzarlo en producción… a mí me ha tocado más de una vez pelearme con un Insufficient privileges que no era de permisos de Graph sino de que me había conectado con el scope de menos 🙂
Si tienes Defender for Cloud Apps con App Governance, buena parte de esto te viene ya masticado. Y si quieres enseñarle el grafo de escalada a dirección en vez de una tabla, AzureHound o las ROADtools de Dirk-jan Mollema son mucho más elocuentes que un CSV.
Triaje con criterios, no con intuición. Nada de «esta me suena rara». Yo puntúo por: si tiene permisos de aplicación o solo delegados; si está en la lista de permisos de escalada de arriba; último uso (sin autenticar en 90 días, candidata); cuántos usuarios le dieron consentimiento — y ojo con esta, porque una app con un único consentimiento es la firma clásica del consent phishing, mientras que una con 400 es una herramienta corporativa de verdad; si el owner sigue vivo y en la empresa; y si tiene credenciales que no caducan.
Actuar en dos tiempos. Deshabilitar primero, borrar después:
Update-MgServicePrincipal -ServicePrincipalId $id -AccountEnabled:$false
Dos o tres semanas a ver quién grita. Lo que nadie reclama, fuera. Los objetos borrados tienen un plazo de recuperación, así que tienes red. Y a las que se quedan, user assignment required a true y asignación solo a quien la necesita, en vez de dejarla abierta a todo el tenant.
Y ahora sí, cerrar la puerta. En Enterprise applications → Consent and permissions, bloqueas el consentimiento de usuario y montas el admin consent workflow.
Pero aquí va mi opinión, y no pretendo sentar cátedra: bloquearlo del todo en una empresa de 2.000 personas te genera una cola de aprobaciones que nadie atiende, y a las tres semanas el control está revertido. Lo he visto pasar. Lo que aguanta es lo híbrido: defines una clasificación de permisos de bajo riesgo (perfil básico, User.Read y poco más), permites autoconsentimiento solo para eso y solo de editores verificados, y el resto pasa por revisión con un SLA comprometido de 48 horas. Si no comprometes el SLA, el control se muere solo.
Y ojo con el «verified publisher», que da una falsa sensación de seguridad: Microsoft ha verificado la identidad del editor, no la seguridad de la aplicación. No es la App Store. En diciembre de 2022 hubo una campaña donde los atacantes consiguieron ese sello suplantando a empresas reales y lo usaron precisamente para que la gente confiara.
Que no se vuelva a acumular. Revisión trimestral, alertas de caducidad de secretos, exportación de logs de service principal a Sentinel y access reviews si tienes licencia. Y una regla cultural que vale más que las anteriores: toda app nueva entra con dueño asignado y fecha de revisión. Sin dueño, no entra.
Ah, y si algún día te toca responder a uno de estos de verdad: no basta con resetear credenciales y revocar sesiones. Hay que revocar el consentimiento, borrar el service principal y revocar los refresh tokens. Si no, el atacante sigue dentro mientras tú celebras que has cambiado la contraseña.
Al final
Esto es de esas cosas que llevas pendientes desde hace tres años. Lo sabes, sabes que hay que mirarlo, y cada vez que abres la consola te encuentras trescientas aplicaciones y lo cierras.
No es falta de capacidad. Es que no hay tiempo, y estos temas —Entra ID, consentimiento OAuth, service principals, detección en Sentinel— no se aprenden leyendo un post suelto un domingo. Se aprenden con una ruta, con alguien al lado y con constancia.
Eso es exactamente lo que hay dentro de la membresía: rutas curadas para que no te pierdas eligiendo por dónde empezar, +30 cursos de Red, Blue, Azure, M365 y SOC, directos cada 15 días y gente que va a lo mismo que tú. A tu ritmo y sin culpa: si la vida aprieta, pausas y te esperamos.
Más información: La Membresía de SeguridadSi
Y si lo que tienes es el problema en tu empresa y no en tu carrera —un tenant que nadie ha revisado nunca y ganas de saber qué hay dentro—, eso es una auditoría de seguridad en Azure y Microsoft 365, que la hago yo y no la subcontrato.
Espero que te guste, y sobre todo que lo mires en tu tenant esta semana !!!
Gracias por leerme.
