Sobre OFFCEPT
Construida por operadores que dedicaron años a entrar en redes antes de crear una empresa alrededor de ello.
Saber Más
← Volver
Investigación Técnica8 de agosto de 202615 min de lectura

BYOVD: Detección y Prevención en un Endpoint Windows 11 con Hardening

Escrito por 0xM4L · Investigación de Seguridad OFFCEPT

TL;DR

Probamos BYOVD contra un endpoint Windows 11 25H2 totalmente hardened con MDE y ASR en modo Block. Siete de veintiún drivers públicamente conocidos fueron detectados al escribirse en disco. Nueve cargaron limpiamente en el kernel y mataron todos los procesos PPL-protected de Defender. La cobertura de la blocklist va con meses de retraso respecto a la divulgación pública. El allow-listing con WDAC y la detección conductual son los únicos controles que cierran la brecha.

Bring Your Own Vulnerable Driver (BYOVD) sigue siendo una de las formas más fiables de que los atacantes consigan código corriendo en el kernel de Windows en 2026. En vez de encontrar un exploit de kernel fresco, el atacante trae un driver legítimamente firmado pero vulnerable, lo carga y abusa de su funcionalidad expuesta (normalmente vía IOCTLs) para leer y escribir memoria de kernel, terminar procesos protegidos, o cegar y desactivar las propias defensas del endpoint.

Este artículo recorre un lab hands-on donde probamos BYOVD contra una máquina Windows 11 totalmente gestionada y protegida por EDR, y muestra que incluso con los controles "Block Vulnerable Drivers" activados, un número significativo de drivers conocidos como vulnerables sigue cargando y corriendo. Terminamos con un conjunto de mitigaciones y defensas que realmente marcan la diferencia.

Aviso. Esta investigación se realizó en un lab aislado que poseemos y controlamos, con fines defensivos. No corras drivers vulnerables ni tooling que mata EDRs contra sistemas que no estás autorizado a probar.

Metodología

Agrupamos los drivers vulnerables en tres categorías según lo "conocidos" que son para los defensores:

  • Categoría 1: en blocklist + PoC público. Drivers ya presentes en blocklists públicas (la Vulnerable Driver Blocklist de Microsoft, LOLDrivers) con un exploit listo para usar publicado.
  • Categoría 2: en blocklist, sin PoC público. Drivers listados como vulnerables pero sin exploit turnkey; tienes que escribir el tuyo.
  • Categoría 3: no listados / desconocidos. Drivers vulnerables aún sin catalogar en ninguna parte. Zero-days: vulnerabilidad desconocida, driver desconocido, sin entrada en ninguna blocklist.

Para este lab usamos un fork del proyecto BYOVD de BlackSnufkin, un PoC en Rust que abusa de IOCTLs de driver para terminar procesos arbitrarios por PID desde kernel mode, incluyendo ~21 drivers vulnerables (Categoría 1), más un driver adicional de LOLDrivers sin exploit público (Categoría 2), y drivers descubiertos en software de Windows de terceros aún no listados en ninguna parte, para los que desarrollamos un PoC que abusa de un zero-day (Categoría 3). Este artículo se centra en la Categoría 1, porque es el caso que los defensores deberían estar mejor equipados para detener y, como veremos, a menudo no lo están.

Configuración del Lab

ComponenteDetalle
SOWindows 11 25H2
EDRMicrosoft Defender for Endpoint (MDE)
GestiónInscrito vía Microsoft Intune
PolíticasAttack Surface Reduction (ASR), Block Abuse of Exploited Vulnerable Signed Drivers

El endpoint está incorporado a MDE e inscrito vía Intune → Endpoint security → Attack surface reduction, usando el perfil de Attack Surface Reduction Rules. La regla específica es "Block abuse of exploited vulnerable signed drivers", configurada en Block. Esta es exactamente la configuración que desplegaría una organización consciente de la seguridad: un SO moderno, un EDR de primer nivel, gestión MDM, y el propio control anti-BYOVD del vendor activado.

Centro de administración de Microsoft Intune mostrando la regla ASR Block abuse of exploited vulnerable signed drivers configurada en Block

Parte 1: Detección on-write

Copiamos los 21 drivers de BlackSnufkin a disco bajo C:\drivers\BYOVD-main\. 7 drivers fueron marcados y puestos en cuarentena por MDE en el momento en que tocaron disco, detectados como VulnerableDriver:* (y uno como Trojan:Win64/KillAV):

  • Ksapi64-Killer
  • NSec-Killer
  • PoisonX-Killer
  • STProcessMonitor-Killer
  • TfSysMon-Killer
  • UnknownKiller
  • Viragt64-Killer
Seguridad de Windows mostrando detecciones VulnerableDriver y Trojan marcadas al escribirse en disco

Los 14 drivers restantes se quedaron en disco; Defender no los marcó al escribirse: AppRemover-Killer, Astra64-RW, BdApiUtil-Killer, CcProtect-Killer, EnPortv-Killer, GameDriverX64-Killer, GoFlyDrv-Killer, HWAudioOs2Ec-Killer, K7Terminator, MonProcessEX-Killer, PCTcore64-Killer, Wsftprm-Killer, Xhunter1-Killer, Xkpsm-Killer.

Conclusión: la detección on-write/on-access solo atrapó a un tercio de un conjunto de drivers de Categoría 1, públicamente conocidos. El resto depende de controles en tiempo de carga, que probamos a continuación.

Parte 2: Registrar e iniciar los drivers

Un driver de kernel solo se vuelve interesante una vez que se registra como servicio y se inicia. Usamos un pequeño wrapper en PowerShell alrededor de sc.exe para registrar cada .sys como servicio de kernel mode con inicio bajo demanda. Todos los servicios se crearon con éxito; registrar el servicio y escribir la clave HKLM\SYSTEM\CurrentControlSet\Services\<nombre> no está bloqueado en sí mismo.

PowerShell
#Requires -RunAsAdministrator
$SC = "$env:SystemRoot\System32\sc.exe"
$DriverRoot = 'C:\drivers\BYOVD-main'

Get-ChildItem -LiteralPath $DriverRoot -Filter *.sys -Recurse -File -Force |
ForEach-Object {
    $name = $_.BaseName
    $key = "HKLM:\SYSTEM\CurrentControlSet\Services\$name"
    if (Test-Path $key) {
        & $SC delete $name 2>&1 | Out-Null
        Remove-Item $key -Recurse -Force -ErrorAction SilentlyContinue
    }
    $out = & $SC create $name binPath= $_.FullName type= kernel start= demand
    if ($LASTEXITCODE -eq 0) {
        Write-Host "[+] $name -> $($_.FullName)" -ForegroundColor Cyan
    } else {
        Write-Warning "[-] $name : $($out -join ' ')"
    }
}
Editor de registro y PowerShell mostrando todos los drivers registrados como servicios de kernel bajo CurrentControlSet Services

La parte interesante es sc start, que dispara la carga real en el kernel. Aquí las protecciones por capas por fin entran en acción, pero solo para algunos drivers:

ResultadoSignificadoQué control lo detuvo
RUNNINGDriver cargado en el kernelNada lo detuvo
FAILED 577: Windows no puede verificar la firma digitalBloqueado por code-integrity / firmaDSE / WHQL
FAILED 0x800B010C: certificado explícitamente revocadoCertificado de firma revocadoRevocación de certificado
FAILED 5: Acceso denegadoBloqueado por la Vulnerable Driver Blocklist / ASRBlocklist
FAILED 31 / 183Error de init de dispositivo/driver (no es un bloqueo de seguridad)n/a

Un driver incluso mostró un mensaje explícito: PCTcore64.sys: A security setting is detecting this as a vulnerable driver and blocking it from loading. You will need to adjust your settings to load this driver.

A pesar de tener todas las protecciones activadas, 9 drivers conocidos como vulnerables alcanzaron el estado RUNNING y quedaron vivos en el kernel: ardrv, ASTRA64, CcProtect, EnPortv, GoFly64, HWAudioOs2Ec_1, MonProcessEX, STProcessMonitor_v114, xkpsm. No son drivers oscuros. La mayoría estaba catalogada en LOLDrivers meses antes de esta prueba. La entrada más antigua se publicó en marzo de 2026; a 8 de agosto de 2026, casi cinco meses después, siguen cargando y corriendo en una máquina totalmente parcheada y con políticas hardened. Ese es el hallazgo central: la cobertura de la blocklist va por detrás de la divulgación pública, y la brecha se mide en meses.

Parte 3: Abusar de un driver cargado para matar Defender

Para demostrar que un driver que "sigue cargando" no es un problema teórico, tomamos uno de los drivers en ejecución (CcProtect.sys) y usamos el PoC de BYOVD para terminar procesos protegidos desde el kernel. El PoC abre el device object del driver (\\.\CcProtect) y envía el IOCTL 0x222024 con el nombre de un proceso objetivo; el driver, corriendo en kernel mode, termina el PID correspondiente, saltándose la protección de user mode (PPL) que normalmente blinda estos procesos.

Lo apuntamos directamente a todo el stack de Defender / MDE:

  • MsMpEng.exe - Motor del antivirus Defender
  • MpDefenderCoreService.exe - Servicio core de Defender
  • SecurityHealthService.exe
  • NisSrv.exe - Servicio de inspección de red
  • MsSense.exe, SenseIR.exe, SenseTVM.exe, SenseNdr.exe - Componentes del sensor MDE
Process Explorer y terminal mostrando CcProtect-Killer matando con éxito todos los procesos PPL-protected de Defender

Todos corren como Protected Processes (PsProtectedSignerAntimalware-Light / PsProtectedSignerWindows-Light). Los kills tienen éxito. Una herramienta de user mode nunca podría hacer esto a un proceso antimalware protegido con PPL, pero un driver de kernel sí.

Una salvedad sobre persistencia: Defender tiene self-healing. Los servicios antimalware dirigidos por MpDefenderCoreService acaban relanzándose. Para mantener el endpoint ciego, un atacante tiene que re-matar los procesos continuamente o encadenar una persistencia completa de SYSTEM/kernel para detener y eliminar los servicios directamente. En cualquier caso, el punto se mantiene: BYOVD es una amenaza real y actual para la seguridad del endpoint, incluso con antimalware y EDR instalados y configurados.

Reglas de detección custom en Microsoft Defender XDR

Dado que la blocklist integrada no ve drivers desconocidos o aún firmados, podemos cerrar parte de la brecha con una regla de detección custom en Microsoft Defender XDR que alerte sobre cualquier registro nuevo de driver de kernel, vulnerable o no. Un enfoque ingenuo vigilaría sc.exe create ... type= kernel, pero eso se salta de forma trivial: un atacante puede registrar el driver directamente vía la API del Service Control Manager, vía NtLoadDriver, o con syscalls indirectas, y ninguna de esas toca sc.exe. Filtrar por paths sospechosos de ficheros es igual de débil.

El chokepoint robusto es el registro. Todas esas técnicas (incluida NtLoadDriver) siguen exigiendo una clave de servicio bajo ...\CurrentControlSet\Services\<nombre> con un ImagePath apuntando al .sys. Detectamos esa escritura en cualquier path y aplicamos un modelo default-deny: alertar sobre cada registro de driver de kernel excepto los que estén en una baseline known-good mantenida.

KQL
// Alerta sobre CUALQUIER registro nuevo de servicio de driver de kernel,
// independientemente de la herramienta o el path.
// La escritura en Services\<name>\ImagePath es el invariante por el que sc.exe,
// la API del SCM y NtLoadDriver pasan todos.
DeviceRegistryEvents
| where ActionType in ("RegistryValueSet", "RegistryKeyCreated")
| where RegistryKey has @"\CurrentControlSet\Services\"
| where RegistryValueName == "ImagePath" and RegistryValueData endswith ".sys"
// default-deny: conserva solo lo que NO está en tu baseline aprobada.
// Mantén KnownGoodDrivers como watchlist, idealmente indexada por hash/firmante y no por path.
| where RegistryValueData !in~ (KnownGoodDrivers)
| project Timestamp, DeviceName, RegistryKey, RegistryValueData,
    InitiatingProcessFileName, InitiatingProcessCommandLine,
    InitiatingProcessAccountName

Guárdala como regla de detección custom en Advanced Hunting; configura la frecuencia, la severidad y las entidades de máquina/fichero a mapear para que un evento que coincida levante una alerta y, opcionalmente, dispare una respuesta automatizada. Un registro que apunte fuera de \Windows\System32\drivers\ merece una severidad más alta.

Mitigaciones y defensas

Ningún control único detiene BYOVD; hace falta defence-in-depth. Aproximadamente por orden de impacto:

  • 1. Aplica la Microsoft Vulnerable Driver Blocklist, y no confíes solo en ella. Actívala (viene activada con HVCI/SAC en Windows moderno), pero trátala como necesaria-pero-insuficiente. Como se muestra arriba, la blocklist va con meses de retraso respecto a la divulgación pública y aquí dejó pasar 9 de 21 drivers bien conocidos.
  • 2. Activa VBS, HVCI/Memory Integrity y Device Guard. Hypervisor-Enforced Code Integrity (HVCI) corre la code integrity de kernel mode dentro de un entorno aislado por VBS y fuerza la validación de firma y las comprobaciones de revocación de certificado en tiempo de carga. Este es el paso de hardening de plataforma más valioso de todos. Despliégalo primero en un anillo de pruebas; drivers incompatibles pueden causar fallos de arranque.
  • 3. Pasa a una allow-list con App Control for Business (WDAC). En vez de bloquear lo conocido como malo, permite solo lo conocido como bueno: whiteliste publishers, firmantes y hashes específicos de drivers. Es el único enfoque que también aborda los drivers de Categoría 3 (desconocidos/zero-day), porque un driver no listado se deniega por defecto.
  • 4. Exige requisitos modernos de firma de drivers (EV / WHQL) y bloquea los drivers heredados. Muchos drivers abusados son binarios antiguos con cross-signing. Exigir firma moderna cierra un gran trozo del catálogo de Categoría 1/2.
  • 5. Restringe quién puede registrar y cargar drivers. Cargar un driver exige admin local / SeLoadDriverPrivilege. Aplica least privilege y JIT/JEA para el personal de IT.
  • 6. Audita y elimina drivers de terceros arriesgados. Los anti-cheat de gaming, las utilidades de overclocking de GPU/CPU y las viejas herramientas de información de sistema de vendors son reincidentes en endpoints de producción. Parchea o prohíbe el software que incluye versiones de driver conocidas como vulnerables.
  • 7. Mantén al día firmas, motor y blocklist. Asegúrate de que la protección cloud de MDE y la blocklist de drivers se auto-actualizan. Una blocklist obsoleta es exactamente el modo de fallo ilustrado arriba.
  • 8. Mantén ASR en modo Block. Usa primero Audit para construir la baseline, luego pasa a Block para "Block abuse of exploited vulnerable signed drivers" y combínalo con el conjunto amplio de reglas ASR.
  • 9. Vigila el comportamiento, no solo el binario. Sysmon Event ID 6 (carga de driver) correlacionando hash, estado de firma y path; Event ID 7045 (nuevo servicio instalado); escrituras de registro de nuevos servicios de kernel; eventos de bloqueo WDAC (3023 / 3033). Alerta sobre cargas desde paths escribibles por el usuario (\AppData\, \Temp\, \ProgramData\) y cruza los hashes contra loldrivers.io.
  • 10. Vigila el impacto. Peticiones IOCTL anómalas a un device object recién cargado, eliminación de callbacks de kernel y terminación de procesos PPL/antimalware iniciada desde el kernel son señales de alta fidelidad de que un kill ya está en curso. Configura alertamiento inmediato sobre terminación de procesos de seguridad y huecos de heartbeat del sensor en el portal de MDE.
  • 11. Valida continuamente y planifica el fallo. Asume que algún driver conseguirá pasar. Corre simulaciones de BYOVD y ejercicios de red team, aísla hosts con actividad de kernel sospechosa y asegúrate de que los planes de backup y recuperación contemplan un escenario donde la prevención falló.

Dónde fallan las blocklists

El tema consistente es que bloquear por reputación es siempre reactivo. Un driver tiene que ser descubierto, analizado, catalogado y empujado a la blocklist antes de ser detenido, y cada día de esa ventana carga limpiamente. Los drivers de Categoría 2 y 3 nunca entran en esa ventana. Así se comportan los controles ante el caso más difícil: un driver vulnerable firmado válidamente pero desconocido (Categoría 3 / zero-day):

Control¿Detiene un driver vulnerable firmado y desconocido?Por qué
Vulnerable Driver BlocklistNoEl driver desconocido no está en ninguna lista
HVCI / Memory IntegrityNoEstá firmado válidamente, así que carga; los ataques de lectura/escritura de kernel data-only nunca introducen código ejecutable nuevo que HVCI pueda atrapar
WDAC / App Control allow-listDefault-deny: un driver no aprobado explícitamente nunca carga, sea conocido como malo o no
Detección conductual de carga de driversDetectaMarca la carga de cualquier driver fuera de la baseline, más la actividad IOCTL anómala / eliminación de callbacks tras la carga

Los controles de firma y reputación son estructuralmente ciegos ante un driver desconocido-pero-firmado. Solo la autorización de carga (allow-listing) y la detección conductual lo abordan, e incluso el allow-listing falla si el driver vulnerable es uno que aprobaste legítimamente, dejando la detección conductual del impacto (kills PPL inesperados, eliminación de callbacks, IOCTLs sospechosos) como última línea.

Por eso la respuesta más duradera es detectar y controlar el acto de cargar un driver, vulnerable o no, en vez de comparar contra una lista de malos. En la próxima parte de esta serie profundizamos exactamente en eso: customizar la lógica de detección de EDR/XDR (Defender Advanced Hunting KQL y queries análogas de Elastic) más el allow-listing con WDAC, para sacar a la superficie cualquier evento de carga de driver y decidir sobre él por política, cerrando la brecha que las defensas BYOVD basadas en firmas y blocklists dejan abierta.

Referencias