Vi serve il cloud computing? Iniziate subito

Funzionalità di difesa in Windows per l'RPC

Stiv Kupchik

scritto da

Stiv Kupchik

August 10, 2023

Stiv Kupchik

scritto da

Stiv Kupchik

Stiv Kupchik svolge il ruolo di Security Researcher Team Lead in Akamai. I suoi progetti di ricerca ruotano intorno ai componenti interni dei sistemi operativi, alla ricerca sulle vulnerabilità e all'analisi dei malware. Ha presentato la sua ricerca in occasione di conferenze come Black Hat, Hexacon e 44CON. Oltre ad essere un esperto di cybersicurezza, Stiv ha conseguito anche una laurea in fisica.

In questo post, vedremo come utilizzare e analizzare gli eventi forniti dal provider RPC ETW e come esaminare gli eventi alla ricerca di attività potenzialmente dannose.

Sommario

I contenuti riportati in questo blog sono stati presentati originariamente in occasione del BlackHat USA 2023.

MS-RPC: come logorare il protocollo per rilevare gli attacchi

Continuiamo il nostro approfondimento dell'MS-RPCcon un altro blog. Questa volta, tuttavia, invece di focalizzarci sul lato offensivo alla ricerca delle eventuali vulnerabilità, andremo a discutere di alcune delle funzionalità di difesa integrate in Windows. Vedremo come utilizzare queste funzionalità per farci un'idea di cosa avviene nell'RPC, sperando di rilevare eventuali attività dannose.

L'MS-RPC è parte integrante del sistema operativo Windows, che, pertanto, viene utilizzato da molti movimenti laterali. Attacchi come PSExec, RST (Remote Scheduled Task)DCSynce PetitPotam vengono tutti eseguiti tramite i protocolli MS-RPC, pertanto può risultare difficile distinguere il traffico di rete legittimo da quello dannoso solo con i metadati di rete tradizionali (indirizzo IP e porta di origine/destinazione; spesso anche informazioni del processo).

Intendiamo rafforzare la nostra visibilità con ETW (Event Tracing for Windows), un meccanismo di tracciamento e monitoraggio integrato nel sistema operativo Windows. ETW ci fornisce preziose informazioni, in modo specifico per l'RPC, specialmente se confrontato con i metadati di rete tradizionali.

Il concetto del tracciamento di eventi RPC tramite il suo provider ETW non è nuovo e sono già disponibili a tal scopo molte risorse e strumenti validi (i relativi collegamenti si trovano nella nostra sezione Riferimenti ; fateci sapere se ne conoscete altri). La maggior parte della ricerca attuale si focalizza sugli eventi lato client, in cui i criminali possono manipolare o modificare il programma per aggirare interamente il processo di registrazione. Ci focalizzeremo, invece, sul rilevamento degli attacchi tramite gli eventi lato server, che sono al di fuori della portata dei criminali, e vedremo nello specifico cosa serve per analizzarli.

In questo post, vedremo come utilizzare e analizzare gli eventi forniti dal provider RPC ETW e come esaminare gli eventi alla ricerca di attività potenzialmente dannose. Tramite il provider ETW, possiamo anche vedere l'esatta operazione richiesta, il che ci fornisce una granularità molto più accurata con cui poter rilevare gli attacchi. Vedremo esattamente come funziona tutto ciò a breve.

Ripasso: che cos'è l'RPC?

Una chiamata di procedura remota o RPC è una forma di comunicazione interprocesso (IPC). Nello specifico, questo protocollo è progettato per richiamare una funzione da remoto tra processi diversi. Nel nostro caso, ci concentreremo sull'implementazione del protocollo Microsoft MS-RPC.

L'MS-RPC è concepito come modello client-server. Il server definisce l'interfaccia che renderà visibile tramite l'IDL (Interface Definition Language). All'interno dell'IDL, troviamo un identificatore univoco universale (UUID) per l'interfaccia, nonché le definizioni delle funzioni che vengono rese visibili (Figura 1).

  [
    uuid(12345678-4000-2006-0000-20000000001a)
]

interface Test
{
    void Foo([in] int number,  [in] char *message);
    void Bar([out] int * result);
}

Figura 1. Esempio di definizione dell'interfaccia IDL

La comunicazione viene stabilita tramite alcuni protocolli di trasporto, ciascuno dei quali presenta un proprio endpoint (Figura 2). L'esempio riportato di seguito è il miglior modo per spiegare questo processo: È possibile stabilire una comunicazione RPC tramite il TCP, in cui il protocollo di trasporto è il TCP e l'endpoint è il socket TCP, identificato da un numero di porta.

Protocolli di trasporto

Endpoint

TCP

Named pipe

UDP

ALPC

HTTP

Socket Hyper-V

<Numero porta>

<Nome pipe>

<Numero porta>

<Porta ALPC>

<Hostname>

<UUID>

Figura 2. I protocolli di trasporto più comuni e i loro rispettivi tipi di endpoint

È importante notare che, mentre le funzioni hanno un nome leggibile nel file IDL, sono identificate nella rete in modo diverso tramite un numero intero, chiamato opnum (abbreviazione di "numero di operazione"), anziché con un nome di stringa. Questo numero, di solito, viene assegnato in base all'ordine di visualizzazione delle funzioni nella definizione dell'interfaccia IDL (quindi, nell'esempio in Figura 1, Foo verrà identificato come opnum 0, mentre Bar verrà identificato come opnum 1). Questo aspetto risulterà importante in un secondo momento quando dovremo sapere il numero di operazioni delle funzioni rilevanti per identificarle nei dati visualizzati.

Per una panoramica più completa e approfondita dell'MS-RPC, potete consultare il nostro post precedenteo una delle nostre presentazioni di conferenze all' HexaCon o al DEF CON sull'argomento.

#define ETW

Event Tracing for Windows (ETW) è un meccanismo di tracciamento e registrazione integrato all'interno del kernel di Windows, che utilizza un modello provider-consumatore: i provider inviano gli eventi al kernel, che li reinstrada ai programmi per consumatori. Sia i provider che i consumatori devono registrarsi con il kernel in anticipo (Figura 3).

Inoltre, poiché l'instradamento di un evento è gestito dal kernel, se gli eventi vengono inviati dai provider, ma non ci sono consumatori, gli eventi vengono semplicemente ignorati e inviati a vuoto.

Flusso relativo alla generazione di rapporti sugli eventi ETW Figura 3. Illustrazione del flusso relativo alla generazione di rapporti sugli eventi ETW

Microsoft-Windows-RPC

Il provider RPC ETW viene implementato all'interno del runtime RPC, rpcrt4.dll, che contiene 13 eventi diversi. Tuttavia, a noi ne interessano maggiormente quattro di essi: gli eventi 5 e 7, rispettivamente, per l'avvio e l'interruzione di una chiamata al client, e gli eventi 6 e 8 per l'avvio e l'interruzione di una chiamata al server. Ci focalizzeremo sugli eventi di avvio di una chiamata (Figura 4), poiché forniscono il maggior numero di informazioni (gli eventi di interruzione di una chiamata indicano lo stato di restituzione dell'RPC). Sia gli eventi del client che quelli del server hanno lo stesso formato.

  <template tid="RpcServerCallStartArgs_V1">
     <data name="InterfaceUuid" inType="win:GUID"/>
     <data name="ProcNum" inType="win:UInt32"/>
     <data name="Protocol" inType="win:UInt32"/>
     <data name="NetworkAddress" inType="win:UnicodeString"/>
     <data name="Endpoint" inType="win:UnicodeString"/>
     <data name="Options" inType="win:UnicodeString"/>
     <data name="AuthenticationLevel" inType="win:UInt32"/>
     <data name="AuthenticationService" inType="win:UInt32"/>
     <data name="ImpersonationLevel" inType="win:UInt32"/>
  </template>

Figura 4. Schema degli eventi di avvio di una chiamata RPC ETW

In teoria, i dati contenuti nell'evento ci forniscono tutti i metadati necessari per ottenere informazioni sul traffico RPC. Ora sappiamo cosa è richiesto dall'opnum e dall'UUID dell'interfaccia e conosciamo anche l'indirizzo di origine o destinazione (a seconda se guardiamo agli eventi del client o del server) tramite il campo NetworkAddress. Ma non può essere così semplice.

Infatti, non lo è: il runtime RPC non compila il campo NetworkAddress durante gli eventi di chiamata del server, pertanto dobbiamo trovare altri modi per individuare questi dati se desideriamo ottenere i metadati di connessione. Gli eventi del client compilano questo campo.

Uno screenhot del runtime RPC. All'interno di un controllo if della variabile globale Microsoft_Windows_RPCEnableBits, si trova una chiamata alla funzione EtwEventWriteTransfer. Dei tanti argomenti ricevuti dalla funzione, l'argomento dell'indirizzo di rete viene inviato come 0. Figura 5. Uno screenhot del runtime RPC; in evidenza il campo relativo all'indirizzo di rete, in cui viene visualizzato uno 0

A questo punto, si pone una domanda: Possiamo ignorare gli eventi del server e basarci solo sul lato client? La risposta a questa domanda è: No. Poiché stiamo cercando di individuare eventuali comportamenti dannosi, che si originano dal computer controllato dal criminale, non possiamo essere sicuri che tali comportamenti non andranno a danneggiare il provider ETW lato client (disattivando o bloccando i suoi eventi) né che passeranno attraverso il runtime RPC.

La nota libreria python Impacket, spesso usata negli strumenti e nei PoC (Proof-of-Concept) degli attacchi (e contenente le implementazioni degli attacchi alle reti, come PSExec), implementa il traffico RPC al suo interno in modo da consentire ai criminali che lo utilizzando di eludere il runtime RPC senza venire registrati nel provider ETW. Poiché gli eventi del server esulano dal controllo dei criminali, è più prudente basarsi su tali eventi:ecco perché ora ci concentreremo su come acquisire i dati di rete da altre fonti e come associarli all'evento RPC.

Associazione degli eventi RPC ai flussi di rete

Ora, passiamo dal provider RPC ETW ad altri provider ETW: i provider TCP e SMB . Si tratta di due comuni protocolli di trasporto del traffico RPC. Poiché abbiamo detto che il tipo di endpoint RPC dipende dal protocollo di trasporto, possiamo associare l'endpoint (numero porta, nome pipe, ecc.) non appena ricevuto dal provider RPC al rispettivo valore nel provider ETW di trasporto.

Per il protocollo TCP, è alquanto semplice. Consideriamo l'ID evento 1017, chiamato TcpAcceptListenerComplete, che si attiva una volta completato l'handshake TCP a tre vie.

Sono presenti due campi (fondamentalmente): LocalAddress e RemoteAddress (anche se, nel nostro caso, poiché consideriamo gli eventi del server, l'indirizzo locale si riferisce al server, mentre l'indirizzo remoto si riferisce al client). I valori dei campi dell'indirizzo sono in forma binaria e contengono l'indirizzo della famiglia, l'indirizzo IP e il numero di porta (Figura 6).

0

1

2

3

4

5

6

7

Indirizzo famiglia

Numero porta

Valore indirizzo (IP se AF_INET)

Figura 6. Formato del campo binario dell'indirizzo

A questo punto, dobbiamo semplicemente estrarre l'indirizzo IP (del client) dal campo RemoteAddress e monitorarlo con la porta (di destinazione) nel campo LocalAddress . Ora, una volta acquisito un evento RPC sul nostro server, tramite lo stesso numero di porta TCP, possiamo conoscere la sua origine in base all'associazione porta-indirizzo IP che abbiamo estratto dal provider TCP (Figura 7).

Un'infografica che illustra la modalità di associazione degli eventi RPC e TCP. I due eventi vengono illustrati come pezzi di un puzzle da far combaciare. L'evento RPC contiene il campo Endpoint relativo alla porta TCP locale. L'evento TCP contiene il campo LocalAddress anch'esso relativo alla porta TCP locale, che include anche il campo RemoteAddress, contenente l'indirizzo IP del client Figura 7. Associazione tra eventi TCP e RPC

Con SMB, la situazione è un po' più complicata poiché diverse informazioni compaiono in diversi eventi ETW. L'endpoint è una named pipe, che è come un file, tuttavia, è possibile accedere a più file tramite la stessa sessione SMB. Pertanto, in tal caso, per associare l'endpoint con la sua origine di rete, dobbiamo monitorare due eventi: uno per la connessione attuale e uno per la richiesta del file (Figura 8).

Per l'evento di connessione, l'ID 500, Smb2ConnectionAcceptStart, viene avviato una volta stabilita la connessione SMB, da cui possiamo acquisire l'indirizzo IP di origine e l'UUID di connessione. L'ID evento 8, Smb2RequestCreate_V2, contiene il nome file richiesto e lo stesso campo UUID di connessione. Ora dobbiamo solo effettuare un riferimento incrociato dei due eventi tramite l'UUID di connessione per associare il nome pipe all'indirizzo IP che l'ha richiesto (e, successivamente, dobbiamo associare il nome pipe all'endpoint di chiamata RPC).

Un diagramma che illustra il processo di associazione degli eventi SMB e RPC. Dall'evento Smb2ConnectionAcceptStart, salviamo l'indirizzo IP e utilizziamo il GUID di connessione per associarlo al Smb2RequestCreate_V2 che lo segue. All'interno del Smb2RequestCreate_V2, prendiamo il nome della pipe, che viene poi associato al campo dell'endpoint all'interno dell'evento RpcServerCallStart_V1 fornito dal provider RPC. Da qui, manteniamo i campi Opnum e Interface, che, insieme all'indirizzo IP salvato in precedenza, ci forniscono tutte le informazioni. Figura 8. Utilizzo degli eventi SMB ETW per associare l'indirizzo IP di origine con gli eventi RPC ETW

Abbiamo implementato un algoritmo per evitare all'utente di dover effettuare tutte queste associazioni da solo e il nostro strumento di visibilità RPC è disponibile nel nostro archivio GitHub. Lo strumento, scritto in Python, salva il traffico di rete RPC registrato in un database Neo4j per consentirne una facile visualizzazione.

Rilevamento dell'attacco

Una volta acquisite tutte le informazioni necessarie, possiamo finalmente focalizzarci sul rilevamento dei flussi RPC dannosi. Il processo generale è semplice: Dopo aver individuato un attacco condotto tramite RPC, viene eseguito un PoC per verificare l'interfaccia RPC utilizzata e l'operazione richiesta. Quindi, possiamo semplicemente creare una firma associata a tale operazione. Abbiamo incluso query di firme compatibili con l'implementazione del database Neo4j nella nostra release, ma di seguito riportiamo la logica e le condizioni generali.

PSExec

PSExec è un nome generico per una tecnica di attacco e anche uno strumento Sysinternals (che ha dato il suo nome alla tecnica). Praticamente, lo strumento copia un file binario del servizio nella condivisione ADMIN$ della destinazione remota (la cartella di installazione di Windows), quindi comunica con il gestore del servizio tramite l'interfaccia RPC (MS-SCMR) per creare un servizio per il file binario ed eseguirlo (Figura 9).

Il flusso dell'attacco psexec: un hacker, un PC e due frecce tra di essi. La prima freccia viene indicata con 1. SMB e contiene il testo "cp psexecsvc.exe \\VICTIM\ADMIN$\psexesvc.exe" per mostrare il comando che consente di copiare il file binario del servizio sul computer preso di mira. La prima freccia viene indicata con "2. RPC, MS-SCMR" e contiene il testo "RCreateServiceW(\\Victim, C:\Windows\psexesvc.exe)" per mostrare la funzione SCMR da chiamare per avviare il servizio da remoto. Figura 9. Flusso dell'attacco PSExec

Esistono tante ragioni legittime che portano a contattare i computer remoti tramite SCMR, come, ad esempio, i watchdog che interrogano lo stato del servizio remoto. Sono, invece, in numero molto inferiore le ragioni che spingono a creare da remoto nuovi servizi. Pertanto, non vogliamo attivare avvisi su qualsiasi connessione tramite SCMR (che possiamo rilevare persino senza l'RPC ETW, semplicemente associando una connessione di rete in entrata al processo del gestore del servizio services.exe), ma solo sulle connessioni che creano servizi remoti.

Di conseguenza, la nostra firma deve essere (in generale, non specifica per la nostra implementazione dello strumento di visibilità RPC):

interface_uuid ==  “367ABB81-9844-35F1-AD32-98F038001003” AND (opnum == 0xC OR opnum == 0x18)

dove 0xC è l'opnum per RCreateServiceW e 0x18 è l'opnum per RCreateServiceA.

Utilità di pianificazione remota

Analogamente al file PSExec, è possibile usare l'utilità di pianificazione per avviare un file binario remoto e ottenere in tal modo il movimento laterale. Non è necessario neanche avviare un nuovo file binario poiché è sufficiente avviare una console cmd o PowerShell e scaricare un file binario ospitato online.

Sempre analogamente al file PSExec, non vogliamo rilevare qualsiasi accesso al servizio dell'utilità di pianificazione, ma siamo maggiormente interessati alle chiamate RPC indirizzate a SchRpcRegisterTask.

interface_uuid ==  “86D35949-83C9-4044-B424-DB363231FD0C” AND opnum == 0x1

DCSync

DCSync è un altro attacco basato su RPC, che tuttavia prende di mira i controller di dominio. In tal caso, il criminale si connette al controller di dominio reale, spacciandosi per un nuovo controller di dominio, quindi chiede di replicare il database delle credenziali del controllo di dominio per ottenere l'accesso agli hash delle password KRBTGT.

La richiesta di replica si verifica tramite l'interfaccia MS-DRSR RPC e utilizza la specifica funzione DRSGetNCChanges (opnum 3).

interface_uuid ==  “e3514235-4b06-11d1-ab04-00c04fc2dcd2” AND opnum == 0x3

PetitPotam

PetitPotam è un attacco di coercizione dell'autenticazione sul servizio EFS (Encrypted File System). In pratica, i criminali possono connettersi all'interfaccia EFS RPC (MS-EFSR) e richiedere di aprire un file remoto specificato da un percorso UNC. Quindi, viene attivata una connessione SMB in uscita con l'autenticazione che il criminale può quindi inoltrare.

Una volta rilasciato, il PoC dell'attacco utilizzava la vulnerabilità EfsRpcOpenFileRaw (opnum 0), che da allora è stata corretta. Topotam, il ricercatore che ha individuato questa vulnerabilità, ha inoltre trovato che EfsRpcEncryptFileSrv (opnum 4) presentava la stessa vulnerabilità.

interface_uuid ==  “c681d488-d850-11d0-8c52-00c04fd90f7e” AND (opnum == 0x0 OR opnum == 0x4)

Svantaggi

Anche se ci consente di ottenere tantissime informazioni, il provider RPC ETW non può soddisfare tutte le nostre esigenze in termini di sicurezza. Benché sapere quale operazione è richiesta in ogni flusso di rete sia fondamentale, le informazioni più importanti, ossia quali dati sono stati passati in ogni richiesta, non vengono registrate. Pertanto, il rilevamento di questo movimento laterale tramite il provider ETW non è ancora solo un approccio euristico, pur con una maggior quantità di contesto rispetto alle 4-tuple delle reti tradizionali.

Si tratta anche di un puro metodo di rilevamento, che non può essere usato per bloccare o rispondere agli attacchi. Microsoft ci fornisce un altro meccanismo di difesa integrato per l'RPC, ossia il filtro dell'RPC nel firewall di Windows. Per ulteriori informazioni su questo meccanismo di filtraggio e per apprendere come usarlo, potete consultare la nostra guida definitiva ai filtri dell'RPC (Remote Procedure Call).

Riepilogo

Il provider RPC ETW non è una nuova aggiunta a Windows, ma è stato spesso trascurato per quanto riguarda la difesa delle reti. Sono disponibili alcuni strumenti in grado di interagire e utilizzare eventi con questo provider, anche se, per la maggior parte, sono concepiti per i ricercatori della sicurezza e si focalizzano meno sul punto di vista delle reti.

In questo post, abbiamo discusso di come usare il provider RPC ETW insieme ai provider TCP e SMB per ottenere visibilità sulle operazioni RPC richieste che provengono dalla rete. Questa capacità ci fornisce un approccio euristico che possiamo usare per rilevare potenziali richieste dannose da poter sfruttare per il movimento laterale.

Riferimenti



Stiv Kupchik

scritto da

Stiv Kupchik

August 10, 2023

Stiv Kupchik

scritto da

Stiv Kupchik

Stiv Kupchik svolge il ruolo di Security Researcher Team Lead in Akamai. I suoi progetti di ricerca ruotano intorno ai componenti interni dei sistemi operativi, alla ricerca sulle vulnerabilità e all'analisi dei malware. Ha presentato la sua ricerca in occasione di conferenze come Black Hat, Hexacon e 44CON. Oltre ad essere un esperto di cybersicurezza, Stiv ha conseguito anche una laurea in fisica.