Sable
Open source C2
Go | HTTPS + DNS transports | Web UI + CLI
Sable is a C2 written in Go. The server takes encrypted beacons from agents over HTTPS, with DNS as a fallback, and exposes a browser console and an interactive CLI for tasking.
Interface Preview
Password-gated operator console on loopback HTTPS:

Fleet Overview with sleep-aware status, command outcomes, recent activity, and
actionable failure alerts:

Shell commands that reach the agent but return an OS or process error are shown
as Warnings. Failed is reserved for delivery or agent communication
failures. A failed-task banner remains until every item under Needs
Attention is cleared with Ignore (for the current session) or
Acknowledge (persistently); either choice retains the task output and
outcome history.
Agent workspace with Success, Warning, and Failed output cards, the Task
Builder, and the full action menu:

Bulk tasking across selected agents:

Agent details rail with outcome totals, jobs, artifacts, metadata, and audit
history:

Remote file browser for navigating paths and downloading files or directory ZIPs:

Authorized Use
Sable is intended for educational use, controlled labs, CTFs, owned systems, and engagements where you hold written authorization. Do not deploy it against systems you do not own or do not have explicit permission to test. The author accepts no responsibility for misuse.
Architecture
flowchart LR
A["Agent<br/><sub>statically compiled<br/>ldflags-configured</sub>"]
O["Operator<br/><sub>Web UI / CLI</sub>"]
S["Sable Server<br/><sub>:443 HTTPS · :53/udp DNS<br/>127.0.0.1:8443 API + Web UI</sub>"]
A -->|HTTPS beacons :443| S
A -.->|DNS fallback :53/udp| S
O -->|loopback :8443| S
See docs/architecture.md for the crypto details, network ports, and project layout.
Prerequisites
- Go 1.26.5 or later (matches
go.mod and includes the current security fixes)
make (Linux, macOS, or Windows; PowerShell or cmd)
- Permission to bind
443 (and 53/udp when DNS fallback is on). Prefer a dedicated unprivileged account with only the bind capability, or use high ports and an OS-level redirect.
Agents cross-compile through GOOS/GOARCH, so you can build from any host OS.
Quick Start
1. Clone
git clone https://github.com/aelder202/sable
cd sable
Guided Setup (Recommended)
From a fresh clone, run one command:
go run ./cmd/sablectl setup
The guide first asks for the agent beacon URL: the HTTPS address every
deployed agent will use to reach the Sable server, not the operator UI. Use an
address reachable from every target machine; 127.0.0.1 only works when an
agent runs on the server host itself. It then asks for the total number of Linux
agents, the total number of Windows agents, and a label for each identity.
Every requested agent receives a unique identity, registration, and binary.
The remaining prompts select the beacon profile, credential location, state
encryption, and whether to start now.
Setup creates the local configuration and TLS certificate, builds sablectl,
the server, and every requested agent, starts the server, registers the local
identities, and runs the health checks. The final summary includes each agent
artifact's SHA-256 checksum and authorized Linux or Windows deployment command
templates.
Setup checks the operator API before asking any configuration questions. If a
server is already running, guided setup first warns that a clean setup will
stop it and permanently remove the current configuration, identities, state,
artifacts, keys, credentials, logs, and builds. The default answer is No.
Nothing is erased until the replacement is accepted and the final setup plan
is confirmed. For unattended replacement, add the explicit --replace flag:
go run ./cmd/sablectl setup --yes --replace
For an unattended local lab setup using the secure defaults (one Linux identity
named linux01):
go run ./cmd/sablectl setup --yes
For an unattended setup that creates two Linux agents and one Windows agent:
go run ./cmd/sablectl setup --yes \
--url https://<your-server-ip>:443 \
--linux-agents 2 \
--windows-agents 1
Unattended count-based setup assigns linux01, linux02, and windows01.
Supplying only one count flag makes the omitted platform count zero. On an
existing installation, the counts are desired totals: existing identities are
reused and only missing agents are added. Setup refuses totals or label changes
that would remove or rename an existing identity.
After setup, use the generated control binary:
./sablectl status
./sablectl down
./sablectl up
On Windows, use .\sablectl.exe in place of ./sablectl. Setup stores the
generated operator password at .sable/operator-password, the state encryption
key at .sable/state.key, and server logs at .sable/server.log by default.
The manual steps below remain available for custom or development installs.
Modules pull on the first build. Run go mod download if you want to pre-warm the cache.
Manual Install
Build the unified helper, then let it create the local config, TLS certificate, server binary, selected agent binaries, and .sable/install.json manifest.
make sablectl
./sablectl install --url https://<your-server-ip>:443 --password-file ./pw.txt --linux-agents 1 --windows-agents 0
--password-file is optional but recommended: when supplied, install creates the file (with a random password if it doesn't already exist) and records its path in .sable/install.json. sablectl start and sablectl agent register reuse that path automatically, so you don't need to retype --password-file on every command.
To build multiple Linux and Windows agents with separate identities:
./sablectl install --url https://<your-server-ip>:443 --password-file ./pw.txt --linux-agents 2 --windows-agents 1
The older --agents, --label, and --windows-label options remain supported
for compatibility, but they cannot be mixed with --linux-agents or
--windows-agents in the same command.
SERVER_URL is the agent beacon URL, not the operator UI. sablectl install
writes config.env, server.crt, server.key, .sable/install.json, and
builds artifacts under builds/<label>/. These files are gitignored and
include secrets.
3. Start
Keep the server binary, server.crt, and server.key in the same directory. If you ran install --password-file ./pw.txt, just run:
./sablectl start # Linux / macOS
.\sablectl.exe start # Windows
start reads the password file path from .sable/install.json. To override it for one run, or if you skipped the flag during install, point at a file directly:
Linux / macOS
printf '%s' 'yourpassword' > ./pw.txt
chmod 600 ./pw.txt
./sablectl start --password-file ./pw.txt
Windows (PowerShell)
Set-Content -Encoding ascii -NoNewline .\pw.txt "yourpassword"
.\sablectl.exe start --password-file .\pw.txt
SABLE_OPERATOR_PASSWORD and stdin both work too.
By default the server persists operator metadata to sable-state.json, stores large artifact bodies under sable-state.json.artifacts/, and encrypts both with AES-256-GCM using .sable/state.key. Registered agents, reliable queued/in-flight tasks, output history, notes, tags, artifacts, and audit events survive a restart. Sable creates the key when missing and writes sensitive files through restricted temporary files and atomic replacement. Back up the key separately: encrypted state cannot be recovered without it. Move state with --state-file <path> or SABLE_STATE_FILE=<path>, disable persistence with --state-file none, or explicitly opt out of encryption with --state-key-file none.
The server prints its TLS fingerprint and listener status:
[*] TLS cert fingerprint (SHA-256): 3a1f...b9c4
[*] Operator API on https://127.0.0.1:8443 | Agent listener on :443
The fingerprint is already baked into the agent binary because setup runs before compile.
The operator API binds to loopback only. Reach it on the server host directly, or tunnel:
ssh -L 8443:127.0.0.1:8443 user@sable-host
4. Register The Agents
Count-based install assigns labels such as linux01 and windows01. Agents can
only be registered after the server API is running.
In a second terminal on the server host, run:
./sablectl agent register
If you skipped --password-file during install, pass it here:
./sablectl agent register --password-file ./pw.txt
register with no label registers every locally known identity. To register
just one, append its label. To start the server and register all generated
identities in one pass, run install with --start:
./sablectl install --url https://<your-server-ip>:443 --password-file ./pw.txt --linux-agents 1 --windows-agents 0 --start
5. Add Or Rebuild Agents
Create another local identity, then build it:
./sablectl agent create windows --label win01
agent create creates the identity, builds its artifact, and registers it when
the local server is running. If the server is offline, registration is deferred
until the next sablectl up.
After source changes, rebuild without remembering which target changed:
./sablectl rebuild
6. Deploy The Agent
Linux:
scp builds/linux01/agent-linux user@target:/tmp/agent
ssh user@target "chmod +x /tmp/agent && /tmp/agent &"
Windows:
make build-agent-windows
Copy-Item .\builds\main\agent.exe C:\Temp\agent.exe
Start-Process -FilePath C:\Temp\agent.exe -WindowStyle Hidden
The agent shows up in the console within one beacon interval.
7. Open The Console
https://127.0.0.1:8443 on the server host (or through the tunnel). Accept the self-signed cert and log in with the operator password.
After login the Overview dashboard summarizes the deployed fleet with
sleep-aware status, activity, and Success, Warning, and Failed outcome counters.
A shell command that reaches an agent but is rejected by the OS or exits with an
error is a Warning. A task becomes Failed when delivery or agent communication
breaks down, including when an agent misses its sleep-aware offline check-in
threshold.
Failed tasks appear under Needs Attention and keep the red Overview banner
active. Open each failed task there and choose Ignore to clear it for the
current browser session or Acknowledge to clear it persistently. Both
actions retain the output and outcome history. Open Agents for task output,
the Task Builder, metadata, artifacts, and Remote Files.
Documentation
- Architecture — diagram, crypto, network ports, project layout
- Operator Interfaces — Web UI, CLI, adding agents, manual registration
- Task Reference — Task Builder Actions, Task Notes, full task table
- REST API — endpoint summary, with the full contract in
docs/openapi.yaml (OpenAPI 3.0.3)
- DNS Fallback — running with the optional DNS transport
- Development — reinstall, rebuild, build targets, tests, configuration, profiles, password sources
- Security Model — design notes for review and defenders
- Troubleshooting — common errors and what to check
License
GPL-3.0. See LICENSE.