BOF Spawn is a Beacon Object File for Cobalt Strike that implements process spawning and shellcode injection Draugr stack spoofing with indirect syscalls. This tool combines multiple evasion techniques to bypass userland hooks, call stack analysis, and memory scanners.
Architecture: x64 only
┌──────────────────────────────────────────────────────────────┐
│ Cobalt Strike Beacon │
│ (Parent Process) │
└────────────────────────┬─────────────────────────────────────┘
│
│ beacon_inline_execute()
│
▼
┌──────────────────────────────┐
│ BOF Spawn (Bof.c) │
│ ┌────────────────────────┐ │
│ │ VxTable Initialization │ │
│ │ (Syscall Resolution) │ │
│ └──────────┬─────────────┘ │
│ │ │
│ ┌──────────▼─────────────┐ │
│ │ Draugr Framework │ │
│ │ - Stack Spoofing │ │
│ │ - Indirect Syscalls │ │
│ └──────────┬─────────────┘ │
│ │ │
│ ┌──────────▼─────────────┐ │
│ │ SpawnAndRun() │ │
│ │ - Process Creation │ │
│ │ - Memory Allocation │ │
│ │ - Shellcode Injection │ │
│ │ - Execution │ │
│ └────────────────────────┘ │
└──────────────┬───────────────┘
│
▼
┌──────────────────────────────┐
│ Target Process │
│ (Suspended → Executing) │
│ │
│ ┌────────────────────────┐ │
│ │ Injected Shellcode │ │
│ └────────────────────────┘ │
└──────────────────────────────┘
The BOF provides extensive customization through the CNA script configuration dialog:
| Option | Description | Format/Notes |
|---|---|---|
| Process Name | Executable path to spawn | NT path format: \??\C:\Windows\System32\rundll32.exe |
| Working Directory | Current directory for spawned process | Standard path: C:\Windows\System32 |
| PPID Spoof Process | Parent process name for PPID spoofing | Process name only (e.g., explorer.exe) |
| Command Line | Arguments for spawned process | Full command line string |
| Block DLL Policy | Restrict to Microsoft-signed DLLs only | Boolean |
| Disable CFG | Disable Control Flow Guard | Boolean - Required for callback execution method |
| Use RWX | Allocate memory as RWX vs RW→RX | Boolean - RW→RX recommended for stealth |
| Execution Method | Shellcode execution technique | See section below |
Note on Process Path Format: The BOF uses NT path format (\??\C:\...) for the process name. This is the native format used by NtCreateUserProcess and bypasses some Win32 path parsing mechanisms.
Original State: Modified State:
┌──────────────┐ ┌──────────────┐
│ RIP: ntdll │ → │ RIP: 0x7FFE │ (shellcode)
│ RAX: ... │ │ RAX: ... │
└──────────────┘ └──────────────┘
Advantage: Simple and reliable.
Detection Risk: High - RIP directly pointing to non-module memory is easily detected by EDR thread scanning.
Step 1: Find Gadget Step 2: Set Context
┌──────────────────┐ ┌──────────────────┐
│ Scan ntdll.dll │ │ RIP: ntdll!gadget│ (0xFF 0xE0)
│ for 0xFF 0xE0 │ → │ RAX: shellcode │
└──────────────────┘ └──────────────────┘
Advantage: RIP points to legitimate ntdll.dll, more stealthy than direct hijacking.
Detection Risk: Medium - Suspicious RAX value and unusual gadget execution may trigger heuristics.
Step 1: Find Gadget Step 2: Set Context
┌──────────────────┐ ┌──────────────────┐
│ Scan ntdll.dll │ │ RIP: ntdll!gadget│ (0xFF 0xE3)
│ for 0xFF 0xE3 │ → │ RBX: shellcode │
└──────────────────┘ └──────────────────┘
Advantage: Similar to JMP RAX, RIP remains in legitimate module space.
Detection Risk: Medium - Same as JMP RAX, slightly different register makes detection signatures less common.
EnumResourceTypesW(hModule, lpEnumFunc, lParam)
↓
RCX = NULL
RDX = shellcode address
R8 = NULL
Advantage: Leverages legitimate callback mechanism, appears as normal Windows API usage.
Detection Risk: Low-Medium - Requires CFG disabled. NULL module handle and callback validation may trigger alerts.
Purpose: Required for callback function execution method. CFG validates indirect call targets and would block shellcode execution.
Risk: Disabling CFG is a strong indicator of malicious intent. Very few legitimate applications disable CFG during process creation.
Recommendation: Only enable when using callback execution method.
Purpose: Prevents loading of non-Microsoft-signed DLLs, blocking security product hooks and monitoring DLLs from being injected.
Risk: Unusual mitigation policy for typical processes. May trigger EDR alerts on process creation with this attribute.
Recommendation: Use selectively - effective against DLL-based EDR hooks but creates detection artifact.
Purpose: Simplifies injection by allocating memory with Read-Write-Execute permissions directly.
Risk: RWX memory is a critical indicator for memory scanners.
Recommendation: Use RW→RX transition instead (default). Allocate as RW, write shellcode, then change to RX.
NtGetContextThread / NtSetContextThread:
- ETW-TI provides callbacks for thread context manipulation via
EtwTiLogReadWriteVm - Modifying RIP register on suspended threads is a strong injection indicator
- Detection: Context modifications are logged with thread ID, process ID, and modified registers
Process Creation (PsSetCreateProcessNotifyRoutine):
NtCreateUserProcesstriggers kernel callbacks visible to EDR drivers- Suspended process creation followed by cross-process operations is suspicious
- Detection: Process creation with unusual parent (PPID spoofing), mitigation policies (BlockDLL, CFG disabled)
Memory Allocation:
- RWX memory allocations are monitored at kernel level via process callbacks
- Even without ETW-TI, kernel drivers can detect RWX via
MmProtectMdlSystemAddressevents - Detection: Unbacked executable memory (not mapped from disk file)
| Technique | Bypasses |
|---|---|
| Indirect Syscalls | Userland API hooks (EDR/AV) |
| Draugr Stack Spoofing | Call stack inspection tools |
| PPID Spoofing | Process tree analysis |
| Gadget-based Execution | Direct RIP detection |
Cobalt Strike → Script Manager → Load → BOF_spawn.cna
Menu: Additionals postex → Spawn Process Config
beacon> spawn_beacon <listener_name>
beacon> spawn_shellcode /path/to/payload.bin
Requires GCC 13 (mingw-w64). Use provided Dockerfile:
docker build -t ubuntu-gcc-13 .
sudo docker run --rm -it -v "$PWD":/work -w /work ubuntu-gcc-13:latest makeOutput: Bin/bof.o
- CET (Control-flow Enforcement Technology): Synthetic stack frames may trigger violations in CET-enabled processes
- Architecture: x64 only - no x86 support
- Kernel Visibility: Process creation still visible to kernel callbacks despite userland evasion