16 KiB
Raw Blame History

Nginx

{{#include ../../banners/hacktricks-training.md}}

Missing root location

Lors de la configuration du serveur Nginx, la directive root joue un rôle crucial en définissant le répertoire de base à partir duquel les fichiers sont servis. Considérez l'exemple ci-dessous :

server {
root /etc/nginx;

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

Dans cette configuration, /etc/nginx est désigné comme le répertoire racine. Cette configuration permet l'accès aux fichiers dans le répertoire racine spécifié, comme /hello.txt. Cependant, il est crucial de noter qu'un emplacement spécifique (/hello.txt) est défini. Il n'y a pas de configuration pour l'emplacement racine (location / {...}). Cette omission signifie que la directive racine s'applique globalement, permettant aux requêtes vers le chemin racine / d'accéder aux fichiers sous /etc/nginx.

Une considération de sécurité critique découle de cette configuration. Une simple requête GET, comme GET /nginx.conf, pourrait exposer des informations sensibles en servant le fichier de configuration Nginx situé à /etc/nginx/nginx.conf. Définir la racine sur un répertoire moins sensible, comme /etc, pourrait atténuer ce risque, mais cela pourrait encore permettre un accès non intentionnel à d'autres fichiers critiques, y compris d'autres fichiers de configuration, des journaux d'accès et même des identifiants chiffrés utilisés pour l'authentification de base HTTP.

Alias LFI Misconfiguration

Dans les fichiers de configuration de Nginx, une inspection minutieuse est nécessaire pour les directives "location". Une vulnérabilité connue sous le nom d'Inclusion de Fichiers Locaux (LFI) peut être introduite involontairement par une configuration qui ressemble à ce qui suit :

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

Cette configuration est sujette aux attaques LFI en raison de l'interprétation par le serveur des requêtes comme /imgs../flag.txt comme une tentative d'accès à des fichiers en dehors du répertoire prévu, se résolvant effectivement en /path/images/../flag.txt. Ce défaut permet aux attaquants de récupérer des fichiers du système de fichiers du serveur qui ne devraient pas être accessibles via le web.

Pour atténuer cette vulnérabilité, la configuration doit être ajustée pour :

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

Plus d'infos : https://www.acunetix.com/vulnerabilities/web/path-traversal-via-misconfigured-nginx-alias/

Tests 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

Restriction de chemin non sécurisé

Check the following page to learn how to bypass directives like:

location = /admin {
deny all;
}

location = /admin/ {
deny all;
}

{{#ref}} ../../pentesting-web/proxy-waf-protections-bypass.md {{#endref}}

Utilisation de variables non sécurisées / Division de requêtes HTTP

Caution

Variables vulnérables $uri et $document_uri et cela peut être corrigé en les remplaçant par $request_uri.

Une regex peut également être vulnérable comme :

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

location ~ /docs/([^/\s])? { … $1 … } - Non vulnérable (vérification des espaces)

location ~ /docs/(.*)? { … $1 … } - Non vulnérable

Une vulnérabilité dans la configuration de Nginx est démontrée par l'exemple ci-dessous :

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

Les caractères \r (retour chariot) et \n (saut de ligne) signifient des caractères de nouvelle ligne dans les requêtes HTTP, et leurs formes encodées en URL sont représentées par %0d%0a. L'inclusion de ces caractères dans une requête (par exemple, http://localhost/%0d%0aDetectify:%20clrf) à un serveur mal configuré entraîne l'émission par le serveur d'un nouvel en-tête nommé Detectify. Cela se produit parce que la variable $uri décode les caractères de nouvelle ligne encodés en URL, entraînant un en-tête inattendu dans la réponse :

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

En savoir plus sur les risques d'injection CRLF et de séparation de réponse à https://blog.detectify.com/2019/06/14/http-response-splitting-exploitations-and-mitigations/.

Cette technique est également expliquée dans cette présentation avec des exemples vulnérables et des mécanismes de détection. Par exemple, pour détecter cette mauvaise configuration d'un point de vue blackbox, vous pourriez utiliser ces requêtes :

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

Si vulnérable, la première renverra "X" comme étant n'importe quelle méthode HTTP et la seconde renverra une erreur car H n'est pas une méthode valide. Ainsi, le serveur recevra quelque chose comme : GET / H HTTP/1.1 et cela déclenchera l'erreur.

D'autres exemples de détection seraient :

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

Certaines configurations vulnérables trouvées dans cette présentation étaient :

  • Notez comment $uri est défini tel quel dans l'URL finale.
location ^~ /lite/api/ {
proxy_pass http://lite-backend$uri$is_args$args;
}
  • Notez comment à nouveau $uri est dans l'URL (cette fois à l'intérieur d'un paramètre)
location ~ ^/dna/payment {
rewrite ^/dna/([^/]+) /registered/main.pl?cmd=unifiedPayment&context=$1&native_uri=$uri break;
proxy_pass http://$back;
  • Maintenant dans AWS S3
location /s3/ {
proxy_pass https://company-bucket.s3.amazonaws.com$uri;
}

Any variable

Il a été découvert que les données fournies par l'utilisateur pourraient être traitées comme une variable Nginx dans certaines circonstances. La cause de ce comportement reste quelque peu insaisissable, mais ce n'est ni rare ni simple à vérifier. Cette anomalie a été mise en évidence dans un rapport de sécurité sur HackerOne, qui peut être consulté ici. Une enquête plus approfondie sur le message d'erreur a conduit à l'identification de son occurrence dans le module de filtre SSI du code de Nginx, pinpointant les Server Side Includes (SSI) comme la cause principale.

Pour détecter cette mauvaise configuration, la commande suivante peut être exécutée, qui implique de définir un en-tête referer pour tester l'impression de variables :

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

Des analyses de cette mauvaise configuration à travers les systèmes ont révélé plusieurs instances où les variables Nginx pouvaient être imprimées par un utilisateur. Cependant, une diminution du nombre d'instances vulnérables suggère que les efforts pour corriger ce problème ont été quelque peu réussis.

Lecture de la réponse brute du backend

Nginx offre une fonctionnalité via proxy_pass qui permet l'interception des erreurs et des en-têtes HTTP produits par le backend, visant à cacher les messages d'erreur internes et les en-têtes. Cela est accompli par Nginx servant des pages d'erreur personnalisées en réponse aux erreurs du backend. Cependant, des défis se posent lorsque Nginx rencontre une requête HTTP invalide. Une telle requête est transmise au backend telle quelle, et la réponse brute du backend est ensuite directement envoyée au client sans l'intervention de Nginx.

Considérons un scénario d'exemple impliquant une application 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!"]

Pour gérer cela, des directives spécifiques dans la configuration Nginx sont utilisées :

http {
error_page 500 /html/error.html;
proxy_intercept_errors on;
proxy_hide_header Secret-Header;
}
  • proxy_intercept_errors : Cette directive permet à Nginx de servir une réponse personnalisée pour les réponses du backend avec un code d'état supérieur à 300. Elle garantit que, pour notre exemple d'application uWSGI, une réponse 500 Error est interceptée et gérée par Nginx.
  • proxy_hide_header : Comme son nom l'indique, cette directive masque les en-têtes HTTP spécifiés du client, améliorant ainsi la confidentialité et la sécurité.

Lorsqu'une requête GET valide est effectuée, Nginx la traite normalement, renvoyant une réponse d'erreur standard sans révéler d'en-têtes secrets. Cependant, une requête HTTP invalide contourne ce mécanisme, entraînant l'exposition des réponses brutes du backend, y compris des en-têtes secrets et des messages d'erreur.

merge_slashes désactivé

Par défaut, la directive merge_slashes de Nginx est réglée sur on, ce qui compresse plusieurs barres obliques dans une URL en une seule barre oblique. Cette fonctionnalité, tout en rationalisant le traitement des URL, peut involontairement dissimuler des vulnérabilités dans les applications derrière Nginx, en particulier celles susceptibles d'attaques par inclusion de fichiers locaux (LFI). Les experts en sécurité Danny Robinson et Rotem Bar ont souligné les risques potentiels associés à ce comportement par défaut, surtout lorsque Nginx agit en tant que reverse-proxy.

Pour atténuer de tels risques, il est recommandé de désactiver la directive merge_slashes pour les applications sensibles à ces vulnérabilités. Cela garantit que Nginx transmet les requêtes à l'application sans modifier la structure de l'URL, évitant ainsi de masquer d'éventuels problèmes de sécurité sous-jacents.

Pour plus d'informations, consultez Danny Robinson et Rotem Bar.

En-têtes de réponse Maclicious

Comme indiqué dans cet article, il existe certains en-têtes qui, s'ils sont présents dans la réponse du serveur web, modifieront le comportement du proxy Nginx. Vous pouvez les consulter dans la documentation :

  • X-Accel-Redirect : Indique à Nginx de rediriger en interne une requête vers un emplacement spécifié.
  • X-Accel-Buffering : Contrôle si Nginx doit mettre en mémoire tampon la réponse ou non.
  • X-Accel-Charset : Définit le jeu de caractères pour la réponse lors de l'utilisation de X-Accel-Redirect.
  • X-Accel-Expires : Définit le temps d'expiration pour la réponse lors de l'utilisation de X-Accel-Redirect.
  • X-Accel-Limit-Rate : Limite le taux de transfert pour les réponses lors de l'utilisation de X-Accel-Redirect.

Par exemple, l'en-tête X-Accel-Redirect provoquera une redirection interne dans Nginx. Ainsi, avoir une configuration Nginx avec quelque chose comme root / et une réponse du serveur web avec X-Accel-Redirect: .env fera que Nginx enverra le contenu de /.env (Path Traversal).

Valeur par défaut dans la directive Map

Dans la configuration Nginx, la directive map joue souvent un rôle dans le contrôle d'autorisation. Une erreur courante consiste à ne pas spécifier une valeur par défaut, ce qui pourrait entraîner un accès non autorisé. Par exemple :

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

Sans un default, un utilisateur malveillant peut contourner la sécurité en accédant à une URI indéfinie dans /map-poc. Le manuel Nginx conseille de définir une valeur par défaut pour éviter de tels problèmes.

Vulnérabilité au Spoofing DNS

Le spoofing DNS contre Nginx est réalisable sous certaines conditions. Si un attaquant connaît le serveur DNS utilisé par Nginx et peut intercepter ses requêtes DNS, il peut falsifier des enregistrements DNS. Cette méthode, cependant, est inefficace si Nginx est configuré pour utiliser localhost (127.0.0.1) pour la résolution DNS. Nginx permet de spécifier un serveur DNS comme suit :

resolver 8.8.8.8;

proxy_pass et directives internal

La directive proxy_pass est utilisée pour rediriger les requêtes vers d'autres serveurs, que ce soit en interne ou en externe. La directive internal garantit que certains emplacements ne sont accessibles qu'au sein de Nginx. Bien que ces directives ne soient pas des vulnérabilités en elles-mêmes, leur configuration nécessite un examen minutieux pour éviter des lacunes de sécurité.

proxy_set_header Upgrade & Connection

Si le serveur nginx est configuré pour passer les en-têtes Upgrade et Connection, une attaque de Smuggling h2c pourrait être réalisée pour accéder à des points de terminaison protégés/internes.

Caution

Cette vulnérabilité permettrait à un attaquant de stablish a direct connection with the proxy_pass endpoint (http://backend:9999 dans ce cas) dont le contenu ne sera pas vérifié par nginx.

Exemple de configuration vulnérable pour voler /flag depuis ici:

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

Notez que même si le proxy_pass pointait vers un chemin spécifique tel que http://backend:9999/socket.io, la connexion sera établie avec http://backend:9999, donc vous pouvez contacter tout autre chemin à l'intérieur de ce point de terminaison interne. Il n'importe donc pas qu'un chemin soit spécifié dans l'URL de proxy_pass.

Essayez par vous-même

Detectify a créé un dépôt GitHub où vous pouvez utiliser Docker pour configurer votre propre serveur de test Nginx vulnérable avec certaines des mauvaises configurations discutées dans cet article et essayer de les trouver vous-même !

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

Outils d'analyse statique

GIXY

Gixy est un outil pour analyser la configuration Nginx. L'objectif principal de Gixy est de prévenir les mauvaises configurations de sécurité et d'automatiser la détection des défauts.

Nginxpwner

Nginxpwner est un outil simple pour rechercher des mauvaises configurations et des vulnérabilités courantes de Nginx.

Références

{{#include ../../banners/hacktricks-training.md}}