Skip to content

Handlers

laptop tester edited this page Sep 6, 2026 · 2 revisions

Handlers

A handler is the teamserver-side component that actually speaks to implants over a transport. A listener is the configuration + socket ("listen for HTTPS on 443 with these URIs"); the handler is the request-processing logic behind it: validating incoming traffic, parsing agent headers, registering sessions, and returning tasking. Handler implementations live in teamserver/pkg/handlers/ (http.go, smb.go, external.go, and the shared funnel handlers.go).

One funnel, two sides of implant

Every implant request, from any listener type, passes through a single dispatch point, parseAgentRequest (teamserver/pkg/handlers/handlers.go). This is where the framework splits into its two implant sides:

Side 1: the Demon (native) handler

  • Requests whose magic value is 0xDEADBEEF are routed to handleDemonAgent.
  • This path knows Demon's wire format natively: it parses the Demon header (teamserver/pkg/agent/agent.go → ParseHeader), decrypts/handles the implant crypto, dispatches task results and check-ins (pkg/agent/demons.go), registers the session, and encrypts queued tasking into the HTTP response.
  • This is the side documented in Demon Agent (wire format) and Demon Console Commands (operator-facing commands).

Side 2: the third-party agent handler (Service API)

  • Requests with any other magic value are routed to handleServiceAgent (handlers.go:339): the teamserver looks up a registered third-party agent by magic value (ServiceAgentExist / ServiceAgent) and forwards the raw request body to that agent's controller over the Service WebSocket; the controller's reply becomes the listener's HTTP response.
  • Third-party agent types are registered via the Service API (RegisterAgent), and their listeners can be created with Listener/ListenerAddExC2 or an External listener block in the profile. This is documented in Service API Reference and Building a Third-Party Agent.

Why this matters for new agent development

If you are building a new implant (Building a Third-Party Agent), you do not modify pkg/handlers at all. You implement a controller that:

  1. Registers with the teamserver over the Service WebSocket and declares an arbitrary magic value.
  2. Receives whatever bytes arrive at your External listener endpoint (validation-free, you control traffic shaping) via Agent/AgentResponse.
  3. Decodes/encodes your own agent protocol inside those bytes and tasks your implant, replying with Agent/AgentResponse carrying the same RandID (the teamserver blocks up to 5 minutes, then fails).

The Demon side is a special case of this architecture with the controller logic built into the teamserver itself.

Handler types

Type Constant File Socket on teamserver?
HTTP/S LISTENER_HTTP 1 http.go Yes, gin engine on HostBind:PortBind (POST = agent traffic, GET = fake 404)
SMB pivot LISTENER_PIVOT_SMB 2 smb.go No, named-pipe channel relayed through a parent agent (Demon-only)
External LISTENER_EXTERNAL 3 external.go POST /<Endpoint> on the teamserver's gin engine, validation-free
Service LISTENER_SERVICE 4 n/a Registered dynamically by controllers over the Service API (ListenerAddExC2)

Per-listener options and validation details are in Listeners; profile fields in Profile Reference.

Security notes

pkg/handlers parses network-controlled data. Bounds checks and the HostHeader / Headers / Uris / UserAgent validation (mismatch → fake nginx 404, handlers/404.html) are load-bearing; preserve them when modifying. The same applies to pkg/agent/agent.go (ParseHeader) on the Demon side and to the Service API path for third-party agents.

Clone this wiki locally