We follow DIY (do-it-yourself) philosophy when preparing C2 solution for a given mission objectives (i.e. red team exercise / adversary simulation engagement). Therefore we provide an open and flexible architectural solution together with reusable building blocks that can be quickly tailored to a given scenario.
The building blocks of the toolkit:
For a description of implant's components depicted on the diagram see below:
BOF zero (BOF0) - heart of z-beac0n implant, it has access to bof-launcher API so it is capable of launching other BOFs. BOF0 is executed right after implant's launch. It will take control over the implant and will manage its whole life-cycle (processing operator's commands, fetching additional BOFs, executing BOFs, uploading BOF's output to the operator, etc.);
C2 Channel: API-style BOF - initial implementation of the communication protocol with the C2 server. This essential BOF provides implementation of the following functions: netInit, netConnect, netDisconnect, netExchange, netMasquerade, and netUnmasquerade which are used by the implant to call home (i.e. C2 server) and obfuscate/mask generated network traffic. Notably an operator can provide alternative implementation of this BOF and re-attach it (during implant's runtime!) to cause the implant to "speak" with the C2 server in different language (i.e. using different communication protocol and/or modify traffic obfuscation/masking algorithm). Of course C2 server needs to act accordingly and prepare for "language" change.
bof-launcher - software component providing BOF management, BOF launching and BOF masking (in-memory evasion features) capabilities.
additional in-memory BOFs - arbitrary number of additional BOFs launched and managed by the BOF0. These BOFs could be launched using one of available routines: bofObjectRun, bofObjectRunAsyncThread, bofObjectRunAsyncProcess and could be short-lived (run and unload) or long-lived (run and stay in memory).
To run z-beac0n implant on o local machine for the testing/experimenting purposes, follow the steps below:
- Build all components
~/bof-launcher$ zig build
- Prepare C2 server
Copy BOFs that will be served by the C2 server, you should put here binaries of every supported architecture. I copy our publicly available BOFs, you can add yours:
~/bof-launcher$ cd examples/implant
cp -r ../../zig-out/bin/bofs/ ./
It's time to launch the server (by default it will listen at 127.0.0.1:8000):
~/bof-launcher/examples/implant$ python z-beac0n-C2.py
The server exposes two endpoints:
/tasking- meant to be used by the operator to issue new tasks for the implant (POSTrequest) and for retrieving output from completed tasks (GETrequest);/heartbeat- meant to be used by the implant to query for a new tasks (GETrequest) and to send back tasks' output (POSTrequest);
Now, run the console. It will use those endpoints to contrl the implant:
~/bof-launcher/examples/implant$ python z-beac0n-console.py
You should see following hackish logo :) and the prompt:
bb 00000
zzzzz bb eee aa aa cccc 00 00 nn nnn
zz _____ bbbbbb ee e aa aaa cc 00 00 nnn nn
zz bb bb eeeee aa aaa cc 00 00 nn nn
zzzzz bbbbbb eeeee aaa aa ccccc 00000 nn nn
z-beac0n>
- Run z-beac0n implant
By default z-beac0n is being built for Linux:
- as shellcode:
zig-out/bin/z-beac0n_lin_x64.bin - as ELF executable:
zig-out/bin/z-beac0n_lin_x64.elf - as shared library:
zig-out/lib/libz-beac0n_lin_x64.so
For Windows:
- as shellcode:
zig-out/bin/z-beac0n_win_{x86,x64}.bin - as PE executable:
zig-out/bin/z-beac0n_win_{x86,x64}.exe
In simplest case (for testing purposes) running the implant is a matter of executing the binary:
~/bof-launcher$ ./zig-out/bin/z-beac0n_lin_x64.elf
Verify the beaconing from the implant in the console:
bb 00000
zzzzz bb eee aa aa cccc 00 00 nn nnn
zz _____ bbbbbb ee e aa aaa cc 00 00 nnn nn
zz bb bb eeeee aa aaa cc 00 00 nn nn
zzzzz bbbbbb eeeee aaa aa ccccc 00000 nn nn
z-beac0n> implant ls
Implant ID First seen at Last seen at Implant identity string
================================================================================
Wxepb5bA 2026-05-14 17:40:16 2026-05-14 17:40:28 x86_64:linux:Wxepb5bA
z-beac0n>
z-beac0n implant is an example of software implant written with bof-launcher library, conceptually it looks like this:
It is composed of:
- z-beac0n core BOF (so called
BOF0, i.e. initally executed BOF), it will take control over the implant and will manage its whole life-cycle (processing operator's commands, fetching additional BOFs, executing BOFs, uploading BOF's output to the operator, etc.); - statically compiled bof-launcher library;
- so called API-style BOF providing C2 communication protocol implementation. Thanks to implementing it as a BOF switching communication protocol implementation is possible during run-time (i.e. an implant is capable of fetching a BOF that provides alternative C2 communication implementation and re-attach it to "speak" with C2 server via other protocol!).
- arbitrary number of additional BOFs launched and managed by the z-beac0n core BOF.
Execution flow:
- During the implant's startup self-contained
z-beac0n core BOFis started using bof-launcher'sbofRun()function. The control is then transferred to BOF0'sgo()entrypoint function. z-beac0n core BOFhas full access to bof-launcher's API so it is capable of launching other BOFs based on the operator's needs and requirements. BOFs could be launched using one of available routines:bofObjectRun.bofObjectRunAsyncThread.bofObjectRunAsyncProcess.- C2 server is queried for additional commands.
z-beac0n implant is currently available as a stageless payload in following forms: elf executable, shellcode and shared library (so).
Example stager.py script is available as a staging script that fetches over HTTP(S) an ELF executable payload and launches it in-memory in the context of Python's interpreter process;
On the server side following components are available:
- stage-listener.py - HTTP(S)-based payload serving listener compatible with "meterpreter protocol";
- z-beac0n-C2.py - Command and control server for handling implant's beaconing.
- z-beac0n-console.py - Operator's console.
- icli.py - Console's dependency.
- BOF-all.yaml - BOFs' manuals.
Of course working horse of z-beac0n implant is bof-launcher library. It exposes following, well thought and efficient interface/API:
int bofLauncherInit(void);
void bofLauncherRelease(void);
int bofMemoryMaskKey(const unsigned char* key, int key_len);
int bofMemoryMaskWin32ApiCall(const char* win32_api_name, int masking_enabled);
int bofObjectInitFromMemory(const unsigned char* file_data_ptr, int file_data_len, BofObjectHandle* out_bof_handle);
void bofObjectRelease(BofObjectHandle bof_handle);
int bofObjectIsValid(BofObjectHandle bof_handle);
void* bofObjectGetProcAddress(BofObjectHandle bof_handle, const char* name);
int bofRun(const unsigned char* file_data_ptr, int file_data_len);
int bofObjectRun(BofObjectHandle bof_handle,
unsigned char* arg_data_ptr,
int arg_data_len,
BofContext** out_context);
int bofObjectRunAsyncThread(BofObjectHandle bof_handle,
unsigned char* arg_data_ptr,
int arg_data_len,
BofCompletionCallback completion_cb,
void* completion_cb_context,
BofContext** out_context);
int bofObjectRunAsyncProcess(BofObjectHandle bof_handle,
unsigned char* arg_data_ptr,
int arg_data_len,
BofCompletionCallback completion_cb,
void* completion_cb_context,
BofContext** out_context);
void bofContextRelease(BofContext* context);
int bofContextIsRunning(BofContext* context);
void bofContextWait(BofContext* context);
unsigned char bofContextGetExitCode(BofContext* context);
const char* bofContextGetOutput(BofContext* context, int* out_output_len);
BofObjectHandle bofContextGetObjectHandle(BofContext* context);
int bofArgsInit(BofArgs** out_args);
int bofArgsInit(BofArgs** out_args);
void bofArgsRelease(BofArgs* args);
int bofArgsAdd(BofArgs* args, unsigned char* arg, int arg_len);
void bofArgsBegin(BofArgs* args);
void bofArgsEnd(BofArgs* args);
const char* bofArgsGetBuffer(BofArgs* args);
int bofArgsGetBufferSize(BofArgs* args);