Мозаика внутри PNG (Mosaic inside PNG)
Мозаика внутри PNG (Mosaic inside PNG)
Platform: bug-makers | Category: Steganography | Type: Challenge | Difficulty: Easy | OS: NA | Author: XESXOR | Date: 2025-10-04 | Status: Solved Techniques: png_chunk_enumeration, ancillary_chunk_reassembly, chunk_order_steganography
Summary
Task: a 1000x1000 PNG that hides data in custom ancillary chunks rather than pixels. Solution: enumerate all PNG chunks, find 100 private pTNN chunks scattered around IDAT, reassemble them in numeric order to recover flag instructions split across chunks 49, 50, 76 and 99.
Мозаика внутри PNG (Mosaic inside PNG) — Bug Makers CTF
Description
Мозаика внутри PNG. «Я по частицам собираю твой портрет». Подсказок и так слишком много, флаг где-то в файле.
Translation: "Mosaic inside PNG. 'I assemble your portrait from particles.' There are already too many hints, the flag is somewhere in the file."
Provided artifact: dabro_bro.png — a 1000x1000, 8-bit RGB, non-interlaced PNG.
Goal: recover the flag hidden somewhere inside the file.
Semantic Clues
The wording matters and points directly at the technique:
- "Мозаика" (mosaic) and "по частицам собираю" (assemble from particles) — the data is split into many small pieces that must be reassembled in order.
- "Подсказок слишком много" (too many hints) — there are a large number of embedded fragments.
These clues steer away from pixel-level LSB and toward structural fragmentation of the file.
Recon
Standard stego recon produced negative results worth recording:
file/exiftool— confirm a plain 1000x1000 RGB PNG, nothing unusual in metadata.binwalk— no appended data, no embedded archive trailer.zsteg— no LSB payload across any channel/bit-plane.
strings was the first thing to leak useful fragments:
First part of your flag is 'y0u_h4ve_
Second part is 'REDACTED'
ts of the flag into 'bUgCtF{}'
four parts: len
So the flag text exists in the file as readable strings, but it is scattered — the fragments do not appear contiguously. This matches the "mosaic / particles" hint.
Key Insight: Custom pT Chunks as Mosaic Tiles
A PNG is a sequence of chunks after the 8-byte signature. Each chunk is:
[4-byte big-endian length][4-byte type][data...][4-byte CRC]
Enumerating the chunks manually reveals 100 custom ancillary chunks named pT00 through pT99. They are scattered both before and after the IDAT chunks — not in any natural order. These are the "particles" of the mosaic, and the numeric index in the chunk type encodes the reassembly order.
zsteg and binwalk miss this entirely: there is no LSB embedding and no appended trailer. The trick lives purely at the PNG chunk-structure level, in custom private chunk names and their ordering.
Solution
Parse the PNG chunk stream, collect every pTNN payload keyed by the integer NN, then print them in numeric order 0..99. Reassembled, they form a Wikipedia-style article about the PNG file-format structure, with the flag instructions embedded in specific chunks.
python read-only • copy allowed#!/usr/bin/env python3 import struct data = open('dabro_bro.png', 'rb').read() off = 8 # skip the 8-byte PNG signature chunks = {} while off < len(data): ln = struct.unpack('>I', data[off:off+4])[0] typ = data[off+4:off+8].decode('latin1') payload = data[off+8:off+8+ln] if typ.startswith('pT'): chunks[int(typ[2:])] = payload if typ == 'IEND': break off += 12 + ln # 4 (len) + 4 (type) + ln (data) + 4 (CRC) for i in range(100): print(i, chunks.get(i, b''))
The instructive chunks:
- Chunk 49:
First part of your flag is 'y0u_h4ve_ - Chunk 50:
c0l1ected'→ first part =REDACTED - Chunk 76:
Second part is 'REDACTED' - Chunk 99:
wrap the parts of the flag into 'bUgCtF{}'
Misdirection
The text mentioning "four parts: len..." refers to the PNG chunk anatomy (length, type, data, CRC), not to four flag parts. Don't over-split the flag — it has two text segments joined inside the wrapper.
Assembling: bUgCtF{ + REDACTED + REDACTED + }.