Chiamata e registrazione - Attacco di inoltro contro il client WinReg RPC
Analisi riassuntiva
Stiv Kupchik, ricercatore di Akamai, ha scoperto una nuova vulnerabilità di elevazione dei privilegi (EoP) nel client Remote Registry di Microsoft, CVE-2024-43532, con un punteggio CVSS di 8,8.
La vulnerabilità sfrutta un meccanismo di fallback nell'implementazione del client di WinReg che utilizza i protocolli di trasporto obsoleti in modo non sicuro se il trasporto SMB non è disponibile.
Sfruttando questa vulnerabilità, un criminale può inoltrare i dettagli di autenticazione NTLM ai servizi ADCS (Active Directory Certificate Service) e richiedere un certificato per sfruttare un'ulteriore autenticazione nel dominio. Forniamo una POC (Proof-of-Concept) nel nostro archivio GitHub.
La vulnerabilità è stata responsabilmente segnalata al Microsoft Security Resource Center (MSRC) a febbraio e descritta nella Patch Tuesday di ottobre 2024.
La vulnerabilità influisce su tutte le versioni di Windows prive di patch.
I nostri risultati sono stati presentati anche in occasione della conferenza sulla sicurezza informatica No Hat.
Introduzione
L'MS-RPC è l'implementazione di Microsoft del protocollo e dello standard RPC (Remote Procedure Call). Una chiamata RPC è una forma di comunicazione interprocesso che consente ai processi di rendere visibili le funzionalità che altri processi possono richiamare. È un componente fondamentale del sistema operativo Windows, su cui si basano più servizi, dalla soluzione di gestione dei servizi alle interruzioni in Wininit.
Il nostro team ha effettuato molte ricerche sull'MS-RPC, sia per la sicurezza offensiva , in cui abbiamo individuato un ampio vettore di attacco sotto forma di attacchi di memorizzazione nella cache, e per la sicurezza difensiva , in cui abbiamo analizzato i relativi meccanismi di sicurezza.
Questa volta, vogliamo esaminare l'RPC da una prospettiva diversa. Un protocollo che consente di effettuare le comunicazioni e le operazioni tra diversi computer deve riguardare l'autenticazione e, in effetti, il protocollo RPC supporta la trasmissione delle credenziali e l'autenticazione come parte del suo processo di associazione. Tuttavia, è possibile inoltrare l'autenticazione, pertanto abbiamo deciso di trovare le relative opportunità.
RPC, autenticazione e tutti gli elementi relativi
Le sessioni RPC sono gestite dalle associazioni. Un'applicazione client si connette all'applicazione di un server, si associa all'interfaccia RPC desiderata e richiede di eseguire una specifica funzione (Figura 1).
La richiesta e la risposta di associazione possono trasportare più campi di dati, in base a quanto richiesto per la connessione. Di solito, se non è richiesta l'autenticazione, viene semplicemente usata l'associazione RPC per decidere sulla sintassi di trasferimento che verrà usata per integrare i parametri della funzione alle chiamate successive.
Che cosa manca in questa interazione? L'autenticazione, ovviamente! In che modo il server può conoscere l'identità del client e se il client può eseguire l'azione richiesta? La risposta è: non lo sa, a meno che il client non abbia specificamente aggiunto un contesto di sicurezza (l'autenticazione) all'associazione. Per impostazione predefinita, tutte le connessioni RPC non sono autenticate e non tutti i server RPC richiedono l'autenticazione.
Per effettuare l'autenticazione (o, in termini RPC, per "aggiungere un contesto di sicurezza"), il client deve aggiungere altri dati alla richiesta di associazione, negoziare il protocollo di autenticazione (ad esempio, NTLM o Kerberos) e inserire gli altri metadati richiesti dal protocollo di autenticazione (come nome utente, dominio, ecc.) (Figura 2).
Individuazione degli obiettivi della ricerca
Il primo obiettivo aziendale consiste nel capire come considerare l'autenticazione dal punto di vista delle API. Questa operazione viene eseguita da una chiamata indirizzata ad una delle funzioni RpcBindingSetAuthInfo* dal client dopo aver creato un handle di associazione. Consultando la documentazione di queste funzioni, si nota un campo chiamato AuthenticationLevel, che indica il livello di sicurezza fornito dall'autenticazione.
La sicurezza con l'autenticazione non consiste solo nel verificare che l'utente esista e che sia autorizzato, ma può essere usata anche per prevenire episodi di manomissione. I livelli di autenticazione variano dalla semplice verifica della connessione una volta stabilita (RPC_C_AUTHN_LEVEL_CONNECT) alla completa crittografia e firma di tutto il traffico per garantire che nulla sia manomesso (RPC_C_AUTHN_LEVEL_PKT_PRIVACY). Ovviamente, i criminali sono interessati al primo livello, che non prevede sistemi di difesa del traffico, rendendolo quindi vulnerabile.
Ma la storia non è così semplice. Gli attacchi di inoltro RPC non sono un concetto nuovo, quindi moltissimi client e server RPC in Windows sono stati già corretti con patch allo scopo di usare il massimo livello di autenticazione in grado di garantire la mancata riuscita di questo tipo di attacchi. È necessario perlustrare il sistema operativ0 nella speranza di trovare alcuni frammenti precedenti di codice che non sono ancora sicuri per qualche motivo (Figura 3).
WinReg: un candidato promettente
Come si sospettava, l'elenco dei potenziali obiettivi che abbiamo individuato includeva meno del 5% dei server e dei client RPC in totale, la maggior parte dei quali non usa più un'autenticazione non protetta. Tuttavia, abbiamo individuato un candidato promettente nel componente advapi32.dll,
che è fondamentale per le API di Windows e implementa gran parte della logica "avanzata" in Windows (come suggerisce il suo nome). Questo componente esporta più di 800 funzioni da vari campi: registrazione di eventi, crittografia, WMI e molto altro.
Per i nostri scopi, abbiamo individuato che, in alcuni casi, la funzione interna BaseBindToMachine richiama RpcBindingSetAuthInfoA con un livello di autenticazione RPC_C_AUTHN_LEVEL_CONNECT, che è il nostro livello desiderato. Il comando BaseBindToMachine viene richiamato dalla funzione RegConnectRegistryExW esportata (anche se non documentata) (Figura 4), se riceve un percorso UNC per il nome di un computer.
Se esaminiamo il comando BaseBindToMachine, possiamo notare che, in realtà, contiene le chiamate alle funzioni RpcBindingSetAuthInfoW e RpcBindingSetAuthInfoA. La prima viene usata in modo sicuro, con il livello di autenticazione RPC_C_AUTHN_LEVEL_PKT_PRIVACY, mentre la seconda utilizza il livello di autenticazione RPC_C_AUTHN_LEVEL_CONNECT, che può essere inoltrato perché non verifica l'autenticità o l'integrità della connessione (Figura 5).
È necessario capire perché ci sono due chiamate in conflitto tra loro. Osservando la logica della funzione, possiamo vedere che presenta una variabile del puntatore e un array di funzioni (Figura 6). Queste funzioni impostano le informazioni sull'associazione RPC in modo da usare un trasporto RPC specifico, che, per impostazione predefinita, tenta di utilizzare il protocollo SMB e le named pipes, ma, se non riesce, tenta di effettuare l'associazione tramite SPX, TCP/IP e altri.
Per vari motivi, se si basa su altri protocolli diversi dall'SMB, utilizza la funzione RpcBindingSetAuthInfoA per impostare il livello di autenticazione su Connect, che non è un livello sicuro.
Il fallback sul protocollo TCP/IP è alquanto promettente perché significa che possiamo usare il metodo di autenticazione non sicuro per inoltrare il traffico tramite un attacco MITM (Machine-in-The-Middle) che passa inosservato dal client. Anche se è possibile usare altri protocolli di trasporto, si tratta di componenti obsoleti, pertanto potrebbe non essere realistico trovarli in una rete moderna (e il loro utilizzo potrebbe comunque attivare dei segnali di allarme). Il protocollo TCP/IP è molto più comune per il trasporto RPC, quindi dovrebbe essere considerato appropriato anche in un'impostazione di red team.
È importante sapere che entrambe le funzioni BaseBindToMachine e RegConnectRegistryExW accettano un flag come argomento per prevenire il comportamento del fallback, ma la funzione RegConnectRegistryW di base richiama RegConnectRegistryExW senza la presenza di questo flag.
Il processo di inoltro
L'inoltro è abbastanza semplice in quanto l'inoltro NTLM è una tecnica d'uso comune. La maggior parte della logica che ci serve è già implementata nel comando ntlmrelayx di Impacket, che verrà maggiormente usato da noi.
Costruzione del server di inoltro RPC
Al comando ntlmrelayx manca un server TCP/IP RPC, che viene implementato solo come server SMB. In quanto tale, dobbiamo costruire il nostro server di inoltro, che deve rifiutare la named pipe di WinReg per attivare un fallback alla funzione di associazione TCP/IP.
Di seguito vengono riportati i tre punti critici da implementare:
Il mapper dell'endpoint RPC
La richiesta di associazione RPC con NTLM
La sfida NTLM
Il mapper dell'endpoint RPC è responsabile della conversione degli UUID dell'interfaccia RPC nei rispettivi endpoint, che, nel caso del trasporto TCP/IP, corrispondono ad un numero di porta. A differenza del protocollo SMB, in cui gli endpoint sono named pipe univoche, che si possono sapere in anticipo, gli endpoint TCP utilizzano porte temporanee, pertanto è necessario un altro livello di conversione.
La parte critica è rappresentata dai problemi correlati alla sfida NTLM. L'associazione RPC funziona con l'NTLM in questo modo: un messaggio di negoziazione NTLM viene inviato durante la richiesta di associazione, quindi viene inviata una sfida NTLM con la risposta di associazione. Infine, il client deve inviare un altro messaggio, chiamato AUTH3, con la risposta della sfida (Figura 7).
Per effettuare l'inoltro, dobbiamo semplicemente analizzare i messaggi corrispondenti nel nostro server RPC. Una volta individuato un messaggio di negoziazione NTLM in un messaggio di associazione, viene stabilita la nostra connessione con il server di autenticazione di destinazione e viene richiesto anche di effettuare l'autenticazione tramite NTLM. È quindi necessario acquisire la sfida inviata dal server, inoltrarla nuovamente alla vittima e reinviare la risposta al server per ottenere la nostra sessione autenticata.
Tutto ciò che dobbiamo considerare è il server a cui vogliamo far inoltrare l'autenticazione.
Inoltro da RPC a RPC
Verrebbe subito da pensare di far inoltrare l'autenticazione ad un altro server RPC su un altro computer, come la soluzione di gestione dei servizi o l'utilità di pianificazione, e ottenere un'esecuzione di codice remoto in questo modo. Il problema è che, tuttavia, nessuno usa più un'autenticazione non sicura tramite RPC, quindi non possiamo far inoltrare l'autenticazione ad un server RPC di alto profilo (l'assenza di un'autenticazione non sicura tramite RPC è il motivo per cui i nostri obiettivi di ricerca sono stati limitati).
Sia i server RPC della soluzione di gestione dei servizi che quelli dell'utilità di pianificazione richiedono il livello RPC_C_AUTHN_LEVEL_PKT_PRIVACY, che crittografa tutto il traffico con l'hash NTLMv2 del client, di cui non sappiamo nulla neanche con l'inoltro. Al contrario, dobbiamo esaminare la questione da un'angolazione diversa.
Da RPC ad ADCS
Fortunatamente, il team di SpecterOps ha lavorato tantissimo sull' ADCS, specialmente sull'inoltro NTLM al server ADCS. Anche in questo caso l'implementazione avviene in Impacket per impostazione predefinita, pertanto tutto ciò che dobbiamo fare è trasmettere la nostra sessione autenticata al modulo HTTPAttack di Impacket e lasciare che la magia abbia inizio.
Il server web HTTP di ADCS non richiede alcuna soluzione per la sicurezza ed è vulnerabile agli attacchi di inoltro. Sfruttando questa vulnerabilità, una volta effettuata l'autenticazione, è possibile richiedere un certificato da poter poi usare per effettuare a sua volta l'autenticazione senza doversi preoccupare di inoltrare nuovamente l'autenticazione (Figura 8).
Abbiamo utilizzato questo certificato per effettuare l'autenticazione al servizio LDAP sui controller di dominio e per creare un nuovo amministratore di dominio persistente nel dominio violato (Figura 9).
Il potenziale impatto
Una funzione in advapi non è interessante di per sé, ma ha un impatto solo se viene usata da qualcun altro. Se guardiamo rapidamente le importazioni del comando RegConnectRegistryExW o RegConnectRegistryExA , non risulta nulla su un controller di dominio aggiornato, mentre una ricerca effettuata per il comando RegConnectRegistryW rivela tantissimi potenziali candidati, come certutil e certsrv (AD CS), EFS, DFS e molti altri.
Rilevamento
Il servizio Remote Registry non è attivato per impostazione predefinita su tutti i computer Windows. È possibile rilevare il suo stato utilizzando la seguente osquery:
SELECT display_name, status, start_type, pid FROM services WHERE name='RemoteRegistry'
Tuttavia, questa operazione non protegge dalla CVE-2024-43532perché si tratta di un problema del client. I risultati della query dovrebbero sollevare casi di utilizzo effettivi per il servizio Remote Registry nell'organizzazione che andrebbe considerata al momento di rafforzare i vostri sistemi.
Per rilevare i client che utilizzano una WinAPI vulnerabile, potete usare la seguente regola YARA:
import "pe"
rule winreg_client_import {
meta:
description = "Detect binaries that rely on RegConnectRegistry"
author = "Stiv Kupchik with Akamai Technologies"
condition:
pe.is_pe and (
pe.imports(pe.IMPORT_ANY, "advapi32.dll", "RegConnectRegistryA")
or pe.imports(pe.IMPORT_ANY, "advapi32.dll", "RegConnectRegistryW")
or pe.imports(pe.IMPORT_ANY, "advapi32.dll", "RegConnectRegistryExA")
or pe.imports(pe.IMPORT_ANY, "advapi32.dll", "RegConnectRegistryExW")
)
}
Gli utenti di Akamai Guardicore Segmentation possono anche creare regole di policy per il traffico in entrata nel servizio Remote Registry (Figura 10).
È anche possibile usare l'utilità ETW (Event Tracing for Windows) per monitorare il traffico RPC sul client e sul server di comunicazione. Abbiamo discusso di questo argomento nella nostra presentazione tenuta in occasione del Black Hat 2023 e nel suo blog correlato. Gli utenti possono utilizzare il nostro strumento open-source di visibilità RPC per tracciare le chiamate RPC e filtrare l'UUID dell'interfaccia RPC di WinReg {338cd001-2244-31f1-aaaa-900038001003}.
Conclusione
Sebbene il protocollo RPC e il protocollo MS-RPC siano stati progettati tenendo conto della sicurezza, possiamo chiaramente vedere come si sono evoluti i principi della sicurezza nel tempo analizzando le varie implementazioni dell'interfaccia RPC. Anche se la maggior parte dei server e dei client RPC oggi sono sicuri, di tanto in tanto, è possibile scovare reliquie di implementazioni non sicure a vari livelli.
In questo caso, siamo riusciti ad ottenere un inoltro NTLM, che è una classe di attacchi appartenente più che altro al passato a dimostrare che i sistemi di difesa della rete devono essere il più accurati possibile perché non potete mai sapere quale interfaccia esistente è comunque vulnerabile o in esecuzione.
Cronologia delle divulgazioni
01/02/2024 - Vulnerabilità segnalata all'MSRC
25/04/2024 - Rapporto chiuso come problema di documentazione
17/06/2024 - Rapporto riaperto con PoC e spiegazioni migliorate
08/07/2024 - Vulnerabilità confermata
08/10/2024 - Vulnerabilità corretta con patch
19/10/2024 - Pubblicazione del post del blog