Skip to content
KitploitKITPLOIT
HerramientasBlog
Log in
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
page_inject — CVE-2026-31431-killed page-cache exploit — ejecución de código en contenedores que comparten la misma capa de imagen | Kitploit
Herramientas/GitHubGitHub/sgkdev/page_inject
Análisis de VulnerabilidadesExplotaciónPost-ExplotaciónPruebas de PenetraciónRed TeamingEscape de ContenedoresExplotación de Binarios
GitHubsgkdev/page_inject

page_inject

CVE-2026-31431-killed page-cache exploit — ejecución de código en contenedores que comparten la misma capa de imagen

Ver Repositorio
741470hace 4 mesesRevisado por Kitploit

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

page_inject - Escape entre contenedores aead AF_ALG

Exploit de vulnerabilidad aead AF_ALG entre contenedores -- pivotar desde un contenedor comprometido a todos los contenedores hermanos que comparten la misma capa de imagen libc.so.6.

Esta es una primitiva de escape: se ejecuta desde dentro de un contenedor no privilegiado que el atacante ya ha comprometido, y utiliza el bug de escritura arbitraria de 4 bytes en la rotación ESN de authencesn de AF_ALG (CVE-2026-31431) para plantar un hook persistente de read() en las páginas de caché de página de libc.so.6. Debido a que Docker / containerd respaldan los archivos de la capa inferior de overlayfs con inodos compartidos, esas páginas son visibles para todos los contenedores hermanos instanciados desde la misma imagen -- el hook se activa también en sus procesos, y el atacante obtiene ejecución de comandos dentro de cada uno.

Modelo de amenaza

  • El atacante tiene acceso shell a un solo contenedor (llámelo victim) en un host que ejecuta otros contenedores (siblings) desde la misma imagen que victim.
  • victim se ejecuta con la configuración predeterminada de Docker/k8s: uid no privilegiado dentro del namespace de usuario del contenedor, perfil seccomp predeterminado, perfil AppArmor predeterminado, sin capacidades especiales, sin bind mounts del host.
  • victim tiene solo:
    • acceso de lectura a su propia libc (/usr/lib/x86_64-linux-gnu/libc.so.6 o donde la distribución la instale)
    • la familia de syscalls estándar socket(AF_ALG, ...)
    • las syscalls estándar splice / vmsplice
    • acceso de escritura a un directorio al que pueda hacer chmod +x (por ejemplo, /tmp)
  • El kernel debe ser vulnerable a CVE-2026-31431 (cualquier compilación de algif_aead + authencesn anterior a la corrección de reversión upstream).

Eso es todo. Sin CAP_* especial, sin acceso al sistema de archivos del host. El atacante coloca un binario autocontenido enlazado estáticamente dentro del contenedor, lo ejecuta, y la corrupción de la caché de página -- y por lo tanto el hook -- se vuelve visible para todos los hermanos.

Cómo se encadena el exploit

  1. Identidad de página de caché de página. Dentro de un contenedor overlayfs, /usr/lib/.../libc.so.6 es servido por el inodo ext4 de la capa inferior de la imagen. Cada contenedor iniciado desde la misma imagen comparte ese inodo subyacente, y la caché de página del kernel se clavea por el inodo subyacente -- no por el overlay ni por el namespace. Así, una sola escritura de 4 bytes en una página de caché de página es visible para todos los procesos de los contenedores hermanos que tengan esa página mapeada.

  2. La vulnerabilidad aead de AF_ALG convierte una escritura de este tipo en muchas. algif_aead encadena el iovec RX del usuario con los bytes authsize finales del SGL TX empalmado, y la rotación ESN de authencesn coloca 4 bytes del campo seq_high del AAD en dst[assoclen + cryptlen] -- que es el primer byte de esa cola externa encadenada. La página empalmada es una página de caché de página de un archivo al que el atacante solo tiene acceso de lectura, pero el cifrador copia bytes en ella de todos modos, sin contabilidad dirty. (Vea crypto/algif_aead.c y crypto/authencesn.c para la mecánica subyacente.)

  3. Inicialización de una primitiva invocable. Lo primero que hace page_inject es inicializar Zone A -- una reimplementación codificada en asm del mismo baile AF_ALG (write_cache.asm), colocada dentro de la cueva .text de libc. Esto hace que la escritura de 4 bytes sea un call regular desde dentro de cualquier payload de hook futuro, sin necesidad de configuración de socket por llamada.

  4. Instalación del hook. El inyector luego escribe Zone C (zone_c.asm) en la cueva .text de libc y parchea los primeros 7-12 bytes de read() con un salto E9 disp32 hacia ella. Los bytes desplazados del prólogo se emulan fielmente en la ruta rápida de Zone C (se reconocen tres prólogos diferentes de glibc -- vea "Manejo de prólogos" más abajo). El hook ahora está activo en la caché de página de libc.

  5. Propagación del hook. Cada contenedor hermano ejecuta procesos que llaman a read() constantemente (demonios de registro, healthchecks, cat /etc/hostname, cualquier cosa). En la primera llamada de este tipo dentro de un contenedor hermano, el prólogo secuestrado salta a Zone C, que:

    • hace stat("/") del inodo raíz del contenedor (un ID estable por namespace), lo usa como clave del slot del contenedor,
    • escanea la tabla de slots en busca de una entrada existente con esa clave,
    • si está ausente, registra la clave y hace fork() de un hijo de bucle de comandos de larga duración que sondea el área CMD en busca de órdenes,
    • retorna a read()+N para que el llamante no se dé cuenta. El proceso hermano original sigue ejecutándose. A partir de ahora, el atacante tiene un demonio dentro de ese contenedor.
  6. Canal de comandos. El atacante usa el mismo binario page_inject en modo --shell para escribir comandos en el área CMD de la región de slots. El hijo del hook de cada contenedor hermano registrado sondea, hace fork de /bin/sh -c <cmd>, captura stdout/stderr en el área OUTPUT, señala finalización, y vuelve a sondear. El shell muestra la salida. Debido a que cada escritura CMD/OUTPUT también pasa por la primitiva de la vulnerabilidad, no se necesita ningún privilegio especial.

  7. Deshacer hook. Cuando se termina, unhook restaura los bytes originales del prólogo de read() y pone a cero la tabla de slots; los hijos del hook ven un slot vacío en su próxima iteración y se autofinalizan. Las modificaciones de la caché de página en sí son limpias (el kernel nunca marcó las páginas modificadas como dirty), así que una vez que se detienen todos los contenedores que tienen libc mapeada, un drop_caches revierte completamente la caché -- no queda ningún artefacto en disco.

Compilación

El inyector se compila fuera del contenedor víctima -- típicamente en la máquina de desarrollo del atacante -- porque la mayoría de las imágenes de contenedor de producción no incluyen un compilador. Un entorno de desarrollo Linux x86_64 estándar con gcc (con soporte de enlace -static) y nasm es suficiente.

make            # assembles .asm sources via gen_arrays.sh, links static page_inject
make shellcode  # also produces inspectable .bin flat binaries
make clean      # removes generated files and the binary

La salida es un único ELF enlazado estáticamente (./page_inject) que se ejecuta en cualquier kernel Linux x86_64 moderno.

Entrega y uso (desde el contenedor víctima)

Una vez que el atacante tiene shell en victim, sube el binario a un directorio escribible (típicamente /tmp):

# inside the compromised container, attacker session
victim$ ./page_inject

Sin argumentos, page_inject usa por defecto /usr/lib/x86_64-linux-gnu/libc.so.6 (la ubicación posterior a la fusión en Debian/Ubuntu). Para otras distribuciones, libc está en una ruta diferente; pásala explícitamente o usa --root / para escanear la tabla de búsqueda incorporada desde la raíz del contenedor:

# Fedora / Rocky / CentOS
victim$ ./page_inject /usr/lib64/libc.so.6

# Arch
victim$ ./page_inject /usr/lib/libc.so.6

# Auto-detect, regardless of distro:
victim$ ./page_inject --root /

Cualquiera de las invocaciones hace lo mismo: analizar ELF de libc dentro del contenedor, instalar el hook en su caché de página, monitorear la tabla de slots durante ~30 s mientras los hermanos se registran, y ejecutar un id de una sola vez contra el primer hermano que se registró como verificación de cordura.

Después de la inicialización, ingresa al shell de comandos para manejar cualquier hermano registrado:

Descargar herramienta