Bypassare il controllo delle applicazioni di Windows Defender con Loki C2
Windows Defender Application Control (WDAC) è una soluzione di sicurezza che limita l’esecuzione a software attendibili. Essendo classificato come limite di sicurezza, Microsoft offre pagamenti di bug bounty per i bypass idonei, rendendolo un campo di ricerca attivo e competitivo.
Risultati tipici di una richiesta di bug bounty per aggirare il WDAC:
Guardando l’elenco dei blocchi consigliati per WDAC di Microsoft, vediamo leggende come Jimmy Bayne (@bohops) e Casey Smith (@subTee) scoprire bypass WDAC che rimangono non corretti ma che hanno ricevuto menzioni onorarie. Guardando oltre questo elenco, il Progetto LOLBAS contiene ulteriori bypass non corretti che non sono stati riconosciuti nella lista di blocco di Microsoft. Un esempio è l’applicazione Microsoft Teams, che rimane un bypass WDAC valido nonostante sia documentata in LOLBAS.
Quando abbiamo incontrato il WDAC durante le operazioni del Red Team, siamo riusciti ad aggirarlo e abbiamo eseguito il nostro attacco Command and Control di fase 2 (C2) utilizzando le seguenti tecniche:
1. Utilizzare un LOLBIN noto come MSBuild.exe
2. Il caricamento in parallelo DLL di un’applicazione attendibile con una DLL non attendibile
3. Utilizzare una regola di esclusione personalizzata dalla politica WDAC del cliente
4. Trovando una nuova catena di esecuzione in un’applicazione affidabile che consenta la distribuzione di C2
Come ha spiegato Ruben Boonen (@FuzzySec) nel suo intervento Wild West Hackin' Fest Statikk Shiv: Leveraging Electron Applications for Post-Exploitation, le applicazioni Electron funzionano come browser web che visualizzano applicazioni desktop utilizzando tecnologie web standard come HTML, JavaScript e CSS. Il motore JavaScript in Electron è Node.js, che fornisce potenti API in grado di interagire con il sistema operativo host. Queste API consentono azioni come la lettura e la scrittura di file, l'esecuzione di programmi e altre operazioni tipiche delle applicazioni native.
Durante il tempo di esecuzione, un'applicazione Electron legge i file JavaScript, interpreta il loro codice e li esegue all'interno del processo Electron. L'animazione qui sotto mostra come l'applicazione Microsoft Teams Electron legge un file JavaScript in fase di esecuzione, che poi utilizza il modulo child_process per eseguire whoami.exe.
In questo esempio, il processo Teams Electron legge il file JavaScript, che poi genera whoami.exe utilizzando il modulo child_process. Questo modulo attiva il processo Electron per eseguire la sua API esportata uv_spawn, responsabile dell'interazione con il sistema operativo per creare un nuovo processo.
L'architettura tradizionale di un'applicazione Windows consiste in:
L'EXE chiama le funzioni esportate dalle DLL per estendere le funzionalità. Tuttavia, le applicazioni Electron invertono questa architettura. Invece dell'EXE che chiama le API dalle DLL, lo stesso Electron EXE espone le esportazioni di API, che vengono chiamate da:
Questa struttura consente a Node.js e ai moduli di nodo di interagire con il sistema operativo in modi che il tradizionale JavaScript in un browser non può fare.
Nell'immagine qui sotto esaminiamo l'applicazione Teams Electron tramite PE Bear, uno strumento fantastico creato da @hasherezade, che rivela che il file eseguibile Teams Electron contiene 2.977 API esportate. Questa ampia superficie API offre funzionalità estese che possono essere utilizzate dai file JavaScript di Node.js e dai moduli di nodo per interagire con il sistema operativo.
Poiché le applicazioni Electron eseguono JavaScript al tempo di esecuzione, la modifica di questi file JavaScript consente agli autori degli attacchi di inserire codice Node.js arbitrario nel processo di Electron. Sfruttando le API Node.js e Chromium, il codice JavaScript può interagire con il sistema operativo.
Non ho scoperto la possibilità di modificare file JavaScript di applicazioni Electron affidabili per eseguire codice Node.js JavaScript arbitrario. I primi tentativi a riguardo risalgono al 2022.
All'inizio del 2022, Andrew Kisliakov ha pubblicato il blog "Microsoft Teams and other Electron Apps as LOLbins". Andrew e @mrd0x hanno contribuito con le loro scoperte al progetto LOLBAS.
Più tardi, nel 2022, Valentina Palmiotti (@chompie1337), Ellis Springe (@knavesec) e Ruben hanno approfondito ulteriormente questo approccio, portando allo sviluppo di uno strumento di persistenza interna che da allora è stato utilizzato nelle operazioni del red team.
Sempre nel 2022, Michael Taggart ha lanciato il progetto quASAR, uno strumento progettato per modificare le applicazioni Electron per consentire l'esecuzione dei comandi. Nel suo blog "Quasar: Compromising Electron Apps", ha raccontato che nel settembre 2022, un membro del progetto Electron lo ha contattato affermando che il controllo dell'integrità era una funzione di prova e che si sperava sarebbe stato pienamente supportato in futuro.
Sperimentando personalmente con le applicazioni Electron più recenti, come Signal, ho avuto la conferma che per alcune applicazioni Electron sono ora in atto controlli di integrità che impediscono la modifica dei file JavaScript. Tuttavia, molte applicazioni Electron attivamente distribuite rimangono vulnerabili.
Questa tecnica è stata osservata anche in attacchi reali. Nel 2022, un attore delle minacce ha eseguito il backdoor dell'applicazione di chat MiMi modificando i file JavaScript in bundle sul server di distribuzione. Trend Micro ha identificato questa operazione come un attacco alla supply chain, in cui l'app compromessa veniva distribuita agli utenti finali, permettendo l'esecuzione di codice JavaScript malevolo che scaricava ed eseguiva un payload C2 di fase 2.
Ad aprile 2024, stavo cercando [Bobby Cooke (@0xBoku) che scrive] una nuova catena di esecuzione da utilizzare in preparazione di un'operazione Red Team per un cliente del settore finanziario. Questo settore ha standard di sicurezza più elevati e normative più severe, spesso implementando controlli di sicurezza aggiuntivi come il WDAC. Durante la mia ricerca, mi sono imbattuto in un'altra applicazione Electron vulnerabile. Tuttavia, poiché non era firmato da Microsoft, era improbabile che potesse aggirare la politica WDAC del client.
Poi sono passato all'applicazione legacy di Microsoft Teams, che è firmata da Microsoft e può aggirare anche le politiche WDAC più rigide. A questo punto, Dylan Tran (@d_tranman) si è unito a me in questa missione, e abbiamo iniziato a cercare un modo per passare da un'esecuzione arbitraria Node.js JavaScript all'esecuzione del nostro shellcode C2 di fase 2.
Sebbene Node.js possa interagire con il sistema operativo tramite le sue API, manca della piena funzionalità di C, dove gli sviluppatori possono chiamare direttamente WINAPI e NTAPI. Per ovviare a questa mancanza, gli sviluppatori hanno creato i moduli di nodo, che estendono le funzionalità del framework Node.js. Questi moduli, compilati da codice C++, possono chiamare WINAPI, interagire con Node.js API ed eseguire JavaScript all'interno delle applicazioni Electron. I moduli di nodo compilati hanno un'estensione .node e vengono caricati nei processi Windows tramite un evento di caricamento DLL.
Durante la nostra ricerca, abbiamo esaminato diverse applicazioni Electron e analizzato i loro moduli nodo firmati. Abbiamo scoperto che questi moduli potevano essere interagiti direttamente da JavaScript, permettendoci di utilizzare le loro funzionalità.
Sebbene la creazione di moduli personalizzati per l'esecuzione di shellcode sia un approccio praticabile e una funzionalità di Loki C2, presenta un dilemma simile a quello dell'uovo e della gallina. Il caricamento di un modulo nodo da JavaScript attiva un evento di caricamento DLL, che può essere bloccato dalle politiche WDAC che impongono rigide regole contro le DLL non firmate. Fortunatamente, esiste un gran numero di moduli di nodo firmati nelle applicazione Electron legittime.
Questo approccio all'esecuzione del nostro payload sembrava promettente, così abbiamo condiviso le nostre scoperte con Valentina e lei si è unita a noi in questa missione. Con il suo aiuto, ci siamo immersi più a fondo nell'inversione dei moduli di nodo firmati, alla ricerca di vulnerabilità o funzionalità integrate che ci avrebbero consentito di eseguire shellcode arbitrario.
Un esempio di modulo di nodo con funzionalità utili è windows_process_tree.node, un modulo firmato da Microsoft fornito in bundle con Visual Studio Code. Analizzandolo in PE Bear, rivela due funzioni esportate, come mostrato di seguito.
A differenza delle DLL tradizionali, i moduli di nodo non elencano tutte le loro funzioni disponibili nella tabella di esportazione. La funzione napi_register_module_v1 esportata è chiamata dal processo Electron ed è responsabile del caricamento del modulo ed esporne la funzionalità esportata al processo Electron. Questo agisce come un ponte, permettendo a JavaScript all'interno del processo Electron di chiamare e interagire con le funzioni del modulo.
Un modo banale per elencare tutte le funzioni richiamabili in un modulo Node è utilizzare il codice Node.js qui sotto.
Eseguendo questo script Node.js in PowerShell, vediamo che ci sono due funzioni richiamabili in windows_process_tree.node. Vale a dire getProcessList e getProcessCpuUsage.
Con la persistenza, è possibile determinare come chiamare queste funzioni da JavaScript. Una limitazione di Node.js è che manca un'API integrata per elencare tutti i processi in esecuzione sul sistema. Questa limitazione è il motivo per cui Microsoft ha introdotto la funzione getProcessList all'interno di questo modulo, ampliando le funzionalità dell'applicazione Electron di VS Code.
È possibile recuperare queste informazioni direttamente in JavaScript, utilizzando il modulo child_process per eseguire PowerShell in un processo figlio, che restituisce i dettagli sui processi in esecuzione. Nell'immagine sottostante, Loki C2 genera un processo secondario PowerShell per recuperare la lista dei processi.
Questo approccio presenta rischi significativi per la sicurezza operativa. L'esecuzione di processi secondari PowerShell è altamente rilevabile e aumenta la probabilità che un'operazione venga segnalata o bloccata. Per evitare ciò, Loki C2 utilizza moduli nodo firmati come windows_process_tree.node per estendere le Node.js funzionalità.
Loki C2 include il comando ps, che recupera le informazioni sui processi caricando il modulo firmato Microsoft windows_process_tree.nodo e chiamando la funzione getProcessList, come si vede nell'immagine sottostante.
Di seguito è riportato il codice JavaScript di Loki C2 che richiama la funzione getProcessList nel modulo windows_process_tree.node. getProcessList restituisce i dati di processo in formato JSON, che Loki C2 formatta in una tabella strutturata per una migliore leggibilità.
Determinare come chiamare correttamente le funzioni all'interno dei moduli del nodo può essere una sfida poiché le loro strutture interne non sono documentate. Tuttavia, utilizzando strumenti come Ghidra, sviluppato dalla NSA, e collaborando con esperti di ingegneria inversa come Valentina, siamo riusciti ad analizzare questi moduli e a identificare come interagire con le loro funzioni.
Alla fine Valentina ha scoperto un modo per eseguire il nostro shellcode C2 Stage 2 senza caricare una DLL non firmata, ma lascerò che sia lei a rivelare i dettagli. Insieme, Dylan, Valentina e io abbiamo lavorato per perfezionare la tecnica e garantire stabilità alla futura campagna di phishing.
Purtroppo, la nostra campagna iniziale di phishing via e-mail è stata segnalata e bloccata dal Blue Team. Dopo questa battuta d'arresto, Brett Hawkins (@h4wkst3r) ed io ci stavamo preparando per una seconda campagna. In quanto responsabile del payload, non volevo riutilizzare lo stesso, altrimenti sarebbe stato troppo facile per il Blue Team rintracciarci e fermare la nostra seconda campagna. Tuttavia, non avevamo abbastanza tempo per applicare la tecnica di Valentina a un nuovo payload, quindi ho iniziato a svilupparne uno nuovo utilizzando un approccio alternativo.
In genere, la possibilità di eseguire codice JavaScript arbitrario nelle applicazioni affidabili viene utilizzata per eseguire comandi che implementano un agente C2. Tuttavia, senza la tecnica di Valentina, questo approccio fallirebbe contro il WDAC, poiché alla fine richiederebbe l'esecuzione di un programma non firmato, che probabilmente verrebbe bloccato.
Avendo a disposizione solo pochi giorni per preparare la seconda campagna, ho pensato: e se creassi un intero framework C2 in JavaScript?
Se l'agente C2 stesso fosse scritto interamente in JavaScript, potrebbe stabilire un canale C2 anche contro le politiche WDAC più rigide. A partire da ciò, si potrebbe effettuare una ricognizione per trovare un modo per implementare un payload C2 di fase 2. Non ci sarebbero eventi di caricamento di DLL non firmate, ma solo l'esecuzione di JavaScript all'interno del processo affidabile di Teams.
Tutto ciò di cui avevamo bisogno erano funzionalità sufficienti per:
Sfruttando tutto il codice Node.js che avevo scritto durante la mia ricerca, ho messo insieme un proof of concept C2 nel giro di una sera. Il giorno dopo, l'ho condiviso con Dylan e, insieme, l'abbiamo rapidamente ampliato in un C2 completamente funzionale basato su JavaScript. Il nostro C2 era in grado di:
JavaScript C2, ora noto come Loki C2, si è rivelato un successo nella seconda campagna. Da allora, abbiamo continuato a perfezionare e ampliare Loki C2, aggiungendo più caratteristiche, aumentando la stabilità e potenziando le funzionalità.
Con tutte le conoscenze su Electron acquisite da questa ricerca, ho costruito un'interfaccia grafica per Loki C2 usando il framework Electron.
Nel video qui sotto, mostro come aggirare una rigida politica WDAC con Loki C2. Le due sezioni seguenti spiegano cosa accade nel video.
Per questa demo, WDAC viene implementato tramite App Control Policy Wizard su un'istanza EC2 di Windows Server 2025 aggiornata in AWS. Il wizard fornisce tre modelli di politica base:
La modalità Windows predefinita è la più rigorosa e consente l'esecuzione di:
Nella demo è selezionata la politica Modalità Windows predefinita. La modalità di controllo predefinita è disabilitata, in modo che il WDAC applichi immediatamente la politica. Inoltre, è selezionata l'opzione Unisci con gli elenchi di blocco consigliati, che include le regole dell'elenco di blocco di WDAC consigliato da Microsoft. L'app Control Wizard genera un file XML e CIP per la policy WDAC, che viene poi implementato sul server tramite CITool.exe.
Una volta che il WDAC è attivo, cerco di eseguire Loki C2 Agent.exe, ma il WDAC lo blocca, poiché il file eseguibile non è firmato da Microsoft.
Per aggirare questa restrizione, copio il contenuto della directory /resources/app/ di Loki Agent. Una cartella denominata "teams" si trova sul desktop e contiene un'applicazione Microsoft Teams legacy legittima. Visualizzando le proprietà di Teams.exe ho la conferma che è firmato da Microsoft.
Poi navigo nella directory /resources/ dell'applicazione Teams e cancello tutti i file esistenti. Una volta fatto, incollo la directory Loki C2 Agent /resources/app/ precedentemente copiata in ~/Desktop/teams/resources/app/.
Con questa modifica, eseguo Teams.exe facendovi clic sopra. Poiché il file eseguibile di Teams è firmato da Microsoft, WDAC non lo blocca. Su System Informer, vediamo che il processo Teams viene creato correttamente senza l'intervento del WDAC. Tuttavia, poiché ho sostituito la directory /resources/app/ di Teams con il codice dell'agente Loki C2, l'applicazione Teams basata su Electron ora esegue JavaScript dell'agente Loki C2 all'interno del processo affidabile di Teams.
Il processo di Teams richiama correttamente il client Loki C2 ed eseguo diversi comandi per dimostrare il controllo remoto del server compromesso.
Dopo aver ottenuto l'accesso iniziale con Loki C2, abbiamo individuato molteplici modi per eseguire un agente C2 di fase 2 più capace, come Dragon, il C2 interno sviluppato da me e Shawn Jones (@anthemtotheego). Anche se tutti i diversi metodi di escalation che abbiamo scoperto dalla creazione iniziale di Loki C2 non saranno divulgati in questo post, abbiamo in programma di trattarli nelle prossime release.
Quando implementata correttamente, questa tecnica continua ad aggirare le soluzioni di rilevamento e risposta degli endpoint (EDR) di alto livello. Tuttavia, senza un C2 furtivo di fase 2, gli operatori devono affidarsi all'esecuzione dei comandi tramite spawn che esegue i comandi nei processi secondari. Ciò attiverà rapidamente i rilevamenti post-sfruttamento contro i principali EDR.
Loki C2 è in linea con la tecnica MITRE ATT&CK T1218.011 - System Binary Proxy Execution: Electron Applications.
Dopo aver cercato su Internet, non ho trovato questa tecnica di svuotamento delle applicazioni Electron e sostituzione del loro codice con un C2 divulgato pubblicamente o utilizzato in modo diffuso. Tuttavia, dopo aver condiviso Loki C2 con team rossi fidati, uno di loro ha confermato di aver sviluppato internamente funzionalità simili.
Anche con un MITRE ATT & CK TTP, diverse pubblicazioni di ricerca e un articolo LOLBAS, questa stessa tecnica di svuotamento per applicazioni Electron continua a non essere rilevata. La mia ipotesi è che le soluzioni di EDR non si concentrino sul rilevamento di questo aspetto, ma piuttosto sugli indicatori di post-sfruttamento, come l'avvio di processi secondari per eseguire i comandi. Poiché abbiamo sviluppato dei metodi per implementare la fase 2 del C2 evitando questi comuni rilevamenti post-sfruttamento, abbiamo utilizzato con successo questa tecnica in più ingaggi evitando il rilevamento.
Tenendo presente tutto questo, la prossima volta che senti un fornitore dichiarare "100% di protezione MITRE" vale la pena di chiedersi cosa significhi veramente...