pcap Tools Reference
The Wireshark suite includes several CLI tools beyond tshark that every network forensics analyst should know by reflex: mergecap for combining captures, editcap for slicing and anonymizing, capinfos for metadata, and tcpreplay for replaying traffic against your detection stack. This chapter covers each tool's forensic use cases.
You've collected 47 separate pcap files from ring buffer rotation across a 3-day incident window. You need to: merge them into a single file for timeline analysis, cut out just the 4-hour attack window to share with a vendor, anonymize source IPs before sharing, verify the time range each file covers, and replay the traffic against your detection lab to validate that your Suricata rules would have fired. Each task requires a different tool.
pcap File Format Internals
pcap File Structure (libpcap format) ═══════════════════════════════════════════════════════════════════ Global Header (24 bytes): ┌────────┬──────────┬────────────┬────────┬────────┬────────────┐ │ Magic │ Version │ Timezone │ Sig. │ Snap- │ Network │ │Number │ Maj/Min │ Offset │ Figs │ len │ (link │ │4 bytes │ 4 bytes │ 4 bytes │ 4 bytes│ 4 bytes│ type) │ └────────┴──────────┴────────────┴────────┴────────┴────────────┘ Magic Number: ├── 0xA1B2C3D4 → microsecond timestamps (standard) ├── 0xA1B23C4D → nanosecond timestamps (pcapng-style) └── Little-endian vs big-endian variants exist Network (link layer type): ├── 1 = Ethernet (most captures) ├── 105 = IEEE 802.11 (wireless raw) ├── 228 = IPv4 only (no Ethernet header) └── 101 = Raw IP (no link-layer header) Per-Packet Record (16-byte header + data): ┌───────────┬───────────┬──────────────┬──────────────┬─────────┐ │ ts_sec │ ts_usec │ incl_len │ orig_len │ data... │ │(timestamp)│(microsecs)│(bytes in file│(bytes on wire│ │ └───────────┴───────────┴──────────────┴──────────────┴─────────┘ If incl_len < orig_len → packet was truncated (snaplen was hit) Truncated packets: you see headers but not full payload tcpdump default snaplen = 262144 bytes (effectively unlimited) Older deployments may have snaplen=65535 — check with capinfos pcapng (next generation) format: ├── Supports multiple interfaces in one file ├── Supports comments on individual packets ├── Supports per-packet interface information └── Wireshark default; use -F pcap with tshark for legacy compat
capinfos — File Metadata
# Basic metadata: time range, packet count, duration
capinfos capture.pcap
# Output:
# File name: capture.pcap
# File type: Wireshark/tcpdump/... - pcap
# File encapsulation: Ethernet
# Packet size limit: file hdr: 65535 bytes
# Number of packets: 1,247,893
# File size: 847 MB
# Data size: 841 MB
# Capture duration: 3601.234 seconds
# First packet time: 2026-09-17 02:00:01.234567
# Last packet time: 2026-09-17 03:00:02.469134
# Data byte rate: 233 kBps
# Data bit rate: 1.87 Mbps
# Average packet size: 673.27 bytes
# Average packet rate: 346.5 packets/s
# Check multiple files (confirm no gaps between ring buffer files)
for f in ring/capture_*.pcap; do
echo -n "$f: "
capinfos -S "$f" 2>/dev/null | grep -E "First packet|Last packet"
done
# Check snaplen (truncated packets = evidence loss)
capinfos -s capture.pcap | grep "Packet size limit"
# If limit is 65535 and you have payloads > 65535 bytes, you may have truncation
# Machine-readable output for scripting
capinfos -T -M capture.pcap # tab-separated
capinfos -m capture.pcap # show MD5 hash of file
mergecap — Combining Captures
# Merge all ring buffer files into one chronologically sorted file
# mergecap sorts by packet timestamp — handles out-of-order files
mergecap -w /cases/CASE-2026-009/merged.pcap ring/capture_*.pcap
# Merge and convert format (pcap → pcapng for Wireshark features)
mergecap -F pcapng -w merged.pcapng ring/capture_*.pcap
# Merge from two different capture points (WAN tap + internal SPAN)
# Both captures will be in the output file; community_id links them
mergecap -w combined.pcap wan-capture.pcap internal-capture.pcap
# Verify merge: packet count should equal sum of input counts
capinfos ring/capture_*.pcap | grep "Number of packets"
capinfos /cases/CASE-2026-009/merged.pcap | grep "Number of packets"
# Check for time gaps (evidence gaps between ring buffer files)
# If last_time[file_n] != first_time[file_n+1] → gap in coverage
python3 -c "
import subprocess, re
files = sorted(__import__('glob').glob('ring/capture_*.pcap'))
for i in range(len(files)-1):
out = subprocess.check_output(['capinfos','-ae', files[i]], text=True)
last = re.search(r'Last packet time:\s+(.+)', out)
out2 = subprocess.check_output(['capinfos','-ae', files[i+1]], text=True)
first = re.search(r'First packet time:\s+(.+)', out2)
if last and first:
print(f'Between {files[i]} and {files[i+1]}:')
print(f' Last: {last.group(1).strip()}')
print(f' First: {first.group(1).strip()}')
"
editcap — Slicing and Anonymizing
# Extract a time window (attack window: 02:00 to 06:00 on 2026-09-17)
editcap -A "2026-09-17 02:00:00" -B "2026-09-17 06:00:00" \
merged.pcap attack-window.pcap
# Split a large file into 100 MB chunks (for sharing or processing)
editcap -c 0 -B 104857600 merged.pcap chunk.pcap
# Creates chunk_00001.pcap, chunk_00002.pcap, etc.
# Truncate payloads to headers only (reduce file size, protect privacy)
# Snaplen of 100 bytes keeps all headers but removes most payload
editcap -s 100 merged.pcap headers-only.pcap
# Anonymize IP addresses (consistent anonymization — same IP → same anon IP)
# Note: editcap -E scrambles bytes randomly; for consistent anonymization use tcpurify or tracewrangler
editcap -E 0.1 merged.pcap anonymized.pcap # randomly error 10% of packets (NOT useful)
# The right tool for IP anonymization is TraceWrangler (GUI) or tcpurify:
# tcpurify -o anonymized.pcap merged.pcap
# Remove duplicate packets (can occur when multiple SPAN ports capture same traffic)
editcap -d merged.pcap deduped.pcap
# Convert between formats
editcap -F pcapng merged.pcap modern.pcapng # to pcapng
editcap -F pcap modern.pcapng legacy.pcap # back to pcap
# Add fake arrival time offset (adjust for clock skew — use with caution, document!)
editcap -t 3600 capture.pcap time-adjusted.pcap # add 1 hour to all timestamps
When sharing PCAP with a vendor or external analyst, run it through editcap first: truncate to headers-only with -s 100 (keeps all forensically relevant headers, removes payload that may contain sensitive data), extract only the relevant time window with -A/-B, and document exactly what editcap commands you ran and their output. The resulting file is smaller, shareable, and doesn't expose plaintext credentials or file content that may be in the original capture. Keep the original full-payload PCAP in your case directory under chain of custody; share only the editcap-processed version.
tcpreplay — Replaying Traffic Against Detection Stack
# Replay a pcap against your detection stack to validate Suricata/Zeek rules
# IMPORTANT: only replay on a lab/isolated network — never against production
# Basic replay at original capture speed
tcpreplay -i eth0 capture.pcap
# Replay at 10% speed (easier for Suricata to keep up)
tcpreplay -i eth0 -m 0.1 capture.pcap
# Replay at maximum speed (stress test your detection stack)
tcpreplay -i eth0 --topspeed capture.pcap
# Replay with timing multiplier (2x speed)
tcpreplay -i eth0 -m 2.0 capture.pcap
# Replay only packets matching a BPF filter (replay just the C2 traffic)
tcpreplay -i eth0 -B 'host 185.220.101.47' capture.pcap
# Use tcprewrite to rewrite IPs/MACs if replaying on a different network
# (so the replayed traffic has valid IPs for your lab network)
tcprewrite \
--srcipmap=185.220.101.47:10.0.99.99 \
--dstipmap=10.0.1.50:10.0.1.50 \
--infile=capture.pcap \
--outfile=rewritten.pcap
tcpreplay -i eth0 rewritten.pcap
# Verify Suricata fired on the replayed traffic
tail -f /var/log/suricata/eve.json | jq 'select(.event_type=="alert")'
Q & A
Q: I merged 50 pcap files and the merged file is missing some packets from the middle of the time range. How do I find the gap?
A missing gap in a merged file is most commonly caused by: (1) a ring buffer file that was deleted or never written (the ring wrapped and the file was overwritten before you collected it), or (2) a clock jump on the capture host (an NTP adjustment mid-capture caused timestamps to go backwards, and some packets appear in the "wrong" file). To find the gap: run capinfos -ae ring/capture_*.pcap on all input files individually and sort the output by first-packet-time. Look for a file where the first-packet-time is later than the last-packet-time of the previous file — that gap is evidence loss. Document the gap in your case notes: "PCAP coverage gap between [time1] and [time2]. Activity during this window is unaccounted for in packet analysis." For the NTP-clock-jump case, the timestamps within the affected file will jump backward — editcap with -A/-B based on wall-clock time may exclude these packets. Check the capture host's system log for NTP adjustment events (e.g., ntpd: adjusting clock by -4.5s) around the gap time.