[Cryptohack]ECB Oracle

0awawa0
3 min readSep 1, 2020

Решение задания ECB Oracle с сайта cryptohack.org

Задание выглядит так:

Есть исходный код и всё, что мы можем — это передать в него какой-то открытый текст для шифрования. В коде видим, что тот текст, который мы присылаем, склеивается с флагом и зашифровывается, а мы получаем шифротекст. Уязвимость здесь заключается в том, что мы можем управлять частью открытого текста. Манипулируя этой частью, мы можем расшифровать неизвестную нам часть(FLAG) без ключа.

Как это работает?

Вот так выглядит блок входных данных, если мы не передаём ничего для шифрования:

То есть все 16 байт текста нам не известны. Однако, мы можем дополнить этот блок данных 15 известными нам значениями:

И теперь мы не знаем только один байт шифротекста. Что это нам даёт? Мы можем отправить 15 байт известных нам, блок дополнится одним байтом, который мы не знаем. После этого мы запоминаем полученный шифротекст(C1) и дальше отправляем на сервер уже 16 байт. Но последний, 16-й, будем перебирать до тех пор, пока полученный шифротекст(C2) не совпадёт с C1.

Если шифротексты совпали, то мы нашли правильный байт открытого текста.

Отлично, теперь мы знаем первый байт. Как получить остальные? Да точно также. Только теперь отправим на сервер не 15 байт, а 14.

Сервер дополнит блок двумя байтами из флага. Но один из этих байт мы уже знаем, поэтому запоминаем полученный шифротекст, а дальше будем отправлять на сервер 14 байт нулей, 15 байт — известный нам (P1), и 16 байт также перебираем.

И снова когда шифротексты совпадут, значит мы нашли следующий байт.

Таким образом мы расшифровываем целый блок текста. Но, судя по длине шифротекста, флаг занимает больше, чем 1 блок. Так, когда мы отправляли один байт, мы получали 32 байта шифротекста. Значит нужно будет расшифровывать и второй блок.

Мы поступим следующим образом. Будем отправлять изначально 32 байта вместо 16 и запоминать сразу первый и второй блоки:

Дальше будем просто убирать по одному байту, также как мы делали для одного блока, и перебирать 32 байт:

Таким образом мы сможем получить оба блока данных. На получение флага у нас уйдёт в худшем случае 256 * 32 =8192 запроса к серверу.

Пишем скрипт

Совершенно очевидно, что делать 8 тысяч запросов вручную нам не хочется. Значит надо писать скрипт. Подробный разбор кода я прилагать не буду. В целом скрипт полностью соответствует тому, что я описал выше. Но, так как флаг — это некая строка символов, то перебирать все 256 значений для каждого байта нет необходимости, нам нужно перебрать только 95 печатных символов. Таким образом количество запросов значительно снижается.

И ещё, большинство строчек(а в частности всё, что начинается с stdscr и curses) в скрипте можно удалить, так как они касаются только красивого вывода информации на экран:

Код скрипта:

--

--