
Generador de shellcode polimórfico para la ejecución en memoria de EXE, DLL, .NET, VBScript y JScript con aleatorización por salida y por compilación para evasión y resistencia a firmas.
El primo evasivo de Donut.
Fritter es un fork muy modificado del generador de shellcode Donut de TheWover y Odzhan. Genera shellcode independiente de la posición para la ejecución en memoria de ensamblados VBScript, JScript, EXE, DLL y .NET, con un enfoque en la evasión y la resistencia a firmas. El código base es solo x64.
Mucho. Fritter elimina características que no se necesitan comúnmente y reemplaza internos que se han vuelto muy detectables por firmas a lo largo de los años. Las capas de criptografía, compresión, hash y resolución de API se han reestructurado entre muchas otras áreas.
El polimorfismo y la evasión son el objetivo de diseño. Cada salida es única, y cada compilación de la herramienta es en sí misma única. Hay dos capas distintas:
Aleatorización por salida: se aplica cada vez que se invoca fritter. El stub de entrada, el decodificador polimórfico, las claves de cifrado y muchos elementos estructurales dentro del shellcode generado se regeneran a partir de nueva entropía en cada compilación PIC.
Aleatorización por compilación: se aplica cada vez que se compila el propio fritter. Las constantes de rotación de cifrado y hash, el diseño de la tabla de resolución de API, el ofuscado de cadenas del lado del shim, las direcciones del recorrido de PEB, los patrones de borrado posteriores a la ejecución y varios ejes estructurales dentro del loader y el shim quedan fijados en tiempo de compilación.
En tiempo de ejecución, Fritter minimiza la huella ejecutable del loader. El loader se particiona en funciones cifradas individualmente, cada una con su propia sección PE, clave XOR y dispatcher. Solo los bytes de una función están en texto plano en un momento dado.
Esto importa. Los binarios precompilados disponibles para pruebas en releases comparten sus constantes por compilación entre todos los usuarios del binario.
Compila tu propia copia. Los ejes por compilación se re-aleatorizan en cada invocación de 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
En Windows, MSVC es la cadena de herramientas recomendada. Coloca cada función del loader en su propia sección PE alineada a página, que es lo que necesita el modelo de despacho por función N>1. mingw actualmente emite todo en un único .text y por lo tanto ejecuta una entrada que cubre todo el loader con una sola clave XOR (funcionalmente idéntico a la salida de MSVC, pero con un solo dispatcher de polimorfismo en lugar de muchos). Si no tienes Visual Studio, compila bajo WSL con Makefile.linux; este compila de forma cruzada el loader de Windows mediante mingw-w64.
Cada make ejecuta tools/gen_poly para emitir nuevas constantes por compilación y tools/gen_api_shuffle para permutar la tabla de resolución de API. El binario fritter resultante es en sí mismo único con diferentes constantes de cifrado, diferentes constantes de hash, un diseño de tabla de API diferente, un ofuscado de cadenas del lado del shim diferente, y así sucesivamente. Cada shellcode generado por ese binario compartirá entonces esas constantes por compilación, pero variará en los ejes por salida.
Se incluye una carpeta /test con calc.exe e inject_local64.exe para probar Fritter. Para reconstruir los hosts de prueba tú mismo: nmake -f Makefile.msvc harness, o make -f Makefile.linux harness bajo 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)
fritter -i payload.exe
fritter -i implant.dll -m RunMain -p "arg1 arg2"
fritter -i payload.exe -g 0 -k 2 -o out.bin
Un payload de shellcode de Fritter está estructurado en capas anidadas, cada una descifra o prepara la siguiente:
Stub de entrada. Un prefijo de basura aleatorizado de longitud variable, una rutina de alineación de RSP generada por salida, y un trampolín generativo. Basado en la disciplina de Shikata Ga Nai.
Decodificador XOR polimórfico. Ensamblado en dos pasadas. Asignación de registros extraída de un grupo mediante la mezcla de Fisher-Yates. Longitud de clave elegida por salida. Se inserta basura entre cada instrucción real. Los grupos de instrucciones móviles del bucle caliente se reordenan dentro de las restricciones de corrección.
Shim de despacho. Reemplaza el anterior shim de ventana deslizante VEH. Cambia la región del loader de RW->RWX y luego entrega el control a la entrada del loader. Bajo despacho N>1, cada llamada se enruta a través de un thunk por función hacia un dispatcher por función que descifra, ejecuta y borra al regresar. El diseño de opcodes de cada dispatcher varía por compilación (ver CHANGELOG v1.3).
Loader. Mapeador de PE en memoria. Resuelve APIs por hash, mapea el PE incrustado mediante las API de sección, aplica importaciones / reubicaciones / callbacks de TLS, invoca el punto de entrada y luego borra. La dirección del recorrido de PEB, el byte de borrado posterior a la ejecución y los sitios de sal estructurales en MainProc se aleatorizan por compilación.
Limpieza. Borra las páginas del loader con un patrón de byte por compilación, borra la instancia y sale mediante la terminación del hilo o del proceso según -x. No hay manejador VEH ni struct de contexto que limpiar.
La huella residual después de la ejecución es una pequeña página RWX donde se ejecutó el shim de despacho. En modo hilo, la sección PE mapeada se deja intencionalmente intacta para que los callbacks de CRT tengan continuaciones.
Fritter está construido sobre el trabajo de TheWover y Odzhan, cuyo proyecto original Donut hizo que la generación de shellcode independiente de la posición fuera accesible y práctica. Su arquitectura, diseño del loader y marco PIC son la base sobre la que se construye todo esto. El mapeo de PE, el alojamiento de .NET y las rutas de ejecución de scripts son en gran parte su trabajo, conservado y respetado.
BSD 3-Clause. Ver LICENSE.