
BOF per eseguire PE in Cobalt Strike Beacon senza creazione della console
BOF RunPE è un Beacon Object File per Cobalt Strike che esegue file PE interamente in memoria all'interno del processo del beacon. A differenza del tradizionale fork&run, nessun processo figlio viene generato, nessuna console viene creata e nessuna pipe viene utilizzata - tutto l'output viene catturato tramite hooking IAT e reindirizzato alla console del beacon.
Architettura: solo x64
┌──────────────────────────────────────────────────────────────┐
│ Cobalt Strike Beacon │
│ (Current Process) │
└────────────────────────┬─────────────────────────────────────┘
│
│ beacon_inline_execute()
│
▼
┌──────────────────────────────────────────────────────────────┐
│ BOF RunPE │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ VxTable + Draugr Initialization │ │
│ │ (Syscall Resolution + Stack Spoofing) │ │
│ └──────────────────────┬─────────────────────────────────┘ │
│ │ │
│ ┌──────────────────────▼─────────────────────────────────┐ │
│ │ PE Mapping │ │
│ │ - Section Copy - IAT Patching (with hooks) │ │
│ │ - Relocations - Memory Protection │ │
│ └──────────────────────┬─────────────────────────────────┘ │
│ │ │
│ ┌──────────────────────▼─────────────────────────────────┐ │
│ │ Thread Execution │ │
│ │ - Spoofed Start Address │ │
│ │ - RIP Hijacking to Entry Point │ │
│ │ - Output Redirection via Hooks │ │
│ └────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
printf/WriteConsoleIl comportamento del BOF può essere modificato in Additionals postex -> RunPe Config

| Metodo | Descrizione |
|---|---|
None | Chiamate API dirette |
Draugr | Chiamate API con spoofing dello stack |
Regwait | Callback RegisterWaitForSingleObject |
Timer | Callback Timer Queue |
| Metodo | Descrizione |
|---|---|
Heap | Heap privato tramite RtlCreateHeap con Draugr |
VirtualAlloc | NtAllocateVirtualMemory con Draugr |
Module stomping | Sovrascrive la sezione .text di una DLL legittima |
| Opzione | Descrizione |
|---|---|
AllocRWX | Alloca come RWX (vs transizione RW→RX) |
UnhookNtdll | Sostituisce ntdll.dll .text con una copia fresca dal disco |
Timeout | Timeout di esecuzione in millisecondi (0 = infinito) |
StompModule | Percorso DLL per module stomping (es. chakra.dll) |
| Opzione | Descrizione |
|---|---|
ModuleName | Modulo legittimo per l'indirizzo di avvio (es. Kernel32.dll) |
ProcedureName | Nome della funzione all'interno del modulo (es. BaseThreadInitThunk) |
Offset | Offset dall'inizio della funzione |
Tutto l'output del PE viene reindirizzato alla console del beacon tramite hook IAT. Nessuna finestra di console o named pipe viene creata.
| Funzione Hookata | Destinazione |
|---|---|
GetCommandLineA/W | Restituisce argomenti spoofati |
__getmainargs / __wgetmainargs | Inizializzazione argomenti CRT |
printf / wprintf | Reindirizzamento BeaconPrintf |
WriteConsoleA/W | Reindirizzamento BeaconPrintf |
__stdio_common_vfprintf | Funzioni di stampa UCRT |
ExitProcess / exit | Convertito in ExitThread |
| Tecnica | Elude |
|---|---|
| Indirect Syscalls | Hook API in userland (EDR/AV) |
| Draugr Stack Spoofing | Ispezione dello stack di chiamate |
| Thread Start Spoofing | Analisi dell'indirizzo di avvio del thread |
| Module Stomping | Rilevamento di memoria non mappata |
| Private Heap Allocation | Monitoraggio di VirtualAlloc |
| Ntdll Unhooking | Sovrascrittura in memoria di ntdll con Ntdll dal disco |
| IAT Hooking (no pipes) | Monitoraggio delle named pipe |
NtGetContextThread / NtSetContextThread:
Operazioni di Memoria:
DONT_RESOLVE_DLL_REFERENCES (se l'allocatore di memoria è module stomping)Cobalt Strike → Script Manager → Load → BOF_RunPe.cna
beacon> runpe /path/to/binary.exe --arg1 value1

beacon> help runpe

Richiede GCC 13 (mingw-w64). Usa il Dockerfile fornito:
sudo docker build -t ubuntu-gcc-13 .
sudo docker run --rm -it -v "$PWD":/work -w /work ubuntu-gcc-13:latest make
Output: Bin/runpe.o
| Limitazione | Descrizione |
|---|---|
| CET | Control-flow Enforcement Technology potrebbe bloccare i frame di stack sintetici |
| Solo x64 | Nessun supporto x86/WoW64 |
| Visibilità del Kernel | Creazione di thread visibile ai callback del kernel |
| .NET | Eseguibili gestiti non supportati |
Windows Native API Programming di Pavel YosifovichWindows Internals, Part 1 di Pavel YosifovichWindows Internals, Part 2 di Andrea Allievi