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.

FeedsContactoPrivacidad© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
CVE-2026-103648 — Aviso y PoC para CVE-2026-103648, un path traversal (CWE-22) en image-downloader 4.3.0 que permite escritura arbitraria de archivos, con análisis de causa raíz, diff del parche y laboratorio Docker. | Kitploit
Herramientas/GitHubGitHub/eternullsec/cve-2026-103648
Escáneres de VulnerabilidadesAnálisis de VulnerabilidadesExplotaciónExplotación de Aplicaciones WebPruebas de PenetraciónPapers e InvestigaciónAprendizaje y EducaciónRed TeamingLabs y Práctica
GitHubeternullsec/cve-2026-103648

CVE-2026-103648

Aviso y PoC para CVE-2026-103648, un path traversal (CWE-22) en image-downloader 4.3.0 que permite escritura arbitraria de archivos, con análisis de causa raíz, diff del parche y laboratorio Docker.

231hace 18 díasAún no revisado
Ver Repositorio

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-103648 — Path Traversal en image-downloader

CVE CVSS CWE Package Status License

Descubierto por: Amirhossein Roustaei (@EterNullSec) — Eternull Security

📖 Análisis técnico completo: eternull.net/posts/cve-2026-103648-image-downloader-path-traversal

⚠️ Solo con fines educativos. Este repositorio documenta una vulnerabilidad divulgada de forma responsable. Todo el código PoC está destinado únicamente a la investigación y pruebas de seguridad autorizadas en entornos de laboratorio aislados. No lo utilice contra sistemas que no sean de su propiedad o para los que no tenga permiso escrito explícito para probar.


📋 Resumen del Aviso

CampoDetalles
ID de CVECVE-2026-103648
Entrada NVDnvd.nist.gov/vuln/detail/CVE-2026-103648
Puntuación CVSS v3.19.1 Crítica — CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H
CWECWE-22: Limitación incorrecta de un nombre de ruta a un directorio restringido
Paqueteimage-downloader (npm) por demsking
Descargas semanales en npm~11.000 (~38.000/mes) — fuente
Versiones afectadas< 4.3.1 (todas las versiones, incluida la 4.3.0)
Versión corregida4.3.1
Asignado porGitLab
Publicado2026-10-02
Reportado porAmirhossein Roustaei (@EterNullSec), Eternull Security

🔬 Análisis Técnico de la Causa Raíz

La vulnerabilidad se encuentra en la lógica de extracción de nombres de archivo de [email protected]. Este es el código fuente real de la versión afectada (index.js, extraído directamente del paquete npm publicado):

// [email protected] — index.js (actual source, unmodified)
module.exports.image = ({ extractFilename = true, ...options } = {}) => {
  if (!options.url) {
    return Promise.reject(new Error('The options.url is required'));
  }
  if (!options.dest) {
    return Promise.reject(new Error('The options.dest is required'));
  }

  if (extractFilename) {
    if (!path.extname(options.dest)) {
      const url = new URL(options.url);
      const pathname = url.pathname;
      const basename = path.basename(pathname);          // ❌ basename BEFORE decode
      const decodedBasename = decodeURIComponent(basename); // decode happens AFTER

      options.dest = path.join(options.dest, decodedBasename); // path.join resolves ".."
    }
  }
  // ...
  return request(options);
};

El error exacto

  1. Se llama a path.basename(pathname) sobre la ruta de URL que aún está codificada en porcentaje. Una secuencia como %2e%2e%2fpwned.sh no contiene ningún / literal, por lo que path.basename() trata todo el conjunto como un único nombre de archivo y lo devuelve sin cambios — no se elimina nada.
  2. El resultado se pasa después por decodeURIComponent(). Este es el paso que convierte %2e%2e%2f de nuevo en un ../ literal — pero para entonces ya ha sobrevivido al paso de basename que se suponía que debía sanearlo.
  3. Se llama a path.join(options.dest, decodedBasename) con una cadena que ahora contiene un segmento ../ real. path.join() normaliza .. de la misma forma que lo haría cd .. — por lo que la ruta de escritura final se resuelve en una ubicación fuera de options.dest.

En resumen: el código decodifica el nombre de archivo de la forma correcta, solo que en el orden equivocado respecto a path.basename(). Decodificar y luego aplicar basename es seguro; aplicar basename y luego decodificar no lo es.

Disparador mínimo

URL pathname:  /%2e%2e%2fpwned.sh
basename():    "%2e%2e%2fpwned.sh"        (unchanged — no literal '/')
decode:        "../pwned.sh"              (traversal now literal)
path.join(dest, "../pwned.sh")
            → resolves one directory ABOVE dest

Desglose de CVSS

Attack Vector:       Network   (AV:N)  — remotely triggerable
Attack Complexity:   Low       (AC:L)  — no special conditions
Privileges Required: None      (PR:N)  — no authentication needed
User Interaction:    None      (UI:N)  — fully automated
Scope:               Unchanged (S:U)
Confidentiality:     None      (C:N)
Integrity:           High      (I:H)   — arbitrary file write
Availability:        High      (A:H)   — overwrite critical files / DoS

🎯 Modelo de ataque

Este laboratorio demuestra el mecanismo del fallo de extremo a extremo en un único script para facilitar su reproducción, pero vale la pena enunciar explícitamente el modelo de ataque del mundo real:

  • Víctima: cualquier aplicación que llame a download.image({ url, dest }) de image-downloader con un valor de url que no controlaba completamente por sí misma — por ejemplo, una URL enviada por un usuario (funciones de importación de avatar/imagen), extraída de la carga útil de un webhook, o leída de un feed RSS/contenido.
  • Atacante: controla (o puede redirigir hacia) el servidor HTTP al que apunta la url de la víctima, y controla el componente de ruta de esa URL — lo cual es suficiente por sí solo, ya que el recorrido de directorios reside en la ruta de la URL (%2e%2e%2f...), no en el cuerpo de la respuesta.
  • Impacto: el proceso víctima escribe un archivo elegido por el atacante en una ruta elegida por el atacante, fuera del directorio que el desarrollador pretendía — en contenedores o scripts que se ejecutan con amplio acceso al sistema de archivos, esto suele escalar a ejecución de código (por ejemplo, sobrescribiendo un archivo cron, un archivo authorized_keys, o un ejecutable que la aplicación ejecuta posteriormente).

En exploit/exploit.py, los roles de atacante y víctima se combinan en un único script por comodidad del laboratorio (levanta tanto la petición al servidor "víctima" como el servidor de carga útil controlado por el atacante). En un escenario de explotación real, estas son dos partes separadas y no relacionadas — el PoC está estructurado de esta manera únicamente para que la vulnerabilidad sea reproducible con un solo comando.


🧪 Configuración del entorno de laboratorio

Requisitos previos

  • Docker y Docker Compose O Node.js v18+
  • Python 3.x (para el script de explotación)

Opción A — Docker (Recomendado)

git clone https://github.com/EterNullSec/CVE-2026-103648.git
cd CVE-2026-103648
docker compose up --build

El servidor vulnerable estará disponible en http://localhost:3000.

Opción B — Node.js manual

cd vulnerable-app/
npm install
node server.js

💥 Pasos para reproducir (PoC)

Paso 1 — Iniciar el servidor vulnerable

cd vulnerable-app/
npm install
node server.js
# Server running on http://localhost:3000
# Download directory: /tmp/downloads/

Paso 2 — Ejecutar el exploit

python3 exploit/exploit.py --target http://localhost:3000 --lhost 127.0.0.1

O manualmente con curl (el recorrido está en la ruta de la URL, no en el cuerpo de la respuesta):

Descargar herramienta