Skip to content

Patch Diffing CVE-2026-41089: Localizando el Bug de Netlogon en 4 Horas Sin PoC Pública

Walkthrough completo de cómo hacer bindiff a un CVE de Patch Tuesday Windows — desde adquirir el MSU hasta identificar la función vulnerable. CVE-2026-41089 (Netlogon pre-auth RCE) como ejemplo. Metodología, herramientas y los límites honestos del desarrollo de trigger sin semanas de exploit engineering.

Yeray Martín
Yeray Martín · 21 min de lectura

Nueve días después de que Microsoft publicara CVE-2026-41089 — un stack buffer overflow crítico pre-autenticación en el servicio Netlogon, CVSS 9.8, wormable, RCE en cualquier domain controller sin parchear — todavía no había PoC pública, ni writeup técnico, ni identificación a nivel de función del bug. El advisory de Microsoft lo describía como un stack-based buffer overflow durante el authentication handshake. Eso es un resumen de marketing, no información técnica. Queríamos saber exactamente qué función de netlogon.dll parcheó Microsoft y cómo se veía el bug a nivel de código. Este post recorre cómo localizamos la función vulnerable en unas cuatro horas de binary diffing metódico — desde adquirir la DLL parcheada hasta identificar el overflow exacto de 2 bytes en el terminator — y dónde estaba el muro cuando intentamos convertir ese hallazgo en un trigger reproducible contra un DC sin parchear.

MITRE ATT&CK: Técnica pre-ataque. La vulnerabilidad permite ejecución remota de código contra un domain controller sin autenticación previa, similar en impacto a CVE-2020-1472 Zerologon pero distinta en mecanismo (stack BoF vs fallo de lógica criptográfica).

¿Por qué hacer bindiff a un parche de Microsoft en lugar de esperar una PoC pública?

Las PoCs públicas para CVEs de Windows de alta severidad típicamente aparecen entre 3 y 12 semanas después del Patch Tuesday — y a veces nunca, cuando el bug es lo suficientemente sutil como para que ningún investigador independiente invierta el tiempo en reproducirlo. CVE-2026-41089 encaja exactamente en ese perfil: actores APT empezaron a explotarlo en el wild el día siguiente a la publicación (según telemetría de CrowdStrike), pero la comunidad pública de investigación en seguridad no había producido nada técnico al día nueve. Para un defensor o pentester que necesita demostrar la presencia de la vulnerabilidad a un cliente hoy, esperar a que alguien publique una PoC no es un workflow. Bindiff sí lo es.

El principio es simple. Microsoft solo cambia lo necesario. Cuando se publica un parche de seguridad, el binario modificado difiere del binario pre-parche en un conjunto pequeño y específico de funciones — típicamente 5 a 30 funciones en una DLL entera con miles. Comparar esos dos binarios función por función revela el code path vulnerable con precisión quirúrgica. Con símbolos públicos de debug disponibles desde el symbol server de Microsoft, el diff devuelve nombres reales de funciones como NetpLogonPutUnicodeString en lugar de FUN_180047770. A partir de ahí, identificar la bug class y trazar el reach del atacante es mayormente leer decompilación en C lado a lado.

¿Cómo es el workflow completo de bindiff para CVE-2026-41089?

El workflow completo es: adquirir versiones pre-parche y post-parche de netlogon.dll, cargar ambas en Ghidra con símbolos PDB del symbol server público de Microsoft, ejecutar ghidriff para identificar todas las funciones modificadas y producir diffs de decompilación side-by-side, y luego leer los diffs buscando los candidatos obvios — helpers de copia de strings, builders de paquetes de red y entry points pre-autenticación.

El cuello de botella en este workflow rara vez es el diff en sí. Es adquirir la DLL post-parche. Microsoft distribuye los cumulative updates como paquetes .msu, que son contenedores CAB-wrapped de CBS deltas — parches binarios incrementales que no son directamente aplicables con msdelta.dll sobre un baseline suficientemente antiguo. Concretamente: intentar instalar KB5087538 (el cumulative de mayo 2026 para Server 2019) en un sistema Server 2019 build 17763.1935 (febrero 2020) falla con 0x80240017 WU_E_NOT_APPLICABLE porque el baseline tiene seis años de antigüedad. dism /Online /Add-Package falla igual. El forward delta PA30 en f/netlogon.dll no se aplica con msdelta.dll stock porque está envuelto en CBS, no en formato msdelta raw.

El workaround práctico es extraer netlogon.dll desde una máquina Windows que ya está en un baseline reciente. Cualquier Windows 11 24H2 que haya aplicado el cumulative de mayo 2026 (KB5089549, OS build 26100.8457) tiene la DLL post-parche en C:\Windows\System32\netlogon.dll. La misma DLL se comparte estructuralmente con las versiones de Server 2019 y Server 2022 de la función — el fix del bug es idéntico entre builds — así que una DLL de workstation sirve perfectamente para el diff. La DLL pre-parche viene del mismo Windows antes de aplicar el parche, o desde cualquier domain controller sin parchear de un lab vía SMB:

nxc smb <DC-IP> -u administrator -H <NT_HASH> -d <dominio> \
    --get-file 'C:\\Windows\\System32\\netlogon.dll' netlogon_prepatch.dll

Con ambas DLLs en disco, el resto es un comando.

¿Cómo se ejecuta un binary diff entre dos DLLs de Windows en Ghidra?

La herramienta de elección en 2026 para patch diffing basado en Ghidra es ghidriff — un wrapper de línea de comandos PyGhidra-native sobre el motor de Version Tracking de Ghidra que produce un reporte Markdown, diffs HTML side-by-side y un output JSON estructurado en una sola invocación. Resuelve automáticamente los símbolos PDB desde el symbol server público de Microsoft, ejecuta análisis Ghidra sobre ambos binarios, aplica una cadena de correlators (exact byte match, exact instruction hash, BSIM, heurísticas de calling/called) y escribe un reporte ordenado de funciones añadidas, eliminadas y modificadas.

La instalación es una línea, asumiendo que Ghidra 12.x con PyGhidra habilitado ya está disponible:

export GHIDRA_INSTALL_DIR="$HOME/tools/ghidra/ghidra_12.1_PUBLIC"
pip install --user ghidriff

Después el diff en sí:

ghidriff netlogon_prepatch.dll netlogon_postpatch.dll \
    --engine VersionTrackingDiff --sxs --output-path ./ghidriff_out

End to end, incluyendo el análisis Ghidra de ambas DLLs con símbolos PDB, el run tarda entre 5 y 10 minutos en un portátil moderno. El reporte de output para CVE-2026-41089 fueron 447KB de Markdown más diffs HTML side-by-side por función para las funciones más interesantes. La sección Diff Stats al inicio del reporte es lo primero que hay que leer:

added_funcs_len: 5
deleted_funcs_len: 0
modified_funcs_len: 20
matched_funcs_no_changes_len: 4471
match_func_similarity_percent: 99.5547%

Cuatro mil cuatrocientas noventa y seis funciones totales en netlogon.dll. Veinte modificadas. Cinco nuevas. Cero eliminadas. Match rate 99.89%. Esa es la signature típica de un único parche de seguridad dirigido — Microsoft no refactorizó nada, añadió validación con bounds en un cluster pequeño de funciones y lo distribuyó.

¿Qué función parcheó Microsoft realmente?

Leyendo el reporte de arriba abajo, ordenado por magnitud del diff, los candidatos emergen inmediatamente. La longitud de la sección de diff por función es un proxy fiable de cuánto código cambió Microsoft realmente. Para CVE-2026-41089 las entradas top fueron:

FunciónTamaño diff¿Reach pre-auth?
NlGetLocalPingResponse837 líneasSí — handler de DC discovery
BuildSamLogonResponse369 líneasSí — encadenado desde arriba
NetpDcBuildPing354 líneasSí — encadenado desde arriba
PrimaryQueryHandler243 líneas
NetpLogonPutUnicodeString200 líneasHelper
NetpLogonPutBytes190 líneasHelper

La familia Authenticate3 / ReqChallenge / PasswordSet2 — a la que apuntaba la mayoría de la especulación temprana, porque el advisory de Microsoft hablaba del "authentication handshake" — no mostró ningún cambio. El bug no está en el handshake NRPC. Está en el code path de DC discovery, que Microsoft sirve vía CLDAP UDP/389 y SMB mailslot. Ese call path aterriza en NlGetLocalPingResponse, que llama a NetpDcBuildPing para construir el paquete NETLOGON_SAM_LOGON_RESPONSE_EX, que a su vez llama a NetpLogonPutUnicodeString y NetpLogonPutBytes para serializar strings attacker-controlled en un buffer de respuesta de tamaño fijo en el stack.

Las dos funciones helper son donde vive el bug. El diff side-by-side de NetpLogonPutBytes es la pistola humeante. En la versión pre-parche, la función es un loop de copia de bytes raw de 17 líneas sin upper bound en el destination buffer:

// PRE-patch NetpLogonPutBytes
void NetpLogonPutBytes(undefined1 *param_1, int param_2, longlong *param_3) {
    do {
        puVar2 = (undefined1 *)*param_3;
        uVar1 = *param_1;
        param_1 = param_1 + 1;
        *puVar2 = uVar1;
        *param_3 = (longlong)(puVar2 + 1);
        param_2 = param_2 + -1;
    } while (param_2 != 0);  // copia param_2 bytes, punto
    return;
}

En la DLL post-parche, la misma dirección ahora contiene una función renombrada a NetpLogonPutUnicodeStringOld — Microsoft marcó la versión insegura como deprecated añadiendo el sufijo Old a su símbolo y añadió un safe path separado bounded vía RtlStringCbCopyExW. El helper inseguro ya no se llama desde el main path; en su lugar, un Feature flag (Feature_740537659__private_IsEnabledDeviceUsageNoInline) gatea el safe path con status return values y bounds checks correctos en cada paso.

El helper compañero NetpLogonPutUnicodeString lleva un bug más sutil. En la versión pre-parche, la función limita correctamente el loop de copia wide-character usando un parámetro count, pero escribe un terminator L'\0' de 2 bytes después del loop sin chequear si el destination tiene espacio para él:

// PRE-patch NetpLogonPutUnicodeString — abreviado
do {
    if (iVar4 == 0) break;          // bound check sobre count
    *local_res8 = wVar1;
    local_res8 = local_res8 + 1;
    wVar1 = *(wchar_t *)((longlong)local_res8 + lVar3);
} while (wVar1 != L'\0');
*local_res8 = L'\0';                  // escritura de 2 bytes más allá del bound
*param_3 = (ulonglong)(local_res8 + 1);

Cuando BuildSamLogonResponse llama a este helper repetidamente para serializar los campos de la respuesta, el destino no es el heap. Es un buffer wide-character de tamaño fijo en el stack dentro de NlGetLocalPingResponse, con el stack cookie justo detrás — el layout clásico al que Microsoft asignó CWE-121 (stack-based buffer overflow). Cada llamada al helper avanza un cursor compartido y escribe su terminator L'\0' de 2 bytes después de su copia bounded. El helper post-parche devuelve STATUS_INVALID_PARAMETER (0x57) cuando el payload excedería el buffer disponible, eliminando la escritura del terminator unbounded por completo. (Nuestra lectura inicial asumió una allocation en heap; el análisis dinámico posterior sobre el target lo corrigió a un buffer de stack — la distinción importa, porque significa que el target del overflow es el stack cookie, no metadata del heap.)

¿Se puede alcanzar el code path vulnerable remotamente sin autenticación?

Sí. La función NlGetLocalPingResponse se ejecuta por cada CLDAP NetLogon ping request (UDP/389) y cada SMB mailslot logon request (UDP/138 + \MAILSLOT\NET\NETLOGON). Ambos protocolos son primitivas pre-autenticación de discovery — un cliente domain-joined los usa para localizar un domain controller para su dominio antes de tener ninguna credencial. No hay gate de autenticación delante de NlGetLocalPingResponse, solo un check de early-rejection que el dominio solicitado coincida con uno que sirve el DC.

Confirmar el reach experimentalmente es directo. En el DC objetivo, habilita Netlogon verbose tracing:

New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters" `
    -Name DBFlag -Value 0x2080FFFF -PropertyType DWord -Force
Restart-Service Netlogon -Force

Después envía un CLDAP NetLogon ping desde cualquier host no autenticado con un marcador reconocible en el filtro:

LDAPMessage searchRequest baseObject="" filter=(&
    (DnsDomain=essos.local)
    (Host=MARKER_ATTACKER_STRING_HERE)
    (NtVer=\x01\x00\x00\x00))
attributes=["Netlogon"]

En milisegundos, %WINDIR%\Debug\netlogon.log contiene entradas probando que el request llegó al handler:

[MAILSLOT] Received ping from MARKER_ATTACKER_STRING_HERE((null)) essos.local (null) on UDP LDAP
[MAILSLOT] ESSOS: Ping response 'Sam Logon Response Ex' (null) to \\MARKER_ATTACKER_STRING_HERE Site: Default-First-Site-Name on UDP LDAP

Dos refinamientos de la fase de análisis dinámico merecen mención, porque corrigen lo que la lectura estática temprana implicaba. Primero, el valor NtVer selecciona el builder de la respuesta. NtVer=V5 (\x06\x00\x00\x00) enruta a BuildSamLogonResponseEx, que nunca llama al NetpLogonPutUnicodeString vulnerable; solo NtVer=V1 (\x01\x00\x00\x00) alcanza el BuildSamLogonResponse legacy que sí lo hace. Miles de iteraciones de fuzzing que usaron el valor moderno V5 ejercitaron el builder equivocado por completo. Segundo, el valor Host mostrado arriba solo alimenta la rutina de logging (NlPrintRoutine), no la copia vulnerable — los bytes influenciados por el atacante que de verdad aterrizan en la escritura bounded del helper vienen del filter attribute User. El bug es genuinamente reachable pre-autenticación desde cualquier host que pueda enrutar un paquete UDP al puerto 389, pero alcanzar la escritura vulnerable en concreto requiere el path V1.

¿Por qué un fuzz CLDAP simple no crashea el DC sin parchear?

Aquí es donde se ven los límites honestos del patch diffing. Enviamos más de once mil mutaciones CLDAP y NRPC contra un domain controller Server 2016 sin parchear — strings de longitudes boundary, runs de spam repetido, combinaciones de integer-overflow entre los campos iSockaddrLength y EntryCount, y llamadas NRPC directas a variantes DsrGetDcName con parámetros crafted. Sysinternals procdump estuvo attached a lsass.exe durante todo el run como tripwire. El DC nunca crasheó. El único crash de lsass que sí llegamos a producir resultó ser un artefacto de la instrumentación del debugger — un dereference de memoria dentro de un comando de breakpoint que habíamos puesto, no un trigger del CVE — lo cual es en sí mismo una lección sobre confirmar qué causó realmente un crash antes de proclamar una PoC.

La primera razón por la que el fuzzing naive falló fue el hecho del builder-routing de arriba: esencialmente todas esas mutaciones tempranas llevaban NtVer=V5, así que las servía BuildSamLogonResponseEx y nunca tocaban el helper vulnerable. Forzar NtVer=V1 y trazar con WinDbg/cdb en el target finalmente metió los bytes controlados por el atacante (el campo User) en NetpLogonPutUnicodeString — pero aun así no crasheó, y la medición dinámica explicó por qué.

El destino es un buffer wide-character de stack de tamaño fijo de unos 264 caracteres, con el stack cookie justo detrás. El builder de la respuesta llena ese buffer desde varias fuentes: el propio DNS host name del DC, el dominio NetBIOS y (en una rama) sus nombres de forest/domain/host, además del campo controlado por el atacante. En un domain controller con nombre por defecto, la escritura acumulada a través de todas esas fuentes cae muy por debajo del final del buffer — en nuestras mediciones, alrededor de dos tercios del camino — así que la porción del atacante nunca alcanza el cookie. Los bytes que el atacante controla están bounded; los bytes que empujarían el cursor por encima del borde son los nombres del propio servidor, que el atacante no controla. Concretamente, el propio DNS domain name del DC tiene que ser inusualmente largo — del orden de 50 o más caracteres — antes de que las escrituras del lado servidor por sí solas lleven el cursor hasta el stack cookie. Un domain name de unos 54 caracteres basta para desbordar un par de bytes; un nombre ordinario como corp.local desborda cero. Esa precondición es la razón entera por la que el bug tiene rating "Exploitation Less Likely": prácticamente ningún domain controller de producción se llama así, de modo que el campo controlado por el atacante nunca alcanza el cookie por sí mismo.

En otras palabras: localizar el bug en netlogon.dll llevó aproximadamente cuatro horas de trabajo de bindiff. Confirmar el reach, el routing del builder, el buffer exacto y el campo de input llevó varios días más de análisis dinámico — y al final de eso, un trigger fiable sin autenticación contra un DC configurado por defecto seguía fuera de alcance dentro de nuestro timebox. Engineering un exploit weaponizado es un proyecto separado medido en semanas, que es exactamente el gap que los operadores APT cierran internamente y la razón por la que sus exploits funcionales no aparecen en público durante meses. Elegimos parar aquí y no publicar un trigger, porque no lo tenemos — y en un CVE wormable activamente explotado, el deliverable responsable es guía de detección, no una ventaja hacia un crash.

¿La PoC pública de CVE-2026-41089 funciona de verdad?

Respuesta corta: las PoC que han aparecido públicamente no crashean un domain controller sin parchear que tenga un domain name ordinario, pese a afirmar que sí. Hay dos motivos concretos, ambos alineados con el análisis de arriba. Primero, el código que circula envía su CLDAP ping con un valor NtVer que tiene el bit V5EX puesto — que enruta al builder seguro BuildSamLogonResponseEx y nunca llega al NetpLogonPutUnicodeString vulnerable. Alcanzar el BuildSamLogonResponse legacy requiere el bit V5EX limpio. Segundo, los scripts asumen que un username de 130 caracteres es suficiente por sí solo, ignorando la precondición del dominio largo: con un domain name normal el campo acotado del atacante no puede alcanzar el cookie por mucha longitud que tenga. Probamos la PoC pública contra domain controllers Server 2016 y Server 2019 vulnerables-por-build con domain names ordinarios — no produjo ningún crash, y las comprobaciones out-of-band (boot time, proceso LSASS, crash dumps) confirmaron que no pasó nada. El "éxito" de la PoC se infiere de un timeout del recv UDP, que un solo paquete perdido dispara en un DC perfectamente sano. La lección es la que también nos mordió a nosotros: confirma un crash por un WER dump de stack cookie (0xc0000409 / STATUS_STACK_BUFFER_OVERRUN), nunca por la ausencia de respuesta.

¿Qué significa este CVE operacionalmente para entornos AD hoy?

Significa que cada domain controller corriendo un build sin parchear de Windows Server 2012 R2, 2016, 2019, 2022, 2022 23H2 o 2025 está expuesto a un vector de ejecución remota de código pre-autenticación que está siendo explotado activamente por threat actors sofisticados en el wild. El parche es directo de desplegar — cada SKU de Server afectado tiene un cumulative de Microsoft publicado — pero la realidad operacional es que los domain controllers no se parchean en la misma cadencia que las workstations. Muchos DCs corren en ciclos de parches trimestrales, y algunos en ciclos anuales, particularmente en entornos con dependencias de replicación o trust que los defensores son reacios a perturbar.

¿Cómo se detecta si un domain controller es vulnerable a CVE-2026-41089?

Detectar CVE-2026-41089 es un check de versión, no un check de explotación. Una PoC funcional no es necesaria para validar la exposición: cualquier domain controller reportando un OS build menor que el threshold parcheado para su Server SKU es vulnerable. Solo los domain controllers están afectados, porque el code path vulnerable vive en el handler del NetLogon ping del DC. Los builds parcheados son:

SKUPrimer build parcheado
Windows Server 2012 R26.3.9600.23132 (KB5082126)
Windows Server 201610.0.14393.9140 (KB5082198)
Windows Server 201910.0.17763.8755 (KB5087538)
Windows Server 202210.0.20348.5074
Windows Server 2022 23H210.0.25398.2330
Windows Server 202510.0.26100.32772

Leer el build de un DC remoto requiere acceso autenticado. El campo OS version devuelto por SMB negotiate da solo el major build number (14393, 17763, 26100) sin el patch-level UBR (9060, 8755, 32772). Hay dos formas precisas de obtener el patch level, ambas requieren admin en el DC: leer la versión de archivo de C:\Windows\System32\netlogon.dll por SMB (\\DC\C$), o leer HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion vía remote registry. La lectura de versión de archivo es la más fiable de las dos, porque mide exactamente el binario que ejecuta el código vulnerable; el UBR del registro es el fallback cuando C$ no es alcanzable. En cualquier caso, cualquier engagement que alcance local admin o domain admin en un DC puede producir un veredicto definitivo vulnerable-o-no por DC en segundos.

¿Por qué no hay un check seguro sin autenticación como Zerologon?

Esta es la pregunta que sorprende a la mayoría de defensores. El NetLogon ping que alcanza el código vulnerable es sin autenticación — cualquiera que pueda enrutar un paquete UDP al DC puede enviarlo. Entonces, ¿por qué detectar CVE-2026-41089 sigue requiriendo credenciales de admin, cuando CVE-2020-1472 Zerologon se puede chequear sin credenciales en absoluto?

La respuesta es si la vulnerabilidad produce una señal no destructiva. Las estrategias de detección caen en dos familias. La detección basada en versión lee la versión de archivo o build parcheado y compara — siempre segura, pero necesita acceso de lectura privilegiado. La detección por comportamiento ejercita el code path vulnerable de forma no destructiva y observa una respuesta reveladora — puede ser sin autenticación, pero solo cuando la vulnerabilidad produce una señal observable distinta del daño en sí.

Zerologon tiene ese observable. Su tester envía un NetrServerAuthenticate3 con un challenge todo a ceros unas 256 veces y observa si el DC acepta la autenticación — una señal que aparece antes del reset destructivo de la password de la cuenta máquina, así que el tester se detiene ahí. El check remoto de PrintNightmare (CVE-2021-34527) es similar en espíritu: confirma que la interfaz RPC del Print Spooler (\pipe\spoolss) es alcanzable, lo que necesita cualquier usuario autenticado pero no elevación.

CVE-2026-41089 no tiene esa señal intermedia. Un DC parcheado y uno sin parchear toman el code path legacy idéntico a través de BuildSamLogonResponse; la única diferencia es el bound check dentro del helper. El único observable de vulnerabilidad es el crash en sí — un overrun del stack cookie (STATUS_STACK_BUFFER_OVERRUN) que tumba lsass y reinicia el DC. Eso es una denegación de servicio destructiva, no un probe seguro, y depende de las condiciones de trigger poco fiables descritas arriba. No hay forma de distinguir parcheado de no parcheado por la red sin acceso de versión privilegiado o tumbar el DC.

Familia de detecciónCVE-2020-1472 ZerologonCVE-2021-34527 PrintNightmareCVE-2026-41089 Netlogon BoF
Check seguro sin autenticaciónSí (observable de auth-bypass)Solo alcanzabilidadNo
Credenciales necesariasNingunaCualquier usuario (low-priv)Local/Domain Admin en el DC
Qué se leeRespuesta de protocoloBinding del pipe RPCVersión de netlogon.dll / UBR del OS
Por quéSeñal de aceptación no destructivaSeñal de exposición de servicioEl único observable es el crash (DoS)

La conclusión práctica: la enumeración de build-version es la única forma segura de flaggear CVE-2026-41089 hoy, y pertenece a la fase autenticada y privilegiada de un assessment — no a un barrido de red sin autenticación, donde devolvería "unknown" para cada DC. No necesitas un exploit funcional para convencer a un CISO de aplicar un parche CVSS 9.8; necesitas la evidencia de que un DC específico, por su build number específico, está en el rango vulnerable.

LongLogon: un checker de precondición open-source

Para llevar este análisis a la práctica sin tumbar nada, construimos y liberamos un checker no destructivo. Envía CLDAP pings benignos, mide la respuesta del builder legacy, e informa si el dominio de un domain controller es lo bastante largo para que un DC sin parchear desborde, todo sin enviar el overflow.

LongLogon comprobando un domain controller

Deliberadamente no determina el estado de parche: un DC parcheado toma el mismo code path y rechaza la escritura larga, así que parcheado y sin parchear se ven igual por la red en un DC con nombre normal. Saber qué DCs están realmente parcheados requiere un check credentialed de versión en toda la flota. El checker es open source: ADScanPro/CVE-2026-41089-LongLogon.

¿Qué aprendimos haciendo esta investigación por las malas?

Tres cosas que vale la pena guardar para el próximo Patch Tuesday.

Primero: hacer bindiff a cumulative updates de Microsoft gana a esperar PoCs públicas cada vez. El tooling es maduro en 2026 — ghidriff con PyGhidra y símbolos públicos de Microsoft convierte lo que solía ser un proyecto de reverse engineering de semanas en un run de un comando que termina durante un coffee break. Cualquier defensor o pentester que necesite inteligencia de CVE a nivel de función puede producirla el día que se publica el parche, sin depender de la comunidad de investigación en seguridad para hacer el trabajo primero.

Segundo: leer los advisories cuidadosamente antes de decidir cómo asignar tiempo de investigación. La clasificación CWE de Microsoft, el rating exploitation-likelihood y el resumen de impacto contienen información real sobre si el bug es alcanzable por fuzzing surface-level, requiere heap grooming o necesita ingeniería de exploit-dev completa. El rating "Exploitation Less Likely" de CVE-2026-41089 combinado con CWE-121 era, en retrospectiva, una predicción acertada de que el fuzzing simple no produciría un crash. Horas de fuzzing a nivel de red podrían haberse ahorrado leyendo el rating primero e yendo directo al análisis dinámico en el target con un debugger attached.

Tercero: el gap entre localizar un bug y weaponizarlo es enorme, y ese gap es el valor que capturan los operadores APT. El bindiff que nos llevó cuatro horas es lo que un ingeniero reverso competente produce en una sola sesión. El exploit que esos mismos operadores APT están corriendo en producción hoy representa semanas o meses de trabajo adicional — análisis de heap layout, construcción de ROP chain por build de Windows, bypass de ASLR y CFG, staging de payload. Para la mayoría de casos de uso defensivos, el bindiff es suficiente. No necesitas un exploit funcional para validar que un CVE aplica a tu entorno, para detectar intentos de explotación en tu red o para priorizar el parche en tu ventana de mantenimiento. Necesitas el nombre de la función, el reach path y el build version threshold. Esos son los deliverables que mueven decisiones de riesgo, y esos son alcanzables en una tarde.

ADscan es un escáner de seguridad de Active Directory que mapea domain controllers, enumera el OS build por DC durante el assessment autenticado y renderiza los attack paths del dominio en contexto. Todavía no incluye un veredicto automático de CVE-2026-41089 — el check de comparación de versión descrito arriba es el enfoque de detección correcto y está en el roadmap como un check credentialed post-autenticación, no como un barrido sin autenticación.

Patch Diffing CVE-2026-41089: Localizando el Bug de Netlogon en 4 Horas Sin PoC Pública | ADscan