Skip to content


This document outlines the implementation of commands in Tuoni. From a broad perspective, there are two types of commands: native commands and plugin-based commands. We will begin our explanation with native commands as they represent the simpler category.

Native commands

Native commands in Tuoni are those implemented directly within the agent. They consistently operate within the agent's process and are primarily associated with managing the agent's configuration or handling tasks that are impractical to implement as plugins. A prime example is the "die" command. This command terminates the agent process and, under no circumstances, should it be associated with any external processes or functionalities.

Plugin based commands

In Tuoni, the majority of commands are implemented as plugin-based commands, which bear a significant resemblance in structure to the listener plugin. These commands are composed of two essential parts:

  1. The C2 Plugin Part: This component is responsible for integrating with the Command and Control (C2) system. It manages the configuration of the implemented command(s), parses results, and handles other related tasks.

  2. Shellcode part: This portion is executed either within the agent or in a different process on the agent's machine. It is the actual implementation of the command, carrying out the intended operations.

How it works in practice

  1. Through the C2 API, the GUI or script selects a command for the agent and configures it.
  2. The command's name, agent GUI, and configuration are transmitted to the C2 via the C2 API.
  3. The C2 forwards the configuration to the command's plugin, which then converts it into a format understandable by the shellcode. The plugin returns this configuration along with the shellcode itself to the C2.

  4. The C2 dispatches all this information to the agent through the listener plugin-shellcode connection.

  5. The agent's core initiates the received shellcode in itself or another process (as configured) and establishes a connection to it (typically using named pipes).
  6. The agent's core sends the command's configuration to the shellcode via this connection and waits for the outcome.
  7. The command's shellcode executes its designated function and sends the result back to the agent's core.
  8. The agent's core then transmits these results back to the C2.
  9. The C2 utilizes the command plugin to interpret the result. The plugin provides the parsed result to the C2 in a specified format (which could be a file, a string, etc.).
  10. The command's results are now accessible through the C2 API.

Visual representation

Step 1

User tasks C2 to send command to the agent via C2 API. This can be done with GUI or script. User provides command configuration.

Command step 1

Step 2

C2 gives command configuration received via API to command plugin.

Command step 2

Step 3

Command plugin parses the provided configuration and gives C2 back the command shellcode and the configuration (in format shellcode understands) that should be relayed to the shellcode upon execution

Command step 3

Step 4

Shellcode and configuration is sent to the agent

Command step 4

Step 5

Agent core parses the information sent to it and separates the shellcode and configuration

Command step 5

Step 6

Agent core executes provided shellcode

Command step 6

Step 7

Agent core and executed shellcode create a data channel (named pipes usually) and agent core relays to it the configuration

Command step 7

Step 8

Command shellcode returns command results to the agent core

Command step 8

Step 9

Result is sent to the C2

Command step 9

Step 10

C2 core provides result to command plugin to parse

Command step 10

Step 11

Command plugin gives C2 core the parsed result

Command step 11

Step 12

User can now ask for command results from the C2 via API

Command step 12