-- Richard Bejtlich, The Practice o">
Classroom Glossary Public page

NET-201 Week 10 -- NSM-Lite: Wireshark Deep-Dive, Suricata, and Zeek

1,205 words

"The first question in any security investigation is: what happened on the wire? The answer is always in a packet capture, if you kept one." -- Richard Bejtlich, The Practice of Network Security Monitoring (No Starch, 2013), Ch. 1


Lecture (100 min, two 50-min blocks)

10.1 Network Security Monitoring: The Discipline

Network Security Monitoring (NSM) is the collection, detection, and analysis of network data for the purpose of identifying and characterizing threats. NSM is not intrusion prevention -- it is the forensic foundation that makes post-incident investigation possible and that provides enough real-time signal to catch active threats.

Three tiers of NSM data:

  1. Full packet capture (FPC): every byte of every packet, stored as PCAP. Complete forensic record. Storage-intensive; typically stored for 24-72 hours on high-volume links, longer on lower-volume ones.
  2. Flow data: connection metadata without payload (source/destination IP, port, protocol, bytes, packets, duration). Long-term retention is practical; provides behavioral baselines. Generated by NetFlow v5/v9, IPFIX, sFlow.
  3. Protocol logs: structured records of what happened at the application layer (HTTP request logs, DNS query logs, TLS certificate logs). Zeek excels at this.

NSM answers: who talked to whom, for how long, on what port, with what application-layer behavior, at what time?

10.2 Wireshark: Deep-Dive Beyond NET-101

NET-101 introduced Wireshark. This week builds the skills required for real security analysis.

Display filter syntax (Wireshark dfilter):

# IP address filters
ip.addr == 192.168.1.10
ip.src == 10.0.0.0/8        # CIDR notation supported
ip.dst != 192.168.1.1

# Protocol filters
tcp
udp
dns
http
tls
ospf
bgp

# Field comparison
tcp.flags.syn == 1 && tcp.flags.ack == 0   # SYN only (connection initiation)
http.request.method == "GET"
dns.flags.response == 1 && dns.qry.name contains "malware"
tls.handshake.type == 1                    # ClientHello

# Combining filters
(ip.addr == 10.0.0.1) && (tcp.port == 443)
frame.len > 1400    # large frames (potential data exfiltration)

Capture filter syntax (BPF, applied at capture time -- much faster):

tcpdump -i eth0 -n "host 192.168.1.10"
tcpdump -i eth0 -n "tcp port 80 or tcp port 443"
tcpdump -i eth0 -n "not port 22"         # exclude SSH (noisy in remote capture)
tcpdump -i eth0 -n "proto ospf"

Expert mode indicators: Wireshark marks packets with severity levels: Note (cyan), Warning (yellow), Error (red). Red packets indicate checksum errors, malformed segments, or retransmissions. In a capture from a troubled network, sort by Expert Info to find the problem quickly.

Statistics tools in Wireshark:

  • Conversations (Ctrl+Alt+C): shows all IP pairs with bytes transferred; immediately reveals the "top talkers"
  • Protocol Hierarchy (Ctrl+Shift+I): breakdown of protocol distribution in the capture
  • I/O Graphs: time-series packet rate; useful for identifying traffic spikes
  • Follow TCP/TLS/UDP Stream: reassembles all packets in a session into readable text

10.3 Suricata: Signature-Based Detection

Suricata is a multi-threaded IDS/IPS/NSM engine that processes network traffic against a rule set. It can run inline (blocking mode, IPS) or passively (NFQUEUE, PCAP, or AF_PACKET for monitoring).

Suricata rule anatomy:

action protocol src_ip src_port direction dst_ip dst_port (rule_options)

# Example: detect HTTP GET to a known malware C2 domain
alert http $HOME_NET any -> $EXTERNAL_NET any (
    msg:"Malware C2 HTTP GET";
    http.method; content:"GET";
    http.host; content:"evil.example.com"; nocase;
    classtype:trojan-activity;
    sid:9000001; rev:1;
)

# Detect outbound DNS TXT query (possible DNS tunneling)
alert dns $HOME_NET any -> any 53 (
    msg:"Possible DNS Tunneling TXT Query";
    dns.query; content:"|00 10|";  # TXT record type in DNS wire format
    threshold: type both, track by_src, count 10, seconds 60;
    sid:9000002; rev:1;
)

Suricata rule options vocabulary:

Option Meaning
content:"STRING" match literal string in payload
nocase case-insensitive match
pcre:"/REGEX/i" Perl-compatible regex match
http.uri match in HTTP URI
http.host match in HTTP Host header
http.method match HTTP method
threshold: rate limiting / suppression for noisy rules
flow:established only match on established TCP sessions
classtype: categorizes the alert type
sid: unique rule identifier; 1-999999 reserved for official rules; 1000000+ for local

Running Suricata against a PCAP:

sudo suricata -c /etc/suricata/suricata.yaml \
  -r /path/to/capture.pcap \
  -l /tmp/suricata-output/

# View alerts
cat /tmp/suricata-output/fast.log
# or structured JSON:
cat /tmp/suricata-output/eve.json | jq '.[] | select(.event_type == "alert")'

Suricata Eve JSON log: all events (alerts, DNS, HTTP, TLS, flows) are logged to eve.json in structured JSON. This makes Suricata output trivially parseable by SIEM systems, ELK stack, or Python scripts.

10.4 Zeek: Protocol Analysis as Code

Zeek (formerly Bro) is a network analysis framework. Rather than matching byte patterns, Zeek dissects protocol state machines and generates structured log records. The conn.log records every connection; dns.log records every DNS transaction; http.log records every HTTP request; ssl.log records every TLS session.

Zeek log format (TSV, with header):

# conn.log sample
ts           uid        id.orig_h      id.orig_p  id.resp_h      id.resp_p  proto  service  duration  orig_bytes  resp_bytes  conn_state
1234567890.0 CiJoFa... 192.168.1.10   52341      93.184.216.34  443        tcp    ssl      0.254     1234        56789       SF

Zeek scripting (detecting long-duration connections -- possible exfiltration):

event connection_state_remove(c: connection)
{
    if (c$duration > 3600 sec && c$resp_bytes > 1000000)
    {
        print fmt("ALERT: Long connection with large transfer: %s -> %s:%d duration=%s bytes=%d",
            c$id$orig_h, c$id$resp_h, c$id$resp_p,
            c$duration, c$resp_bytes);
    }
}

Running Zeek against a PCAP:

zeek -C -r capture.pcap /opt/zeek/share/zeek/base/init-default.zeek

# View generated logs
ls -la *.log
# conn.log, dns.log, http.log, ssl.log, files.log, x509.log, ...

# Query conn.log for connections to port 443 with > 1MB transferred
zeek-cut ts id.orig_h id.resp_h resp_bytes conn_state < conn.log | \
  awk '$4 > 1000000 {print}'

Zeek vs. Suricata: complementary roles

Dimension Suricata Zeek
Detection model Signature-based (rules) Protocol-state + scripted behavioral analysis
Output Alert events + protocol logs Comprehensive protocol logs (no alerts by default)
Customization Rule authoring (low barrier) Script authoring in Zeek language (higher barrier)
Best for Known-bad detection; IDS/IPS deployment Unknown-bad investigation; behavioral baselining; forensic analysis

NSM practitioners use both: Suricata for real-time alerting; Zeek for comprehensive protocol logging and custom behavioral detections.

10.5 The NSM Corpus

The NET-201 NSM corpus ships as a directory of ~20-30 PCAP files representing named TTPs (Tactics, Techniques, and Procedures). Each file has a corresponding ground-truth answer (what is in it). Lab 8 uses this corpus to evaluate Suricata rule and Zeek script effectiveness.

Sample corpus entries:

  • corpus/arp_poisoning.pcap: ARP poisoning attack with MITM traffic capture
  • corpus/dns_tunneling.pcap: DNS queries with encoded data in FQDN labels
  • corpus/tls_cert_anomaly.pcap: TLS connection with self-signed certificate to unusual destination
  • corpus/bgp_update_anomaly.pcap: BGP UPDATE announcing a prefix not belonging to the announcing AS
  • corpus/port_scan_syn.pcap: SYN scan against a /24 subnet
  • corpus/lateral_movement_smb.pcap: SMB lateral movement with PSEXEC-style execution

Lab Preview

Lab 8 processes the NSM corpus with both Suricata and Zeek:

  • Run the full corpus through Suricata; examine false-positive and false-negative rates against ground truth
  • Author one custom Suricata rule targeting a specific TTP; test against the relevant corpus file
  • Process the DNS tunneling corpus file through Zeek; write a Zeek script that computes average FQDN label length per source; flag sources with unusually long labels (DNS tunneling signature)
  • Generate a combined alert + log report: for each corpus file, list Suricata alerts triggered + Zeek log anomalies detected

Homework

Reading (45 min): Bejtlich, The Practice of Network Security Monitoring, Ch. 1 (What Is NSM?) and Ch. 9 (NSM in Practice). These chapters provide the operational context behind why Suricata and Zeek are used together. If you have Sanders, Practical Packet Analysis: read Ch. 8 (TCP/IP Analysis in the Real World) for Wireshark technique depth.

Hands-on (60 min): Write a Suricata rule to detect ICMP tunneling (ICMP payloads larger than 64 bytes are anomalous for normal ping traffic):

alert icmp any any -> any any (
    msg:"Possible ICMP Tunneling Large Payload";
    dsize:>64;
    itype:8;      # ICMP Echo Request
    threshold: type both, track by_src, count 5, seconds 10;
    sid:9000010; rev:1;
)

Generate a test PCAP using Scapy:

from scapy.all import *
pkts = [IP(dst="8.8.8.8")/ICMP(type=8)/"A"*200 for _ in range(10)]
wrpcap("/tmp/icmp_tunnel.pcap", pkts)

Run Suricata against /tmp/icmp_tunnel.pcap with your rule; confirm the alert fires. Then explain in your notes why this rule would generate false positives in a network with legitimate network diagnostic tools.


Toolchain Diary Entry

Deepen this week: Suricata (advanced rule authoring); Zeek (log analysis + scripting)

suricata -c CONFIG -r PCAP -l OUTPUT_DIR: run Suricata in PCAP replay mode; outputs logs to OUTPUT_DIR.

jq '.[] | select(.event_type == "alert") | .alert.signature' < eve.json | sort | uniq -c: count unique alert signatures from Suricata's eve.json.

zeek -C -r PCAP SCRIPT: run Zeek on a PCAP with a specific script (-C = ignore checksum errors, common in test captures).

zeek-cut FIELD1 FIELD2 < LOG_FILE: extract specific columns from a Zeek log file.

zeekctl deploy: deploy a Zeek cluster configuration (for live capture on production networks).

suricata-update: update Suricata rule sets from ET Open, ET Pro, and other rule sources.

Wireshark: Edit -> Preferences -> Protocols -> TLS -> (Pre)-Master-Secret log filename: enable TLS decryption using SSLKEYLOGFILE session key material.


Key Terms

  • NSM: Network Security Monitoring; collection, detection, and analysis of network data to identify and characterize security threats; produces full packet capture, flow data, and protocol logs
  • Suricata: multi-threaded IDS/IPS/NSM engine; rule-based detection; outputs alerts and structured protocol logs (eve.json); supports inline (IPS) and passive (IDS) modes
  • Zeek: network analysis framework (formerly Bro); dissects protocol state machines; generates comprehensive structured logs; scripting language for behavioral detection
  • Eve JSON: Suricata's primary structured output format; all event types (alerts, DNS, HTTP, TLS, flows) in one NDJSON log; ideal for SIEM ingestion
  • Flow data: connection metadata (src/dst IP, port, protocol, bytes, duration) without payload; generated by NetFlow/IPFIX; long-term retention baseline for behavioral analysis
  • Signature-based detection: matching network traffic against known-bad patterns (byte strings, regex, protocol states); high precision on known threats; blind to novel/unknown threats
  • Behavioral detection: identifying anomalies against a baseline of normal network behavior; effective against novel threats; requires tuning to reduce false positives
  • DNS tunneling: encoding arbitrary data in DNS query FQDNs or TXT record payloads to exfiltrate data or establish covert C2 channels through DNS-permitting firewalls
  • PCAP: Packet Capture format; libpcap binary format for storing full network captures; universal input for Wireshark, Suricata, Zeek, and all NSM tools