Yuval Gordon Ricercatore di sicurezza | Microsoft

Come i potenziali attaccanti possono ottenere la persistenza dei privilegi su un DC attraverso DnsAdmins

Il team di ricerca Semperis ha recentemente ampliato una ricerca precedente che mostrava un abuso di funzionalità nell'ambiente Windows Active Directory (AD), in cui gli utenti del gruppo DnsAdmins potevano caricare una DLL arbitraria in un servizio DNS in esecuzione su un controller di dominio. Yuval Gordon del team di ricerca Semperis ha ampliato questa ricerca per mostrare come un problema con la tecnica precedente possa essere superato e per dimostrare che un avversario potrebbe utilizzare questa tattica per lasciare una backdoor non rilevata nell'Active Directory di un'azienda, un rischio significativo per la sicurezza.

In un post su Medium del 2017, i ricercatori di sicurezza hanno mostrato come gli utenti del gruppo DnsAdmins potessero utilizzare una "funzione" del protocollo di gestione DNS di Microsoft per far sì che il servizio DNS caricasse qualsiasi DLL. Questo servizio viene eseguito sui controller di dominio come NT AuthoritySystem, consentendo ai DnsSAdmins di scalare i privilegi a SYSTEM sui DC (con autorizzazioni pari almeno a quelle degli amministratori di dominio). Questo "trucco carino", come lo ha definito il ricercatore originale, Shay Ber, può essere utile per i Red Team che esplorano l'escalation dei privilegi di AD ed è una potenziale backdoor per gli aggressori nel controller di dominio.

Lettura correlata

In questo post, amplierò la ricerca di Shay Ber mostrando come superare un problema con la tecnica precedente e come renderla più furtiva. Esaminerò anche i permessi necessari per dimostrare che un avversario potrebbe usare questa tattica per lasciare una backdoor a DC che probabilmente non verrebbe notata e potrebbe bypassare alcuni strumenti.

Per ricapitolare la ricerca precedente condotta da Shay Ber e Nikhil Mittal, essi hanno dimostrato che è possibile caricare una DLL arbitraria in un servizio DNS in esecuzione su un controller di dominio attraverso i seguenti passaggi:

  1. L'attaccante deve far parte del gruppo DnsAdmins per eseguire l'eseguibile dnscmd e puntare il servizio a una DLL su un percorso UNC.
  2. L'attaccante riavvia il servizio DNS utilizzando "sc.exe stop/start dns": si tratta di una limitazione poiché le configurazioni predefinite non consentono agli utenti DnsAdmins di arrestare e avviare i servizi.

La mia ricerca amplia la comprensione di questa capacità di attacco nei seguenti modi:

  1. Non è strettamente necessario far parte di DnsAdmins per eseguire questo attacco, ma solo avere accesso in lettura/scrittura al contenitore MicrosoftDNS e accesso RPC al DC.
  2. È possibile riavviare il servizio DNS con i soli privilegi elencati al punto 1.

È quindi possibile per un aggressore con privilegi sufficienti creare/aggiornare un utente con permessi minimi e accesso diretto in lettura/scrittura al contenitore MicrosoftDNS. Nella maggior parte dei casi, questo utente passerebbe inosservato, poiché le autorizzazioni del contenitore sono raramente monitorate. Questo utente potrebbe rimanere inosservato e potrebbe essere utilizzato per eseguire comandi arbitrari con privilegi DC SYSTEM caricando una DLL nel processo DNS.

Il contesto della ricerca

Tre anni fa, nel post su Medium "Feature, not bug: DnsAdmin to DC compromise in one line", Shay Ber ha notato che qualsiasi membro del gruppo DnsAdmins può fare in modo che il servizio DNS Server carichi una DLL come NT AuthoritySystem sul DC al successivo riavvio del servizio.

Per impostazione predefinita, DnsAdmins non ha i permessi necessari per riavviare il servizio sul DC da remoto, il che significa che gli aggressori che vogliono abusarne dovranno aspettare (o usare altri metodi) fino al riavvio del server o del servizio per far girare il loro payload.

La mia missione di ricerca consisteva nel cercare un modo per forzare il servizio a riavviarsi o a caricare la DLL all'istante, e farlo nel modo più furtivo possibile. (Anche se avessi avuto i permessi per il riavvio usando sc.exe, avrebbe generato numerosi log e probabilmente sarebbe stato rilevato). Questo approccio si è rivelato sorprendentemente facile, ma ha avuto conseguenze inaspettate. Prima di continuare a leggere, vi consiglio di leggere la ricerca originale di Ber.

Un nuovo inizio
Ho iniziato semplicemente esaminando le specifiche MS-DNSP, alla ricerca di qualsiasi riferimento alla parola Restart, quando ho incontrato quanto segue:

Riavviare pszOperation
Figura 1: Riavvio di pszOperazione

Questa riga indica che uno dei comandi accettati dal server (pszOperation) in R_DnssrvOperation è restart, che (non sorprende) riavvia il processo del server DNS. Sembra perfetto!

Per semplificarmi la vita, ho consultato la documentazione dello strumento dnscmd (strumento CLI per la gestione dei server DNS) e ho cercato un modo per utilizzarlo per inviare un comando di riavvio al server DNS, ma non ho trovato nulla.

Ho pensato di provare a guardare le stringhe dello strumento per "riavviare" e (sorprendentemente) era lì:

Figura 2 Stringa di riavvio all'interno delle stringhe di dnscmd
Figura 2: Stringa di riavvio all'interno delle stringhe di dnscmd

Sebbene né la documentazione Microsoft né la guida dello strumento ne facciano menzione, esiste un'opzione "/Restart" che si può usare in dnscmd per attivare il riavvio del processo di un server DNS.

Figura 3 Richiamo riuscito del comando di riavvio
Figura 3: Richiamo riuscito del comando di riavvio

Il servizio ha attivato un riavvio interno, chiamando una funzione interna chiamata "reloadShutdown" e riavviando tutto senza terminare il processo, al contrario di un normale riavvio del servizio.

Quindi ora sapevo come attivare un reload e caricare la DLL all'istante, ma quali erano i permessi necessari?

Tornando alla documentazione, il controllo iniziale di qualsiasi operazione DNS consiste nel verificare le credenziali del client per il privilegio di lettura del contenitore MicrosoftDNS. Per le nostre operazioni specifiche (riavvio e ServerLevelPluginDll) è richiesto anche il privilegio di scrittura sullo stesso oggetto.

A questo punto ho attivato un reload, facendo in modo che il servizio caricasse la DLL inviata in precedenza (il comando mostrato nella sezione dello scenario) e lasciando meno tracce dietro di sé, poiché non venivano generati log sul riavvio del servizio o sulla creazione di processi.

I log generati, entrambi nel registro del server DNS, erano l'ID evento 770 (è stata caricata una DLL di plugin a livello di server) e l'ID evento 140:

Figura 4: Voci di registro del server DNS

Nella prossima sezione, spiegherò perché viene generato questo errore. Se volete saltare i dettagli, potete passare alla sezione "potenziale impatto".

Il bug
È successo qualcosa di inaspettato durante l'esecuzione del comando di riavvio: La DLL è stata caricata (come previsto) e il servizio ha continuato a funzionare, ma nel registro del server DNS è stato generato il seguente log:

Figura 5: Registro degli errori generato dopo il riavvio dell'operazione
Figura 5: Registro degli errori generato dopo il riavvio dell'operazione

Il controllo del codice di errore ha evidenziato un problema con l'endpoint RPC (0x6cc - L'endpoint è un duplicato).

Quando ho provato a inviare qualsiasi altro comando allo stesso server DNS, utilizzando dnscmd, improvvisamente non ha funzionato nulla:

Figura 6 Non funziona nulla
Figura 6: Non funziona nulla

Anche la console di gestione DNS non funziona più:

Figura 7 Altri errori
Figura 7: Altri errori

Per capire cosa non funzionava, ho usato ApiMonitor e ho visto che c'era un problema nella registrazione dell'endpoint dopo il riavvio.

Quando si riavvia il servizio del server DNS nel modo consueto (ad esempio, services.msc), il servizio si arresta e si avvia senza generare alcun errore. Pertanto, il passo successivo è stato quello di verificare il motivo per cui non viene generato un errore in questo caso rispetto a quando viene trasmesso al server un comando di ricarica tramite /restart.

Tuttavia, è successa una cosa interessante. Sia il riavvio che la ricarica del servizio sono falliti durante la stessa chiamata API.

Questo messaggio suona come un campanello d'allarme, vero? Il servizio non è riuscito a disiscrivere l'endpoint RPC e ha generato un errore duplicato quando ha cercato di utilizzare l'endpoint.

La spiegazione del fatto che non si sono verificati errori successivi dopo un riavvio del servizio è che quando si verifica il riavvio del servizio, il processo esce, il che causa la disiscrizione automatica dell'endpoint. Questo non accade quando si attiva un ricaricamento del servizio (il processo non viene effettivamente riavviato, quindi non esce dal processo).

Impatto potenziale

Utilizzando questi metodi, un utente malintenzionato può eseguire DLL arbitrarie nel contesto di sicurezza del servizio DNS.

Poiché il servizio DNS è spesso in esecuzione sui controller di dominio, questa vulnerabilità offre agli aggressori l'opportunità di aumentare i privilegi di qualsiasi utente del dominio sotto il loro controllo. Come descritto nella sezione successiva, oltre a far progredire l'attacco in corso, le specifiche ACL dei container di Active Director offrono agli aggressori l'opportunità di creare "amministratori dormienti", ovvero utenti non privilegiati che possono aumentare i privilegi a piacimento.

Affinché questi attacchi funzionino, un attaccante deve disporre di quanto segue:

  • Dnscmd (non è necessario, ma fa risparmiare tempo e fatica)
  • RPC aperto a DC
  • Autorizzazioni di lettura e scrittura sul contenitore MicrosoftDNS (nel contenitore di sistema)

Esempio di scenario

Gli aggressori che riescono a compromettere un utente del gruppo DnsAdmin possono espandere la loro posizione in diversi modi. Oltre all'escalation immediata dei privilegi all'utente SYSTEM su un DC (che consente loro di aggiungere utenti Domain Admin o persino di ottenere una Skeleton Key), possono anche dare a un utente con privilegi bassi la possibilità di elevare i privilegi assegnandogli l'accesso in lettura/scrittura al contenitore MicrosoftDNS come parte del loro attacco iniziale.

Questo utente potrebbe essere creato dall'attaccante o da un utente esistente con una password compromessa o un SPN noto per un successivo kerberoasting. Mentre i gruppi AD privilegiati, come gli amministratori di dominio, sono spesso monitorati da vicino, le ACL degli oggetti esatti sono notoriamente difficili da monitorare in modo efficace. Questo crea una situazione in cui gli utenti sembrano non avere privilegi ma, in realtà, possono riavviare il servizio DNS e iniettare nuovamente le DLL per riottenere l'accesso privilegiato, fornendo una backdoor persistente nell'ambiente.

Figura 8: Utenti del dominio

Nella schermata precedente, l'utente "haxer" sembra un utente non privilegiato perché è solo un membro degli utenti del dominio. Ma tutto ciò di cui ha bisogno per diventare un amministratore di dominio è avere RPC al DC e accesso in scrittura a una condivisione accessibile dal DC.

In questo esempio, la DLL avvierà una shell al caricamento che riceverà i comandi da un file in una condivisione (command.txt) e scriverà l'output in un altro file nella stessa condivisione (out.txt).

L'aggressore accede come utente "haxer", attualmente non membro di alcun gruppo privilegiato, e crea una condivisione con accesso in lettura/scrittura per tutti con la sua DLL dannosa:

Figura 9: L'attaccante effettua il login come "haxer".

Ora tutto ciò che l'aggressore deve fare è registrare la DLL come ServerLevelPluginDll sul DC, attivare un riavvio del servizio e iniziare a inviare comandi utilizzando il file creato:

Figura 10: Registrazione della DLL

Due aspetti di questo scenario sono importanti da ricordare:

  1. Se il DC non può accedere al percorso inviato come ServerLevelPluginDLL, il trigger di riavvio farà terminare il servizio DNS, che non potrà essere riavviato finché il DC non sarà in grado di accedere al percorso o il percorso non verrà rimosso dal registro del DC. (E come DnsAdmin, probabilmente non saremo in grado di avviare il servizio quando è interrotto).
  2. A causa del bug descritto sopra, l'attivazione di una ricarica causerà problemi con la duplicazione dell'endpoint RPC e non sarà possibile inviare altri comandi o attivare un altro riavvio:
Figura 11: Il comando di riavvio non riesce

Registrazione e rilevamento

Ecco alcune misure che le aziende possono adottare per registrare e rilevare potenziali intrusioni. Innanzitutto, è importante notare che se il processo DNS Server è stato riavviato utilizzando il comando restart pszOperation, NON genererà un log con ID evento 7036 perché non si tratta di un riavvio del servizio.

1. L'ID evento 770 verrà creato nel registro DNS Server sul DC quando caricherà la DLL dopo un riavvio, con il percorso della DLL specificato.

Figura 12: Evento 770 registrato

2. L'ID evento 140 verrà creato quando verrà attivato un riavvio tramite R_DnssrvOperation (solo a causa del bug; idealmente questo non accadrà in futuro).

Figura 13: Evento 140 registrato

3. Monitorare le modifiche di ntSecurityDescriptor su MicrosoftDNS e sul gruppo DnsAdmins (ID evento 5136).

4. Monitorare l'aggiunta di membri al gruppo DnsAdmins.

5 Trattare gli utenti e i gruppi che hanno già queste autorizzazioni come amministratori di dominio e monitorarli di conseguenza.

6. Gli utenti e i gruppi con queste autorizzazioni devono essere aggiunti al gruppo Utenti protetti per una maggiore protezione.

7. Utilizzando IPSIDS, è possibile monitorare le richieste R_DnssrvOperation e R_DnssrvOperation2 da computer non amministratori a server DNS.

8. Monitorare le modifiche al percorso di registro "HKLMSYSTEMCurrentControlSetServicesDNSParametersServerLevelPluginDLL" sui server DNS.

Protezione del servizio DNS Microsoft

Implementando queste best practice di registrazione e rilevamento, l'organizzazione può difendersi da uno scenario in cui gli utenti che hanno già le autorizzazioni per gestire il DNS possono sfruttarlo per compromettere un controller di dominio o lasciare una backdoor furtiva nel dominio per intrusi indesiderati.