misc

Challenges

Null Sanity

Are you ready for another great Nullcon event in Berlin?!

Awesome! Here's a first flag for your sanity: ENO{Let's_H4ve_S0m3_FuN_In_Berlin!}

  • ENO{Let's_H4ve_S0m3_FuN_In_Berlin!}

usbstorage

I attached my friend's USB drive to my laptop and accidently copied a private file, which I immediately deleted. But my friend still somehow got the file from looking at the USB message their drive recorded...

usbstorage.pcapng

❯ binwalk -e usbstorage.pcapng

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------
1343984       0x1481F0        gzip compressed...

❯ cd _usbstorage.pcapng-0.extracted
❯ file 1481F0
1481F0: POSIX tar archive (GNU)
❯ tar -xvf 1481F0
flag.gz
❯ gunzip flag.gz
❯ cat flag
ENO{USB_STORAGE_SHOW_ME_THE_FLAG_PLS}
  • Now onto the second (intended?) solution, the pcapng file us usb mass stoarge messages hidden (hence the name).

The other approach requires parsing the pcapng file to extract USB bulk OUT transfers, which contain the actual data written to the storage device. Here's how it works:

  • Step 1: Extract Frame Data Parses each frame in the packet capture, identifying USB bulk transfer packets and extracting their payloads. It correlates frame numbers with their corresponding data lengths to ensure accurate reconstruction.

  • Step 2: Hexdump Parsing: Parses hexdump-formatted output, extracting only the relevant hex bytes while ignoring ASCII representations.

  • Step 3: Data Reconstruction By taking the last usb.data_len bytes from each frame (representing the bulk OUT payload), reconstructs the complete data stream that was written to the USB storage device.

  • Step 4: File Carving The reconstructed binary data contains a gzip-compressed tar archive starting at byte offset 24576.

If you are a visual learner~ here da go 🐧

┌─────────────────────────────────────────────────────────────────┐
│                    usbstorage.pcapng                            │
│                 (USB Packet Capture)                            │
└─────────────────────┬───────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────┐
│              Parse USB Frames                                   │
│   Frame 1: [USB Data] Frame 2: [USB Data] ... Frame N: [USB]    │
└─────────────────────┬───────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────┐
│          Extract USB Bulk OUT Transfers                         │
│   ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐               │
│   │Frame 123│ │Frame 456│ │Frame 789│ │Frame XYZ│ ...           │
│   │12 34 56 │ │AB CD EF │ │78 9A BC │ │DE F0 12 │               │
│   └─────────┘ └─────────┘ └─────────┘ └─────────┘               │
└─────────────────────┬───────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────┐
│              Reconstruct Binary Stream                          │
│  [12 34 56 AB CD EF 78 9A BC DE F0 12 ... ] → bulk_out.bin      │
└─────────────────────┬───────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────┐
│                 File Carving                                    │
│  bulk_out.bin: [junk data...] [GZIP at offset 24576] [more...]  │
│                                    │                            │
│                                    ▼                            │
│                            ┌─────────────┐                      │
│                            │ flag.tar.gz │                      │
│                            └─────────────┘                      │
└─────────────────────┬───────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────┐
│                Extract & Get Flag 🤷‍♂                            │
│              tar xzf flag.tar.gz                                │
│                       │                                         │
│                       ▼                                         │
│            ENO{USB_STORAGE_SHOW_ME_THE_FLAG_PLS}                │
└─────────────────────────────────────────────────────────────────┘

Script

import re, binascii

# Load (frame -> usb.data_len)
lens = {}
for ln in open('out_lens.tsv'):
    ln = ln.strip()
    if not ln: continue
    f, l = ln.split()
    lens[int(f)] = int(l)

out = bytearray()
cur_frame = None
cur_hex = []
def flush():
    global out, cur_frame, cur_hex
    if cur_frame is None or cur_frame not in lens or not cur_hex: 
        return
    # Gather all hex bytes in this frame
    hexbytes = []
    for line in cur_hex:
        # hexdump lines look like: "  0000  12 34 56  ...  |....|"
        m = re.match(r'^\s*[0-9A-Fa-f]{4}\s+(.*)$', line)
        if not m: 
            continue
        # take only the left hex columns (stop before the ASCII)
        left = m.group(1).split('  ')[0]   # split before big gap to ASCII
        for tok in left.split():
            if re.fullmatch(r'[0-9A-Fa-f]{2}', tok):
                hexbytes.append(tok)
    frame_bytes = binascii.unhexlify(''.join(hexbytes)) if hexbytes else b''
    need = lens[cur_frame]
    # take the *last* usb.data_len bytes (bulk OUT payload)
    if need > 0 and len(frame_bytes) >= need:
        out += frame_bytes[-need:]
    elif need > 0 and frame_bytes:  # truncated capture, take whatever we have
        out += frame_bytes
    # reset
    cur_hex.clear()

with open('out_vx.txt','r', errors='replace') as f:
    for line in f:
        m = re.match(r'^(?:Frame|Packet)\s+(\d+):', line)
        if m:
            flush()
            cur_frame = int(m.group(1))
            continue
        if re.match(r'^\s*[0-9A-Fa-f]{4}\s', line):
            cur_hex.append(line)
# last one
flush()

open('bulk_out.bin','wb').write(out)
print(f"Wrote bulk_out.bin ({len(out)} bytes)")


> 
# carve the gzip member starting at byte 24576
dd if=bulk_out.bin of=flag.tar.gz bs=1 skip=24576 status=none

# sanity checks
file flag.tar.gz
gzip -t flag.tar.gz
tar -xvf flag.tar
cat flag
  • ENO{USB_STORAGE_SHOW_ME_THE_FLAG_PLS}

atruecryptographer (upsolve)

You know what I like most? Nullcon aftermovies and Kerckhoffs's principle! But since I'm a true cryptographer and a 1337 h4xx0r, I can even provide you my password without you ever finding my secrets: U"gkXYg;^#qXxJ(jm*jKik|N/gezj7)z

My question is: Are you a true cryptographer, too? Prove it by finding my secret!

https://static.enoflag.de/nullconctfberlin2025/nullcon-aftermovie.mp4

  • Mount the volume in TrueCrypt:

    • In TrueCrypt, click "Select File..."

    • Browse to and select the downloaded "aftermovie.mp4" file

    • Click "Mount"

  • ENO{Tru3_Cryp7_St3G0_F04_Ze_W1n!}

  • Tbh, this sh baffled me.

Last updated