
Analyse de reproduction pour CVE-2026-31431, exploit adapté en C.
.
├── container
│ ├── container.md # Idées d'évasion de conteneur
│ ├── expenv # Environnement du conteneur
│ │ ├── bin
│ │ │ ├── gscontainer
│ │ │ └── share
│ │ ├── Dockerfile
│ │ ├── run.sh
│ │ └── src
│ │ ├── gscontainer.c
│ │ └── share.c
│ ├── images
│ │ ├── container.png
│ │ ├── getshell.png
│ │ ├── host.png
│ │ ├── payload.png
│ │ └── share.png
│ ├── recode.bin # Shellcode monophase
│ └── stager
│ ├── shell.elf # Shellcode par étapes intégré dans l'exploit
│ ├── stager1.bin
│ ├── stager2.bin
│ ├── stager3.bin
│ └── stager4.bin
├── doc
│ ├── cve-2026-31431.md # Analyse synthétique par xint.io
│ └── shellcode.md # Qu'est-ce qu'un shellcode
├── exp.py # curl http://copy.fail/exp -o exp.py
├── README.md
├── success
│ ├── code.py # Shellcode extrait de exp.py
│ └── exploit.c # Exploit simplifié en C, contient un shellcode msf natif pour élévation de privilèges (nécessite une désinfection personnalisée)
└── test
├── exptest.c # Version sans commentaires
└── test.c # Version correcte avec commentaires pour faciliter la compréhension
Trois commits inoffensifs distincts, combinés, créent la vulnérabilité :
splice(fichier → pipe → AF_ALG)
↓
af_alg_sendmsg : page de cache de fichier → TX SGL (zéro copie)
↓
_aead_recvmsg : optimisation in-place
├─ memcpy_sglist : AAD+texte chiffré copiés vers RX SGL
├─ sg_chain : la page de tag (toujours pointant vers le cache de fichier) chaînée dans RX SGL
└─ req->src = req->dst (= scatterlist contenant la page de cache de fichier)
↓
crypto_authenc_esn_decrypt : réarrangement ESN
└─ scatterwalk_map_and_copy(tmp+1, dst, assoclen+cryptlen, 4, 1)
↓ parcourt le scatterlist dst jusqu'à la position du tag
↓ kmap_local_page() mappe la page de cache de fichier
↓ memcpy : écrit seqno_lo dans la page de cache de fichier
↓
Échec de vérification HMAC → retourne -EBADMSG
↓
La page de cache de fichier est modifiée, le noyau ne marque pas la page comme sale, le fichier disque reste inchangé
L'article de recherche affirme que « presque toutes les distributions Linux » sont affectées depuis 2017. Le cache de page est partagé entre conteneurs, donc cette vulnérabilité constitue à la fois un vecteur d'élévation de privilèges locale (LPE) et d'évasion de conteneur.
Le correctif principal du noyau (a664bf3d603d) ramène les opérations AEAD AF_ALG en mode out-of-place (src et dst séparés) :
Before : aead_request_set_crypt(..., rsgl_src,
areq->first_rsgl.sgl.sgt.sgl, ...)
^ src == dst ^
After : aead_request_set_crypt(..., tsgl_src,
areq->first_rsgl.sgl.sgt.sgl, ...)
^ src ≠ dst ^ (TX SGL pour src, RX SGL pour dst)
Message du commit : « Il n'y a aucun avantage à opérer en mode in-place dans algif_aead puisque la source et la destination proviennent de mappings différents. »
Mesures d'atténuation d'urgence :
echo "install algif_aead /bin/false" > /etc/modprobe.d/disable-algif-aead.conf
rmmod algif_aead
Ou interdire la création de socket AF_ALG via une politique seccomp (socket(AF_ALG, ...)).
| Temps | Commit | Impact |
|---|
| 2011 | a5079d084f8b | authencesn ajouté, utilisant le scatterlist dst comme espace temporaire pour le réarrangement ESN. Inoffensif à l'époque — l'ancienne interface AEAD maintient AAD séparé, et le seul appelant est le xfrm du noyau. |
| 2015 | 104880a6b470 | authencesn converti à la nouvelle interface AEAD, introduisant l'écriture de seqno_lo « au-delà de la sortie » à l'offset assoclen+cryptlen. Toujours inexploitable — car AF_ALG utilise le mode out-of-place, req->src et req->dst sont séparés, et la page de cache de fichier est uniquement dans le src en lecture seule. |
| 2017 | 72548b093ee3 | Optimisation in-place AF_ALG. Copie AAD+texte chiffré du TX SGL vers le tampon RX, mais chaîne la page de tag via sg_chain. Définit req->src = req->dst. Désormais, la page de cache de fichier introduite par splice se trouve également dans le scatterlist dst en écriture. Vulnérabilité formée. |
| Distribution | Version du noyau | Touché |
|---|
| Ubuntu 24.04 LTS | 6.17.0-1007-aws | Oui |
| Amazon Linux 2023 | 6.18.8-9.213.amzn2023 | Oui |
| RHEL 10.1 | 6.12.0-124.45.1.el10_1 | Oui |
| SUSE 16 | 6.12.0-160000.9-default | Oui |
| Caractéristique | Vérification source | Description |
|---|
| authencesn écrit seqno_lo à la fin | authencesn.c:134 | Écrit seqno_lo (32 bits de poids faible) à l'offset assoclen+cryptlen. Description utilisateur correcte. |
| Convention de réarrangement ESN | Blog confirmé (xint.io) | Octets AAD 0-3 = seqno_hi, octets 4-7 = seqno_lo. tmp[1] (=octets 4-7=seqno_lo) est écrit à la fin. |
| Le chemin de déchiffrement ne restaure pas les octets écrasés | authencesn.c:270-273 vs 215-217 | decrypt_tail restaure ESN aux offsets 0-7 mais ne restaure jamais les octets originaux à assoclen+cryptlen. Le chemin de chiffrement (genicv_tail) les restaure avant d'écrire l'ICV. |
| Chiffrement/déchiffrement in-place AF_ALG | algif_aead.c:189-252 | rsgl_src pointe vers le même RX SGL que areq->first_rsgl.sgl.sgt.sgl. |
| Chaînage du tag AF_ALG | algif_aead.c:238-244 | En déchiffrement, le tag est référencé via sg_chain plutôt que copié — dans le scénario splice, la page de tag pointe toujours vers le cache de fichier. Cause racine de la faille de sécurité. |
| Transfert zéro copie via splice | fs/splice.c:876, af_alg.c:1049, lib/scatterlist.c:1167 | Référence directement la page du pipe, zéro copie. |
| CVE-2026-31431 | Trois chaînes de commit | authencesn (2011/2015) + in-place (2017) + splice zéro copie = primitive d'écriture de cache de fichier contrôlable. |