
Un informe sobre Dirty Frag, que es una cadena de vulnerabilidades de escalada de privilegios local (LPE) en Linux que permite a un usuario sin privilegios obtener acceso root.
Laboratorio de reproducción y detección de exploits para una cadena de escalada de privilegios local en el kernel de Linux.
Estado: VERIFICADO. Completé la reproducción, la verificación sin archivos y la detección a nivel de llamadas al sistema en el laboratorio (kernel 6.18.9+kali-amd64). Este documento es un registro de laboratorio. Cada afirmación a continuación fue observada durante la ejecución de la reproducción. Las capturas de pantalla y los artefactos son capturas reales de la máquina virtual.
Dirty Frag combina dos errores lógicos deterministas en el kernel de Linux. Estos errores permiten que un usuario local sin privilegios sobrescriba la caché de páginas de archivos de solo lectura (por ejemplo, /usr/bin/su) y obtenga un shell root:
| Variante | CVE | Sumidero | Ruta de activación | ¿Necesita userns sin privilegios? |
|---|---|---|---|---|
| Escritura en Caché de Páginas xfrm‑ESP | CVE‑2026‑43284 | crypto_authenc_esn_decrypt() en esp_input() | socket(AF_INET) con UDP‑encap, luego xfrm_input() | Sí (CAP_NET_ADMIN) |
| Escritura en Caché de Páginas RxRPC | CVE‑2026‑43500 | rxkad_verify_packet_1() (pcbc(fcrypt)) | socket(AF_RXRPC) | No |
Ambas variantes usan el mismo patrón raíz que Dirty Pipe y Copy Fail. La llamada al sistema splice(2) coloca una referencia a una página de caché de páginas de un archivo en la ranura frag de un sk_buff del lado del remitente. El atacante solo puede leer este archivo. El código del kernel del lado receptor luego realiza un STORE criptográfico in situ sobre ese frag. Esto muta la caché de páginas en RAM. No ocurre ninguna escritura en disco, por lo que el monitoreo de integridad de archivos (AIDE, Tripwire) no puede verlo. El ataque es determinista. No tiene ventana de carrera ni pánico del kernel en caso de fallo.
cac2661c53f3 (2017‑01) hasta f4c50a4034e6 (parcheado 2026‑05‑05)2dc334f1a63a (2023‑06) hasta aa54b1d27fe0 (parcheado 2026‑05‑10)CVE-2026-43284 = 8.8 (Alta), CVE-2026-43500 = 7.8 (Alta)Dirty Frag es un LPE sin archivos. Corrompe la caché de páginas en memoria, no el archivo en disco. El monitoreo tradicional de integridad de archivos no puede verlo. La detección debe ocurrir en la capa de llamadas al sistema. La cadena usa estas primitivas de llamadas al sistema: socket(AF_ALG)/socket(AF_RXRPC), splice y unshare(CLONE_NEWUSER|CLONE_NEWNET). La ruta ESP también crea sockets UDP AF_INET y netlink. Esta capa es el enfoque de la ingeniería de detección en este repositorio.
Ambas variantes usan el mismo sumidero: criptografía in situ que ALMACENA bytes en una página de caché de páginas que el atacante coloca con splice(2).
UDP_ENCAP_ESPINUDP.vmsplice, luego 16 bytes de /usr/bin/su en el desplazamiento del archivo objetivo con splice.splice empuja la tubería hacia el socket de envío. splice_to_socket() establece MSG_SPLICE_PAGES. Esto coloca la página de caché de páginas de /usr/bin/su directamente en skb->frags[0].xfrm4_udp_encap_rcv, luego xfrm_input, luego esp_input(). La rama vulnerable skip_cow (!skb_cloned() && !skb_has_frag_list()) omite skb_cow_data(). Realiza descifrado AEAD in situ con la página de caché de páginas como origen y destino.crypto_authenc_esn_decrypt() emite un STORE de los 32 bits de orden superior del ESN. Ese valor es replay_esn->seq_hi. El atacante elige este valor en el registro de SA con el atributo netlink XFRMA_REPLAY_ESN_VAL.El atacante controla tanto la ubicación (desplazamiento de splice) como el valor (4 bytes). La verificación de autenticación se ejecuta después del store, por lo que la capa criptográfica nunca marca la escritura. Esta variante requiere CAP_NET_ADMIN y usa unshare(CLONE_NEWUSER|CLONE_NEWNET).
rxkad_verify_packet_1() realiza un descifrado pcbc(fcrypt) de un solo bloque directamente sobre el frag skb fijado con splice. No copia los datos primero. El atacante elige una clave de sesión (add_key("rxrpc", …)) para que decrypt(ciphertext) sea igual a desired_plaintext. Esto produce un STORE de 8 bytes. Esta variante apunta a /etc/passwd. No necesita espacio de nombres de usuario. Requiere el módulo rxrpc.ko (cargado por defecto en Ubuntu).
El PoC público apunta a /usr/bin/su. Escribe 48 stores ESP de 4 bytes cada uno (192 bytes en el desplazamiento de archivo 0). Reemplaza los primeros bytes de la caché de páginas con un ELF estático de shell root. El punto de entrada del ELF ejecuta setgid(0); setuid(0); setgroups(0,NULL); execve("/bin/sh", …). Un solo execve("/usr/bin/su") luego produce un shell root.
El parche ESP (mainline f4c50a4034e6) marca los frags de página que llegan a través de splice() con la bandera SKBFL_SHARED_FRAG. La rama skip_cow en esp_input() ahora también verifica esta bandera. Los skbs con frags compartidos pasan por skb_cow_data() antes del descifrado AEAD in situ.
El parche RxRPC (mainline aa54b1d27fe0) agrega una verificación de skb->data_len junto a la verificación existente de skb_cloned(). El kernel copia un skb no lineal con datos paginados antes del descifrado pcbc(fcrypt) in situ.
| Componente | Detalles |
|---|---|
| Hipervisor | VirtualBox |
| VM objetivo | Kali Linux 2026.1 (instantánea restaurada a un estado vulnerable) |
| Kernel | 6.18.9+kali‑amd64 (anterior a las correcciones de mayo de 2026) |
| PoC del exploit | V4bel/dirtyfrag (archivo C único) |
| Detección | auditd (reglas en detection/dirtyfrag.rules) |
Captura de pantalla de la configuración del laboratorio VirtualBox:
