Skip to content
KitploitKITPLOIT
工具漏洞利用博客
Log in
提交
工具漏洞利用博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

订阅源联系隐私© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
KeycloakESC — 可复现的 Docker 实验环境 + PoC:通过复合角色实现 Keycloak manage-users -> realm-admin 权限提升(CVE-2026-94000 变体)。已在 26.8.1 上验证。 | Kitploit
工具/GitHubGitHub/secfathy/keycloakesc
身份验证与授权权限提升漏洞分析漏洞利用Web应用程序漏洞利用渗透测试身份与访问管理 (IAM)实验室与实践
GitHubsecfathy/keycloakesc

KeycloakESC

可复现的 Docker 实验环境 + PoC:通过复合角色实现 Keycloak manage-users -> realm-admin 权限提升(CVE-2026-94000 变体)。已在 26.8.1 上验证。

查看仓库
313天前尚未审核

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

Keycloak 复合 map-role 权限提升

一个可复现的 Docker 实验环境和 PoC,用于演示 Keycloak 管理 REST API 中的一条权限提升路径:一个仅持有 manage-users 的委派管理员可以通过映射一个复合角色,将自身(或任意用户或组)提升为完整的 realm-admin,该复合角色的名称很普通,但其子角色包含 realm-management/realm-admin。

已针对官方镜像 quay.io/keycloak/keycloak:26.8.1 完成端到端确认。

⚠️ 仅限授权研究。 所有操作均针对 localhost 上的一次性 Keycloak 运行。 请勿将 PoC 指向你未获得明确授权测试的系统。

  • 问题(根本原因)
  • 概念验证
  • 已验证的运行
  • 修复措施

问题(根本原因)

Keycloak 26.8.1 加固了组加入(CVE-2026-94000):持有 manage-users 的管理员 不能再将用户添加到可传递授予 realm-management 管理角色的组中。 GroupUtils.checkAdminGroupRoles 会递归遍历组的角色,并对每个嵌套的管理角色调用 requireMapRole:

private static void requireMapRoleRecursive(RoleModel role, AdminPermissionEvaluator auth, Set<String> visited) {
    if (!visited.add(role.getId())) return;
    if (AdminRoles.isAdminRole(role)) auth.roles().requireMapRole(role);   // checks nested admin roles
    if (role.isComposite()) role.getCompositesStream().forEach(child -> requireMapRoleRecursive(child, auth, visited));
}

同样的递归遍历从未被添加到角色映射端点中。 当角色被直接映射到用户或组上时,服务器只检查提交的角色:

// RoleMapperResource.addRealmRoleMappings — mounted on BOTH users and groups
for (RoleRepresentation role : roles) {
    RoleModel roleModel = realm.getRole(role.getName());
    auth.roles().requireMapRole(roleModel);   // posted role only — children never inspected
    roleMapper.grantRole(roleModel);
}

而权限门控本身依据的是角色的名称,而非其内容。在 RolePermissionsV2.canMapRole 中,只有当角色的容器为 realm-management/master 且其名称位于 AdminRoles.ALL_ROLES 中时,该角色才被视为特权角色:

public boolean canMapRole(RoleModel role) {
    if (isRealmAdminRole(role)) { ... }                 // isRealmAdminRole = container + ALL_ROLES.contains(name)
    if (root.hasOneAdminRole(AdminRoles.MANAGE_USERS))  // manage-users may map ANY non-admin-named role
        return true;
    ...
}

因此,一个名为 sneaky-composite、包装了 realm-management/realm-admin 的复合角色能够通过这道校验——它的名称不在 ALL_ROLES 中,而且它的子角色从未被遍历。这个缺口横跨三个端点:

  • RoleMapperResource.addRealmRoleMappings —— 用户和组
  • ClientRoleMappingsResource.addClientRoleMapping —— 任意客户端上的客户端角色

净效果: 特权载荷(一个包装了 realm-admin 的复合角色)只需要存在即可——由真实管理员创建、通过 realm 导入创建,或由更早的进程创建。随后 manage-users 就能分配它,而这正是 CVE-2026-94000 威胁模型从未设想的情况。

攻击变体

#变体为何有效
A将 sneaky-composite 自映射到 realm-admin名称校验漏掉了该复合角色
B将嵌套的 outer-sneaky(→ sneaky-composite → realm-admin)映射到某个用户未检查嵌套深度
C在非管理客户端上映射客户端角色(spa/hidden-ra → realm-admin)ClientRoleMappingsResource 使用了同一道校验
D将该复合角色映射到一个已有成员的组上与加入操作使用不同的 API;现有成员无需任何加入操作即可提权

概念验证

要求: Docker + Docker Compose v2,以及宿主机上的 curl + jq。

cp .env.example .env     # optional: pin KC_VERSION (default 26.8.1)
make up                  # start Keycloak + auto-bootstrap the vulnerable realm `app`
make logs                # wait for "Lab realm 'app' is ready"

make check               # non-destructive detection (maps, then immediately unmaps)
make exploit             # Attack A: self-escalate limited-admin -> realm-admin
make all                 # full chain: check + A + B + C + D
make reset               # undo every escalation (keep the lab running)
make clean               # tear everything down

一次性 bootstrap 容器通过 admin REST API 构建场景,然后退出:

对象用途
limited-admin / limitedpass攻击者 — 仅持有 manage-users
alice / bob / carol / dave受害用户
sneaky-composite(realm 角色)复合角色 → realm-management/realm-admin
outer-sneaky(realm 角色)复合角色 → sneaky-composite(多一跳)
spa 客户端 + spa/hidden-ra 角色非管理员客户端角色 → realm-admin
confidential 客户端(confsecret)密钥读取影响目标
helpdesk 组(alice 是成员)组映射攻击目标

PoC 以 manage-users 调用者实际可行的方式解析角色 ID —— 通过 .../role-mappings/.../available 端点 —— 因为该账户被拒绝访问 GET /roles/{name} 和 GET /clients(403),但不被拒绝访问 available 列表。这使 脚本成为诚实的低权限攻击者视角复现。

验证修复

将实验环境指向已修补的构建;修复后的服务器必须在每个映射步骤返回 403, 同时仍允许普通的非管理员角色映射:

KC_VERSION=<patched-tag> docker compose up -d --force-recreate
make check        # expect: NOT vulnerable

已验证运行

针对 quay.io/keycloak/keycloak:26.8.1(完整记录见 docs/demo.txt,详情见 VALIDATION.md):

步骤操作结果
基线limited-admin POST /roles403(确为低权限)
检查将 sneaky-composite 映射到自身(随后取消映射)204 → 存在漏洞
A将 sneaky-composite 自映射 → realm-admin → 创建角色 / 导出用户邮箱204 / 201 / 200
B将嵌套的 outer-sneaky 映射到 bob → bob 创建角色204 / 201
C将 spa/hidden-ra 映射到 carol → carol 创建角色204 / 201
D将包装角色映射到 helpdesk → 现有成员 alice 创建角色204 / 201
D 对照manage-users 将新成员加入 helpdesk403(CVE-2026-94000 修复仍然有效)

D 对照证明了这种不对称性:组加入被阻止,但将同一复合角色映射到该组(或映射到用户/客户端)时却未被遍历检查,并返回 204。


修复建议

  1. 在 RolePermissionsV2.canMapRole / RolePermissions.checkAdminRoles 中,当 AdminRoles.isAdminRoleOrComposite(role) 为 true 时拒绝该角色,除非调用者可以映射每一个嵌套的管理角色——参照 GroupUtils.requireMapRoleRecursive 的实现。
  2. 对 RoleMapperResource.addRealmRoleMappings(用户和组)以及 ClientRoleMappingsResource.addClientRoleMapping 执行该遍历检查。
  3. 增加测试覆盖,确保 manage-users 无法映射 sneaky-composite、嵌套包装角色、复合了 realm-admin 的非管理客户端角色,或将包装角色映射到有成员的组。仅靠现有的组加入测试是不够的。

完整技术报告:report/report.md。

目录结构

docker-compose.yml               Keycloak + one-shot bootstrap container
bootstrap/setup-realm.sh         Builds the vulnerable realm via the admin REST API
poc/kc_composite_maprole_poc.sh  Detection + exploitation + cleanup PoC (curl/jq)
report/report.md                 Full technical write-up
VALIDATION.md / docs/demo.txt    Verified run evidence

许可证

MIT — 参见 LICENSE。

下载工具