April 12, 2026

Wireshark and pcap Analysis for CTF Forensics

Wireshark and tshark for CTF: analyze pcap files, follow TCP streams, find credentials, extract files, reconstruct DNS exfiltration, and apply display filters.

Introduction

Network forensics challenges give you a packet capture file (usually a .pcap or .pcapng file) recorded from a real or simulated network. Your job is to find the flag hidden somewhere inside the traffic: in a plaintext HTTP response, embedded in a file transferred over FTP, encoded in DNS queries, or smuggled inside a protocol you wouldn't normally suspect.

Wireshark is the standard tool for this work. It parses and dissects hundreds of protocols, lets you reconstruct TCP streams as readable text, and can export files from network transfers. This guide covers the skills needed for challenges like Packets Primer, Eavesdrop, Wireshark doo dooo do doo, Wireshark twoo twooo two twoo, pcap poisoning, and shark on wire 1.

Note: For captures of USB traffic (keyboard or mouse HID reports) rather than network packets, see USB HID pcap forensics. For how packet analysis fits alongside disk, memory, and steganography work, see the forensics roadmap.

Opening a pcap file

Install Wireshark on Ubuntu or Debian:

sudo apt install wireshark

Open a capture file from the command line or via File → Open:

wireshark challenge.pcap
Note: On first launch Wireshark may ask whether non-root users should be able to capture packets. For CTF work you only need to read existing files, so the default setting is fine.

Wireshark also accepts compressed files (.pcap.gz) and the newer .pcapng format that supports multiple interfaces and packet comments.

Tip: Before opening in Wireshark, run strings challenge.pcap | grep -i 'picoctf\|flag' from the terminal. A surprising number of beginner challenges have the flag sitting in plaintext and this finds it in under a second.

The Wireshark interface

The Wireshark window has three main panes:

  • Packet list (top): one row per packet, showing number, timestamp, source, destination, protocol, and a summary.
  • Packet details (middle): the dissected protocol tree for the selected packet. Click any row to expand it.
  • Packet bytes (bottom): the raw hex and ASCII representation. Selecting a field in the details pane highlights the corresponding bytes here.

The display filter bar at the top is where you type filters to hide irrelevant packets. Press Enter or the arrow button to apply. The bar turns red for an invalid filter and green for a valid one.

Tip: Use Statistics → Protocol Hierarchy to see a breakdown of which protocols appear in the capture and what fraction of packets each occupies. This is a fast way to spot unexpected protocols that might be carrying the flag.

Following TCP/UDP streams

Reconstructing a complete conversation from individual packets is the most useful forensics operation. Right-click any packet in a TCP flow and choose Follow → TCP Stream. Wireshark reassembles all the packets in that flow into a single readable window, with client data in red and server data in blue.

This instantly shows you the full HTTP request and response, an FTP data transfer, or a shell session. Many CTF flags are directly visible as plaintext in a stream view.

At the bottom of the stream window you can switch the display to:

  • ASCII: printable characters (default)
  • Hex Dump: raw bytes alongside ASCII
  • Raw: the raw byte stream, useful for saving binary data

For UDP flows, use Follow → UDP Stream. For DNS challenges use Statistics → DNS or filter on dns and examine individual query names in the packet detail tree.

Display filters

Display filters narrow the packet list to only the packets you care about. Wireshark uses its own filter language (not Berkeley Packet Filter). Some essential filters:

FilterWhat it matches
httpAll HTTP traffic
tcp.port == 4444Traffic on a specific port
ip.addr == 10.0.0.5Traffic to or from a specific IP
http.request.method == "POST"HTTP POST requests only
ftp-dataFTP data transfers (the actual file contents)
dnsAll DNS queries and responses
tcp contains "picoCTF"TCP packets whose payload includes that string
frame contains "flag"Any packet containing the word flag
http.response.code == 200Successful HTTP responses
!(arp || dns)Hide ARP and DNS noise
icmpICMP packets (ping, potential covert channel)
Tip: Use tcp contains "picoCTF{" as a quick flag search. The braces are safe because they appear in the middle of the string, not as filter syntax.

Finding credentials

Plaintext protocols like HTTP (not HTTPS), FTP, Telnet, and POP3 transmit usernames and passwords in the clear. Wireshark can extract them automatically:

Go to Tools → Credentials. Wireshark scans the capture for known credential patterns across dozens of protocols and lists them in a separate window with the packet number, protocol, username, and password.

For HTTP Basic Auth, filter to http.authbasic and read the Authorization header. The value is Base64-encoded; decode it to recover username:password.

# Decode HTTP Basic Auth from the terminal
echo 'dXNlcjpwYXNz' | base64 -d
# user:pass

Extracting files from captures

Files transferred over HTTP, FTP, SMB, or TFTP are reconstructed by Wireshark automatically. Go to File → Export Objects and choose the protocol. Wireshark lists every transferred file with its filename and size. Save the ones you want to disk.

For protocols not in the Export Objects menu, follow the TCP stream, switch the view to Raw, then click Save As to write the raw bytes to a file.

Note: Always run file on any extracted binary to check its true type. The transferred data might be a ZIP, PNG, or PDF that was stored with a misleading extension.
Tip: Once you have an image or binary out of the capture, drop it into Stegall to run LSB sweeps, polyglot carving, metadata, and a base/ROT/XOR/zlib decode cascade in parallel. Network forensics challenges that smuggle a payload over HTTP or FTP often finish with a steganography hop.

tshark on the command line

tshark is the command-line version of Wireshark. It is invaluable when you want to grep, pipe, or script analysis of a large capture without a GUI.

# List all HTTP requests
tshark -r capture.pcap -Y 'http.request' -T fields \
-e ip.src -e http.request.method -e http.request.uri
# Print every DNS query name
tshark -r capture.pcap -Y 'dns.qry.name' -T fields -e dns.qry.name
# Follow TCP stream 0 and print as ASCII
tshark -r capture.pcap -q -z follow,tcp,ascii,0
# Extract all HTTP objects to a folder
tshark -r capture.pcap --export-objects http,/tmp/exported_files
# Search for the flag in any packet payload
strings capture.pcap | grep 'picoCTF'
Tip: The strings trick works surprisingly often. Before doing any analysis, run it first to see if the flag is sitting in plaintext.

TLS and encrypted traffic

HTTPS traffic is encrypted, so you cannot read the payload directly. However, TLS connections still expose useful metadata in the handshake, and some CTF setups give you a key log file to decrypt everything.

Extracting metadata without decryption

The TLS ClientHello packet is sent in the clear and contains the Server Name Indication (SNI), which reveals which hostname the client was connecting to. This is often enough to identify the suspicious connection in a capture.

# Extract all SNI values (server names) from TLS handshakes:
tshark -r cap.pcap -Y 'tls.handshake.type == 1' \
-T fields -e tls.handshake.extensions_server_name
# Extract certificate Common Names from the capture:
tshark -r cap.pcap -Y 'x509sat.printableString' \
-T fields -e x509sat.printableString | sort -u
# Wireshark filter to isolate TLS traffic to a specific domain:
tls.handshake.extensions_server_name == "suspicious.attacker.com"

Decrypting TLS with a key log file

Some challenges provide a SSLKEYLOGFILE (a file containing TLS session keys logged by the browser or client). If you have one, Wireshark can decrypt the entire TLS session:

# In Wireshark:
Edit -> Preferences -> Protocols -> TLS
-> (Pre)-Master-Secret log filename: browse to the .log file
# Wireshark will now show decrypted HTTP/2 or HTTP traffic inside the TLS streams.
# With tshark:
tshark -r cap.pcap -o 'tls.keylog_file:/path/to/sslkeys.log' \
-Y 'http' -T fields -e http.request.uri -e http.file_data
Note: The key log file is the method that works everywhere. Each CLIENT_RANDOM line records the session master secret keyed by the client random, so Wireshark can decrypt any TLS 1.2 session it covers, including static RSA and forward-secret (ECDHE/DHE) key exchanges alike. The server private key (Edit → Preferences → Protocols → TLS → RSA keys list) is the fallback for when you have no key log: it only works against non-PFS static RSA key exchange and cannot decrypt ECDHE/DHE traffic, because with forward secrecy the private key never derives the session keys.

ICMP covert channels

ICMP (ping) packets should have a small, fixed payload. When you see ICMP packets with unusually large or non-standard payloads, the data may be a covert channel carrying the flag.

# Filter to ICMP packets with data payloads:
icmp
# With tshark, extract each ICMP payload as hex:
tshark -r cap.pcap -Y icmp -T fields -e data.data
# Concatenate and decode:
tshark -r cap.pcap -Y icmp -T fields -e data.data | tr -d '\n' | xxd -r -p

Common CTF patterns

Flag in HTTP response body

The most common beginner pattern. Filter to http, follow the stream of a suspicious request, and read the response. The flag may be in the HTML body, a JSON field, or a custom header. Used in Packets Primer and Wireshark doo dooo do doo.

Flag in DNS exfiltration

Flags are sometimes encoded as subdomain labels in DNS queries, e.g. cGljb0NURg.attacker.com. The data is split across multiple queries, each carrying one chunk as a subdomain label. To reconstruct:

# 1. Extract all unique query names:
tshark -r cap.pcap -Y dns.qry.name -T fields -e dns.qry.name | sort -u
# 2. Strip the common parent domain and sort by order (often a sequence number prefix):
# Example queries: 01-cGljb0N.exfil.com 02-RGSB5Y3Q.exfil.com 03-dGZ7ZG5z.exfil.com
# 3. In Python: extract, join, and decode:
import base64
chunks = ['cGljb0N', 'RGSB5Y3Q', 'dGZ7ZG5z'] # extracted labels in order
combined = ''.join(chunks)
# Fix base64 padding:
combined += '=' * (4 - len(combined) % 4)
print(base64.b64decode(combined))

Exfiltration channels frequently stack base32 or hex inside a base64 outer layer. Paste the concatenated result into Recipe Chain and run Magic to peel apart nested encodings automatically. Used in Wireshark twoo twooo two twoo.

Credentials used as the flag

Some challenges are solved by finding a username or password that is itself the flag, or leads to a service where the flag lives. Use Tools → Credentials or filter to the relevant plaintext protocol. Used in Eavesdrop.

Modified or injected packets

In pcap poisoning, extra packets have been injected into a legitimate capture. Look for packets that break the normal conversation flow (out-of-sequence TCP, responses with no matching request, packets from unexpected source IPs) and inspect their payloads directly.

Unusual protocol

Check Statistics → Protocol Hierarchy. If you see an unexpected protocol like ICMP with large payloads, raw TCP on a non-standard port, or an unrecognized stream, that is usually the carrier for the hidden data. Used in shark on wire 1 and shark on wire 2.

Quick reference

FilterWhat it matches
Follow TCP StreamRight-click packet -> Follow -> TCP Stream
Export HTTP filesFile -> Export Objects -> HTTP
Find credentialsTools -> Credentials
Protocol breakdownStatistics -> Protocol Hierarchy
Conversation statsStatistics -> Conversations
strings + grepstrings capture.pcap | grep picoCTF
tshark fieldstshark -r cap.pcap -Y 'filter' -T fields -e field.name
Decrypt TLSEdit -> Preferences -> TLS -> key log file
Export all HTTP objectstshark -r cap.pcap --export-objects http,/tmp/out

Practice with: Packets Primer, Eavesdrop, Wireshark doo dooo do doo, Wireshark twoo twooo two twoo, pcap poisoning, shark on wire 1.

Try it on these picoCTF challenges

Walkthroughs that put this technique to work, grouped by event.

Keep reading

Guides that build on the same ideas, plus the roadmap this topic sits under.