
CVE-2026-68398 Ubuntu PPPoL2TP use-after-free local privilege escalation

Questo repository contiene un exploit di escalation dei privilegi locali specifico per una build per CVE-2026-68398, una race condition use-after-free tra l'elaborazione in ricezione di PPPoL2TP e la distruzione di un canale PPP non collegato. È stato validato in QEMU contro il pacchetto ufficiale Ubuntu 22.04 linux-image-5.15.0-187-generic (5.15.0-187.197).
Il test finale parte da un utente dedicato UID 1001, senza gruppi supplementari, senza capacità e senza accesso sudo, quindi ottiene UID 0 nei namespace iniziali. KASLR, SMEP, SMAP e AppArmor rimangono attivi. L'ospite non viene avviato con nokaslr, nopti, nosmep o nosmap.
Avvertenza
Questo codice corrompe intenzionalmente lo stato dell'heap del kernel ed è legato a una build esatta del kernel Ubuntu. Una race fallita può causare panic o corrompere il sistema. Eseguilo solo in una VM isolata, usa e getta, di tua proprietà.
pppol2tp_recv() viene eseguito nel percorso di ricezione UDP di L2TP all'interno di una sezione critica di lettura RCU e alla fine chiama ppp_input(&po->chan). La socket PPPoX e il suo ppp_channel incorporato sono sicuri per RCU, ma la struct channel interna usata da ppp_input() è un'allocazione separata.
Per un canale vincolato con PPPIOCGCHAN ma né collegato a un'unità PPP né in bridging, il percorso di chiusura liberava immediatamente quell'oggetto interno:
RX: l2tp_udp_encap_recv -> pppol2tp_recv -> ppp_input(channel)
CLOSE: pppol2tp_release -> pppox_unbind_sock
-> ppp_unregister_channel -> ppp_release_channel -> kfree(channel)
Il percorso di ricezione può quindi operare sulla coda skb e sulla waitqueue del canale liberato. La correzione aggiunge una callback RCU a struct channel e rimanda lo svuotamento della coda e la liberazione a dopo il trascorrere di un periodo di grazia RCU.
La vulnerabilità è stata scoperta e corretta upstream da Norbert Szetei di Doyensec. La correzione nel mainline è ec4215683e47424c9c4762fd3c60f552a3119142.
Il record CNA Linux identifica la linea vulnerabile a partire da Linux 4.15. I kernel dei vendor possono includere la correzione con un numero di versione diverso, quindi il changelog esatto della sorgente o del pacchetto ha precedenza su questa tabella.
Le linee vendor supportate più vecchie richiedono un backport. Alla data del 2026-08-12, il tracciatore CVE di Ubuntu segna il pacchetto linux di Jammy come needs-triage; non è stato identificato alcun pacchetto Ubuntu Jammy corretto. La sorgente testata 5.15.0-187.197 chiama ancora direttamente kfree(pch) ed è vulnerabile.
Il kernel non è stato ricompilato. L'immagine cloud minima non includeva linux-modules-extra-5.15.0-187-generic, quindi è stato installato quel pacchetto Ubuntu ufficiale per fornire l2tp_ppp. Una normale installazione Jammy tramite il metapacchetto linux-generic dipende già dal pacchetto modules-extra corrispondente. Il modulo del protocollo viene caricato automaticamente quando l'exploit crea la sua socket PPPoL2TP.
Il rilevatore automatico di KASLR usa un canale laterale di temporizzazione via prefetch x86 e richiede RDTSCP con KPTI inattivo. La CPU host testata espone rdtscp, smep e smap e non è affetta da Meltdown, quindi Ubuntu lascia KPTI inattivo senza alcuna modifica all'avvio. Su una CPU in cui /proc/cpuinfo riporta il flag pti, il rilevatore rifiuta di funzionare. Questa è una condizione hardware specifica dell'exploit: la CVE sottostante rimane raggiungibile, ma questa release non dichiara un bypass di KASLR su un sistema con KPTI attivo. Uno slide fornito manualmente esiste solo per diagnostica controllata.
struct channel liberata. Il percorso RX ancora in esecuzione tratta i byte di chiave controllati come la propria coda skb e waitqueue.core_pattern come area di appoggio per la divulgazione ed espone un puntatore relativo all'allocazione della chiave.override_creds() con la credenziale falsificata. I campi UID/GID, le capacità e i puntatori richiesti a user, namespace, ucount e group corrispondono esattamente alla build Ubuntu./proc/self/exe in un file univoco in /tmp, lo rende di proprietà di root con modalità 4755 e verifica tali attributi./usr/bin/id.L'ultimo passaggio intermedio è necessario perché override_creds() modifica le credenziali soggettive del task kernel attivo; installare ed eseguire la copia SUID verificata trasforma quella primitiva di breve durata in credenziali di processo normali.
Il Makefile linka staticamente l'exploit. L'oggetto prefetch sensibile alla temporizzazione è compilato deliberatamente con -O0; l'exploit stesso usa -O2.
make
Comandi equivalenti:
gcc -O0 -Wall -Wextra -Werror -c -o build/kaslr_prefetch.o kaslr_prefetch.c
gcc -O2 -static -pthread -Wall -Wextra -Werror \
-o build/CVE-2026-68398 exploit.c build/kaslr_prefetch.o
Dall'account utente ordinario, sul kernel esatto validato:
id
grep '^Cap' /proc/self/status
./CVE-2026-68398 auto 60
Il sorgente controlla uname() e rifiuta qualsiasi release diversa da 5.15.0-187-generic. La race è probabilistica; riavvia uno snapshot usa e getta prima di riprovare dopo un errore o un crash.
Un'esecuzione riuscita termina con:
[KASLR] image_base=0xffffffffb9200000 slide=0x38200000
CVE-2026-68398 Ubuntu local privilege-escalation exploit
uid=1001 euid=1001 slide=0x38200000
...
[9/9] invoking override_creds and installing the SUID transition...
override callback: uid=0 euid=0 gid=0 egid=0
installed root-owned mode 4755 helper: /tmp/.cve-2026-68398-root-948
SUID helper ready; executing it from the original unprivileged task...
SUID transition: uid=0 euid=0 gid=0 egid=0
uid=0(root) gid=0(root) groups=0(root),1001(poc)
La trascrizione concisa completa di quella reale esecuzione in QEMU si trova in docs/example-output.txt.
La catena è stata completata su tre avvii Ubuntu nuovi e normalmente randomizzati. Le basi immagine recuperate automaticamente erano 0xffffffff90800000, 0xffffffffa5a00000 e 0xffffffffb9200000. L'esecuzione finale ha usato l'account dedicato non amministrativo UID 1001 descritto sopra e ha verificato che il file SUID temporaneo fosse stato rimosso in seguito.
La stessa race finale è stata eseguita anche per 60 secondi sull'esatto commit di correzione upstream con KASAN abilitato e la stessa topologia a quattro vCPU. Ha completato 5.969 cicli canale/chiave, ha riportato stage 1: no controlled reclaim e non ha prodotto alcun report KASAN né transizione di stato dell'exploit.
Verifica effettuata il 2026-08-12 prima della creazione di questo repository privato. SearchSploit/Exploit-DB non ha restituito alcun exploit; Packet Storm non ha restituito file corrispondenti; la ricerca codice esatto su GitHub ha restituito 22 mirror di CVE/avvisi e nessun PoC; e le ricerche web esatte hanno trovato solo la correzione upstream e i metadati. Questo è un risultato puntuale, non una garanzia che un altro PoC non appaia in seguito.
kaslr_prefetch.cL'exploit è stato scritto da A. Ramos <[email protected]> (Twitter: @aramosf). La scoperta della vulnerabilità e la correzione upstream sono attribuite a Norbert Szetei (Doyensec).
exploit.c è con licenza GPL-2.0-only. kaslr_prefetch.c e kaslr_prefetch.h sono con licenza MIT e mantengono l'attribuzione KASLD e l'avviso di permesso completo nei file sorgente.
| Linea del kernel | Prima release corretta | Commit di correzione |
|---|
| 6.6.y | 6.6.148 | 4bb84e964ff0 |
| 6.12.y | 6.12.101 | 3ab32218d718 |
| 6.18.y | 6.18.42 | c9574b8a8ede |
| 7.1.y | 7.1.6 | 06213c85d8c0 |
| Mainline | 7.2-rc4 | ec4215683e47 |
| Proprietà | Valore |
|---|
| Distribuzione | Ubuntu 22.04.5 LTS (Jammy) |
| Pacchetto kernel | linux-image-5.15.0-187-generic / 5.15.0-187.197 |
| Release kernel | 5.15.0-187-generic #197-Ubuntu |
| Architettura | x86-64 |
| VM | QEMU/KVM, -cpu host, quattro vCPU, 5 GiB di RAM |
| Identità iniziale | uid=1001(poc) gid=1001(poc) groups=1001(poc) |
| Capacità iniziali | ereditabili, consentite, effettive e ambientali tutte a zero |
| Identità finale | uid=0(root) gid=0(root) nei namespace iniziali |
| Modifiche all'avvio | Nessuna; riga di comando standard, KASLR attivo |
| Requisito | Stato Ubuntu 5.15.0-187 | Uso nell'exploit |
|---|
| PPP | CONFIG_PPP=y | Integrato |
| L2TP / PPPoL2TP | CONFIG_L2TP=m, CONFIG_PPPOL2TP=m | Modulo ufficiale linux-modules-extra |
| Chiavi utente | CONFIG_KEYS=y | Recupera il canale kmalloc-256 liberato |
| AppArmor | CONFIG_SECURITY_APPARMOR=y | Rimane attivo; la credenziale falsa include un'etichetta unconfined valida |
| KASLR | CONFIG_RANDOMIZE_BASE=y | Rimane attivo; lo slide viene recuperato a runtime |
| SMAP | CONFIG_X86_SMAP=y | Rimane attivo |
| Namespace utente/rete | Abilitati da Ubuntu, ma non usati | Non è richiesta alcuna configurazione di namespace o acquisizione di capacità |
/dev/ppp | Non richiesto | Il canale è vincolato ma mai collegato a un'unità PPP |