Wireshark twoo twooo two twoo... picoCTF 2021 Solution

Published: April 2, 2026

Description

Can you find the flag in this packet capture? Download shark2.pcapng.

Download the pcap file and open it in Wireshark.

bash
wget https://mercury.picoctf.net/static/.../shark2.pcapng

Solution

Want to try it yourself first?

The guided walkthrough reveals hints one step at a time.

Walk me through it
  1. Step 1
    Filter for DNS queries from the client
    Observation
    I noticed the pcap description mentioned the flag was hidden inside network traffic and the challenge name hinted at repetition, which suggested an exfiltration channel built on a protocol sent in high volumes; DNS stood out because it is rarely blocked and its query names can carry arbitrary text.
    Apply 'dns.flags.response == 0' in Wireshark to keep only outbound queries. The flag is exfiltrated character by character through DNS query subdomains, not through DNS responses.
    bash
    wireshark shark2.pcapng
    What didn't work first

    Tried: Look for the flag in HTTP or TCP streams using 'Follow Stream' in Wireshark

    The pcap contains no HTTP traffic carrying the flag. Focusing on TCP/HTTP streams produces empty or unrelated results because the exfiltration channel is DNS, not a transport-layer stream. The correct approach is to switch to DNS traffic and inspect query names.

    Tried: Apply 'dns.flags.response == 1' to look at DNS responses for the flag

    DNS responses carry only resolver-generated A or NXDOMAIN records back to the client, not the attacker-encoded data. The encoded chunks live in the query name field of outbound queries (response == 0), not in the answer section of responses. Filtering on response == 1 shows the wrong direction of traffic.

    Learn more

    DNS exfiltration. DNS traffic is allowed almost everywhere, so attackers encode data into subdomain names of queries to a domain they control. The authoritative name server logs the queries and reconstructs the data later.

    Why dns.flags.response == 0. DNS packets come in pairs: the query (flags.response = 0, sent by the client) and the response (flags.response = 1, sent by the resolver). The exfil data is typed by the attacker into the query name. The response carries only an A/NXDOMAIN record back. Keeping only queries halves the noise and ensures you don't double-count the same hostname when it appears in both the question and answer sections.

  2. Step 2
    Order, concatenate, and base64-decode the subdomains
    Observation
    I noticed each filtered DNS query name had a varying first label made up of characters from the base64 alphabet (A-Z, a-z, 0-9, +, /, =), which suggested the labels were base64 chunks that needed to be joined in capture order and decoded to recover the flag.
    Sort queries by frame.time so they're in the order the client sent them. Pull the first label from each hostname, concatenate, and base64-decode.
    bash
    # Dump query names in capture order:
    tshark -r shark2.pcapng -Y 'dns.flags.response == 0' -T fields -e frame.time -e dns.qry.name
    bash
    # Strip the base domain, take the leading label, join, b64decode:
    tshark -r shark2.pcapng -Y 'dns.flags.response == 0' -T fields -e dns.qry.name \
      | grep -v 'in-addr\|local' \
      | awk -F'.' '{print $1}' \
      | tr -d '\n' \
      | base64 -d

    Expected output

    picoCTF{dns_3xf1l_ftw_...}
    What didn't work first

    Tried: Pipe the tshark output through 'sort -u' before joining to remove duplicate query names

    Sorting the labels scrambles the transmission order, so the concatenated base64 string is corrupted and base64 -d produces garbage or an error. The chunks must stay in capture order. tshark already outputs packets in frame order, so a plain 'tr -d newline' is sufficient without any sort step.

    Tried: Use 'awk -F. {print $2}' to grab the second label instead of the first

    The second label is the beginning of the attacker's base domain (e.g. 'attacker' in 'cGljb0NU.attacker.com'), which is the same constant string in every packet and contains no encoded flag data. Only the first label ($1) varies per packet and holds the encoded payload chunk.

    Learn more

    Why split on the first label. Each query name looks like cGljb0NU.attacker.com. The leading label (before the first .) is the encoded chunk; everything after is the attacker's base domain and is the same for every packet. awk -F'.' '{print $1}' isolates the chunk.

    Why concatenate without a separator. Each chunk is one piece of a base64-encoded message. Joining them as one continuous string gives the original base64 blob; decode it with base64 -d to get the flag.

    Order matters. Use frame.time rather than sort: the chunks were sent in transmission order, not lexicographic order. tshark output is already in capture order by default, so a plain tr -d '\n' preserves it. Avoid piping through sort -u (it scrambles order and can drop legitimate duplicates).

    See Wireshark for CTF for the broader pcap workflow and CTF encodings for base64 alongside the rest of the encoding zoo.

Interactive tools
  • Hex ViewerView text or raw hex bytes as a xxd-style hex dump with byte offset, hex columns, and ASCII sidebar. Highlights printable characters and null bytes.
  • Strings ExtractorPull printable text from any binary, library, or image. ASCII and UTF-16 detection, configurable minimum length, flag-like highlight, no command line needed.
Alternate Solution

Once you concatenate the Base64 subdomain chunks, decode them with the Base64 Decoder on this site. Paste the joined string and the flag appears without needing a terminal.

Flag

Reveal flag

picoCTF{dns_3xf1l_ftw_...}

The flag was exfiltrated via DNS queries with base64-encoded subdomains, a classic covert channel that bypasses firewall restrictions on other protocols.

Key takeaway

DNS exfiltration abuses the fact that DNS traffic is almost universally permitted outbound, even on networks that block HTTP, FTP, and other data channels. By encoding a payload into the subdomain labels of queries to an attacker-controlled domain, data leaves the network without triggering port-based firewall rules. Defenders detect this pattern through DNS anomaly monitoring: unusually long labels, high query volume to a single domain, or base64-like character distributions in query names are reliable indicators.

Related reading

Want more picoCTF 2021 writeups?

Useful tools for Forensics

What to try next