Skip to content
KitploitKITPLOIT
HerramientasBlog
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
CVE-2026-46215-POC — Exploit para CVE-2026-46215, una escalada de privilegios local por use-after-free en DRM GEM del kernel de Linux. Utiliza carreras, slab spraying y sobrescritura de archivos estilo Dirty Pipe para convertir a un usuario no privilegiado del nodo de renderizado en root sin contraseña. | Kitploit
Herramientas/GitHubGitHub/0xcyberstan/cve-2026-46215-poc
Escalada de PrivilegiosForensia de MemoriaAnálisis de VulnerabilidadesExplotaciónCTFAprendizaje y EducaciónExplotación de Binarios
GitHub0xcyberstan/cve-2026-46215-poc

CVE-2026-46215-POC

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 →

Acerca de

Exploit para CVE-2026-46215, una escalada de privilegios local por use-after-free en DRM GEM del kernel de Linux. Utiliza carreras, slab spraying y sobrescritura de archivos estilo Dirty Pipe para convertir a un usuario no privilegiado del nodo de renderizado en root sin contraseña.

Ver Repositorio
1123hace 2 mesesAún no revisado
Compartir

CVE-2026-46215: DRM GEM change_handle Use-After-Free (LPE sin privilegios)

Escalada de privilegios local a través de un use-after-free en el ioctl del núcleo DRM DRM_IOCTL_GEM_CHANGE_HANDLE (drm_gem_change_handle_ioctl, ioctl nr 0xD2). Accesible por cualquier usuario con acceso a un nodo de renderizado (/dev/dri/renderD*, otorgado a la sesión activa por systemd-logind en todas las principales distribuciones de escritorio). La cadena en este repositorio lleva el UAF a root sin contraseña desde un usuario sin privilegios.

  • CVE: CVE-2026-46215 (HIGH, 7.8, AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H)
  • Introducido: v6.18-rc1, commit 53096728b891 ("drm: Add DRM prime interface to reassign GEM handle", David Francis / AMD), añadido para el trabajo CRIU de AMD
  • Corregido en: 6.18.32, 7.0.9, 7.1-rc3 (upstream 5e28b7b94408). El ioctl también se está desactivando en upstream 7.1 debido a esto y a race conditions relacionadas.
  • Afectado: v6.18-rc1 hasta las versiones corregidas anteriores

Atribución

Este error fue reportado por primera vez por Puttimet Thammasaeng, quien tiene el crédito Reported-by en la corrección upstream. Lo encontré y lo reporté de forma independiente a [email protected] el 12 de abril de 2026. Mi reporte fue reconocido y reenviado a los mantenedores, pero el reporte anterior es el que se acredita upstream. Este repositorio contiene mi propio análisis y exploit.

Writeup: https://cyberstan.co.uk

Estado de divulgación

La corrección está en kernels estables publicados (6.18.32 y 7.0.9 en adelante). Este repositorio fue publicado después de que las correcciones estuvieran ampliamente disponibles.

El error

drm_gem_change_handle_ioctl() mueve un objeto GEM de un identificador a otro pero nunca ajusta obj->handle_count. También omite drm_vma_node_allow/revoke y los callbacks de open/close del driver. Debido a que handle_count permanece en 1, un GEM_CLOSE concurrente en el identificador antiguo lo reduce a 0 y libera el objeto mientras el nuevo identificador aún lo referencia en el IDR. Ese identificador colgante es el use-after-free, posteriormente desreferenciado en drm_gem_object_release_handle().

Cadena de explotación

  1. Hacer una race condition entre GEM_CHANGE_HANDLE y GEM_CLOSE para obtener un identificador colgante.
  2. Reclamar la ranura del slab del objeto liberado con un array de pipe_buffer rociado (feng shui de msg_msg para condicionar kmalloc-512, luego pipes llenados con splice).
  3. Filtrar pipe_buf_ops a través de un ioctl de información del driver: obj->size (offset 216) se superpone con pipe_buf[5].ops, dando un puntero del kernel y la base de KASLR.
  4. FLINK el identificador colgante para que obj->name (offset 224) caiga sobre pipe_buf[5].flags y establezca PIPE_BUF_FLAG_CAN_MERGE (name = 16 = 0x10).
  5. Escribir a las pipes para fusionar en el page cache y sobrescribir un archivo de solo lectura (estilo DirtyPipe). El objetivo es , root se vuelve sin contraseña.

Los offsets están verificados mediante pahole y son específicos del diseño entre 6.18 y 7.0. Sobrescribir las definiciones GEM_* / PIPEBUF_* para otros kernels.

Archivos

  • poc.c - el exploit. Compilar estático con -lpthread.
  • run_exploit.sh - construye el PoC y un initramfs mínimo, lo arranca en QEMU.

Prerrequisitos del host

qemu-system-x86_64, gcc, busybox (estático), fakeroot, cpio, gzip. Se recomienda KVM (/dev/kvm); la race condition es mucho más fiable con él.

Construir un kernel de prueba

El exploit necesita un objetivo vulnerable construido con opciones específicas:

  • CONFIG_KASAN debe estar DESACTIVADO. KASAN pone en cuarentena los slabs liberados y bloquea la reclamación de pipe-spray, por lo que el exploit no funcionará contra una compilación con KASAN.
  • Un driver DRM que exponga los campos size/name en los offsets esperados: virtio_gpu (usado en la demo) o nouveau.
  • CONFIG_DRM=y, CONFIG_DRM_VIRTIO_GPU=y, CONFIG_DEVTMPFS=y, CONFIG_BLK_DEV_INITRD=y.

Pasos:

  1. Hacer checkout de un árbol de fuentes 6.18 a 7.0 (o cualquier árbol que falle la comprobación de parcheo más abajo).
  2. Establecer las opciones de configuración anteriores y asegurarse de que CONFIG_KASAN no esté activado.
  3. make -j"$(nproc)" bzImage, produciendo arch/x86/boot/bzImage.

La demo arranca con nokaslr para que el puntero filtrado sea determinista. La filtración vence a KASLR por sí sola, así que KASLR activado también funciona, la dirección varía en cada arranque.

Comprobar si un árbol es vulnerable o está parcheado

Mirar drivers/gpu/drm/drm_gem.c, función drm_gem_change_handle_ioctl().

Comprobación rápida:

root@kitploit:~
awk '/^int drm_gem_change_handle_ioctl/,/^}/' \
    drivers/gpu/drm/drm_gem.c | grep -c handle_count
  • 0 significa VULNERABLE (sin manejo de refcount).
  • distinto de cero significa PARCHADO.

Por estructura:

  • Vulnerable: toma file_priv->prime.lock, un único idr_alloc(&file_priv->object_idr, obj, ...), luego idr_remove() en el identificador antiguo. No hay drm_gem_object_handle_get.
  • Parcheado: inserción en dos fases (idr_alloc luego idr_replace(NULL) para desvincular el identificador antiguo), con el objeto real intercambiado solo cuando las operaciones prime tienen éxito.

Ejecutar el exploit

root@kitploit:~
./run_exploit.sh /path/to/bzImage

Construye poc.c, lo envuelve en un initramfs y arranca QEMU con -device virtio-gpu-pci y nokaslr. El PoC se ejecuta como uid 1000 (sin privilegios), luego el script imprime /etc/passwd antes y después y te deja en un shell. Sal de la VM con poweroff -f o Ctrl-A X.

Salida esperada

root@kitploit:~
[!] Race won (iter 977): handle=132049
[!] KASLR: pipe_buf_ops = 0xffffffff82428400
[!] EXPLOIT SUCCESSFUL
[!] FLINK: 16 = 0x10
[*] /etc/passwd:
    root::0:0:pwned:/root:/bin/sh
[!] LPE CONFIRMED
[!] root account is now passwordless

Un /etc/passwd de solo lectura (chmod 444) propiedad de root es sobrescrito por un proceso sin privilegios. La línea root: pierde su campo de contraseña.

Fiabilidad

  • Alrededor del 99% por arranque en pruebas (99/100 en 100 arranques nuevos, más 53/53 en ejecuciones anteriores). El PoC reintenta internamente: en una filtración mala, vuelve a hacer la race para obtener un objeto colgante nuevo en lugar de volver a rociar una ranura muerta, hasta 200 rondas, cada ronda unas decenas de milisegundos. La mayoría de los arranques ganan en la primera race; el peor observado usó 11 de las 200 rondas.
  • Raro (cerca del 1%) modo de fallo: una race perdedora corrompe el estado del kernel y bloquea la VM (cuelgue silencioso, sin veredicto impreso). Esto es inherente a un UAF de race en el kernel. Si una ejecución no imprime un veredicto en aproximadamente 30 segundos, reinicia el ciclo y vuelve a ejecutar.

Confirmar la corrección

Reconstruir contra un árbol parcheado (6.18.32, 7.0.9, 7.1-rc3 o posterior, o cualquier árbol que pase la comprobación de parcheo anterior) y volver a ejecutar:

root@kitploit:~
./run_exploit.sh /path/to/patched-bzImage

Contra el kernel parcheado el exploit nunca debería alcanzar "EXPLOIT SUCCESSFUL": la race ya no libera el objeto por debajo del nuevo identificador, por lo que la filtración nunca devuelve un puntero válido del kernel.

Aviso legal

Publicado con fines de investigación y defensa después de que las correcciones upstream hayan sido distribuidas. Se proporciona tal cual. Ejecutar solo contra VMs que controles.

Descargar herramienta
/etc/passwd