Sécurisation du montage de volume de docker
Bonjour aujourd'hui on va faire de la sécurité informatique.
Docker est un outils fantastique mais peut devenir la pire des failles de sécurité.
On va découper l'article en 2 parties:
- D'abord l'exploit qui permet l'escalade de privilèges
- Comment combler cette faille
Mise en place de l'exploit
Je vais faire ma démo sur une Ubuntu 20.04
Via l'utilisateur priviligé (root ou sudo).
On installe docker
On créé un utilisateur non-priviligié, sans homedir et sans login.
On ajoute l'utilisateur alice
au group docker
On créé un dossier de travail
On donne l'ownership de ce dossier à alice
On va maintenant devenir alice
On vérifie qu'on est bien alice
uid=1000() ) groups=119() )
Vérifions qu'on a 0 droit priviligié.
Bon visiblement on est pas root.
On vérifie que l'on a le droit d'utiliser docker
Direction le dossier de travail
Maintenant on créé ce Dockerfile, il va nous permettre d'utiliser notre volume. J'utilise l'image ubuntu
pour avoir un shell, mais on peut le faire avec toute sorte d'image de la plus simple à la plus compliquée.
FROM ubuntu
ENV WORKDIR /opt/workdir
RUN mkdir -p $WORKDIR
VOLUME [ $WORKDIR ]
WORKDIR $WORKDIR
Construisons notre joli cheval de Troie.
Maintenant on va faire un truc rigolo ( pas pour la machine cible 😋 ).
On va monter /
dans notre container!
Et là on commence à jouer 😋
Avec le shell du container
# echo "I was here" > /opt/workdir/flag
Pas de denied! 😨
C'est pas le pire, connectez vous avec une autre session utilisateur priviligié sur le serveur hôte de docker.
# cat /flag
Bon on vient d'écrire dans /
depuis un container en lançant celui-ci avec un utilisateur non-privilégié.
Mais il y a bien pire !! Même si on est déjà game over !!!
Oui visudo
c'est là pour la décoration!
On sort du container.
Puis
# id
uid=0() ) groups=0()
Et voilà c'est la fin des temps. Vous laissez un utilisateur runner un container et il devient root !
On sécurise
Heureusement il y a une parade à tout ça. Et ceci s'appelle le userns-remap
.
L'idée de base est simple, si le container n'a pas explicitement le droit de monter un dossier de l'host on remap l'utilisateur du dossier vers un autre utilisateur.
Cela à pour effet de passer en readonly le montage.
En utilisant votre session priviligiée.
Tout d'abord on défini un fichier /etc/docker/daemon.json
. S'il n'existe pas déjà, vous devez le créer.
Ensuite vous devez redémarrer le service docker
Deux fichier ont été créé/mise à jour.
# cat /etc/subuid
# cat /etc/subgid
Ce que signifie c'est fichier c'est que les uid des utilisateurs du système hôte sont remappé dans les containers vers des uid/gid différents, dans le cas présent le 65536
.
Or cette utilisateur n'aura aucun moyen de se faire passer pour le root 0 de la machine hôte et donc aucun moyen de modifier le /
.
Un autre phénomène est apparu aussi. Un dossier de namespace a été créé.
# ls -la /var/lib/docker
Il appartient à l'utilisateur 165536
. Si vous avez fait un peu de python dans votre vie, c'est l'équivalent d'un virtualenv.
Il contient une copie de la structure de /var/lib/docker
.
A ceci près que le dossier n'appartient pas à root
!
Retournons avec alice. (pensez bien à la retirer des sudoers).
Si on refait un coup de
C'est vide.
On est reparti
On monte /
de nouveau dans le container.
Avec le shell du container
Ah c'est étrange, il y a un utilisateur nobody
à la place de root
.
Continuons mais ça sent la poudre
# echo "I was here again" > /opt/workdir/flag
Oh beaucoup mieux !! 🤩
On essaie même pas sudoers, ça passera pas. :D
On vient de combler notre faille de sécu ^^
Bonus: Monter un volume légitime en écriture
C'est bien tout ça mais si je veux monter un dossier en écriture je fais comment ?
Pour le moment on ne peut pas.
Si vous créé un montage légitime avec l'utilisateur alice
Que vous montez ça
On a le même soucis, on est en nobody comme owner, et donc les accès en écriture seront interdit.
Si vous vous rappelez des
# cat /etc/subuid
# cat /etc/subgid
Je vous avais parlé de mapping
Ben on va se créer un mapping pour notre utilisateur alice
qui lui permettra de monter en écriture le volume mais sans lui permettre de monter /
en écriture aussi.
Dans un shell privilégié.
username="alice"
uid=
gid=
lastuid=
lastgid=
Ces deux commandes ont pour rôle de modifier ainsi les fichiers
# cat /etc/subuid
# cat /etc/subgid
On modifie ensuite le /etc/docker/daemon.json
en conséquence.
On redémarre le service docker
service docker restart
Un nouveau namespace /var/lib/docker/1000.1000
se créé.
Dans le shell de alice
C'est vide de nouveau.
On est recréé l'image
On monte /
de nouveau dans le container.
On tente l'écriture
# echo "I was here again" > /opt/workdir/flag
Parfait, on a pas retroué la sécu du container. 😁
On quitte le container puis
Dans le shell du container
# ls -la
ça sent bon 😋
On quitte le container
# cat data/test
Yes 🥳
Conclusion
On vient d'apprendre à combler une faille majeure de docker et du montage de volume.
Je pense bien qu'il doit encore rester des montagnes d'exploit, mais ça sera tout pour aujourd'hui :D
Vous remercie de m'avoir lu et je vous dis à la prochaine ^^
Si je raconte des conneries, n'ésitez pas à me le dire en commentaires, je débute dans la sécu 😅
Ce travail est sous licence CC BY-NC-SA 4.0.