BOOT CHAIN LAB
Lab 4 · detection engineering

Catching the call-home.

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.

01 — the idea

Two tells, both statistical

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.

beaconingThe implant checks in on a schedule. Humans browse in bursts and gaps; a beacon's inter-arrival times cluster tight around one value. Low variance over many connections to one destination is the tell — even through jitter.
DNS tunnelingData is smuggled in the names being looked up. The subdomains get long and high-entropy, the unique-name count explodes under one parent domain, and failed lookups (NXDOMAIN) spike. Normal DNS looks nothing like it.
why it survivesBoth are properties of the aggregate, not of any one packet. Encryption doesn't hide a rhythm, and a tunnel can't avoid being made of queries. You measure the distribution, not the payload.
02 — score the traffic

Find the channel

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.

03 — with your tools

C2 detection on your stack

what feeds it

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%

in the detection lab

  • R3 already flags beaconing: it buckets a proc_key's connections to one destination and scores the regularity of the gaps.
  • R4 already flags DNS tunneling: entropy and unique-subdomain volume per parent domain, with the NXDOMAIN rate.
  • Thresholds live in rules/params.json — tune CV and entropy cutoffs to your own baseline instead of a vendor default.
  • A confirmed channel becomes a Vertical case: the destination, the metric, and the window of records as evidence.
04 — the hard part

Everything legitimate beacons too

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.