
Análisis y reproducción de la vulnerabilidad NGINX Rift
CVE-2026-42945 (nombre en clave "NGINX Rift") es una vulnerabilidad de desbordamiento de búfer en el montón en ngx_http_rewrite_module de NGINX, con una puntuación CVSS v4 de 9.2 (Crítica).
La vulnerabilidad fue descubierta por el equipo de investigación de seguridad depthfirst en abril de 2026 y ha estado latente durante 18 años desde su introducción en NGINX 0.6.27 en 2008.
La vulnerabilidad requiere el siguiente patrón de configuración de NGINX para activarse:
location ~ ^/api/(.*)$ {
rewrite ^/api/(.*)$ /internal?migrated=true;
set $original_endpoint $1;
}
Condiciones clave:
rewrite contiene ? (signo de interrogación)set posterior hace referencia a un grupo de captura de expresión regular (por ejemplo, $1)+, &, %, etc.)El motor de scripts de NGINX utiliza un procesamiento en dos fases para ejecutar las directivas rewrite/set:
El núcleo de la vulnerabilidad radica en una inconsistencia de estado del motor entre las dos fases:
rewrite establece la bandera is_argsCuando la cadena de sustitución de la directiva rewrite contiene ?, la función ngx_http_script_start_args_code establece:
void ngx_http_script_start_args_code(ngx_http_script_engine_t *e)
{
e->is_args = 1; // Se establece permanentemente, ¡nunca se reinicia!
e->args = e->pos;
e->ip += sizeof(uintptr_t);
}
set utiliza un submotor completamente nuevoCuando la directiva set posterior hace referencia a un grupo de captura, ngx_http_script_complex_value_code crea un submotor con todos los valores a cero:
void ngx_http_script_complex_value_code(ngx_http_script_engine_t *e)
{
ngx_http_script_engine_t le;
// ...
ngx_memzero(&le, sizeof(ngx_http_script_engine_t)); // le.is_args = 0
le.ip = code->lengths->elts;
Cálculo de longitud (usando el submotor le, is_args=0):
// ngx_http_script_copy_capture_len_code
if ((e->is_args || e->quote) && (e->request->quoted_uri || e->request->plus_in_uri))
{
// is_args=0, condición falsa, va a la rama else
return cap[n + 1] - cap[n]; // Devuelve la longitud original (sin escape)
}
Copia real (usando el motor principal e, is_args=1):
// ngx_http_script_copy_capture_code
if ((e->is_args || e->quote) && (e->request->quoted_uri || e->request->plus_in_uri))
{
// is_args=1, condición verdadera, va a la rama if
e->pos = (u_char *) ngx_escape_uri(pos, &p[cap[n]],
cap[n + 1] - cap[n],
NGX_ESCAPE_ARGS);
// ¡Cada carácter escapable se expande de 1 byte a 3 bytes!
}
raw_size (longitud de captura original)raw_size + 2 * N (N = número de caracteres escapables)Por ejemplo, si la URI contiene 100 signos +, la cantidad de desbordamiento es de 200 bytes.
La forma más simple de explotación: enviar una solicitud que contenga muchos caracteres escapables provoca el bloqueo del proceso worker:
GET /api/+++++++++++++++++++++++++++++++++++ HTTP/1.1
Host: target.com
Cadena de explotación RCE completa (requiere ASLR desactivado o eludido):
ngx_pool_t a través del orden de las conexionescleanup mediante desbordamiento: desbordar hacia la estructura del pool de memoria adyacentesystem() a través del cuerpo de una solicitud POSTngx_destroy_pool recorra la lista enlazada cleanupLa arquitectura multiproceso de NGINX hace que la explotación sea más fiable: tras el bloqueo de un worker, el master crea un nuevo worker con el mismo diseño de memoria.
README.md - Este archivo, documento de análisis de vulnerabilidadDockerfile - Construir un entorno NGINX vulnerablenginx.conf - Configuración de NGINX para activar la vulnerabilidadpoc_crash.py - PoC de DoS (provoca el bloqueo del worker)docker-compose.yml - Iniciar el entorno de prueba con un solo comando# 1. Construir e iniciar NGINX vulnerable
docker-compose up -d
# 2. Ejecutar el PoC de DoS
python3 poc_crash.py
# 3. Ver los logs de error de NGINX para confirmar el bloqueo
docker-compose logs nginx
Este material está destinado únicamente a fines de investigación y educación en seguridad. No utilice esta información para acciones de ataque no autorizadas.