خطوات آمنة

تقييمات الأمن السيبراني، ورؤى معمقة، وحلول واضحة للمعالجة.

Category:

Min beste venn — PCAP Bit Encoding | NNS CTF

Min beste venn — PCAP Bit Encoding

Platform: NNS CTF 2026
Category: Forensics

1. Initial inspection

The archive contains a single capture, capture.pcap. A packet count shows 3,662 TCP packets, and filtering for HTTP requests reveals that the traffic is dominated by HEAD requests to static.notion-static.com. The requests do not carry an obvious flag in their bodies.

The unusual feature is the requested path. Paths end in numeric CSS filenames, and the numeric values use only digits 0 through 7. That strongly suggests octal positions or an intentionally restricted bit index rather than ordinary asset names.

2. Finding the encoding rule

Each logical message is separated by a prefix such as d/h/0, d/h/1, d/c/0, or d/c/1. Within a group, a numeric suffix appears either once or twice. Treat the suffix as a position and the multiplicity as its bit:

  • one request for a position means bit 0;
  • two requests for a position mean bit 1.

Sort the numeric positions before reading them. Sorting is essential because packet order is not the encoding order; the suffix itself supplies the position.

3. Turning groups into bytes

After mapping multiplicity to bits, concatenate the bits in sorted-position order and consume them eight at a time. Convert each eight-bit chunk to a byte. Decode all four streams instead of stopping at the first readable text. The d/h streams contain prompts and framing, while the d/c/1 stream contains the complete flag.

4. Reproduction

import collections, re, subprocess

raw = subprocess.check_output([
    "tshark", "-r", "forensics_min-beste-venn/capture.pcap",
    "-Y", "http.request", "-T", "fields",
    "-E", "separator=|", "-e", "http.request.uri",
], text=True)

for prefix in ("d/h/0", "d/h/1", "d/c/0", "d/c/1"):
    counts = collections.Counter()
    for uri in raw.splitlines():
        match = re.search(r"/" + re.escape(prefix) + r"/([0-9]+)\\.css$", uri)
        if match:
            counts[int(match.group(1))] += 1
    positions = sorted(counts)
    bits = "".join("1" if counts[p] > 1 else "0" for p in positions)
    decoded = bytes(int(bits[i:i+8], 2)
                    for i in range(0, len(bits)-7, 8))
    print(prefix, decoded)

5. Result and validation

The decoded streams include readable challenge dialogue. The d/c/1 stream yields the complete flag, including its closing brace:

NNS{1_l0v3_ch4tt1ng_w1th_m1n_b3st3_v3nn_1n_th3_cl0ud5}

This is stronger than finding a matching string in packet metadata: the result comes from a deterministic transformation of the complete capture and the other streams provide contextual confirmation.

6. Lessons

  • Repeated requests can encode data through metadata rather than payloads.
  • Packet order and logical position are different; always test the ordering rule.
  • Decode every stream so framing and prompts can validate the interpretation.
  • Keep the original PCAP and decoder together for future competitions.
ar
Secure Steps
Privacy Overview

This website uses cookies so that we can provide you with the best user experience possible. Cookie information is stored in your browser and performs functions such as recognising you when you return to our website and helping our team to understand which sections of the website you find most interesting and useful.