
Fritter v1.3
Generatore di shellcode polimorfico per l'esecuzione in memoria di EXE, DLL, .NET, VBScript e JScript con randomizzazione per output e per build per elusione e resistenza alle firme.
Fritter
Il cugino evasivo di Donut.
Fritter è un fork pesantemente modificato del generatore di shellcode Donut di TheWover e Odzhan. Genera shellcode position-independent per l'esecuzione in memoria di VBScript, JScript, EXE, DLL e assembly .NET, con un focus su evasione e resistenza alle firme. Il codebase è solo x64.
Cosa c'è di diverso
Molto. Fritter rimuove le funzionalità che non sono comunemente necessarie e sostituisce le parti interne che nel corso degli anni hanno acquisito firme ben note. I layer di crittografia, compressione, hashing e risoluzione API sono stati tutti rielaborati, tra molte altre aree.
Il polimorfismo e l'evasione sono l'obiettivo di design. Ogni output è unico e ogni build del tool è a sua volta unica. Ci sono due layer distinti:
Randomizzazione per output: applicata ogni volta che fritter viene invocato. Lo stub di ingresso, il decoder polimorfico, le chiavi di cifratura e molti elementi strutturali all'interno della shellcode generata vengono rigenerati da nuova entropia a ogni build PIC.
Randomizzazione per build: applicata ogni volta che fritter stesso viene compilato. Le costanti di rotazione di cifratura e hash, il layout della tabella di risoluzione API, lo scrambling delle stringhe lato shim, le direzioni della PEB walk, i pattern di wipe post-esecuzione e diversi assi strutturali all'interno di loader e shim vengono fissati in fase di compilazione.
A runtime, Fritter minimizza l'impronta eseguibile del loader. Il loader è suddiviso in funzioni singolarmente cifrate, ciascuna con la propria sezione PE, chiave XOR e dispatcher. Solo i byte di una funzione sono in chiaro in un dato momento. Il precedente modello VEH a finestra scorrevole è stato ritirato a favore di questo modello a dispatch.
!! Compilare dai sorgenti è fortemente raccomandato !!
Questo è importante. I binari precompilati disponibili per il test in releases condividono le loro costanti per-build tra tutti gli utenti del binario.
Compila la tua copia. Gli assi per-build vengono ri-randomizzati a ogni invocazione di make:
# Linux, static-musl ELF, no runtime libc dependency
# Requires: build-essential, mingw-w64, musl-tools
make -f Makefile.linux release
# Windows (MSVC), recommended on Windows
nmake -f Makefile.msvc
Su Windows, MSVC è la toolchain raccomandata. Dispone ogni funzione del loader nella propria sezione PE allineata a pagina, che è ciò di cui il modello di dispatch per-funzione N>1 ha bisogno. mingw attualmente emette tutto in un singolo .text e quindi esegue un'unica entry che copre l'intero loader con una sola chiave XOR (funzionalmente identico all'output MSVC, ma con un solo dispatcher di polimorfismo invece di molti). Se non hai Visual Studio, compila sotto WSL con Makefile.linux; cross-compila il loader Windows tramite mingw-w64.
Ogni make esegue tools/gen_poly per emettere nuove costanti per-build e tools/gen_api_shuffle per permutare la tabella di risoluzione API. Il binario fritter risultante è esso stesso unico, con costanti di cifratura diverse, costanti di hash diverse, un layout della tabella API diverso, uno scrambling delle stringhe lato shim diverso, e così via. Ogni shellcode generata da quel binario condividerà quindi quelle costanti per-build, ma varierà sugli assi per-output.
Utilizzo
È inclusa una cartella /test con calc.exe e inject_local64.exe per testare Fritter. Per ricompilare gli host di test: nmake -f Makefile.msvc harness, oppure make -f Makefile.linux harness sotto WSL.
fritter [options] -i <EXE/DLL/VBS/JS>
INPUT
-i, --input <path> Input file to execute in-memory
-p, --args <args> Parameters / command line for target
-c, --class <name> Class name (required for .NET DLL)
-m, --method <name> Method or function for DLL
-r, --runtime <ver> CLR runtime version
-w, --unicode Pass command line as UNICODE
-t, --thread Run unmanaged EXE entrypoint as thread
OUTPUT
-o, --output <path> Output file (default: loader.bin)
-f, --format <1-8> 1=Bin 2=B64 3=C 4=Ruby 5=Py 6=PS 7=C# 8=Hex
-x, --exit <1-3> 1=Thread (default) 2=Process 3=Block
-y, --fork <offset> Fork thread, continue at RVA offset
LOADER
-e, --entropy <1-3> 1=None 2=Random names 3=Names+Crypto (default)
-k, --headers <1-2> 1=Overwrite (default) 2=Keep all
-g, --chunked <0-1> (deprecated; dispatch shim is always used)
-d, --domain <name> AppDomain name for .NET
-j, --decoy <path> Decoy module for Module Overloading
STAGING
-n, --modname <name> Module name for HTTP staging
-s, --server <url> Server URL (supports basic auth)
Esempi
fritter -i payload.exe
fritter -i implant.dll -m RunMain -p "arg1 arg2"
fritter -i payload.exe -g 0 -k 2 -o out.bin
Architettura (molte implementazioni non sono elencate qui)
Una payload shellcode di Fritter è strutturata come layer annidati, ciascuno dei quali decifra o effettua lo staging del successivo:
-
Entry stub. Un prefisso junk randomizzato di lunghezza variabile, una routine di allineamento RSP generata per output e un trampolino generativo. Basato sulla disciplina di Shikata Ga Nai.
-
Decoder XOR polimorfico. Assemblaggio a due passate. Allocazione dei registri estratta da un pool tramite Fisher-Yates shuffle. Lunghezza della chiave scelta per output. Junk inserito tra ogni istruzione reale. I gruppi di istruzioni mobili del loop caldo vengono riordinati entro vincoli di correttezza.
-
Dispatch shim. Sostituisce il precedente shim VEH a finestra scorrevole. Commuta la regione del loader da RW a RWX, poi passa il controllo all'entry del loader. Con dispatch N>1, ogni chiamata viene instradata tramite un thunk per-funzione in un dispatcher per-funzione che decifra, esegue e fa wipe al ritorno. Il layout degli opcode di ogni dispatcher varia per build (vedi CHANGELOG v1.3).
-
Loader. Mapper PE in memoria. Risolve le API tramite hash, mappa la PE incorporata tramite le API di sezione, applica import / rilocazioni / callback TLS, invoca l'entrypoint, poi esegue il wipe. La direzione della PEB walk, il byte di wipe post-esecuzione, i punti di sale strutturale in MainProc sono tutti randomizzati per build.
-
Cleanup. Esegue il wipe delle pagine del loader con un pattern di byte per-build, cancella l'istanza ed esce tramite terminazione del thread o del processo secondo
-x. Nessun handler VEH o struct di contesto da ripulire.
L'impronta residua dopo l'esecuzione è una piccola pagina RWX dove è girato il dispatch shim. In modalità thread, la sezione PE mappata viene lasciata intenzionalmente intatta, così che le callback CRT abbiano continuazioni.
Riconoscimenti
Fritter è costruito sul lavoro di TheWover e Odzhan, il cui progetto originale Donut ha reso accessibile e pratica la generazione di shellcode position-independent. La loro architettura, il design del loader e il framework PIC sono le fondamenta su cui è costruito tutto ciò che c'è qui. I percorsi di mapping PE, hosting .NET ed esecuzione di script sono in gran parte opera loro, mantenuti e rispettati.
Licenza
BSD 3-Clause. Vedi LICENSE.