
BOF para executar PE no Cobalt Strike Beacon sem criação de console
BOF RunPE é um Beacon Object File para o Cobalt Strike que executa arquivos PE inteiramente em memória dentro do processo do beacon. Diferentemente do tradicional fork&run, nenhum processo filho é criado, nenhum console é criado e nenhum pipe é usado - toda a saída é capturada via hooking de IAT e redirecionada para o console do beacon.
Arquitetura: apenas 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/WriteConsoleO comportamento do BOF pode ser editado em Additionals postex -> RunPe Config

| Method | Description |
|---|---|
None | Chamadas diretas de API |
Draugr | Chamadas de API com stack spoofing |
Regwait | Callback de RegisterWaitForSingleObject |
Timer | Callback de Timer Queue |
| Method | Description |
|---|---|
Heap | Heap privado via RtlCreateHeap com Draugr |
VirtualAlloc | NtAllocateVirtualMemory com Draugr |
Module stomping | Sobrescreve a seção .text de uma DLL legítima |
| Option | Description |
|---|---|
AllocRWX | Alocar como RWX (vs transição RW→RX) |
UnhookNtdll | Substituir a seção .text da ntdll.dll por uma cópia nova do disco |
Timeout | Tempo limite de execução em milissegundos (0 = infinito) |
StompModule | Caminho da DLL para module stomping (ex.: chakra.dll) |
| Option | Description |
|---|---|
ModuleName | Módulo legítimo para o endereço inicial (ex.: Kernel32.dll) |
ProcedureName | Nome da função dentro do módulo (ex.: BaseThreadInitThunk) |
Offset | Offset a partir do início da função |
Toda a saída do PE é redirecionada para o console do beacon via hooks de IAT. Nenhuma janela de console ou pipe nomeado é criada.
| Hooked Function | Target |
|---|---|
GetCommandLineA/W | Retorna argumentos falsificados |
__getmainargs / __wgetmainargs | Inicialização de argumentos do CRT |
printf / wprintf | Redirecionamento para BeaconPrintf |
WriteConsoleA/W | Redirecionamento para BeaconPrintf |
__stdio_common_vfprintf | Funções de impressão da UCRT |
ExitProcess / exit | Convertido em ExitThread |
| Technique | Bypasses |
|---|---|
| Syscalls Indiretos | Hooks de API em userland (EDR/AV) |
| Stack Spoofing do Draugr | Inspeção da pilha de chamadas (call stack) |
| Spoofing de Início de Thread | Análise do endereço inicial da thread |
| Module Stomping | Detecção de memória não mapeada (unbacked) |
| Alocação de Heap Privado | Monitoramento de VirtualAlloc |
| Unhooking do Ntdll | Substitui a ntdll em memória pela ntdll do disco |
| Hook de IAT (sem pipes) | Monitoramento de pipes nomeados |
NtGetContextThread / NtSetContextThread:
Operações de Memória:
DONT_RESOLVE_DLL_REFERENCES (se o alocador de memória for module stomping)Cobalt Strike → Script Manager → Load → BOF_RunPe.cna
beacon> runpe /path/to/binary.exe --arg1 value1

beacon> help runpe

Requer GCC 13 (mingw-w64). Use o Dockerfile fornecido:
sudo docker build -t ubuntu-gcc-13 .
sudo docker run --rm -it -v "$PWD":/work -w /work ubuntu-gcc-13:latest make
Saída: Bin/runpe.o
| Limitation | Description |
|---|---|
| CET | A Control-flow Enforcement Technology pode bloquear stack frames sintéticos |
| Apenas x64 | Sem suporte a x86/WoW64 |
| Visibilidade do Kernel | Criação de threads visível para callbacks do kernel |
| .NET | Executáveis gerenciados não suportados |
Windows Native API Programming por Pavel YosifovichWindows Internals, Part 1 por Pavel YosifovichWindows Internals, Part 2 por Andrea Allievi