# Black Sand Beacon

A Linux C2 beacon with a native in-memory ELF BOF loader, written in
C with no Go or Rust runtime. Designed to plug into the LazyOwn
RedTeam framework and inspired by Cobalt Strike's Beacon Object
Files.

This repository contains:

* **Beacons** in `beacons/v1/`, `beacons/v2/`, `beacons/v3/`
  Three variants of the same HTTPS/CFB beacon. v1 is the canonical
  pull-mode beacon. v2 adds mesh/p2p discovery. v3 is an
  experimental branch.
* **BOFs** in `bof/<name>/bof.c`
  Position-independent ELF objects the beacon can fetch and execute
  in memory. The five included are: `whoami`, `is_sudo`, `cat`,
  `userenum`, `suid_enum`.
* **C2 server** in `c2/server.py`
  A small Python Gopher-like server that serves commands, accepts
  results, and hosts BOFs.
* **Shared library** in `include/`
  AES-256 standalone (`aes.c`/`aes.h`), cJSON, the runtime
  configuration loader (`config.c`/`config.h` plus the Python
  mirror `config_py.py`), and the AES-256-CFB wrappers shared by
  the beacon and the tests.
* **Build** in `Makefile`, **CI** in `.github/workflows/ci.yml`,
  **tests** in `tests/`.

For a 5-minute end-to-end run, see [QUICKSTART.md](QUICKSTART.md).
For the BOF authoring guide, see [docs/BOF_AUTHORING.md](docs/BOF_AUTHORING.md).
For the C2 wire protocol, see [docs/PROTOCOL.md](docs/PROTOCOL.md).

## Requirements

Build (Debian/Ubuntu):

```
sudo apt-get install gcc libcurl4-openssl-dev libssl-dev make
```

Runtime for the C2 server:

```
pip install -r requirements.txt
```

## Build

```
make config        # one-time: copies config.example.json -> config.json
make beacon        # builds build/beacon (runnable, with build/config.json staged next to it)
make bofs          # builds all BOFs into build/bof/*.x64.o
make all-beacons   # builds v1, v2, v3
make test          # runs the full test suite
make clean         # removes build/
```

After `make beacon`, the binary is ready to run:

```
./build/beacon
```

It reads `build/config.json` (next to itself) via the binary-relative
search path, so no `BSB_CONFIG` or `cd config/` is needed. The same
binary copied to another host works identically as long as a
`config.json` sits next to it.

If you only want to rebuild one BOF:

```
make bof-whoami
make bof-suid_enum
```

## Deploy to another host (optional)

For shipping to a target, the Makefile has an `install` target that
stages a self-contained directory:

```
make install-all DESTDIR=/tmp/deploy
scp -r /tmp/deploy/* user@target:/opt/bsb/
ssh user@target /opt/bsb/beacon
```

This is **not** the normal flow. Use it only when you need to
bundle the binary + config + BOFs into a single directory you can
copy somewhere.

## Run the C2

```
python3 c2/server.py
```

The server binds `0.0.0.0:7070` by default and reads its AES key
and C2 URI from `config/config.json`. Override the config path
with `BSB_CONFIG=/path/to/config.json`.

Once the server is up you can inject commands from the REPL:

```
Client ID: linux
Command:   id
```

## Run the beacon

```
./build/beacon
```

The beacon reads `config/config.json` (relative to the binary, found
via the binary-relative search path), polls the C2, and prints
what it sends and receives. With no commands queued it just
sleeps between polls.

To run a BOF, the C2 returns a JSON object with a `bof` field
pointing at `/bof/<name>.x64.o`. The beacon fetches the file and
loads it into its own process via the in-memory ELF loader
(`RunELF` in `beacons/v1/beacon.c`).

## Configuration

All operational parameters live in `config/config.json` and are
read at startup. Nothing is baked into the binaries.

| Section | Key | Default | Purpose |
|---|---|---|---|
| `c2` | `url` | `https://127.0.0.1:4444` | C2 base URL |
| `c2` | `uri` | `/api/poll/` | URI path before the client id |
| `c2` | `client_id` | `linux` | Beacon identifier |
| `crypto` | `aes_key_hex` | (placeholder) | 64 hex chars = 32 bytes |
| `crypto` | `mode` | `cfb` | Encryption mode |
| `timing` | `sleep_seconds` | `6` | Base poll interval |
| `timing` | `jitter_percent` | `20` | +/- percent jitter on sleep |
| `timing` | `curl_timeout_seconds` | `10` | libcurl total timeout |
| `timing` | `curl_connect_timeout_seconds` | `5` | libcurl connect timeout |
| `network` | `user_agents` | (4 strings) | Rotation list |
| `network` | `verify_tls` | `false` | C2 TLS verification |
| `bof` | `download_chunk_size` | `4096` | BOF download buffer |

The CI runs a guardrail that fails the build if a 64-char hex key
appears in source. Real keys belong in `config/config.json`, which
is git-ignored.

## Writing a new BOF

A BOF is just a C source file that exports `void go(char *args, int alen)`.
Include `bof/include/beacon_api.h` for the callback API and
`bof/include/syscalls.h` for direct-syscall helpers. Compile it
position-independent and with no libc:

```
gcc -c -fPIC -nostdlib -m64 -O2 -I bof/include bof/<name>/bof.c -o build/bof/<name>.x64.o
```

The `make bof-<name>` target wraps this. Drop the resulting
`.x64.o` into `sessions/uploads/` on the C2 host and trigger it
by returning a command like `bof:<name>` from your command
injection.

See [docs/BOF_AUTHORING.md](docs/BOF_AUTHORING.md) for the full
contract.

## Testing

```
make test
```

The test suite is split into several files in `tests/`:

| File | What it covers |
|---|---|
| `test_config.py` | C JSON config loader: defaults, overrides, errors |
| `test_crypto.py` | AES-256-CFB roundtrip and Python/C interop |
| `test_bof_compile.py` | Every BOF compiles, exports `go`, has no libc leak |
| `test_beacon_build.py` | Beacon binary builds, exposes BOF API + RunELF |
| `test_c2_server.py` | C2 dispatcher: GET/POST/BOF, path-traversal hardening |
| `test_c2_http_e2e.py` | Real HTTP/1.1 socket roundtrip with crypto |
| `test_install_deploy.py` | `make` workflow produces a runnable tree, `make clean` wipes it |

## Repository layout

```
beacons/
  v1/beacon.c        canonical beacon
  v2/beacon.c        mesh/p2p variant
  v3/beacon.c        experimental variant
bof/
  include/           shared BOF headers (beacon_api.h, syscalls.h)
  whoami/bof.c       sample: print effective UID
  is_sudo/bof.c      sample: check sudo/wheel membership
  cat/bof.c          sample: read a file
  userenum/bof.c     sample: list /etc/passwd users and privileges
  suid_enum/bof.c    privesc recon: walk FS, list SUID/SGID binaries
c2/
  server.py          Gopher-style C2 server
config/
  config.example.json  template (copy to config.json)
include/
  config.h, config.c  runtime config loader
  config_py.py        Python mirror for the C2
  aes.h, aes.c        standalone AES (ECB/CTR/CBC)
  aes_cfb.h, aes_cfb.c  AES-256-CFB the beacon actually uses
  cJSON.h, cJSON.c     vendored JSON parser
  beacon.h            BOF API the beacon implements
tests/
  test_*.py           Python test suite
  *_harness.c         C test harnesses
docs/
  PROTOCOL.md         wire protocol
  BOF_AUTHORING.md    BOF contract and gotchas
.github/workflows/
  ci.yml              build + test + key-leak guard
Makefile
requirements.txt      C2 server runtime deps
```

## License

GPL v3. See `LICENSE`.

<!-- readmenator-kb-link -->
## Knowledge Base

This project has been analyzed by [ReadMenator](https://github.com/grisuno/ReadMenator),
a zero-token polyglot static analysis tool. Regenerate with
`pip install readmenator && readmenator . --rebuild`. Analysis outputs:

- **[KNOWLEDGE_BASE.md](./KNOWLEDGE_BASE.md)** -- Full architecture reference with all
  classes, functions, imports, dependency graphs, UML class diagrams, security
  audit findings, community analysis, taint paths, hotspots, cycles, and more.
- **[readmenator-agent/](./readmenator-agent/)** -- Agent-friendly, grep-optimized index.
  - `INDEX.md` -- Quick reference: what each file does
  - `SYMBOLS.md` -- Every symbol with file:line
  - `ARCHITECTURE.md` -- Internal dependency pairs + external imports
  - `API.md` -- Public function contracts
  - `GOTCHAS.md` -- Change warnings (blast radius, cycles, hotspots)
  - `SECURITY.md` -- Findings by severity with fix hints
  - `MEMORY.md` -- Rules, workflow, style, deliverables, session log
  - `MANIFEST.json` -- Freshness (git_commit + source_fingerprint) + read order
  - `KB_<subsystem>.md` -- Per-subsystem context
  - `recipes/*.md` -- Grounded task guides (add-function, fix-cycle, ...)
- **[readmenator-wiki/](./readmenator-wiki/)** -- Navigable wiki (start here for the big picture).
  - `index.md` -- Entry point: overview, reading order, god nodes, connections
  - `community_*.md` -- One synthesis page per code community
  - `connections.json` -- Typed bridges between communities
  - `queries.md` -- Suggested questions + answer log
  - `REPORT.md` -- Honest audit: coverage, confidence, limits
- **[readmenator-graphrag/](./readmenator-graphrag/)** -- Zero-token GraphRAG index.
  - `index.json` + `REPORTS.md` -- Query with `readmenator . ask "<question>"`
- **[readmenator-apidocs/](./readmenator-apidocs/)** -- API reference (Sphinx/Doxygen style).
  - `index.md` + `modules/*.md` -- Signatures, parameters, returns, raises, examples, call graphs
  - `architecture.md` -- Tiered architecture + execution flows (control flow, call tree, sequence)
  - `classes.md`, `genindex.md`, `COVERAGE.md` -- Hierarchy, A-Z index, doc coverage + warnings
  - `index.html` + `api/` -- Offline searchable browser and machine-readable model (`api/index.json`, `api/modules/*.jsonl` one entity per line)
- **[readmenator-maps/](./readmenator-maps/)** -- Interactive gallery (`index.html`).
  - 5 system maps: architecture, workflow, sequence, dataflow, lifecycle
  - `graph-force.html` -- Force-graph explorer (2D/3D, reach, paths, lenses)
  - `graph-bundle.html` -- Edge bundle explorer (circle + sphere)
  - `components.html` -- Component diagrams
- **[docs/](./docs/)** -- Static site (GitHub Pages ready).
  - Gallery copy + `llms.txt` (agent entry point) + `md/` docs + video
- **[readmenator-diagrams/](./readmenator-diagrams/)** -- Component diagrams.
  - `analysis.json` + `graph LR` markdown + per-component pages + `index.html`
- **[readmenator-rules/](./readmenator-rules/)** -- Suggested Semgrep rules (`*.yml`),
  `yara_rules.yar` (YARA-lite) + `exclusions.yaml` (false-positive blocklist)
- **[readmenator.mp4](./readmenator.mp4)** -- Cinematic synthwave overview video
- **[.cursorrules](./.cursorrules)** -- Generated AI assistant rules
- **[readmenator_audit.sarif](./readmenator_audit.sarif)** -- SARIF v2.1.0 audit (when security scan is on)

Cache (`.readmenator_cache/`), packaged agent skills (`.claude/skills/`), and the
GitHub wiki mirror are also produced on `run`/`--rebuild`.

AI agents: Read `readmenator-wiki/index.md` first for the big picture, then `readmenator-agent/INDEX.md` for grep-friendly lookup.
Developers: Read `KNOWLEDGE_BASE.md` for full architecture reference, open `readmenator-maps/index.html` for the visual gallery.
<!-- /readmenator-kb-link -->

<!-- deploynator-footer -->

---

Deployed with [deploynator](https://github.com/grisuno/deploynator)

<!-- /deploynator-footer -->
