# MMM | reverse, linux, beginner **Автор:** — ## Описание > У ворот стоит зеркало. Оно впускает лишь тех, кто идёт по одной линии со своим отражением. > Принеси печати правильное подношение. > Flag format: `ctfcup{[0-9a-f]+}` ## Деплой Не требуется. ## Выдать участникам Только [public/mmm.zip](public/mmm.zip). ## Идея Простой реверс на линейную алгебру. Бинарник на C++ без защит, с символами. Принимает флаг аргументом командной строки и проверяет его двумя функциями: - `check` — сверяет длину строки (40 байт), умножает вектор из байтов строки на целочисленную матрицу 40x40 из `.rodata` и проверяет, что результат коллинеарен исходному вектору (все миноры 2x2 равны нулю). То есть строка должна быть собственным вектором матрицы. Собственное значение в бинарнике нигде не хранится. - `hash_check` — считает SHA-256 от строки и сравнивает с эталонным дайджестом. Матрица строится как `λ·I + U·Wᵀ`, где столбцы `W` ортогональны вектору флага и порождают его ортогональное дополнение, а `U` имеет полный столбцовый ранг. Поэтому собственное подпространство для `λ` одномерно и целиком задаётся флагом. Исходники и генератор параметров лежат в [src/](src/): `gen.py` генерирует `params.h`, сборка через CMake. Раздаточный бинарник собирается в чистом Debian-контейнере скриптом [src/build.sh](src/build.sh), который обновляет `public/mmm.zip`. Обёртка [build_public.sh](build_public.sh) просто вызывает его. ## Решение Открываем бинарник, находим `check`: цикл умножения матрицы на вектор и проверка `y[i]*v[j] == y[j]*v[i]` — это коллинеарность, значит ищем собственный вектор матрицы. Вытаскиваем матрицу из `.rodata` (символ `MATRIX`, 40x40 `int64`), считаем собственные числа через numpy, берём вещественное целое собственное значение (1337) и его собственный вектор. Нормируем так, чтобы первая координата стала `ord('c')`, округляем — получаем байты флага. `hash_check` нужен лишь для подтверждения, SHA-256 от полученной строки совпадает с эталоном. [solve/solve.py](solve/solve.py) ## Флаг ``` ctfcup{99aeaf6c1fb1d156e4194be638825e6f} ```