/Разборы задач
5 ноября 2026
Райтап на задачу «Огрызок»
Определяем компактный формат Micro QR и считываем флаг с обрывка листа.3
9

Misc
Задача «Тяжелый сценарий»
Скачаем архив и посмотрим что внутри. Мы сразу видим кучу непонятных файлов, будто текстур. Попробуем найти, что это за формат.
Находим файл chart.bme.
Видимо, этот файл и объединяет в себе все те сотни файлов. Загуглим, что это.
Оказывается, что у этого формата есть даже статья на Википедии. Это формат нотных чартов для ритм-игр семейства Beatmania IIDX. Занимательно.
Можно долго крутить стегу в картинках и мучить aperisolve, можно долго искать всякое в спектрограмме WAV-файлов, но, к сожалению, это не приведёт ни к чему. Может, попробуем сыграть? Для этого подойдёт любой сайт, например bemuse.ninja, который умеет читать этот формат.
Вдоволь наигравшись, вернёмся к этому файлу. Попробуем его почитать и проанализировать.
Прокрутим список #WAV в самый конец. Там будут достаточно подозрительные строки:
Попробуем найти оригинальные файлы этого Ascension to Heaven от автора xi. Скачиваем с archive.org — и действительно, там нет никаких ZV-сигналов. Копаем дальше.
Эти ноты образуют какие-то фигуры, что если в них закодированы буквы? Например, если они что-то отображают?
Вспомним, что представляет из себя сама игра — двумерную плоскость, где 5 столбцов по горизонтали (дорожки клавиш) и строки по вертикали. Строка ZVZVZVZVZVZVZV00 состоит из 16 символов, то есть 8 «шагов».
Возьмём как t — номер шага. t = 0 — берём первые пары из каждой строки (каналы 12-18). t = 1 — берём вторые и т. д. Составим таблицу.
А теперь давайте закрасим ненулевые значения чёрным цветом, чтобы выделялось.
Ничего не напоминает? Это ведь буква B. Первая буква флага. Вот так каждый такт превращается в букву.
Теперь остаётся дело за малым — написать Python-скрипт для парсинга этого файла и вывода букв.
CHANNELS = ["12", "13", "14", "15", "18"]
SIGNALS = {"ZV", "ZW", "ZX", "ZY", "ZZ"}
measures = {}
with open("chart.bme.txt", "r", encoding="utf-8", errors="ignore") as f:
for line in f:
if line.startswith("#") and ":" in line:
tag, data = line.strip().split(":", 1)
meas = tag[1:4]
chan = tag[4:6]
if chan in CHANNELS and any(s in data for s in SIGNALS):
if meas not in measures:
measures[meas] = {}
# Режем hex строку на пары по 2 символа
measures[meas][chan] = [data[i:i+2] for i in range(0, len(data), 2)]
for meas in sorted(measures):
grid = []
for t in range(7, -1, -1):
row = ""
for ch in CHANNELS:
tokens = measures[meas].get(ch, [])
note = tokens[t] if t < len(tokens) else "00"
row += "#" if note in SIGNALS else "."
grid.append(row)
# Убираем пустые строки сверху и снизу
while grid and grid[0] == ".....":
grid.pop(0)
while grid and grid[-1] == ".....":
grid.pop()
print(f"[{meas}]")
for row in grid:
print(row)
print()
Запускаем скрипт — и остаётся только прочитать флаг: