
# Riscrittura educativa del PoC Copy Fail (CVE-2026-31431) — LPE del kernel Linux tramite crypto in-place algif_aead + scrittura page-cache con splice()
Riscrittura a scopo educativo del proof-of-concept di Theori/Xint per CVE-2026-31431,
una vulnerabilità di escalation dei privilegi locale nell'interfaccia socket crittografica
algif_aead del kernel Linux. Colpisce tutti i kernel mainline dalla 4.14 (luglio 2017)
fino alla 6.18.21, e il ramo stabile 6.19 fino alla 6.19.11.
Solo per ricerca educativa e test di sicurezza autorizzati. Non eseguire su sistemi di cui non sei proprietario o per cui non hai esplicita autorizzazione scritta per il test. Eseguirlo su un host vulnerabile concede a qualsiasi utente locale non privilegiato accesso root immediato. Gli autori non si assumono alcuna responsabilità per un uso improprio.
Il kernel Linux espone un'API crittografica interna allo spazio utente dal
kernel 3.2 tramite la famiglia di socket AF_ALG (<linux/if_alg.h>). Lo spazio utente
apre un socket SOCK_SEQPACKET, lo associa a un template di algoritmo (es.
"aead" / "authencesn(hmac(sha256),cbc(aes))"), e invia dati per
crittografia o decrittografia.
Nel 2017 è stata integrata un'ottimizzazione delle prestazioni che consente agli algoritmi AEAD di crittografare o decrittografare i dati in-place quando il kernel rileva che la sorgente e la destinazione condividono le stesse pagine sottostanti. Questo evita una copia di memoria ridondante a ogni operazione.
Il template authencesn (che aggiunge il supporto Extended Sequence Number alla
crittografia autenticata) contiene una scrittura temporanea durante la decrittografia: scrive
i byte ESN in un offset specifico all'interno del buffer dati dell'operazione prima che venga eseguito
il controllo di autenticazione. Quando le pagine sorgente dell'operazione sono state ottenute dalla page cache
di un file regolare tramite splice(), e l'ottimizzazione in-place è attiva, questa scrittura
temporanea va direttamente in quelle pagine in cache.
Poiché la page cache del kernel è un mapping condiviso — qualsiasi processo che apre lo stesso file vede le stesse pagine fisiche — un utente non privilegiato può:
/usr/bin/su) con O_RDONLY.AF_ALG.authencesn; la scrittura temporanea ESN corrompe la
pagina a un offset controllato con byte controllati dall'attaccante.Gli scanner di integrità off-host (AIDE, Tripwire, IMA/EVM) che confrontano i checksum dei file su disco sono completamente ciechi a questo attacco. La scrittura scompare dopo un'evizione della page cache o un riavvio, senza lasciare tracce forensi su disco.
Prendendo di mira /usr/bin/su (un binario setuid root) e sovrascrivendo un ramo
che protegge il controllo di autenticazione PAM, l'attaccante ottiene una shell root
senza password.
| Ramo | Prima versione vulnerabile | Ultima versione vulnerabile | Corretta in |
|---|---|---|---|
| mainline | 4.14 | 6.18.21 | 6.18.22 |
| 6.19 stable | 6.19.0 | 6.19.11 | 6.19.12 |
| 7.0-rc | 7.0-rc1 | 7.0-rc6 | 7.0-rc7 |
Il commit di ottimizzazione che ha introdotto il bug è arrivato nel ciclo di sviluppo
della 4.14 (luglio 2017). Qualsiasi kernel compilato con CONFIG_CRYPTO_USER_API_AEAD=y
e CONFIG_CRYPTO_AUTHENC=y (entrambe impostazioni predefinite comuni) negli intervalli
sopra indicati è vulnerabile.
| Distribuzione | Kernel fornito (circa) | Corretta? |
|---|---|---|
| Debian 12 (Bookworm) | 6.1.x | Sì (backport) |
| Debian 13 (Trixie) | 6.12.x / 6.14.x | Sì (backport) |
| Ubuntu 24.04 LTS | 6.8.x | Sì (USN-7xxx) |
| Ubuntu 24.10 | 6.11.x | Sì |
| RHEL 9.x | 5.14.x (rebased) | Sì (RHSA) |
| Alpine 3.20 | 6.6.x | Sì (backport) |
| Arch Linux | rolling (≥ 6.18.22 ora) | Sì |
| Kali Linux 2026.1 | 6.18.12 | Vulnerabile |
| Kali Linux 2026.2+ | 6.18.22+ | Corretta |
| Linux Mint 22 | 6.8.x (base Ubuntu) | Sì (USN Ubuntu) |
Controlla il security tracker della tua distribuzione per lo stato esatto dell'avviso.
os.splice è stato aggiunto in Python 3.10)/usr/bin/su, leggibile da tutti
poiché è setuid)# Mostra cosa verrebbe scritto senza toccare il kernel (sicuro):
python3 copy_fail_exploit.py --dry-run
# Corregge la page cache di /usr/bin/su (richiede kernel vulnerabile):
# ATTENZIONE: richiede kernel vulnerabile -- usare solo su sistemi di tua proprietà
python3 copy_fail_exploit.py
# Corregge e passa immediatamente a root:
python3 copy_fail_exploit.py --spawn-shell
# Usa un binario di destinazione e un payload personalizzati:
python3 copy_fail_exploit.py --target /usr/bin/sudo --payload-file ./custom_patch.bin
# Output dettagliato (stampa ogni scrittura da 4 byte):
python3 copy_fail_exploit.py --verbose --dry-run
Per impostazione predefinita --spawn-shell è disattivato. Dopo la correzione, lo script stampa:
[+] Patch applicata alla page cache di '/usr/bin/su' (disco invariato).
Esegui `su` per l'escalation, oppure riesegui con --spawn-shell.
Per ripristinare: echo 3 | sudo tee /proc/sys/vm/drop_caches
Devi accettare esplicitamente l'avvio della shell con --spawn-shell. Questa è una scelta
intenzionale: ti obbliga a capire cosa ha fatto l'exploit prima di eseguirne il risultato.
Impostazione della primitiva.
L'exploit apre un socket AF_ALG e lo associa al template
authencesn(hmac(sha256),cbc(aes)) con una chiave fittizia tutta a zero. Poi
configura la dimensione del tag di autenticazione a 4 byte tramite ALG_SET_AEAD_AUTHSIZE.
accept() sul socket di controllo produce un socket di operazione che può inviare
singole richieste di decrittografia.
Attivazione della scrittura nella page cache.
Per ogni blocco da 4 byte del payload della patch, l'exploit chiama sendmsg() sul
socket di operazione con il flag MSG_MORE impostato, passando 8 byte di dati associati
(AAD): 4 byte di riempimento seguiti dai 4 byte del payload. MSG_MORE dice al
kernel di tenere in sospeso l'operazione finché non arrivano altri dati. Poi crea una pipe
ed esegue due chiamate splice() — file_fd → pipe → op_sock — donando le pagine
della page cache del file stesso come input per l'operazione di decrittografia. Quando
viene infine chiamata recv(), il kernel esegue la decrittografia authencesn. L'
ottimizzazione in-place scatta (sorgente e destinazione sono le stesse pagine), e la
scrittura temporanea ESN copia i byte del nostro payload nella pagina in cache all'
offset di destinazione. recv() restituisce EBADMSG perché il tag di autenticazione
non può essere verificato — questo è previsto e innocuo. La scrittura è già avvenuta.