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

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

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

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

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2026-18963-PoC — CVE-2026-18963(Keycloakのreset-credentialsフローにおける未認証のアカウント乗っ取り)の概念実証および脆弱性チェッカー。単一ファイルのPython製で、オプションのPlaywrightブラウザコンポーネント付き。 | Kitploit
ツール/GitHubGitHub/orevim/cve-2026-18963-poc
脆弱性分析エクスプロイトウェブアプリケーション悪用ウェブセキュリティペネトレーションテスト認証
GitHuborevim/cve-2026-18963-poc

CVE-2026-18963-PoC

CVE-2026-18963(Keycloakのreset-credentialsフローにおける未認証のアカウント乗っ取り)の概念実証および脆弱性チェッカー。単一ファイルのPython製で、オプションのPlaywrightブラウザコンポーネント付き。

リポジトリを見る
17日前未レビュー
ウェブサイト

人気

すべて見る →

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

すべてのツールを探索

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

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

CVE-2026-18963

Keycloakのreset-credentialsフローバイパスに対する概念実証(PoC)および脆弱性チェッカーです。オプションのブラウザコンポーネントを使用すると、結果の状態を実際のChromeウィンドウでレンダリングできます。

このツールは単一ファイル cve_2026_18963_poc.py で、Python標準ライブラリに対して記述されています。サードパーティの依存関係はPlaywrightのみで、これは遅延インポートされるため、HTTP側は何もインストールされていない標準のインタプリタで動作します。

cve_2026_18963_poc.py     1009 lines, Python 3.10 or newer

クレジット。 CVE-2026-18963 は James Paremain によって Red Hat に報告され、 ベンダーアドバイザリにクレジットされています。Orevim はこの脆弱性を発見または報告した ものではありません。このリポジトリは、公開されたアドバイザリに基づいて書かれた 独立した概念実証です。


1. 脆弱性

CVE-2026-18963 は Keycloak のパスワード忘れフローにおける認証バイパスです。 これは 2 つの欠陥が組み合わさって動作します。

スコープされていないノート。 ユーザーが認証器選択画面を開くと、 Keycloak は認証セッションに AUTHENTICATION_SELECTOR_SCREEN_DISPLAYED ノートを書き込みます。 このノートは単なる真偽値です。ある 選択画面が表示されたことを記録するだけで、 どの 実行がそれを表示したかは記録しません。このノートは、それを設定した実行よりも長く存続します。

ガードされていないハンドラ。 ResetCredentialEmail.action() は解決されたユーザーに emailVerified を設定し、メールのリンクが持つはずのアクショントークンをチェックせずに success() を呼び出します。このメソッドは、そのリンクをたどることによってのみ到達できると 想定しています。

連鎖させると、未認証の呼び出し元がユーザー名実行に対してノートを設定し、フローを進めて メール実行をカレントにし、その後リセット URL に再びアクセスします。古いノートにより、 選択画面がメール実行にバインドされてレンダリングされます。その実行の loginAction に 空のボディを POST すると、ガードされていないハンドラが直接呼び出されます。メールが一切 読まれることなく、フローは UPDATE_PASSWORD 必須アクションへと進みます。

識別子CVE-2026-18963, GHSA-4gv3-mc9p-5wqc
クラスCWE-640, パスワード忘れに対する脆弱なパスワード回復メカニズム
CVSS v3.19.1 AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N
影響範囲>= 26.0.0, < 26.4.15, >= 26.5.0, < 26.6.6, >= 26.7.0, < 26.7.2
修正済み26.4.15, 26.6.6, 26.7.2。26.8.0 系には修正が含まれています
パッケージorg.keycloak:keycloak-services (Maven)
公開日2026年8月18日
報告者James Paremain(Red Hat アドバイザリにクレジット)

唯一の前提条件は、レルムが未認証ユーザーにパスワード回復を提供していることです。 資格情報、トークン、または事前のセッションは必要ありません。

リクエストチェーン

順番に 8 つのリクエスト。タグはツールが出力するステップラベルおよび --out 配下に 書き込まれるファイル名と一致します。

#タグメソッド動作
1loginGET認可 URL。認証セッションを確立し、リセットリンクを生成します。
2resetGET資格情報リセットページ。ユーザー名フォームを含みます。
3tryanotherPOSTtryAnotherWay=on。スコープされていないノートを書き込みます。
4usernamePOST識別子。フローを進めてメール実行をカレントにします。識別子が解決されると回復メールを送信します。
5reenterGET再びリセット URL。古いノートにより、セレクタがメール実行にバインドされてレンダリングされます。
6actionPOSTその実行の loginAction への空のボディ。ガードされていないハンドラを呼び出します。
7required-actionGETLocation をたどって UPDATE_PASSWORD ページへ移動します。
8setpasswordPOST新しいパスワード。--set-password 指定時のみ送信されます。

ステップ 6 がエクスプロイトであり、空のボディが要となります。代わりに authenticationExecution=<id> を POST するのは通常のセレクタ操作です。これは実行を 切り替えて回復メールを再送するため、欠陥には決して到達しません。空の POST はどの チャレンジにも応答しないため、Keycloak は古いノートがカレントのままにした実行に対して ハンドラを呼び出します。


2. パート 1: HTTP チェーン

モード

# Decide whether the instance is affected. Changes nothing, sends no mail.
./cve_2026_18963_poc.py --url https://sso.example.com --realm demo \
    --client-id account-console --check

# Additionally report which identifiers resolve to a real account.
# Resolving accounts receive a recovery email. See the note below.
./cve_2026_18963_poc.py --url https://sso.example.com --realm demo \
    --client-id account-console --check --users-file names.txt --rate 0.25

# Reach the set-password form for one account and stop there.
./cve_2026_18963_poc.py --url https://sso.example.com --realm demo \
    --client-id account-console --username [email protected]

# Complete the takeover. This locks the account holder out.
./cve_2026_18963_poc.py --url https://sso.example.com --realm demo \
    --client-id account-console --username [email protected] \
    --set-password 'N3w-passw0rd!'

--check は <16 hex>@<8 hex>.invalid 形式のランダムな識別子でプローブします。.invalid TLD は RFC 2606 で予約されており解決できないため、プローブが実在のアカウントと衝突することはなく、メールが送信されることもありません。これにより、誰にも影響を与えることなくビルドの状態を確認できます。

--users を追加するとこれが変わります。 ステップ 4 は通常のパスワード忘れ送信です。SMTP が設定されたレルムでは、メールアドレスを持つユーザーに解決される識別子は、影響を受けるビルドでもパッチ済みビルドでも、本物のパスワード回復メールを受け取ります。素のプローブではこれが起きません。ユーザーが null の場合、ResetCredentialEmail.authenticate() は何も送信しないためです。--check --users は実在の人物に通知を行うフローとして扱い、実行前にこれがあなたの権限の範囲内であることを確認してください。

判定

このツールはステップ 6(空の POST)への応答に基づいて分類します。

応答結果意味
400account-absentハンドラがアクショントークンなしで実行され、ユーザーを解決しなかった。ビルドは影響を受けている。
Location 付きの 302form-reachedハンドラが実行され、アカウントが解決された。影響を受けており、この識別子は実在する。
それ以外not-vulnerable空の POST が進まなかった。
ステップ 5 でセレクタなしnot-vulnerable古いノートが尊重されなかった。
ステップ 8 後の 302password-setパスワードが変更され、レルムがセッションを発行した。
リトライ予算を超えた 429rate-limited判定なし。実行は停止した。
スロットリング後に到達した否定結果inconclusive以下を参照。

400 が重要なものです。これはビルドが影響を受けていることとこのアカウントが存在することを切り分けるため、--check は実在のユーザーを一人も列挙することなく、インスタンスに対する露出を確認できます。識別子の解決は、それとは別のオプトインの問いとなります。

否定結果は、何もスロットリングされなかった場合にのみ妥当です。 Keycloak は独自のクロックで認証セッションを失効させます。チェーン途中の 429 はバックオフを要し、長時間のスリープ後に再開したチェーンは、パッチ済みビルドが返すのとまったく同じページを返します。それを影響なしと報告することは、チェッカーが決して犯してはならない唯一の失敗モードです。そのため、スロットルイベント後に到達した否定結果は、スロットル回数とより低速で再実行するよう促す助言とともに inconclusive に格下げされます。

ターゲットの導出

デプロイメントについてハードコードされたものはありません。ツールは必要なものを読み取ります。

  • エンドポイントは、--url と --realm から導出されるか、--discovery-url で直接指定される、レルムの OIDC ディスカバリドキュメントから取得されます。--auth-url を渡すとディスカバリを完全にスキップします。
  • リセット URL は、ログインページ上でパスに login-actions/reset-credentials を含む最初のリンクです。
  • フォームのアクションとフィールド名は、各ページが到着するたびに解析されるため、名前が変更されたフィールドや非デフォルトのパスにフラグは不要です。
  • リダイレクト URI は、デフォルトでディスカバリされた発行者のアカウントコンソールになります。
  • PKCE パラメータは実行ごとに生成されます。ランダムな 32 バイトのベリファイアとその S256 チャレンジです。

シングルページアプリケーションのテーマ(Keycloakify など)は、サーバー側の <form> 要素をまったくレンダリングしません。アクションは、テーマが <script> ブロックに埋め込む kcContext オブジェクト内にのみ存在します。ツールはそのオブジェクトから loginAction と loginResetCredentialsUrl を読み取るフォールバックを行い、\/ と \uXXXX をアンエスケープします。フォームがなければ引き継ぐフィールドもないため、リクエストボディはそのステップが上書きするものだけとなり、フィールド名は --username-field と --password-fields から取得されます。

すべてのプロトコルのデフォルトはフラグとして公開されており、セレクタフィールド自体(--selector-field、デフォルト tryAnotherWay=on)も含まれます。

ペーシング

429 は決して判定ではなく、それを招いたレートでリトライしても別の 429 を招くだけです。ペーサーは強くバックオフし、ゆっくりと回復します。トークンバケットではなく、リクエスト間の間隔に基づいて制御されます。

  • 実行は --rate リクエスト/秒で開始し、それを超えることは決してない。 --rate は上限であり、収束させる目標ではない。
  • 429 を受けると、間隔は --slow-factor だけ広がり、広がったまま維持される。次のリクエストで即座に戻ることはない。
  • Retry-After はエッジが送信した場合に尊重され、そのスリープに限り計算されたバックオフを上書きする。
  • 間隔は --recover-after 回連続の正常応答の後にのみ --recover-factor だけ狭まり、要求されたレートを超えることは決してない。
  • --floor-rate は実行がどこまで遅くなり得るかの下限を定める。
  • 各間隔は --jitter によってランダム化され、リクエストパターンがメトロノームのようにならない。
  • --retries は単一のスロットリングされたリクエストの再試行回数を制限する。それを超えると、推測するのではなく rate-limited で実行を停止する。

すべての実行は、ペーシングが最終的にどこに落ち着いたかを報告する:

pacing: asked for 0.5 rps, settled at 0.125 rps after 3 throttled request(s);
pass --rate 0.125 next time

その行がこのメカニズムの要点である。1回の実行でエッジが何を許容するかを測定し、次の実行はそこから開始する。

--check でリストを指定した場合、各識別子にはそれぞれ独自の cookie jar を持つ新しい Exploit インスタンスが割り当てられるが、すべてが1つの pacer を共有するため、学習されたレートは識別子ごとに再発見されるのではなく、リスト全体に引き継がれる。

トランスポート

  • アドレスピンニング。 --address は Host ヘッダーと TLS SNI をホスト名にバインドしたまま、すべての接続を1つの IP に固定する。これはカスタムの HTTPSConnection であり、その connect() は固定されたアドレスにダイヤルし、wrap_socket(server_hostname=self.host) を呼び出す。
  • 自動リダイレクトなし。 リダイレクトハンドラーは None を返すものに置き換えられる。このチェーン内のすべての Location が証拠となるためである。ステップ6の302が判定であり、ステップ8の302が認可コードの存在する場所である。
  • 識別子ごとに1つの cookie jar。 認証状態はアカウント間で漏洩してはならない。
  • 証明書検証は有効 である。ただし --insecure が渡された場合を除く。
  • リクエストの識別情報 は自分で設定する: --user-agent および繰り返し指定可能な --header NAME:VALUE。何も注入されない。相関ヘッダーも、マーカーパラメータも、合成トレーサーもないため、リクエストのフィンガープリントは、それが名乗るクライアントを代表するものにとどまる。

証拠

--out DIR はすべてのリクエストとレスポンスを番号付きのペアとして書き出す:

DIR/01-login.headers      request line, request headers, status, response headers
DIR/01-login.body         the response body, verbatim
DIR/02-reset.headers
...

--check では、これらは対象ごとに名前空間化されます。ランダムプローブには DIR/probe/、各識別子には DIR/id-001/、DIR/id-002/ が使われるため、リスト実行では単一のサマリーではなくリクエストごとのマニフェストが生成されます。

このモジュールは何かを書き込む前に umask(0o077) を設定するため、キャプチャは所有者のみアクセス可能な状態で保存されます。キャプチャにはセッション Cookie と完全なレスポンスボディが含まれます。このディレクトリは制限された資料として扱ってください。

ツールをダウンロード