
Implementaciones educativas de exploits en varios lenguajes para CVE-2026-31431, una escalada de privilegios local en el kernel de Linux a través del módulo algif_aead, con un detector seguro y guía de uso para CTF.
Repo educativo con implementaciones en múltiples lenguajes del exploit Copy Fail.
Creado y mantenido por @shotafry — porque leer el CVE no es suficiente. Hay que reproducirlo.
Copy Fail es una vulnerabilidad de escalada de privilegios local (LPE) en el kernel de Linux, catalogada como CVE-2026-31431. Afecta al subsistema criptográfico del kernel, concretamente al módulo algif_aead que gestiona las operaciones de cifrado autenticado (AEAD) a través de sockets AF_ALG.
El fallo fue introducido en 2017 en una optimización del módulo authencesn y permaneció sin detectarse durante casi 9 años, presente en prácticamente todas las distribuciones Linux modernas.
Lo que hace especial a Copy Fail respecto a otros LPEs históricos:
| Característica | Copy Fail | LPE típico |
|---|---|---|
| Necesita race condition | ❌ No | ✅ Sí |
| Necesita offset específico del kernel | ❌ No | ✅ Sí |
| Funcional en todas las distros | ✅ Sí | ❌ Normalmente no |
| Fiabilidad | 100% determinista | Variable |
| Modifica el disco | ❌ No (solo RAM) | Depende |
La vulnerabilidad fue descubierta por Taeyang Lee del equipo de investigación de Theori. La cadena de exploit completa fue desarrollada por el equipo Xint Code Research, que documentó el proceso usando análisis asistido por IA sobre el subsistema crypto/ del kernel de Linux.
La divulgación pública incluye PoC funcional, análisis técnico completo y documentación en copy.fail.
CVE: CVE-2026-31431
CVSS: 7.8 — ALTA
Vector: Local
Impacto: Escalada de privilegios completa (root)
Distros: Todas las distribuciones Linux con kernel >= 2017 sin parchear
El CVSS es 7.8 y no llega a crítico (9+) únicamente porque requiere acceso local previo — el atacante ya debe tener una sesión en el sistema. En entornos cloud y con contenedores Docker, este requisito es considerablemente más fácil de cumplir de lo que parece.
El kernel de Linux guarda en RAM los ficheros que ha leído recientemente. A esto se le llama page cache. Cuando un proceso lee /etc/passwd, el kernel no va al disco — sirve la copia en RAM. Esto es más rápido, pero crea una superficie de ataque: si puedes modificar esa copia en RAM sin tocar el disco, el sistema verá datos falsos.
El módulo algif_aead permite hacer operaciones AEAD desde espacio de usuario a través de sockets AF_ALG. El bug está en la optimización introducida en 2017: cuando se usa splice() para pasar páginas de un fichero al socket, esas páginas de la page cache acaban en la lista de dispersión destino (escribible) de la operación criptográfica.
Resultado: cualquier usuario sin privilegios puede escribir 4 bytes controlados en cualquier fichero que pueda leer, sin tocar el disco.
Usuario sin privilegios
│
▼
Abre socket AF_ALG (authencesn)
│
▼
sendmsg() — parámetros AEAD con nuestros 4 bytes en seqno_lo
│
▼
splice() — fichero → pipe → socket op
[BUG] La page cache del fichero queda en el scatterlist destino
│
▼
recv() dispara la operación AEAD
La auth falla (EBADMSG) pero el scratch-write ya ocurrió
│
▼
/etc/passwd (page cache) ahora dice: usuario → UID 0
│
▼
su <usuario> → PAM valida contraseña real → setuid(0) → ROOT
Imagina que el kernel tiene un libro de registros del castillo (/etc/passwd). Copy Fail es como descubrir que si abres el taller de magia del castillo en un orden muy concreto, el libro de registros accidentalmente se queda sobre tu mesa de trabajo — y puedes cambiar tu rango de "soldado raso" a "rey" con un bolígrafo. El archivero (PAM) comprueba tu contraseña pero no comprueba el libro original, solo la copia que tienes delante. Eres rey.

>= ~2017 sin el parche de CVE-2026-31431algif_aead disponible y cargableEsto realmente se puede saltar y directamente probar uno de los exploits, pero tambien es valido si no queremos arriesgarnos a subir o crearlos y solo queremos ver si funciona, pero los exploits tienen su funcion para revisar si el sistema en cuestion es vulnerable.
# Ver versión del kernel
uname -a
# Comprobar si el algoritmo está disponible
grep -i authencesn /proc/crypto
# Comprobar si el módulo está cargado
lsmod | grep alg
Si grep -i authencesn /proc/crypto devuelve authencesn(hmac(sha256),cbc(aes)), el sistema es vulnerable.
| Lenguaje | Requisito en el objetivo | Compilación previa |
|---|---|---|
| C | Ninguno (binario estático) | gcc en máquina de compilación |
| Python | Python 3.10+ | No |
| Rust | Ninguno (binario estático) | rustc en máquina de compilación |
| Go | Ninguno (binario estático) | go en máquina de compilación |
| Ruby | Ruby + gem fiddle (incluido por defecto) | No |
| Perl | Perl 5 (incluido en prácticamente todo Linux) | No |
Este repositorio contiene el exploit implementado en 6 lenguajes, todos funcionalmente equivalentes, con comentarios educativos en castellano.
copy_fail_exploit.c → C — binario estático, cero dependencias
copy_fail_exploit.py → Python — más legible, ideal para aprender
copy_fail_exploit.rs → Rust — la ironía: lenguaje "seguro" explota kernel
copy_fail_exploit.go → Go — binario estático, muy portable
copy_fail_exploit.rb → Ruby — omnipresente en servidores Rails
copy_fail_exploit.pl → Perl — el más silencioso, está en todo Linux
test_cve_2026_31431.py → Detector — verifica vulnerabilidad sin explotar nada
python3 test_cve_2026_31431.py
# Compilar
gcc copy_fail_exploit.c -o copy_fail_c
# Dry-run (limpia al salir, no deja rastro)
./copy_fail_c