C2 Beaconing Detection
How to detect C2 beaconing without ML — interval regularity, jitter analysis, and JA3 fingerprints over Zeek logs, with an SPL analytic and egress hardening.
C2 beaconing detection is a statistics problem, not a signature problem. An implant has to periodically check in with its command-and-control server to receive instructions, and that periodicity is a fingerprint even when the traffic is fully encrypted. You detect it by measuring the regularity of connections to each destination: low jitter, many check-ins, consistent small payloads. No machine learning required — just the right analytic over your network logs. This guide ships it.
Beaconing maps to MITRE ATT&CK T1071.001 — Application Layer Protocol: Web Protocols and T1573 — Encrypted Channel. It is the network counterpart to DNS tunneling — both are covert channels you catch by behavior, not content.
What is C2 beaconing?
After an attacker plants an implant (a Cobalt Strike beacon, a custom RAT), the implant cannot just sit and wait — it has to reach out to the command server on a schedule to fetch new instructions and return results. That heartbeat is “beaconing.” The content is usually encrypted and the payloads small, but the pattern — the same host contacting the same destination at a roughly regular cadence, over and over — is what gives it away.
Attackers know this and add jitter (interval randomization) and randomize payload sizes to blur the pattern. The defensive answer is to look at the distribution over many samples: jittered beacons still cluster around a central interval far more tightly than genuine human or application traffic does.
What are the signals of beaconing?
| Signal | Beaconing | Normal traffic |
|---|---|---|
| Connection-interval variance | Low (tight cluster, even with jitter) | High and irregular |
| Connection count to one dest | Many, over a long window | Bursty, then idle |
| Payload size consistency | Small and uniform check-ins | Variable |
| Connection duration | Often short, repeated | Mixed |
| TLS fingerprint (JA3) | May match a known C2 client | Diverse, browser-like |
No single signal is conclusive — a software updater also polls regularly. The detection is the combination, especially low interval variance plus a long observation window plus small uniform payloads to a destination with no business reason.
How to detect C2 beaconing
The analytic measures interval regularity per source-destination pair over Zeek connection logs. Low variance plus a high connection count is the beacon.
index=zeek sourcetype=zeek:conn
| sort 0 id.orig_h id.resp_h ts
| streamstats current=f last(ts) AS prev_ts by id.orig_h, id.resp_h
| eval interval = ts - prev_ts
| stats count AS conns, avg(interval) AS mean_int, stdev(interval) AS jitter,
avg(orig_bytes) AS avg_bytes by id.orig_h, id.resp_h
| eval cov = jitter / mean_int
| where conns >= 50 AND cov < 0.15 AND mean_int > 5
| sort cov The coefficient of variation (cov = jitter ÷ mean interval) is the key score — a low
value means tightly regular connections. Combine it with a high connection count and small
average bytes, and you have a beacon. Add JA3/JA3S fingerprint matching to flag known C2
TLS clients outright.
What false positives will you actually see?
Almost everything in a modern estate beacons. That is the central difficulty, and the candidate list is worth knowing before you run the analytic and conclude your network is full of implants.
| Source | Why it beacons | Handling |
|---|---|---|
| EDR and AV agents | Heartbeat to the management console | Allowlist the destination; alert if it stops |
| Software updaters | Poll for new versions on a timer | Allowlist by destination and process |
| Monitoring and telemetry agents | Metrics on a fixed interval | Allowlist; these are the tightest intervals you own |
| NTP | Time sync, extremely regular | Allowlist; should only reach your NTP servers |
| Certificate revocation checks | OCSP and CRL fetches | Allowlist the CA endpoints |
| Chat and collaboration clients | Long-poll and presence | Allowlist, and note the caveat below |
| IoT and building systems | Cloud check-ins, often very regular | Inventory these; they are frequently unmanaged |
Note that your EDR agent is the most beacon-like thing on the network — regular interval, low jitter, small uniform payloads, single destination. It scores near the top of any honest analytic. That is a useful sanity check when you first run it: if your security agent does not appear high in the results, the analytic is not working.
Two disciplines make this manageable:
- Allowlist by destination and process together. “Ignore traffic to the updater domain” is fine; “ignore regular traffic” removes the detection. And a process allowlist matters because malware naming itself after your updater is not a novel idea.
- Alert when an allowlisted beacon stops. Your EDR heartbeat going silent on a host is a strong tamper signal, and you get it free from the same data you built the allowlist with. It converts a suppression list into a second detection.
Why JA3 is not the tool it was
TLS fingerprinting is in this guide’s key takeaways and needs a currency note, because the recommendation has shifted.
JA3 fingerprints have become unreliable for browser traffic. Chromium-based browsers now randomise TLS extension order, which changes the JA3 hash between connections from the same client. A fingerprint that varies is not a fingerprint, and JA3-based allowlists and blocklists built before that change silently degraded.
JA4 and the wider JA4+ suite are the successors, designed to be resilient to that randomisation by normalising the inputs before hashing, and covering more than the client hello. If you are building TLS fingerprinting now, build it on JA4; if you have JA3 rules deployed, they are not worthless and you should know they are noisier than the day they were written.
And malleable profiles blunt both. Mature C2 frameworks let the operator customise their traffic indicators — the TLS stack presented, HTTP headers, URI patterns, and payload encoding. Matching a default profile catches operators who did not change the defaults, which is a real and declining population. Treat a fingerprint hit as strong enrichment on a candidate the statistical analytic already surfaced, never as the primary detection.
What defeats interval analysis?
The analytic above is good and it has three specific blind spots. Knowing them keeps your coverage claim honest.
A very long sleep starves the statistics. An implant checking in once every eight hours
produces three samples a day. The conns >= 50 condition will not be met for weeks, and by then
your log retention may have rolled. The counter is not a better statistic — it is destination
rarity: a host contacting a destination that no other host in the estate has ever contacted, even
a handful of times, is worth review regardless of timing. That analytic works on three samples,
which is exactly where the timing one fails.
Wide or non-uniform jitter flattens the distribution. An operator sampling sleep from a broad range, rather than adding a modest percentage, raises the coefficient of variation past any sensible threshold. Some frameworks also vary the interval by time of day to imitate working hours. Longer observation windows help; a wide enough distribution genuinely defeats interval analysis, at the cost of a much less responsive implant.
A single long-lived connection has no interval at all. C2 over a websocket or a persistently held connection never disconnects, so there are no inter-connection gaps to measure. The signal inverts: alert on unusually long connection duration to a destination, which Zeek’s connection log gives you directly. This is a separate analytic and it is cheap — run both, because the techniques are mutually exclusive and so are the detections.
Encrypted Client Hello reduces destination visibility. As ECH deployment grows, the server name in a TLS handshake becomes unavailable to network monitoring, which weakens destination-based enrichment. Connection metadata — who talked to which IP, how often, how much — survives, which is another reason to keep the statistical analytic as the primary detection rather than anything content-derived.
C2 over legitimate services defeats destination reputation
The enrichment step above assumes an attacker’s infrastructure looks suspicious. Increasingly it does not, because it is not theirs.
Command and control routed through mainstream collaboration platforms — chat services, code hosting, cloud storage, document platforms — arrives at a destination that is well-categorised, highly reputable, TLS-protected, and almost certainly already allowlisted in your proxy. Domain reputation, newly-registered-domain blocking, and threat intelligence all return “clean,” correctly.
What still works:
- Which hosts should talk to that service at all? A developer workstation reaching a code platform is expected. A domain controller, a database server, or a print server doing so is not. Server-segment egress is where this detection is cheap and decisive, because servers have narrow, well-defined outbound needs.
- Beacon-like regularity to a legitimate service. A human using a chat client produces bursty, irregular traffic. An implant polling one produces the same tight interval distribution it would anywhere else. The statistical analytic still works — you simply cannot let destination reputation veto its findings.
- Which application is making the connection. Endpoint telemetry showing an unexpected process connecting to a collaboration platform is a strong signal that network data alone cannot provide.
- Volume and direction anomalies. Sustained upload to a cloud storage service from a host that has never used it.
The general lesson: destination reputation is enrichment, not adjudication. A detection design that filters candidates by destination reputation before scoring will systematically miss the C2 that uses infrastructure you already trust — which is the direction the technique has been moving for years.
How do you respond to a confirmed beacon?
- Identify the process, not just the host. Network data gives you an IP; endpoint telemetry gives you the executable and its parent chain, which is what identifies the implant and how it arrived.
- Find every other host contacting the same destination, before doing anything the operator would notice. The proxy and connection logs already contain the full scope, and this is the cheapest scoping answer of the whole incident.
- Reconstruct the timeline back to first contact. The first beacon approximates initial access, and it bounds everything else you need to investigate.
- Sinkhole rather than block, if you can. Redirecting to infrastructure you control preserves visibility and reveals hosts you have not identified yet. A firewall block ends both the C2 and your view of it, and it tells the operator immediately.
- Estimate what was moved. Connection logs carry byte counts in both directions. Large or sustained outbound volume changes this from an intrusion into a data-loss incident, and that determination drives obligations rather than just remediation.
- Look for the second channel. Competent operators establish a backup with a different protocol and a longer sleep, specifically to survive the removal of the first. Finding one beacon and stopping is how intrusions resume a fortnight later.
- Preserve the network logs. They are frequently the only record of the C2 traffic, and their retention is usually shorter than the investigation.
Step 6 is the one that determines whether the response holds. The beacon you detected is by definition the one the operator was least careful about, and a slow secondary channel sits below every threshold in this guide by design.
How to test your beaconing detection
In an isolated lab on infrastructure you own:
- Run a benign beaconing simulator (a script polling a lab server on a fixed interval) and confirm the analytic scores it.
- Add jitter to the simulator and confirm the distribution-based score still catches it.
- Replay normal traffic and a software updater and confirm they rank below the threshold or are enriched out.
- Validate JA3 matching against a known test fingerprint.
How to defend against C2
- Proxy and log all outbound so beaconing has a record to analyze.
- Threat-intel on destinations to flag known C2 infrastructure.
- Hunt periodically for low-and-slow beacons that sit below real-time thresholds, using destination rarity rather than timing — the analytic that works on three samples is a different one from the analytic that needs fifty.
- Tighten server egress first. Servers have narrow, well-defined outbound needs, which makes a default-deny policy achievable there and turns most C2 into a blocked, logged event rather than a detection problem.
What data do you need before any of this works?
The analytic is a few lines. The data behind it is the actual project, and it is worth being explicit about the requirements because a beaconing programme built on partial data reports a clean network with unwarranted confidence.
- Connection records for all egress, with source, destination, timestamps, and byte counts in both directions. Zeek’s connection log is the reference shape; proxy logs and firewall session logs work if they carry the same fields. Byte counts matter — they are how you distinguish a check-in from an exfiltration and how you bound the data loss afterwards.
- Coverage of every egress path. A beaconing analytic over 80% of your egress finds beacons on 80% of your egress, and reports nothing about the rest. Guest networks, cloud workloads, VPN split-tunnelling, and remote workers not routed through the corporate path are the usual gaps, and they are also where the least-managed endpoints live.
- Retention long enough to see a slow beacon. A daily beacon needs weeks of data before the interval analysis has anything to work with. Connection metadata is small relative to its value; this is the log source to keep longest.
- Accurate internal-host attribution. NAT collapses many hosts into one address, and an alert you cannot attribute to a machine is an alert you cannot action. Log before the translation, or keep the translation table.
- A current asset inventory. “Which host is 10.4.22.87 and what is it for” determines whether regular traffic to a cloud endpoint is a build agent or an implant, and answering it during an investigation rather than before is where hours go.
If you are starting from nothing, collect first and analyse second. The order matters because a beaconing analytic over incomplete data does not fail loudly — it returns a short, clean list, and a short clean list is exactly what a healthy network also produces. Those two states are indistinguishable from the output, which makes coverage verification part of the detection rather than a prerequisite to it.
Common beaconing detection mistakes
- Alerting on regularity alone. Updaters poll too — enrich the destination.
- Looking at single intervals. Jitter defeats that; measure the distribution.
- Too-short a window. Beacons reveal themselves over many samples, not minutes.
- No egress logging. Without proxy/Zeek logs, there is nothing to score.
- Suppressing regularity instead of destinations. Allowlist by destination and process; suppressing “regular traffic” deletes the detection.
- Not alerting when an allowlisted beacon stops. A silent EDR heartbeat is a tamper signal you get free from the data you already collected.
- Treating a JA3 hit as the detection. Browser TLS randomisation made JA3 unstable, JA4 is the successor, and malleable profiles let an operator change the fingerprint anyway.
- Only running the interval analytic. A long sleep starves it of samples and a single long-lived connection has no intervals at all — add destination rarity and connection duration.
- Letting destination reputation veto the score. C2 over mainstream collaboration and code platforms arrives at a well-categorised, already-allowlisted domain.
- Skipping server egress. Servers have narrow, predictable outbound needs, which makes them the cheapest place to detect this and the place it is least often looked at.
- Blocking instead of sinkholing. A block ends the C2 and your visibility simultaneously, and tells the operator you found them.
- Stopping at the first beacon. The backup channel is slower and quieter by design, and it is what brings the intrusion back a fortnight later.
C2 beaconing detection checklist
- Capture connection logs (Zeek) and proxy logs for all egress.
- Score interval regularity (coefficient of variation) per source-destination pair.
- Require a high connection count over a long window plus small uniform payloads.
- Add JA3/JA3S fingerprinting to flag known C2 TLS clients.
- Enrich candidates with destination reputation (new/uncategorized domains).
- Default-deny egress; route outbound through a logged proxy.
- Block newly-registered and uncategorized domains.
- Hunt for low-and-slow beacons below real-time thresholds.
The takeaway
C2 beaconing detection is statistics over network logs: score interval regularity (low jitter) and connection count per destination, enrich with JA3 and destination reputation, and constrain egress so beacons have nowhere to go. No ML required. Continue with DNS tunneling detection, Sysmon configuration and detecting lateral movement — where the C2 operator goes next — or browse the full Detection Engineering pillar.
Training & tools referenced
Disclosure: Some links below are affiliate links. If you buy through them, darkpwn may earn a commission at no extra cost to you. We only recommend training and tools we actually use in our own lab, and affiliate links never influence editorial coverage.
- TryHackMeAuthorized labs to practice network threat detection and C2 analysisSecurity TrainingStart training
Frequently asked questions
How do you detect C2 beaconing?
Beaconing is periodic check-in traffic from an implant to its command server. Detect it statistically — without ML — by measuring the regularity of connection intervals to each destination: low variance (low jitter) in the time between connections, many connections over a long window, and small, consistent payload sizes. Add JA3/JA3S TLS fingerprints and long-connection analysis.
What is jitter in C2 beaconing?
Jitter is randomization an implant adds to its check-in interval to evade time-based detection — for example, beaconing every 60 seconds plus or minus 20%. Defenders counter it by measuring the distribution of intervals: even jittered beacons cluster around a central interval far more tightly than human or application traffic.
What tools detect beaconing?
Zeek provides the connection logs, and an analytic engine like RITA (Real Intelligence Threat Analytics) or your SIEM scores beaconing from them by interval regularity, connection count, and data-size consistency. JA3/JA3S hashing identifies known malicious TLS clients such as default Cobalt Strike profiles.
Why is beaconing hard to hide?
An implant must check in to receive commands, and that periodicity is a statistical signature even when the content is encrypted. Attackers add jitter and randomize payloads, but the long-run regularity of contacting one destination remains detectable over enough samples.