
Crittografo polimorfico che trasforma file shellcode, PE e COFF in payload offuscati e indipendenti dalla posizione, con crittografia RC4 e cifrario a blocchi casuale, più generazione di istruzioni spazzatura utilizzando la libreria AsmJit.
Presentato a
Shoggoth è un progetto open-source basato su C++ e sulla libreria asmjit utilizzato per cifrare polymorphicamente shellcode, file PE e COFF forniti.
Shoggoth genera un file di output che memorizza il payload e il suo corrispondente loader in forma offuscata. Poiché il contenuto dell'output è indipendente dalla posizione, può essere eseguito direttamente come shellcode. Durante l'esecuzione del payload, si decifra autonomamente a runtime. Oltre alla routine di cifratura, Shoggoth aggiunge anche istruzioni spazzatura, che non cambiano nulla, tra le routine.
Ho iniziato a sviluppare questo progetto per studiare diversi approcci di generazione dinamica di istruzioni, pratiche di assembly e rilevamenti di firme. Prevedo di aggiornare regolarmente il repository con i miei nuovi apprendimenti.
Le funzionalità attuali sono elencate di seguito:
Il flusso di esecuzione generale di Shoggoth per un file di input può essere visto nell'immagine sottostante. Puoi osservare questo flusso con le configurazioni predefinite.
In pratica, Shoggoth unisce prima lo shellcode del loader precompilato in base alla modalità scelta (file COFF o PE) e al file di input. Quindi aggiunge a questo payload unito multiple istruzioni spazzatura che genera. Lo stub contenente il loader, l'istruzione spazzatura e il payload viene cifrato prima con la cifratura RC4 e poi con una cifratura a blocchi generata casualmente combinando i corrispondenti decifratori. Infine, aggiunge un'istruzione spazzatura al blocco risultante.
Mentre Shoggoth genera casualmente istruzioni per stub spazzatura o routine di cifratura, utilizza la libreria AsmJit.
AsmJit è una libreria leggera per la generazione di codice macchina scritta in C++. Può generare codice macchina per le architetture X86, X86_64 e AArch64 e supporta le istruzioni di base e tutte le estensioni recenti. AsmJit consente di specificare codici operativi, registri, operandi immediati, etichette di chiamata e di incorporare valori arbitrari in qualsiasi offset all'interno del codice. Durante la generazione di alcune istruzioni assembly usando AsmJit, è sufficiente chiamare la funzione API che corrisponde all'operazione assembly richiesta con i valori degli operandi assembly della classe Assembler. Per ogni chiamata API, AsmJit memorizza le informazioni sul codice e il riposizionamento nella sua struttura interna CodeHolder. Dopo aver chiamato le funzioni API di tutti i comandi assembly da generare, la sua classe JitRuntime può essere utilizzata per copiare il codice da CodeHolder in memoria con permesso di esecuzione e riposizionarlo.
Mentre cercavo una libreria di generazione di codice, mi sono imbattuto in AsmJit e ho visto che è ampiamente utilizzata da molti progetti popolari. Ecco perché ho deciso di usarla per le mie esigenze. Non so se Shoggoth sia il primo progetto a usarla nel contesto del red team, ma credo che possa essere un riferimento per implementazioni future.
Shoggoth può essere utilizzato per cifrare file PE e COFF dati in modo che entrambi possano essere eseguiti come shellcode grazie a loader precompilati indipendenti dalla posizione. Ho semplicemente usato il metodo C to Shellcode per ottenere la versione PIC di noti loader PE e COFF che ho modificato per i miei vecchi progetti. Per la compilazione, ho usato il Makefile del progetto HandleKatz che è un dump LSASS in forma PIC.
In pratica, per ottenere shellcode con la tecnica C to Shellcode, ho rimosso tutte le variabili globali nel codice sorgente del loader, ho memorizzato tutte le stringhe nello stack e ho risolto gli indirizzi delle funzioni API di Windows caricando e analizzando le DLL necessarie a runtime. Successivamente, ho determinato il punto di ingresso con un linker script e ho compilato il codice usando MinGW con vari flag di compilazione. Ho estratto la sezione .text del file eseguibile generato e ho ottenuto lo shellcode del loader. Poiché il file eseguibile ottenuto dopo la modifica del codice come sopra non contiene sezioni diverse dalla sezione .text, il codice in questa sezione può essere utilizzato come indipendente dalla posizione.
Il codice sorgente di questi può essere visualizzato e modificato dalle directory COFFLoader e PELoader. Inoltre, le versioni compilate di questi codici sorgente si trovano nella directory stub. Per ora, se vuoi modificare o cambiare questi loader, devi rispettare le firme e sostituire i binari precompilati dalla directory stub.
Per passare argomenti a un BOF, usa l'opzione '--coff-arg'. Shoggoth si aspetta una stringa esadecimale preformattata contenente gli argomenti impacchettati, che può essere creata usando lo script beacon_generate.py di TrustedSec. Una copia di questo script è stata inclusa come COFFArgGenerator/beacon_generate.py. (Molte grazie a @Octoberfest7)
Shoggoth utilizza prima uno dei cifrari a flusso, l'algoritmo RC4, per cifrare il payload che ottiene. Dopo aver generato casualmente la chiave utilizzata qui, cifra il payload con quella chiave. Lo stub decifratore, che decifra il payload durante il runtime, viene creato dinamicamente e assemblato usando AsmJit. I registri utilizzati nello stub vengono selezionati casualmente per ogni campione.
Ho fatto riferimento al codice di Nayuki per l'implementazione dell'algoritmo RC4 che ho usato in Shoggoth.
Dopo aver eseguito la prima cifratura, Shoggoth utilizza la seconda cifratura che è un cifrario a blocchi generato casualmente. Con la seconda cifratura, cifra sia il decifratore RC4 sia opzionalmente lo stub che contiene il payload, le istruzioni spazzatura e il loader cifrato con RC4. Divide il blocco da cifrare in blocchi da 8 byte e utilizza istruzioni generate casualmente per ogni blocco. Queste istruzioni includono ADD, SUB, XOR, NOT, NEG, INC, DEC, ROL e ROR. Anche gli operandi per queste istruzioni vengono selezionati casualmente.