Головоломка «Test My Patience» от Check Point Security Academy
Я несколько раз упоминал на Хабре программу «Check Point Security Academy»: суть её в том, что фирма Check Point летом объявила конкурс в формате «Capture the Flag», где не важен прошлый опыт участника, а важны только его способности к распутыванию кибер-головоломок. По результатам этого конкурса фирма набрала двадцать участников на трёхмесячный профессиональный курс по кибер-безопасности, и все участники с самого начала курса получают полную зарплату специалиста по КБ, под обязательство отработать в фирме два года после окончания курса.
В соревновании CTF флаг может быть даже картинкой, например такой.
Отбор участников завершился в августе, но сайт конкурса продолжит действовать до следующего лета, и я приглашаю желающих зарегистрироваться и попробовать свои силы ради спортивного интереса. Конкурс состоит из 12 головоломок различной сложности, оцененных от 10 до 150 очков.
Здесь я хочу разобрать головоломку «Test My Patience» из категории «Surprise». Она средней сложности (50 очков), и вот её полный текст:
Hi there,
We found This executable on the local watchmaker’s computer.
It is rumored that somehow the watchmaker was the only person who succeeded to crack it.
Think you’re as good as the watchmaker?
Note: This file is not malicious in any way
По ссылке — 32-битный бинарник для Windows, на который ругаются некоторые антивирусы, но если его всё же запустить, то выглядит он так:
Внутри бинарник зашифрован; запускаться под отладчиком он отказывается; если к нему к запущенному попытаться подключить отладчик — он моментально завершается. Вероятно, специалисты из Check Point обернули свою головоломку в крипто-пакер, позаимствованный у какой-то малвари.
Как же будем угадывать число, загаданное часовщиком?
Есть два способа. Первый можно условно назвать «сила есть, ума не надо»: если программу нельзя отлаживать вживую — значит, будем отлаживать мёртвую!
Запускаем 32-битный «Диспетчер задач» (\Windows\SysWOW64\taskmgr.exe), кликаем по загадочному процессу правой кнопкой, и выбираем Create dump file. (64-битный «Диспетчер задач» для 32-битных процессов создаёт дамп эмулятора wow64cpu, с которым работать сложнее.)
Заглядываем в дамп и видим, что как минимум, строки в нём уже расшифрованы:
Но строк ни с загаданным числом, ни с флагом пока не видно.
Переходим к орудию главного калибра: WinDbg (X86) → Open Crash Dump…
Где в памяти та строка, которую мы хотим увидеть напечатанной — «Good job my friend!»?
Команда lm
позволяет определить, что бинарник загружен от 01140000
до 015b2000
; затем s-a 01140000 015b2000 "Good job my friend!"
находит искомую строку по адресу 0115a0d0
:
Давайте теперь найдём, где эта строка печатается: может, в какой-нибудь команде содержатся байты d0 a0 15 01
, соответствующие адресу искомой строки? (s-b 01140000 015b2000 d0 a0 15 01
)
Удача! — такая команда нашлась:
Что за код вокруг этой команды? (ub 011412f7; u 011412f7
)
Видим, что в зависимости от результата функции 01141180
печатается либо искомое сообщение, либо «Wrong one…»
Код функции 01141180
занимает три экрана; довольно легко понять, что это реализация strcmp()
, внутрь которой добавлен вызов Sleep(700)
. Пока непонятно, зачем там Sleep()
;, но на результат функции это всё равно не влияет, так что лучше разберёмся, что за строки сравниваются:
Передаются два указателя, равные ebp-14h
и ebp-24h
; второй из них перед этим передавался аргументом в функцию 011410b0
.
Не та ли эта функция, которая запрашивает загаданное число? Проверим по стеку вызовов (k
):
Да, это именно она!
Общая схема головоломки теперь ясна: догадка пользователя сохраняется по адресу ebp-24h
, загаданное число — по адресу ebp-14h
, потом они сравниваются, и печатается либо «Good job my friend!», либо «Wrong one…»
Всё, что осталось — вытащить загаданное число из стекового фрейма. Его ebp
нам уже известен из стека вызовов:
Ну-ка, ну-ка…
Успех! Можно откупоривать что-нибудь вкусное.
Но остались без объяснения три загадочные вещи:
- Зачем внутри здешней
strcmp()
вызовSleep(700)
? - Почему, когда мы ввели загаданное число, программа подвисла на десяток секунд, прежде чем напечатала «Good job my friend!»?
- Какое отношение ко всей этой головоломке имеет часовщик?
Так вот, оказывается, что есть второй — более интеллектуальный — способ отгадать загаданное число. Если просто пробовать наугад цифры 0–9, то легко заметить, что на девятке программа немножко «подвисает». Если пробовать числа 90–99, то можно заметить, что на числе 98 программа «подвисает» вдвое надольше. (Расковыряв её потроха, мы уже понимаем, в чём дело: успешное сравнение каждой пары символов вызывает задержку на 0.7с.) Чтобы решить головоломку, даже не запуская отладчик, достаточно было подбирать каждую следующую цифру так, чтобы задержка до ответа увеличивалась — либо вручную с точным секундомером, либо несложным скриптом. Таким образом составители намекали на давний способ атаки на криптографические алгоритмы, когда замеряется и анализируется время до сообщения об ошибке.
Но научиться расковыривать программы, обёрнутые неизвестными крипто-пакерами — на мой взгляд, и интереснее, и ценнее:-)
Заметьте, что нам не потребовалось разбираться ни каким образом бинарник зашифрован, ни каким образом в стеке появляется строка с загаданным числом (мы видели в дампе, что среди строковых констант её нет) — и то, и другое мы сумели получить готовым, причём на всё про всё хватило дюжины команд WinDbg.