Nginx

Apprenez le piratage AWS de zéro à héros avec htARTE (Expert de l'équipe rouge AWS de HackTricks)!

Autres façons de soutenir HackTricks:

Configuration instantanément disponible pour l'évaluation des vulnérabilités et les tests de pénétration. Lancez un pentest complet de n'importe où avec plus de 20 outils et fonctionnalités allant de la reconnaissance au reporting. Nous ne remplaçons pas les pentesteurs - nous développons des outils personnalisés, des modules de détection et d'exploitation pour leur donner du temps pour creuser plus profondément, ouvrir des shells et s'amuser.

Emplacement racine manquant

Essentiels de la configuration du répertoire racine Nginx

Lors de la configuration du serveur Nginx, la directive root joue un rôle critique 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 répertoire racine. Cette configuration permet d'accéder 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, voire des informations d'identification chiffrées utilisées pour l'authentification de base HTTP.

Configuration de l'alias LFI mal configurée

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 Fichier Local (LFI) peut être introduite involontairement par le biais d'une configuration qui ressemble à ce qui suit:

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

Cette configuration est vulnérable aux attaques LFI car le serveur interprète les requêtes telles que /imgs../flag.txt comme une tentative d'accéder à des fichiers en dehors du répertoire prévu, se résolvant effectivement en /chemin/images/../flag.txt. Cette faille 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 devrait être ajustée comme suit :

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

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

Tests d'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ée

Consultez la page suivante pour apprendre comment contourner les directives telles que:

location = /admin {
deny all;
}

location = /admin/ {
deny all;
}

Utilisation non sécurisée des variables / Fractionnement de requête HTTP

Les variables vulnérables $uri et $document_uri doivent être remplacées par $request_uri.

Une expression régulière peut également être vulnérable comme suit :

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 de nouveaux caractères de ligne dans les requêtes HTTP, et leurs formes encodées en URL sont représentées comme %0d%0a. Inclure ces caractères dans une requête (par exemple, http://localhost/%0d%0aDetectify:%20clrf) à un serveur mal configuré entraîne le serveur à émettre un nouvel en-tête nommé Detectify. Cela se produit car 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 fractionnement des réponses sur 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 de vulnérabilités et des mécanismes de détection. Par exemple, pour détecter cette mauvaise configuration d'un point de vue boîte noire, vous pourriez utiliser ces requêtes :

  • https://example.com/%20X - Tout code HTTP

  • https://example.com/%20H - 400 Bad Request

Si vulnérable, le premier retournera "X" car c'est n'importe quelle méthode HTTP et le second 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 et présenté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 à nouveau que $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;
}

Toute variable

Il a été découvert que des 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 il 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 permis d'identifier son occurrence dans le module de filtre SSI du code source de Nginx, en identifiant les Inclusions Côté Serveur (SSI) comme la cause principale.

Pour détecter cette mauvaise configuration, la commande suivante peut être exécutée, ce 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’

Les analyses de cette mauvaise configuration sur les systèmes ont révélé de multiples cas où les variables Nginx pouvaient être affiché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 fructueux.

Lecture brute de la réponse du serveur

Nginx propose une fonctionnalité via proxy_pass qui permet l'interception des erreurs et des en-têtes HTTP générés par le serveur, dans le but de masquer les messages d'erreur internes et les en-têtes. Cela est réalisé en faisant en sorte que Nginx serve des pages d'erreur personnalisées en réponse aux erreurs du serveur. Cependant, des défis surviennent lorsque Nginx rencontre une requête HTTP invalide. Une telle requête est transmise au serveur tel qu'elle a été reçue, et la réponse brute du serveur est ensuite directement envoyée au client sans l'intervention de Nginx.

Considérez 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 de 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 serveur avec un code d'état supérieur à 300. Cela garantit que, pour notre application uWSGI exemple, une réponse d'erreur 500 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 serveur, y compris les en-têtes secrets et les messages d'erreur.

merge_slashes défini sur off

Par défaut, la directive merge_slashes de Nginx est définie 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 sujettes aux attaques d'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, en particulier 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 susceptibles à ces vulnérabilités. Cela garantit que Nginx transmet les requêtes à l'application sans modifier la structure de l'URL, ne masquant ainsi aucun problème de sécurité sous-jacent.

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

Valeur par défaut dans la directive Map

Dans la configuration de Nginx, la directive map joue souvent un rôle dans le contrôle d'autorisation. Une erreur courante est de ne pas spécifier de 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 une default, un utilisateur malveillant peut contourner la sécurité en accédant à une URI non définie dans /map-poc. Le manuel de Nginx recommande de définir une valeur par défaut pour éviter de tels problèmes.

Vulnérabilité de l'usurpation DNS

L'usurpation DNS contre Nginx est réalisable dans certaines conditions. Si un attaquant connaît le serveur DNS utilisé par Nginx et peut intercepter ses requêtes DNS, il peut usurper 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;

Directives proxy_pass et 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'à l'intérieur de Nginx. Bien que ces directives ne soient pas des vulnérabilités en elles-mêmes, leur configuration nécessite un examen attentif pour éviter les failles de sécurité.

proxy_set_header Upgrade & Connection

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

Cette vulnérabilité permettrait à un attaquant d'établir une connexion directe avec le point de terminaison proxy_pass (http://backend:9999 dans ce cas) dont le contenu ne serait pas vérifié par nginx.

Exemple de configuration vulnérable pour voler /flag à partir de 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;
}

Notez que même si proxy_pass pointait vers un chemin spécifique tel que http://backend:9999/socket.io, la connexion sera établie avec http://backend:9999 afin que vous puissiez contacter tout autre chemin à l'intérieur de ce point de terminaison interne. Ainsi, il n'importe pas si un chemin est 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 est un outil d'analyse de configuration Nginx. Le but principal de Gixy est de prévenir les mauvaises configurations de sécurité et d'automatiser la détection des failles.

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

Références

Configuration instantanément disponible pour l'évaluation des vulnérabilités et les tests de pénétration. Exécutez un pentest complet de n'importe où avec plus de 20 outils et fonctionnalités allant de la reconnaissance aux rapports. Nous ne remplaçons pas les pentesteurs - nous développons des outils personnalisés, des modules de détection et d'exploitation pour leur donner du temps pour creuser plus profondément, ouvrir des shells et s'amuser.

Apprenez le piratage AWS de zéro à héros avec htARTE (HackTricks AWS Red Team Expert)!

Autres façons de soutenir HackTricks:

Dernière mise à jour