Skip to content
KitploitKITPLOIT
ツールエクスプロイトブログ
Log in
提出
ツールエクスプロイトブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

フィードお問い合わせプライバシー© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2026-18963 — CVE-2026-18963(Keycloakのreset-credentialsフローをバイパスし、メール検証の回避によるアカウント乗っ取りを可能にする脆弱性)に対するDockerベースのラボとPythonエクスプロイト。 | Kitploit
ツール/GitHubGitHub/ivanesk315/cve-2026-18963
脆弱性分析エクスプロイトウェブアプリケーション悪用ウェブセキュリティペネトレーションテストアイデンティティ&アクセス管理 (IAM)認証学習と教育ラボと実践
GitHubivanesk315/cve-2026-18963

CVE-2026-18963

CVE-2026-18963(Keycloakのreset-credentialsフローをバイパスし、メール検証の回避によるアカウント乗っ取りを可能にする脆弱性)に対するDockerベースのラボとPythonエクスプロイト。

1621日前未レビュー
リポジトリを見る

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

CVE-2026-18963 — Keycloak Reset-Credentials Flow Bypass Lab

概要

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

スクリプトは以下を作成します:

  • reset-password を有効にした Realm vuln-lab
  • メール送信用の SMTP (MailHog) 設定
  • ユーザー victim ([email protected] / VictimPass123!)

3. Exploit の実行

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 — exploit 中に送信された reset-password メールを確認できます。

5. クリーンアップ

docker-compose down -v

技術的詳細

根本原因

Keycloak における 2 つの不具合が組み合わさり、攻撃チェーンを形成します:

不具合 1 — Selector 状態の破損 (DefaultAuthenticationFlow.java): ユーザーが「Try Another Way」をクリックすると、auth note AUTHENTICATION_SELECTOR_SCREEN_DISPLAYED が execution model ID ではなく "true" (真偽値の文字列) として保存されます。値 "true" は特定の execution に紐付かないため、フロー内の各ステップを通じて存続し、selector が誤ったコンテキストで表示されます。

不具合 2 — 無条件の action 成功 (ResetCredentialEmail.java): ResetCredentialEmail の action() メソッドは、action token を検証せずに無条件で context.success() を呼び出します。通常、action() はユーザーがメール内のリンク (action token を含む) をクリックした場合にのみ呼び出されます。しかし selector が破損している場合、攻撃者はフロー処理を通じて action() を直接トリガーできます。

攻撃フローの詳細

Attacker                              Keycloak
   │                                     │
   │─── GET /auth (OIDC + PKCE) ────────>│  1. auth セッションを初期化
   │<── Login page + cookies ────────────│
   │                                     │
   │─── GET /reset-credentials ─────────>│  2. reset フローへ遷移
   │<── Username form ──────────────────│
   │                                     │
   │─── POST tryAnotherWay=on ─────────>│  3. selector 状態を破損
   │<── Authenticator selector ─────────│     SELECTOR_DISPLAYED = "true"
   │                                     │
   │─── POST username=victim ──────────>│  4. selector 経由で username を送信
   │<── "Check your email" page ────────│     メール送信、CURRENT_EXEC = email_id
   │                                     │
   │─── GET /reset-credentials ────────>│  5. reset フローに再進入
   │<── Corrupted selector (!!!) ───────│     processFlow() が SELECTOR="true" を検出
   │                                     │     → email ステップに selector を表示
   │                                     │
   │─── POST {} (empty body) ──────────>│  6. BYPASS: action() をトリガー
   │<── 302 → UPDATE_PASSWORD ─────────│     processAction() が form 内に
   │                                     │     authenticationExecution を検出せず
   │─── GET /required-action ──────────>│     → action() 分岐に到達
   │<── Password update form ──────────│     ResetCredentialEmail.action()
   │                                     │     → context.success() (無条件!)
   │                                     │     → フローが ResetPassword へ遷移
   │                                     │
   │─── POST password-new=Pwned! ──────>│  7. 新しいパスワードを設定
   │<── 302 → /account/ ──────────────│     アカウント乗っ取り完了
   │                                     │
   └── 新しいパスワードでログイン ──────┘

なぜ step 6 が機能するのか?

DefaultAuthenticationFlow.processAction() において、POST を受信した際:

  1. form 内の tryAnotherWay を確認 → なし (form は空)
  2. form 内の authenticationExecution を確認 → なし (form は空)
  3. 最後の分岐に到達: URL の model に対して authenticator.action(result) を呼び出す

URL に execution=<email_exec_id> (selector form action 由来) が含まれているため、ResetCredentialEmail.action() が呼び出される → context.success() を返す → フローが ResetPassword へ遷移 → パスワード設定フォームを表示。

影響を受けるバージョン

製品影響を受ける修正済み
Keycloak (upstream)< 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() は Boolean.parseBoolean() ではなく selector.equals(lastExecutionId) を検証
  • 一致しない場合 → removeAuthNote(SELECTOR_DISPLAYED)

ResetCredentialEmail.java:

  • action() は context.success() を呼び出す前に ACTION_TOKEN_USER_ID を検証
  • 有効な action token が存在しない場合 → context.failure(INVALID_USER)

参考資料

  • NVD - CVE-2026-18963
  • Red Hat CVE Page
  • Keycloak Issue #51833
  • Fix PR #51844
  • Kudelski Security Research
  • The Hacker News
ツールをダウンロード