Решение задания "Reverse-ing" с TSG CTF 2020.
https://t.me/hacker_sanctuary
На прошедших выходных можно было поиграть в "TSG CTF 2020".
Соревнования были организованы командой TSG из Японии.
Официальный сайт мероприятия - https://score.ctf.tsg.ne.jp/
Ссылка на событие - https://ctftime.org/event/1004
На соревнование были представлены задания из стандартных категорий и сложность была высокой.
В данном посте разберём задание "Reverse-ing" из категории Reverse.
К заданию.

Задача была не очень сложной и с ней справилось много команд. В целом она похожа на разминочную, но сделана интересно.
Скачиваем файл и получаем исполняемый файл всего с двумя функциями.

Посмотрим на функцию reverse.

Всё что делает эта функция - это меняет байты местами, но есть один нюанс. Она меняют из в секции кода, таким образом модифицирую код во время выполнения.
Попробуем остановиться сразу на первом вызове функции.

Сразу после вызова reverse мы меняем большую часть кода и уже в момент возвращения из reverse попадаем на другой код.

Как можно увидеть - новый код выполняет одну инструкцию и опять вызывает функцию reverse, которая вернёт привычный порядок. Таким образом у нас получается всего два активных состояния секции кода.
Мы можем выписать весь код из этих двух состояний и соединить его в один.

В начале мы читаем 0x25 символов с клавиатуры с помощью системного вызова read. После этого мы попадаем в цикл с двумя простыми шагами.
Шаг 1 - взять очередной символ введённой строки и выполнить XOR с некоторой константой, после чего добавить ещё одну константу.
Шаг 2 - взять следующий символ и выполнить те же действия, в том же порядке, но места от куда берутся константы будут поменяны.
Константы обозначены как vals1 и vals2. Мы можем вытащить их также во время отладки исполняемого файла.

Теперь посмотрим на условие вывода "correct".

Прыжок произойдёт, если на момент операции "dec rdi" в регистре rdi был ноль. В данном регистре хранится результат операции "or" со всеми результатами преобразования флага.

То есть надо чтобы на каждом шаге при выполнении этой операции получался 0. Это можно получить только если результат преобразования символа пароля будет 256 (т.к. младший байт будет равен нулю). Попробуем выполнить это условие и подобрать необходимые символы с помощью Python.

Запустим и получим флаг.

Вот такое простое задание на реверс само-модифицирующегося кода.