Skip to main content
  1. Documentation/
  2. Plugins/

Agent Modules

Table of Contents
Agent modules are compiled payloads that agents load and execute on targets. Each module declares its format, and the teamserver matches it to compatible agents.
Not to be confused with server modules. Server modules are Python plugins that run on the teamserver and define task types. Agent modules are compiled binaries that run inside agents on targets. See the Plugin Overview for the full taxonomy.

Concepts
#

Module Formats
#

Every agent module has a format identifier — a string like "bof", "shellcode", "coff", "dll", or "tanto". Agent packages declare which formats they accept via supported_module_formats(). The teamserver matches modules to agents by checking that the module’s format appears in the agent’s supported list.

No format is privileged — compatibility is determined solely by matching identifiers. This means:

  • A BOF module can be loaded by any agent that declares "bof" support
  • A custom format "crystal_palace" works if both agent and module agree on the identifier
  • Agents that don’t support module loading declare an empty list and are never offered modules

Managed Mode (default)
#

When daemonize=false (the default), the loading agent manages the module’s lifecycle:

  • The agent allocates memory, loads the payload, and executes it
  • Results flow back through the loading agent’s communication channel
  • Long-running modules (keylogger, proxy, port scanner) can stream results incrementally over multiple check-in cycles
  • The operator can cleanly unload the module — the agent continues operating normally
  • The teamserver tracks each managed module per agent: name, format, load time, status, originating task

Daemonized Mode
#

When daemonize=true, the payload runs independently:

  • The agent launches the payload in its own thread/process with full autonomy
  • If the payload is itself an agent (contains crypto, codec, and registration logic), it establishes its own communication channel and registers independently as a new agent
  • The teamserver records the parent-child relationship for topology tracking
  • This is how agents deploy other agents through module loading — e.g., loading a Shinobi shellcode payload through another Shinobi as a daemonized module

Not all agents support daemonize. Agents that don’t MUST reject daemonized load requests with a clear error.

YAML Manifest
#

Each agent module is a compiled payload accompanied by a YAML metadata manifest:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
name: screenshot
description: Capture a screenshot of the active desktop
author: TantoC2 Team
format: bof
platforms:
  - windows
architectures:
  - x64
  - x86
privilege_required: false
mitre_attack:
  - T1113
options:
  monitor:
    type: int
    description: Monitor index (0 = primary)
    required: false
    default: 0
  format:
    type: str
    description: Image format
    required: false
    default: png
    choices: [png, bmp, jpg]

Required Fields
#

FieldTypeDescription
namestrUnique module name
descriptionstrHuman-readable description
authorstrModule author
formatstrModule format identifier (must match an agent’s supported_module_formats())
platformslist[str]Supported platforms (e.g., ["windows", "linux"])
architectureslist[str]Supported architectures (e.g., ["x64", "x86", "arm64"])

Optional Fields
#

FieldTypeDescription
privilege_requiredboolWhether elevated privileges are needed (default: false)
mitre_attacklist[str]MITRE ATT&CK technique IDs
optionsdictOptions schema (same structure as server module options)

Compatibility Filtering
#

The teamserver filters agent modules on three dimensions before presenting them to an operator:

  1. Format — the module’s format must appear in the agent’s supported_module_formats()
  2. Platform — the module’s platforms must include the agent’s platform
  3. Architecture — the module’s architectures must include the agent’s architecture

Only modules passing all three checks are offered. Attempting to load an incompatible module is rejected with a clear error.

Directory Structure
#

Agent modules are organized by format and platform:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
agent_modules/
  bof/
    windows/
      screenshot/
        manifest.yaml
        screenshot_x64.o
        screenshot_x86.o
      keylogger/
        manifest.yaml
        keylogger_x64.o
  shellcode/
    linux/
      reverse_shell/
        manifest.yaml
        reverse_shell_x64.bin
    windows/
      inject/
        manifest.yaml
        inject_x64.bin
        inject_x86.bin

Modules are discovered automatically from the agent_modules/ directory. Drop in a new module directory with its manifest and payload, then trigger a refresh.

Discovery and Refresh
#

1
2
3
4
5
6
7
8
# CLI
tantoc2> modules list
tantoc2> modules compatible <agent-id>  # Only compatible
tantoc2> modules refresh

# API
GET /api/v1/agent-modules/compatible/<agent_id>
POST /api/v1/agent-modules/refresh

Task Types
#

load_module
#

Delivers a module payload to an agent for execution.

ParameterTypeDescription
module_namestrName of the agent module to load
daemonizeboolfalse = managed mode (default), true = daemonized mode
optionsdictModule-specific options from the manifest schema

unload_module
#

Terminates a running managed module and cleans up.

ParameterTypeDescription
module_namestrName of the loaded module to unload

Tracking
#

The teamserver tracks managed modules loaded in each agent:

FieldDescription
Module nameWhich module is loaded
FormatThe module’s format identifier
Load timeWhen the module was loaded
Statusrunning, completed, failed, unloaded
Originating taskThe task that triggered the load

For daemonized loads that result in a new agent, the teamserver records the parent_agent_id on the new agent for topology tracking.

Tanto Module Specification
#

TantoC2 defines its own module format specification (working name: Tanto Module Spec, final name TBD) consisting of two parts:

  • Module side: Binary format, entry point conventions, and how modules use the comms interface to send results and receive data.
  • Loader side (Tanto Loader Spec): What agents must implement to load modules in this format — the comms interface, daemonize support, memory management (including zeroing on unload), and module lifecycle (load, run, unload, cleanup).

TantoC2-developed agents (e.g., Shinobi) MUST implement the Tanto Loader Spec. The specification is designed so that other C2 frameworks can adopt it independently.

A module development SDK with headers, build tooling, and example modules will be provided.

Next Steps
#