tshark CLI for PCAP triage and forensic analysis. Statistics, display filtering, field extraction, object export. Pairs with Wireshark for GUI workflows; flags below verified against tshark 4.6.4.
Side: blue
Time format
Reports must state times in UTC. Capture timestamps render in local TZ by default — fix this on every command.
tshark -r file.pcap -t ud # absolute date and time, UTC ('2026-04-15 17:52:59.947')
tshark -r file.pcap -t u # absolute time only, UTC
tshark -r file.pcap -t ad # absolute date and time, local TZ (do NOT use for reports)
tshark -r file.pcap -t r # seconds since first packet (timing analysis)
tshark -r file.pcap -t e # epoch seconds.us (machine-readable)Lab and acquisition VMs frequently have wrong TZ. Treat any non-UTC timestamp as suspect until verified.
Initial triage
First contact with a PCAP. Each command answers one question.
capinfos file.pcap # hash, duration, packet count, first/last time, file type
sha256sum file.pcap # standalone hash for chain of custody
tshark -r file.pcap -q -z io,phs # protocol hierarchy - what's in the capture
tshark -r file.pcap -q -z endpoints,ip # IPv4 hosts ranked by traffic
tshark -r file.pcap -q -z conv,ip # host-pair conversations
tshark -r file.pcap -q -z conv,tcp # TCP conversations broken out per port-q suppresses per-packet output, -z runs a statistic and exits. Combine for clean batch reports.
Display filtering
Wireshark display filter syntax works identically in tshark via -Y. To reduce a capture, add -w.
tshark -r in.pcap -Y "ip.addr == 10.0.0.5" # filter to one host
tshark -r in.pcap -Y "tcp.port == 445" # SMB only
tshark -r in.pcap -Y "tcp.flags.syn==1 && tcp.flags.ack==0" # lone SYNs (scanning, half-open)
tshark -r in.pcap -Y "http.request" # HTTP requests only
tshark -r in.pcap -Y "tls.handshake.type==1" # TLS Client Hello (gives SNI)
tshark -r in.pcap -Y "<filter>" -w out.pcap # write filtered subset
tshark -r in.pcap -Y "<filter>" -V # full packet detail (Wireshark tree view)
tshark -r in.pcap -Y "<filter>" | wc -l # count matchesFor pre-dissection filtering on huge captures, pair -2 -R "<read filter>" (two-pass mode) with -Y for a display filter on the second pass.
Field extraction
The CLI advantage over GUI. Pull specific fields, pipe to sort/uniq/grep/awk.
tshark -r file.pcap -T fields -e ip.src -e ip.dst # two-column output
tshark -r file.pcap -T fields -e dns.qry.name -E header=y -E quote=d # CSV-safe with header
tshark -r file.pcap -T json # full JSON dump
tshark -r file.pcap -T ek # Elasticsearch bulk import formatFind a field name from the GUI: select a value in packet details, status bar bottom-left shows protocol.field.name. Or right-click > Copy > Field Name.
High-value fields
| Field | What it gives |
|---|---|
frame.time, frame.time_epoch | packet timestamp |
frame.protocols | protocol stack (eth:ip:tcp:http) |
ip.src, ip.dst, tcp.dstport, tcp.stream | core flow identity |
dns.qry.name, dns.qry.type, dns.flags.rcode | DNS query target, type, rcode (3 = NXDOMAIN) |
http.host, http.request.uri, http.user_agent, http.request.method | HTTP request fields |
tls.handshake.extensions_server_name | SNI - the only hostname visible in TLS |
dhcp.option.hostname, dhcp.hw.mac_addr, dhcp.ip.your | DHCP client identity, MAC, leased IP |
dhcp.option.router, dhcp.option.domain_name | DHCP-supplied gateway (Opt 3) and AD/DNS domain (Opt 15) |
smb2.tree, smb2.filename, smb2.cmd, smb2.write_length | SMB share path, file opened, command opcode, bytes written |
kerberos.CNameString, kerberos.realm | Kerberos principal and AD realm |
ntlmssp.auth.username, ntlmssp.auth.domain | NTLM authenticate fields (who-logged-on-where) |
data.data | application payload as hex (covert-channel decode) |
Stream following
tshark -r file.pcap -q -z follow,tcp,ascii,<id> # TCP stream as ASCII (id from tcp.stream)
tshark -r file.pcap -q -z follow,http,ascii,<id> # HTTP stream
tshark -r file.pcap -q -z follow,tls,ascii,<id> # TLS (decrypted only with keylog)
tshark -r file.pcap -q -z follow,tcp,raw,<id> > out.bin # raw bytes for binary carving
# decrypt TLS with a captured SSLKEYLOGFILE
tshark -r file.pcap -o tls.keylog_file:keys.log -Y "tls"
# find streams containing a literal string
tshark -r file.pcap -Y 'frame contains "string"' -T fields -e tcp.stream | sort -uObject extraction
Extracts files transferred over the protocol. Always run in an isolated VM — extracted objects may be live malware.
tshark -r file.pcap --export-objects http,./out # HTTP transfers
tshark -r file.pcap --export-objects smb,./out # SMB file writes
tshark -r file.pcap --export-objects imf,./mail_out # SMTP message bodies (.eml)
tshark -r file.pcap --export-objects tftp,./out # TFTP transfers
tshark -r file.pcap --export-objects ftp-data,./out # FTP data channelAvailable exporters in 4.6.4: dicom, ftp-data, http, imf, smb, tftp, x509af.
Forensic patterns
Each row maps a question an analyst asks during PCAP triage to the tshark command that answers it.
| Question | Command |
|---|---|
| What domains were queried? | tshark -r file.pcap -Y "dns.qry.type==1" -T fields -e dns.qry.name | sort | uniq -c | sort -rn | head |
| What HTTP hosts were contacted? | tshark -r file.pcap -Y "http.request" -T fields -e http.host | sort -u |
| What TLS SNI hostnames? | tshark -r file.pcap -Y "tls.handshake.type==1" -T fields -e tls.handshake.extensions_server_name | sort -u |
| What user-agents in HTTP? | tshark -r file.pcap -T fields -e http.user_agent | sort -u | grep -v '^$' |
| Hostname / MAC / leased IP from DHCP | tshark -r file.pcap -Y dhcp -T fields -e dhcp.option.hostname -e dhcp.hw.mac_addr -e dhcp.ip.your | sort -u | grep -v '^\s*$' |
| Authenticated AD usernames | tshark -r file.pcap -Y kerberos -T fields -e kerberos.CNameString | sort -u | grep -v '^$' |
| AD realm | tshark -r file.pcap -Y kerberos -T fields -e kerberos.realm | sort -u |
| SMB Tree IDs to share paths | tshark -r file.pcap -Y "smb2.cmd == 3" -T fields -e smb2.tid -e smb2.tree |
| Files written over SMB | tshark -r file.pcap -Y "smb2.cmd == 5 and smb2.filename" -T fields -e smb2.tid -e smb2.filename | sort -u |
| Bytes written per SMB tree | tshark -r file.pcap -Y "smb2.cmd == 9" -T fields -e smb2.tid -e smb2.write_length | awk '{s[$1]+=$2} END{for(k in s) print k,s[k]}' |
| POP3 plaintext credentials | tshark -r file.pcap -Y 'pop.request.command == "USER" or pop.request.command == "PASS"' -T fields -e pop.request.parameter |
| SMTP envelope (MAIL FROM / RCPT TO) | tshark -r file.pcap -Y 'smtp.req.command == "MAIL" or smtp.req.command == "RCPT"' -T fields -e smtp.req.parameter |
| ICMP Echo payload decode (covert channel) | tshark -r file.pcap -Y "icmp.type==8" -T fields -e data.data | xxd -r -p |
| DNS subdomain hex exfil | tshark -r file.pcap -Y 'dns.qry.name contains "<marker>"' -T fields -e dns.qry.name | cut -d'.' -f3 | tr -d '\n' | xxd -r -p |
| SYN scan source/target/port | tshark -r file.pcap -Y "tcp.flags.syn==1 && tcp.flags.ack==0" -T fields -e ip.src -e ip.dst -e tcp.dstport | sort | uniq -c | sort -rn |
Pipe idioms
| Pipe | Purpose |
|---|---|
| sort | uniq -c | sort -rn | frequency count, most common first |
| sort -u | unique values |
| wc -l | row count |
| grep -v '^$' | drop empty lines |
| head -N / | tail -N | first / last N |
| awk '{s[$1]+=$2} END{for(k in s) print k,s[k]}' | sum column 2 grouped by column 1 |
Batch idioms
# protocol hierarchy for every PCAP in a directory
for f in *.pcap; do tshark -r "$f" -q -z io,phs > "${f%.pcap}.phs.txt"; done
# diff two captures' protocol hierarchies
diff <(tshark -r a.pcap -q -z io,phs) <(tshark -r b.pcap -q -z io,phs)
# extract a single packet for sharing
tshark -r in.pcap -Y "frame.number == 42" -w packet42.pcaplinks:
Field Manual | Wireshark for Forensics | Network Forensics | Networking Essentials