Real-time C2 beacon detection tool for Debian-based Linux. Captures live network traffic, detects beaconing patterns (jitter, entropy, frequency), enriches destinations via GreyNoise and offline threat feeds, and serves a dark-themed dashboard with WebSocket live updates.
| Requirement | Details |
|---|---|
| OS | Debian, Ubuntu, Linux Mint, Kali Linux, Parrot OS |
| Python | 3.9+ |
| Privileges | root or CAP_NET_RAW for live pcap |
| Optional | GreyNoise Community API key (free at greynoise.io) |
Python packages: scapy flask flask-sock requests
System packages: libpcap-dev libcap2-bin (installed by install.sh)
git clone https://github.com/Ob1ppO/c2-hunter.git c2-hunter
cd c2-hunter
sudo bash install.shThe installer will:
- Install system and Python dependencies
- Download Feodo Tracker and abuse.ch SSLBL feeds into
feeds/ - Set
CAP_NET_RAWonpython3(allows capture without full root) - Create
/usr/local/bin/c2hunterwrapper - Install and configure
c2hunter.servicesystemd unit - Prompt for your GreyNoise API key (can be added later)
# Basic — capture on auto-detected interface
sudo c2hunter
# Specify interface
sudo c2hunter -i eth0
# With GreyNoise API key
sudo c2hunter -i eth0 --api-key YOUR_KEY_HERE
# All traffic (not just from private IPs)
sudo c2hunter -i eth0 --all-traffic
# Custom database and feeds directory
sudo c2hunter -i eth0 --db /var/lib/c2hunter/c2hunter.db --feeds /etc/c2hunter/feeds
# Verbose debug logging
sudo c2hunter -i eth0 --log-level DEBUGOpen the dashboard: http://localhost:5001
| Flag | Default | Description |
|---|---|---|
-i, --interface |
any |
Network interface to capture on |
--port |
5001 |
Dashboard HTTP/WebSocket port |
--db |
c2hunter.db |
SQLite database path |
--feeds |
feeds/ |
Threat feeds directory |
--api-key |
env GREYNOISE_API_KEY |
GreyNoise Community API key |
--all-traffic |
off | Include traffic from public source IPs |
--score-threshold |
65 |
Minimum beacon score to flag |
--log-level |
INFO |
DEBUG / INFO / WARNING / ERROR |
- Register for a free Community account at greynoise.io
- Copy your API key from the dashboard
Option A — Environment variable (recommended for systemd):
sudo nano /etc/c2hunter.conf
# Set: GREYNOISE_API_KEY=your_key_here
sudo systemctl restart c2hunterOption B — CLI flag:
sudo c2hunter -i eth0 --api-key your_key_hereOption C — Shell export:
export GREYNOISE_API_KEY=your_key_here
sudo -E c2hunter -i eth0Without a key, enrichment falls back to offline threat feeds (Feodo, SSLBL).
# Start
sudo systemctl start c2hunter
# Enable on boot
sudo systemctl enable c2hunter
# Status
sudo systemctl status c2hunter
# Live logs
journalctl -u c2hunter -f
# Restart (e.g. after config change)
sudo systemctl restart c2hunter
# Stop
sudo systemctl stop c2hunterThe service file is at /etc/systemd/system/c2hunter.service.
To change the interface or API key, edit /etc/c2hunter.conf and restart.
Feeds should be refreshed weekly. A helper script is included:
sudo bash update-feeds.shOr set up a weekly cron:
sudo crontab -e
# Add:
0 3 * * 1 /path/to/c2-hunter/update-feeds.sh >> /var/log/c2hunter-feeds.log 2>&1Feed sources:
| Feed | URL | Contents |
|---|---|---|
| Feodo Tracker | feodotracker.abuse.ch | Botnet C2 IPs (Emotet, TrickBot, etc.) |
| abuse.ch SSLBL | sslbl.abuse.ch | Malicious SSL cert IPs |
| Local blocklist | feeds/blocklist.txt |
One IP per line, add your own |
Each (src_ip, dst_ip, dst_port) session is scored 0–100 using a rolling 1-hour window.
A minimum of 5 connections is required before scoring begins.
| Component | Max Points | Description |
|---|---|---|
| Jitter / CV | 40 | Coefficient of Variation of inter-arrival intervals. CV < 3% = 40 pts. Real C2 beacons are extremely regular. |
| Autocorrelation (lag-1) | 20 | Lag-1 autocorrelation of intervals. High = clock-driven regularity. |
| Connection count | 20 | More samples = higher confidence. |
| Payload entropy | 15 | Shannon entropy 5.2–7.5 bits with low variance → likely encrypted C2. |
| Payload size consistency | 10 | Fixed-size frames are a strong C2 indicator. |
Alert thresholds:
| Score | Level | Meaning |
|---|---|---|
| 85–100 | Critical | High-confidence C2 beacon, immediate triage recommended |
| 65–84 | High | Strong beaconing pattern, investigate |
| 40–64 | Medium | Possible periodic traffic, monitor |
| 20–39 | Low | Weak signal, logged but not alerted |
| 0–19 | — | Not flagged |
| Page | Description |
|---|---|
| Overview | KPI cards, 2-hour traffic timeline, live alert feed, live flow log |
| Beacon Analysis | All flagged sessions with score rings, jitter, interval analysis. Resolve/suppress per session. |
| IP Reputation | GreyNoise + feed enrichment table. Classification, threat score, tags, noise flag. |
| IR Correlation | Source hosts grouped with all their beacon sessions and threat intel. Risk levels. |
| Flow Logs | Raw flow table. Entropy highlighted. Destination reputation inline. |
The dashboard connects via WebSocket (ws://localhost:5001/ws) for live updates and
falls back to polling REST endpoints every 10–60 seconds.
The dashboard renders a dark-themed SOC console with live WebSocket updates.
All screenshots below are rendered from the real dashboard/index.html (the
actual UI shipped with the tool). The traffic data shown is seeded sample
data — used for illustration, since capturing real C2 traffic requires a live
daemon on an authorized network. The UI layout, scoring, charts and enrichment
are all the genuine in-repo code.
When you run c2hunter against real traffic, you get the same views populated
with your actual flows, beacons and alerts.
KPI cards, 2-hour traffic timeline, beacon score distribution, live alert feed and flow log.
All flagged (src → dst:port) sessions with score rings, jitter, interval stats, and Resolve / Suppress / Analyze actions.
Expanded beacon detail — mean interval, jitter (CV), std dev, sample count, plus interval-history and payload-entropy micro-charts.
GreyNoise + offline-feed enrichment: classification, threat score, org, country, tags, noise flag.
Source hosts grouped with all their beacon sessions and threat intel, with risk-level indicators.
Manual, analyst-confirmed blocking with a dry-run command preview. A red Block button on every beacon, correlation and reputation row opens a modal that shows the exact command that would run and requires an explicit confirmation checkbox before execution. The sidebar badge shows the configured backend and dry-run state.
See RUNBOOK.md for why enforcement is opt-in and kept separate from detection.
The enforcement surface was hardened against injection and abuse:
- No command injection — every backend (
iptables,nftables,dnsmasq-sinkhole,webhook) runs withshell=False, argv lists, and timeouts. IPs are canonicalised viaipaddress(loopback/multicast/unspecified/link-local and RFC1918 rejected unlessallow_private=True). Domains are IDNA-encoded and matched against a strict regex (no/, whitespace, or shell metachars), so sinkhole linesaddress=/<domain>/0.0.0.0cannot inject file content. - No SQL injection — all database access uses parameterized
?placeholders. - CSRF + bearer-token auth on enforcement POSTs — same-origin
Origin/Refererrequired for browser requests; programmatic clients needAuthorization: Bearer $C2HUNTER_API_TOKEN(constant-time compare) when a token is configured. See RUNBOOK.md. - XSS hardening — dashboard
esc()is used for HTML text context; a separatejsq()(JSON-stringify + HTML-escape) handles any value interpolated into inline event handlers, closing the HTML/JS dual-context gap that plain single-quote escaping cannot fix. - Sinkhole write race — a dedicated
sinkhole_lockserialises the read-modify-write so concurrentblock_domaincalls cannot lose entries. - No secret logging — the webhook bearer token is sent in the request only, never written to logs, DB, or command argv.
Run pytest -q to execute the security-focused test suite.
Raw flow table with Shannon entropy color-coded and inline destination reputation.
When C2 Hunter flags traffic and the suspicion is confirmed, follow the step-by-step playbook in RUNBOOK.md:
- Triage criteria (what makes a beacon "confirmed")
- Immediate containment: network vs. host isolation
- Evidence preservation (memory, disk, network capture, the c2hunter DB)
- Investigation: process correlation via Sysmon, persistence, lateral movement
- MITRE ATT&CK mapping for common C2 behaviours
- CLI triage queries against the SQLite database
- False-positive handling (Suppress / allowlisting / threshold tuning)
- Discussion: should C2 Hunter auto-block IPs? (short answer: no — detection and enforcement are kept separate; recommended patterns included)
Network interface
│ (Scapy pcap / /proc/net/tcp fallback)
▼
CaptureEngine capture.py
│ FlowRecord
▼
BeaconDetector detector.py
│ alert_callback
├──────────────────────────────┐
▼ ▼
Database (SQLite) EnrichmentEngine database.py / enrichment.py
│ │
└──────┬─────────────┘
▼
C2Hunter daemon daemon.py
│
Flask + flask-sock
│
Dashboard (port 5001)
Modules:
capture.py— Scapysniff()with BPF filter;/proc/net/tcpfallback; Shannon entropy per packet; 10s flow timeoutdetector.py— Rolling 1h window per session; jitter/CV, autocorrelation, entropy, size consistency scoringenrichment.py— 4-tier lookup: LRU cache → SQLite (24h TTL) → offline feeds → GreyNoise API; 0.2s rate limitdatabase.py— SQLite WAL mode; tables:flow_logs,beacon_sessions,alerts,ip_reputation,hostnamesdaemon.py— Coordinator; Flask REST API + WebSocket broadcast; ANSI terminal alerts
# System packages
sudo apt-get install python3 python3-pip libpcap-dev libcap2-bin
# Python packages
pip3 install scapy flask flask-sock requests
# Download feeds
mkdir -p feeds
curl -o feeds/feodo.json https://feodotracker.abuse.ch/downloads/ipblocklist.json
curl -o feeds/sslbl.csv https://sslbl.abuse.ch/blacklist/sslipblacklist.csv
# Run
sudo python3 -m c2hunter.daemon -i eth0 --api-key YOUR_KEY"Operation not permitted" when capturing:
sudo setcap cap_net_raw+eip $(which python3)
# or just run with sudo"No module named scapy":
pip3 install --break-system-packages scapy flask flask-sock requestsDashboard not loading:
Make sure the process started without errors (journalctl -u c2hunter -n 50), then open http://localhost:5001.
GreyNoise returns 401:
Check your API key in /etc/c2hunter.conf or the GREYNOISE_API_KEY env var.
No flows captured (only /proc fallback):
Either Scapy isn't installed, or the process lacks CAP_NET_RAW. Run sudo bash install.sh again to fix capabilities.
This tool is intended for:
- Monitoring networks you own or have explicit written authorization to monitor
- Cybersecurity research, education, and CTF environments
- Incident response on your own infrastructure
Unauthorized network monitoring is illegal in most jurisdictions.
Use responsibly. For educational and defensive purposes only.
MIT — use freely, modify, share.




