Implanted code has to reach its operator — to pull tasking and push results. That channel is command-and-control, and it leaves a shape in the traffic even when every packet is encrypted. You don't need a signature; you need the two things malware can't fully hide: it calls back on a rhythm, and when it hides data in DNS, the names go strange.
A good C2 channel blends into normal traffic: HTTPS to a plausible host, or DNS that every network allows out. Content inspection loses here — it's encrypted, or it's a legal DNS query. So defenders stop reading packets and start measuring behaviour across many of them.
Sample telemetry from one host, several destinations. Pick a detector and run it: benign talkers should come back clear, the C2 channel should stand out on the metric — not on anything you could read in a single packet.
Neither detector needs packet contents — only connection records and DNS logs, which Zeek produces by default and osquery can supplement with process ownership.
# beaconing — group a destination's connections, measure rhythm zeek: conn.log # ts, id.resp_h, duration group by resp_h → inter-arrival deltas → cv = stdev/mean # dns tunneling — profile each parent domain zeek: dns.log # query, rcode group by parent → label-len, uniq-subs, nxdomain%
proc_key's connections to one destination and scores the regularity of the gaps.rules/params.json — tune CV and entropy cutoffs to your own baseline instead of a vendor default.This is where C2 detection earns its keep. NTP, software update checks, telemetry, certificate OCSP, a mail client polling — all call home on a rhythm, and plenty of CDNs answer long random-looking names. A naive regularity rule drowns you in them.
Next: Lab 5 — memory forensics: finding what a disk scan can't, in the one place the implant must become real.