Beacon Command Behavior
An explanation on all the different command 'classes' of the agent
House-keeping commands
used to set config option or perform other tasks
helpsleep: changes Beacons sleep interval and jitter %downloads: shows downloads in progressjobs: shows running post-exploitation jobspowershell-import: imports a powershell script into Beaconspawnto: changes the sacrificial process for fork & run commandscheckin: instructs Beacon to send metadata (when using DNS)clear: clears current Beacon consolecancel: stops a downloadnote: sets a custom note about current Beaconppid: sets the parent PID for fork & run commands
API-only commands
pwd: orints Beacon's current working directory
download: transfers file from target to team
ls: list files/ directories
make_token: creates and impersonates an access token
rev2self : drops token impersonation
exit: instructs Beacon to terminate
cd: change dir
upload: transfer file from attacker's machine to the target
getuid: gets the username of the current user
steal_token: duplicates and impersonates access token fom another process
kill : terminates a target process
Inline commands
commands implemented as Beacon Object Files (BOF) which are compiled C programs that execute within the Beacon session.
- BOF and command arguments are sent down to the Beacon inside the tasking data
- Once BOF has finsihed executing, it is cleared from memory.
- Commands:
clipboard: montiors users clipboard contentjump psexec: lateral movement techniquereg: queries the registrygetsystem: elevates the Beacon session to SYSTEM privilegeskerberos_ticket_use: imports a Kerberos ticket into the Beacon sessionrunasadmin uac-cmstplua: is a UAC bypass technique
OPSEC considerations
The way BOFs are loded into memory is controlled with process-inject block in Malleable C2 profile
process-inject {
# This sets the API used to allocate BOF memory. Options are VirtualAlloc, MapViewOfFile, and HeapAlloc.
set bof_allocator "VirtualAlloc";
# This controls what happens to the memory allocation after a BOF has run.
# If true, allocation is kept but zero'd out. If false, allocation is freed (depending on bof_allocator).
# If memory is not large enough for the next BOF, it's freed and re-allocated regardless.
set bof_reuse_memory "true";
# This controls the size of the initial memory allocation. Make sure this is large
# enough to accommodate the BOFs you typically run if you want to avoid too many memory
# freeing and allocation events.
set min_alloc "8192";
# This controls the initial/resting permission of the memory allocation.
# If true, RWX is used. If false, RW is used.
# If bof_reuse_memory is true, memory is restored to this permission when a BOF has run.
set startrwx "false";
# This controls the final permission of the memory allocation prior to calling a BOFs entry point.
# If true, it's flipped to RWX.
# If false, it's flipped to RX for the BOFs code section and RW for the data section.
set userwx "false";
}
Fork & run comands
- Beacon's post-exploitation features are implemented as Windows DLLs.
- They are appended to a loader to produce shellcode package which is then injected into a target process.
- Output is then provided to Beacon over SMB named pipe
- Two subcategories of this pattern:
explicit: injects the post-ex capability into a target process that already existsspawn: starts a new process and injects the post-ex capability into it
Spawn only commands
execute-assembly: runs a .NET assembly in memorypowerpick: runs PowerShell via an unmanaged runspace
Explicit only commands
psinject: same functionality as powerpick
Commands used by both
portscankeyloggerprintscreendesktop: injects a full VNC sessionmimikatz
OPSEC considerations
These commands carry the heaviest OPSEC burden because they must inject shellcode, start a new thread, and start a new named pipe. The spawn variant must also start a new sacrificial process. As with BOFs, Malleable C2's process-injectblock can influence how the shellcode is injected.
process-inject {
# This sets the API used to allocate memory in the target process.
# Options are VirtualAllocEx and NtMapViewOfSection.
# Be aware that NtMapViewOfSection can only be used for same-arch injection.
# VirtualAllocEx will always be used for cross-arch injection.
set allocator "VirtualAllocEx";
# These options behave in a similar way as they do for BOFs.
set startrwx "false";
set userwx "false";
# This sub-block sets the APIs used to create the new thread. Multiple options are provided here
# to cover various cases, mostly cross-arch injection. The following is a breakdown of each
# option and technique:
#
# CreateThread : for the current process only.
# CreateRemoteThread : supports x64 -> x86 injection.
# NtQueueApcThread : same arch injection only.
# NtQueueApcThread-s : this is the "early bird" injection pattern (also same arch only).
# ObfSetThreadContext : same arch injection only.
# RtlCreateUserThread : supports x86 -> x64 injection but must use RWX memory.
# SetThreadContext : also supports x64 -> x86 injection.
# Beacon evaluates techniques top-to-bottom, so put your prefered techniques at the top
# and 'backup' techniques as you go down. If an edge case is not covered, injection will fail.
#
# CreateThread, CreateRemoteThread, and ObfSetThreadContext can spoof the address of another
# function using the "module!function+0x##" syntax. These threads are created in a suspended state
# and are updated to point at the shellcode before they're resumed.
# This can help avoid those memory scan triggers.
execute {
CreateThread "ntdll.dll!RtlUserThreadStart+0x2c";
NtQueueApcThread-s;
NtQueueApcThread;
SetThreadContext;
}
}
post-ex block can be used to control other elements of fork & run as well as to modify the post-ex DLLS themselves
post-ex {
# These control default process paths used by the 'spawn' variant for x64 & x86 post-ex DLLs.
# Environment variables are ok, but always use 'sysnative' and 'syswow64' instead of 'system32'.
# Override these at runtime using the spawnto command.
set spawnto_x64 "%windir%\\sysnative\\msiexec.exe";
set spawnto_x86 "%windir%\\syswow64\\msiexec.exe";
# This option tells the post-ex DLL to free the post-ex loader from memory.
set cleanup "true";
# This option changes the name of the post-ex named pipe from "postex_####".
# A comma-separated list allows Cobalt Strike to pick a random one each time.
# Each '#' will also be replaced with a random hex character.
set pipename "dotnet-diagnostic-#####, ########-####-####-####-############";
# Some post-ex DLLs (like the portscanner) create multiple threads to help it run faster.
# This option tells the DLL to spawn new threads with the specificed spoofed start address.
set thread_hint "ntdll.dll!RtlUserThreadStart+0x2c";
# This disables AMSI in powerpick, execute-assembly, and psinject, using a memory patching technique.
set amsi_disable "true";
# This sub-block can be used to replace strings in the post-ex DLL.
# Use transform-x86 for x86 DLLs.
transform-x64 {
# strrep will replace a string in any post-ex DLL. This is good for generic strings.
strrep "This program cannot be run in DOS mode." "This is totally not a PE.";
# strrepex will replace a string in a specific post-ex DLL. This is good for strings
# that only appear in specific DLLs.
#
# The valid post-ex names are: BrowserPivot, ExecuteAssembly, Hashdump, Keylogger, Mimikatz,
# NetView, PortScanner, PowerPick, Screenshot, and SSHAgent.
strrepex "PowerPick" "CLRCreateInstance failed w/hr 0x%08lx" "CLRCreateInstance failed: 0x%08lx";
strrepex "PowerPick" "Failed to get default AppDomain w/hr 0x%08lx" "Failed to get default AppDomain: 0x%08lx";
strrepex "ExecuteAssembly" "Invoke_3 on EntryPoint failed." "Unhandled exception.";
strrepex "ExecuteAssembly" "Failed to load the assembly w/hr 0x%08lx" "Failed to load the assembly: 0x%08lx";
}
}
Process execution commands
used to run arbitrary program on disk
execute: runs a program without returning outputrunas: executes program using alternate usershell: passes provided arguments via cmd.exerun: executes program and does return outputrunu: is like run but attempts to spoof its parent PIDpowershell: passes the provided arguments via powershell.exe
Service creations
commands that create a service ro run a command or beacon
elevate svc-exe: used to elevate from high-integroty to SYSTEM privsremote-exec psexec: runs an arbitrary commandjump psexec,psexec64,psexec_psh: lat mvmnt techniques
OPSEC consderations:
The service binary payload will always use rundll32 as its default spawnto. The post-ex.spawnto directive in Malleable C2 cannot be used here because environment variables, such as %windir%, are not valid in a SYSTEM context. The artifact kit provides a command called ak-settings, which allows you to set the spawnto to an explicit path instead.