
Keycloak 26.8.1 Средний 6.6 Удалённая аутентифицированная аутентификация, оставшаяся. Администратор службы поддержки с правами manage-users может закрепить за собой заранее созданный композит manage-realm, а затем прочитать полный документ realm. Требуется, чтобы этот композит уже существовал. PoC через loopback.
Учётная запись службы поддержки, которой положено только сбрасывать пароли и создавать пользователей, может повысить собственные привилегии. Пользователь с ролью Keycloak manage-users находит в realm оставшуюся без присмотра должность (композитную роль, которая незаметно включает manage-realm), закрепляет эту должность на своей учётной записи и затем читает полный документ realm, который был скрыт от него одним запросом ранее. Создать этот композит он не может. Настоящий администратор realm должен был создать его заранее. Это «родственный» по механизму сопоставления ролей аналог CVE-2026-94000, который закрыл тот же трюк при присоединении к группам.
Класс: Auth leftover
Доступ: Удалённый (аутентифицированный manage-users)
Keycloak 26.8.1 (24ed1dad) - Red Hat
| ID | CVE пока нет |
| Класс | Auth leftover |
| Доступ | Удалённый (аутентифицированный Admin REST; требуется manage-users плюс заранее созданный композит) |
| CWE | CWE-269 / CWE-266 |
| CVSS | Средний: 6.6 CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:H/I:H/A:H |
| Продукт | Keycloak |
| Затронуто | 26.8.1 (24ed1dadf3f246a555adb6d3d4a99e9b3003fb3b); образ quay.io/keycloak/keycloak:26.8.1 |
| Аутентификация | делегированный администратор с realm-management / manage-users. FGAP v2 — оценщик по умолчанию. |
| Лицензия | GNU Affero GPL v3.0 |
| Лаборатория | только 127.0.0.1:18082 |
Требуется существующая учётная запись Keycloak, которая уже имеет manage-users, и роль realm или клиента, чьё собственное имя не является административной ролью и чьи композиты включают manage-realm или realm-admin. Не требуется manage-realm в токене. Создать этот композит невозможно. Прямое назначение роли с именем manage-realm / realm-admin по-прежнему отклоняется.
| Привилегия | Метод / точка назначения | Разведка / целостность / доступность | Доказано в лаборатории или выведено |
|---|---|---|---|
| Сопоставить неадминистративный композит самому себе | POST /admin/realms/{realm}/users/{id}/role-mappings/realm с id и именем композита | Целостность (выдача роли) | Доказано в лаборатории. HTTP 204. Свидетельство kcr02m7q4 |
| То же назначение для роли клиента | POST /admin/realms/{realm}/users/{id}/role-mappings/clients/{client} | Целостность | Исходный код. Тот же canMapRole в ClientRoleMappingsResource.java:184 |
| Прочитать полный документ realm с тем же токеном доступа | GET /admin/realms/{realm} после сопоставления | Разведка | Доказано в лаборатории. До: HTTP 200 частично (без атрибутов, без accessTokenLifespan). После: HTTP 200 полностью, внедрённый атрибут присутствует |
Использовать вложенный manage-realm в последующих административных вызовах | UserAdapter.hasRole обходит композиты; KeycloakIdentity.hasClientRole доверяет модели пользователя | Целостность | Выведено из исходного кода. Оракул в лаборатории — полный GET realm |
Вложенный realm-admin, когда именно он является композитом | Тот же обход | Целостность | Выведено. В лаборатории использовался manage-realm |
| Негативный контроль | Второй пользователь с manage-users, который не сопоставляет композит | н/д | Доказано в лаборатории. Контрольный GET остаётся частичным |
Остаётся закрытым в этом leftover
| Ось | Метод / точка назначения | Почему закрыто |
|---|---|---|
| Целостность | Прямое сопоставление manage-realm / realm-admin / других AdminRoles.ALL_ROLES | RolePermissionsV2.isRealmAdminRole по-прежнему отклоняет |
| Целостность | Создать композит, включающий административную роль | canMapComposite по-прежнему вызывает checkAdminRoles |
| Целостность | Присоединиться к группе, чей композит включает административную роль | CVE-2026-94000 обходит композиты в GroupUtils.checkAdminGroupRoles |
| Целостность | Создать пользователя, уже состоящего в этой группе | Тот же обход в UsersResource.createUser |
| Разведка | Анонимный Admin REST | Требуется токен manage-users |
| Целостность | RCE на хосте, выдача realm-admin через realm-admin | Вне класса |
GET /admin/realms/{realm} не возвращает HTTP 403 для manage-users. Эта роль сама по себе является административной ролью, поэтому сервер возвращает 200 с частичным документом. Остаток — это поля, которые появляются только после маппинга композита.
Я зафиксировал Keycloak 26.8.1. Детализированные административные разрешения v2 включены по умолчанию. RolePermissionsV2.canMapRole возвращает true для каждой роли, которая не проходит isRealmAdminRole, и никогда не обходит композиты. Исправление CVE-2026-94000 обходит их только на пути групп.
Уже зафиксированные неверные шаги: трактовка v1 isRealmAdminRole как актуальной проверки (v2 переопределяет её); ожидание HTTP 403 на GET realm до выдачи разрешения (фактический результат — частичный 200); повторная подача CVE-2026-94000 (вступление в группу, уже закрыто); обратная оболочка. Театр.
python3 keycloak-manage-users-composite-Abraxas-Labs.py
или:
cd lab
./run.sh
Цель — только http://127.0.0.1:18082. Образ quay.io/keycloak/keycloak:26.8.1. Требуется Docker. Лаунчер выполняет chdir в lab/ и запускает run.sh.
IOC image=quay.io/keycloak/keycloak:26.8.1 label-version=26.8.1
IOC serverinfo-version=26.8.1
IOC admin-composite=manage-realm
IOC limited-direct=manage-users
IOC control-direct=manage-users
IOC before-status=200 witness=0 full=0
IOC available=sneaky-composite
IOC post-status=204
IOC after-get attempt=1 status=200 witness=1 full=1
IOC control-status=200 witness=0 full=0 same-token=1
SUCCESS KC-H02-ROLEMAP kcr02m7q4
Обходите композитные роли в RolePermissionsV2.canMapRole так же, как это уже делает GroupUtils.checkAdminGroupRoles при присоединении к группе. Роль, включающая manage-realm или realm-admin, является административной ролью, даже если её собственное имя таковым не является.
24ed1dadf3f246a555adb6d3d4a99e9b3003fb3b)RolePermissionsV2.canMapRole (RolePermissionsV2.java:59-61)RoleMapperResource.addRealmRoleMappings (RoleMapperResource.java:289-290)GNU Affero GPL v3.0. См. LICENSE. Только для лаборатории с обратной петлёй. Без гарантий.
Abraxas Labs [email protected]
Пожалуйста, указывайте авторство CVE за Abraxas Labs.