Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Всех, кто использует относительно новые версии Java-фреймворка Oracle, в минувшую среду ждал неприятный сюрприз. Исследователь из компании ForgeRock Нил Мэдден сообщил о критической уязвимости в Java, которая позволяет злоумышленникам легко подделывать сертификаты и подписи TLS, сообщения двухфакторной аутентификации и учетные данные авторизации. Эксперт опубликовал в сети подробное описание уязвимости, с основными тезисами которого мы сегодня хотим тебя познакомить.
Хронология событий
Нил Мэдден обнаружил эту ошибку в OpenJDK еще 11 ноября 2021 года и сразу же сообщил о ней в Oracle. 18 ноября разработчик подтвердил наличие проблемы и пообещал добавить исправление в следующее критическое обновление безопасности, которое вышло 19 апреля 2022 года. В этот же день ForgeRock опубликовал отчет с описанием уязвимости.
В популярном британском телесериале «Доктор Кто» есть повторяющийся сюжет: главный герой с успехом выпутывается из различных неприятностей, показывая окружающим совершенно пустой документ, изготовленный из специальной «психобумаги». Эта бумага заставляет смотрящего на нее человека видеть то, что хочет продемонстрировать ему владелец артефакта: пропуск, удостоверение полицейского, судебный ордер или что‑то иное. Схожим образом работает уязвимость, обнаруженная в нескольких недавних выпусках Java, вернее, в механизме широко используемого алгоритма с открытым ключом для создания цифровых подписей ECDSA. Этой уязвимости, получившей обозначение CVE-2022-21449, подвержены версии Java 15, 16, 17 и 18, вышедшие до критического обновления от апреля 2022 года. Кроме того, в официальном сообщении Oracle также упоминаются более старые версии Java, включая 7, 8 и 11. С другой стороны, в рекомендациях OpenJDK перечислены только версии 15, 17 и 18, затронутые этой конкретной уязвимостью.
С использованием CVE-2022-21449 злоумышленники могут легко подделать некоторые типы SSL-сертификатов и SSL-рукопожатий, что, в свою очередь, позволяет перехватывать и изменять сообщения. Кроме того, становится возможной подмена подписанных JSON Web Tokens (JWT), данных SAML, токенов идентификации OIDC и даже сообщений аутентификации WebAuthn. Фактически это и есть полный аналог киношной «психобумаги», только в электронной форме.
Серьезность этой проблемы трудно недооценить. Если ты используешь подписи ECDSA для любого из перечисленных механизмов безопасности, а на сервере установлена уязвимая версия Java, злоумышленник может без труда обойти эти механизмы. В реальности почти все устройства WebAuthn/FIDO (включая Yubikeys) используют подписи ECDSA, а многие поставщики OIDC — токены JWT, подписанные тем же методом.
Oracle присвоила этому CVSS оценку 7,5 балла, посчитав, что уязвимость не оказывает серьезного влияния на конфиденциальность или доступность данных, однако исследователи из ForgeRock оценили проблему в 10 баллов из‑за широкого спектра воздействий на различные функции в контексте управления доступом. Как же все‑таки работает уязвимость CVE-2022-21449? Чтобы разобраться, необходимо немного углубиться в теорию.
ECDSA расшифровывается как алгоритм цифровой подписи на эллиптических кривых (Elliptic Curve Digital Signature Algorithm) и широко используется в качестве стандарта для подписи всех видов цифровых документов. По сравнению со старым стандартом RSA ключи и подписи на основе эллиптической криптографии имеют намного меньшие размеры в байтах, но при этом обеспечивают эквивалентную безопасность, в результате чего они применяются в тех случаях, когда размер имеет большое значение. Например, стандарт WebAuthn для двухфакторной аутентификации позволяет производителям устройств выбирать из широкого спектра алгоритмов создания подписи, но на практике почти все произведенные на сегодняшний день устройства поддерживают только ECDSA (заметным исключением является разве что Windows Hello, которая использует RSA, предположительно для совместимости со старым оборудованием TPM).
Не вдаваясь в технические детали, можно сказать, что подпись ECDSA состоит из двух значений, называемых r
и s
. Чтобы проверить такую подпись, верификатор решает уравнение, включающее значения r
, s
, открытый ключ подписавшего и хеш сообщения. Если две части уравнения равны, подпись считается действительной, в противном случае она отклоняется.
Одна часть уравнения должна быть равна r
, а другая часть умножается на r
и значение, полученное из s
. Очевидно, было бы очень плохо, если бы r
и s
оказались равны 0, потому что тогда мы проверяли бы равенство 0 = 0 ⨉ [куча вещей], которое будет истинным независимо от значения «кучи вещей». Притом что эта самая «куча вещей» — важные данные, такие как сообщение и открытый ключ. Вот почему самая первая проверка в алгоритме ECDSA выполняется с целью удостовериться, что значения r
и s
>= 1.
Догадайся, какую проверку забыли в Java? Бинго: валидатор подписи ECDSA в Java не проверял, равны ли r
или s
нулю, поэтому ты при желании можешь создать подпись с нулевыми значениями этих параметров. Тогда Java примет такую подпись для любого сообщения или публичного ключа как действительную.
Вот интерактивный сеанс JShell, показывающий реализацию этой уязвимости, — здесь используется абсолютно пустая подпись, которая принимается в качестве действительной:
| Welcome to JShell -- Version 17.0.1
| For an introduction type: /help intro
jshell> import java.security.*jshell> var keys = KeyPairGenerator.getInstance("EC").generateKeyPair()keys ==> java.security.KeyPair@626b2d4a
jshell> var blankSignature = new byte[64]
blankSignature ==> byte[64] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... , 0, 0, 0, 0, 0, 0, 0, 0 }jshell> var sig = Signature.getInstance("SHA256WithECDSAInP1363Format")sig ==> Signature object: SHA256WithECDSAInP1363Format<not initialized>
jshell> sig.initVerify(keys.getPublic())jshell> sig.update("Hello, World".getBytes())jshell> sig.verify(blankSignature)$8 ==> true// Oops, that shouldn't have verified...
Квалификатор InP1363Format
упрощает демонстрацию ошибки. Подписи в формате ASN.1 DER могут использоваться таким же образом: просто сначала нужно немного повозиться с кодировкой. Но обрати внимание, что JWT и другие стандарты применяют необработанный формат IEEE P1363.
Источник: xakep.ru