Skip to main content

Common NGINX Misconfigurations

Updated 5 min readMarkdown
Common NGINX Misconfigurations

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:

  1. Você monta uma URL maliciosa.

  2. Manda para a vítima (qualquer técnica de phishing).

  3. Ela clica.

  4. Faz um request para o server.

  5. O server responde com seu Header customizado.

  6. 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:

  1. Vítima abre o link https://mysite.com/%0d%0aSet-Cookie:%20session=12345

  2. Servidor recebe requisição.

  3. Servidor encontra rota no NGINX (location /)

  4. Servidor ve que precisa redirecionar para v2 mantendo o path etc (return 302 http://localhost/v2$uri;)

  5. Todo redirect (301, 302) seta um header location. Neste caso, vai definir este header com o redirecionamento, que é http://localhost/v2$uri

  6. Mas para redirecionar, precisa colocar o valor da variável $uri .

  7. Ao substituir a variável, fica assim: http://localhost/v2/%0d%0aSet-Cookie:%20session=12345

  8. Por estar usando a variável $uri , precisa parsear os caracteres especiais, no caso de %0d%0a , é uma nova linha.

  9. No protocolo HTTP, uma nova linha é... UM HEADER NOVO.

  10. É adicionado a nova linha Set-Cookie:%20session=12345 , que vira um novo header.

  11. Este header é devolvido na resposta.

  12. O navegador lê os headers da resposta.

  13. 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.

References

No comments yet. Be the first to comment.

More from this blog