Network Forensics Cheatsheet
What the wire saw. Capture commands, the Wireshark and tshark filters that matter, protocol indicators, Suricata rules, and C2 beacon detection, the packet-level reference for investigating an intrusion in network traffic. No account needed.
Network evidence is the one source the attacker cannot edit after the fact: the bytes were on the wire or they were not. Endpoint and cloud logs can be cleared, timestamps backdated, histories wiped, but a packet capture taken at the time is ground truth for what actually traversed the network, independent of any host the attacker controls. That independence is why network forensics resolves disputes the host evidence cannot: when a compromised server's logs say one thing and the PCAP says another, the PCAP wins. This is the reference for working it, capture, filter, identify, rule. Commands assume a Linux sensor with tcpdump, tshark, Zeek, and Suricata available; the filter syntax is identical in the Wireshark GUI.
The network evidence question
Three forms of network evidence, in descending fidelity and ascending retention. Full packet capture (PCAP) has everything but is expensive to keep; flow records (NetFlow/IPFIX) are cheap and long-lived but lack content; Zeek logs sit between, structured summaries of every connection. Knowing which you have determines what questions you can answer.
| Evidence | Has / lacks |
|---|---|
| Full PCAP | Every byte, including payloads. Answers "what was sent." Expensive; short retention. |
| Zeek logs | Structured per-connection records (conn, dns, http, ssl). The investigative workhorse. |
| NetFlow / IPFIX | Who talked to whom, when, how much. No content. Cheap; long retention, good for scoping. |
Capture and acquisition
Capture is volatile by definition, traffic not recorded is gone. On a sensor you capture continuously into a ring buffer; in an investigation you capture targeted and full-payload. The key flag is the snap length: capture full packets, not truncated headers, or you lose the payload that holds the evidence.
sudo tcpdump -i eth0 -s 0 -w /opt/sensor/pcap/capture-$(date +%Y%m%d-%H%M%S).pcap \
--time-stamp-precision=nano -B 4096 -Z $USER
| Flag | Why |
|---|---|
| -s 0 | Full snap length: capture entire packets including payload, not just headers. |
| -w file.pcap | Write raw packets to disk for offline analysis; do not rely on live decode. |
| -i eth0 | The capture interface; use a SPAN/TAP for a real sensor, not a host NIC. |
| ring buffer (-C / -G) | Rotate files by size or time so continuous capture does not fill the disk. |
Display filters (Wireshark / tshark)
Display filters are how you go from a million packets to the handful that matter, and fluency with them is the difference between finding the web shell in minutes and scrolling for hours. The same syntax works in the Wireshark GUI and in tshark on the command line, so learn it once. The investigative pattern is funnel-then-extract: a broad filter to find the conversation of interest, then tshark with -T fields -e to pull the specific columns (timestamps, URIs, hosts) into something you can grep, sort, and timeline. A filter mistake to avoid: filtering on a port assumes the protocol runs there, but C2 deliberately runs HTTP over 443 or DNS over odd ports, so filter on the protocol dissector, not the port number.
# Extract the web shell conversation from PCAP
tshark -r capture.pcap -Y "http.request.method==POST && http.request.uri contains thumb.php" \
-T fields -e frame.time -e http.request.uri -e http.file_data | head -20
| Filter | Finds |
|---|---|
| http.request.method=="POST" | POST requests, where uploads and web-shell commands live. |
| http.request.uri contains "..." | A specific path, e.g. a known web-shell filename. |
| dns.qry.name contains "..." | DNS queries to a suspect domain or matching a pattern. |
| tls.handshake.extensions_server_name | The SNI in TLS, the hostname even when content is encrypted. |
| ip.addr == x.x.x.x | All traffic to or from a host of interest. |
| tcp.flags.syn==1 && tcp.flags.ack==0 | Connection attempts, useful for scanning and beaconing. |
| frame.time >= "..." | Window the capture to the incident timeframe. |
Protocol indicators
Each protocol has its own tells, and what looks malicious in one is normal in another: the same large outbound transfer is routine over HTTPS to a CDN and alarming over DNS to a single resolver. Knowing the per-protocol signature is what turns a packet dump into an investigation, and the deeper skill underneath the table below is baselining, learning what each protocol normally looks like on this network so the abnormal stands out. DNS is the protocol worth watching most closely: it is allowed out almost everywhere, rarely inspected, and therefore the favorite covert channel, tunnelling data in subdomain labels or TXT records that a firewall waves straight through.
| Protocol | Malicious indicator |
|---|---|
| DNS | Tunnelling (long/high-entropy subdomains, large TXT), DGA (many NXDOMAIN), rare resolvers. |
| HTTP | Web-shell POSTs to odd paths, suspicious user agents, base64 in URIs, unexpected file uploads. |
| TLS | Self-signed or rare certificates, JA3/JA3S fingerprints of known tooling, SNI that does not match the destination. |
| SMB | Admin-share writes (lateral movement), PsExec service creation, unusual named-pipe traffic. |
| SSH | Tunnelling/port-forwarding, off-hours sessions, connections from unexpected sources. |
| SMTP | Outbound to unfamiliar relays, attachment patterns, bulk send from one internal host (BEC/exfil). |
Suricata rule writing
Suricata turns a known indicator into a standing detection, the network equivalent of a SIEM detection rule. A signature is an action, a protocol and direction, and the content that matches within a specific part of the traffic. The anatomy below is the same whether you are matching a web-shell request or a C2 callback, but the craft is in the content match: too specific and the attacker evades it by changing one byte, too loose and it fires on everything. Good rules anchor on what the attacker cannot easily change, a protocol behavior or a structural pattern, rather than a string they can trivially randomize, and every rule is scoped with flow so it only evaluates the right direction of established traffic, which cuts false positives and saves the engine work.
alert http $EXTERNAL_NET any -> $HOME_NET any ( \
msg:"ET WEB_SPECIFIC_APPS WordPress Pingback.ping SSRF Attempt"; \
flow:to_server,established; \
http.method; content:"POST"; \
http.uri; content:"/xmlrpc.php"; \
http.request_body; content:"pingback.ping"; \
content:""; \
content:""; \
distance:0; \
pcre:"/https?:\/\/(?:127\.|10\.|192\.168\.|172\.(?:1[6-9]|2[0-9]|3[01])\.)/"; \
reference:cve,2013-0235; \
reference:url,blog.sucuri.net/2014/03/more-than-162000-wordpress-sites
The header (alert http $EXTERNAL_NET any -> $HOME_NET any) sets action, protocol, and direction; flow scopes to established server-bound traffic; the http.method and http.uri sticky buffers with their content matches are the actual signature. A DNS rule follows the same shape against the query:
alert dns $HOME_NET any -> any 53 ( \
msg:"NE DNS query to malicious domain"; \
dns.query; content:"microsft-verify.com"; nocase; \
sid:5100003; \
rev:2;)
| Rule element | Purpose |
|---|---|
| action / protocol / direction | What to do (alert), on which protocol, which way the traffic flows. |
| flow | Scope to established connections and direction; cuts false matches on stray packets. |
| sticky buffer + content | http.uri, dns.query, etc., then the bytes to match within it. The signature itself. |
| sid / rev | Unique rule ID and revision, for management and tuning over time. |
C2 and beacon detection
Command-and-control is the channel an implant uses to reach its operator, and beaconing, the regular check-in, is its most detectable feature. You hunt it in connection records: many connections, same pair, regular interval, small and similar sizes. The Zeek conn.log is the natural place to look, profiling the timing between connections for one host pair.
cat conn.log | zeek-cut ts uid id.orig_h id.resp_h id.resp_p proto service duration orig_bytes resp_bytes \
| awk '$3=="10.0.3.42" && $4=="198.51.100.77"' | head -15
| Beacon trait | What to measure |
|---|---|
| Interval regularity | Time delta between connections clusters around a value (the beacon period). |
| Jitter | Randomized timing widens the cluster; modern frameworks enable it, so regularity is a floor, not a guarantee. |
| Size consistency | Check-ins are small and similar; a sudden large response is a tasking or exfil. |
| Destination rarity | A host nothing else talks to, or a domain newly seen, weights the finding. |
Flow analytics and NSM
When you do not have full PCAP, flow records still answer the scoping questions: who talked to the compromised host, how much left the network, when it started. At scale, this is the network security monitoring (NSM) discipline, sensors, Zeek, and Suricata feeding a pipeline so the evidence exists before you need it.
| Use | What it answers |
|---|---|
| Scoping with flow | Every host that talked to the known-bad IP, and the data volumes, without payload. |
| Exfil sizing | Outbound byte counts per destination; the large transfer to a rare host. |
| NSM architecture | TAP/SPAN to sensor, Zeek for logs, Suricata for signatures, retention tiered by fidelity. |
| Hunting in network data | Baseline normal per host, then hunt the deviation, new destinations, new protocols, volume spikes. |
A DMZ web server is suspected compromised. You filter the capture for POST requests to unusual paths (http.request.method==POST) and find repeated POSTs to a file that should not accept them. tshark extracts the conversation: the requests carry base64-encoded commands, the responses carry command output. That is an interactive web shell, and the request timestamps give you the activity window.
Next: pivot on the source IP across the flow records to scope what else it touched, write a Suricata rule on the web-shell URI to catch re-use, and hand the activity window to the endpoint team to correlate with host artifacts.
Quick lookup
| Question | Filter / tool |
|---|---|
| What did this host talk to? | ip.addr == x.x.x.x; or Zeek conn.log / flow records |
| Is there DNS tunnelling? | dns.qry.name length/entropy; high TXT volume; Zeek dns.log |
| Web shell on a server? | http.request.method==POST to odd paths; tshark extract conversation |
| C2 beaconing? | Zeek conn.log interval analysis per host pair; size consistency |
| What left the network? | Flow/NetFlow outbound byte counts by destination |
| Lateral movement? | SMB admin-share writes, named pipes; SSH from unexpected sources |
| Encrypted but suspicious? | TLS SNI, JA3 fingerprint, certificate anomalies |
From reading packets to running network forensics
This cheatsheet is the filter-and-rule reference. Network Detection & Forensics teaches the discipline: protocol-by-protocol analysis, Suricata rule writing, C2 and beacon detection, and the NSM architecture that captures the evidence before you need it.
Explore the course