Райтап на задачу «CTF-ер, который смог»

musa2ap

Автор:

musa2ap

6 ноября 2026

17

06.11.2026
CTF-ер, который смог
Категория:

Forensic

Задача «CTF-ер, который смог»

AlexB

Автор:

AlexB

Первая кровь:
3T0T_FL4G_1MB4
Сложность:
medium
Дата публикации:
08.11.2025
Решений:
64
Рейтинг:
4.5/5
Ссылка:
Решать

— Пейн, я не чувствую центральной директории!

— Буба, у тебя её нет!

Из условия задачи получаем подсказку: центральная директория — это «центральный каталог» формата ZIP, по сути, оглавление, лежащее в конце файла.

Пробуем переименовать Bubba в Bubba.zip и пробуем открыть:

Проводник, 7-Zip, WinRAR говорят, что архив повреждён либо у него неверный формат.

Но данные-то внутри остались. Надо достать их ручками.

Сигнатуры (байты), которые нам сто процентов пригодятся:

  • 50 4B 03 04 — локальный заголовок файла;
  • 50 4B 07 08 — data descriptor, размеры после данных;
  • 50 4B 01 02 — запись центрального каталога;
  • 50 4B 05 06 — конец центрального каталога, EOCD.

Смотрим файл в hex-редакторе

Открываем Bubba в HxD. Первое, что видим:

Решение задачи «CTF-ер, который смог»: иллюстрация 1

Мы ожидали 50 4B 03 04 — начало локального заголовка ZIP. А тут 66 69 66 75 78 = fifux.

Смотрим конец файла:

Решение задачи «CTF-ер, который смог»: иллюстрация 2

Вот он, 50 4B 07 08 — data descriptor. Разбираем его поля:

  • Сигнатура 50 4B 07 08 — PK\x07\x08 (синий);
  • CRC32 B7 85 1A AD — 0xAD1A85B7 (красный);
  • Сжатый размер 2A DE 03 00 — 253 482 (фиолетовый);
  • Несжатый размер 27 F6 .. — обрезан (зелёный): в файле не хватает последних 2 байт. Это нам не мешает, так как наш сжатый размер полностью цел.

Теперь желательно дополнительно пройтись по всему файлу и посмотреть, сколько раз встречается каждая сигнатура (удобнее через встроенный поиск, не забудьте поменять со строки на hex-значение):

  • 50 4B 03 04 — 0;
  • 50 4B 01 02 — 0;
  • 50 4B 05 06 — 0;
  • 50 4B 07 08 — 1, его мы уже находили.

То есть заголовки и оглавление кто-то «снёс», а дескриптор в конце остался. Именно он даёт нам зацепку.

Логика простая: data descriptor идёт сразу после сжатых данных. Значит, начало данных — это позиция дескриптора минус сжатый размер:

data_start = descriptor_offset − csize = 253517 − 253482 = 35 (0x23)

Схема расположения:

Проверяем по hex: по смещению 0x23 (= 35) действительно начинаются байты 9C BB 69 58 52 6B ... — это уже похоже на сжатый поток (никакого 78 9C, как и должно быть в ZIP).

Теперь нужно распаковать raw deflate. Для этого берём байты с offset 35 до дескриптора (ровно 253 482 байта) и распаковываем.

import zlib
d = open('Bubba', 'rb').read()
i = d.rfind(b'PK\x07\x08')          # позиция дескриптора
csize = int.from_bytes(d[i+8:i+12], 'little')
start = i - csize
raw = zlib.decompress(d[start:i], -15)   # -15 = raw deflate
open('bubba.jpg', 'wb').write(raw)
print(start, csize, len(raw))

С помощью скрипта мы получаем вывод, где FF D8 FF E0 — сигнатура JPEG:

start = 35
packed = 253482
unpacked = 259623
первые байты = FF D8 FF E0

Открываем bubba.jpg, записываем флаг и ставим 5 звёзд таску за хороший фильм:

Решение задачи «CTF-ер, который смог»: иллюстрация 3
Если вы нашли опечатку или ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter

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

Райтап на задачу «Слив флагов»

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

Райтап на задачу «Слив флагов»

Исследуем WIM-образ через 7-Zip, находим альтернативный поток flag_404.txt и декодируем спрятанную строку Base64.
Прочитать

8

Райтап на задачу «CTF-ер, который смог»

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

Райтап на задачу «CTF-ер, который смог»

Исследуем повреждённый ZIP в HxD и восстанавливаем изображение с помощью Take bytes и Raw Inflate в CyberChef.
Прочитать

6