
Introduction
Docker est un outil incontournable dans le domaine du DevOps pour automatiser, déployer et gérer des conteneurs de manière flexible et efficace. Il est souvent perçu comme une solution offrant une séparation complète entre les conteneurs et leur hôte, avec une sécurité considérée parmi les meilleures. Cependant, cette réputation n’est pas infaillible : Docker peut être compromis en raison de vulnérabilités ou de mauvaises configurations, permettant dans certains cas un accès non autorisé à l’hôte. Dans cet article, nous allons explorer les différentes méthodes d’exploitation de Docker, les techniques d’évasion des conteneurs et les moyens de renforcer la sécurité pour éviter de telles situations.
1. Contexte : Pourquoi Docker est-il une cible ?
Docker est devenu un pilier des pratiques DevOps modernes, permettant aux équipes de développement et d’exploitation de déployer des applications rapidement et efficacement dans des environnements isolés. Cependant, cette adoption massive a également attiré l’attention des attaquants, car une mauvaise configuration ou une vulnérabilité dans Docker peut avoir des conséquences graves.
Pourquoi Docker est utilisé massivement ?
- Flexibilité et portabilité : Docker permet de faire tourner des applications dans des conteneurs indépendants de l’hôte, garantissant ainsi un déploiement cohérent sur différentes machines.
- Gain de temps : Les conteneurs Docker démarrent rapidement, ce qui facilite les tests, les itérations et les mises à jour continues.
- Écosystème riche : Avec des millions d’images disponibles sur Docker Hub, les équipes ont accès à des outils et frameworks préconfigurés pour accélérer leurs projets.
Docker donne une fausse impression de sécurité
Docker est souvent perçu comme une solution offrant une isolation parfaite des conteneurs. Cette perception provient de ses mécanismes qui segmentent les ressources. Cependant, ces mécanismes ne sont pas infaillibles. Une mauvaise configuration ou une vulnérabilité peut permettre l’accès non autorisé à l’hôte ou l’évasion de conteneur, contournant les restrictions d’isolation.
Docker est une cible de choix pour les attaquants en raison de son omniprésence dans les environnements DevOps et cloud. Sa popularité croissante signifie qu’il est souvent utilisé pour exécuter des applications critiques, ce qui en fait un point d’entrée stratégique pour les cyberattaques. Les erreurs de configuration, comme l’exposition de l’API sans authentification, et l’utilisation d’images non vérifiées augmentent les risques. De plus, le partage du noyau entre l’hôte et les conteneurs permet, en cas de compromission, d’échapper à l’isolation et d’accéder à l’hôte, exposant ainsi toute l’infrastructure.
2. Compromission d’un hôte via Docker
Compromission direct de l’hôte en exploitant le démon Docker
Le démon Docker (dockerd) est un service essentiel qui orchestre toutes les opérations liées aux conteneurs, comme leur création, exécution ou suppression. Cette API permet à des services externes comme les orchestrateurs d’interagir avec les conteneurs. Il communique avec le client Docker via une API REST, qui peut être exposée de plusieurs façons :
- Localement via une socket Unix (
/var/run/docker.sock
). - À distance via une API accessible sur le réseau, généralement sur le port 2375 (non sécurisé) ou 2376 (chiffré avec TLS).
Cependant, lorsqu’elle est activée, elle ne dispose souvent pas d’authentification par défaut et le démon est généralement lancé avec les privilèges root.
Exploitation pratique :
Après avoir identifié l’adresse IP de la cible et le port exposant l’API, il faut installer le démon Docker et le configurer ainsi:
export DOCKER_HOST="tcp://<IP_CIBLE>:<PORT>"
On peut ensuite vérifier la listes des images et des conteneurs disponibles avec les commandes suivantes:
docker images
docker ps -a
On peut ensuite lancer l’image choisie ainsi:
docker run -it -v /:/mnt <IMAGE>
La commande docker run permet de lancer un image choisie sur l’hôte. Les options suivantes permettent de:
- -it permet de lancer la commande de manière interactive afin d’accéder à un terminal
- -v : Permet de choisir un point de montage, ici /mnt.
Le conteneur dispose désormais d’un accès complet aux fichiers du système hôte, montés dans le répertoire /mnt
. On pourrait à présent lire les fichiers contenant les secrets du système pouvant permettre un accès direct (ex: /etc/shadow) ou modifier des fichiers système afin de créer un reverse shell.
Compromission d’un conteneur
Si l’attaquant ne peut pas faire de compromission directe, il peut cibler un ou plusieurs conteneurs pour prendre pied dans l’environnement. Une fois le conteneur compromis, l’objectif est souvent de maintenir un accès persistant, d’extraire des données sensibles, ou de l’utiliser comme tremplin pour accéder à l’hôte.
Exploitation d’une application vulnérable
La méthode la plus courante pour compromettre un conteneur consiste à exploiter une application vulnérable qu’il expose. Cela dépend largement des services ou applications accessibles via le conteneur. Les techniques de compromission peuvent inclure l’utilisation de mots de passe par défaut, l’exploitation de vulnérabilités connues dans une application ou des failles présentes par défaut dans la configuration.
Utilisation d’une image compromise
Les conteneurs Docker reposent sur des images, et une image compromise ou non vérifiée peut servir de vecteur d’attaque. Cette compromission peut survenir de deux manières principales : soit par l’utilisation d’une image publique déjà compromise et téléchargée sur le système, soit par la distribution d’une image malveillante à la cible via des techniques d’ingénierie sociale. Ces scénarios exploitent la confiance accordée aux images Docker pour introduire des backdoors, exfiltrer des données ou compromettre l’ensemble du système.
Méthodes d’évasion de conteneurs Docker
Une fois un conteneur compromis, l’objectif de l’attaquant est souvent de contourner l’isolation imposée par Docker pour accéder à l’hôte ou à d’autres conteneurs. Bien que Docker utilise des mécanismes comme les namespaces, les cgroups et les capabilities pour isoler les conteneurs, ces mesures ne sont pas toujours infaillibles. Une mauvaise configuration ou une exploitation de vulnérabilités peut permettre une évasion.
Reconnaissance de l’environnement conteneurisé
Avant de tenter une évasion, l’attaquant doit déterminer s’il se trouve dans un environnement conteneurisé et identifier les limites de l’isolation. Pour cela, on dispose de différentes méthodes :
- Fichiers spécifiques à Docker : Vérifier la présence de fichiers comme
/proc/1/cgroup
ou/proc/self/mountinfo
pour détecter des traces d’environnement conteneurisé ou le fichier.dockerinit
(obsolète sur les versions modernes de Docker). - Détection des ressources partagées : Rechercher les processus ou interfaces réseau partagés avec l’hôte grâce à la commande:
ps aux
Exploitation du noyau partagé
Docker utilise le noyau de l’hôte pour tous ses conteneurs. Cela signifie que si une vulnérabilité existe dans le noyau, un attaquant peut l’exploiter pour échapper à l’isolation.
Exemple : DirtyCow (CVE-2016-5195)
DirtyCow est une vulnérabilité du noyau Linux qui permet à un attaquant d’écrire sur des fichiers en lecture seule, permettant une élévation de privilèges.
Exploitation pratique :
- Identifier la version du noyau :
uname -a
- Trouver un exploit correspondant et l’exécuter depuis le conteneur pour obtenir un accès root sur l’hôte.
Exécution en mode privilégié
Le mode --privileged
est une option spéciale dans Docker qui accorde au conteneur des permissions étendues. En activant ce mode, le conteneur obtient les droits suivants:
- Accès total aux ressources : Le conteneur peut interagir librement avec les périphériques matériels de l’hôte, comme les disques, les périphériques USB ou les interfaces réseau.
- Levée des restrictions de capabilities : Les capabilities (droits spécifiques accordés aux processus) qui sont normalement limitées pour un conteneur sont toutes activées.
- Accès aux espaces de noms de l’hôte : Le conteneur peut interagir directement avec les processus, les réseaux et les fichiers de l’hôte.
En bref, on pourrait simplifier en disant qui si on a les droits en root sur le conteneur, on a presque autant de permissions qu’un utilisateur root sur l’hôte. Un attaquant pourrait donc monter une partition pour accéder directement aux fichiers de l’hôte, manipuler directement les paramètres du noyau, etc.
Abus des capabilities
Les capabilities sont un mécanisme de sécurité intégré au noyau Linux qui permet de diviser les privilèges root en droits spécifiques. Grâce à ce système, Docker peut restreindre les actions qu’un processus peut effectuer dans un conteneur, renforçant ainsi la sécurité en limitant les accès inutiles. Cependant, si certaines capabilities critiques sont mal configurées ou laissées activées, elles peuvent être exploitées pour contourner l’isolation des conteneurs et compromettre l’hôte.
Par défaut, un conteneur Docker n’a accès qu’à un sous-ensemble des capabilities disponibles, ce qui réduit les risques. Par exemple, certaines actions comme charger des modules noyaux ou modifier des namespaces système sont désactivées, sauf si elles sont explicitement autorisées. Il existe un certain nombre de capabilities dangereuse dans le cas d’une évasion de conteneur Docker. Nous allons voir ici les plus courantes.
CAP_SYS_ADMIN
Cette capability, souvent appelée le « couteau suisse » des permissions, donne accès à de nombreuses opérations sensibles. Elle permet notamment de manipuler les namespaces, de monter ou démonter des systèmes de fichiers, et de modifier les paramètres du noyau Linux.
Pour l’exploiter, un attaquant peut monter un système de fichiers de l’hôte dans le conteneur : mount /dev/sda1 /mnt
. Une fois monté, il peut accéder aux fichiers sensibles de l’hôte ou modifier son environnement à l’aide de la commande chroot
: chroot /mnt
.
CAP_SYS_PTRACE
Cette capability autorise le débogage et l’injection de code dans d’autres processus. Elle est fréquemment utilisée par des outils de diagnostic, mais elle peut également être exploitée pour manipuler des processus critiques. L’attaquant peut identifier un processus avec des privilèges élevés à l’aide de ps aux
puis utiliser un outil comme gdb
pour attacher un processus et y injecter du code malveillant.
CAP_SYS_MODULE
Cette capability permet de charger ou décharger des modules dans le noyau. Elle est particulièrement critique, car un module malveillant peut donner à l’attaquant un contrôle total sur l’hôte. L’attaquant peut charger un module malveillant pour exécuter un code arbitraire avec les privilèges root.
CAP_DAC_READ_SEARCH
Cette capability permet de contourner les restrictions de lecture sur des fichiers ou des répertoires protégés, même si les permissions standards ne le permettent pas. L’attaquant peut lire des fichiers sensibles de l’hôte.
Exploitation d’autres mauvaises configurations
Certaines configurations laxistes permettent aux attaquants de prendre le contrôle de l’hôte, notamment :
- Volumes mal sécurisés : Monter un volume sensible avec
docker run -v /:/mnt
donne accès à l’ensemble des fichiers de l’hôte. - Exposition des sockets Docker : L’accès au socket
/var/run/docker.sock
permet de manipuler directement le démon Docker.