forked from HavocFramework/Havoc
-
Notifications
You must be signed in to change notification settings - Fork 1
Architecture Overview
kthreatt edited this page Sep 1, 2026
·
1 revision
Havoc is split into three deployable pieces:
┌──────────────┐ wss://host:port/havoc/ ┌─────────────────────────────┐
│ Client │ ◄────────────────────────► │ Teamserver │
│ (Qt, per- │ JSON "packager" events │ (Go, gin HTTP(S) engine) │
│ operator) │ │ │
└──────────────┘ │ ┌───────────────────────┐ │
│ │ Listeners │ │
┌──────────────┐ wss://host:port/<SvcEP> │ │ • HTTP / HTTPS │◄─┼─── implants (Demon / custom)
│ Third-party │ ◄────────────────────────► │ │ • SMB pivot (no net) │ │
│ agent │ Service API (JSON) │ │ • External endpoint │ │
│ controller │ │ └───────────────────────┘ │
└──────────────┘ │ Agents / Jobs / Loot / DB │
└─────────────────────────────┘
There are three distinct protocols in Havoc; do not confuse them:
-
Operator client ↔ teamserver: WebSocket (WSS) at
wss://<host>:<port>/havoc/, JSON envelopes (packager.Package), authenticated with SHA3-256 of the operator password. See Client Teamserver Protocol. -
Implant ↔ listener: binary protocol consisting of a 12-byte big-endian header
[Size][MagicValue][AgentID]+ payload, POSTed to an HTTP/HTTPS or External listener. For Demon the payload is AES-256-CTR encrypted; for third-party agents the teamserver does no crypto. See Demon Agent and Building a Third-Party Agent. -
Service API (third-party controller ↔ teamserver): WebSocket at
wss://<host>:<port>/<Service.Endpoint>, JSON (the route lives on the teamserver's TLS gin engine, so it is always WSS). This is how you plug in custom agents, listeners and payload builders. See Service API Reference.
Every agent type is identified by a 32-bit "magic value" in the implant header:
-
0xDEADBEEF(agent.DEMON_MAGIC_VALUE) → built-in Demon handling. - Anything else → looked up among agents registered through the Service API; matching traffic is proxied to the owning controller.
This single dispatch point (parseAgentRequest in teamserver/pkg/handlers/handlers.go) is what makes third-party agents possible through any listener. Full treatment (listener vs handler, both implant sides, per-handler internals): Handlers.
-
gin engine (
Teamserver.Server.Engine): serves/havoc/(operator WS),/homestatic,POST /:endpoint(External listeners), and/<Service.Endpoint>(Service WS). The teamserver generates a self-signed RSA cert at startup (data/server.cert/data/server.key) and runs TLS. -
Agents (
agent.Agents): in-memory sessions + jobs queue, persisted in SQLite (data/teamserver.db, tablesTS_Agents,TS_Listeners,TS_Links). Agents and listeners are restored from the DB on startup. -
Events (
EventsList []packager.Package): every state change is an event; events are replayed to newly connected clients so the UI state is reconstructed from the event log. -
Loot (
pkg/logr): per-run directory underdata/loot/<timestamp>/holding downloaded files, listener certs and logs.
- The operator password is only ever hashed (SHA3-256, unsalted) client-side before comparison.
- The teamserver TLS cert is self-signed. The Qt client verifies TLS by default (
QSslSocket::VerifyPeer) and only disables verification (VerifyNone) when "Ignore SSL errors" is checked for that profile (Connector.cc:17-33). - Implant traffic to the HTTP listener is validated against the profile's
Uris,UserAgent,Headersand (if set)HostHeader; failures get a fake nginx 404 with anX-Havoc: trueheader.