Published

Building Resilient C2 Infrastructure - OPSEC Considerations

A deep dive into building layered, resilient C2 infrastructure with real OPSEC considerations. From redirectors and domain fronting to malleable profiles and categorized domains.

Building Resilient C2 Infrastructure: A Practical OPSEC Guide

If you’ve spent any time doing red team engagements or reading through breach disclosures, you know that C2 infrastructure is often the backbone that determines whether an op succeeds or gets burned in the first 48 hours. A sloppy C2 setup is the difference between a multi-month engagement and getting your IP blocklisted by a Palo Alto EDR before your beacon even phones home.

This post is a brain dump of how I think about building C2 infrastructure: from the philosophy behind layered redirectors, to domain selection, to the nuances of making your traffic actually look like traffic. I’ll reference the work that influenced my thinking throughout, because most of what’s considered “good practice” in this space was documented by people smarter than me.


The Mental Model: Layers of Indirection

Before touching a single command, it’s worth internalizing why layered infrastructure matters. The core idea is that your actual C2 team server (the thing you care about losing) should never be directly exposed to the target environment. Every layer you add between the implant and the server buys you time and resilience.

A typical architecture looks something like this:

[Implant] → [Redirector/CDN] → [C2 Team Server]

But in practice, mature setups add more:

[Implant] → [CDN/Domain Front] → [Apache/Nginx Redirector] → [C2 Team Server]

The foundational reference here is Raphael Mudge’s original work on Cobalt Strike malleable C2 and the Red Team Infrastructure Wiki maintained by Joe Vest and Andrew Chiles. If you haven’t read those, stop here and go read them first.


Domain Selection and Categorization

Your domains are your reputation, and this is one of the most overlooked areas of C2 OPSEC. A domain registered yesterday with a .xyz TLD that has never been crawled is going to get flagged by proxy categorization tools almost immediately. You want something aged, indexed, and sitting in a category that gives you an operational advantage.

That last part is worth expanding on. Proxy categorization isn’t just about avoiding “Uncategorized” status. Certain categories actively work in your favor. Organizations often skip TLS inspection (break and inspect) for domains categorized under Finance or Healthcare, either because they don’t want to break compliance requirements or because tools like DLP are configured to exclude sensitive verticals to avoid processing personal data. A beacon calling out to something categorized as a financial services site has a meaningfully better chance of bypassing inspection than one hitting a generic domain.

So the goal is to buy aged domains that are already established with tools like Bluecoat/Symantec WebPulse, Palo Alto URL Filtering, and Cisco Talos, and ideally ones already sitting in a high-value category. Stick to .com or .org TLDs. Anything more exotic draws unnecessary attention before a single packet is sent.

Dominic Chell’s (@domchell) post on CDNs and domain fronting is still one of the clearest explanations of why categorization matters, even if you’re not fronting through CloudFront anymore. The underlying reasoning applies regardless of your delivery mechanism.

Before an engagement, run your domains through all of these:

# Quick check for domain reputation
curl -s "https://urlfiltering.paloaltonetworks.com/query/?url=yourdomain.com"

Domain Fronting

Domain fronting deserves its own section because it’s both powerful and increasingly restricted. To understand why it works, you need to understand what happens at two different layers of an HTTPS request. The SNI (Server Name Indication) field is part of the TLS handshake and is sent in plaintext before encryption is established. It tells the server (and anyone watching the wire, aka blue team) which hostname the client is trying to reach, which is how a single IP hosting multiple domains knows which certificate to present. The HTTP Host header, on the other hand, is sent after the TLS tunnel is established and encrypted. It tells the web server or CDN which backend to actually route the request to.

Domain fronting exploits the gap between those two. The SNI says you’re going to legitimate-cdn-domain.com (something trusted and whitelisted), but the Host header inside the encrypted tunnel says to route the request to your C2. Network inspection tools that only look at SNI (which is most of them, since it’s the only plaintext signal) see totally legitimate traffic. Your beacon, from the outside, looks indistinguishable from any other user hitting that CDN.

MDSec’s post and Vincent Yiu’s (@vysecurity) writing on the topic are the good references. The TLDR of why this matters: a defender blocking your C2 IP is easy. A defender blocking all of *.cloudfront.net or *.azureedge.net is a much harder call to make.

In practice, most major CDN providers have cracked down on domain fronting. AWS banned it in 2018 and Azure followed. The technique remains viable through a few paths though:

  • Cloudflare Workers to proxy through a Worker that forwards to your server
  • Azure CDN with specific configs where some edge cases still exist
  • Fastly, worth researching per your engagement context
  • Praetorian Blog for domain fronting with Google Domains

Redirectors

Redirectors are the workhorses of your infrastructure. They sit between the target and your team server, and they do two things: forward legitimate C2 traffic to your server and return something benign (or nothing at all) for anything that doesn’t look like your implant.

Apache mod_rewrite

Apache with mod_rewrite is the classic approach, first popularized for red team use by Jeff Dimmock. His blog series on Apache redirectors at SpecterOps is mandatory reading.

First, enable the required modules:

sudo apt install apache2 -y
sudo a2enmod rewrite proxy proxy_http ssl headers

Your .htaccess or VirtualHost config does the heavy lifting. Here’s a working example that only forwards requests matching your implant’s URI profile and redirects everything else to a legitimate site:

# /etc/apache2/sites-enabled/000-default.conf
<VirtualHost *:443>
    ServerName your-domain.com
    SSLEngine on
    SSLCertificateFile      /etc/letsencrypt/live/your-domain.com/fullchain.pem
    SSLCertificateKeyFile   /etc/letsencrypt/live/your-domain.com/privkey.pem

    SSLProxyEngine On
    SSLProxyVerify none
    SSLProxyCheckPeerCN off
    SSLProxyCheckPeerName off

    RewriteEngine On
    RewriteCond %{REQUEST_URI} ^/updates/  [OR]
    RewriteCond %{REQUEST_URI} ^/api/v2/
    RewriteRule ^(.*)$ https://YOUR_TEAMSERVER_IP$1 [P,L]

    # Catch-all redirect for anything that doesn't match
    RewriteRule ^.*$ https://microsoft.com/ [L,R=302]
</VirtualHost>

The key OPSEC win here: if a blue teamer or automated scanner hits your redirector IP directly, they get a 302 to Microsoft. Nothing looks weird. Your team server never gets that request.

For automation, check out Jeff Dimmock’s cs2modrewrite tool, which generates .htaccess rules directly from a Cobalt Strike malleable C2 profile.

git clone https://github.com/threatexpress/cs2modrewrite
python3 cs2modrewrite.py -i jquery.profile -c https://YOUR_TEAMSERVER_IP -r https://microsoft.com

Nginx as a Redirector

Nginx is a solid alternative, especially if you’re comfortable with its config syntax. The logic is the same: match URIs, forward to teamserver, block everything else.

# /etc/nginx/sites-enabled/c2-redirector.conf
server {
    listen 443 ssl;
    server_name your-domain.com;

    ssl_certificate     /etc/letsencrypt/live/your-domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;

    # Only proxy matching URI patterns
    location ~* ^/(updates|api/v2)/ {
        proxy_pass https://YOUR_TEAMSERVER_IP;
        proxy_ssl_verify off;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    # Everything else gets redirected
    location / {
        return 302 https://microsoft.com/;
    }
}

C2 Frameworks

There are several solid frameworks worth knowing, depending on your engagement requirements and licensing situation.

Cobalt Strike

The industry standard for commercial red teaming. Malleable C2 profiles are its killer feature, giving you the ability to make your beacon’s traffic pattern look like literally anything. The profile reference is extensive.

A few profile fields that matter most for OPSEC:

set sleeptime "60000";         # Beacon interval in ms — slower = quieter
set jitter     "30";           # % jitter on sleep — randomizes timing
set useragent  "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36";
set http_post_header "Content-Type" "application/octet-stream";

Threatexpress maintains a solid collection of profiles worth reviewing to understand the patterns, though you should always write or modify your own for a real engagement. Using a public profile verbatim is an easy detection for the blue team.

Havoc

The open-source framework that’s gotten the most traction in the last couple of years. Written by @C5pider, it has a clean UI and solid architecture for extending with custom agents. If you’re doing research or don’t have a CS license, Havoc is a solid choice.

Sliver

BishopFox’s open-source framework. Written in Go, which makes the implants easy to cross-compile. Supports HTTP, HTTPS, DNS, and mTLS communication.


Certificates and HTTPS

Running C2 over plain HTTP in 2025 is not something you should be doing. Beyond the obvious interception risk, it’s a detection signal. Get a valid TLS certificate on your redirectors.

Let’s Encrypt via certbot is the obvious path:

sudo apt install certbot python3-certbot-apache -y
sudo certbot --apache -d your-domain.com

One OPSEC note: Let’s Encrypt certificates get logged to Certificate Transparency logs by default, which means your domains are public knowledge. Defenders actively monitor CT logs for newly issued certs on domains that aren’t in their asset inventory. You can use CT log monitoring offensively too; it’s a good way to track what infrastructure a target org is spinning up.

If you want to reduce your CT log exposure, you can use a CA that supports private issuance, or use a wildcard cert (though those still appear in CT logs). The point isn’t to avoid CT logs entirely. It’s to understand your operational exposure.


DNS C2 and DNS Considerations

DNS-based C2 is slow but it works through most firewalls, gets proxied through internal resolvers, and is often poorly monitored. dnscat2 by Ron Bowes is the classic reference implementation. Cobalt Strike’s DNS beacon and Sliver both support DNS C2 natively.

For DNS C2 to work, you need to control the authoritative DNS server for a domain. Set up your A record pointing to your team server, then configure an NS record for a subdomain pointing to a VPS you control:

; Zone file entries
ns1.c2domain.com.     A      YOUR_VPS_IP
c2.c2domain.com.      NS     ns1.c2domain.com.

Your implant then encodes data in DNS queries to [data].c2.c2domain.com, and responses come back in TXT or A records. The throughput is terrible but as a fallback or covert channel it’s solid.

Watch your DNS query volume. Generating hundreds of DNS queries per minute for a subdomain nobody has ever heard of is a detection signal. Keep your DNS beacon interval long and your query sizes near-maximum to reduce query count.


Additional OPSEC Considerations

Firewall Rules on the Team Server

Your team server should never be reachable by anything other than your redirectors. Lock it down:

# Only allow inbound C2 traffic from your redirectors
ufw default deny incoming
ufw allow from REDIRECTOR_IP_1 to any port 443
ufw allow from REDIRECTOR_IP_2 to any port 443
ufw allow from YOUR_OP_IP to any port 50050   # Cobalt Strike team server port
ufw enable

Never expose your team server to 0.0.0.0. Ever.

Operational Separation

Keep your infrastructure separated by function. Use different VPS providers and different payment methods for your redirectors vs your team server. The goal is that burning one piece of infrastructure doesn’t compromise the rest.

Use separate domains for:

  • HTTP beacons
  • DNS beacons
  • Phishing infrastructure
  • File staging/payload hosting

Blogs have been written about how infrastructure overlap is one of the primary ways APT groups get tracked and attributed. The lessons apply to red teams as well. If you reuse IPs or domains across engagements, you’re building a fingerprint.

Cloud Providers and ASN Considerations

Your redirectors should not be hosted on infrastructure with a bad ASN reputation. Some proxy tools will flag traffic originating from DigitalOcean, Vultr, or Linode based purely on the ASN being commonly associated with VPS hosting and abuse.

Options that tend to have cleaner reputations:

  • AWS EC2 is expensive but typically less flagged
  • Azure is the same story, and enterprise orgs tend to trust Azure traffic
  • Cloudflare Workers are excellent for HTTP redirectors and the free tier is generous

The tradeoff is that legitimate CDN infrastructure may scrutinize your traffic more. It’s a balance between reputation and risk.


Putting It Together: A Reference Architecture

For a typical engagement, a reasonable starting architecture looks like this:

ComponentRoleNotes
CDN/CloudflareFront-facing layerHides redirector IP, provides valid cert
Apache mod_rewrite redirectorURI filteringForwards legitimate beacon traffic only
C2 team server (Havoc/CS/Sliver)Core C2Firewalled, only accessible from redirectors
DNS VPSDNS C2 fallbackSeparate provider, separate domain
File staging serverPayload deliveryShort-lived, torn down after initial access

The exact tooling matters less than the principle: every hop adds indirection, every layer has a single purpose, and nothing talks to your team server that shouldn’t.