
Un generador de cargadores de shellcode con soporte para múltiples técnicas de inyección, diseñado para operaciones de red team.
hollow es un generador de cargadores de shellcode. Le proporcionas un binario de shellcode sin procesar y un perfil, y genera un cargador PE de Windows compilado con tu shellcode encriptado en su interior.
Los binarios están disponibles en la página de lanzamientos, o puedes compilar desde el código fuente:
go build -o hollow .
Requiere x86_64-w64-mingw32-gcc para compilación cruzada.
En Arch Linux: pacman -S mingw-w64-gcc
En Debian/Ubuntu: apt install gcc-mingw-w64-x86-64
./hollow -shellcode payload.bin -profile profiles/new_process_injection_sc.json
| Bandera | Descripción |
|---|---|
-shellcode | Ruta al shellcode sin procesar (.bin) |
-profile | Ruta a un archivo JSON de perfil |
-templates | Directorio de plantillas (por defecto: ./templates) |
hollow sigue un proceso de tres pasos: encriptar, sustituir, compilar.
Tu shellcode se encripta con AES-256-CBC usando una clave y un IV generados aleatoriamente en cada ejecución. Ambos están incrustados dentro del binario de salida. Luego, la plantilla C elegida reemplaza sus marcadores de posición con el shellcode encriptado, la clave y el IV, y el resultado se compila en un PE enlazado estáticamente y depurado por MinGW.
En tiempo de ejecución, el cargador descifra el shellcode usando BCrypt de Windows y lo ejecuta mediante la técnica de inyección que implementa la plantilla.
Las plantillas son los archivos fuente C que implementan la lógica real de inyección. Cada una reside en templates/ y contiene tokens de marcador de posición (${SHELLCODE}, ${KEY}, ${IV}, ${TARGET_PROCESS}) que hollow completa antes de la compilación. Seleccionas una plantilla a través de tu perfil.
hollow incluye seis plantillas:
Puedes escribir tus propias plantillas y colocarlas en templates/ — hollow las detectará automáticamente siempre que tu perfil las referencie.
Los perfiles son archivos JSON que le indican a hollow qué plantilla usar, qué proceso atacar y cómo compilar la salida. Residen en profiles/ y están pensados para personalizarse por compromiso.
{
"name": "New Process Injection via Direct Syscalls",
"author": "",
"template": "new_process_injection_sc",
"target_process": "C:\\Windows\\System32\\cmd.exe",
"arch": "x64",
"compile": {
"automatic": true,
"gcc": "x86_64-w64-mingw32-gcc",
"strip": true,
"output_type": "exe"
},
"output_dir": "./output"
}
output_type es ya sea exe o dll. Establece automatic: false para volcar el código fuente C sustituido al disco en lugar de compilarlo, útil si deseas modificar el código antes de compilar.
El archivo de salida se escribe en output_dir, con el nombre {template}_loader.{exe|dll}.
Plantilla: new_process_injection
Técnica: Inyección de hilo remoto en un proceso recién creado.
Crea el proceso objetivo con CREATE_BREAKAWAY_FROM_JOB | CREATE_NO_WINDOW, espera dos segundos para que se inicialice, luego asigna memoria en su espacio de direcciones, escribe el shellcode descifrado, lo marca como ejecutable y crea un hilo remoto que apunta a él. La bandera BREAKAWAY es necesaria cuando el cargador se lanza desde WinRM, que envuelve todos los procesos en un objeto de trabajo. El objetivo es una ruta completa de ejecutable.
Llamadas Win32: CreateProcessA, VirtualAllocEx, WriteProcessMemory, VirtualProtectEx, CreateRemoteThread.
Plantilla: new_process_injection_sc
Técnica: Inyección de hilo remoto en un proceso recién creado, mediante syscalls directas (Hell's Gate).
Mismo comportamiento que new_process_injection, pero cada llamada de asignación y de hilo evita completamente la capa Win32. Los SSN se resuelven desde ntdll en tiempo de ejecución y se ejecutan mediante la instrucción syscall sin procesar. Consulta la sección de benchmarks.
Plantilla: remote_thread_injection
Técnica: Inyección clásica de hilo remoto en un proceso existente.
Encuentra un proceso en ejecución por nombre usando CreateToolhelp32Snapshot, abre un identificador hacia él, luego asigna memoria, escribe el shellcode y crea un hilo remoto. No se genera ningún proceso nuevo. Se recomienda su uso contra procesos de larga duración como explorer.exe. El objetivo es un nombre de imagen de proceso, no una ruta completa.
Llamadas Win32: OpenProcess, VirtualAllocEx, WriteProcessMemory, VirtualProtectEx, CreateRemoteThread.
Plantilla: remote_thread_injection_sc
Técnica: Inyección clásica de hilo remoto en un proceso existente, mediante syscalls directas (Hell's Gate).
Mismo comportamiento que remote_thread_injection, evitando la capa Win32. Consulta la sección de benchmarks.
Plantilla: earlybird_apc
Técnica: Inyección Early Bird APC (CyberArk, 2018).
Crea el proceso objetivo en estado suspendido (CREATE_SUSPENDED | CREATE_BREAKAWAY_FROM_JOB | CREATE_NO_WINDOW), escribe el shellcode descifrado en su espacio de direcciones, luego pone en cola una Llamada a Procedimiento Asincrónica (APC) al hilo principal que apunta al shellcode mediante QueueUserAPC, y reanuda con ResumeThread. Debido a que la APC se dispara antes de que se ejecute el punto de entrada del proceso, el shellcode se ejecuta antes de que cualquier herramienta defensiva dentro del proceso se haya inicializado. Evita la tríada VirtualAllocEx + WriteProcessMemory + CreateRemoteThread por completo.
Plantilla: dll_sideload
Técnica: Sideloading de DLL / Ejecución de shellcode en proceso.
Produce un DLL en lugar de un EXE. En DLL_PROCESS_ATTACH, se genera un hilo que descifra y ejecuta el shellcode en el mismo proceso: VirtualAlloc, memcpy, VirtualProtect, y luego una llamada directa a función hacia el shellcode. El proceso anfitrión debe permanecer vivo mientras el payload se inicializa (alrededor de 10 segundos para un beacon de Sliver). Despliega colocando el DLL en una ubicación donde un binario legítimo lo cargará a través de una entrada faltante en la ruta de búsqueda de DLL.
Probado en Windows 10 Build 19041, protección en tiempo real de Windows Defender activada, definiciones 1.453.354.0, con un beacon de Sliver envuelto en Donut de 17 MB como payload:
Trojan:Win64/AsyncRat.RPY!MTB es una regla de comportamiento de amenaza de máquina activada por la secuencia clásica de inyección remota: VirtualAllocEx + WriteProcessMemory + CreateRemoteThread llamadas sobre un identificador de proceso remoto a través de la capa de API Win32. Defender registra una devolución de llamada del kernel que se dispara cuando estas tres llamadas aparecen en secuencia.
Las plantillas _sc evitan esto al nunca llamar a esas funciones Win32. En su lugar, resuelven los números de servicio de syscall (SSN) del kernel correspondientes directamente desde ntdll en tiempo de ejecución usando Hell's Gate: cada stub no enganchado de ntdll comienza con el prólogo de cuatro bytes 4C 8B D1 B8, y el SSN se encuentra en el desplazamiento 4. La syscall real es una función desnuda de GCC que contiene únicamente movq %rcx, %r10 / movl ssn(%rip), %eax / syscall / ret, que es la secuencia exacta que el propio stub de ntdll ejecutaría. La devolución de llamada de Defender nunca se dispara porque los envoltorios Win32 monitorizados nunca se invocan.
En sistemas donde los stubs de ntdll están parcheados por un EDR completo (prólogo reemplazado por un salto), la verificación del stub limpio falla y el cargador sale de forma temprana. No se implementa Halo's Gate (escaneo de stubs vecinos para inferir el SSN).
El código del cargador añade aproximadamente 19 KB de sobrecarga. El tamaño de salida es esencialmente el tamaño del shellcode de entrada. Un beacon de Sliver de 17 MB produce un cargador de 18 MB. Un shellcode típico de Metasploit (~200 KB) produciría un cargador de ~220 KB.
Las contribuciones son bienvenidas. Si tienes una plantilla que hayas escrito y deseas agregarla, o mejoras a las existentes, no dudes en abrir un PR. Si encuentras un error o tienes una sugerencia, abre un issue.
El objetivo de esta herramienta es facilitar el proceso de desarrollo de cargadores, no ser un producto terminado. Nuevas plantillas, mejores perfiles y mejoras en el núcleo son bien recibidos. hollow también fue creado con la intención de ayudar a las personas a comprender los conceptos detrás de los cargadores de shellcode y las técnicas de inyección, por lo que el código de plantilla claro y legible es igualmente valioso que la funcionalidad.
Pronto detallaré los conceptos detrás de cada técnica y el uso completo de hollow en mi blog. Estén atentos.
| Plantilla | Técnica |
|---|
new_process_injection | Inyección de hilo remoto en un proceso recién creado |
new_process_injection_sc | Igual, mediante syscalls directas (Hell's Gate) |
remote_thread_injection | Inyección clásica de hilo remoto en un proceso existente |
remote_thread_injection_sc | Igual, mediante syscalls directas (Hell's Gate) |
earlybird_apc | Inyección Early Bird APC |
dll_sideload | Sideloading de DLL, produce un DLL en lugar de un EXE |
| Plantilla | Alerta de comportamiento de Defender | Sesión establecida |
|---|
| new_process_injection | Trojan:Win64/AsyncRat.RPY!MTB | sí |
| remote_thread_injection | Trojan:Win64/AsyncRat.RPY!MTB | sí |
| earlybird_apc | ninguna | sí |
| dll_sideload | ninguna | sí |
| new_process_injection_sc | ninguna | sí |
| remote_thread_injection_sc | ninguna | sí |