Matar la Visibilidad del EDR en el Kernel: BYOVD
La mayoría de los productos EDR comparten un presupuesto arquitectónico fundamental: dependen de kernel callbacks para observar lo que pasa en el endpoint. Creación de procesos, inyección de threads, carga de imágenes, modificación del registro. Son los ojos y oídos de todos los principales EDR del mercado. El presupuesto es que si el driver del EDR está cargado y sus callbacks registrados, el SOC tiene visibilidad. Pero ¿qué pasa cuando alguien simplemente elimina esos callbacks del kernel?
Este artículo recorre la técnica que presentamos en rootedPT 2026. No es teórica. La cadena de ataque funciona contra productos EDR desplegados actualmente, las herramientas están disponibles públicamente y el problema central lleva años conocido sin una corrección integral. Publicamos esto porque los defensores necesitan entender exactamente cuán frágil es su visibilidad y qué pueden hacer realmente al respecto.
Cómo los EDR ven realmente tus endpoints
Cuando un agente EDR instala su driver en una máquina Windows, no monitoriza cada system call directamente. Eso sería demasiado caro. En su lugar, registra rutinas de callback con el kernel de Windows. Estos callbacks son funciones que el kernel promete llamar cada vez que ocurren eventos específicos. Los más importantes:
- PspCreateProcessNotifyRoutine se dispara cada vez que un proceso se crea o termina. Así es como tu EDR sabe cuándo notepad.exe lanza cmd.exe.
- PspCreateThreadNotifyRoutine se dispara en la creación de threads. Así es como tu EDR detecta la remote thread injection, donde un proceso crea un thread dentro de otro.
- PspLoadImageNotifyRoutine se dispara cuando una DLL o EXE se carga en memoria. Así es como tu EDR ve cuándo una DLL sospechosa se inyecta en un proceso legítimo.
- CmCallbackList se dispara en operaciones de registro. Así es como tu EDR rastrea mecanismos de persistencia instalándose en el registro.
El kernel almacena estos callbacks en arrays fijos. PspCreateProcessNotifyRoutine, por ejemplo, es un array que puede contener hasta 64 entradas. Cuando se crea un proceso, el kernel recorre este array y llama a cada función registrada. El driver del EDR recibe el evento, lo inspecciona y decide si registrarlo, alertar o bloquearlo.
Esta arquitectura es eficiente y bien diseñada. También tiene una debilidad crítica: los arrays viven en memoria de kernel y son escribibles.
BYOVD: la cadena de ataque
Bring Your Own Vulnerable Driver (BYOVD) es exactamente lo que el nombre sugiere. El atacante carga un driver de kernel legítimamente firmado que contiene una vulnerabilidad conocida y luego explota esa vulnerabilidad para obtener capacidades arbitrarias de lectura y escritura en el kernel. Sin ningún zero-day. El driver es real, firmado por un vendor real y, en muchos casos, aún distribuido a través de Windows Update o de paquetes de software del fabricante.
La cadena corre en cinco pasos, todos desde user mode, sin privilegios especiales más allá de administrador local:
- Dejar caer el driver vulnerable. El atacante coloca en disco un fichero .sys conocido como vulnerable. Dell, ASRock, Gigabyte y otros han lanzado drivers que más tarde se revelaron con vulnerabilidades explotables. El fichero pasa la verificación de firma porque la firma es válida. Se suponía que estaba ahí.
- Cargar el driver. APIs estándar de creación de servicios Windows. El Service Control Manager lo acepta porque la firma es válida. El EDR ve un evento de carga de driver, comprueba la firma, ve el nombre de un vendor legítimo y sigue adelante.
- Explotar la vulnerabilidad. Abrir un handle al device object del driver y enviar un IOCTL manipulado. La vulnerabilidad dispara operaciones arbitrarias de lectura o escritura de memoria en kernel space. El atacante tiene ahora una primitiva de lectura/escritura para todo el espacio de direcciones del kernel, desde user mode.
- Localizar los arrays de callbacks. Con la primitiva de lectura de kernel, escanear la memoria del kernel en busca de los arrays de callbacks. Están en offsets fijos a partir de símbolos exportados del kernel. Los offsets varían por build de Windows pero se descubren de forma trivial mediante análisis inverso del ntoskrnl.exe. Herramientas como CallbackDb mantienen bases de datos de offsets actualizadas para cada build. Leer el contenido de los arrays y sabes exactamente qué está vigilando el EDR.
- Poner a cero los callbacks. Con la primitiva de escritura de kernel, sobrescribir cada puntero de función de callback con null (0x0000000000000000). El kernel sigue recorriendo el array cuando ocurren eventos, pero todas las entradas son null. Los callbacks nunca se disparan. El driver del EDR sigue cargado, su servicio sigue corriendo, el dashboard sigue en verde. Pero el kernel ya no le está diciendo nada.
En este punto, el atacante tiene total libertad para ejecutar técnicas en el endpoint. Inyección de procesos, volcado de credenciales, movimiento lateral. El EDR no verá nada de esto porque los kernel callbacks que habrían reportado estos eventos fueron silenciados.
Prueba: WinDbg antes y después

Lo demostramos en rootedPT con un WinDbg conectado a un kernel Windows en vivo. Antes del ataque, volcar PspCreateProcessNotifyRoutine muestra un array poblado. Se ven varios punteros de funciones, cada uno correspondiente a un callback registrado por un EDR o producto de seguridad. El array está activo y funcional.
Después del ataque, la misma región de memoria muestra todo ceros. Cada puntero de callback ha sido sobrescrito. El driver del EDR no es consciente de que su callback fue eliminado porque el propio driver no tiene mecanismo para verificar que su callback sigue en el array. Registró el callback al arrancar y asume que será llamado para siempre.

A continuación ejecutamos una serie de técnicas de ataque: inyección de procesos, volcado de credenciales vía acceso a LSASS y movimiento lateral vía PsExec. El EDR detectó cero de estas. Su consola no mostró alertas. Su árbol de procesos no mostró actividad sospechosa. El endpoint parecía completamente normal mientras teníamos acceso total.
La Laguna 1 está resuelta. ¿Y la Laguna 2?
Entonces los kernel callbacks están a cero. El mecanismo de detección primario del EDR está ciego. Pero los productos EDR modernos también tienen modelos de ML, motores de análisis conductual y sistemas de reputación en la nube. Incluso sin kernel callbacks, seguro que estos atraparían actividad sospechosa, ¿no?
Esta es la segunda laguna, y es independiente de la primera.
La detección por ML y conductual depende de recopilar telemetría sobre procesos, escrituras en ficheros, conexiones de red y cambios en el registro. Pero la calidad de esta telemetría importa enormemente. Si el atacante elabora su payload con cuidado, las señales conductuales parecen benignas:
- PE headers y metadata válidos. El payload tiene timestamps de compilación correctos, recursos de versión de aspecto legítimo y firmas digitales propias (certificados self-signed con nombres de organización creíbles). Los modelos de ML que dependen de análisis estático ven un ejecutable normal.
- Tabla de imports legítima. Las funciones importadas son APIs Windows estándar sin patrones sospechosos. Sin VirtualAllocEx, sin WriteProcessMemory, sin CreateRemoteThread. Las llamadas peligrosas se resuelven dinámicamente en runtime.
- Alineación con la baseline conductual. El perfil de comportamiento del payload coincide con herramientas administrativas legítimas. Corre desde directorios esperados, accede a recursos esperados y sigue patrones de ejecución esperados. Los modelos conductuales que marcan anomalías estadísticas no ven nada inusual.
- Manipulación de providers ETW. Muchos EDR complementan los kernel callbacks con providers de Event Tracing for Windows (ETW). Pero los providers ETW también son estructuras de kernel. Un atacante con una primitiva de escritura en kernel puede desactivar providers ETW específicos parcheando el registro de sus GUIDs de la misma forma que pone a cero los arrays de callbacks. El modelo de ML no recibe telemetría que analizar porque el pipeline que lo alimenta fue cortado en el origen.

La idea clave es que la Laguna 1 (ceguera de los kernel callbacks) y la Laguna 2 (bypass de ML/conductual) son independientes. Arreglar una no arregla la otra. Puedes hacer hardening de los kernel callbacks (hablamos del HVCI enseguida) y aun así tener a un atacante pasando de largo ante tu detección de ML. O puedes tener detección conductual perfecta y aun así perdértelo todo porque tus kernel callbacks fueron puestos a cero.
Este modelo de dos lagunas es lo que hace a los ataques BYOVD tan peligrosos en la práctica. Los defensores que se centran solo en blocklists de drivers tratan la Laguna 1 pero ignoran la Laguna 2. Los defensores que se centran solo en la detección conductual tratan la Laguna 2 pero ignoran la Laguna 1. Ambas lagunas hay que cerrarlas simultáneamente.
HVCI: la mitigación que debería funcionar
El Hypervisor-Protected Code Integrity (HVCI) usa el hipervisor de Windows para crear regiones de memoria aisladas. Las páginas de código y datos del kernel que no deben modificarse se colocan en memoria solo accesible desde el host Virtual Trust Level 0 (VTL 0), no desde el sistema operativo invitado. En teoría, esto significa que aunque un atacante tenga una primitiva de escritura en kernel, no puede modificar estructuras protegidas del kernel.
Microsoft ha posicionado el HVCI como la defensa primaria contra ataques a nivel de kernel, incluido BYOVD. Y en un despliegue HVCI totalmente hardened, funciona. Los arrays de callbacks quedan protegidos. El atacante no puede ponerlos a cero.
Pero el HVCI tiene tres superficies de bypass que importan operativamente:
Superficie de bypass 1: drivers firmados vulnerables
El HVCI restringe qué drivers pueden cargar según requisitos de code integrity. Pero los drivers firmados antes de que los requisitos del HVCI se endurecieran pueden seguir cargando a través de excepciones de compatibilidad. En nuestras pruebas, encontramos consistentemente drivers vulnerables que cargan sin problemas en sistemas con HVCI activado.
Superficie de bypass 2: ataques de detonación
Incluso cuando el HVCI protege directamente los arrays de callbacks, un atacante con una primitiva de escritura en kernel puede apuntar a otras estructuras de kernel no protegidas para lograr el mismo resultado. El HVCI no lo protege todo. Los propios arrays de callbacks pueden estar guardados, pero las estructuras dispatcher que los invocan, los registros de providers ETW que alimentan la telemetría y los callbacks del object manager que rastrean accesos a handles no están todos cubiertos. Un atacante que estudie qué estructuras están y no están protegidas puede redirigir el ataque por un camino desprotegido.
Superficie de bypass 3: la realidad de los despliegues
El HVCI exige soporte de hardware (virtualización nested en la CPU) y configuraciones de firmware específicas. En entornos empresariales, encontramos rutinariamente máquinas donde el HVCI está activado en la política pero no está realmente corriendo. Aplicaciones heredadas, drivers personalizados y hardware más antiguo impiden a menudo que el HVCI se active. Un porcentaje significativo de los endpoints que probamos en proyectos de EDR tiene el HVCI listado como activado en el dashboard de seguridad pero no está efectivamente protegido a nivel de hipervisor.
Caso de estudio: DsArk64
Durante nuestra presentación en rootedPT, recorrimos un ejemplo real que demuestra por qué las blocklists de drivers por sí solas son insuficientes. DsArk64 es un driver firmado con WHQL. La firma WHQL (Windows Hardware Quality Labs) es el nivel de confianza más alto para drivers Windows. Significa que Microsoft probó y aprobó el driver. Se distribuye junto con 360 Total Security, un producto de seguridad legítimo.

DsArk64 expone IOCTLs que proporcionan terminación de procesos y capacidades arbitrarias de lectura y escritura de memoria de kernel. Estas capacidades son intencionales. El driver fue construido para proporcionarlas. La firma es legítima porque el driver se presentó por los canales propios y pasó la validación de Microsoft.
Este es el problema de las blocklists reactivas. DsArk64 nunca se añadió a ninguna blocklist porque fue firmado mediante el proceso propio. Proporciona primitivas completas de lectura y escritura en kernel. Se distribuye con un producto de seguridad que los usuarios instalan intencionadamente. Un atacante que deja caer DsArk64 en una máquina objetivo está cargando un driver aprobado por Microsoft, firmado con un certificado WHQL y distribuido por canales legítimos.
La conclusión no es que la firma WHQL esté rota. Es que cualquier sistema que dependa de enumerar drivers malos siempre irá con retraso. Nuevos drivers vulnerables se descubren continuamente. Drivers legítimos con capacidades peligrosas existen en gran número.
Kernel Data Protection: la corrección que no está desplegada
Microsoft ha desarrollado una tecnología llamada Kernel Data Protection (KDP) que abordaría directamente el problema de poner los callbacks a cero. KDP usa el hipervisor para marcar estructuras específicas de datos del kernel como read-only, incluso para código en kernel mode. Si KDP se aplicara a los arrays de callbacks, la primitiva de escritura de un ataque BYOVD simplemente fallaría.
El problema es el despliegue. KDP existe en Windows, pero no está ampliamente activado para los arrays de callbacks en la práctica. Las razones son complejas: preocupaciones de rendimiento, requisitos de pruebas de compatibilidad y el hecho de que aplicar KDP a estructuras de kernel frecuentemente modificadas exige coordinación cuidadosa dentro del equipo del kernel de Windows. Hasta nuestras pruebas en 2026, los arrays de callbacks en sistemas Windows totalmente parcheados siguen siendo escribibles desde kernel mode.
Lo que los defensores deberían hacer realmente
La respuesta estándar de los vendors a BYOVD es "activa HVCI y actualiza la blocklist de drivers". Es correcta pero insuficiente. Esto es lo que recomendamos según lo que vemos en proyectos reales:
- Activa HVCI y verifica que realmente está corriendo. No confíes en el dashboard. Comprueba que el hipervisor está protegiendo activamente la memoria de kernel en tus endpoints. Encontramos una tasa de fallo del 20-30% en despliegues empresariales donde la política dice activado pero el hipervisor no está activo.
- Despliega Windows Defender Application Control (WDAC) con una política estricta. WDAC permite definir qué drivers tienen permiso para cargar en tus máquinas. Una política WDAC bien configurada es más eficaz que cualquier blocklist porque bloquea todo excepto lo que explícitamente permitas.
- Vigila eventos de carga de drivers, no solo drivers conocidos como malos. Alerta sobre cualquier carga nueva de driver fuera de tu baseline. Si una máquina de repente carga un driver de un vendor que no usas, eso es sospechoso independientemente de que esté o no en una blocklist.
- Asume que tu EDR puede quedar ciego y construye visibilidad secundaria. Los providers ETW (Event Tracing for Windows), Sysmon y los Windows Event Logs proporcionan fuentes de datos independientes. Si tu EDR queda ciego, estas fuentes pueden seguir capturando evidencia. Pero nota: los providers ETW también pueden desactivarse desde kernel mode, así que esto es una capa, no una garantía.
- Prueba tu EDR contra técnicas BYOVD. Ejecuta la cadena de ataque que describimos contra tus propios endpoints en una prueba controlada. Mira qué atrapa tu EDR y qué se le escapa. Los resultados suelen ser un baño de agua fría.
- Mapea tu cobertura de detección a MITRE ATT&CK. Mira específicamente T1068 (Exploitation for Privilege Escalation), T1569 (System Services) y T1543 (Create or Modify System Process). Si tus reglas de detección para estas técnicas dependen solo de kernel callbacks, fallarán durante un ataque BYOVD.
La verdad incómoda
El problema BYOVD no es nuevo. El abuso de drivers vulnerables está documentado desde al menos 2018. La manipulación de kernel callbacks se discute en círculos de seguridad ofensiva desde hace años. Las técnicas que presentamos en rootedPT están construidas sobre vulnerabilidades públicamente conocidas y internals de kernel públicamente documentados.
Lo que hace esto persistente es que la arquitectura fundamental no ha cambiado. Los EDR siguen dependiendo de kernel callbacks almacenados en arrays escribibles. La mitigación (KDP) existe pero no está desplegada a escala. La defensa (HVCI) funciona cuando está bien configurada, pero muchas veces no lo está. La tirita (blocklists de drivers) es siempre reactiva.
Para los defensores, el mensaje es directo: la visibilidad a nivel de kernel de tu EDR no está garantizada. Depende de estructuras de datos que pueden modificarse silenciosamente por cualquiera que consiga cargar un driver en tu máquina. Pon a prueba ese presupuesto con regularidad. Construye capas de detección que no dependan todas de la misma infraestructura frágil de kernel. Y cuando evalúes productos EDR, pregunta específicamente cómo manejan la eliminación de callbacks, no solo cómo detectan malware conocido.
Si quieres descubrir si tu EDR sobrevive a este ataque, lo probamos por ti. Ejecutamos la cadena BYOVD completa, puesta a cero de callbacks incluida, contra tus endpoints reales y te mostramos exactamente qué ve tu EDR y qué se le escapa. Habla con nosotros.