Skip to content

Commercial payload

The commercial payload is the full-featured Windows agent, supporting both x64 and x86 architectures. It covers all common payload types - debug executable, executable, service, DLL, and shellcode - with significantly more configuration options than the open-source payload.

Plugin ID: shelldot.payload.commercial

Template ID (x64): shelldot.payload.commercial-windows-x64

Template ID (x86): shelldot.payload.commercial-windows-x86

Supported types: DEBUG_EXECUTABLE, EXECUTABLE, SERVICE, DLL, SHELLCODE

Configuration

Use the table below to customize how the Commercial Payload behaves. Some attributes apply universally; others come into play only when certain methods or payload types are selected.

type is the only required top-level property. All other top-level properties are optional; their effective defaults are documented below. When an execTypeSelf, execTypeNew, or execTypeExisting object is supplied, its allocMethod is required. When peStructureElements is supplied, it must contain versionElements with all eleven string properties shown in the table.

Attribute Explanation
type The payload type. Options: DEBUG_EXECUTABLE, EXECUTABLE, SERVICE, DLL, SHELLCODE.
confLocation Where the payload's configuration is stored. Options: Resource, Appended. Default: Resource. Appended is not valid for SHELLCODE payloads.
dllInternalName For DLL-type payloads, this value appears in the export table header (under filename).
dllMethodName The exported method name used by DLL-type payloads. Default: bob; an empty value also uses bob.
paddingSize Number of bytes of NULL-padding appended to the payload. Default: 0 (no padding).
randomnessSeed Seed for random actions used in obfuscation. Default 0 produces a random build; a nonzero fixed seed produces reproducible random actions.
startupNopOperationCount Number of random no-op actions performed at startup. Default: 0. These are not literal CPU NOP instructions but functionally equivalent operations that add junk execution before the real payload logic runs.
startupAmsiBypassMethod AMSI bypass method applied at startup. Options: None, PatchAmsiScanBuffer, PatchAmsiScanBufferDelayedThreaded, HwBreakpoint, PatchClrPtr. Default: None.
startupEtwBypassMethod ETW bypass method applied at startup. Options: None, PatchEtwEventWrite, PatchEtwEventWriteDelayedThreaded, HwBreakpoint. Default: None.
initialWait Seconds to wait after startup before launching the main payload code. Default: 0.
sleepMethod Method used for sleep intervals between callbacks. Options: Sleep, StdSleep, WaitableTimer, WaitForEvent. Default: Sleep.
rweSectionSize Size of the executable section where shellcodes and BOF files are loaded. By default the reusable section is disabled; set a positive size to enable it.
notUseDotNetLoader Default: false. The payload normally uses a COM-based .NET execution method when it detects .NET shellcode. Set to true to disable this and use the standard loader instead.
unloadAppDomain Default: false. When enabled, attempts to unload the AppDomain after .NET execution. Can be unstable in some scenarios - test before operational use.
disableAmsiBypassInShellcodes Default: true. Disables the automatic AMSI bypass applied inside shellcode when running in the agent's own process. Set to false to keep that automatic bypass enabled.
importTableRandomizationSeed Controls Import Address Table (IAT) randomization. Default 0 produces a fully random IAT on each generation. A fixed seed produces identical IAT layouts across builds.
customTemplate By default the built-in template is used. Supply a filename or relative path beneath this plugin's configured template directory, or a direct http: or https: URL. Local values require the plugin's custom-payload-template-dir setting.
certificateFile At most one PE code-signing certificate file (.pfx / .p12) may be uploaded in a multipart/form-data request. It must be valid PKCS#12. When set, generated PE payloads are signed with this certificate. SHELLCODE output is not signed.
signingCertificatePassword Password for the certificateFile.
signingTimestampProvider Reachable URL of a trusted timestamping authority used when signing (e.g. http://timestamp.digicert.com). When omitted, the signature has no timestamp.
peStructureElements Optional PE metadata block. If supplied, its versionElements object and every string field below are required.
  ↳ versionElements.companyName Company name embedded in the PE version info.
  ↳ versionElements.fileDescription File description embedded in the PE version info.
  ↳ versionElements.fileVersion File version string embedded in the PE version info.
  ↳ versionElements.internalName Internal name embedded in the PE version info.
  ↳ versionElements.legalCopyright Copyright notice embedded in the PE version info.
  ↳ versionElements.legalTrademarks Trademark notice embedded in the PE version info.
  ↳ versionElements.originalFilename Original filename embedded in the PE version info.
  ↳ versionElements.privateBuild Private build description embedded in the PE version info.
  ↳ versionElements.productName Product name embedded in the PE version info.
  ↳ versionElements.productVersion Product version string embedded in the PE version info.
  ↳ versionElements.specialBuild Special build description embedded in the PE version info.
execUnitTypeOrder Ordered list of up to four ExecUnit formats the agent advertises as preferred for self-process command execution. Entries can be DOTNET_EXE, DOTNET_DLL, NATIVE_LIB, or SHELLCODE_NATIVE. Default: [DOTNET_EXE, DOTNET_DLL, NATIVE_LIB, SHELLCODE_NATIVE].
pipenameTemplate Template string for naming the internal named pipes used during command and listener communication, can use same templates as HTTP listener filename. When omitted, a random name is generated.
mutex Optional string-based mutex that prevents the payload from launching multiple concurrent instances with the same mutex value on the same machine. Default: not set.
autoDestructDate ISO-8601 timestamp after which the agent will terminate itself automatically. Default: not set.
obfuscationType Obfuscation strategy applied to the payload binary. Options: NONE, LIGHT_OBFUSCATION, SINGLE_NOP, GARBAGE_CODE. Default: NONE.
obfuscationSeed Used only when obfuscationType is GARBAGE_CODE. Default 0 produces random garbage code; a nonzero fixed seed makes it reproducible. It has no effect with the other obfuscation types.
embeddedListener Optional embedded listener generated into the payload. Options: NONE, HTTP. Default: NONE (no embedded listener).
shellcodeDecodingLogic Custom encoding/decoding logic for SHELLCODE output. It is validated and applied only when type is SHELLCODE; it is ignored for other output types. The decoding stub is automatically prepended. See shellcodeDecodingLogic below.
guardrails[ ] Conditions that must be met before the payload starts execution. Default: empty. At most one guardrail may use EnvSecret.
  ↳ type Guardrail type. Options: DomainExists, DomainNotExists, TimeBefore, TimeAfter, EnvSecret. See EnvSecret below.
  ↳ value Value for the guardrail. For DomainExists/DomainNotExists: a hostname. For TimeBefore/TimeAfter: an ISO-8601 timestamp. For EnvSecret: see below.
execTypeSelf Optional settings for allocating and executing shellcode in the agent's own process. If supplied, allocMethod is required.
  ↳ allocMethod Required in execTypeSelf. Options: VirtualAlloc, VirtualAllocNuma, NtAllocateVirtualMemory, NtAllocateMapView, NtAllocateDllMap.
  ↳ allocOnOtherThread Perform the allocation on a separate thread.
  ↳ dllName DLL to map when using NtAllocateDllMap as the allocation method.
  ↳ dripAlloc Allocate memory page-by-page instead of in a single call.
  ↳ dripProtectRwRwe When drip allocating, set each page to RWE individually.
  ↳ drippingSize Size in bytes of each chunk when drip-writing shellcode into memory.
  ↳ execMethod Execution method. Currently only Direct is available (jumps to shellcode directly with no intermediate API call).
  ↳ protectOnOtherThread Change memory protection on a separate thread.
  ↳ protectRwRwe Allocate as RW first, then switch to RWE just before execution.
  ↳ shellcodeEncoding Number of times shellcode is recursively encoded and prefixed with a decoding stub.
  ↳ shellcodePadding Bytes of no-op padding prepended to the shellcode (not literal NOP instructions, but functionally inert).
  ↳ sleepBetweenAllocExec Milliseconds to sleep between allocation and execution.
  ↳ sleepBetweenAllocProtect Milliseconds to sleep between allocation and protection change.
  ↳ sleepBetweenAllocWrite Milliseconds to sleep between allocation and writing shellcode.
  ↳ sleepBetweenDrippings Milliseconds to sleep between drip-write chunks.
  ↳ writeOnOtherThread Write shellcode to memory on a separate thread.
execTypeNew Optional settings for allocating and executing shellcode in a newly spawned process. If supplied, allocMethod is required.
  ↳ allocMethod Required in execTypeNew. Options: VirtualAlloc, VirtualAllocNuma, NtAllocateMapView, NtAllocateVirtualMemory.
  ↳ allocOnOtherThread Perform the allocation on a separate thread.
  ↳ dripAlloc Allocate memory page-by-page instead of in a single call.
  ↳ dripProtectRwRwe When drip allocating, set each page to RWE individually.
  ↳ drippingSize Size in bytes of each chunk when drip-writing shellcode into memory.
  ↳ execMethod Execution method. Options: CreateThreadEx, NtCreateThreadEx, RtlCreateUserThread.
  ↳ protectOnOtherThread Change memory protection on a separate thread.
  ↳ protectRwRwe Allocate as RW first, then switch to RWE just before execution.
  ↳ shellcodeEncoding Number of times shellcode is recursively encoded and prefixed with a decoding stub.
  ↳ shellcodePadding Bytes of no-op padding prepended to the shellcode (not literal NOP instructions, but functionally inert).
  ↳ sleepBetweenAllocExec Milliseconds to sleep between allocation and execution.
  ↳ sleepBetweenAllocProtect Milliseconds to sleep between allocation and protection change.
  ↳ sleepBetweenAllocWrite Milliseconds to sleep between allocation and writing shellcode.
  ↳ sleepBetweenDrippings Milliseconds to sleep between drip-write chunks.
  ↳ writeOnOtherThread Write shellcode to memory on a separate thread.
execTypeExisting Optional settings for allocating and executing shellcode in an existing remote process. If supplied, allocMethod is required.
  ↳ allocMethod Required in execTypeExisting. Options: VirtualAlloc, VirtualAllocNuma, NtAllocateMapView, NtAllocateVirtualMemory.
  ↳ allocOnOtherThread Perform the allocation on a separate thread.
  ↳ dripAlloc Allocate memory page-by-page instead of in a single call.
  ↳ dripProtectRwRwe When drip allocating, set each page to RWE individually.
  ↳ drippingSize Size in bytes of each chunk when drip-writing shellcode into memory.
  ↳ execMethod Execution method. Options: CreateThreadEx, NtCreateThreadEx, RtlCreateUserThread.
  ↳ protectOnOtherThread Change memory protection on a separate thread.
  ↳ protectRwRwe Allocate as RW first, then switch to RWE just before execution.
  ↳ shellcodeEncoding Number of times shellcode is recursively encoded and prefixed with a decoding stub.
  ↳ shellcodePadding Bytes of no-op padding prepended to the shellcode (not literal NOP instructions, but functionally inert).
  ↳ sleepBetweenAllocExec Milliseconds to sleep between allocation and execution.
  ↳ sleepBetweenAllocProtect Milliseconds to sleep between allocation and protection change.
  ↳ sleepBetweenAllocWrite Milliseconds to sleep between allocation and writing shellcode.
  ↳ sleepBetweenDrippings Milliseconds to sleep between drip-write chunks.
  ↳ writeOnOtherThread Write shellcode to memory on a separate thread.

Guardrail: EnvSecret

The EnvSecret guardrail locks agent execution to a specific environment by tying the configuration encryption to an environment variable present on the target machine. A payload can contain at most one EnvSecret guardrail. The configured value is normalized to lowercase before the server derives the stored hash and encryption key. Use a non-empty value: empty value leaves the hash unset and the configuration unencrypted, so the guardrail is ineffective.

During payload generation:

  1. The UTF-16LE encoding of the lowercase EnvSecret value is hashed with SHA-256 and stored in the payload configuration.
  2. The server appends _ to the lowercase value, encodes that string as UTF-16LE, hashes it with SHA-256, and uses the resulting 256-bit digest as the AES key for the rest of the configuration.

During payload execution:

  1. The payload iterates over all environment variable names and values, hashing each with SHA-256.
  2. Each hash is compared against the stored hash in the configuration.
  3. If a match is found, the agent derives the same SHA-256 AES key from the matched lowercase value plus _, then decrypts the configuration and continues execution.
  4. If no match is found, execution stops immediately.

Info

Because only the hash is stored in the payload, static analysis of the binary does not reveal which environment variable is required. An analyst would need to reverse the decoding logic to determine the expected value.


How shellcodeDecodingLogic works

The shellcodeDecodingLogic option defines a sequence of byte-level operations for SHELLCODE output. During generation, the named operations transform the shellcode in reverse expression order. The generated runtime stub then applies each operation's inverse in forward expression order, restoring the original bytes before execution.

Available operations:

Operation Description
ADD(value) Generation adds value; the runtime decoder subtracts it.
SUB(value) Generation subtracts value; the runtime decoder adds it.
XOR(value) Generation and the runtime decoder XOR each byte with value.
RAW(value) Inserts a raw byte directly into the runtime decoding stub and does not transform shellcode bytes.

Operator names are case-sensitive and must be uppercase. Spaces are ignored. Values can be decimal or hexadecimal and must be between -128 and 255, inclusive; for example, 111 and 0x6F represent the same byte value.

Example 1 - simple multi-step encoding:

ADD(0x11) XOR(111) SUB(0x22)

During generation, the shellcode is transformed from the last expression to the first:

  1. Subtract 0x22 from each byte.
  2. XOR each byte with 111.
  3. Add 0x11 to each byte.

At runtime, the decoder follows the expression from left to right using inverse operations:

  1. Subtract 0x11 from each byte.
  2. XOR each byte with 111.
  3. Add 0x22 to each byte.

Example 2 - with raw byte insertion:

ADD(0x11) XOR(111) RAW(0x90) RAW(0x90) SUB(0x22)

Same as above, but two raw 0x90 bytes (NOP instructions) are inserted into the runtime decoding stub between the XOR and final ADD decoder steps. These raw bytes become part of the stub's instruction stream and can be used to alter the stub's signature or alignment.

Tip

Combining multiple operations with different values produces a unique encoding per payload, making signature-based detection of the encoded shellcode significantly harder. The RAW() operation is useful for inserting junk bytes that change the decoding stub's hash without affecting the decoded shellcode.