Veja também em vídeo aqui:
https://youtu.be/0Kn9RmUByXQ
Aposto que você já teve que criar algum arquivo de rotas usando NGINX, seja para distribuir assets de uma pasta específica, seja para redirecionar o tráfego para outra aplicação interna.
Contudo, todavia, entretanto, se você acabar comentendo alguns destes 3 erros clássicos, você pode acabar com um set de vulnerabilidades bem facinho aí.
1 - Missing Root
Todo arquivo de NGINX pode ter um ponto de partida onde ele vai procurar por arquivos. Para isto, utilizamos o root
:
server {
listen 80;
server_name localhost;
root /etc/nginx; # <-- AQUI
location /home/ {
alias /usr/share/nginx/html/;
index home.html home.htm;
try_files $uri $uri/ =404;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
Porém perceba que em nossas configurações, não temos nenhum location
que aponta para /
.
A falta desta configuração faz com que o NGINX tenha a permissão de entregar qualquer arquivo que esteja dentro da pasta definida no root
(/etc/nginx
).
Ou seja, se você fizer uma request para `/nginx.conf`, o NGINX vai procurar por este arquivo dentro do diretório root. Se encontrar, vai entregar para você.
=== REQUEST ===
curl http://localhost/nginx.conf
=== RESPONSE ===
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
keepalive_timeout 65;
# include /etc/nginx/conf.d/*.conf;
include /etc/nginx/conf.d/server.conf;
}
Para corrigir este problema, basta definir uma rota raiz. Ela pode redirecionar para o index do site ou outra página que deseje.
server {
listen 80;
server_name localhost;
root /etc/nginx;
location / { # <-- AQUI
return 302 https://my-site-index.com;
}
location /home/ {
alias /usr/share/nginx/html/;
index home.html home.htm;
try_files $uri $uri/ =404;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
2 - Alias Traversal
Um erro bastante comum e inclusive fácil de cometermos é expormos os arquivos do servidor por causa da falta de um /
.
Veja a configuração a seguir:
server {
listen 80;
server_name localhost;
location /health {
return 200 "healthy\n";
add_header Content-Type text/plain;
}
location /assets {
alias /var/assets/;
}
location / {
root /usr/share/nginx/html;
index home.html home.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
Justamente onde temos o /assets
, estamos mapeando que todo request recebido neste path, devemos buscar por resources dentro de /var/assets/
.
Até aí tudo bem, mas o problema aqui é justamente usarmos /assets
e não /assets/
.
A falta desta /
ao final, permite que um atacante busque por outros arquivos no servidor, usando um traversal (../
).
Com isso, deixamos nosso server vulnerável a ataques como este aqui:
curl http://mysite.com/assets../log/nginx/access.log
Onde o NGINX vai permitir que uma busca a nível mais alto na hierarquia de diretorios seja realizada, concendo acessos à outros arquivos na qual não deveriam ser expostos externamente.
Para corrigir isso, basta colocar uma /
ao final:
# ❌ NOOOP
location /assets {
alias /var/assets/;
}
# ✅ YEEEP
location /assets/ {
alias /var/assets/;
}
3 - Unsafe $uri
O terceiro e um dos mais legais na minha opinião é você ser capaz de adicionar header qualquer na resposta de uma requisição via URL.
Simples:
Você monta uma URL maliciosa.
Manda para a vítima (qualquer técnica de phishing).
Ela clica.
Faz um request para o server.
O server responde com seu Header customizado.
Se a aplicação confia nos headers de resposta do servidor e faz algo com ela, boooom 💀.
Veja a configuração a seguir:
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html/;
location / {
return 302 http://localhost/v2$uri;
}
location /v2/ {
return 200 "Hello\n";
add_header Content-Type text/plain;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
Perceba onde mapeamos o location /
estamos redirecionando todos para a versão 2 do nosso site ou api (beeem comum aqui). Porém contatenamos tudo que o usuário colocar na URL, para preservar paths, query strings, etc (com o $uri
).
O problema aqui é justamente o uso do $uri
e abertura para um CRLF Injection.
Se o atacante enviar este link para a vítima:
https://mysite.com/%0d%0aSet-Cookie:%20session=12345
O servidor vai responder que deve criar este cookie session=12345 no navegador da vítima.
Porque isto acontece?
Este %0d%0a
é uma quebra de linha. Ao montar a resposta, o pacote HTTP vai ficar assim:
HTTP/2 302 Found
Location: http://localhost/v2/
Set-Cookie: session=12345
E isso aconteceu porque:
Vítima abre o link
https://mysite.com/%0d%0aSet-Cookie:%20session=12345
Servidor recebe requisição.
Servidor encontra rota no NGINX (
location /
)Servidor ve que precisa redirecionar para v2 mantendo o path etc (
return 302 http://localhost/v2$uri;
)Todo redirect (301, 302) seta um header location. Neste caso, vai definir este header com o redirecionamento, que é
http://localhost/v2$uri
Mas para redirecionar, precisa colocar o valor da variável
$uri
.Ao substituir a variável, fica assim:
http://localhost/v2/%0d%0aSet-Cookie:%20session=12345
Por estar usando a variável
$uri
, precisa parsear os caracteres especiais, no caso de%0d%0a
, é uma nova linha.No protocolo HTTP, uma nova linha é... UM HEADER NOVO.
É adicionado a nova linha
Set-Cookie:%20session=12345
, que vira um novo header.Este header é devolvido na resposta.
O navegador lê os headers da resposta.
Vê um header
Set-Cookie
e cria o cookie.
Ou seja, se sua aplicação confia cegamente nas respostas da api e você possui esta config, possui uma vulnerabilidade que pode ser explorada.
Para corrigir isso, basta utilizar $request_uri
e não $uri
ou $document_uri
.
Igual, não se esqueça de sanitizar os headers Location, uma vez que esta mesma vulnerabilidade pode estar presente em outros mecanismos de redirecionamento em sua infraestrutra.