Современный формат (Modern Format)
Современный формат (Modern Format)
Platform: bug-makers | Category: Forensics | Type: Challenge | Difficulty: Medium | OS: Linux | Author: XESXOR | Date: 2025-10-04 | Status: Solved Techniques: av1_obu_concatenation, avif_sequence_recovery, hidden_track_sample_extraction, isobmff_box_parsing
Summary
Task: a static site serves a modern AVIF image that does not display in most browsers; the file is an AVIF image sequence with a faked stsz sample_count hiding a second frame. Solution: parse the ISOBMFF boxes to find the real track samples, concatenate both AV1 temporal units from mdat, and decode the raw OBU stream with ffmpeg to reveal the flag frame.
Современный формат (Modern Format) — bug-makers
Description
Я делаю статичный сайт с описанием персонажа аниме. Но у меня есть проблема с отображением изображения в большинстве браузеров. Я использую современный формат AVIF для оптимизации, но похоже что этот формат не кроссбраузерный. Адрес: http://31.207.77.216:4020
English summary: A static site describes the anime character Megumin (KonoSuba) and embeds <img src="/megumin-flag.avif">. The author complains the modern AVIF image "doesn't display in most browsers." The filename ("flag") and the cross-browser hint point to a hidden frame inside the AVIF. The goal is to recover that hidden frame containing the flag.
Recon
Fetch the page and download the image:
bash read-only • copy allowedcurl -s http://31.207.77.216:4020/ | grep -i avif # <img src="/megumin-flag.avif"> curl -s -o megumin-flag.avif http://31.207.77.216:4020/megumin-flag.avif file megumin-flag.avif # megumin-flag.avif: ISO Media, AVIF Image Sequence
Key insight: the file is an AVIF Image Sequence (a 4-second, 1920x1080 animation), not a single still. Browsers lacking AVIF-sequence support only render the primary still item — exactly the "not cross-browser" symptom described.
Default decoders only emit the first frame:
bash read-only • copy allowedffmpeg -i megumin-flag.avif frame_%03d.png # -> only ONE frame (standing Megumin, no flag) avifdec megumin-flag.avif out.png # -> "BMFF parsing failed / Truncated sample table"
Analysis
The file is ISOBMFF (MP4-family). Parsing the box tree with a small Python script reveals:
ftyp— brandavifmeta—pitm(primary item id=1),iloc,iinf,iprp/ipco(ispe, pixi, av1C, colr),ipmamoov— a video track (the AVIF sequence) withmdia/minf/stbl→stsd, stts, stsc, stsz, stco, stssuuid— an XMP block with anezgif.comsoftware tag (red herring)mdat— the actual AV1 payload
The primary item (what browsers show) is located via iloc:
extent_offset = 0x0eea = 3818
extent_length = 0xbfa0 = 49056 -> bytes [3818:52874] = standing Megumin still
The trick is in the track's stsz (sample size) box:
raw stsz: 0000001c 7374737a 00000000 00000000 00000001 0000bfa0 0000b1c6
^sample_size=0 ^count=1 ^entry1 ^entry2
sample_size = 0 means per-sample sizes follow, but sample_count is faked to 1 while two entries are actually present:
- entry1 =
0x0000bfa0= 49056 (the standing still / primary item) - entry2 =
0x0000b1c6= 45510 (the hidden FLAG frame)
Cross-checking the other tables confirms two real samples:
stts: 1 entry, sample_count=2, delta=0xc8 (200)stsc: 1 chunk, 2 samples per chunkstco: single chunk offset = 0xeea = 3818
The faked stsz sample_count=1 is exactly what produces avifdec's "Truncated sample table" and makes naive decoders stop after the first frame.
Offsets line up perfectly:
sample1 @ 3818, len 49056 -> ends at 52874 (= primary item)
sample2 @ 52874, len 45510 -> ends at 98384 (= exact file size)
3818 + 49056 + 45510 = 98384 ✓
Solution
Both samples sit contiguously in mdat and each begins with an AV1 temporal-delimiter OBU (12 00). Sample 1 carries the sequence-header OBU; sample 2 is a frame-only OBU that reuses it. The reliable recovery is to dump both temporal units as one raw AV1 OBU stream and decode it:
python read-only • copy allowed#!/usr/bin/env python3 # Extract both AVIF-sequence samples from mdat as a continuous AV1 OBU stream. data = open('megumin-flag.avif', 'rb').read() # chunk offset from stco = 3818; both samples are contiguous to EOF (98384) both = data[3818:98384] # sample1 (seq header + frame) + sample2 (frame) open('both.obu', 'wb').write(both) print('wrote', len(both), 'bytes')
bash read-only • copy allowedffmpeg -i both.obu both_%03d.png -y # -> both_001.png : Megumin standing (still) # -> both_002.png : Megumin collapsed in a grassy field, flag overlaid bottom-left
both_002.png reveals the flag.
What Failed (for future solvers)
- Default
ffmpeg/avifdec/magickdecode only the first (primary) frame because of the fakedstszsample_count. - Patching
stszsample_countfrom 1 to 2 alone did not make ffmpeg emit the second frame. - Rebuilding a fresh minimal AVIF container around only the extracted second sample failed with "Error parsing OBU data" / "getNextImage() failed": sample 2 is a FRAME-only OBU (
12 00 32 ..., OBU type 6) that depends on sample 1's sequence-header OBU (0a 0b ...). - The
uuid/XMP box (ezgif.comsoftware tag) is standard metadata — a non-issue. - The winning method: concatenate both temporal units (sample1 provides the sequence header, sample2 is the dependent frame) and decode as one continuous raw AV1 OBU stream.