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 matches

For 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 format

Find 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
FieldWhat it gives
frame.time, frame.time_epochpacket timestamp
frame.protocolsprotocol stack (eth:ip:tcp:http)
ip.src, ip.dst, tcp.dstport, tcp.streamcore flow identity
dns.qry.name, dns.qry.type, dns.flags.rcodeDNS query target, type, rcode (3 = NXDOMAIN)
http.host, http.request.uri, http.user_agent, http.request.methodHTTP request fields
tls.handshake.extensions_server_nameSNI - the only hostname visible in TLS
dhcp.option.hostname, dhcp.hw.mac_addr, dhcp.ip.yourDHCP client identity, MAC, leased IP
dhcp.option.router, dhcp.option.domain_nameDHCP-supplied gateway (Opt 3) and AD/DNS domain (Opt 15)
smb2.tree, smb2.filename, smb2.cmd, smb2.write_lengthSMB share path, file opened, command opcode, bytes written
kerberos.CNameString, kerberos.realmKerberos principal and AD realm
ntlmssp.auth.username, ntlmssp.auth.domainNTLM authenticate fields (who-logged-on-where)
data.dataapplication 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 -u

Object 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 channel

Available 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.

QuestionCommand
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 DHCPtshark -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 usernamestshark -r file.pcap -Y kerberos -T fields -e kerberos.CNameString | sort -u | grep -v '^$'
AD realmtshark -r file.pcap -Y kerberos -T fields -e kerberos.realm | sort -u
SMB Tree IDs to share pathstshark -r file.pcap -Y "smb2.cmd == 3" -T fields -e smb2.tid -e smb2.tree
Files written over SMBtshark -r file.pcap -Y "smb2.cmd == 5 and smb2.filename" -T fields -e smb2.tid -e smb2.filename | sort -u
Bytes written per SMB treetshark -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 credentialstshark -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 exfiltshark -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/porttshark -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

PipePurpose
| sort | uniq -c | sort -rnfrequency count, most common first
| sort -uunique values
| wc -lrow count
| grep -v '^$'drop empty lines
| head -N / | tail -Nfirst / 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.pcap

Field Manual | Wireshark for Forensics | Network Forensics | Networking Essentials