Files
Tajna-tretej-stolicy/reverse-dungeon-crawler/WRITEUP.md
2026-04-22 10:58:32 +03:00

3.3 KiB
Raw Blame History

Dungeon Crawler

Reverse 888 pts

Бинарь перед нами — прототип навигационной системы для подземельного робота. Робот обязан пройти лабиринт от входа до выхода, и если маршрут верный, программа выдаёт секретный код. Формат ввода — строка из U/D/L/R. Внутри бинаря, если аккуратно поковыряться, находится сразу четыре лабиринта — три в открытом виде и один зашифрованный. Вся задача построена вокруг того, чтобы сбить с пути автоматические солверы.

Решение

Начинаем с того, что лежит на виду. В .rodata три лабиринта 20x20 в plaintext, у каждого даже есть корректный путь от входа до выхода. Подставляем — получаем мусор.

Настоящий лабиринт четвёртый, того же размера, но хранится зашифрованным. Ключ — CRC32 от конкатенации:

checkpoint_keys ‖ moving_wall_positions ‖ magic_constant

То есть чтобы его расшифровать, нужно сначала восстановить всю структуру данных, а не просто дёрнуть строку. Дальше три ловушки:

# Ловушка Как работает
1 Три plaintext-лабиринта в .rodata Все три имеют валидный путь, но ведут к неправильным ответам
2 Движущиеся стены 3 позиции меняются в зависимости от номера шага: step % 5 < 3 → открыто, иначе → закрыто
3 getpid() ^ getpid() в расшифровке флага Выглядит как PID-зависимая соль, всегда равен нулю

Вторая ловушка — самая неприятная. Если извлечь лабиринт статикой и запустить обычный BFS, правильного пути он не найдёт. BFS обязан знать текущий шаг и состояние подвижных стен именно на этом шаге.

Правильный порядок действий:

  1. Разбираем структуру данных (checkpoints + moving walls → derived key).
  2. Расшифровываем настоящий лабиринт.
  3. Гоняем BFS с учётом номера шага и состояния движущихся стен.
  4. Собираем контрольные точки по пройденному маршруту.
  5. Расшифровываем флаг через LFSR.

Флаг

caplag{3v3ry_w4ll_h4s_4_d00r}