
Una sola llamada a función faltante en el registro de rutas fue suficiente para convertir la interfaz MCP en una puerta de enlace RCE sin autenticación.
Herramienta de detección no destructiva para la omisión de autenticación MCP de nginx-ui conocida públicamente como MCPwn. Permite la toma de control no autenticada de cualquier instancia de nginx-ui que ejecute una versión vulnerable mediante dos peticiones HTTP.
| Campo | Valor |
|---|---|
| ID CVE | CVE-2026-33032 |
| Alias | MCPwn |
| CVSS 3.1 | 9.8 / Crítico (AV:N / AC:L / PR:N / UI:N / S:U / C:H/I:H/A:H) |
| CWE | CWE-306 Autenticación Ausente para Función Crítica |
| Producto afectado | nginx-ui (github.com/0xjacky/nginx-ui) |
| Versiones afectadas | Todas las versiones anteriores a 2.3.4 |
| Versión corregida | 2.3.4 |
| Estado de explotación | Activa en la naturaleza (Picus Security, Recorded Future) |
| Exposición en Shodan | ~2.689 instancias expuestas a internet |
| Fecha de publicación | 2026-04-15 |
nginx-ui expone una interfaz de Protocolo de Contexto de Modelo (MCP) que permite a un operador autenticado ejecutar herramientas destructivas como ediciones de configuración de nginx, comandos de reinicio y operaciones de copia de seguridad a través de JSON-RPC.
El endpoint /mcp está protegido por el middleware AuthRequired(), mientras
que su endpoint asociado /mcp_message, que realmente recibe las invocaciones
de herramientas, fue desplegado sin el middleware. Cualquier cliente que
pueda alcanzar la interfaz web a través de la red puede:
/mcp y
recibir un sessionID nuevo sin presentar ninguna credencial.sessionID para invocar cualquier herramienta MCP registrada
enviando un POST a /mcp_message, aún sin autenticación.El atacante obtiene control total del proceso de nginx: editar bloques de servidor para redirigir tráfico, extraer claves privadas TLS mediante lecturas de rutas, recargar o detener nginx, e implantar puertas traseras persistentes.
// vulnerable (pre-2.3.4)
r.GET("/mcp", AuthRequired(), mcpHandler)
r.POST("/mcp_message", mcpMessageHandler) // middleware ausente
// corregido en 2.3.4
r.GET("/mcp", AuthRequired(), mcpHandler)
r.POST("/mcp_message", AuthRequired(), mcpMessageHandler)
Una única llamada a función ausente en el registro de rutas fue suficiente para convertir la interfaz MCP en una puerta de entrada de RCE no autenticada.
Atacante nginx-ui (<2.3.4)
| 1) GET /mcp (sin autenticación) |
| --------------------------------------> |
| 2) event: endpoint data: /mcp_message?sessionID=XYZ
| <-------------------------------------- |
| 3) POST /mcp_message?sessionID=XYZ |
| body: JSON-RPC call_tool "nginx_reload" o
| "edit_config {...}" |
| --------------------------------------> |
| 4) 200 OK; herramienta ejecutada con privilegios completos
| <-------------------------------------- |
| Herramienta MCP | Efecto en el servidor nginx |
|---|---|
edit_config | Reescribir bloques de servidor arbitrarios, insertar upstream del atacante |
reload_nginx | Aplicar configuración del atacante sin acción manual |
stop_nginx | Denegación de servicio |
read_file | Exfiltrar claves privadas TLS, credenciales de rutas montadas |
create_cert | Re-emitir certificados TLS bajo control del atacante |
list_backups / download | Extraer copia de seguridad completa de nginx-ui incluyendo node_secret y hashes |
Este repositorio evita intencionalmente cualquier acción destructiva. El
detector solo utiliza métodos MCP de solo lectura (tools/list). La lógica:
> Paso 1 Identificar nginx-ui mediante
> GET / (título HTML, paquetes JS)
> GET /api/settings (JSON que referencia claves de nginx-ui)
> Extraer versión mediante regex en cabecera / cuerpo
> Paso 2 Abrir flujo SSE hacia /mcp
> Analizar el primer sessionID del evento "endpoint"
> Paso 3 POST /mcp_message?sessionID=<id>
> Body: {"jsonrpc":"2.0","method":"tools/list","params":{}}
> Sin cabecera Authorization
> Paso 4 Vulnerable si estado 200 y el cuerpo contiene un manifiesto de herramientas
> Parcheado si estado 401 / 403 / 404
> No concluyente en cualquier otro caso
El método JSON-RPC tools/list es de solo lectura. Enumera qué
herramientas conoce el servidor MCP pero no invoca ninguna de ellas. El script
se niega a enviar POST con cualquier otro método y nunca construye cargas
útiles para herramientas destructivas.
git clone https://github.com/your-org/CVE-2026-33032-detector.git
cd CVE-2026-33032-detector
python3 --version # 3.9 o superior
# No se requieren paquetes de terceros.
Para el componente Nmap NSE, copie nginx-ui-mcpwn.nse en su directorio
local de scripts y actualice la base de datos de scripts:
cp nginx-ui-mcpwn.nse /usr/share/nmap/scripts/
sudo nmap --script-updatedb
# Objetivo único
python3 detect_nginx_ui_mcpwn.py --target https://nginx-ui.internal
# Escaneo masivo desde archivo
python3 detect_nginx_ui_mcpwn.py --targets targets.txt --workers 20
# Salida JSON (NDJSON) adecuada para canalizar a jq
python3 detect_nginx_ui_mcpwn.py --target 10.0.0.5:9000 --json | jq .
Referencia de línea de comandos: