Jonathan Elkabas e Tomer Nahum

Nota dell'editore

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


Maltenuto e pericoloso: Manuale del proprietario per l'amministrazione globale

Iniziamo i nostri esempi di utilizzo di EntraGoat con lo Scenario 1, che abbiamo chiamato Misowned and Dangerous: Un manuale del proprietario per l'amministratore globale. Questo esercizio pratico mostra come la proprietà legittima di un'applicazione in Microsoft Entra ID possa essere sfruttata per aumentare i privilegi e compromettere un account di amministratore globale, consentendo l'acquisizione completa del tenant.

Partendo da un account utente a basso privilegio compromesso, l'attaccante scopre la proprietà di un'applicazione aziendale (service principal) a cui è assegnato un ruolo privilegiato.

Aggiungendo un segreto del client al service principal, l'attaccante fa leva sull'identità dell'applicazione, quindi utilizza il suo ruolo per reimpostare la password dell'amministratore e rilasciare un Temporary Access Pass (TAP) per ottenere l'accesso interattivo completo al portale Azure.

Questo scenario enfatizza le conseguenze reali di una cattiva gestione delle applicazioni e illustra la differenza di comportamento, i confini di accesso e l'esposizione al rischio tra flussi di autenticazione delegati e flussi di autenticazione solo app.


Panoramica del percorso di attacco

  1. Storia di un primo punto d'appoggio: L'aggressore si autentica come utente finanziario compromesso (david.martinez) con credenziali rubate.
  2. Enumerazione: Utilizzando PowerShell nativo e le cmdlet di Microsoft Graph, l'attaccante scopre che l'utente possiede un servizio principale denominato Finance Analytics Dashboard a cui è assegnato il valore Privileged Authentication Administrator ruolo.
  3. Escalation dei privilegi: L'attaccante aggiunge un segreto del client al service principal di proprietà e si autentica utilizzando credenziali di sola app, passando a un'identità di service principal.
  4. Acquisizione dell'account: Dal contesto di sola app con il ruolo privilegiato, l'attaccante reimposta la password dell'amministratore globale o aggiunge un TAP per bypassare l'autenticazione multifattoriale (MFA), quindi accede in modo interattivo e recupera il flag, confermando la compromissione completa del tenant.

Flusso di attacco

La Figura 1 mostra il flusso di questo attacco.

Figura 1. Flusso di attacco che compromette un account amministratore globale EntraGoat

Perché è importante capire la proprietà dell'applicazione?

Ogni applicazione in Entra ID ha due identità distinte:

  1. Registrazione dell'applicazione, un oggetto di definizione globale nell'home tenant in cui l'applicazione è stata originariamente creata. Questo oggetto contiene le autorizzazioni (scope) blueprint-OAuth2 dell'applicazione, che l'applicazione può richiedere URI di reindirizzamento per i flussi di accesso, metadati di branding e publisher e altro ancora. Questa identità non rappresenta di per sé un presidio di sicurezza attivo nel tenant.
  2. Service principal, un'istanza locale dell'app nel tenant che agisce come identità di sicurezza e impone il controllo degli accessi. Un service principal viene creato automaticamente quando un utente del tenant registra una nuova app, dà il consenso a un'app esterna e così via. L'identità del service principal è quella che Entra ID utilizza per assegnare i ruoli, applicare le policy e applicare le autorizzazioni. È anche l'identità autenticata quando l'app agisce da sola (contesto solo app).

La proprietà delle applicazioni è una funzione amministrativa legittima. Questo design supporta l'amministrazione decentralizzata nelle grandi organizzazioni, consentendo ai team di gestire le proprie applicazioni aziendali. Consente agli sviluppatori, ai processi di automazione e ai proprietari dei servizi di gestire il ciclo di vita e la configurazione delle loro applicazioni. Tuttavia, questa funzione diventa un problema quando:

  • Alle applicazioni vengono concessi ruoli privilegiati
  • La proprietà è assegnata agli utenti regolari senza governance
  • L'igiene delle credenziali è debole o non monitorata

I presidi di servizio mal governati consentono l'aggiunta di credenziali e l'accesso solo alle app, aggirando i controlli di identità come l'MFA e l'accesso condizionato.

Questo approfondimento mette in luce perché gli aggressori danno la priorità al movimento laterale utilizzando i principi di servizio nei moderni ambienti cloud e perché i difensori devono comprendere la differenza tra i contesti di sicurezza delegati e quelli riservati alle app.


Come rilevare e difendere dall'uso improprio della proprietà del service principal

La comprensione e il monitoraggio della proprietà dell'applicazione non sono facoltativi, ma sono un controllo di sicurezza fondamentale in qualsiasi ambiente Entra ID. La proprietà dell'applicazione garantisce la possibilità di gestire le credenziali, configurare le autorizzazioni e controllare efficacemente l'identità dell'applicazione. Senza visibilità sulla proprietà dell'applicazione e sull'assegnazione dei permessi, i percorsi di escalation dei privilegi rimangono nascosti sia ai difensori che ai revisori.

I difensori devono monitorare e correlare:

  • Quali applicazioni esistono nel tenant?
  • Chi li possiede?
  • Quali sono le autorizzazioni o i ruoli di directory assegnati?
  • Gli utenti non privilegiati possiedono dei mandanti di servizio con accesso elevato?
  • Quali applicazioni non sono più in uso e possono essere dismesse?

Le soluzioni Semperis aiutano a colmare le lacune nella comprensione di queste domande con molteplici livelli di difesa, a partire dagli indicatori di esposizione (IOE) e dagli indicatori di compromissione (IOC).

Questi indicatori rilevano automaticamente e segnalano le impostazioni predefinite e le configurazioni errate pericolose, come ad esempio i criteri di autorizzazione troppo permissivi per la configurazione delle applicazioni, i non amministratori che possiedono i principals di servizio privilegiati e le linee di base deboli per la sicurezza delle applicazioni.


Approfondimento dello scenario: Soluzione descritta passo dopo passo

Vediamo i passi specifici da compiere per simulare l'uso improprio della proprietà dell'applicazione e capire in quali condizioni consente la compromissione del Global Admin.


Fase 1: Punto d'appoggio iniziale

Iniziamo con il contesto di sicurezza di un analista finanziario, david.martinez (Figura 2) che ha inserito le sue credenziali aziendali durante una campagna di phishing.

Figura 2. Credenziali compromesse di un utente con basso livello di privilegio

Utilizzando il Connect-MgGraph ci si autentica come utente compromesso (Figura 3).

Figura 3. Accesso con le credenziali rubate

Per comprendere le nostre capacità attuali, iniziamo con l'ispezionare il contesto di sicurezza della sessione autenticata(Figura 4).

Figura 4. Contesto di sicurezza della sessione autenticata

Un metodo alternativo e ben noto per autenticarsi come utente Entra ID e ottenere un token di accesso JWT è quello di sfruttare strumenti di automazione come BARK1. Il seguente snippet di PowerShell mostra come acquisire e utilizzare un token di accesso tramite autenticazione nome utente/password dalla CLI:

      $userToken = Get-MSGraphTokenWithUsernamePassword -Username $UPN -Password $password -TenantID $tenantId
$userAccessToken = $userToken.access_token
$SecureToken = ConvertTo-SecureString $userAccessToken -AsPlainText -Force
Connetti-MgGraph -AccessToken $SecureToken

BARK include anche una funzionalità per decodificare il JWT risultante, esponendo metadati di sessione dettagliati come i permessi delegati (scp), ruoli di directory (wids), metodo di autenticazione (amr) e le informazioni sul cliente (app_displayname), come Figura 5 spettacoli.

Figura 5. Metadati di sessione decodificati

Questa fase di decodifica è particolarmente utile per un rapido triage dei privilegi. Ad esempio, se il token è stato emesso a un utente con ruoli di directory, il parametro wids elenca direttamente i GUID dei ruoli assegnati, come ad esempio il ruolo di Amministratore globale che Figura 6 senza richiedere un'ulteriore enumerazione dell'API Graph.

Figura 6. L'UID dell'amministratore globale rivelato

Tuttavia, questa guida evita di affidarsi a strumenti o astrazioni di terze parti. Tutte le fasi di enumerazione e sfruttamento vengono eseguite utilizzando PowerShell nativo e chiamate dirette all'API Graph per garantire che ogni fase del percorso di attacco sia completamente trasparente e tecnicamente spiegata.

NOTA: Per impostazione predefinita, tutti gli utenti autenticati in Entra ID possono interrogare i dati di base del profilo di altri utenti, nonché attributi come extensionAttribute1–15 non sono classificati come sensibili. Di conseguenza, il flag memorizzato nel profilo dell'amministratore può essere tecnicamente recuperato immediatamente con la seguente query API:

      $uri = "https://graph.microsoft.com/v1.0/users/EntraGoat-admin-s1@334brf.onmicrosoft.com?`$select=onPremisesExtensionAttributes"
$response = Invoke-MgGraphRequest -Uri $uri -Method GET
$response.onPremisesExtensionAttributes.extensionAttribute1

Questo comportamento è intenzionale. L'obiettivo di EntraGoat non è quello di nascondere il flag, ma di insegnare tecniche realistiche di escalation dei privilegi in ambienti Entra ID. È possibile recuperare il flag tramite una chiamata diretta all'API, ma il vero obiettivo è scalare i privilegi, accedere al portale Azure come utente amministratore e visualizzare il flag nella propria interfaccia utente, dimostrando il pieno controllo di un'identità di amministratore globale. Il flag è un artefatto da gioco, non l'obiettivo principale.

      Invoke-MgGraphRequest -Uri 'https://graph.microsoft.com/v1.0/me?$select=id,userPrincipalName,onPremisesExtensionAttributes' |
    Select-Object @{n='UPN';e={$_.userPrincipalName}},
                  @{n='Id';e={$_.id}},
                  @{n='Flag';e={$_.onPremisesExtensionAttributes.extensionAttribute1}}

Fase 2: Enumerazione

Poiché questo è il primo scenario della serie EntraGoat, ci occuperemo del processo di enumerazione e metteremo in evidenza le tecniche fondamentali di escalation dei privilegi. Negli altri scenari, assumeremo questa linea di base e ci concentreremo direttamente sul percorso di attacco principale, saltando le fasi di ricognizione in stile CTF.

Con l'accesso iniziale a david.martinezSi inizia a cercare i percorsi per l'escalation dei privilegi. Il primo compito è capire quali accessi ha l'identità compromessa.

Si inizia controllando se all'utente è stato assegnato un ruolo nella directory(Figura 7).

Figura 7. Verifica dei ruoli degli utenti

Il Get-MgRoleManagementDirectoryRoleAssignment Il cmdlet non rivela alcun ruolo privilegiato, confermando che david.martinez non ha accesso elevato per impostazione predefinita. Successivamente, si esaminano le appartenenze ai gruppi (Figura 8).

Figura 8. Visualizzazione delle appartenenze ai gruppi del nostro utente

L'utente fa parte solo del gruppo tenant predefinito, che viene assegnato a ogni utente Entra ID per i servizi di collaborazione come SharePoint o Teams. Anche in questo caso non c'è un percorso di escalation dei privilegi.

Verifichiamo inoltre se david.martinez è proprietario di qualsiasi gruppo, poiché i proprietari dei gruppi possono aggiungersi come membri ed ereditare i privilegi del gruppo (come i ruoli assegnati). Anche questo controllo restituisce un risultato vuoto (Figura 9).

Figura 9. Verifica della proprietà del gruppo del nostro utente

Tuttavia, l'interrogazione della proprietà del service principal restituisce un risultato(Figura 10).

Figura 10. Scoperta che il nostro utente possiede un servizio principale

david.martinez possiede il servizio principale Finance Analytics Dashboard. Questo è importante perché i proprietari del service principal possono gestire le credenziali, compresa l'aggiunta di nuovi segreti per autenticarsi come service principal.

Verifichiamo se il Finance Analytics Dashboard il committente del servizio ha dei permessi assegnati (Figura 11).

Figura 11. Verifica delle autorizzazioni assegnate al service principal

Nessuna è configurata. Successivamente, si controlla se ci sono ruoli di directory assegnati(Figura 12).

Figura 12. Verifica dei ruoli di directory del service principal

Vediamo l'assegnazione di un ruolo, ma è rappresentato solo da un GUID. Ogni ruolo integrato di Entra ID è rappresentato da un GUID, che è globale e uguale per tutti i tenant di Entra ID. È possibile visualizzare tutti i ruoli incorporati ufficiali e i relativi GUID qui.

Per risolvere il GUID in un nome di ruolo leggibile dall'uomo, si può inviare in pipe l'output di Get-MgRoleManagementDirectoryRoleAssignment a Get-MgRoleManagementDirectoryRoleDefinition (Figura 13), che tradurrà ogni ID di ruolo assegnato nel nome visualizzato corrispondente.

Figura 13. Rivelazione del nome visualizzato di un ruolo

Privileged Authentication Administrator è un ruolo altamente sensibile in Entra ID. Consente al titolare di gestire i metodi di autenticazione per tutti gli utenti, compreso il ripristino delle impostazioni MFA, la configurazione delle opzioni di accesso FIDO2 e senza password e la modifica dei criteri chiave che regolano le modalità di autenticazione degli utenti. Ecco perché un utente malintenzionato, agendo come proprietario, vorrebbe sicuramente aggiungere un segreto del cliente e usarlo per influenzare l'account Amministratore globale.

NOTA: Se avete seguito da vicino la fase di enumerazione, avrete probabilmente notato la verbosità e l'impegno manuale richiesto quando si utilizzano i cmdlet nativi di Microsoft Graph. (Cosa succederebbe se possedessimo 5[0] applicazioni Entra invece di 1?) Questo è uno dei limiti principali dell'affidarsi esclusivamente agli strumenti nativi. I comandi spesso restituiscono dati di basso livello (come i GUID) che richiedono ulteriori query per essere trasformati in informazioni significative.

È proprio per questo che molti framework di enumerazione automatizzano questi processi. Essi astraggono dalle query ripetitive e semplificano l'output, consentendo un'analisi dei privilegi e un processo decisionale più rapidi. Per esempio, per migliorare l'usabilità, si possono scrivere semplici funzioni wrapper come Find-OwnedServicePrincipals e Get-ServicePrincipalRoles che sono stati progettati per automatizzare la scoperta della proprietà del SP e risolvere in modo più efficiente le assegnazioni dei ruoli della directory:

      function Find-OwnedServicePrincipals {
    param([string]$UserId)
    
    # Get all service principals in tenant
    $allSPs = Get-MgServicePrincipal -All
    Write-Host "Found $($allSPs.Count) service principals in tenant"
    
    $ownedSPs = @()
    $checkCount = 0
    
    # Check ownership of each service principal
    foreach ($sp in $allSPs) {
        $checkCount++
        if ($checkCount % 50 -eq 0) {
            Write-Host "Checked $checkCount/$($allSPs.Count) service principals..."
        }
        
        try {
            $owners = Get-MgServicePrincipalOwner -ServicePrincipalId $sp.Id -ErrorAction SilentlyContinue
            if ($owners) {
                foreach ($owner in $owners) {
                    if ($owner.Id -eq $UserId) {
                        $ownedSPs += $sp
                        Write-Host "OWNED SERVICE PRINCIPAL FOUND!" -ForegroundColor Red
                        Write-Host "   Name: $($sp.DisplayName)" -ForegroundColor Yellow
                        Write-Host "   SP ID: $($sp.Id)" -ForegroundColor Yellow
                        Write-Host "   App ID: $($sp.AppId)" -ForegroundColor Yellow
                        break
                    }
                }
            }
        } catch {
            continue
        }
    }
    return $ownedSPs
}

function Get-ServicePrincipalRoles {
    param([object]$ServicePrincipal)
    
    Write-Host "Checking roles for: $($ServicePrincipal.DisplayName)"
    
    # Check directory role assignments for the SP
    $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 Cyan
        }
    } else {
        Write-Host "   No directory roles assigned"
    }
    
    return $roles
}

Ora, per scoprire tutti i presidi di servizio posseduti dall'utente compromesso ed enumerare i ruoli assegnati, possiamo semplicemente eseguire Find-OwnedService Principals, come Figura 14 spettacoli.

Figura 14. Scoperta dei presidi di servizio posseduti

Fase 3: Fare perno sul contesto del committente del servizio

Questo passaggio evidenzia il motivo principale per cui abbiamo creato questo scenario e lo abbiamo posizionato per primo nella serie: I service principal danno forma al panorama dell'escalation dei privilegi in Entra ID. Il movimento laterale nel contesto di sicurezza di un service principal e il suo sfruttamento per eseguire operazioni privilegiate è una tecnica fondamentale che ogni difensore, attaccante e ricercatore che lavora con Entra ID dovrebbe conoscere.

Aggiungiamo un segreto del cliente al file Finance Analytics Dashboard per stabilire un accesso backdoor e autenticarsi come SP:

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

$newSecret = Add-MgServicePrincipalPassword -ServicePrincipalId $SP.Id -PasswordCredential $passwordCredential

# Salva i dettagli del segreto aggiunto
$clientSecret = $newSecret.SecretText

Successivamente, disconnettere la sessione utente corrente con Disconnect-MgGraph, costruire le credenziali del client e autenticarsi utilizzando l'identità del mandante del servizio via Connect-MgGraph:

      $secureSecret = ConvertTo-SecureString -String $clientSecret -AsPlainText -Force
$credenziale = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $SP.AppId, $secureSecret
Connect-MgGraph -TenantId $tenantId -ClientSecretCredential $credential

E in effetti, ora siamo autenticati come i Finance Analytics Dashboard principale del servizio (Figura 15).

Figura 15. Dimostrazione dell'autenticazione come servizio principale

Il Get-MgContext rivela informazioni sulla modalità di autenticazione della sessione Microsoft Graph corrente, che determina direttamente il contesto di sicurezza, il livello di accesso e il modello di autorizzazione applicato. Concentriamoci sui campi AuthType e TokenCredentialType in quanto espongono la semantica dell'identità di base in Entra ID.

Dopo l'autenticazione come david.martinez, questi valori sono apparsi come:

      AuthType : Delegato
TokenCredentialType : Browser interattivo

Indica una sessione delegata, in cui il token emesso rappresenta un'identità utente. L'accesso è regolato dai ruoli assegnati all'utente e dalle autorizzazioni delegate, e tutte le operazioni sono eseguite per conto dell'utente. Il contesto della sessione è limitato a ciò a cui l'identità dell'utente ha accesso, poiché eredita le politiche di accesso condizionato, l'applicazione dell'MFA e i vincoli PIM.

Al contrario, un contesto solo app, come quello avviato da un mandante di servizio che utilizza le credenziali del cliente (AppId + Secret + TenantId) opera come un'identità non umana. Qualsiasi client (script, lavoro in background, demone) che utilizza tali credenziali può autenticarsi come l'applicazione e invocare le API di Microsoft Graph in base alle autorizzazioni dell'applicazione, indipendentemente dal contesto dell'utente. I criteri di accesso condizionato, MFA e PIM non sono applicabili o applicati in questo flusso.

Questa distinzione è fondamentale nella progettazione della sicurezza dell'identità e spiega perché il comportamento delle API, gli ambiti di accesso e i privilegi dei token differiscono nell'ambito delle stesse cmdlet, a seconda del contesto della sessione.

Come prevedibile, questa distinzione ha un forte impatto sulla superficie di attacco e sul potenziale di abuso. I flussi delegati sono vincolati dal contesto dell'utente, mentre i flussi solo app operano con fiducia a livello di servizio e spesso con confini di privilegio più ampi e meno controllati. Per gli aggressori, la compromissione del segreto di un'applicazione o di un certificato spesso si traduce in un accesso persistente e ad alto livello di privilegio che aggira i meccanismi di applicazione incentrati sull'identità.


Passo 4: acquisizione dell'account: accesso come amministratore globale

Ora che ci si è autenticati come identità con l'oggetto Privileged Authentication Administrator abbiamo la possibilità di resettare le password (Figura 16) per qualsiasi utente del tenant, compreso l'amministratore globale.

Figura 16: Reimpostazione della password amministratore

Con questo livello di accesso, possiamo anche assegnare un TAP(Figura 17) come metodo di autenticazione, consentendoci di bypassare l'MFA e di accedere direttamente al portale Azure:

Figura 17. Assegnazione di un TAP per l'autenticazione

Successivamente, si effettua il login con il TAP(Figura 18).

Figura 18. Accesso con il nuovo TAP

Si recupera quindi il flag dello scenario(Figura 19).

Figura 19. La bandiera viene catturata

Una volta completato lo scenario, si esegue lo script di pulizia per ripristinare il tenant EntraGoat allo stato originale(Figura 20).

Figura 20. La pulizia di EntraGoat ci prepara per il prossimo scenario

Questo scenario dimostra come configurazioni apparentemente legittime e comuni, come l'assegnazione della proprietà di un'applicazione a un utente standard, possano aprire la porta a una compromissione completa del tenant se abbinate a ruoli privilegiati.

Sfruttando la proprietà di un service principal, gli aggressori possono aumentare i privilegi, aggirare le difese incentrate sull'utente, come MFA e accesso condizionato, e infine ottenere l'accesso come amministratore globale attraverso un flusso di sole app.

Questo esercizio sottolinea l'importanza fondamentale di una solida governance delle autorizzazioni delle applicazioni, della proprietà del service principal e dell'assegnazione dei ruoli. Nei moderni ambienti cloud, i service principal sono spesso l'anello più debole e la comprensione del loro modello di identità duale, dei confini di accesso e del potenziale di abuso è essenziale sia per gli attaccanti che per i difensori.

Lo Scenario 1 di EntraGoat pone le basi per ulteriori esplorazioni e per i nostri prossimi scenari. Quindi continuate ad hackerare!


Affronta la tua prossima sfida EntraGoat

Nota finale

  1. https://github.com/BloodHoundAD/BARK

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.