
Code source et fichiers de configuration liés à notre article dans MISC96
Ce dépôt est un complément à l'article publié dans MISC Magazine #96.
Nous avons réussi à élever nos privilèges de manière fiable, sur notre machine virtuelle avec SMEP / SMAP et KASLR activés. Il convient toutefois de noter que le système est laissé dans un état instable et qu'un oops est très susceptible de se produire.
Dans le dossier configs/, vous trouverez des fichiers de configuration pour le noyau Linux
et Busybox, chacun étant légèrement différent des fichiers par défaut.
Le dossier binaries/ contient tous les binaires pré-compilés dont vous aurez besoin
pour reproduire notre environnement de test, comme un rootfs complet prêt à être utilisé avec
QEMU.
linux-stable est un sous-module git pointant vers une révision vulnérable du noyau
Linux. Utilisez git submodule update --recursive pour le récupérer (si vous avez au
moins 1GB libre sur votre système...). Il en va de même pour busybox.
Notre environnement est basé sur une machine virtuelle QEMU x86 avec un dossier partagé
avec l'hôte via 9P. Une version vulnérable du noyau (ff33952e4d23) est
compilée avec une construction statiquement liée de Busybox.
Notre configuration est assez simple, car nous n'avons pas besoin de prendre en charge un quelconque type
d'architecture ou de matériel exotique. Elle a été générée en exécutant make defconfig et certaines fonctionnalités ont été activées, pour prendre en charge le réseau et le
partage de dossiers de QEMU :
CONFIG_BLK_MQ_VIRTIO=y
CONFIG_MEMORY_BALLOON=y
CONFIG_BALLOON_COMPACTION=y
CONFIG_NET_9P=y
CONFIG_NET_9P_VIRTIO=y
CONFIG_NET_9P_DEBUG=y
CONFIG_VIRTIO_BLK=y
CONFIG_VIRTIO_BLK_SCSI=y
CONFIG_VIRTIO_NET=y
CONFIG_HVC_DRIVER=y
CONFIG_VIRTIO_CONSOLE=y
CONFIG_HW_RANDOM_VIRTIO=y
CONFIG_VIRTIO=y
CONFIG_VIRTIO_PCI=y
CONFIG_VIRTIO_PCI_LEGACY=y
CONFIG_VIRTIO_BALLOON=y
CONFIG_VIRTIO_INPUT=y
CONFIG_VIRTIO_MMIO=y
CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y
CONFIG_9P_FS=y
CONFIG_9P_FS_POSIX_ACL=y
CONFIG_9P_FS_SECURITY=y
Des scripts GDB et des symboles de débogage ont également été ajoutés pour faciliter le développement des premiers PoCs :
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_INFO_DWARF4=y
CONFIG_GDB_SCRIPTS=y
Veuillez noter que dans cette version, KASLR est activé par défaut sur x86. Comme le
noyau est mappé à des adresses différentes après chaque redémarrage, GDB ne pourra pas
faire correspondre le fichier de symboles avec lui. Vous avez alors deux options : effectuer des tests
sans KASLR ou passer l'adresse de base du noyau à symbol-file lors du
chargement des symboles dans GDB.
Après l'avoir compilé, vous trouverez le bzImage dans linux-stable/arch/x86/boot/bzImage.
Ce fichier est présent dans binaries/bzImage et notre fichier de configuration dans
confifs/kernel.config. Pour l'utiliser, il vous suffit de le copier en tant que .config
dans linux-stable.
Nous avons utilisé la dernière version stable de Busybox, 1.28. Le seul paramètre à modifier est
CONFIG_STATIC, mettez-le à y. Sa compilation ne devrait poser aucun problème.
Notre fichier de configuration est disponible dans configs/busybox.config et un
binaire compilé statiquement dans binaries/busybox. Comme pour Linux, il suffit de le copier
en tant que .config dans le dossier des sources de Busybox.
Busybox implémente déjà un processus init qui tentera d'exécuter /etc/init.d/rcS.
Habituellement, celui-ci est fourni par votre distribution (potentiellement sous un nom différent)
mais nous devrons le faire nous-mêmes ici ! Ce script créera et montera plusieurs
dossiers système obligatoires (proc, sys, dev), notre dossier partagé avec
l'hôte, puis nous amènera dans un shell non privilégié :
for i in $(seq 1 9); do mknod /dev/tty$i c 4 1; done
mknod -m 0666 /dev/null c 1 3
mknod -m 0660 /dev/ttyS0 c 4 64
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t devtmpfs none /dev
mkdir -p /mnt/share
mount -t 9p -o trans=virtio share /mnt/share/ -oversion=9p2000.L,posixacl,sync
chmod 777 /mnt/share/
export ENV=/etc/profile
setsid cttyhack setuidgid 1000 sh
umount /proc
umount /sys
umount /dev
poweroff -f
Le fichier /etc/profile n'est pas obligatoire mais plutôt utile pendant nos tests,
surtout lorsque l'exploit n'était pas fiable et qu'il a fallu plusieurs essais pour
obtenir les privilèges root.
Le processus derrière l'écriture de l'exploit est assez bien documenté dans MISC 96 : nous utilisons
unsafe_put_user pour sonder la mémoire jusqu'à trouver l'adresse de base du tas.
Ensuite, des milliers d'appels à clone nous permettent d'arroser la mémoire de nombreuses
structures cred. Lors de nos tests, leur position en mémoire était bien plus
« constante » qu'avec fork, car cela alloue moins de structures pour la nouvelle tâche.
La sortie de l'enfant provoquera un oops du noyau, en raison d'une demande de pagination erronée ; cela doit être correctement géré.
Si vous souhaitez améliorer la fiabilité de cet exploit ou ajouter de la documentation, les contributions sont les bienvenues ! Nous avons peut-être aussi commis des erreurs ou des imprécisions sur certains concepts, n'hésitez pas à ouvrir une issue si vous pensez que quelque chose est incorrect.
Noyau Linux
Exploitation