"Every attack leaves a trace. The attacker's job is to minimize the trace. The defender's job is to detect the minimum trace. Understanding the attacker's job is a prerequisite for doing the defender's job well." -- Bejtlich, The Practice of Network Security Monitoring, Ch 1
Lecture (90 min)
10.1 Why Offense Informs Defense
Weeks 6-9 built the NSM infrastructure: Suricata, Zeek, RITA, SIEM, 5G anomaly detection, QUIC visibility gap documentation. Week 10 inverts the lens: students operate an attack chain against a sandboxed lab network and observe what that chain looks like from the defender's side.
The pedagogical goal is not to teach offensive technique. It is to build the calibration that turns NSM output from noise into signal. An analyst who has never run a beaconing C2 client cannot make good decisions about RITA's beacon-detection threshold. An analyst who has never run an nmap scan cannot interpret conn.log scan bursts correctly.
Lab 12 authorization reminder: All exercises in this chapter use an isolated Containerlab network. No external systems are touched. The exercise is authorized within the lab scope. Students must not apply these techniques outside the designated lab environment.
10.2 Network Reconnaissance from the NSM Side
Attack side: nmap -sS 10.0.1.0/24 -T4 — a SYN scan of a /24 subnet.
What this generates in NSM data:
- Zeek conn.log: 254 connection records to
10.0.1.1through10.0.1.254, each withstate=S0(SYN sent, no SYN-ACK received) orstate=SF(SYN+SYN-ACK+RST for open ports). Duration is sub-second per host. Total connection burst: ~3,000 half-open connections in under 5 seconds at T4 timing. - Suricata alerts: ET rules
ET SCAN Nmap SYN ScanandET SCAN Potential SSH Scanfire by default. The rules use rate-based thresholds (threshold type both, track by_src). - Zeek
notice.log: Zeek'sScan::Scan_Summaryscript fires for hosts that scan more thanScan::activate_delayhosts within the window.
What T4 doesn't catch: Slow scan (--T1, 1 packet per 15 seconds) defeats threshold-based detection. Decoy scan (-D RND:10) poisons source-IP attribution but does not hide the scan pattern. OS fingerprinting (-O) generates distinctive IPID and TCP option sequences that Zeek's weird.log may flag.
Implication for NSM: Threshold tuning matters. An nmap -T1 slow scan against 254 hosts over 63 minutes generates 1 connection per 15 seconds -- below most threshold rules. Detection requires statistical baseline analysis (RITA connection-count anomaly, not alert thresholds).
10.3 C2 Infrastructure Design and Beacon Detection
Attack side: Metasploit meterpreter with HTTPS beacon, sleep interval 60s, jitter 30%.
What jitter does to RITA: RITA's beaconing detection scores connections by their inter-arrival-time regularity. A 60-second beacon with 0% jitter produces intervals of exactly 60 seconds -- RITA scores this as high-confidence beaconing. A 30% jitter produces intervals ranging from 42 to 78 seconds -- the coefficient of variation is ~17%, which RITA's default threshold (skew score + madm score) detects less reliably.
The jitter > 25% rule: Red team doctrine treats 25% jitter as the approximate threshold below which RITA reliably detects beaconing, and above which detection is inconsistent. This is empirical; the exact threshold depends on RITA's scoring parameters, but 25-35% is the range where the detection boundary lies.
Domain fronting: The meterpreter payload is configured with a legitimate CDN domain (e.g., a major cloud provider's CDN) as the SNI/Host header, while the actual destination is the C2 server IP behind the same CDN. Zeek's ssl.log shows server_name = legitimate-cdn.com. The C2 domain never appears in NSM logs.
NSM detection for domain fronting:
- Mismatch between SNI and CN:
ssl.logserver_namevs.ssl.logsubject-- if the certificate subject doesn't match the SNI, the connection is suspect. Zeek'sssl_certificate_expiredandssl_unknown_issuernotices fire for self-signed certs but not for legitimate CDN certificates. - JA3 hash: Meterpreter's embedded TLS library has a distinctive JA3 hash. If the JA3 appears for a connection to a CDN that normally serves browser traffic, the fingerprint mismatch is a hunt trigger.
- Byte-count ratio: C2 beacons typically have very small request bodies and small response bodies (keepalive + task delivery). An HTTPS session to a CDN with consistently sub-1KB request/response pairs is anomalous vs. normal CDN traffic.
10.4 Lateral Movement Signatures in Zeek
SMB traversal -- Zeek smb_files.log:
# Identify hosts writing executable files over SMB
zeek-cut ts id.orig_h id.resp_h action name < smb_files.log \
| awk '$4 == "SMB::FILE_OPEN" && $5 ~ /\.exe$|\.dll$|\.bat$/' \
| sort -k2
Lateral movement via PsExec, WMI remote exec, or CobaltStrike jump psexec generates SMB file-write records in smb_files.log for the service binary being staged to ADMIN$ or C$.
WinRM -- Zeek dce_rpc.log:
# WinRM over HTTP(S) port 5985/5986 -- look for DCE/RPC calls
zeek-cut ts id.orig_h id.resp_h endpoint operation < dce_rpc.log \
| grep -i "WS-Management\|winrm\|Execute"
Pass-the-Hash vs. Kerberoasting:
| Technique | Network signature | Zeek log |
|---|---|---|
| Pass-the-Hash (NTLM) | NTLM Type 1/2/3 exchange; no Kerberos ticket | ntlm.log (NTLMSSP auth to SMB/WinRM/HTTP) |
| Overpass-the-Hash (PTH → Kerberos) | Kerberos AS-REQ with RC4 encryption type (etype 23) | kerberos.log: request_type=AS, cipher=rc4-hmac |
| Kerberoasting | Kerberos TGS-REQ for service tickets; RC4 etype 23 or AES | kerberos.log: request_type=TGS, high frequency of service ticket requests |
Zeek Kerberos anomaly detection:
# Kerberoasting detection: many TGS requests from one source in short window
event zeek_init()
{
SumStats::create([$name="kerberoasting",
$epoch=5mins,
$reducers=set(SumStats::SUM),
$threshold=30.0,
$threshold_crossed(key: SumStats::Key, result: SumStats::Result) = {
NOTICE([$note=NetSec::Kerberoasting_Activity,
$msg=fmt("Kerberoasting: %s made %d TGS requests in 5 min",
key$host, result$sum)]);
}]);
}
event kerberos_request(c: connection, msg: KRB::KDC_Request) &priority=5
{
if ( msg$msg_type == KRB::AS_REQ || msg$msg_type == KRB::TGS_REQ )
SumStats::observe("kerberoasting", [$host=c$id$orig_h], [$num=1]);
}
10.5 Exfiltration over DNS
Attack side: iodine DNS tunnel -- encodes arbitrary data in DNS query labels; decodes server responses as data.
What this generates in Zeek dns.log:
# High-entropy subdomain labels: length >30 chars, high character diversity
zeek-cut ts id.orig_h query qtype_name < dns.log \
| awk 'length($3) > 30' | head -20
Entropy-based detection:
import math
def label_entropy(label: str) -> float:
if not label:
return 0.0
freq = {}
for c in label:
freq[c] = freq.get(c, 0) + 1
probs = [f / len(label) for f in freq.values()]
return -sum(p * math.log2(p) for p in probs)
# iodine labels typically have entropy > 3.5 bits/char
# Normal domain labels average 2.5-3.2 bits/char
ENTROPY_THRESHOLD = 3.5
RITA DNS tunneling detection:
rita show-exploded-dns hunt_dataset --long-hostnames
RITA flags FQDNs where individual subdomain labels exceed length thresholds, combined with large TXT response sizes. The iodine default configuration uses TXT records for downlink data, generating TXT responses of 200+ bytes -- anomalous vs. legitimate SPF/DKIM TXT records.
10.6 Evasion Technique Catalog
| Technique | What it evades | What it doesn't evade | NSM gap |
|---|---|---|---|
| QUIC/HTTP3 for C2 (Ch 9) | JA3, HTTP-level detection, URL logging | Flow metadata, SNI (for now) | QUIC visibility gap |
| Certificate pinning | JA3 mismatch detection | Flow metadata, byte-count analysis | TLS inspection bypass |
| Encrypted SNI (ECH) | SNI-based blocking and alerting | Flow metadata | ECH adoption is partial as of 2026 |
| Jitter > 25% | RITA beacon scoring | Long-session detection, byte-count anomaly | Threshold calibration |
| Domain fronting | C2 domain in logs | JA3 mismatch, byte-count ratio anomaly | CDN traffic analysis |
| Slow scan (T1) | Threshold-based scan alerts | Statistical baseline anomaly over days | Baseline window |
| Process-hollowing (endpoint) | Network-layer detection (no new process) | Endpoint telemetry (EDR) | Network-only NSM blind spot |
The defense implication: No single NSM data type closes all evasion paths. The defense-in-depth model requires: (a) network flow metadata for long-session and byte-count analysis; (b) DNS log analysis for tunneling and exfiltration; (c) TLS metadata for JA3 and SNI-based detection; (d) endpoint telemetry (EDR) for evasions that are network-invisible.
Architecture Comparison Sidebar: NSM Detection Coverage by Attack Phase
| Attack phase | Suricata (signature) | Zeek (log analytics) | RITA (statistical) | Endpoint (EDR) |
|---|---|---|---|---|
| Reconnaissance (nmap) | High (ET SCAN rules) | Medium (notice.log scan) | Low (threshold-based) | None |
| Initial access (exploit) | High (ET EXPLOIT rules) | Medium (protocol anomaly) | None | High |
| C2 (HTTPS beacon, low jitter) | Medium (JA3, byte ratio) | Medium (ssl.log analysis) | High (beacon score) | High |
| C2 (QUIC, jitter >25%) | Low (QUIC SNI only) | Low (conn.log flow only) | Medium (flow metadata) | High |
| Lateral movement (SMB) | Medium (ET SMB rules) | High (smb_files.log) | Low | High |
| Exfiltration (DNS tunnel) | Medium (size/rate rules) | High (entropy analysis) | High (RITA DNS) | Medium |
| Exfiltration (QUIC/ECH) | Very low | Very low | Medium (flow size) | High |
Reading the table: Network-only NSM has high coverage for conventional reconnaissance and SMB lateral movement, medium coverage for C2, and very low coverage for QUIC + ECH exfiltration. The gaps point to where endpoint telemetry integration is not optional but mandatory for a Belt-5 NSM posture.
Reflection Prompts
- RITA uses coefficient of variation (CoV) and median absolute deviation (madm) to score beaconing candidates. Explain why madm is more robust than standard deviation for beacon interval analysis when an attacker uses jitter. What distribution of interval times does jitter produce, and why does that distribution break standard deviation as a measure of regularity?
- The Kerberoasting detection Zeek script triggers on 30 TGS requests in 5 minutes from one host. A legitimate service account (a backup agent, a monitoring system) might generate 50+ Kerberos TGS requests per 5-minute window during normal operation. How would you tune the detection to reduce false positives while preserving detection of actual Kerberoasting activity?
- The evasion catalog shows that process-hollowing leaves no network-layer trace. A defender using only Zeek and Suricata would miss it entirely. What is the minimum endpoint telemetry integration that would detect process-hollowing, and what network-side indicator (if any) typically co-occurs with process-hollowing-based C2?