
CVE-2026-68398 Escalação local de privilégios por use-after-free no PPPoL2TP do Ubuntu

Este repositório contém um exploit de escalonamento de privilégios local específico para uma build
da CVE-2026-68398, uma condição de corrida do tipo use-after-free entre o processamento de recepção
do PPPoL2TP e a destruição de um canal PPP não anexado. Foi validado em
QEMU contra o pacote oficial do Ubuntu 22.04
linux-image-5.15.0-187-generic (5.15.0-187.197).
O teste final começa como um usuário dedicado com UID 1001, sem grupos
suplementares, sem capabilities e sem acesso sudo, e então obtém o
UID 0 do namespace inicial. KASLR, SMEP, SMAP e AppArmor permanecem ativos. A VM não é iniciada
com nokaslr, nopti, nosmep ou nosmap.
Aviso
Este código corrompe intencionalmente o estado do heap do kernel e está vinculado a uma build exata do kernel Ubuntu. Uma corrida mal-sucedida pode causar pânico ou corromper o sistema. Execute-o somente em uma VM isolada e descartável que você possua.
pppol2tp_recv() é executada no caminho de recepção UDP do L2TP dentro de uma seção crítica
de leitura do RCU e eventualmente chama ppp_input(&po->chan). O socket PPPoX
e seu ppp_channel embutido são seguros para RCU, mas o struct channel interno
usado por ppp_input() é uma alocação separada.
Para um canal vinculado com PPPIOCGCHAN, mas nem anexado a uma unidade PPP nem
em ponte, o caminho de fechamento liberava esse objeto interno imediatamente:
RX: l2tp_udp_encap_recv -> pppol2tp_recv -> ppp_input(channel)
CLOSE: pppol2tp_release -> pppox_unbind_sock
-> ppp_unregister_channel -> ppp_release_channel -> kfree(channel)
O caminho de recepção pode, consequentemente, operar na fila skb e na waitqueue do canal já
liberado. A correção adiciona um callback de RCU ao struct channel e adia a limpeza
da fila e a liberação até que um período de graça do RCU tenha decorrido.
A vulnerabilidade foi descoberta e corrigida upstream por
Norbert Szetei da Doyensec.
A correção na mainline é
ec4215683e47424c9c4762fd3c60f552a3119142.
O registro CNA do Linux identifica a linhagem vulnerável como tendo início no Linux 4.15. Kernels de fornecedores podem trazer a correção com um número de versão diferente, portanto a fonte exata ou o changelog do pacote tem precedência sobre esta tabela.
As linhas de fornecedores mais antigas ainda suportadas exigem um backport. Em 2026-08-12, o
rastreador de CVEs do Ubuntu
marca o pacote linux do Jammy como needs-triage; nenhum pacote corrigido do Ubuntu Jammy
foi identificado. O código-fonte testado 5.15.0-187.197 ainda chama
kfree(pch) diretamente e é vulnerável.
O kernel não foi recompilado. A imagem de nuvem mínima não incluía
linux-modules-extra-5.15.0-187-generic, portanto esse pacote oficial do Ubuntu foi
instalado para fornecer l2tp_ppp. Uma instalação normal do Jammy usando o
metapacote linux-generic já depende do pacote modules-extra correspondente.
O módulo do protocolo é carregado automaticamente quando o exploit cria seu socket PPPoL2TP.
O detector automático de KASLR usa um canal lateral de temporização do prefetch x86 e
exige RDTSCP com KPTI inativo. A CPU do host testado expõe rdtscp,
smep e smap e não é afetada pelo Meltdown, então o Ubuntu deixa o KPTI
inativo sem qualquer alteração no boot. Em uma CPU em que /proc/cpuinfo reporta o
flag pti, o detector se recusa a executar. Essa é uma condição de hardware específica do exploit:
a CVE subjacente permanece alcançável, mas esta versão não afirma um bypass de KASLR em um sistema com KPTI ativo. Um slide fornecido manualmente existe
apenas para diagnósticos controlados.
struct channel liberado. O caminho RX ainda em execução
trata os bytes controlados da chave como sua fila skb e waitqueue.core_pattern como área de escrita temporária para divulgação
e expõe um ponteiro de alocação da chave.override_creds() com a credencial forjada.
Os campos UID/GID, capabilities e os ponteiros necessários de user, namespace, ucount e
group correspondem exatamente à build do Ubuntu testada./proc/self/exe para um
arquivo exclusivo em /tmp, altera-o para propriedade de root com modo 4755 e verifica esses
atributos./usr/bin/id.A última ponte é necessária porque override_creds() altera as credenciais subjetivas
da tarefa ativa do kernel; instalar e executar a cópia SUID verificada
transforma essa primitiva de curta duração em credenciais normais de processo.
O Makefile vincula o exploit estaticamente. O objeto de prefetch sensível a temporização é
deliberadamente compilado em -O0; o próprio exploit usa -O2.
make
Comandos equivalentes:
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
A partir da conta de usuário comum, no kernel validado exato:
id
grep '^Cap' /proc/self/status
./CVE-2026-68398 auto 60
O código-fonte verifica uname() e recusa qualquer release diferente de
5.15.0-187-generic. A corrida é probabilística; reinicie um snapshot descartável
antes de tentar novamente após uma falha ou um travamento.
Uma execução bem-sucedida termina com:
[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)
A transcrição concisa e completa dessa execução real em QEMU está em
docs/example-output.txt.
A cadeia foi concluída em três boots novos do Ubuntu, normalmente randomizados. As
bases de imagem recuperadas automaticamente foram 0xffffffff90800000,
0xffffffffa5a00000 e 0xffffffffb9200000. A execução final usou a conta
não administrativa dedicada com UID 1001 descrita acima e verificou que o
arquivo SUID temporário foi removido depois.
A mesma corrida final também foi executada por 60 segundos exatamente no commit da correção
upstream com KASAN ativado e a mesma topologia de quatro vCPUs. Ela completou 5.969
ciclos de canal/chave, reportou stage 1: no controlled reclaim e não produziu nenhum
relatório do KASAN nem transição de estágio do exploit.
Verificado em 2026-08-12 antes de este repositório privado ser criado. SearchSploit/Exploit-DB não retornou nenhum exploit; Packet Storm não retornou nenhum arquivo correspondente; a pesquisa de código exato no GitHub retornou 22 espelhos de CVE/avisos e nenhum PoC; e buscas exatas na web encontraram apenas a correção upstream e metadados. Este é um resultado pontual, não uma garantia de que outro PoC não aparecerá depois.
kaslr_prefetch.cO exploit foi escrito por A. Ramos <[email protected]> (Twitter:
@aramosf). A descoberta da vulnerabilidade e a
correção upstream são creditadas a Norbert Szetei (Doyensec).
exploit.c é licenciado apenas sob GPL-2.0. kaslr_prefetch.c e kaslr_prefetch.h são licenciados sob MIT
e mantêm a atribuição do KASLD e o aviso de permissão completo nos
arquivos-fonte.
| Linha do kernel | Primeira versão corrigida | Commit da correção |
|---|
| 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 |
| Propriedade | Valor |
|---|
| Distribuição | Ubuntu 22.04.5 LTS (Jammy) |
| Pacote do kernel | linux-image-5.15.0-187-generic / 5.15.0-187.197 |
| Release do kernel | 5.15.0-187-generic #197-Ubuntu |
| Arquitetura | x86-64 |
| VM | QEMU/KVM, -cpu host, quatro vCPUs, 5 GiB de RAM |
| Identidade inicial | uid=1001(poc) gid=1001(poc) groups=1001(poc) |
| Capabilities iniciais | herdáveis, permitidas, efetivas e ambientais todas zeradas |
| Identidade final | uid=0(root) gid=0(root) nos namespaces iniciais |
| Alterações no boot | Nenhuma; linha de comando padrão, KASLR ativado |
| Requisito | Estado no Ubuntu 5.15.0-187 | Uso no exploit |
|---|
| PPP | CONFIG_PPP=y | Compilado embutido |
| L2TP / PPPoL2TP | CONFIG_L2TP=m, CONFIG_PPPOL2TP=m | Módulo oficial linux-modules-extra |
| User keys | CONFIG_KEYS=y | Recupera o canal kmalloc-256 liberado |
| AppArmor | CONFIG_SECURITY_APPARMOR=y | Permanece ativo; o cred falso inclui um rótulo unconfined válido |
| KASLR | CONFIG_RANDOMIZE_BASE=y | Permanece ativo; o slide é recuperado em tempo de execução |
| SMAP | CONFIG_X86_SMAP=y | Permanece ativo |
| Namespaces de usuário/rede | Ativados pelo Ubuntu, mas não usados | Nenhuma configuração de namespace ou ganho de capability é necessária |
/dev/ppp | Não necessário | O canal é vinculado, mas nunca conectado a uma unidade PPP |