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

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

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

订阅源联系隐私© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
CVE-2026-18963 — 基于 Docker 的 CVE-2026-18963 实验环境与 Python 漏洞利用程序,该漏洞是 Keycloak 重置凭据流程绕过,可通过绕过电子邮件验证实现账户接管。 | Kitploit
工具/GitHubGitHub/ivanesk315/cve-2026-18963
漏洞分析漏洞利用Web应用程序漏洞利用Web安全渗透测试身份与访问管理 (IAM)身份验证学习与教育实验室与实践
GitHubivanesk315/cve-2026-18963

CVE-2026-18963

基于 Docker 的 CVE-2026-18963 实验环境与 Python 漏洞利用程序,该漏洞是 Keycloak 重置凭据流程绕过,可通过绕过电子邮件验证实现账户接管。

1621天前尚未审核

最受欢迎

查看全部 →

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

探索所有工具

浏览我们的工具集合

查看所有工具 →
查看仓库
分享

CVE-2026-18963 — Keycloak 重置凭据流程绕过实验

概述

本实验模拟 Keycloak 中的 CVE-2026-18963 漏洞(CVSS 9.1),该漏洞允许 攻击者通过绕过密码重置流程中的邮箱验证来接管任意账户。

仅供安全研究和教育目的使用。

环境要求

  • Docker 与 Docker Compose
  • Python 3.8+
  • pip

使用说明

1. 启动存在漏洞的 Keycloak

docker-compose up -d

等待 Keycloak 启动(约 30-60 秒)。

2. 配置实验环境

pip install -r requirements.txt
python setup-lab.py

脚本将创建:

  • 启用重置密码功能的 Realm vuln-lab
  • 用于发送邮件的 SMTP 配置(MailHog)
  • 用户 victim([email protected] / VictimPass123!)

3. 运行漏洞利用

python exploit.py -u http://127.0.0.1:8080 -r vuln-lab -t victim -p Pwned123!

选项:

  • -u / --url:Keycloak URL(默认:http://127.0.0.1:8080)
  • -r / --realm:Realm 名称(默认:vuln-lab)
  • -t / --target:目标用户名(默认:victim)
  • -p / --password:新密码(默认:Pwned123!)
  • -v / --verbose:启用调试输出

4. 查看邮件(可选)

MailHog UI:http://127.0.0.1:8025 — 查看漏洞利用过程中发送的重置密码邮件。

5. 清理

docker-compose down -v

技术细节

根本原因

Keycloak 中的两个缺陷组合形成了攻击链:

缺陷 1 — 选择器状态损坏(DefaultAuthenticationFlow.java): 当用户点击 "Try Another Way" 时,认证备注 AUTHENTICATION_SELECTOR_SCREEN_DISPLAYED 被保存为 "true"(布尔字符串)而非执行模型 ID。值 "true" 不绑定到任何具体执行,因此它会在流程的各个步骤中持续存在, 导致选择器在错误的上下文中显示。

缺陷 2 — 无条件操作成功(ResetCredentialEmail.java): ResetCredentialEmail 的 action() 方法无条件调用 context.success() 而不检查操作令牌。正常情况下,action() 仅在用户 点击邮件中的链接(带有操作令牌)时被调用。但当选择器损坏时,攻击者 可以通过流程处理直接触发 action()。

详细攻击流程

攻击者                                Keycloak
   │                                     │
   │─── GET /auth (OIDC + PKCE) ────────>│  1. 初始化认证会话
   │<── 登录页面 + cookies ──────────────│
   │                                     │
   │─── GET /reset-credentials ─────────>│  2. 跳转到重置流程
   │<── 用户名表单 ──────────────────────│
   │                                     │
   │─── POST tryAnotherWay=on ─────────>│  3. 损坏选择器状态
   │<── 认证器选择器 ────────────────────│     SELECTOR_DISPLAYED = "true"
   │                                     │
   │─── POST username=victim ──────────>│  4. 通过选择器提交用户名
   │<── "Check your email" 页面 ────────│     邮件已发送,CURRENT_EXEC = email_id
   │                                     │
   │─── GET /reset-credentials ────────>│  5. 重新进入重置流程
   │<── 损坏的选择器 (!!!) ──────────────│     processFlow() 看到 SELECTOR="true"
   │                                     │     → 为邮件步骤显示选择器
   │                                     │
   │─── POST {} (空请求体) ─────────────>│  6. 绕过:触发 action()
   │<── 302 → UPDATE_PASSWORD ─────────│     processAction() 在表单中未发现
   │                                     │     authenticationExecution
   │─── GET /required-action ──────────>│     → 落入 action() 分支
   │<── 密码更新表单 ────────────────────│     ResetCredentialEmail.action()
   │                                     │     → context.success()(无条件!)
   │                                     │     → 流程跳转到 ResetPassword
   │                                     │
   │─── POST password-new=Pwned! ──────>│  7. 设置新密码
   │<── 302 → /account/ ──────────────│     账户接管完成
   │                                     │
   └── 使用新密码登录 ───────────────────┘

为什么第 6 步有效?

在 DefaultAuthenticationFlow.processAction() 中,当收到 POST 时:

  1. 检查表单中的 tryAnotherWay → 无(表单为空)
  2. 检查表单中的 authenticationExecution → 无(表单为空)
  3. 落入最后分支:对来自 URL 的模型调用 authenticator.action(result)

由于 URL 包含 execution=<email_exec_id>(来自选择器表单 action),因此 ResetCredentialEmail.action() 被调用 → 返回 context.success() → 流程跳转到 ResetPassword → 显示密码设置表单。

受影响版本

产品受影响已修复
Keycloak(上游)< 26.7.226.7.2+
RHBK 26.4.x< 26.4.1526.4.15+
RHBK 26.6.x< 26.6.626.6.6+

补丁(PR #51844)

DefaultAuthenticationFlow.java:

  • setAuthNote(SELECTOR_DISPLAYED, "true") → setAuthNote(SELECTOR_DISPLAYED, model.getId())
  • processFlow() 检查 selector.equals(lastExecutionId) 而非 Boolean.parseBoolean()
  • 如果不匹配 → removeAuthNote(SELECTOR_DISPLAYED)

ResetCredentialEmail.java:

  • action() 在调用 context.success() 之前检查 ACTION_TOKEN_USER_ID
  • 如果没有有效的操作令牌 → context.failure(INVALID_USER)

参考资料

  • NVD - CVE-2026-18963
  • Red Hat CVE Page
  • Keycloak Issue #51833
  • Fix PR #51844
  • Kudelski Security Research
  • The Hacker News
下载工具