sable

module
v0.0.0-...-16aca47 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 23, 2026 License: GPL-2.0, GPL-3.0

README

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:

Sable login screen

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

Sable fleet Overview with warning totals and Needs Attention guidance

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:

Sable web console with active session and warning output

Bulk tasking across selected agents:

Sable bulk tasking across Linux and Windows sessions

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

Session Details with success, warning, and failed totals

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

Download file browser modal


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

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


License

GPL-3.0. See LICENSE.

Directories

Path Synopsis
cmd
agent command
sablectl command
server command
internal
agentlabel
Package agentlabel validates and generates human-readable agent labels.
Package agentlabel validates and generates human-readable agent labels.
api
cli
operatorpw
Package operatorpw normalizes operator password file contents so the server and sablectl agree on what the password is, even when the file was written with a UTF-16 BOM (PowerShell's default) or other Windows-friendly encodings.
Package operatorpw normalizes operator password file contents so the server and sablectl agree on what the password is, even when the file was written with a UTF-16 BOM (PowerShell's default) or other Windows-friendly encodings.
securefile
Package securefile centralizes permissions for local Sable secret files.
Package securefile centralizes permissions for local Sable secret files.
tlspin
Package tlspin provides certificate-pinned HTTPS clients for Sable's local control plane.
Package tlspin provides certificate-pinned HTTPS clients for Sable's local control plane.
tools
gensecret command
restrictfile command
updatepeas command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL