Movimento laterale senza file con oggetti COM intrappolati

Primo piano sulle mani di un uomo che digita su laptop e tiene in mano un tablet in un ufficio buio illuminato di blu

Sin dai primi anni '90, Component Object Model (COM) ha rappresentato una pietra miliare dello sviluppo di Microsoft Windows e ancor oggi è molto diffuso nelle applicazioni e nei sistemi operativi Windows moderni. La dipendenza dai componenti COM e lo sviluppo esteso di funzionalità nel corso degli anni hanno creato una superficie d'attacco generosa. Nel febbraio 2025, James Forshaw (@tiraniddo) di Google Project Zero ha pubblicato un post sul blog che descrive un approccio innovativo per abusare della tecnologia di remoting Distributed COM (DCOM), in cui gli oggetti COM intrappolati possono essere utilizzati per eseguire codice gestito da .NET nel contesto di un processo DCOM lato server. Forshaw evidenzia diversi casi d'uso per l'escalation dei privilegi e il bypass del Protected Process Light (PPL).

Sulla base della ricerca di Forshaw, Mohamed Fakroud (@T3nb3w) ha pubblicato un'implementazione della tecnica per bypassare le protezioni PPL all'inizio di marzo 2025. Jimmy Bayne (@bohops) ed io abbiamo condotto una ricerca simile nel febbraio 2025, che ci ha portato a sviluppare una tecnica di movimento laterale senza file proof-of-concept sfruttando oggetti COM intrappolati.

Background

COM è uno standard di interfaccia binaria e un livello di servizio middleware che consente l'esposizione di componenti distinti e modulari per interagire tra loro e con le applicazioni, indipendentemente dal linguaggio di programmazione sottostante. Ad esempio, gli oggetti COM sviluppati in C++ possono interfacciarsi facilmente con un'applicazione .NET, consentendo agli sviluppatori di integrare efficacemente diversi moduli software. DCOM è una tecnologia di remoting che consente ai client COM di comunicare con i server COM tramite comunicazione inter-processo (IPC) o chiamate di procedura remota (RPC). Molti servizi Windows implementano componenti DCOM accessibili localmente o da remoto.

Le classi COM sono tipicamente registrate e contenute all'interno del Registro di Windows. Un programma client interagisce con un server COM creando un'istanza della classe COM, nota come oggetto COM. Questo oggetto fornisce un puntatore a un'interfaccia standardizzata. Il client utilizza questo puntatore per accedere ai metodi e alle proprietà dell'oggetto, facilitando la comunicazione e la funzionalità tra il client e il server.

Gli oggetti COM sono spesso bersagli di ricerca per valutare l'esposizione alla vulnerabilità e scoprire caratteristiche abusabili. Un oggetto COM intrappolato è una classe di bug in cui un client COM crea un'istanza di una classe COM in un server DCOM fuori processo, dove il client controlla l'oggetto COM tramite un puntatore a un oggetto sottoposto a marshalling per riferimento. A seconda della condizione, questo vettore di controllo può presentare difetti logici legati alla sicurezza.

Il blog di Forshaw descrive un caso d'uso di bypass PPL in cui l'interfaccia IDispatch, esposta nella classe COM WaaSRemediation, viene manipolata per l'abuso di oggetti COM e l'esecuzione di codice .NET. WaaSRemediation è implementata nel servizio WaaSMedicSvc, che viene eseguito come un processo svchost.exe protetto nel contesto di NT AUTHORITY\SYSTEM. L'eccellente guida di Forshaw è stata la base per la nostra ricerca applicata e per lo sviluppo di una tecnica di prova di movimento laterale senza file.

Uomo che guarda il computer

Rafforza la tua intelligence sulla sicurezza 


Rimani al passo con le minacce con notizie e insight su sicurezza, AI e altro ancora, ogni settimana con la newsletter Think. 


Panoramica della ricerca

Il nostro percorso di ricerca è iniziato esplorando la classe COM WaaSRemediation che supporta l'interfaccia IDispatch . Questa interfaccia consente ai client di eseguire il late binding. Normalmente, i client COM hanno le definizioni di interfaccia e tipo per gli oggetti che utilizzano definite in fase di compilazione. Invece, il binding tardivo permette al client di scoprire e chiamare metodi sull'oggetto al tempo di esecuzione. IDispatch include il metodo GetTypeInfo , che restituisce un'interfaccia ITypeInfo. ITypeInfo dispone di metodi che possono essere utilizzati per scoprire informazioni sul tipo di oggetto che lo implementa.

Se una classe COM utilizza una libreria di tipi, può essere interrogata dal client tramite ITypeLib (ottenuto da ITypeInfo-> GetContainingTypeLib) per recuperare le informazioni sui tipi. Inoltre, le librerie di tipi possono anche fare riferimento ad altre librerie di tipi per ottenere informazioni aggiuntive sui tipi.

Secondo il post sul blog di Forshaw, WaaSRemediation fa riferimento alla libreria di tipi WaaSRemediationLib, che a sua volta fa riferimento a stdole (automazione OLE). WaaSRemediationLib utilizza due classi COM di quella libreria, StdFont e StdPicture. Eseguendo il COM Hijacking sull'oggetto StdFont tramite modifica della chiave del registro TreatAs, la classe punterà a un'altra classe COM di nostra scelta, come System.Object nel framework .NET. È importante notare che Forshaw sottolinea che StdPicture non è fattibile poiché questo oggetto esegue un controllo per l'istanziazione fuori processo, quindi abbiamo continuato a concentrarci sull'utilizzo di StdFont.

Gli oggetti .NET sono interessanti per noi grazie al metodo GetTypedi System.Object. Attraverso GetType, possiamo eseguire la riflessione .NET per accedere infine ad Assembly.Load. Sebbene sia stato scelto System.Object, questo tipo risulta essere la radice della gerarchia dei tipi in .NET. Pertanto, è possibile utilizzare qualsiasi oggetto COM .NET.

Con la fase iniziale impostata, c'erano altri due valori DWORD nella chiave HKLM\Software\Microsoft\.NetFramework necessari per rendere reale il nostro caso d'uso percepito:

Dopo aver confermato che l'ultima versione del CLR e di .NET poteva essere caricata nei nostri primi test, abbiamo capito di essere sulla strada giusta.

Dal processo locale al computer remoto

Spostando la nostra attenzione sugli aspetti programmatici remoti, abbiamo prima utilizzato Remote Registry per manipolare i valori delle chiavi del registro .NetFramework e dirottare l'oggetto StdFont sulla macchina di destinazione. Successivamente, abbiamo sostituito CoCreateInstance con CoCreateInstanceEx per istanziare l'oggetto COM WaaSRemediation sul target remoto e ottenere un puntatore all'interfaccia IDispatch .

Con un puntatore a IDispatch, chiamiamo il metodo membro GetTypeInfo per ottenere un puntatore all'interfaccia ITypeInfo, che è intrappolata nel server. I metodi membro chiamati successivamente si verificano sul lato server. Dopo aver identificato il riferimento della libreria di tipi contenuta di interesse (stdole) e aver derivato il successivo riferimento all'oggetto di classe di interesse (StdFont), abbiamo infine utilizzato il metodo "remotable" CreateInstance sull'interfaccia ITypeInfo per reindirizzare il flusso di link degli oggetti StdFont (tramite manipolazione precedente TreatAs ) per istanziare System.Object.

Poiché AllowDCOMReflection è impostato correttamente, possiamo eseguire la riflessione .NET su DCOM per accedere ad Assembly.Load e caricare un assembly .NET nel server COM. Poiché utilizziamo Assembly.Load su DCOM, questa tecnica di movimento laterale è completamente senza file, in quanto il trasferimento dei byte dell'assembly è gestito dalla magia del remoting DCOM. Per una spiegazione approfondita di questo flusso tecnico dall'istanziazione dell'oggetto alla riflessione, consulta il seguente diagramma:

diagramma di flusso che mostra l'istanziazione della classe System.Object
Flusso di istanziazione della classe System.Object

Difficoltà dello sviluppo

Il nostro primo e principale problema è stato chiamare Assembly.Load_3 tramite IDispatch->Invoke. Invoke passa un array di argomenti alla funzione di destinazione, mentre Load_3 è l'overload di Assembly.Load che accetta un array di byte singoli. Pertanto, abbiamo dovuto racchiudere il SAFEARRAY di byte all'interno di un altro SAFEARRAY di VARIANT: inizialmente, abbiamo continuato a provare a passare un singolo SAFEARRAY di byte.

codice che mostra come creare un equivalente non gestito di Object Byte
Creazione di un equivalente non gestito di Object Byte

Un altro problema è stato trovare il giusto sovraccarico di Assembly.Load. Le funzioni di supporto sono state prese dal codice CVE-2014-0257 di Forshaw, che includeva la funzione GetStaticMethod. Questa funzione utilizza la riflessione di .NET su DCOM per trovare un metodo statico dato un puntatore di tipo, il nome del metodo e il suo numero di parametri. Assembly.Load ha due overload statici che richiedono un solo argomento; pertanto, abbiamo finito per utilizzare una soluzione complicata. Abbiamo notato che la terza istanza di Load con un singolo argomento era la scelta giusta.

codice utilizzato per cercare il giusto sovraccarico Assembly.Load
Alla ricerca del giusto sovraccarico Assembly.Load

Difficoltà operative

Uno dei maggiori svantaggi che abbiamo osservato con questa tecnica è stato che il beacon generato avrebbe avuto una durata limitata al client COM; in questo caso, la durata dell'applicazione del nostro binario di armamento "ForsHops.exe" (dal nome elegante, ovviamente). Quindi, se ForsHops.exe puliva i riferimenti COM o usciva, lo faceva anche il beacon che girava sotto la svchost.exe della macchina remota. Abbiamo provato diverse soluzioni, come ad esempio far sì che il nostro assembly .NET bloccasse indefinitamente il suo thread principale, eseguisse lo shellcode in un altro thread e facesse sì che ForsHops.exe lasciasse sospeso il thread dell'exploit, ma niente di elegante.

Il thread principale del caricatore .NET si blocca mentre lo shellcode viene eseguito in un thread separato
Il thread principale del caricatore .NET si blocca mentre lo shellcode viene eseguito in un thread separato

Nello stato attuale, ForsHops.exe viene eseguito finché il beacon non esce, dopodiché rimuove le operazioni del registro. Esistono margini di miglioramento, ma lo lasceremo come esercizio per il lettore.

Dimostrazione di esecuzione ForShops.exe
Esecuzione di ForShops.exe
Beacon riuscito su Windows 2019 Server
Beacon riuscito su Windows 2019 Server
schermata di Beacon in esecuzione in un processo svchost PPL
Il beacon viene eseguito in un processo PPL svchost
esempio di ForShops.exe che rimuove le modifiche dopo l'uscita del beacon
ForShops.exe rimuove le modifiche dopo l'uscita del beacon

Consigli difensivi

La guida per il rilevamento proposta da Samir Bousseaden (@SBousseaden) dopo che Mohamed Fakroud ne ha pubblicato l'implementazione si applica anche a questa tecnica di movimento laterale:

  • Rilevamento degli eventi di carico CLR all'interno del processo svchost.exe di WaaSMedicSvc
  • Rilevamento della manipolazione (o creazione) del registro della seguente chiave: HKLM\SOFTWARE\Classes\CLSID\{0BE35203-8F91-11CE-9DE3-00AA004BB851}\TreatAs (chiaveTreatAs di StandardFont CLSID)

Inoltre, consigliamo di implementare i seguenti controlli aggiuntivi:

  • Rilevamento della manipolazione DACL di HKLM\SOFTWARE\Classi\CLSID\{0BE35203-8F91-11CE-9DE3-00AA004BB851}
  • Ricerca della presenza di valori OnlyUseLatestCLR e AllowDCOMReflection abilitati in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework
  • Abilitare il firewall basato su host per limitare l'accesso temporaneo alle porte DCOM ove possibile

Inoltre, utilizza la seguente regola YARA proof-of-concept per rilevare l'eseguibile standard ForsHops.exe:

regola Detect_Standard_ForsHops_PE_By_Hash

{
    meta:   
        description = "Detects the standard ForShops PE file by strings"
        reference = "GitHub Project: https://github.com/xforcered/ForsHops/"
    strings:
        $s1 = "System.Reflection.Assembly, mscorlib" wide
        $s2 = "{72566E27-1ABB-4EB3-B4F0-EB431CB1CB32}" wide
        $s3 = "{34050212-8AEB-416D-AB76-1E45521DB615}" wide
        $s4 = "GetType" wide
        $s5 = "Load" wide

    condition:
        all of them
}

Conclusione

La nostra implementazione estende leggermente l'abuso del COM spiegato nel blog di Forshaw sfruttando oggetti COM intrappolati per il movimento laterale piuttosto che l'esecuzione locale per il bypass PPL. Pertanto, è ancora soggetta agli stessi rilevamenti delle implementazioni che eseguono l'esecuzione locale.

Puoi trovare qui il codice ForsHops.exe proof-of-concept per il movimento laterale.

Ringraziamenti

Un ringraziamento speciale a Dwight Hohnstein (@djhohnstein) e Sanjiv Kawa (@sanjivkawa) per aver fornito feedback su questa ricerca e per aver fornito una recensione dei contenuti dei post del blog.

Risorse

Mixture of Experts | 12 dicembre, episodio 85

Decoding AI: Weekly News Roundup

Unisciti al nostro gruppo di livello mondiale di ingegneri, ricercatori, leader di prodotto e molti altri mentre si fanno strada nell'enorme quantità di informazioni sull'AI per darti le ultime notizie e gli ultimi insight sull'argomento.

Soluzioni correlate
Soluzioni di sicurezza aziendale

Trasforma il tuo programma di sicurezza con le soluzioni offerte dal più grande provider di sicurezza aziendale.

Esplora le soluzioni di cybersecurity
Servizi di cybersecurity

Trasforma il tuo business e gestisci i rischi con la consulenza sulla cybersecurity, il cloud e i servizi di sicurezza gestiti.

    Scopri i servizi di sicurezza informatica
    Cybersecurity dell'intelligenza artificiale (AI)

    Migliora la velocità, l'accuratezza e la produttività dei team di sicurezza con soluzioni di cybersecurity basate sull'AI.

    Esplora la cybersecurity dell'AI
    Fai il passo successivo

    Che tu abbia bisogno di soluzioni di sicurezza dei dati, di gestione degli endpoint, o di gestione delle identità e degli accessi (IAM), i nostri esperti sono pronti a collaborare con te per farti raggiungere un solido livello di sicurezza.Trasforma il tuo business e gestisci i rischi con un leader a livello globale nel campo della consulenza per la cybersecurity, del cloud e dei servizi di sicurezza gestiti.

    Esplora le soluzioni di cybersecurity Scopri i servizi di cybersecurity