
Analyse complète de CVE-2026-31431, une élévation de privilèges locale (LPE) du noyau Linux, incluant la méthodologie d'exploitation, les scripts de détection, les règles YARA, les configurations auditd et Falco, ainsi que des recommandations de remédiation.
algif_aeadCISA KEV | CVSS 7.8 ÉLEVÉ | Affecte les noyaux Linux 4.14 – début 2026 (~9 ans)
CVE-2026-31431, surnommée « Copy Fail », est une vulnérabilité d'élévation de privilèges locale (LPE) de haute sévérité dans le sous-système cryptographique du noyau Linux. Un utilisateur local à faibles privilèges peut passer à root en quelques secondes sur tout système non corrigé.
detection/check_vulnerable.sh avant et après la remédiation.CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
| Métrique | Valeur | Justification |
|--------|-------|-----------|
| Vecteur d'attaque | **Local** | Nécessite un accès shell (SSH, exec de conteneur, physique) |
| Complexité de l'attaque | **Faible** | Fiable, entièrement automatisé — aucune condition de course requise |
| Privilèges requis | **Faibles** | N'importe quel compte utilisateur non privilégié |
| Interaction utilisateur | **Aucune** | Aucune interaction de la victime nécessaire |
| Confidentialité | **Élevée** | Compromission complète du système |
| Intégrité | **Élevée** | Compromission complète du système |
| Disponibilité | **Élevée** | Compromission complète du système |
### Paysage des menaces
| Facteur | Évaluation |
|--------|-----------|
| Disponibilité du PoC | Public, armé, Python autonome de 732 octets |
| Fiabilité de l'exploit | Élevée — fonctionne sur les distributions testées sans modification |
| Difficulté de détection | Élevée — aucune écriture sur disque, aucune page sale |
| Compétence requise de l'attaquant | Faible — script kiddie avec un PoC public |
| CISA KEV | Ajouté en 2026 — surveillé activement |
| Microsoft Defender | Signalé comme faisant l'objet d'une enquête active |
### Environnements concernés
| Environnement | Risque |
|-------------|------|
| Serveurs Linux sur métal nu | Critique |
| Machines virtuelles Linux (cloud ou sur site) | Critique |
| Nœuds Kubernetes | Critique (permet également l'évasion de conteneur) |
| Hôtes Docker | Critique |
| Hébergement mutualisé / multi-locataire | Critique |
| WSL2 / Linux sur Windows | À évaluer selon la version du noyau |
---
## 3. Plongée technique approfondie
### 3.1 Contexte : AF_ALG et AEAD
Le noyau Linux expose les opérations cryptographiques aux applications en espace utilisateur via les **sockets AF_ALG** (`AF_ALG = 38`). Cette interface (`algif_aead`) permet aux applications non privilégiées d'invoquer les accélérateurs matériels cryptographiques du noyau sans nécessiter de code en mode noyau.
**AEAD** (Authenticated Encryption with Associated Data) — les algorithmes comme AES-GCM et ChaCha20-Poly1305 sont largement utilisés pour TLS, le chiffrement de disque et les protocoles VPN. Le template vulnérable est `authencesn` — une composition AEAD utilisant `hmac(sha256)` + `cbc(aes)` avec prise en charge du numéro de séquence étendu (ESN), couramment utilisée dans IPsec.
### 3.2 Cause racine
En 2017, le commit `72548b093ee3` a introduit l'**opération AEAD en place** dans `algif_aead` comme optimisation de performance — permettant au moteur cryptographique de lire et d'écrire dans le même tampon. Cela était défectueux :```
The bug chain:
1. Caller binds AF_ALG socket to:
authencesn(hmac(sha256),cbc(aes))
2. Caller sends a decryption request via sendmsg() with specific flags
3. Caller uses splice() to feed PAGE CACHE PAGES from an open file
descriptor directly into the socket's scatterlist
4. The authencesn template, during ESN header processing, uses the
OUTPUT BUFFER as scratch space — writing 4 bytes past the
expected output boundary
5. Because the scatterlist contains page cache pages (not private
copies), this scratch write lands DIRECTLY IN THE PAGE CACHE
6. Page cache is shared kernel-wide — all processes reading the
same file now see the modified bytes
Key insight: splice() is zero-copy — it hands page cache references
to the socket. The in-place "optimization" then writes INTO those
pages. No dirty bit is set because the write goes through the crypto
engine, not the normal write path.
La vulnérabilité permet une écriture contrôlée de 4 octets dans le cache de pages de tout fichier que l'attaquant peut ouvrir en lecture :
L'écriture est répétable — l'exploit boucle l'écriture de 4 octets pour corriger des séquences de code plus longues.
[1] Open /usr/bin/su (or any setuid-root binary) for reading ↓ [2] Map a copy to find target instruction bytes (e.g., UID check, execve path, security gate) ↓ [3] Compute exact page cache offset of target bytes ↓ [4] Set up AF_ALG socket → authencesn(hmac(sha256),cbc(aes)) ↓ [5] splice() the target binary's page cache into the socket ↓ [6] Trigger decryption → authencesn scratch write patches the target bytes in page cache (4 bytes per iteration) ↓ [7] Repeat for each 4-byte patch needed ↓ [8] Execute /usr/bin/su → runs root-owned setuid binary but now with attacker-controlled code in page cache ↓ [9] Root shell
### 3.5 Pourquoi les défenses standard échouent
| Défense | Contournée ? | Raison |
|---------|-----------|--------|
| Surveillance de l'intégrité des fichiers (Tripwire/AIDE) | **Oui** | Aucune modification sur disque |
| Vérifications de hachage des fichiers par l'IDS | **Oui** | Octets du disque inchangés |
| Surveillance de fichiers `inotify` | **Oui** | Aucun événement d'écriture VFS |
| SELinux / AppArmor | **Partielle** | Contrôle le processus, pas l'écriture dans le cache de pages via le moteur cryptographique |
| Montages en lecture seule | **Oui** | Cache de pages modifié en mémoire, pas via le montage |
| `watch` d'auditd sur le binaire | **Oui** | Audit surveille les écritures VFS — cela contourne VFS |
### 3.6 Versions du noyau concernées
| Branche | Vulnérable jusqu'à | Corrigé à partir de |
|--------|-------------------|------------|
| 4.14.x | Toutes (origine de la vulnérabilité) | Aucun correctif en amont (EOL) |
| 5.4.x (LTS) | Toutes | Rétroportage de la distribution requis |
| 5.10.x (LTS) | Toutes | Rétroportage de la distribution requis |
| 5.15.x (LTS) | Toutes | Rétroportage de la distribution requis |
| 6.1.x (LTS) | ≤ 6.1.129 | **6.1.130+** |
| 6.6.x (LTS) | ≤ 6.6.86 | **6.6.87+** |
| 6.12.x (LTS) | ≤ 6.12.22 | **6.12.23+** |
| 6.15-rc | Corrigé dans rc | **6.15-rc+** |
> Les noyaux de distribution peuvent avoir rétroporté le correctif à des numéros de version différents. Vérifiez toujours l'avis de sécurité de votre distribution.
---
## 4. Méthodologie d'attaque — Équipe rouge
> **Autorisation requise.** Cette section existe pour aider les défenseurs à comprendre le point de vue de l'attaquant. N'exécutez que sur des systèmes que vous possédez ou pour lesquels vous disposez d'une autorisation écrite explicite de test.
### 4.1 Prérequis
- Shell à privilèges faibles sur la cible (SSH, exec de conteneur, chaîne RCE)
- Python 3.10+ **ou** binaire C compilé
- Noyau non corrigé avec `algif_aead` disponible
### 4.2 Reconnaissance```bash
# Check if vulnerable
uname -r
cat /proc/crypto | grep -A10 "authencesn"
lsmod | grep algif_aead
# Verify setuid target exists
ls -la /usr/bin/su /usr/bin/sudo /usr/bin/passwd
Les chercheurs d’origine (Theori) ont publié un PoC Python autonome entièrement fonctionnel de 732 octets :
python3 copy_fail_exp.py
python3 copy_fail_exp.py /usr/bin/passwd
Une copie locale est disponible dans `exploit/poc.py`. Consultez `exploit/README.md` pour une analyse technique détaillée.
### 4.4 Scénario d'évasion de conteneur
Étant donné que le cache de pages Linux est partagé entre tous les processus sur le même hôte (y compris l'hôte et les conteneurs) :```
Attacker in container → patches /usr/bin/su in HOST page cache
Host user runs su → executes attacker code as root on host
Cela fonctionne même depuis des conteneurs non privilégiés, tant que le noyau hôte est vulnérable.
C'est l'objectif principal de ce dépôt.
Exécutez le script de détection sur n'importe quel système Linux :```bash chmod +x detection/check_vulnerable.sh sudo ./detection/check_vulnerable.sh
**Ce qu'il vérifie :**
- Version du noyau par rapport aux plages connues comme vulnérables
- Statut de chargement du module `algif_aead` et statut de mise sur liste noire
- Disponibilité de `authencesn` dans `/proc/crypto`
- Intégrité du cache de pages des binaires setuid (nécessite root)
- Statut des correctifs spécifiques à la distribution
- Processus en cours d'exécution pour détecter des indicateurs d'exploitation active
Un rapport horodaté est enregistré dans `/tmp/cve-2026-31431-report-*.txt`.
### 5.2 Détection YARA
Deux règles YARA sont fournies dans `detection/yara/` :
| Fichier de règle | Objectif |
|-----------|---------|
| `cve_2026_31431_base.yar` | Correspond exactement au PoC public connu |
| `cve_2026_31431_enhanced.yar` | Détecte les exploits obfusqués, compilés et variantes |```bash
# Install YARA
apt-get install yara # Debian/Ubuntu
dnf install yara # RHEL/Fedora
apk add yara # Alpine
# Scan running process executables
sudo yara -r detection/yara/cve_2026_31431_enhanced.yar /proc/*/exe 2>/dev/null
# Scan common dropper locations
sudo yara -r detection/yara/cve_2026_31431_enhanced.yar /home /tmp /var/tmp /dev/shm
# Scan uploaded files / quarantine
yara detection/yara/cve_2026_31431_base.yar <suspect_file>
Pourquoi les règles renforcées sont importantes : Les attaquants peuvent obscurcir le PoC Python public (encoder les chaînes en base64, encoder le nom de l'algorithme avec XOR, compiler en binaire C, supprimer les symboles). La règle renforcée détecte ces variantes en ciblant les invariants qui ne peuvent pas être supprimés sans casser l'exploit :
authesn comme nom d'algorithmesplice() pour obtenir un accès zéro-copie au cache de pages38)Déployer vers /etc/audit/rules.d/cve-2026-31431.rules :```bash
-a always,exit -F arch=b64 -S socket -F a0=38 -k cve_2026_31431_afalg
-a always,exit -F arch=b64 -S splice -k cve_2026_31431_splice
-a always,exit -F arch=b64 -S init_module -S finit_module -k cve_2026_31431_modload
-a always,exit -F arch=b64 -S execve -F euid=0 -F auid>=1000 -k cve_2026_31431_suid_exec
Reload :```bash
augenrules --load && service auditd restart
Requête pour les tentatives d'exploitation :```bash
ausearch -k cve_2026_31431_afalg --start today
ausearch -k cve_2026_31431_afalg -k cve_2026_31431_splice --start today
### 5.4 Détection Falco / eBPF
Ajoutez à `/etc/falco/rules.d/cve-2026-31431.yaml` :```yaml
- rule: CVE-2026-31431 AF_ALG Socket Creation
desc: Detects unprivileged process creating AF_ALG socket (family 38) — required step for Copy Fail exploit
condition: >
syscall.type = socket and
evt.arg.domain = 38 and
not user.uid = 0 and
not proc.name in (known_crypto_daemons)
output: >
CVE-2026-31431 exploitation attempt - AF_ALG socket (user=%user.name
uid=%user.uid pid=%proc.pid cmd=%proc.cmdline)
priority: CRITICAL
tags: [cve-2026-31431, lpe, kernel, crypto]
- list: known_crypto_daemons
items: [strongswan, charon, pluto, openssl]
- rule: CVE-2026-31431 Splice After AF_ALG
desc: Detects splice() syscall shortly after AF_ALG socket creation — exploitation sequence
condition: >
syscall.type = splice and
not user.uid = 0 and
evt.elapsed < 5000000000
output: >
CVE-2026-31431 splice after AF_ALG socket (user=%user.name pid=%proc.pid)
priority: CRITICAL
tags: [cve-2026-31431, lpe]
Étant donné que l'exploit modifie le cache de pages sans écrire sur le disque, les outils FIM standard sont aveugles. Cette vérification détecte l'exploitation active :```bash #!/bin/bash
SETUID_BINS=("/usr/bin/su" "/usr/bin/sudo" "/usr/bin/passwd")
for binary in "${SETUID_BINS[@]}"; do [[ -f "$binary" ]] || continue LIVE_HASH=$(sha256sum "$binary" | awk '{print $1}') echo 3 | sudo tee /proc/sys/vm/drop_caches > /dev/null # flush page cache DISK_HASH=$(sha256sum "$binary" | awk '{print $1}') if [[ "$LIVE_HASH" != "$DISK_HASH" ]]; then echo "CRITICAL: Page cache tampering detected on $binary" echo " Pre-flush: $LIVE_HASH" echo " Post-flush: $DISK_HASH" else echo "OK: $binary page cache matches disk" fi done
> **Note de production :** `drop_caches` entraîne une baisse de performance. À exécuter pendant les fenêtres de maintenance ou d'abord sur des systèmes non critiques.
### 5.6 Indicateurs de compromission (IoCs)
| Type d'IoC | Indicateur | Confiance |
|----------|-----------|-----------|
| Chaîne (binaire/script) | `authencesn(hmac(sha256),cbc(aes))` | Élevée |
| Octets hexadécimaux | `78 DA AB 77 F5 71 63 62 64 64` (en-tête de charge utile zlib) | Élevée |
| Séquence d'appels système | `socket(38,5,0)` → `bind()` → `splice()` | Élevée |
| Réseau | Aucun — purement local | N/A |
| Fichier | Aucune écriture sur disque (furtif) | — |
| Processus | Processus Python/C de courte durée avec socket AF_ALG | Moyenne |
| Cache de pages | Cache de pages du binaire setuid ≠ empreinte sur disque | Critique |
### 5.7 Requêtes de détection SIEM
**Splunk (source auditd) :**```spl
index=linux_audit sourcetype=auditd action=SYSCALL syscall=socket a0="0x26"
| join pid [
search index=linux_audit sourcetype=auditd action=SYSCALL syscall=splice
]
| where (_time - join_time) < 30
| table _time host user pid cmd a0
| eval severity="CRITICAL"
Elastic KQL :```kql event.action: "SYSCALL" AND process.args: "socket" AND auditd.data.a0: "0x26" AND NOT user.id: "0"
**Microsoft Sentinel (KQL) :**```kql
Syslog
| where Facility == "kern" or ProcessName == "audit"
| where SyslogMessage contains "socket" and SyslogMessage contains "a0=0x26"
| extend UserName = extract("uid=([0-9]+)", 1, SyslogMessage)
| where UserName != "0"
| project TimeGenerated, Computer, UserName, SyslogMessage
| order by TimeGenerated desc
Exécutez le script de correctif automatisé :```bash chmod +x patch/patch.sh sudo ./patch/patch.sh
### 6.1 Atténuation immédiate (sans redémarrage requis*)```bash
# Blacklist the module permanently
echo "install algif_aead /bin/false" | sudo tee /etc/modprobe.d/disable-algif-aead.conf
echo "install authencesn /bin/false" | sudo tee -a /etc/modprobe.d/disable-algif-aead.conf
# Unload if currently loaded
sudo rmmod algif_aead 2>/dev/null || echo "Not loaded — mitigation active after config"
# Verify
lsmod | grep algif_aead && echo "WARNING: still loaded — reboot needed" || echo "OK: not loaded"
*Si algif_aead est déjà chargé, un redémarrage est nécessaire pour que la liste noire prenne pleinement effet.
Effets secondaires : Les applications qui utilisent l'interface AEAD du noyau via AF_ALG (peu courantes — la plupart utilisent OpenSSL en espace utilisateur) peuvent échouer. Les outils standard de TLS, de chiffrement de disque et de VPN ne sont généralement pas affectés.
kubectl get nodes -o wide
kubectl drain --ignore-daemonsets --delete-emptydir-data
kubectl uncordon
Utilisez des auto-upgradeurs de nœuds (Karpenter, groupes de nœuds gérés) ou la rotation du pool de nœuds du cluster lorsque cela est disponible.
### 6.4 Vérification post-correctif```bash
# Re-run detection script
sudo ./detection/check_vulnerable.sh
# Quick manual verification
uname -r # confirm new kernel version
lsmod | grep algif_aead # should be empty
cat /proc/crypto | grep authencesn # should return nothing (or still listed but module blacklisted)
Un laboratoire Docker Alpine minimal est fourni pour tester les outils de détection en toute sécurité.```bash cd lab/ docker compose up -d docker exec -it cve-2026-31431-lab /bin/sh
/cve-2026-31431/detection/check_vulnerable.sh
> **Important :** Les conteneurs Docker partagent le noyau de l'hôte. Le laboratoire teste l'état de vulnérabilité **du noyau de votre hôte**. Les résultats de vulnérabilité reflètent le système hôte réel — c'est intentionnel pour une évaluation réaliste.
Pour des tests isolés avec une version spécifique de noyau vulnérable, utilisez une VM dédiée avec un noyau épinglé. Consultez `lab/README.md` pour les instructions de configuration de la VM.
---
## 8. Références
| Ressource | Lien |
|----------|------|
| Avis NVD | https://nvd.nist.gov/vuln/detail/CVE-2026-31431 |
| Recherche originale | https://copy.fail |
| Article technique | https://xint.io/blog/copy-fail-linux-distributions |
| PoC public | https://github.com/theori-io/copy-fail-CVE-2026-31431 |
| Catalogue KEV de la CISA | https://www.cisa.gov/known-exploited-vulnerabilities-catalog |
| Correctif du noyau — Commit annulé | `a664bf3d603d` / `fafe0fa2995a` |
| Commit vulnérable | `72548b093ee3` |
| Avis Microsoft Defender | Blog Microsoft Defender Threat Intelligence |
---
## Structure du dépôt```
cve-2026-31431/
├── README.md ← This document
├── exploit/
│ ├── README.md ← Technical exploit breakdown
│ └── poc.py ← Public PoC (theori-io, for reference)
├── detection/
│ ├── README.md ← Detection guide
│ ├── check_vulnerable.sh ← Vulnerability & IoC detection script
│ └── yara/
│ ├── cve_2026_31431_base.yar ← Detects known public PoC
│ └── cve_2026_31431_enhanced.yar ← Detects obfuscated/compiled variants
├── patch/
│ ├── README.md ← Remediation guide
│ └── patch.sh ← Automated patch/mitigation script
└── lab/
├── README.md ← Lab setup guide
├── Dockerfile ← Alpine-based lab container
└── docker-compose.yml ← Lab orchestration
Cette recherche est fournie à des fins éducatives et de sécurité défensive uniquement. Tous les outils sont conçus pour aider les défenseurs à détecter et corriger CVE-2026-31431 sur les systèmes qu'ils sont autorisés à protéger.
Dépôt maintenu par rippsec
| Attribut | Valeur |
|---|
| CVE | CVE-2026-31431 |
| Surnom | Copy Fail |
| CVSS v3.1 | 7.8 ÉLEVÉ |
| Vecteur d'attaque | Local |
| Privilèges requis | Faibles |
| Interaction utilisateur | Aucune |
| Composant | crypto/algif_aead.c — modèle authencesn |
| Introduit | 2017 (commit 72548b093ee3) |
| Divulgué | 2026 |
| Années silencieuses | ~9 ans |
| CISA KEV | Oui |
| PoC public | Oui (script Python autonome de 732 octets) |
| Propriété | Valeur |
|---|
| Taille d'écriture | 4 octets |
| Contrôle du décalage | Oui — contrôlé par l'attaquant via le décalage de splice |
| Cible | Cache de pages de tout fichier lisible |
| Marquage de page sale | Aucun |
| Modification sur disque | Aucune |
| Mise à jour de l'horodatage | Aucune |
| Entrée du journal noyau | Aucune (sauf si auditd est configuré) |
| Technique | ID | Notes |
|---|
| Exploitation pour l'élévation de privilèges | T1068 | Technique principale |
| Contournement du mécanisme de contrôle d'élévation : Setuid/Setgid | T1548.001 | Détournement du binaire Setuid |
| Détournement du flux d'exécution | T1574 | Correction binaire en mémoire |
| Suppression d'indicateurs : Timestomp | T1070.006 | Aucun horodatage mis à jour |
| Exécution de commandes indirecte | T1202 | Le binaire corrigé exécute le shell |
| Distribution | Commande de mise à jour |
|---|
| Ubuntu / Debian | apt-get update && apt-get upgrade linux-image-generic && reboot |
| RHEL / CentOS / Rocky | dnf update kernel && reboot |
| Amazon Linux 2 | yum update kernel && reboot |
| Amazon Linux 2023 | dnf update kernel && reboot |
| SUSE / SLES | zypper update kernel-default && reboot |
| Arch Linux | pacman -Syu linux && reboot |
| Alpine Linux | apk update && apk upgrade linux-lts && reboot |
| Debian | apt-get update && apt-get upgrade linux-image-amd64 && reboot |