1 points par GN⁺ 2023-07-04 | 1 commentaires | Partager sur WhatsApp
  • Nginx, serveur web polyvalent qui domine le marché avec une part majeure depuis 2004
  • Une mauvaise configuration de Nginx peut entraîner des failles de sécurité et une exposition de données
  • Présentation de NavGix, un outil automatisé pour détecter les vulnérabilités de Nginx
  • Cette vulnérabilité peut permettre d’accéder à des fichiers et répertoires au-delà du périmètre prévu
  • Des études de cas sur Bitwarden et le HPC Toolkit de Google montrent la gravité de cette vulnérabilité

1 commentaires

 
GN⁺ 2023-07-04
Commentaires Hacker News
  • Pour information, gixy (un vérificateur de configuration nginx) détecte ce problème : https://github.com/yandex/gixy/blob/master/docs/en/plugins/a...
    Et NixOS exécutait automatiquement gixy sur les configurations générées via son système, en refusant le build du système s’il y avait un problème

    • Si un serveur web oblige les utilisateurs à ajouter un outil supplémentaire pour éviter ce genre de piège, il faudrait peut-être revoir les valeurs par défaut
    • Je ne connaissais pas gixy, je l’ai lancé sur mon home server et il a trouvé une vulnérabilité. J’utilisais $uri dans une redirection 301
    • J’ai essayé Nix une fois et jusqu’ici ça a l’air plutôt bien
      Par contre, je me demande s’il existe un meilleur chercheur d’options. Je n’aimais pas devoir chercher dans l’ensemble des milliers d’options ; j’aimerais pouvoir regarder seulement un paquet comme ssh puis voir uniquement les options qui s’y rapportent, mais il y a trop de résultats sans rapport
    • NixOS n’exécute plus Gixy. Voir https://github.com/NixOS/nixpkgs/pull/209075
  • C’est peut-être une question bête, mais y a-t-il une bonne raison pour que nginx autorise la remontée vers le répertoire parent avec .. dans le chemin d’URL ? Ça ressemble juste à un comportement qui attend les problèmes
    Édition : je suis un peu confus sur ce qui se passe exactement dans la vulnérabilité d’origine. On dirait que http://localhost/foo../secretfile.txt est interprété comme quelque chose du genre /var/www/foo/../secretfile.txt, mais alors, sur un serveur non vulnérable, pourquoi http://localhost/foo/../secretfile.txt ne serait-il pas interprété de la même façon ? Je ne comprends pas pourquoi .. dans le chemin ne fonctionne que dans certains cas

    • C’est un problème connu depuis très longtemps dans nginx, et c’est un vecteur d’attaque fréquent en CTF : https://book.hacktricks.xyz/network-services-pentesting/pent...
    • Le problème, c’est que l’URL n’est pas un chemin réel. Une URL est une adresse abstraite vers une ressource, qui peut être un répertoire, un fichier, un exécutable, un flux, etc.
      Dans ce cas, une partie de l’URL est interprétée comme un répertoire (http://localhost/foo) par nginx à cause de la façon dont la configuration la mappe au système de fichiers local. Comme cela semble désigner un répertoire, nginx construit alors le chemin complet de la ressource demandée comme "${mapped_path}/../secretfile.txt", ce qui n’a aucun sens du point de vue de l’URL mais devient valide sur le système de fichiers local. Une URL n’est qu’une chaîne, pas une vraie suite d’éléments de chemin, donc la position des slashs n’a pas d’importance intrinsèque
      C’est un problème qu’on voit très souvent, dans tous les serveurs web, depuis les débuts du Web. Le mapping direct des URL vers des chemins de fichiers était populaire parce qu’on partait de simples serveurs de fichiers avec index, puis on est vite passé à des environnements hybrides où l’URL n’était plus un chemin mais un identifiant d’application. On désignait l’application avec une partie du chemin, et le reste devenait des paramètres ou des arguments
      Et de manière générale, respecter . ou .. de l’URL pour des objets du système de fichiers n’a généralement pas de sens. Mes applications normalisent les chemins de requête pour garantir un mapping correct. Les navigateurs, eux, traitent les URL comme des chemins lorsqu’ils construisent des liens relatifs, donc il faut aussi faire attention à l’usage du / final selon les cas. Cela peut pointer vers des ressources dont le sens côté serveur est différent
    • Dans un cas d’usage “normal”, il n’y en a pas besoin. Il semblerait plus logique d’avoir dans location un drapeau du type allow_parent_traversal on; et d’en faire un comportement activé explicitement
    • J’imagine que NginX vérifie probablement "/foo/bar/.." et l’interdit ou le normalise en "/foo/". Mais "/foo/bar.." est un nom de fichier tout à fait valide, donc ce type de vérification semble lui échapper
    • Le fait que .. fonctionne ou non dans un chemin dépend entièrement des permissions de fichiers
      Dans ce cas, si l’on suppose que depuis le répertoire d’index web (../index.html) on a le droit de lire jusqu’au répertoire racine (/), alors une fois qu’on peut remonter jusqu’à la racine, on peut aussi voir tous les fichiers lisibles par tous accessibles depuis cette racine, par exemple /etc/passwd
      Imaginez une fourche à trois dents : le serveur web se trouve sur la dent tout à droite. Si la partie où les dents se rejoignent représente le système de fichiers, alors, tant que le serveur web a les permissions d’accès sur les fichiers et répertoires allant de sa dent droite jusqu’au manche, une fois arrivé au manche il peut continuer à accéder aux fichiers des autres dents
  • Je ne vois pas pourquoi cela ne serait pas considéré comme une vulnérabilité nginx. Ce comportement est complètement absurde, ne semble avoir aucun usage bénéfique, et il est immédiatement exploitable

    • C’est fait ainsi pour des raisons de performance. Une simple substitution de texte est bien plus rapide que de vérifier si un chemin se termine correctement par un slash
      Il faut aussi se rappeler que nginx a gagné en popularité grâce à des benchmarks qui le présentaient comme plus “web scale” qu’Apache2
  • Je me dis qu’on pourrait faire comme ceci : ajouter une option proche d’une capability Linux qui supprimerait la possibilité d’utiliser .. dans l’analyseur de noms de fichiers du noyau Linux
    Dans les applis web, il existe depuis l’époque des modems téléphoniques toutes sortes de contournements pour réussir à glisser .. d’une manière ou d’une autre. Comme pour d’autres catégories de bugs en espace utilisateur que le noyau Linux a déjà traitées, il serait peut-être temps de trouver un moyen de fermer ce problème une bonne fois pour toutes

    • Il y a RESOLVE_BENEATH dans https://man7.org/linux/man-pages/man2/openat2.2.html
      FreeBSD propose aussi cette fonctionnalité dans openat(2) standard via O_RESOLVE_BENEATH
    • Cela casserait beaucoup trop de choses, ce ne serait pas une décision raisonnable
      Il suffit d’exécuter nginx avec un utilisateur séparé aux privilèges très limités, ou dans Docker. En y ajoutant des mises à jour régulières, on règle en général 90 % des problèmes de sécurité
    • /some/../path devrait être interdit dans presque 100 % des cas. À part « quelqu’un a écrit du code affreux », il n’y a pas de cas d’usage rationnel
      ../some/path a au moins parfois un sens
      Cela dit, ce ne serait sans doute pas aussi utile qu’on l’imagine. Beaucoup d’applis résolvent déjà .. avant de passer le chemin au système d’exploitation
    • Pas une grande différence. Le code normalise souvent les chemins avant même d’atteindre l’API du système de fichiers
    • Côté noyau, il existe un autre mécanisme, à savoir le système de permissions sur lequel nous nous appuyons
      Si l’on sert des fichiers d’un dossier vers le web, c’est au framework web de veiller à ne pas sortir du dossier racine public dont il a la charge. Si vous faites cela vous-même, il faut prévoir toutes sortes de situations, y compris celle-ci
  • « Le Google VRP Team a accordé une récompense de 500 dollars pour la découverte de cette vulnérabilité. Il a estimé que l’impact sur l’application n’était pas assez grave pour justifier une prime plus élevée » : donc l’exposition d’un e-mail de compte GCP et d’une clé privée ne vaut que 500 dollars ? C’est quoi, au juste ? Très Google, en effet

  • Heureusement, les éléments divulgués étaient encore chiffrés. Même une entreprise spécialisée dans ce domaine n’est pas à l’abri d’une fuite, donc honnêtement, c’est à peu près le meilleur scénario possible

  • Le titre a été pas mal retouché. Le titre original est Hunting for Nginx Alias Traversals in the wild
    Le titre de la soumission HN met l’accent sur la vulnérabilité de Bitwarden, mais l’article traite aussi du cas de Google

    • Très bien, j’ai remis le titre d’origine. Le titre de soumission était « Leaking Bitwarden's Vault with a Nginx vulnerability »
  • Si l’on a seulement besoin d’un serving de fichiers statiques sûr et fiable, avec une consommation minimale de ressources, quelle est aujourd’hui la meilleure option ? Autrefois, j’aurais choisi Nginx, mais du point de vue de la sécurité, je me demande s’il ne vaut pas mieux un outil plus spécialisé et moins configurable

    • J’utilise https://static-web-server.net/
      C’est multiplateforme, écrit en Rust, la configuration est simple, et les valeurs par défaut sont sûres. Il existe aussi une image de conteneur durcie et un module NixOS durci
      Je ne recommande pas Caddy. Son image Docker officielle s’exécute en tant que root par défaut [1], et il ne fournit pas non plus de fichier d’unité systemd correctement sandboxé [2]
      [1]: https://github.com/caddyserver/caddy-docker/issues/104
      [2]: https://github.com/caddyserver/dist/blob/master/init/caddy.s...
      Édition : formulation ajustée
    • Petit moment autopromo : Caddy fait très bien le travail ici. Il offre le HTTPS automatique, il est écrit en Go donc il n’y a pas à craindre les bugs de sûreté mémoire, et il dispose d’un solide module file_server
    • J’utilise Caddy depuis des années. Il fournit des certificats SSL automatiques, le serving de fichiers et le reverse proxy, et sa configuration est très simple et claire. Comme c’est un binaire unique en Go, même « l’installation » est facile, et il n’y a qu’un seul fichier de configuration
    • Configurer Caddy pour servir des fichiers statiques est assez simple
    • Merecat : https://github.com/troglobit/merecat/
  • Question peut-être stupide, mais pourquoi Bitwarden autorisait-il au départ des requêtes non authentifiées vers /attachments ? Même avec un bug Nginx, si cette URL avait nécessité une authentification, la requête n’aurait-elle pas échoué ?

    • Il s’agit d’un exploit visant la configuration du serveur web, donc le code d’authentification de Bitwarden — voire le code de Bitwarden tout court — n’est jamais exécuté. Ce n’est ni étrange ni incorrect qu’un projet utilise sa propre authentification plutôt que celle de Nginx ou d’un module
      Cela dit, Bitwarden reste responsable d’avoir déployé cette configuration risquée via Docker. Bitwarden semble d’ailleurs l’avoir reconnu et l’a corrigée par la suite
  • Désolé pour cette question idiote. Une propriété correcte des répertoires et des fichiers ne bloque-t-elle pas ce type de traversée ?
    Si nginx ne s’exécute pas en root, comment peut-il lire autre chose que les fichiers explicitement attribués à l’utilisateur nginx ?

    • Bien sûr que si, on peut l’empêcher. Il suffit d’exécuter l’app avec un utilisateur, nginx avec un autre, de mettre go-rwx sur tous les fichiers de l’app, de définir le groupe des fichiers « static » sur www-data, puis de ne donner que g+r ; ainsi le serveur web ne peut pas accéder aux fichiers de l’app
      C’est littéralement les bases de l’hébergement d’applications, et c’est comme ça que les gens faisaient déjà il y a 20 ans
    • Ah, les merveilles de l’umask 022. Personnellement, je recommande toujours d’empêcher les autres utilisateurs de lire les fichiers. Si c’est trop compliqué pour tous les fichiers, faites-le au moins pour les répertoires sensibles comme ceux sous /home
      Il faudra peut-être ajuster un peu plus l’appartenance aux groupes, mais ça en vaut largement la peine
    • Je ne sais pas pour les autres, mais aujourd’hui, pour un usage perso, je n’installe plus nginx proprement. Je lance juste une image Docker. Et je ne vérifie pas vraiment si elle tourne en root ou non
      Je suis peut-être en train de faire une énorme bêtise. Aïe
    • L’umask par défaut est généralement 022, donc dans la plupart des cas les workers nginx peuvent lire mais pas écrire. Pas besoin que ce soit explicitement attribué à un utilisateur comme www-data. Si l’application génère des données sensibles, il est évidemment préférable d’utiliser un umask 077
    • Exact
      Malheureusement, nginx et les autres serveurs web doivent généralement s’exécuter en root dans une application web classique, parce qu’ils doivent écouter sur les ports 80 ou 443. Les ports inférieurs à 1024 ne peuvent être ouverts que par root
      Plus d’explications ici : https://unix.stackexchange.com/questions/134301/why-does-ngi...