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-70376 — Aviso y PoC en Python para el CSRF de Pluck CMS: una comprobación de Referer con fallo abierto (fail-open) junto con la subida de doble extensión permite el despliegue de webshells y la ejecución remota de código. | Kitploit
Herramientas/GitHubGitHub/ilhomjonr/cve-2026-70376
Análisis de VulnerabilidadesExplotaciónExplotación de Aplicaciones WebSeguridad WebPruebas de PenetraciónAprendizaje y Educación
GitHubilhomjonr/cve-2026-70376

CVE-2026-70376

Aviso y PoC en Python para el CSRF de Pluck CMS: una comprobación de Referer con fallo abierto (fail-open) junto con la subida de doble extensión permite el despliegue de webshells y la ejecución remota de código.

Ver Repositorio
6hace 1 mesAú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-70376 — CSRF en todo el sitio de Pluck CMS → RCE

Comprobación de Referer fail-open + sin tokens CSRF + subida de doble extensión

Una sola visita de un administrador a una página elimina contenido, inyecta páginas y suelta un webshell

CVE CVSS 3.1 CWE CWE

Product Status Researcher

De un vistazo · Resumen · Causa raíz · Cadena de ataque · Exploit · Remediación · Cronología


📋 De un vistazo

CVE IDCVE-2026-70376
ID de seguimientoPT-2026-68036
Productopluck-cms/pluck — Pluck CMS (PHP de archivos planos)
Afectado4.7.x hasta 4.7.21-dev / master actual
DebilidadCWE-352 (CSRF) · CWE-434 (subida sin restricciones, amplificador)
CVSS v3.18.0 — Alta · AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:H/A:H
VectorRed · sin privilegios · una visita de página de administrador (UI:R)
ImpactoDestrucción de contenido/DoS, inyección de contenido almacenado, RCE en Apache/mod_php
Introducidocommit f79f916 (dic. 2019) — lógica vulnerable presente desde entonces
InvestigadorIlhomjon Rustamov (@IlhomjonR)

🔎 Resumen

El panel de administración de Pluck no tiene tokens CSRF por petición en ninguna parte del código. Cada acción administrativa que cambia el estado está controlada por una única función, requestedByTheSameDomain(), cuya única defensa es una comparación del host del Referer — y esa comprobación falla en abierto (fail-open): cuando una petición llega sin cabecera Referer en absoluto, la función devuelve true y la acción se permite.

Dado que una página del atacante controla por completo si se envía un Referer (<meta name="referrer" content="no-referrer">), cualquier administrador con la sesión iniciada que visite una página maliciosa puede verse obligado a realizar acciones privilegiadas entre sitios. Varias acciones destructivas se ejecutan mediante GET, y Pluck no establece ningún atributo SameSite en PHPSESSID (los navegadores aplican SameSite=Lax, que sigue viajando en las navegaciones GET de nivel superior), por lo que son alcanzables entre sitios con la configuración predeterminada del navegador.

Una debilidad secundaria en el filtro de subida permite que el mismo CSRF coloque un archivo de doble extensión shell.php.jpg, convirtiendo el CSRF en un RCE drive-by en hosts Apache/mod_php.


🧬 Causa raíz

1. Comprobación de Referer fail-open — data/inc/functions.admin.php

function requestedByTheSameDomain() {
    if (isset($_SERVER['HTTP_HOST'])) { $myDomain = $_SERVER['HTTP_HOST']; }
    elseif (isset($_SERVER['SCRIPT_URI'])) { $myDomain = $_SERVER['SCRIPT_URI']; }
    else { $myDomain = NULL; }

    if (isset($_SERVER['HTTP_REFERER'])) { $requestsSource = $_SERVER['HTTP_REFERER']; }
    else { $requestsSource = NULL; }

    $referelDomain = parse_url($requestsSource, PHP_URL_HOST);

    if ($myDomain != NULL && $requestsSource != NULL &&
        (strcmp(trim($myDomain), trim($referelDomain)) === 0)) {
        return true;                 // Referer host == our host  -> allow
    } elseif ($myDomain == NULL || $requestsSource == NULL) {
        show_error("Be carefull with clicking links, ...", 1);
        return true;                 // Referer ABSENT -> FAIL OPEN -> allow  <==
    } else {
        return false;                // Referer host mismatch -> block
    }
}

Una petición entre sitios con un Referer externo se rechaza correctamente (la rama else), lo que crea una falsa sensación de protección — pero el atacante simplemente suprime el Referer, cae en la rama fail-open y la petición se permite. No hay ninguna capa de tokens detrás de esta comprobación.

La barrera se aplica una vez en admin.php y se confía en ella para todo el switch de acciones:

$isCSRF = requestedByTheSameDomain();
if (isset($_GET['action']) && $isCSRF) {
    switch ($_GET['action']) {
        case 'deletefile':  include_once('data/inc/deletefile.php');  break;
        case 'deleteimage': include_once('data/inc/deleteimage.php'); break;
        case 'deletepage':  include_once('data/inc/deletepage.php');  break;
        case 'module_delete': /* ... */
        case 'images':      include_once('data/inc/images.php');      break; // upload
        // ...
    }
}

2. Sin SameSite en la cookie de sesión (amplificador)

Pluck nunca llama a session_set_cookie_params(), por lo que PHPSESSID hereda el valor predeterminado vacío → los navegadores aplican SameSite=Lax, que sigue viajando en las navegaciones GET de nivel superior. Por tanto, las acciones expuestas por GET (deletefile, deleteimage, deletepage, module_delete, theme_delete, logout) se pueden falsificar con una sola visita a una página.

3. Subida de doble extensión — data/inc/images.php (amplificador de RCE)

if (in_array($_FILES['imagefile']['type'],                       // client-controlled MIME
    array('image/pjpeg','image/jpeg','image/png','image/gif'))) {
    $imagewhitelist = array('jfif', '.png', '.jpg', '.gif', 'jpeg');
    if (!in_array(strtolower(substr($_FILES['imagefile']['name'], -4)), $imagewhitelist)) {
        show_error($lang['general']['upload_failed'], 1);         // only checks LAST 4 chars
    } else {
        copy($_FILES['imagefile']['tmp_name'], 'images/'.latinOnlyInput($_FILES['imagefile']['name']));
        // ...
    }
}

Ambas comprobaciones se omiten trivialmente:

  • el tipo MIME proviene del cliente ($_FILES[...]['type']) → establecer image/jpeg;
  • solo se validan los últimos 4 caracteres del nombre de archivo → shell.php.jpg termina en .jpg y pasa.

El archivo se escribe en images/shell.php.jpg; en un host Apache/mod_php con manejo de extensiones múltiples se ejecuta como PHP.


⛓️ Cadena de ataque

Una sola visita de un administrador autenticado — sin ningún clic.

flowchart LR
    A[Admin logged into Pluck] --> B[Opens attacker page]
    B --> C["meta referrer=no-referrer<br/>suppresses Referer"]
    C --> D[Top-level nav / auto-form to admin.php]
    D --> E["Lax PHPSESSID cookie rides along<br/>Referer absent"]
    E --> F["requestedByTheSameDomain() -> FAIL OPEN -> true"]
    F --> G1[deletefile / deletepage -> destruction / DoS]
    F --> G2[editpage -> stored-content injection]
    F --> G3["images upload -> shell.php.jpg -> RCE"]

Las acciones falsificables incluyen:

Descargar herramienta