
Genera shellcode independiente de posición para x86, x64 o AMD64+x86 que carga .NET Assemblies, archivos PE y otras cargas útiles de Windows desde la memoria y las ejecuta con parámetros

Versión actual: v1.1
Donut es un código independiente de la posición que permite la ejecución en memoria de archivos VBScript, JScript, EXE, DLL y ensamblados .NET. Un módulo creado por Donut puede ser servido desde un servidor HTTP o incrustado directamente en el propio cargador. El módulo está opcionalmente cifrado usando el cifrador de bloque Chaskey y una clave de 128 bits generada aleatoriamente. Después de que el archivo se cargue y ejecute en memoria, la referencia original se borra para disuadir a los escáneres de memoria. El generador y cargador soportan las siguientes características:
Hay bibliotecas dinámicas y estáticas tanto para Linux como para Windows que se pueden integrar en tus propios proyectos. También hay un módulo de Python del que puedes leer más en Construcción y uso de la extensión Python.
Donut contiene cargadores individuales para cada tipo de archivo soportado. Para ensamblados .NET EXE/DLL, Donut utiliza la API de Alojamiento CLR No Administrada para cargar el Common Language Runtime. Una vez que el CLR se carga en el proceso anfitrión, se crea un nuevo Dominio de Aplicación para permitir la ejecución de Ensamblados en AppDomains desechables. Cuando el AppDomain está listo, el ensamblado .NET se carga mediante el método AppDomain.Load_3. Finalmente, se invoca el Punto de Entrada para EXEs o el método público para DLLs especificado por el usuario con cualquier parámetro adicional. Consulte MSDN para obtener documentación sobre la API de Alojamiento CLR No Administrada. Para un ejemplo independiente de un Host CLR, consulte el código aquí.
Los archivos VBScript y JScript se ejecutan utilizando la interfaz IActiveScript. También hay soporte mínimo para algunos de los métodos proporcionados por el Host de Scripts de Windows (wscript/cscript). Para un ejemplo independiente, consulte el código aquí. Para una descripción más detallada, lea: Ejecución en Memoria de JavaScript, VBScript, JScript y XSL
Los archivos EXE/DLL no administrados o nativos se ejecutan utilizando un cargador PE personalizado con soporte para Importaciones Retrasadas, TLS y parcheo de la línea de comandos. Solo se admiten archivos con información de reubicación. Lea Ejecución en Memoria de DLL para más información.
El cargador puede deshabilitar AMSI y WLDP para ayudar a evadir la detección de archivos maliciosos ejecutados en memoria. Para más información, lea Cómo los Red Teams evaden AMSI y WLDP para Código Dinámico .NET. También soporta la descompresión de archivos en memoria usando aPLib o la API RtlDecompressBuffer. Lea Compresión de Datos para más información.
A partir de v1.0, ETW también se evita. Al igual que con AMSI/WLDP, este es un sistema modular que te permite intercambiar la evasión predeterminada por la tuya propia. La evasión predeterminada se deriva de la investigación de XPN. Lea Ocultando tu .NET - ETW para más información.
Por defecto, el cargador sobrescribirá las cabeceras PE de los PE no administrados (desde la dirección base hasta `IMAGE_OPTIONAL_HEADER.SizeOfHeaders`). Si no se utiliza un módulo señuelo (sobrecarga de módulos), las cabeceras PE se pondrán a cero. Si se utiliza un módulo señuelo, las cabeceras PE del módulo señuelo se usarán para sobrescribir las del módulo de carga útil. Esto es para disuadir la detección comparando las cabeceras PE de los módulos en memoria con el archivo que los respalda en disco. El usuario puede solicitar que todas las cabeceras PE se conserven en su estado original. Esto es útil para escenarios donde el módulo de carga útil necesita acceder a sus cabeceras PE, como cuando se buscan recursos PE incrustados.
Para un recorrido detallado usando el generador y cómo Donut afecta el arte operativo, lea Donut - Inyectando Ensamblados .NET como Shellcode. Para más información sobre el cargador, lea Cargando Ensamblados .NET desde Memoria.
Aquellos que deseen saber más sobre el funcionamiento interno deben consultar las Notas de desarrollo.
Hay dos tipos de compilación. Si deseas depurar Donut, consulta la documentación aquí. Si no, continúa leyendo para la compilación de lanzamiento.
Desde una ventana de comandos de Windows o terminal Linux, clona el repositorio.
git clone http://github.com/thewover/donut.git
El siguiente paso depende de tu sistema operativo y del compilador que decidas usar. Actualmente, la plantilla del generador y del cargador para Donut se puede compilar correctamente tanto con Microsoft Visual Studio 2019 como con MingGW-64. Para usar las bibliotecas en tu propio proyecto C/C++, consulta los ejemplos proporcionados aquí.
Para generar la plantilla del cargador, la biblioteca dinámica donut.dll, la biblioteca estática donut.lib y el generador donut.exe. Inicia un Símbolo del sistema para desarrolladores de Microsoft Visual Studio x64, cambia al directorio donde clonaste el repositorio de Donut e ingresa lo siguiente:
nmake -f Makefile.msvc
Para hacer lo mismo, excepto usando MinGW-64 en Windows o Linux, cambia al directorio donde clonaste el repositorio de Donut e ingresa lo siguiente:
make -f Makefile.mingw
Para generar la biblioteca dinámica donut.so, la biblioteca estática donut.a y el generador donut. Cambia al directorio donde clonaste el repositorio de Donut y simplemente escribe make.
Donut se puede instalar y usar como un módulo de Python. Para instalar desde el código fuente se requiere pip para Python3. Primero, asegúrate de que las versiones anteriores de donut-shellcode no estén instaladas ejecutando el siguiente comando en una terminal Linux o en el símbolo del sistema de Microsoft Visual Studio.
pip3 uninstall donut-shellcode
Después de confirmar que las versiones anteriores ya no están instaladas, ejecuta el siguiente comando.
pip3 install .
También puedes instalar Donut como un módulo de Python obteniéndolo del repositorio PyPi.
pip3 install donut-shellcode
Para más información, consulta Construcción y uso de la extensión Python.
Construir el contenedor Docker.
docker build -t donut .
Ejecutar Donut.
docker run -it --rm -v "${PWD}:/workdir" donut -h
Donut incluye varios otros ejecutables que pueden compilarse por separado. Estos incluyen "hash.exe", "encrypt.exe", "inject.exe" e "inject_local.exe". Los dos primeros se utilizan en la generación de shellcode. Los dos últimos se proporcionan para ayudar a probar el shellcode de Donut. "inject.exe" inyectará un archivo binario sin procesar (loader.bin) en un proceso por su PID o nombre de proceso. "inject_local.exe" inyectará un archivo binario sin procesar en su propio proceso.
Para compilar estos ejecutables de soporte por separado, puedes usar el makefile de MSVC. Por ejemplo, para compilar "inject_local.exe" para probar tu shellcode de Donut, puedes ejecutar.
nmake inject_local -f Makefile.msvc
Se han proporcionado etiquetas para cada versión de lanzamiento de Donut que contienen los ejecutables compilados.
Actualmente, hay otros dos generadores disponibles.
La siguiente tabla enumera los modificadores compatibles con la versión de línea de comandos del generador.
Hay algunos requisitos específicos que tu carga útil debe cumplir para que Donut pueda cargarla correctamente.
Los ejecutables de Cygwin usan rutinas de inicialización que esperan que el proceso anfitrión se ejecute desde el disco. Si se ejecuta desde la memoria, es probable que el proceso anfitrión falle.
Hay cuatro proyectos complementarios proporcionados con Donut:
Es posible que desees agregar soporte para más tipos de cargas útiles, cambiar nuestro conjunto de características o integrar Donut en tus herramientas existentes. Hemos proporcionado documentación para desarrolladores. Las características adicionales se dejan como ejercicios para el lector. Nuestras sugerencias:
Si tienes alguna pregunta o comentario sobre Donut, únete al canal #Donut en el Slack de BloodHound Gang.
No somos responsables del mal uso de este software o técnica. Donut se proporciona como una demostración de Inyección CLR y carga en memoria a través de shellcode para proporcionar a los equipos rojos una forma de emular adversarios y a los defensores un marco de referencia para construir análisis y mitigaciones. Esto inevitablemente corre el riesgo de que los autores de malware y actores de amenazas lo utilicen de manera indebida. Sin embargo, creemos que el beneficio neto supera el riesgo. Con suerte, eso es correcto. En caso de que los productos EDR o AV sean capaces de detectar Donut mediante firmas o patrones de comportamiento, no actualizaremos Donut para contrarrestar firmas o métodos de detección. Para evitar ofenderse, por favor no preguntes.
| Modificador | Argumento | Descripción |
|---|---|---|
| -a | arch | Arquitectura objetivo para el cargador: 1=x86, 2=amd64, 3=x86+amd64 (predeterminado). |
| -b | nivel | Comportamiento para evadir AMSI/WLDP: 1=Ninguno, 2=Abortar si falla, 3=Continuar si falla (predeterminado). |
| -k | cabeceras | Conservar cabeceras PE: 1=Sobrescribir (predeterminado), 2=Conservar todas. |
| -j | señuelo | Ruta opcional del módulo señuelo para Sobrecarga de Módulos. |
| -c | clase | Nombre de clase opcional. (requerido para DLL .NET) También puede incluir espacio de nombres: p.ej. espacioDeNombres.clase |
| -d | nombre | Nombre del AppDomain a crear para .NET. Si la entropía está habilitada, se generará uno aleatoriamente. |
| -e | nivel | Nivel de entropía: 1=Ninguno, 2=Generar nombres aleatorios, 3=Generar nombres aleatorios + usar cifrado simétrico (predeterminado). |
| -f | formato | Formato de salida del cargador guardado en archivo: 1=Binario (predeterminado), 2=Base64, 3=C, 4=Ruby, 5=Python, 6=PowerShell, 7=C#, 8=Hexadecimal. |
| -m | nombre | Nombre del método o función opcional para DLL. (se requiere un método para DLL .NET) |
| -n | nombre | Nombre del módulo para el servidor HTTP. Si la entropía está habilitada, se genera uno aleatoriamente. |
| -o | ruta | Especifica dónde Donut debe guardar el cargador. El valor predeterminado es "loader.bin" en el directorio actual. |
| -p | parámetros | Parámetros/línea de comandos opcionales entre comillas para el método/función DLL o EXE. |
| -r | versión | Versión del runtime CLR. Se usa MetaHeader por defecto o v4.0.30319 si no hay disponible. |
| -s | servidor | URL del servidor HTTP que alojará un módulo de Donut. Se pueden proporcionar credenciales en el siguiente formato: https://usuario:contraseñ[email protected]/ |
| -t | Ejecuta el punto de entrada de un EXE no administrado/nativo como un hilo y espera a que el hilo termine. | |
| -w | La línea de comandos se pasa a la función DLL no administrada en formato UNICODE. (el valor predeterminado es ANSI) | |
| -x | opción | Determina cómo debe salir el cargador: 1=salir del hilo (predeterminado), 2=salir del proceso, 3=No salir ni limpiar y bloquear indefinidamente. |
| -y | dir | Crea un nuevo hilo para el cargador y continúa la ejecución en una dirección que es un desplazamiento relativo al ejecutable del proceso anfitrión. El valor proporcionado es el desplazamiento. Esta opción admite cargadores que deseen reanudar la ejecución del proceso anfitrión después de que donut complete la ejecución. |
| -z | motor | Empaquetar/Comprimir el archivo de entrada: 1=Ninguno, 2=aPLib, 3=LZNT1, 4=Xpress, 5=Xpress Huffman. Actualmente, los últimos tres solo son compatibles en Windows. |
| Herramienta | Descripción |
|---|---|
| DemoCreateProcess | Un ensamblado .NET de muestra para usar en pruebas. Toma dos parámetros de línea de comandos que especifican cada uno un programa a ejecutar. |
| DonutTest | Un simple inyector de shellcode en C# para usar en pruebas de Donut. El shellcode debe estar codificado en Base64 y copiado como una cadena. |
| ModuleMonitor | Una herramienta de prueba de concepto que detecta la inyección CLR tal como la realizan herramientas como Donut y execute-assembly de Cobalt Strike. |
| ProcessManager | Una herramienta de Descubrimiento de Procesos que los operadores ofensivos pueden usar para determinar en qué inyectar y los operadores defensivos pueden usar para determinar qué se está ejecutando, qué propiedades tienen esos procesos y si tienen el CLR cargado o no. |