Райтап на задачу «Мозаика внутри PNG»

musa2ap

Автор:

musa2ap

7 ноября 2026

11

07.11.2026
Мозаика внутри PNG
Категория:

Stegano

Задача «Мозаика внутри PNG»

AlexB

Автор:

AlexB

Первая кровь:
broken_reality
Сложность:
medium
Дата публикации:
04.10.2025
Решений:
110
Рейтинг:
4.37/5
Ссылка:
Решать

Смотрим файл

Сначала открываем картинку. Внешне это обычное фото группы Dabro размером 1000 × 1000, но файл весит почти 1,2 МБ. Сигнатура PNG на месте, однако Pillow отказывается открывать файл с ошибкой cannot identify image file. Значит, дело не в пикселях, а в структуре файла.

Мозаика внутри PNG: Изображение Dabro из файла задачи

Открываем файл в hex-редакторе. После сигнатуры и IHDR идут чанки с именами pT69, pT01, pT06… По спецификации имя чанка — четыре ASCII-буквы, а здесь в имени стоят цифры. Из-за этого строгие парсеры и не читают файл. Всего внутри 139 чанков: IHDR, 37 × IDAT, IEND и 100 кастомных pT00…pT99.

Мозаика внутри PNG: Нестандартные pT-чанки PNG в hex-редакторе

Каждый чанк устроен просто: 4 байта длины, 4 байта имени, данные и 4 байта CRC. У всех pT-чанков CRC посчитан только от данных, без имени чанка, поэтому некоторые утилиты дополнительно считают файл битым. На извлечение это не влияет.

Собираем мозаику

Чанки pT лежат в файле в перемешанном порядке: pT69, pT01, pT06, pT56, pT74, pT99… А после каждого есть текст, который разбросан кусками. Так как номера чанков у нас даны, попытаемся отсортировать их лёгким скриптом на Пайтоне и посмотреть текст, который получится.

import struct

data = open("dabro_bro.png", "rb").read()

pos = 8
pts = {}
while pos < len(data):
    length = struct.unpack(">I", data[pos:pos + 4])[0]
    name = data[pos + 4:pos + 8].decode("latin1")
    if name.startswith("pT"):
        pts[name] = data[pos + 8:pos + 8 + length]
    pos += 12 + length

# вся склейка — вот здесь:
text = b"".join(pts["pT%02d" % i] for i in range(100)).decode("utf-8")

print(text)

first = text.split("First part of your flag is '")[1].split("'")[0]
second = text.split("Second part is '")[1].split("'")[0]
print("Флаг: bUgCtF{%s%s}" % (first, second))

Запускаем:

Мозаика внутри PNG: Результат склейки фрагментов текста и найденный флаг
Если вы нашли опечатку или ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter

Также по теме:

Райтап на задачу «Edit from planes»

/Разборы задач

Райтап на задачу «Edit from planes»

Разбираем видео на кадры, исследуем младшие биты изображений и находим спрятанный флаг.
Прочитать

11

Райтап на задачу «Немое кино»

/Разборы задач

Райтап на задачу «Немое кино»

Изучаем строки MP4-файла и собираем скрытую строку Base64 с флагом.
Прочитать

24