Skip to content

Agent Capabilities

The capabilities bitmap in agent metadata advertises execution contexts, native-command features, and executable-unit (ExecUnit) formats to Command and Control (C2). This reference defines the byte layout, commercial payload reporting, and C2 interpretation at the source revisions documented below.

Metadata fields

Capabilities and format preferences are separate fields in the agent metadata Type-Length-Value (TLV) structure:

Field ID Type Meaning
0x44 BLOB Capabilities bitmap: each bit advertises support for a specific feature.
0x45 BLOB Ordered ExecUnit type IDs for execution in the agent's own process; earlier entries are preferred.
0x46 BLOB Ordered ExecUnit type IDs for execution in a new or existing process; earlier entries are preferred.

These fields are optional in the general protocol for compatibility with other agent implementations. The commercial agent includes 0x44 in its full metadata and emits each preference field when its list is nonempty. Its metadata-field policy keeps capabilities and preferences enabled; Metadata Controls cannot disable them.

The bitmap is separate from the agent-defined feature strings in field 0x42 and from the metadataFields settings that control which optional metadata the agent collects.

Reporting lifecycle

The commercial agent calculates the bitmap and preference lists during metadata initialization at startup and reuses them in later reports. These values come from the build and embedded settings; refreshing metadata does not probe installed runtimes, plugin availability, or command functionality.

Full metadata includes the capability bitmap and any nonempty preference lists. Between full reports, Metadata::getBytes() can return no full metadata body for unchanged metadata; the listener then sends a GUID-only metadata update. A counter also forces full reports at 16-call intervals.

Metadata updates are incremental: a GUID-only update does not withdraw previously reported capabilities or preferences. Retain an existing field value when an update omits that field; if no value has ever been reported, it remains unknown. See the listener metadata interface and server listener integration.

Bitmap encoding

Field 0x44 contains raw bytes, with no additional count or terminator inside the value. The TLV length gives the number of bytes. The current commercial implementation produces 12 bytes, indexed from 0 through 11.

Each byte is an independent bitmask. Bit 0 is the least significant bit (0x01), and bit 7 is the most significant bit (0x80). Combine flags within a byte with bitwise OR. To read a known flag, first check that its byte exists, then test (byte & mask) != 0. Do not interpret the whole blob as a multi-byte integer.

Byte index Meaning
0 Supported execution contexts
1-4 Native-command support
5-7 Reserved; currently zero
8 Supported ExecUnit formats in the agent's own process
9 Reserved; currently zero
10 Supported ExecUnit formats in new or existing processes
11 Reserved; currently zero

Treat undefined bits and additional bytes as unknown extensions. Keep reserved positions when interpreting the bitmap, and check the received length instead of assuming every agent sends the current 12-byte layout.

Execution contexts

Byte 0 reports which execution contexts the agent supports:

Capability mask Name Execution-context ID Meaning
0x01 SELF 0 The agent's own process
0x02 NEW 2 A new process
0x04 EXISTING 1 An existing process

The context IDs are the ExecContextType values used in execution configuration. They are separate from the capability masks: deriving a mask as 1 << context ID would swap NEW and EXISTING. Use the explicit mapping above.

These flags describe contexts; bytes 8 and 10 separately describe the formats supported in those contexts. For example, byte 0 equal to 0x07 advertises all three contexts without implying that every format is supported in each context.

Native commands

Bytes 1-4 use the following flags. Names identify capabilities, not numeric command IDs; see the native-command protocol for command messages.

Mask Byte 1 Byte 2 Byte 3 Byte 4
0x01 BOF OVERRIDE_LIST RUN_AS METADATA_FIELDS_ENABLE
0x02 CD OVERRIDE_LOAD SH METADATA_FIELDS_DISABLE
0x04 CHMOD OVERRIDE_SET TOKEN_DEL METADATA_FIELDS_REPORT
0x08 CMD OVERRIDE_UNLOAD TOKEN_DEL_ALL Reserved
0x10 CONNECTION_CONF OVERRIDE_UNSET TOKEN_LIST Reserved
0x20 DIE POWERSHELL TOKEN_MAKE Reserved
0x40 JOBS PS TOKEN_STEAL Reserved
0x80 LS RUN TOKEN_USE Reserved

Byte 4 advertises the three metadata-control commands. It does not describe which individual metadata fields are enabled; those are reported by metadata-fields-report.

The override command flags in byte 2 do not describe individual hook functions or DLL callback signatures; see DLL Override Functions.

Several capability names differ from their corresponding protocol command names:

Capability name Protocol command
CONNECTION_CONF SET_LISTENER_CONF
PS PROCLIST
JOBS COMMAND_LIST
OVERRIDE_LOAD OVERRIDE_ADD
OVERRIDE_UNLOAD OVERRIDE_REMOVE
TOKEN_DEL TOKEN_DELETE
TOKEN_DEL_ALL TOKEN_DELETE_ALL

The CMD, POWERSHELL, SH, and RUN_AS flags describe command features; they have no standalone wire-command opcodes in the commercial agent's native-command factory. A capability name therefore does not identify a distinct protocol message. The source constant for RUN_AS is named CAPABILITY_NATIVE_BYTE_3_RUNAS.

The bitmap is not a complete inventory of native commands. SHUTDOWN, TOKEN_FROM_HANDLE, PRIVILEGE_LIST, PRIVILEGE_ENABLE, and PRIVILEGE_DISABLE have protocol command codes but no dedicated bits in this layout. Their availability cannot be determined by testing a corresponding flag. The C2's command-specific eligibility rules must handle these commands separately; see Receiver interpretation.

ExecUnit formats and preferences

Bytes 8 and 10 use the same format masks. Preference fields 0x45 and 0x46 instead contain a sequence of type IDs, one per byte:

Format mask in 0x44 Type ID in 0x45 / 0x46 ExecUnit type
0x01 0x00 SHELLCODE_NATIVE
0x02 0x01 DOTNET_EXE
0x04 0x02 DOTNET_DLL
0x08 0x03 NATIVE_LIB

For example, byte 8 equal to 0x0F advertises all four formats for self-process execution. A preference value of 01 02 03 00 orders those formats as .NET executable, .NET library, native library, then shellcode. The final 00 is a valid type ID, not a terminator.

Preferences do not add support. The C2 also needs a compatible artifact from the command plugin; see Agent capability matching and Formats and Compatibility.

NATIVE_LIB identifies the platform's native library format: a Windows dynamic-link library (DLL), a Linux/FreeBSD Executable and Linkable Format (ELF) shared object, or a macOS Mach-O dynamic library. The implementation's capability constants retain the name NATIVE_DLL for this bit on all platforms.

Receiver interpretation

The following decoding and selection rules were verified against tuoni-server commit 4bdaacbb033569a3564d499026806d2e77085d4a, whose version.yml declares 0.17.1. They describe that implementation of the C2 and its software development kit (SDK); other revisions may differ. Apply the incremental update rules before interpreting an omitted field.

Decoding and metadata updates

Received data Verified C2 interpretation
No new metadata, or 0x44 omitted No new bitmap is supplied. Retain any previously reported value; if none exists, support remains unreported.
0x44 present with a zero-length value Every mapped native capability becomes UNSUPPORTED; both format sets become empty. This replaces previously reported support.
Nonempty bitmap that does not contain a native capability's byte That native capability is UNREPORTED. An earlier reported value is retained during metadata merging.
Native capability's byte exists and its bit is clear / set That capability becomes UNSUPPORTED / SUPPORTED, replacing any earlier value.
0x44 is present, but format byte 8 or 10 is missing The corresponding format set becomes empty. It replaces the earlier set rather than retaining it.
Format byte 8 or 10 is present Its known set bits define the corresponding format set, replacing the earlier set. Unknown bits are ignored.
0x45 or 0x46 omitted No new preference list is supplied for that context. Retain any previous list; if none exists, no preference has been reported. Omission does not clear support bits.
A preference field is explicitly empty The TLV decoder treats it as omitted. It does not clear an earlier preference list.
A preference list contains only some supported formats Those formats have an explicit preference order. The remaining support bits are unchanged.

The verified C2 decoder reads native-command bytes 1-4 and format bytes 8 and 10. It ignores execution-context byte 0, reserved bytes, and unknown bits. The context flags remain part of the payload's advertised layout, but this decoder does not use them to determine context support.

Do not pad a short bitmap with zeroes before decoding native capabilities: that changes missing statuses from UNREPORTED to UNSUPPORTED. Format sets follow different rules, as shown above. Native statuses merge individually, while both format sets come from the latest supplied bitmap.

Nonempty preference fields are decoded in order, preserving duplicates. Unknown type IDs cause preference decoding to fail; they are not silently ignored. An explicit empty preference field is treated as absent, so it cannot be used to clear a cached preference list through this TLV interface.

Native-command eligibility

Built-in native templates using BaseNativeCommandTemplate first check their unconditional requirements, such as applicable listener requirements. The mapped capability then determines eligibility; legacy platform and agent-codename checks apply in the UNREPORTED path:

Effective native status Eligibility
SUPPORTED Passes the capability check.
UNSUPPORTED Fails the capability check.
UNREPORTED Uses the template's legacy checks, and only for an agent of SDK type SHELLCODE_AGENT.

An absent capabilities object also follows the unreported path. Templates based on BaseNativeCommandTemplate without an assigned capability bit follow that same path, including the SDK agent-type restriction and their command-specific legacy checks. A capability check does not guarantee that a custom payload build includes working functionality.

ExecUnit selection and fallback

For an ExecUnitCommand, the selector uses the self-process format set and preference list for self or unspecified context. New and existing contexts share the other-process set and list. The table describes effective SDK metadata after decoding and merging. The rules below assume consistent reports: every preferred format should also be present in the corresponding supported set.

Effective metadata Selection behavior
Capabilities absent, both format sets empty/absent, or the selected set absent Treats ExecUnit support as unavailable; legacy fallback may apply.
Selected format set empty while the other set is nonempty Keeps an empty supported set for this context. This differs from unavailable ExecUnit support.
Selected set nonempty and its preference list absent/empty Uses all supported formats in the default SDK order below.
Nonempty preference list Uses listed formats as automatic candidates in preference order. Supported formats omitted from the list are not appended as automatic candidates.

The default SDK order is SHELLCODE_NATIVE, NATIVE_LIB, DOTNET_DLL, then DOTNET_EXE, restricted to the selected context's supported formats. This is the Java SDK enum order, not the order of the wire type IDs. If an incoming preference field was empty but an earlier list was retained, that retained list still controls selection.

An explicitly requested execUnitType must appear in both the command's supported formats and the agent's selected-context support set. It need not appear in the preference list. Failure is an error; an explicit request does not use legacy fallback.

Without an explicit request, the selector chooses the first preferred type supplied by the command. If no type is selected, it permits legacy shellcode serialization only when the command also implements ShellcodeCommand and either ExecUnit support is unavailable or the effective preference list contains SHELLCODE_NATIVE. Otherwise, selection fails with No compatible execUnitType found. Legacy serialization is a separate path from selecting a typed SHELLCODE_NATIVE ExecUnit.

In particular, an empty bitmap makes both format sets empty and can still allow that legacy fallback, even though all mapped native capabilities are UNSUPPORTED. Native-command eligibility and plugin-command format selection are separate decisions.

Info

The automatic selector in the verified revision assumes capability and preference reports agree; it does not normalize a preference list against the supported set. Contradictory reports can therefore produce an unsupported selection. Explicit execUnitType validation checks the supported set separately. Keep preferred entries within the advertised format set; this is an implementation limitation of the documented revision.

Current commercial payload values

The current initialization code advertises the following bitmap values. Hexadecimal pairs below are the 12 value bytes in order, without a TLV header.

Build 0x44 value
Windows, native DLL loader enabled 07 FB FF FD 07 00 00 00 0F 00 01 00
Windows, native DLL loader disabled 07 FB FF FD 07 00 00 00 07 00 01 00
Linux, FreeBSD, macOS 01 F6 C0 02 07 00 00 00 08 00 00 00

Windows reports all three contexts, with shellcode as the only format advertised for other processes. Linux, FreeBSD, and macOS report self-process execution with NATIVE_LIB. All four platforms advertise the three metadata-control commands in byte 4.

Default preferences are:

Build Self-process field 0x45 Other-process field 0x46
Windows, native DLL loader enabled 01 02 03 00 00
Windows, native DLL loader disabled 01 02 00 00
Linux, FreeBSD, macOS 03 Omitted

Custom preference lists

On Windows, the payload's execUnitTypeOrder setting can replace the default self-process preference order. This changes field 0x45, not the bitmap or the other-process preference list.

The payload stores the order in the four-byte embedded execUnitTypesOrder array. The native emitter handles that array as follows:

Embedded configuration Emitted self-process preferences
First byte is 0xFF Keep the default list.
First byte is not 0xFF Replace the default list with the configured entries, stopping at the first 0xFF or after four entries.
Supported format omitted from a custom list Do not append it automatically; its support bit is unchanged.
NATIVE_LIB entry with _DISABLE_DLL_LOADER Skip the entry. That build also clears NATIVE_LIB support in byte 8.

The 0xFF sentinel belongs to the embedded configuration, not the emitted preference blob. If filtering leaves no entries, the agent omits 0x45 even though other format support bits can remain set. An absent preference list therefore does not mean that the context supports no formats; see Receiver interpretation.

Apart from the sentinel and disabled-native-library filtering, the native emitter copies the configured bytes without deduplicating or validating type IDs. These are the rules for the embedded array, not a claim that the payload-generation API accepts duplicate or invalid entries; input validation by the generator is a separate contract.

Info

These values describe what the current implementation advertises. The native-command bitmap does not account for the _DISABLE_BOF, _DISABLE_TOKENS, or _DISABLE_OVERRIDES build switches. A custom build using those switches can therefore advertise commands whose functionality is disabled. A capability bit also does not establish that a compatible plugin artifact or runtime dependency is available.

_DISABLE_DLL_LOADER removes NATIVE_LIB support and preference entries, but leaves the OVERRIDE_LOAD capability set even though override loading cannot succeed. The "native DLL loader disabled" examples show the advertised values, not every functional effect of that build switch.

Implementation references

Payload behavior and build-specific examples were checked against payloads_commercial commit 0023aa38439ac06f910c18daac4b4abf99899f15. These examples describe that revision; they are not a guarantee for all releases or custom builds. The source paths below are relative to AgentPower/AgentPower/:

Source Responsibility
Definitions.h Metadata field IDs and CAPABILITY_* byte masks
data_objects/Metadata.cpp Metadata::setCapabilitiesAndExecUnitTypes() builds the bitmap and preference lists at startup; Metadata::getBytes() controls full metadata emission.
Enums.h ExecContextType IDs and ExecUnitType ordinal values
Structs.h Four-byte GlobalConfInitial::execUnitTypesOrder array on Windows
commands/INativeCommand.cpp Native-command codes and handler registrations
listeners/Listener.cpp Listener::received_request_metadata() sends GUID-only metadata when no full report is supplied.
containers/TLV.h Byte-vector constructors store the raw blob value.
specials/DllLoader.cpp, commands/natives/overrides/NativeCommandOverridesUpload.cpp Disabled DLL-loader behavior and its effect on override loading

The receiver rules were checked separately against tuoni-server commit 4bdaacbb033569a3564d499026806d2e77085d4a (version.yml: 0.17.1). The following classes are under each module's src/main/java/com/shelldot/tuoni/ package tree:

Module directory Class or enum Responsibility
server/crypto/impl server.crypto.impl.tlv.AgentMetadataTlv Bitmap and preference-field decoding
server/domain server.domain.tlv.TlvConstants Mapping wire type IDs to SDK ExecUnit types
server/agent/api server.agent.CustomizableAgentMetadata Incremental native-status, format-set, and preference updates
server/native-command server.native_command.templates.BaseNativeCommandTemplate Native capability checks and legacy eligibility
server/command/impl server.command.impl.CommandExecUnitService Format selection, explicit-type validation, and legacy fallback
plugin/sdk plugin.sdk.command.ExecUnitType Default SDK format ordering

The listener integration guide describes incremental metadata updates, and the SDK changelog identifies the capability and preference accessors. Recheck the listed consumer sources before applying these exact fallback rules to a different server revision.