Introduction
Every network-based attack — reconnaissance, lateral movement, data exfiltration, C2 beaconing — leaves a trace on the wire. IDS tools like Suricata and Zeek automate detection at scale, but when you need to manually verify an alert, reconstruct a session, or answer "what actually happened," nothing beats reading the raw packets yourself.
Wireshark is the de facto standard GUI packet analyzer, and its command-line sibling tshark ships in the same package for headless captures on servers, jump boxes, and automation pipelines. This guide covers installing both, building effective capture and display filters, and walking through a few attack patterns you'll actually see in the field.
In this guide you will:
- Install Wireshark/tshark and configure non-root packet capture on Linux
- Capture traffic with BPF capture filters (to keep files small) and Wireshark display filters (to triage what you captured)
- Follow TCP/HTTP streams and decrypt TLS traffic with a session key log
- Extract files and IOCs from a capture
- Recognize common patterns: port scans, DNS tunneling, and plaintext credential leaks
Prerequisites
- A Linux (Ubuntu/Debian shown), macOS, or Windows host with a network interface you're authorized to monitor
sudo/admin rights for the initial install and capture permission setup- Authorization: only capture traffic on networks and systems you own or have explicit written permission to monitor. Packet capture on networks you don't control may violate wiretapping laws.
Step 1: Install Wireshark and tshark
Ubuntu/Debian:
sudo apt update
sudo apt install -y wireshark tsharkDuring install, you'll be asked whether non-superusers can capture packets. Choose Yes — this adds a wireshark system group that can access the capture interface without running as root.
macOS (Homebrew):
brew install --cask wiresharkWindows: download the installer from wireshark.org; it bundles Npcap for packet capture.
Grant capture permission without root (Linux)
sudo usermod -aG wireshark $USER
# log out and back in for the group change to take effect
newgrp wireshark
# verify
groups | grep wiresharkConfirm tshark works without sudo:
tshark -DThis lists available interfaces. If you get a permissions error, double-check the group membership and that /usr/bin/dumpcap has the cap_net_raw,cap_net_admin capabilities set (the Debian/Ubuntu package does this automatically):
getcap /usr/bin/dumpcap
# /usr/bin/dumpcap cap_net_admin,cap_net_raw+eipStep 2: Capture traffic with a capture filter
Capture filters (BPF syntax) are applied before packets hit disk — use them to keep files small on busy links. Display filters (Wireshark syntax) are applied after capture, for triage.
Capture only traffic to/from a host, excluding your own SSH session so you don't capture your own management traffic:
tshark -i eth0 \
-f "host 10.10.0.55 and not port 22" \
-w /tmp/host-10.10.0.55.pcapngCapture a rolling set of files, useful for long-running sensors:
tshark -i eth0 \
-b filesize:102400 -b files:10 \
-w /var/log/pcap/capture.pcapngThis rotates every 100 MB and keeps the last 10 files (~1 GB ring buffer).
Stop after a fixed packet count or duration for a quick spot-check:
tshark -i eth0 -c 5000 -w /tmp/spotcheck.pcapng
# or
timeout 60 tshark -i eth0 -w /tmp/60sec.pcapngStep 3: Triage with display filters
Open the capture in Wireshark (wireshark /tmp/host-10.10.0.55.pcapng) or filter directly with tshark. A few filters analysts use constantly:
# Only TCP resets and SYNs — good for spotting scans
tcp.flags.syn == 1 and tcp.flags.ack == 0
# HTTP requests with a specific method
http.request.method == "POST"
# DNS queries longer than typical hostnames — possible tunneling
dns.qry.name.len > 50
# Traffic to/from a suspicious IP
ip.addr == 45.33.32.156
# TLS handshakes showing SNI (server name) — useful even without decryption
tls.handshake.extensions_server_name
Run a filter headlessly and extract just the fields you need (great for scripting IOC pivots):
tshark -r /tmp/capture.pcapng \
-Y "tls.handshake.extensions_server_name" \
-T fields -e ip.src -e tls.handshake.extensions_server_nameStep 4: Follow a stream and decrypt TLS
Right-click any TCP packet in Wireshark and choose Follow > TCP Stream to reconstruct the full conversation — invaluable for reading plaintext HTTP, FTP, or Telnet sessions end to end.
For TLS traffic, you can decrypt it if you have the session keys. Have your browser or test client log them:
export SSLKEYLOGFILE=/tmp/sslkeys.log
# then launch Chrome/Firefox from this same shell and browseIn Wireshark: Edit > Preferences > Protocols > TLS, set (Pre)-Master-Secret log filename to /tmp/sslkeys.log. Wireshark will now decrypt matching sessions in the capture live, and Follow > TLS Stream shows plaintext application data.
Headless equivalent with tshark:
tshark -r capture.pcapng \
-o "tls.keylog_file:/tmp/sslkeys.log" \
-Y "http" -T fields -e http.host -e http.request.uriStep 5: Extract files and IOCs
Wireshark can carve transferred files straight out of a capture: File > Export Objects > HTTP (or SMB/DICOM/etc.), which lists every file the browser or file share transferred and lets you save it for offline analysis (in an isolated, non-production environment).
From the command line:
tshark -r capture.pcapng --export-objects http,/tmp/extracted-http/Pull a quick list of unique external IPs an endpoint talked to — a fast first pass for a compromised-host triage:
tshark -r capture.pcapng -T fields -e ip.dst | sort -u | grep -v '^10\.\|^192\.168\.'Recognizing common patterns
Port scan — many SYNs from one source to sequential/varied destination ports with few or no completed handshakes:
tcp.flags.syn==1 and tcp.flags.ack==0 and ip.src==<scanner-ip>
Sort by destination port in the packet list; a fan-out across dozens of ports in seconds is the signature.
DNS tunneling — unusually long or high-entropy subdomains, high query volume from a single host, or TXT/NULL record types used for data smuggling:
dns.qry.name.len > 50 or dns.qry.type == 16
Plaintext credentials — legacy protocols (HTTP Basic Auth, FTP, Telnet) still show up more often than they should:
ftp.request.command == "PASS" or http.authorization
Verification and testing
Confirm your pipeline end-to-end before relying on it during an incident:
# 1. Generate known traffic
curl -s http://example.com > /dev/null
# 2. Capture it
sudo timeout 10 tshark -i eth0 -f "host example.com" -w /tmp/test.pcapng
# 3. Confirm the HTTP request is visible
tshark -r /tmp/test.pcapng -Y "http.request" -T fields -e http.host -e http.request.uriYou should see example.com and / printed back. If the file is empty, check that you captured on the correct interface (tshark -D) and that the capture filter's hostname resolved to the IP you expected at capture time.
Troubleshooting
- "You don't have permission to capture on that device" — group membership didn't take effect. Fully log out/in (or reboot), and re-check
getcap /usr/bin/dumpcap. - Capture file grows huge instantly — a capture filter wasn't applied, or you captured on a SPAN/mirror port carrying full link traffic. Add a
host/netcapture filter, or use-s 96to snap-length each packet to headers only when you don't need payloads. - TLS won't decrypt despite a keylog file — the keylog must be generated by the same TLS session you captured; browsers only write to
SSLKEYLOGFILEif it's set before the process starts, and the cipher suite must support it (modern TLS 1.3 with ECDHE works fine with a keylog — it doesn't require the server's private key). - Wireshark GUI is slow on a large file — use tshark with
-Yto filter and-T fieldsto extract only what you need, or split the file first:editcap -c 100000 big.pcapng split.pcapng. - Interface shows no traffic on a switch — switches only forward unicast traffic to its destination port. You need a SPAN/mirror port, a network TAP, or to capture on the host itself.
Summary
Wireshark and tshark turn "the alert says something happened" into "here is exactly what happened, byte for byte." Capture filters keep your files manageable, display filters get you from a firehose of packets to the handful that matter, and stream/TLS decryption reconstructs full conversations for confirmation. Pair this with your existing IDS/NSM stack (Suricata, Zeek) — those tools tell you when to look; Wireshark and tshark are how you look.