
Um relatório sobre Dirty Frag, que é uma cadeia de vulnerabilidades de Escalação de Privilégio Local (LPE) do Linux que permite que um usuário não privilegiado obtenha acesso root.
Laboratório de Reprodução e Detecção de Exploit para uma cadeia de escalonamento local de privilégios no kernel Linux.
Status: VERIFICADO. Concluí a reprodução, a verificação sem arquivos e a detecção no nível de chamadas de sistema no laboratório (kernel 6.18.9+kali-amd64). Este documento é um registro de laboratório. Cada afirmação abaixo foi observada durante a execução da reprodução. As capturas de tela e artefatos são capturas reais da VM.
O Dirty Frag combina dois bugs lógicos determinísticos no kernel Linux. Esses bugs permitem que um usuário local sem privilégios sobrescreva o cache de páginas de arquivos somente leitura (por exemplo, /usr/bin/su) e obtenha um shell root:
| Variante | CVE | Sink | Caminho de gatilho | Requer userns sem privilégios |
|---|---|---|---|---|
| Gravação no Page-Cache via xfrm‑ESP | CVE‑2026‑43284 | crypto_authenc_esn_decrypt() em esp_input() | socket(AF_INET) com UDP‑encap, depois xfrm_input() | Sim (CAP_NET_ADMIN) |
| Gravação no Page-Cache via RxRPC | CVE‑2026‑43500 | rxkad_verify_packet_1() (pcbc(fcrypt)) | socket(AF_RXRPC) | Não |
Ambas as variantes usam o mesmo padrão de raiz do Dirty Pipe e do Copy Fail. A chamada de sistema splice(2) coloca uma referência a uma página do page-cache de um arquivo no slot frag de um sk_buff do lado do remetente. O atacante só pode ler este arquivo. O código do kernel no lado do receptor então executa um STORE criptográfico in-place sobre esse frag. Isso altera o page-cache na RAM. Nenhuma gravação em disco ocorre, portanto o monitoramento de integridade de arquivos (AIDE, Tripwire) não consegue detectar. O ataque é determinístico. Não possui janela de corrida nem pânico do kernel em caso de falha.
cac2661c53f3 (2017‑01) a f4c50a4034e6 (corrigido em 2026‑05‑05)2dc334f1a63a (2023‑06) a aa54b1d27fe0 (corrigido em 2026‑05‑10)CVE-2026-43284 = 8.8 (Alta), CVE-2026-43500 = 7.8 (Alta)O Dirty Frag é um LPE sem arquivos. Ele corrompe o page-cache na memória, não o arquivo no disco. O monitoramento tradicional de integridade de arquivos não consegue detectá-lo. A detecção deve ocorrer na camada de chamadas de sistema. A cadeia usa estes primitivos de chamadas de sistema: socket(AF_ALG)/socket(AF_RXRPC), splice e unshare(CLONE_NEWUSER|CLONE_NEWNET). O caminho ESP também cria sockets UDP AF_INET e netlink. Esta camada é o foco da engenharia de detecção neste repositório.
Ambas as variantes usam o mesmo sink: criptografia in-place que ARMAZENA bytes em uma página do page-cache que o atacante coloca com splice(2).
UDP_ENCAP_ESPINUDP.vmsplice e, em seguida, 16 bytes de /usr/bin/su no deslocamento do arquivo alvo com splice.splice empurra o pipe para o socket de envio. splice_to_socket() define MSG_SPLICE_PAGES. Isso coloca a página do page-cache de /usr/bin/su diretamente em skb->frags[0].xfrm4_udp_encap_rcv, depois xfrm_input, depois esp_input(). O ramo vulnerável skip_cow (!skb_cloned() && !skb_has_frag_list()) ignora skb_cow_data(). Ele executa descriptografia AEAD in-place com a página do page-cache como origem e destino.crypto_authenc_esn_decrypt() emite um STORE dos 32 bits de ordem superior do ESN. Esse valor é replay_esn->seq_hi. O atacante escolhe esse valor no registro da SA com o atributo netlink XFRMA_REPLAY_ESN_VAL.O atacante controla tanto a localização (deslocamento do splice) quanto o valor (4 bytes). A verificação de autenticação é executada após o store, portanto a camada criptográfica nunca sinaliza a gravação. Esta variante requer CAP_NET_ADMIN e usa unshare(CLONE_NEWUSER|CLONE_NEWNET).
rxkad_verify_packet_1() executa uma descriptografia pcbc(fcrypt) de bloco único diretamente no frag do skb fixado por splice. Ele não copia os dados primeiro. O atacante escolhe uma chave de sessão (add_key("rxrpc", …)) para que decrypt(ciphertext) seja igual a desired_plaintext. Isso produz um STORE de 8 bytes. Esta variante tem como alvo /etc/passwd. Ela não requer namespace de usuário. Requer o módulo rxrpc.ko (carregado por padrão no Ubuntu).
O PoC público tem como alvo /usr/bin/su. Ele grava 48 stores ESP de 4 bytes cada (192 bytes no deslocamento 0 do arquivo). Ele substitui os primeiros bytes do page-cache por um ELF estático de shell root. O ponto de entrada do ELF executa setgid(0); setuid(0); setgroups(0,NULL); execve("/bin/sh", …). Um único execve("/usr/bin/su") então produz um shell root.
O patch ESP (mainline f4c50a4034e6) marca os frags de página que chegam por splice() com o sinalizador SKBFL_SHARED_FRAG. O ramo skip_cow em esp_input() agora também verifica esse sinalizador. Skbs com frags compartilhados passam por skb_cow_data() antes da descriptografia AEAD in-place.
O patch RxRPC (mainline aa54b1d27fe0) adiciona uma verificação de skb->data_len ao lado da verificação existente de skb_cloned(). O kernel copia um skb não linear com dados paginados antes da descriptografia pcbc(fcrypt) in-place.
| Componente | Detalhes |
|---|---|
| Hipervisor | VirtualBox |
| VM alvo | Kali Linux 2026.1 (snapshot restaurado para um estado vulnerável) |
| Kernel | 6.18.9+kali‑amd64 (mais antigo que as correções de maio de 2026) |
| PoC do exploit | V4bel/dirtyfrag (arquivo C único) |
| Detecção | auditd (regras em detection/dirtyfrag.rules) |
Captura de tela da configuração do laboratório VirtualBox:

.
├── README.md # este registro de laboratório
├── detection/
│ ├── dirtyfrag.rules # regras de detecção no nível de chamadas de sistema do auditd
│ ├── ausearch_dirtyfrag_observed.txt # saída real de detecção do exploit
│ ├── sigma/
│ │ └── dirty_frag_exploit.yml # regra Sigma para detecção em SIEM
│ └── yara/
│ └── dirty_frag_exploit.yar # regra YARA para código PoC em disco/memória
├── mitigation/
│ └── dirtyfrag_mitigation.sh # bloqueio de módulos + limpeza do page cache
├── poc/
│ └── check_vulnerable.py # verificador pré-voo não destrutivo
├── reports/
│ └── incident-dirtyfrag.md # playbook de resposta a incidentes
└── screenshots/ # capturas reais da VM do laboratório