Sécurité Docker : Attaques en environnement Docker

Copie de securité docker (4)

Expertise

On entend souvent dire qu’utiliser Docker et son environnement c’est s’assurer d’un niveau de sécurité élevé. Compte tenu de la séparation des applications, on s’attend à un niveau plus élevé qu’une architecture virtualisée. Nous allons démontrer qu’il est possible assez « facilement » d’attaquer et de compromettre un container, un hôte ou encore des actifs relatifs à Docker.

Virtualisation Vs Conteneurisation

Tout d’abord, il est important de signaler qu’il n’y a pas de match entre ces deux composants totalement différents. A chacun ses avantages et inconvénients, mais leur raison d’être et d’utilisation est complètement différente.

Aujourd’hui, j’ai choisi d’aborder cette problématique souvent entendue lors d’échanges avec des clients. Il est clair que la manière de sécuriser et d’attaquer l’un ou l’autre est différente. En effet, sur un environnement Docker classique, la séparation des ressources entre conteneurs et hôtes est assez fine. A la différence d’un système de virtualisation qui impose des surcouches supplémentaires afin de garantir une étanchéité des ressources. Il y a donc un manque de flexibilité et de scalabilité pour les systèmes de virtualisation a contrario d’un système de conteneurisation.

Mais cette finesse entre les différentes couches apporte son lot de problèmes de sécurité. Voici un schéma récapitulatif des vecteurs d’attaques possibles sur un système conteneurisé :

Sécurtié docker

Par cette illustration, nous nous rendons compte que la sécurité est assez poreuse. D’autant plus que ne sont pas présents les autres actifs tel que les services « Registry », l’orchestration ou la gestion de conteneurs tel que Portainer.

Nous verrons dans cet article certaines attaques et risques auxquels vous pouvez vous exposer en vous appuyant sur un environnement conteneurisé pas suffisamment sécurisé ou mal configurés.

Compromission distante d’un conteneur ou d’un hôte

Hôte

Il est possible de compromettre de manière simple un serveur hôte lorsque le port 2375 (ou 2376 via TLS)  du deamon Docker est exposé sur Internet sans authentification. Il s’agit alors d’une vulnérabilité critique car ce daemon requiert généralement des droits élevés quand ce ne sont pas les droits root.

Effectuons par exemple une recherche sur Shodan sur le port 2375 présentant un en-tête HTTP JSON :

deamon docker

Nous pouvons alors voir que 4700 résultats sont disponibles via le filtre apposé. Bien entendu, tous ne sont pas accessibles mais si la moitié l’est, cela ouvre des possibilités pour de potentiels attaquants.

Via ce port, le deamon docker expose une API qui permet d’effectuer de nombreuses opérations comme lister les conteneurs, en lancer un, interagir avec un autre, modifier leur exécution, etc.

Un des scénario les plus probables est qu’un attaquant crée un conteneur sur la cible en mode privilégié. Puis qu’il y exécute une commande spécifique pour obtenir un reverse shell et procède à l’évasion du conteneur via le mode privilégié préalablement activé (technique que nous aborderons un peu plus tard dans l’article). Simple, rapide et efficace et voilà l’attaquant aux mains de l’hôte.

A savoir qu’il est également possible de s’évader directement d’un conteneur en utilisant cette technique.

Conteneur

Pour compromettre un conteneur, il existe autant de possibilités que de technologies pouvant être conteneurisées. En effet, le conteneur lance des services et des librairies qui peuvent être vulnérables. Il est donc nécessaire d’attaquer ces services (web, SQL, cache, proxy…) afin de compromettre un conteneur (ex: serveur SQL sans authentification, WordPress non à jour…).

Aussi, dans une architecture micro-services qui repose couramment sur Docker, des rebonds sont possibles entre les conteneurs. C’est possible si de mauvaises configurations sont faites ou des vulnérabilités sont présentes (ex : présence de mot de passe sur un conteneur permettant de se connecter à un autre conteneur…)

Evasion d’un conteneur

Kernel panic

Dans un système Docker totalement à jour, il n’est à priori pas possible de s’évader d’un conteneur si facilement. Cependant, l’expérience montre que bien trop souvent tous les éléments ne sont pas maintenus à jour.

Prenons un premier cas où un kernel n’est pas à jour. Pour rappel, les conteneurs et l’hôte se partagent le kernel. Si ce fameux noyau présente une vulnérabilité de type élévation de privilèges alors un attaquant peut en tirer parti dans un conteneur compromis. Ce qui lui permettra d’obtenir les droits les plus élevés non pas sur le conteneur mais directement sur l’hôte.

Trop de privilèges abolie le privilège

En tant qu’auditeur, on peut faire face à un autre problème tels que des problèmes de configuration. Notamment, dans le cas où les droits accordés aux conteneurs et à leurs ressources sont trop élevés.

Lorsqu’un conteneur est lancé en mode privilégié, un attaquant peut alors accéder à certaines ressources de l’hôte. Ainsi, il peut avoir la capacité de monter le disque de l’hôte et modifier les fichiers présents afin d’obtenir un accès sur la machine et la compromettre.

Cap ou pas cap

De la même manière, le conteneur peut posséder certaines capabilities pour des raisons diverses (debug ou maintenance ). Ces dernières peuvent être utilisées et détournées pour s’évader du conteneur. Voici les capabilities les plus à risque et pouvant être détournées par un attaquant :

  • SYS_ADMIN : équivalent au mode privilégié à peu de choses près
  • SYS_PTRACE : permet de débugguer des processus
  • SYS_MODULE : insertion de modules dans le kernel
  • DAC_READ_SEARCH : permet la lecture de ressources partagées
  • DAC_OVERRIDE : permet d’écrire sur des ressources partagées

Capacité SYS_ADMIN

La capacité SYS_ADMIN permet, comme pour le mode privilégié, de monter des ressources tel que des partitions de l’hôte. Ce qui signifie qu’ un attaquant peut modifier des fichiers critiques pour obtenir un accès sur l’hôte.

Capacité SYS_PTRACE

Pour la capacité SYS_PTRACE, un attaquant peut en tirer profit pour s’évader si en plus d’être active, le PID namespace est partagé entre plusieurs conteneurs ou directement avec l’hôte. L’attaquant peut alors s’injecter dans l’un des processus, rebondir sur l’actif avec qui est partagé celui-ci et exécuter des commandes avec le même niveau de privilèges que le processus.

Capacité SYS_MODULE

Concernant la capacité SYS_MODULE, elle permet au conteneur, si besoin, d’insérer un module au kernel. Il est alors possible de créer un module malveillant à insérer au kernel. Pour rappel, le noyau est partagé entre l’hôte et les conteneurs : en insérant ce module malveillant, il sera donc exécuté par l’hôte qui porte le kernel et l’attaquant peut donc obtenir un accès à haut niveau de privilèges sur ce dernier.

Capacité DAC_READ_SEARCH

La capacité DAC_READ_SEARCH mappent certains fichiers de l’hôte sur le conteneur. En utilisant un exploit connu appelé Shocker, il est possible de cartographier d’autres fichiers normalement non accessibles depuis le conteneur et de les lire. Il s’agit de fichiers hôte tel que /etc/shadow contenant les mots de passe système. Cette capacité ne permet pas directement de s’évader mais elle peut fortement aidée.

Capacité DAC_OVERRIDE

Enfin la capacité DAC_OVERRIDE est très souvent présente voire nécessaire au fonctionnement d’un conteneur, et seule, elle n’a pas de grande utilité pour un acteur malveillant. Cependant, combiné à la capacité évoquée juste avant (DAC_READ_SEARCH), elle permet l’évasion total du conteneur. En effet, un attaquant va pouvoir utiliser le même procédé qu’auparavant pour mapper des fichiers de l’hôte normalement inaccessible. Mais encore, il va être en capacité de les modifier : il est possible d’imaginer un scénario où il modifie le mot de passe d’un utilisateur présent sur l’hôte directement dans le fichier /etc/shadow et qu’il accède à la machine hôte via SSH.

Cependant, il ne faut pas se voiler la face : la plupart des capacités citées nécessitent d’avoir un accès root sur le conteneur. Ceci rajoute une étape supplémentaire à l’attaquant mais le jeu peut en valoir la chandelle.

Les Registries comme vecteur de contamination

On appelle « Registry », un système qui stocke les images s’appuyant sur les conteneurs. Ces Registries permettent donc aux DevOps de mettre à disposition les images toutes faites aux systèmes. L’objectif est de ne pas avoir à les re-créer à chaque fois.

Des registries publiques existent tel que celui proposé par Docker lui-même. Mais on internalise les registries pour les infrastructures privées, malgré que dans certains cas, ils sont mal protégés car les risques sont mal évalués.

En effet, atteindre un registry permettrait à un attaquant d’extraire les images. Celui-ci pouvant contenir des informations sensibles telles que des mots de passe, des clés d’authentification ou encore des certificats. De la même manière, il est possible d’imaginer un attaquant pousser une image contenant une porte dérobée sur le système d’information ou encore en modifier une pour les mêmes raisons.

Encore une fois, quelque soit le système de Regitry, ils fonctionnent plus ou moins de la même manière et s’appuient donc sur la même API. Ce qui rend les actions relativement simples à un attaquant à partir du moment où il est en capacité de communiquer avec le fameux Registry.

Et comment se défendre ?

Tout d’abord, il est important de comprendre que ces vulnérabilités ciblent des problèmes de sécurité : il est possible d’effectuer un audit afin de vérifier s’il y a une erreur de configuration ou un oubli.

Il existe des outils permettant d’analyser la sécurité des images avant déploiement ou encore d’analyser le comportement des conteneurs en runtime. Ces derniers sont relativement simples à mettre en place et relativement efficaces.

Pour l’analyse sécurité d’images Docker, on utilise le plus souvent Clair et Trivy. Concernant,  l’exécution en temps réel, Falco permet de lever des alertes en temps réel sur des actions suspicieuses. Celles-ci ayant lieu tant sur l’hôte que sur les conteneurs, il est idéal d’intégrer un outil de type SIEM.

AppArmor, SELinux ou encore Seccomp peuvent réduire les risques de compromission en limitant l’exécution de certaines actions via la création de profils de sécurité.

Pour plus de détails sur ces systèmes de protection, un article devrait faire écho à celui-ci.

Conclusion

Cet article ne se veut pas totalement exhaustif et il existe d’autres techniques de compromission ou d’évasion Docker comme l’exploitation de vulnérabilités inhérentes à Docker. Cependant, il lève un mythe disant que Docker est plus sécurisé que d’autres architectures. Il ne l’est pas forcément plus ni forcément moins.

Malheureusement, on constate que c’est soit par un défaut de configuration soit par un manque de mise à jour que les vulnérabilités s’introduisent. Il est vrai qu’avec Docker, où une ouverture de port ou une mauvaise capacité activée, peut conduire à une compromission de l’architecture entière.

Ecrit par Ricardo Matias, Consultant Sécurité chez NBS System