Skip to content

C2 and agent communication protocol

This document describes TLV structures exchanged between C2 and Tuoni agent. There are currently two ways to get them to the agent:

  • patch them into the payload file (exe, dll, shellcode) so they are handled right after execution
  • send them over listener connection.

Top Level TLV Parent (TLV[1]) map

ID TYPE DESCRIPTION
0x01 PARENT Executable code (legacy shellcode or ExecUnit)
0x03 PARENT Built-in command
0x04 PARENT Command result
0x05 PARENT Agent command control
0x0C PARENT Agent configuration
0x11 (currently 0x1) PARENT Agent metadata
0x12 PARENT Encrypted metadata
0x13 PARENT Encrypted data

Table Of Contents


Structures

Shellcode TLV structure

The 0x01 top-level structure is historically named Shellcode in the protocol and code, but it now carries either legacy native shellcode or an ExecUnit. Existing anchors keep the old name for compatibility.

  • ID: 0x01
    TYPE: PARENT
    VALUE: structure contains executable code and metadata
    • ID: 0x01
      TYPE: BYTE
      required: YES
      VALUE: Executable-code wrapper type [ 0x01 for listener | 0x02 for command ]
    • ID: 0x02
      TYPE: PARENT
      required: no (default is same process context and pipe based communication)
      VALUE: execution policy [same process | new process | existing process]
      • ID: 0x01
        TYPE: BYTE
        required: no
        VALUE: In what context the code is executed - 0 (self), 1 (existing), 2(new)
      • ID: 0x02
        TYPE: BYTE
        required: no
        VALUE: Communication channel - 0 (none), 1 (pipe)
      • ID: 0x03
        TYPE: STR_UTF8
        required: no
        VALUE: In case of "new process" context, what executable to use
      • ID: 0x03
        TYPE: INT32
        required: no
        VALUE: In case of "existing process" context, what process to target
      • ID: 0x04
        TYPE: BYTE
        required: no
        VALUE: In case of "new process" context, should process be suspended
      • ID: 0x05
        TYPE: BYTE
        required: no
        VALUE: In case of "new process" context, should executable window be hidden
      • ID: 0x06
        TYPE: STR_UTF8
        required: no
        VALUE: In case of "new process" context, what username to use for runas type of execution
      • ID: 0x07
        TYPE: STR_UTF8
        required: no
        VALUE: In case of "new process" context, what password to use for runas type of execution
      • ID: 0x08
        TYPE: INT32
        required: no
        VALUE: In case of "new process" context, value of the PPID
    • ID: 0x03
      TYPE: BLOB
      required: YES
      VALUE: Executable code bytes. If 0x07 is absent, the bytes are treated as legacy SHELLCODE_NATIVE.
    • ID: 0x04
      TYPE: UNDEFINED
      required: no
      VALUE: IPC configuration. For named-pipe IPC this is the pipe name.
    • ID: 0x05
      TYPE: BLOB
      required: no
      VALUE: Configuration sent to the executable code
    • ID: 0x06
      TYPE: UNDEFINED
      required: no
      VALUE: Wrapper type TLV[1.1] specific configuration. For command wrappers this is the command ID.
    • ID: 0x07
      TYPE: PARENT
      required: no (required for ExecUnit; absent for legacy shellcode)
      VALUE: ExecUnit configuration
      • ID: 0x01
        TYPE: BYTE
        required: YES
        VALUE: ExecUnit format: 0=SHELLCODE_NATIVE, 1=DOTNET_EXE, 2=DOTNET_DLL, 3=NATIVE_LIB
      • ID: 0x02
        TYPE: STR_UTF8
        required: no
        VALUE: Entrypoint, method, or exported function name
      • ID: 0x03
        TYPE: STR_UTF8
        required: no
        VALUE: Command/listener-specific type identifier
      • ID: 0x04
        TYPE: INT32
        required: no
        VALUE: Command/listener-specific version

Shellcode TLV structure listener

TLV[1.1] == 0x01

  • ID: 0x01
    TYPE: PARENT
    VALUE: structure contains listener executable code and metadata
    • ID: 0x01
      TYPE: BYTE
      required: YES
      VALUE: 0x01
    • ID: 0x02
      TYPE: PARENT
      required: no (default is same process context and pipe based communication)
      VALUE: execution policy [same process | new process | existing process]
      • ID: 0x01
        TYPE: BYTE
        required: no
        VALUE: In what context the code is executed - 0 (self), 1 (existing), 2(new)
      • ID: 0x02
        TYPE: BYTE
        required: no
        VALUE: Communication channel - 0 (none), 1 (pipe)
      • ID: 0x03
        TYPE: STR_UTF8
        required: no
        VALUE: In case of "new process" context, what executable to use
      • ID: 0x03
        TYPE: INT32
        required: no
        VALUE: In case of "existing process" context, what process to target
      • ID: 0x04
        TYPE: BYTE
        required: no
        VALUE: In case of "new process" context, should process be suspended
      • ID: 0x05
        TYPE: BYTE
        required: no
        VALUE: In case of "new process" context, should executable window be hidden
      • ID: 0x06
        TYPE: STR_UTF8
        required: no
        VALUE: In case of "new process" context, what username to use for runas type of execution
      • ID: 0x07
        TYPE: STR_UTF8
        required: no
        VALUE: In case of "new process" context, what password to use for runas type of execution
      • ID: 0x08
        TYPE: INT32
        required: no
        VALUE: In case of "new process" context, value of the PPID
    • ID: 0x03
      TYPE: BLOB
      required: YES
      VALUE: Listener executable code bytes. If 0x07 is absent, the bytes are treated as legacy SHELLCODE_NATIVE.
    • ID: 0x04
      TYPE: UNDEFINED
      required: YES
      VALUE: IPC configuration. For named-pipe IPC this is the pipe name.
    • ID: 0x05
      TYPE: BLOB
      required: YES
      VALUE: Configuration sent to the listener code. Should contain instructions for communicating with the listener.
    • ID: 0x07
      TYPE: PARENT
      required: no (required for ExecUnit listeners; absent for legacy shellcode listeners)
      VALUE: ExecUnit configuration
      • ID: 0x01
        TYPE: BYTE
        required: YES
        VALUE: ExecUnit format: 0=SHELLCODE_NATIVE, 1=DOTNET_EXE, 2=DOTNET_DLL, 3=NATIVE_LIB
      • ID: 0x02
        TYPE: STR_UTF8
        required: no
        VALUE: Entrypoint, method, or exported function name
      • ID: 0x03
        TYPE: STR_UTF8
        required: no
        VALUE: Listener-specific type identifier
      • ID: 0x04
        TYPE: INT32
        required: no
        VALUE: Listener-specific version

Shellcode TLV structure command

TLV[1.1] == 0x2

  • ID: 0x01
    TYPE: PARENT
    VALUE: structure contains command executable code and metadata
    • ID: 0x01
      TYPE: BYTE
      required: YES
      VALUE: 0x02
    • ID: 0x02
      TYPE: PARENT
      required: no (default is same process context and pipe based communication)
      VALUE: execution policy [same process | new process | existing process]
      • ID: 0x01
        TYPE: BYTE
        required: no
        VALUE: In what context the code is executed - 0 (self), 1 (existing), 2(new)
      • ID: 0x02
        TYPE: BYTE
        required: no
        VALUE: Communication channel - 0 (none), 1 (pipe)
      • ID: 0x03
        TYPE: STR_UTF8
        required: no
        VALUE: In case of "new process" context, what executable to use
      • ID: 0x03
        TYPE: INT32
        required: no
        VALUE: In case of "existing process" context, what process to target
      • ID: 0x04
        TYPE: BYTE
        required: no
        VALUE: In case of "new process" context, should process be suspended
      • ID: 0x05
        TYPE: BYTE
        required: no
        VALUE: In case of "new process" context, should executable window be hidden
      • ID: 0x06
        TYPE: STR_UTF8
        required: no
        VALUE: In case of "new process" context, what username to use for runas type of execution
      • ID: 0x07
        TYPE: STR_UTF8
        required: no
        VALUE: In case of "new process" context, what password to use for runas type of execution
      • ID: 0x08
        TYPE: INT32
        required: no
        VALUE: In case of "new process" context, value of the PPID
    • ID: 0x03
      TYPE: BLOB
      required: YES
      VALUE: Command executable code bytes. If 0x07 is absent, the bytes are treated as legacy SHELLCODE_NATIVE.
    • ID: 0x04
      TYPE: UNDEFINED
      required: no
      VALUE: IPC configuration. For named-pipe IPC this is the pipe name.
    • ID: 0x05
      TYPE: BLOB
      required: YES
      VALUE: Configuration sent to the command code
    • ID: 0x06
      TYPE: INT32
      required: YES
      VALUE: Command ID
    • ID: 0x07
      TYPE: PARENT
      required: no (required for ExecUnit commands; absent for legacy shellcode commands)
      VALUE: ExecUnit configuration
      • ID: 0x01
        TYPE: BYTE
        required: YES
        VALUE: ExecUnit format: 0=SHELLCODE_NATIVE, 1=DOTNET_EXE, 2=DOTNET_DLL, 3=NATIVE_LIB
      • ID: 0x02
        TYPE: STR_UTF8
        required: no
        VALUE: Entrypoint, method, or exported function name
      • ID: 0x03
        TYPE: STR_UTF8
        required: no
        VALUE: Command-specific type identifier
      • ID: 0x04
        TYPE: INT32
        required: no
        VALUE: Command-specific version

Built-in command TLV structure

  • ID: 0x03
    TYPE: PARENT
    VALUE: structure contains built-in command and metadata
    • ID: 0x01
      TYPE: INT32
      required: YES
      VALUE: Command ID, required for result correlation
    • ID: 0x02
      TYPE: INT32
      required: YES
      VALUE: Command control code - determining what type of functionality it triggers - for example 0x01 is "DIE" command for the Agent
    • ID: 0x03
      TYPE: UNDEFINED
      required: no
      VALUE: Configuration for command

Command result TLV structure

  • ID: 0x04
    TYPE: PARENT
    VALUE: structure contains result data
    • ID: 0x01
      TYPE: INT32
      required: YES
      VALUE: ID of the task
    • ID: 0x02
      TYPE: BLOB
      required: YES
      VALUE: Result data
    • ID: 0x03
      TYPE: BYTE
      required: no
      VALUE: Status of the result :[ 0x00 = failed | 0x01 = ongoing | 0x02 = success]
    • ID: 0x04
      TYPE: BLOB
      required: no
      VALUE: Error data

Agent command control TLV structure

  • ID: 0x05
    TYPE: PARENT
    VALUE: structure contains settings to control running command in agent
    • ID: 0x01
      TYPE: INT32
      required: YES
      VALUE: ID of the command to be controlled in the agent
    • ID: 0x02
      TYPE: BYTE
      required: YES
      VALUE: Type of the command (task) manipulation - 0x01 means that there is new data (next value) provided for the command, 0xDD means that this task should be canceled/stopped
    • ID: 0x03
      TYPE: UNDEFINED
      required: no
      VALUE: Configuration for manipulation, depends on the previous type (if TLV[1.2]==0x01, then this will contain data relayed to the running command code)

Agent configuration TLV structure

  • ID: 0x0C
    TYPE: PARENT
    VALUE: structure contains settings for agent (none of the values inside are mandatory, they just replace existing ones if they are there)
    • ID: 0x01
      TYPE: BLOB
      required: no
      VALUE: Public key to use, [NOT IMPLEMENTED BY C2 YET]
    • ID: 0x02
      TYPE: BLOB
      required: no
      VALUE: GUID of the public key used, [NOT IMPLEMENTED BY AGENT OR C2 YET]

Relayed Data Structures

Agent metadata TLV structure

NB: The outer TLV type is currently 0x01 for backward compatibility with existing deployments. It is slated to change to 0x11 in a future revision of the specification. Until that revision is adopted, implementations must use 0x01 for the outer TLV type.

  • ID: 0x1 (in future will be 0x11)
    TYPE: PARENT
    VALUE: structure contains metadata about the agent

    • ID: 0x01
      TYPE: GUID
      required: YES
      VALUE: GUID of the agent
    • ID: 0x02
      TYPE: STR_UTF8
      required: no
      VALUE: Username of the agent process
    • ID: 0x03
      TYPE: STR_UTF8
      required: no
      VALUE: Process name of the agent process
    • ID: 0x04
      TYPE: INT32
      required: no
      VALUE: PID of the agent process
    • ID: 0x05
      TYPE: STR_UTF8
      required: no
      VALUE: Working directory of the agent
    • ID: 0x06
      TYPE: BYTE
      required: no
      VALUE: OS type (1=WINDOWS, 2=LINUX, 3=BSD, 4=MAC)
    • ID: 0x07
      TYPE: BYTE
      required: no
      VALUE: Major version of the OS
    • ID: 0x08
      TYPE: BYTE
      required: no
      VALUE: Minor version of the OS
    • ID: 0x09
      TYPE: STR_ASCII
      required: no
      VALUE: IPv4 addresses of the agent machine
    • ID: 0x0A
      TYPE: STR_ASCII
      required: no
      VALUE: Hostname of the agent machine
    • ID: 0x0B
      TYPE: BYTE
      required: no
      VALUE: Architecture of the process (0=x86, 1=x64)
    • ID: 0x0C
      TYPE: BYTE
      required: no
      VALUE: Architecture of the OS (0=x86, 1=x64)
    • ID: 0x0D
      TYPE: INT32
      required: no
      VALUE: Agent OS ANSI code page
    • ID: 0x0E
      TYPE: STR_UTF8
      required: no
      VALUE: Process integrity level (e.g. System, High, Medium, Low)
    • ID: 0x10
      TYPE: BLOB
      required: YES
      VALUE: 16-byte AES key for encryption
    • ID: 0x11
      TYPE: BYTE
      required: no
      VALUE: Encryption algorithm (0=none, 1=aes128-cbc [default], 2=aes128-gcm)
    • ID: 0x40
      TYPE: STR_UTF8
      required: no
      VALUE: Codename / type identifier of the agent
    • ID: 0x41
      TYPE: INT32
      required: no
      VALUE: Build version of the agent
    • ID: 0x42
      TYPE: LIST<STR_UTF8>
      required: no
      VALUE: List of agent feature strings (agent-defined capability flags)
    • ID: 0x43
      TYPE: INT32 or LONG
      required: no
      VALUE: ID of the payload used to generate this agent. Sent as INT32 for legacy agents; newer agents may send LONG. The server accepts both.
    • ID: 0x44
      TYPE: BLOB
      required: no
      VALUE: Capabilities bitmap. Byte at index 8 advertises supported ExecUnit formats for self-process execution; byte at index 10 advertises supported formats for new/existing-process execution. Bit flags in both bytes are: 0x01=SHELLCODE_NATIVE, 0x02=DOTNET_EXE, 0x04=DOTNET_DLL, 0x08=NATIVE_LIB.
    • ID: 0x45
      TYPE: BLOB
      required: no
      VALUE: Preferred ExecUnit format order for self-process execution. This does not add support by itself; it orders the supported formats from 0x44. Each byte is an ExecUnitType: 0x00=SHELLCODE_NATIVE, 0x01=DOTNET_EXE, 0x02=DOTNET_DLL, 0x03=NATIVE_LIB. Earlier entries are preferred.
    • ID: 0x46
      TYPE: BLOB
      required: no
      VALUE: Preferred ExecUnit format order for new/existing-process execution. Same encoding and support/preference separation as 0x45.

    Note: 0x44 uses bitmask encoding for supported formats; 0x45 and 0x46 use ordered ordinal ExecUnitType byte values.

Encrypted metadata TLV structure

  • ID: 0x12
    TYPE: PARENT
    VALUE: structure contains encrypted metadata
    • ID: 0x01
      TYPE: BYTE
      required: YES
      VALUE: Is metadata encrypted [ no = 0x00 | yes = 0x01 ]
    • ID: 0x02
      TYPE: GUID
      required: no
      VALUE: Encryption key GUID
    • ID: 0x03
      TYPE: PARENT
      required: no
      VALUE: Encryption configuration (not used yet)
    • ID: 0x10
      TYPE: BLOB
      required: no VALUE: Encrypted metadata TLV

Encrypted data TLV structure

(in both direction between C2 and Agent core)

  • ID: 0x13
    TYPE: PARENT
    VALUE: structure contains encrypted data
    • ID: 0x01
      TYPE: BYTE
      required: YES
      VALUE: Is data encrypted [ no = 0x00 | yes = 0x01 ]
    • ID: 0x03
      TYPE: PARENT
      required: no
      VALUE: Encryption configuration
      • ID: 0x01
        TYPE: BYTE
        required: no
        VALUE: Encryption algorithm (1=aes128-cbc [default as of now], 2=aes128-gcm)
    • ID: 0x04
      TYPE: BLOB
      required: no
      VALUE: IV value, if not present then null IV is used
    • ID: 0x10
      TYPE: BLOB
      required: no
      VALUE: Encrypted data