
Keycloak 26.8.1 Moyen 6.6 Résidu d'authentification distant authentifié. Un administrateur de help-desk disposant de manage-users peut s'attribuer un composite préconstruit de manage-realm puis lire le document complet du realm. Nécessite que ce composite existe déjà. PoC en boucle locale.
Un compte de help-desk censé uniquement réinitialiser des mots de passe et créer des utilisateurs peut s'auto-promouvoir. Une personne disposant du rôle manage-users de Keycloak trouve un intitulé de poste résiduel dans le realm (un rôle composite qui inclut discrètement manage-realm), l'épingle sur son propre compte, puis lit le document complet du realm qui lui était caché une requête plus tôt. Elle ne peut pas créer ce composite. Un véritable administrateur de realm doit l'avoir construit au préalable. Il s'agit du pendant « role-mapping » de CVE-2026-94000, qui fermait la même astuce sur le join de groupe.
Classe : Auth leftover
Portée : Distant (authentifié manage-users)
Keycloak 26.8.1 (24ed1dad) - Red Hat
| ID | pas encore de CVE |
| Classe | Auth leftover |
| Portée | Distant (Admin REST authentifié ; nécessite manage-users plus un composite préconstruit) |
| CWE | CWE-269 / CWE-266 |
| CVSS | Moyen : 6.6 CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:H/I:H/A:H |
| Produit | Keycloak |
| Affecté | 26.8.1 (24ed1dadf3f246a555adb6d3d4a99e9b3003fb3b) ; image quay.io/keycloak/keycloak:26.8.1 |
| Auth | admin délégué avec realm-management / manage-users. FGAP v2 est l'évaluateur par défaut. |
| Licence | GNU Affero GPL v3.0 |
| Lab | 127.0.0.1:18082 uniquement |
Nécessite un compte Keycloak existant qui détient déjà manage-users, ainsi qu'un rôle de realm ou de client dont le nom propre n'est pas un rôle admin et dont les composites incluent manage-realm ou realm-admin. Ne nécessite pas manage-realm sur le token. Ne peut pas créer ce composite. L'attribution directe d'un rôle nommé manage-realm / realm-admin reste refusée.
| Privilège | Méthode / sink | Recon / intégrité / disponibilité | Prouvé en lab ou déduit |
|---|---|---|---|
| Mapper un composite non-admin sur soi-même | POST /admin/realms/{realm}/users/{id}/role-mappings/realm avec l'id et le nom du composite | Intégrité (attribution de rôle) | Prouvé en lab. HTTP 204. Témoin kcr02m7q4 |
| Même attribution sur un rôle de client | POST /admin/realms/{realm}/users/{id}/role-mappings/clients/{client} | Intégrité | Source. Même canMapRole à ClientRoleMappingsResource.java:184 |
| Lire le document complet du realm avec le même token d'accès | GET /admin/realms/{realm} après le mapping | Recon | Prouvé en lab. Avant : HTTP 200 partiel (pas d'attributs, pas d'accessTokenLifespan). Après : HTTP 200 complet, attribut planté présent |
Utiliser manage-realm imbriqué sur les appels admin ultérieurs | UserAdapter.hasRole parcourt les composites ; KeycloakIdentity.hasClientRole fait confiance au modèle utilisateur | Intégrité | Déduit de la source. L'oracle du lab est le GET complet du realm |
realm-admin imbriqué lorsque c'est le composite | Même parcours | Intégrité | Déduit. Le lab a utilisé manage-realm |
| Contrôle négatif | Un second utilisateur manage-users qui ne mappe pas le composite | n/a | Prouvé en lab. Le GET de contrôle reste partiel |
Reste fermé sur ce leftover
| Axe | Méthode / sink | Pourquoi c'est fermé |
|---|---|---|
| Intégrité | Mapping direct de manage-realm / realm-admin / autre AdminRoles.ALL_ROLES | RolePermissionsV2.isRealmAdminRole refuse toujours |
| Intégrité | Créer le composite qui inclut un rôle admin | canMapComposite appelle toujours checkAdminRoles |
| Intégrité | Rejoindre un groupe dont le composite inclut un rôle admin | CVE-2026-94000 parcourt les composites dans GroupUtils.checkAdminGroupRoles |
| Intégrité | Créer un utilisateur déjà dans ce groupe | Même parcours sur UsersResource.createUser |
| Recon | Admin REST anonyme | Nécessite un token manage-users |
| Intégrité | RCE hôte, realm-admin créant realm-admin | Hors classe |
GET /admin/realms/{realm} ne renvoie pas HTTP 403 pour manage-users. Ce rôle est lui-même un rôle d'administration, donc le serveur renvoie 200 avec un document partiel. Ce qui reste correspond aux champs qui n'apparaissent qu'après le mappage du composite.
J'ai épinglé Keycloak 26.8.1. Les permissions d'administration à granularité fine v2 sont activées par défaut. RolePermissionsV2.canMapRole renvoie true pour chaque rôle qui échoue à isRealmAdminRole et ne parcourt jamais les composites. Le correctif de CVE-2026-94000 ne les parcourt que sur le chemin des groupes.
Fausses pistes déjà consignées : traiter isRealmAdminRole de la v1 comme la vérification active (la v2 la remplace) ; s'attendre à un HTTP 403 sur le GET du realm avant l'octroi (le résultat réel est un 200 partiel) ; re-déposer CVE-2026-94000 (jointure de groupe, déjà clos) ; un reverse shell. Du théâtre.
python3 keycloak-manage-users-composite-Abraxas-Labs.py
ou :
cd lab
./run.sh
Ciblez uniquement http://127.0.0.1:18082. Image quay.io/keycloak/keycloak:26.8.1. Docker requis. Le lanceur fait un chdir dans lab/ et exécute 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
Parcourir les composites dans RolePermissionsV2.canMapRole de la même manière que GroupUtils.checkAdminGroupRoles le fait déjà pour l'adhésion à un groupe. Un rôle qui inclut manage-realm ou realm-admin est un rôle d'administrateur même lorsque son propre nom ne l'est pas.
24ed1dadf3f246a555adb6d3d4a99e9b3003fb3b)RolePermissionsV2.canMapRole (RolePermissionsV2.java:59-61)RoleMapperResource.addRealmRoleMappings (RoleMapperResource.java:289-290)GNU Affero GPL v3.0. Voir LICENSE. Laboratoire en boucle locale uniquement. Aucune garantie.
Abraxas Labs [email protected]
Veuillez créditer la CVE à Abraxas Labs.