Уязвимость в библиотеке с базовой реализацией алгоритма SHA-3

В реализации криптографической хэш-функции SHA-3 (Keccak), предлагаемой в пакете XKCP (eXtended Keccak Code Package), выявлена уязвимость (CVE-2022-37454), которая может привести к переполнению буфера в процессе обработки определённо оформленных данных. Проблема вызвана ошибкой в коде конкретной реализации SHA-3, а не уязвимостью в самом алгоритме. Пакет XKCP преподносится как официальная реализация SHA-3, развивается при участии команды разработчиков Keccak и используется в качестве основы в функциях для работы с SHA-3 в различных языках программирования (например, код XKCP используется в Python-модуле hashlib, Ruby-пакете digest-sha3 и PHP-функциях hash_*).

По заявлению исследователя, выявившего проблему, ему удалось использовать уязвимость для нарушения криптографических свойств хэш-функции и нахождения первого и второго прообраза, а также определения коллизий. Кроме того, заявлено о создании прототипа эксплоита, позволяющего добиться выполнения кода при вычислении хэша специально оформленного файла. Потенциально уязвимость также может быть использована для атак на алгоритмы проверки цифровых подписей, использующих SHA-3 (например, Ed448). Подробности методов проведения атак планируется опубликовать позднее, после повсеместного устранения уязвимости.

Насколько уязвимость затрагивает существующие приложения на практике пока не ясно, так как для проявления проблемы в коде должно применяться цикличное вычисление хэша блоками и один из обрабатываемых блоков должен иметь размер около 4 ГБ (не менее 2^32 – 200 байт). При обработке входных данных разом (без последовательного вычисления хэша частями) проблема не проявляется. В качестве наиболее простого метода защиты предлагается ограничить максимальный размер данных, участвующих в одной итерации вычисления хэша.

Уязвимость вызвана ошибкой при блочной обработке входных данных. Из-за некорректного сравнения значений с типом “int” определяется неверный размер ожидающих обработки данных, что приводит к записи хвоста за пределы выделенного буфера. В частности, при сравнении использовалось выражение “partialBlock + instance->byteIOIndex”, которое при больших значениях составных частей приводило к целочисленному переполнению. Кроме того, в коде присутствовало неверное приведение типов “(unsigned int)(dataByteLen – i)”, приводившее к переполнению на системах с 64-разрядным типом size_t.

Пример кода, приводящего к переполнению:

Release. Ссылка here.