
Un generatore di loader per shellcode con supporto per molteplici tecniche di iniezione, progettato per operazioni di red team.
hollow è un generatore di loader per shellcode. Fornisci un binario shellcode grezzo e un profilo, e produce un loader PE Windows compilato con il tuo shellcode crittografato al suo interno.
I binari sono disponibili nella pagina releases, oppure compila dal sorgente:
go build -o hollow .
Richiede x86_64-w64-mingw32-gcc per la cross-compilazione.
Su Arch Linux: pacman -S mingw-w64-gcc
Su Debian/Ubuntu: apt install gcc-mingw-w64-x86-64
./hollow -shellcode payload.bin -profile profiles/new_process_injection_sc.json
| Flag | Descrizione |
|---|---|
-shellcode | Percorso dello shellcode grezzo (.bin) |
-profile | Percorso di un file JSON del profilo |
-templates | Directory dei template (default: ./templates) |
hollow segue un processo in tre fasi: crittografa, sostituisci, compila.
Il tuo shellcode viene crittografato con AES-256-CBC utilizzando una chiave e un IV generati casualmente ad ogni esecuzione. Entrambi sono incorporati nel binario di output. Il template C scelto ha quindi i suoi segnaposto sostituiti con lo shellcode crittografato, la chiave e l'IV, e il risultato viene compilato in un PE statico e depurato (stripped) da MinGW.
A runtime, il loader decritta lo shellcode usando Windows BCrypt e lo esegue utilizzando la tecnica di iniezione implementata dal template.
I template sono file sorgente C che implementano la logica di iniezione effettiva. Ciascuno risiede in templates/ e contiene token segnaposto (${SHELLCODE}, ${KEY}, ${IV}, ${TARGET_PROCESS}) che hollow sostituisce prima della compilazione. Selezioni un template tramite il tuo profilo.
hollow viene fornito con sei template:
Puoi scrivere i tuoi template e metterli in templates/ — hollow li riconoscerà automaticamente purché il tuo profilo li indichi.
I profili sono file JSON che dicono a hollow quale template usare, quale processo prendere di mira e come compilare l'output. Risiedono in profiles/ e devono essere personalizzati per ogni operazione.
{
"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 può essere exe o dll. Imposta automatic: false per salvare su disco il sorgente C sostituito invece di compilarlo, utile se vuoi modificare il codice prima della compilazione.
Il file di output viene scritto in output_dir, con nome {template}_loader.{exe|dll}.
Template: new_process_injection
Tecnica: Iniezione di thread remoto in un processo appena avviato.
Avvia il processo target con CREATE_BREAKAWAY_FROM_JOB | CREATE_NO_WINDOW, attende due secondi per l'inizializzazione, poi alloca memoria nel suo spazio di indirizzi, scrive lo shellcode decrittato, lo marca come eseguibile e crea un thread remoto che punta ad esso. Il flag BREAKAWAY è necessario quando il loader viene lanciato da WinRM, che racchiude tutti i processi in un oggetto job. Il target è un percorso completo dell'eseguibile.
Chiamate Win32: CreateProcessA, VirtualAllocEx, WriteProcessMemory, VirtualProtectEx, CreateRemoteThread.
Template: new_process_injection_sc
Tecnica: Iniezione di thread remoto in un processo appena avviato, tramite syscall dirette (Hell's Gate).
Stesso comportamento di new_process_injection, ma ogni chiamata di allocazione e threading bypassa completamente il layer Win32. Gli SSN vengono risolti da ntdll a runtime ed eseguiti tramite l'istruzione syscall grezza. Vedi la sezione benchmark.
Template: remote_thread_injection
Tecnica: Iniezione classica di thread remoto in un processo esistente.
Trova un processo in esecuzione per nome usando CreateToolhelp32Snapshot, apre un handle ad esso, poi alloca memoria, scrive lo shellcode e crea un thread remoto. Non viene avviato alcun nuovo processo. Meglio usato contro processi a lunga durata come explorer.exe. Il target è un nome di immagine del processo, non un percorso completo.
Chiamate Win32: OpenProcess, VirtualAllocEx, WriteProcessMemory, VirtualProtectEx, CreateRemoteThread.
Template: remote_thread_injection_sc
Tecnica: Iniezione classica di thread remoto in un processo esistente, tramite syscall dirette (Hell's Gate).
Stesso comportamento di remote_thread_injection, bypassando il layer Win32. Vedi la sezione benchmark.
Template: earlybird_apc
Tecnica: Iniezione APC Early Bird (CyberArk, 2018).
Avvia il processo target in stato sospeso (CREATE_SUSPENDED | CREATE_BREAKAWAY_FROM_JOB | CREATE_NO_WINDOW), scrive lo shellcode decrittato nel suo spazio di indirizzi, poi accoda una chiamata a procedura asincrona (APC) al thread principale che punta allo shellcode tramite QueueUserAPC, e riprende con ResumeThread. Poiché l'APC viene eseguita prima del punto di ingresso del processo, lo shellcode viene eseguito prima che qualsiasi strumento difensivo nel processo sia stato inizializzato. Evita completamente la triade VirtualAllocEx + WriteProcessMemory + CreateRemoteThread.
Template: dll_sideload
Tecnica: DLL Sideloading / Esecuzione dello shellcode in-process.
Produce una DLL invece di un EXE. Su DLL_PROCESS_ATTACH, viene avviato un thread che decritta ed esegue lo shellcode in-process: VirtualAlloc, memcpy, VirtualProtect, poi una chiamata diretta di funzione allo shellcode. Il processo host deve rimanere attivo mentre il payload si inizializza (circa 10 secondi per un beacon Sliver). Distribuisci inserendo la DLL in una posizione dove un binario legittimo la caricherà tramite una voce mancante nel percorso di ricerca DLL.
Testato su Windows 10 Build 19041, protezione in tempo reale di Windows Defender abilitata, definizioni 1.453.354.0, con un beacon Sliver avvolto in Donut da 17 MB come payload:
Trojan:Win64/AsyncRat.RPY!MTB è una regola comportamentale di minacce macchina attivata dalla sequenza classica di iniezione remota: VirtualAllocEx + WriteProcessMemory + CreateRemoteThread chiamate su un handle di processo remoto tramite il layer API Win32. Defender registra un callback del kernel che si attiva quando queste tre chiamate appaiono in sequenza.
I template _sc bypassano questo problema non chiamando mai quelle funzioni Win32. Invece, risolvono i numeri di servizio di syscall del kernel (SSN) direttamente da ntdll a runtime usando Hell's Gate: ogni stub ntdll non hookato inizia con il prologo di quattro byte 4C 8B D1 B8, e l'SSN si trova all'offset 4. La syscall effettiva è una funzione GCC naked contenente solo movq %rcx, %r10 / movl ssn(%rip), %eax / syscall / ret, che è esattamente la sequenza che lo stub ntdll stesso eseguirebbe. Il callback di Defender non si attiva mai perché i wrapper Win32 monitorati non vengono mai invocati.
Su sistemi in cui gli stub di ntdll sono patchati da un EDR completo (prologo sostituito con un salto), il controllo dello stub pulito fallisce e il loader termina presto. Halo's Gate (scansione degli stub vicini per dedurre l'SSN) non è implementato.
Il codice del loader aggiunge circa 19 KB di overhead. La dimensione dell'output è essenzialmente la dimensione dello shellcode di input. Un beacon Sliver da 17 MB produce un loader da 18 MB. Uno shellcode Metasploit tipico (~200 KB) produrrebbe un loader di circa 220 KB.
I contributi sono benvenuti. Se hai scritto un template e desideri aggiungerlo, o miglioramenti a quelli esistenti, sentiti libero di aprire una PR. Se trovi un bug o hai un suggerimento, apri una issue.
L'obiettivo di questo strumento è rendere più facile il processo di sviluppo del loader, non essere un prodotto finito. Nuovi template, profili migliori e miglioramenti al core sono tutti ben accetti. hollow è stato anche costruito con l'intento di aiutare le persone a comprendere i concetti alla base dei loader di shellcode e delle tecniche di iniezione, quindi codice template chiaro e leggibile è prezioso quanto la funzionalità.
Presto descriverò in dettaglio i concetti dietro ogni tecnica e l'uso completo di hollow sul mio blog. Resta sintonizzato.
| Template | Tecnica |
|---|
new_process_injection | Iniezione di thread remoto in un processo appena avviato |
new_process_injection_sc | Stessa, tramite syscall dirette (Hell's Gate) |
remote_thread_injection | Iniezione classica di thread remoto in un processo esistente |
remote_thread_injection_sc | Stessa, tramite syscall dirette (Hell's Gate) |
earlybird_apc | Iniezione APC Early Bird |
dll_sideload | DLL sideloading, produce una DLL invece di un EXE |
| Template | Avviso comportamentale Defender | Sessione stabilita |
|---|
| new_process_injection | Trojan:Win64/AsyncRat.RPY!MTB | sì |
| remote_thread_injection | Trojan:Win64/AsyncRat.RPY!MTB | sì |
| earlybird_apc | nessuno | sì |
| dll_sideload | nessuno | sì |
| new_process_injection_sc | nessuno | sì |
| remote_thread_injection_sc | nessuno | sì |