
Applica un approccio divide et impera per bypassare gli EDR
Divide et Impera è un algoritmo comunemente applicato in programmazione per risolvere un problema complesso dividendolo in molti sottoproblemi più semplici. Possiamo applicare questo approccio alla sicurezza offensiva con un obiettivo diverso: confondere gli EDR in modo che perdano traccia delle nostre attività, impedendo loro di generare qualsiasi alert. Questo è qualcosa di simile a ciò che si vede ultimamente in quasi ogni campagna di phishing reale: lunghe catene di infezione, che eseguono più file passo dopo passo (es. .url -> .one -> .js -> .bat -> .dll) invece di eseguire direttamente il payload finale. Ciascuno dei file eseguiti svolge un compito semplice (scaricare un altro file, apportare una qualsiasi modifica al registro, spostare file tra directory o cambiarne nomi/estensioni e così via) che è difficile da etichettare come malevolo di per sé, preparando l'ambiente per l'esecuzione finale.
Ho deciso di testare questa semplice idea ma applicata a qualcosa di diverso, in questo caso, un'iniezione di processo remota. Il codice presentato in questo repository non è nulla di nuovo, anzi, è probabilmente uno dei modi più comuni e diretti per iniettare uno shellcode in un processo remoto: fare uso di NtOpenProcess, NtAllocateVirtualMemory, NtWriteVirtualMemory, NtProtectVirtualMemory e NtCreateThreadEx. L'unica differenza è che sto facendo il fork del processo usando NtCreateUserProcess dopo ognuna di queste chiamate. Poiché il processo figlio continua l'esecuzione da RIP + 1 e la memoria è interamente copiata dal padre, possiamo eseguire l'iniezione di processo remota ma usando 5 processi diversi; dobbiamo solo assicurarci che ogni handle necessario per le successive chiamate API sia ereditato correttamente.
In questo modo, spezziamo la procedura di iniezione dello shellcode in compiti più semplici ed eseguiamo ciascuno di essi in un contesto separato (processo).
Ho testato questo PoC contro tre degli EDR più comuni al giorno d'oggi: MDE, CrowdStrike e SentinelOne. I risultati parlano da soli: 2 EDR su 3 hanno generato un alert di Remote Process Injection quando il PoC veniva eseguito senza i fork; al contrario, nessuno di essi ha generato alcun alert una volta introdotto il meccanismo di forking.
Ovviamente, anche con il meccanismo di fork possiamo vedere nella telemetria grezza gli eventi corrispondenti alla creazione di processi, alla creazione di thread e anche tutto il comportamento cross-process, ma sembra che non sia sufficiente per gli EDR per etichettare l'attività come malevola, dimostrando il punto di questo PoC. Dividendo il comportamento malevolo in compiti più semplici ed eseguendo ciascuno di essi da un processo diverso, possiamo confondere gli EDR e impedire loro di generare alcun alert.
Lo stesso risultato potrebbe essere ottenuto in modi diversi; ho usato il meccanismo di fork solo per semplificare il mio codice e ridurre l'attività cross-process.
Se vuoi testarlo di persona, compila il codice con e senza le chiamate alla funzione fork(), quindi esegui entrambi i payload in un ambiente con l'EDR desiderato.
Poiché stiamo usando il plugin LITCRYPT per offuscare le stringhe letterali (solo per il codice Dinvoke_rs), è necessario impostare la variabile d'ambiente LITCRYPT_ENCRYPT_KEY prima di compilare il codice:
C:\Users\User\Desktop\Split> set LITCRYPT_ENCRYPT_KEY="yoursupersecretkey"
Dopodiché, compila semplicemente il codice ed esegui lo strumento:
C:\Users\User\Desktop\Split> cargo build --release
C:\Users\User\Desktop\Split\target\release> split.exe -h
Questa tecnica da sola non è sufficiente per bypassare un EDR; se il tuo codice non è affatto opsec, è molto probabile che verrai comunque scoperto. Non è un proiettile d'argento, ma solo un altro livello di evasione che puoi aggiungere ai tuoi strumenti. Ciononostante, il codice presentato in questo repository non è affatto opsec per i seguenti motivi, tra gli altri:
D'altra parte, ho testato questo approccio solo contro gli EDR menzionati e non so se anche altri EDR verranno bypassati. Puoi testarlo e farmi sapere com'è andata ;)