
Implémentations éducatives multi-langues d’exploits pour CVE-2026-31431, une élévation de privilèges locale du noyau Linux via le module algif_aead, avec un détecteur sûr et des conseils d’utilisation pour les CTF.
Repo éducatif avec des implémentations en plusieurs langages de l'exploit Copy Fail.
Créé et maintenu par @shotafry — parce que lire le CVE ne suffit pas. Il faut le reproduire.
Copy Fail est une vulnérabilité d'élévation de privilèges locale (LPE) dans le noyau Linux, cataloguée comme CVE-2026-31431. Elle affecte le sous-système cryptographique du noyau, plus précisément le module algif_aead qui gère les opérations de chiffrement authentifié (AEAD) via les sockets AF_ALG.
Le défaut a été introduit en 2017 dans une optimisation du module authencesn et est resté non détecté pendant près de 9 ans, présent dans pratiquement toutes les distributions Linux modernes.
Ce qui rend Copy Fail spécial par rapport aux autres LPE historiques :
| Caractéristique | Copy Fail | LPE typique |
|---|---|---|
| Nécessite une race condition | ❌ Non | ✅ Oui |
| Nécessite un offset spécifique du noyau | ❌ Non | ✅ Oui |
| Fonctionnel sur toutes les distros | ✅ Oui | ❌ Normalement non |
| Fiabilité | 100 % déterministe | Variable |
| Modifie le disque | ❌ Non (RAM uniquement) | Dépend |
La vulnérabilité a été découverte par Taeyang Lee de l'équipe de recherche de Theori. La chaîne d'exploitation complète a été développée par l'équipe Xint Code Research, qui a documenté le processus en utilisant une analyse assistée par IA sur le sous-système crypto/ du noyau Linux.
La divulgation publique inclut un PoC fonctionnel, une analyse technique complète et une documentation sur copy.fail.
CVE: CVE-2026-31431
CVSS: 7.8 — ÉLEVÉE
Vecteur: Local
Impact: Élévation de privilèges complète (root)
Distros: Toutes les distributions Linux avec noyau >= 2017 non corrigé
Le CVSS est de 7.8 et n'atteint pas le niveau critique (9+) uniquement parce qu'il nécessite un accès local préalable — l'attaquant doit déjà avoir une session sur le système. Dans les environnements cloud et avec les conteneurs Docker, cette exigence est considérablement plus facile à satisfaire qu'il n'y paraît.
Le noyau Linux conserve en RAM les fichiers qu'il a lus récemment. C'est ce qu'on appelle le page cache. Lorsqu'un processus lit /etc/passwd, le noyau ne va pas sur le disque — il sert la copie en RAM. C'est plus rapide, mais cela crée une surface d'attaque : si vous pouvez modifier cette copie en RAM sans toucher au disque, le système verra des données falsifiées.
Le module algif_aead permet d'effectuer des opérations AEAD depuis l'espace utilisateur via les sockets AF_ALG. Le bug se trouve dans l'optimisation introduite en 2017 : lorsque splice() est utilisé pour passer des pages d'un fichier au socket, ces pages du page cache se retrouvent dans la liste de dispersion destination (inscriptible) de l'opération cryptographique.
Résultat : n'importe quel utilisateur sans privilèges peut écrire 4 octets contrôlés dans n'importe quel fichier qu'il peut lire, sans toucher au disque.
Utilisateur sans privilèges
│
▼
Ouvre un socket AF_ALG (authencesn)
│
▼
sendmsg() — paramètres AEAD avec nos 4 octets dans seqno_lo
│
▼
splice() — fichier → pipe → socket op
[BUG] Le page cache du fichier reste dans le scatterlist destination
│
▼
recv() déclenche l'opération AEAD
L'auth échoue (EBADMSG) mais l'écriture scratch a déjà eu lieu
│
▼
/etc/passwd (page cache) indique maintenant : utilisateur → UID 0
│
▼
su <utilisateur> → PAM valide le vrai mot de passe → setuid(0) → ROOT
Imaginez que le noyau possède un registre du château (/etc/passwd). Copy Fail, c'est comme découvrir que si vous ouvrez l'atelier de magie du château dans un ordre très précis, le registre se retrouve accidentellement sur votre table de travail — et vous pouvez changer votre rang de « simple soldat » à « roi » avec un stylo. L'archiviste (PAM) vérifie votre mot de passe mais ne vérifie pas le registre original, seulement la copie que vous avez devant vous. Vous êtes roi.

>= ~2017 sans le correctif de CVE-2026-31431algif_aead disponible et chargeableOn peut réellement sauter cette étape et tester directement l'un des exploits, mais c'est aussi valable si nous ne voulons pas prendre le risque de les téléverser ou de les créer et que nous voulons seulement voir si cela fonctionne, mais les exploits ont leur fonction pour vérifier si le système en question est vulnérable.
# Voir la version du noyau
uname -a
# Vérifier si l'algorithme est disponible
grep -i authencesn /proc/crypto
# Vérifier si le module est chargé
lsmod | grep alg
Si grep -i authencesn /proc/crypto renvoie authencesn(hmac(sha256),cbc(aes)), le système est vulnérable.
| Langage | Prérequis sur la cible | Compilation préalable |
|---|---|---|
| C | Aucun (binaire statique) | gcc sur la machine de compilation |
| Python | Python 3.10+ | Non |
| Rust | Aucun (binaire statique) | rustc sur la machine de compilation |
| Go | Aucun (binaire statique) | go sur la machine de compilation |
| Ruby | Ruby + gem fiddle (inclus par défaut) | Non |
| Perl | Perl 5 (inclus dans pratiquement tout Linux) | Non |
Ce dépôt contient l'exploit implémenté en 6 langages, tous fonctionnellement équivalents, avec des commentaires pédagogiques en espagnol.