Agent plugin
Last updated
Last updated
┌──────────────────────────────────────────────────────────────────────────────────┐
│ AGENT PLUGIN FLOW │
├──────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ╔════════════════════════════════════════════════════════════════════════════╗ │
│ ║ AGENT GENERATION ║ │
│ ╚════════════════════════════════════════════════════════════════════════════╝ │
│ │
│ GUI ──> WS /channel (agent/generate) │
│ │ │
│ V │
│ ┌─────────────────────────────────────────────────────────────────────────────┐ │
│ │ TEAMSERVER │ │
│ │ │ │ │
│ │ V │ │
│ │ TsAgentGenerate(agentType, config) │ │
│ │ │ │ │
│ │ V │ │
│ │ ┌───────────────────────────────────────────────────────────────────────┐ │ │
│ │ │ EXTENDER │ │ │
│ │ │ │ │ │ │
│ │ │ V │ │ │
│ │ │ PluginAgent.GenerateProfiles(BuildProfile) │ │ │
│ │ │ │ │ │ │
│ │ │ └──> Create profiles for each listener │ │ │
│ │ │ return [][]byte (agentProfiles) │ │ │
│ │ │ │ │ │
│ │ │ PluginAgent.BuildPayload(BuildProfile, agentProfiles) │ │ │
│ │ │ │ │ │ │
│ │ │ ├──> TsAgentBuildExecute() ←── Run build commands │ │ │
│ │ │ ├──> TsAgentBuildLog() ←── Build logging │ │ │
│ │ │ │ │ │ │
│ │ │ └──> return []byte (payload), filename │ │ │
│ │ │ │ │ │
│ │ └───────────────────────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ╔════════════════════════════════════════════════════════════════════════════╗ │
│ ║ AGENT REGISTRATION ║ │
│ ╚════════════════════════════════════════════════════════════════════════════╝ │
│ │
│ Agent ──> Request to Listener (first contact) │
│ │ │
│ V │
│ ┌─────────────────────────────────────────────────────────────────────────────┐ │
│ │ EXTENDER (Listener Plugin) │ │
│ │ │ │ │
│ │ V │ │
│ │ processRequest(ctx) ──> Parse data │ │
│ │ │ │ │
│ │ V │ │
│ │ ┌───────────────────────────────────────────────────────────────────────┐ │ │
│ │ │ TEAMSERVER │ │ │
│ │ │ │ │ │ │
│ │ │ V │ │ │
│ │ │ TsAgentCreate(agentCrc, agentId, data, listenerName, IP, async) │ │ │
│ │ │ │ │ │ │
│ │ │ V │ │ │
│ │ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ │
│ │ │ │ EXTENDER (Agent Plugin) │ │ │ │
│ │ │ │ │ │ │ │ │
│ │ │ │ V │ │ │ │
│ │ │ │ PluginAgent.CreateAgent(data) │ │ │ │
│ │ │ │ │ │ │ │ │
│ │ │ │ ├──> Decrypt data │ │ │ │
│ │ │ │ ├──> Parse agent info (OS, user, computer, etc.) │ │ │ │
│ │ │ │ │ │ │ │ │
│ │ │ │ └──> return AgentData, ExtenderAgent │ │ │ │
│ │ │ │ │ │ │ │
│ │ │ └─────────────────────────────────────────────────────────────────┘ │ │ │
│ │ │ │ │ │ │
│ │ │ └──> Save to DBMS, broadcast to clients │ │ │
│ │ │ │ │ │
│ │ └───────────────────────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ╔════════════════════════════════════════════════════════════════════════════╗ │
│ ║ COMMAND EXECUTION ║ │
│ ╚════════════════════════════════════════════════════════════════════════════╝ │
│ │
│ GUI ──> POST /agent/command/execute │
│ │ │
│ V │
│ ┌─────────────────────────────────────────────────────────────────────────────┐ │
│ │ TEAMSERVER │ │
│ │ │ │ │
│ │ V │ │
│ │ TsTaskCreate(agentId, command, args) │ │
│ │ │ │ │
│ │ V │ │
│ │ ┌───────────────────────────────────────────────────────────────────────┐ │ │
│ │ │ EXTENDER │ │ │
│ │ │ │ │ │ │
│ │ │ V │ │ │
│ │ │ ExtenderAgent.CreateCommand(agentData, args) │ │ │
│ │ │ │ │ │ │
│ │ │ ├──> Parse command and arguments │ │ │
│ │ │ ├──> Create TaskData with packed command │ │ │
│ │ │ │ │ │ │
│ │ │ └──> return TaskData, ConsoleMessageData │ │ │
│ │ │ │ │ │
│ │ └───────────────────────────────────────────────────────────────────────┘ │ │
│ │ │ │ │
│ │ └──> Add to agent queue, broadcast to clients │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ╔════════════════════════════════════════════════════════════════════════════╗ │
│ ║ DATA PROCESSING (Agent → Server) ║ │
│ ╚════════════════════════════════════════════════════════════════════════════╝ │
│ │
│ Agent ──> Request to Listener (with results) │
│ │ │
│ V │
│ ┌─────────────────────────────────────────────────────────────────────────────┐ │
│ │ EXTENDER (Listener Plugin) │ │
│ │ │ │ │
│ │ V │ │
│ │ processRequest(ctx) ──> Parse body data │ │
│ │ │ │ │
│ │ V │ │
│ │ ┌───────────────────────────────────────────────────────────────────────┐ │ │
│ │ │ TEAMSERVER │ │ │
│ │ │ │ │ │ │
│ │ │ V │ │ │
│ │ │ TsAgentProcessData(agentId, bodyData) │ │ │
│ │ │ │ │ │ │
│ │ │ V │ │ │
│ │ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ │
│ │ │ │ EXTENDER (Agent Plugin) │ │ │ │
│ │ │ │ │ │ │ │ │
│ │ │ │ V │ │ │ │
│ │ │ │ ExtenderAgent.Decrypt() + ProcessTasksResult() │ │ │ │
│ │ │ │ │ │ │ │ │
│ │ │ │ ├──> case COMMAND_OUTPUT: TsTaskUpdate │ │ │ │
│ │ │ │ ├──> case COMMAND_DOWNLOAD: TsDownloadAdd/Update/Close │ │ │ │
│ │ │ │ ├──> case COMMAND_SCREENSHOT: TsScreenshotAdd │ │ │ │
│ │ │ │ ├──> case COMMAND_LINK: TsPivotCreate │ │ │ │
│ │ │ │ ├──> case COMMAND_TUNNEL_*: TsTunnelConnection* │ │ │ │
│ │ │ │ └──> ... other commands │ │ │ │
│ │ │ │ │ │ │ │
│ │ │ └─────────────────────────────────────────────────────────────────┘ │ │ │
│ │ │ │ │ │
│ │ └───────────────────────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────────────────────┘extender_type: "agent"
extender_file: "agent.so"
ax_file: "ax_config.axs"
agent_name: "AGENT_NAME"
agent_watermark: "deadbeef"
listeners:
- "LISTENER_NAME_1"
- "LISTENER_NAME_2"
# - ....
multi_listeners: falsetype PluginAgent interface {
// Get ExtenderAgent
GetExtender() ExtenderAgent
// Generate profiles for listeners
GenerateProfiles(profile BuildProfile) ([][]byte, error)
// Build agent payload
BuildPayload(profile BuildProfile, agentProfiles [][]byte) ([]byte, string, error)
// Create agent from beat data
CreateAgent(beat []byte) (AgentData, ExtenderAgent, error)
}
// ExtenderAgent - interface for working with agent
type ExtenderAgent interface {
// Encrypt data
Encrypt(data []byte, key []byte) ([]byte, error)
// Decrypt data
Decrypt(data []byte, key []byte) ([]byte, error)
// Pack tasks for sending to agent
PackTasks(agentData AgentData, tasks []TaskData) ([]byte, error)
// Pack data for pivot agent
PivotPackData(pivotId string, data []byte) (TaskData, error)
// Create task from command
CreateCommand(agentData AgentData, args map[string]any) (TaskData, ConsoleMessageData, error)
// Callbacks for tunnels
TunnelCallbacks() TunnelCallbacks
// Callbacks for terminal
TerminalCallbacks() TerminalCallbacks
}
// TunnelCallbacks - functions for tunnel management
type TunnelCallbacks struct {
ConnectTCP func(channelId, tunnelType, addressType int, address string, port int) TaskData
ConnectUDP func(channelId, tunnelType, addressType int, address string, port int) TaskData
WriteTCP func(channelId int, data []byte) TaskData
WriteUDP func(channelId int, data []byte) TaskData
Close func(channelId int) TaskData
Reverse func(tunnelId, port int) TaskData
}
// TerminalCallbacks - functions for terminal management
type TerminalCallbacks struct {
Start func(terminalId int, program string, sizeH, sizeW int, oemCP int) TaskData
Write func(terminalId int, oemCP int, data []byte) TaskData
Close func(terminalId int) TaskData
}// 1. Register agent commands (called when plugin loads)
function RegisterCommands(listenerType) {
// listenerType: "BeaconHTTP", "BeaconDNS", "BeaconSMB", "BeaconTCP", etc.
// Create command
let cmd_ls = ax.create_command("ls", "List files", "ls /tmp", "Task: list files");
cmd_ls.addArgString("path", false, "."); // name, required, default
let cmd_cd = ax.create_command("cd", "Change directory", "cd /tmp", "Task: change dir");
cmd_cd.addArgString("path", true);
// Command with subcommands
let cmd_ps_list = ax.create_command("list", "Show processes", "ps list");
let cmd_ps_kill = ax.create_command("kill", "Kill process", "ps kill 1234");
cmd_ps_kill.addArgInt("pid", true);
let cmd_ps = ax.create_command("ps", "Process manager");
cmd_ps.addSubCommands([cmd_ps_list, cmd_ps_kill]);
// Alias with pre-hook
let cmd_shell = ax.create_command("shell", "Execute via cmd.exe", "shell whoami");
cmd_shell.addArgString("cmd", true);
cmd_shell.setPreHook(function(id, cmdline, parsed_json) {
ax.execute_alias(id, cmdline, "ps run -o cmd.exe /c " + parsed_json["cmd"]);
});
// Commands group
let commands = ax.create_commands_group("beacon", [cmd_ls, cmd_cd, cmd_ps, cmd_shell]);
return {
commands_windows: commands, // Commands for Windows
// commands_linux: commands, // Commands for Linux (optional)
}
}
// 2. UI for payload generation (called when generation dialog opens)
function GenerateUI(listeners_type) {
// listeners_type: array of selected listener types
let labelArch = form.create_label("Arch:");
let comboArch = form.create_combo();
comboArch.addItems(["x64", "x86"]);
let labelFormat = form.create_label("Format:");
let comboFormat = form.create_combo();
comboFormat.addItems(["Exe", "DLL", "Shellcode"]);
let layout = form.create_gridlayout();
layout.addWidget(labelArch, 0, 0);
layout.addWidget(comboArch, 0, 1);
layout.addWidget(labelFormat, 1, 0);
layout.addWidget(comboFormat, 1, 1);
let container = form.create_container();
container.put("arch", comboArch);
container.put("format", comboFormat);
let panel = form.create_panel();
panel.setLayout(layout);
return {
ui_panel: panel,
ui_container: container,
ui_height: 300,
ui_width: 400
}
}// Context menus for agent sessions
let exit_action = menu.create_action("Terminate", function(agents) {
agents.forEach(a => ax.execute_command(a, "terminate process"));
});
menu.add_session_agent(exit_action, ["beacon"]); // For agents of type "beacon"
// Context menus for File Browser
let download_action = menu.create_action("Download", function(files) {
files.forEach(f => ax.execute_command(f.agent_id, "download " + f.path + f.name));
});
menu.add_filebrowser(download_action, ["beacon"]);
// Browser event handlers
event.on_filebrowser_disks(function(id) {
ax.execute_browser(id, "disks");
}, ["beacon"]);
event.on_filebrowser_list(function(id, path) {
ax.execute_browser(id, "ls " + path);
}, ["beacon"]);
event.on_processbrowser_list(function(id) {
ax.execute_browser(id, "ps list");
}, ["beacon"]);