Shai Laron | Investigador en seguridad Investigador en seguridad

Active Directory (AD) sigue siendo la joya de la corona de la infraestructura empresarial y, para los atacantes, el santo grial está claro: obtener privilegios de administrador de dominio. Este nivel de privilegios otorga, en la práctica, un control total sobre el entorno. Por lo tanto, la protección de la identidad desempeña un papel fundamental en la seguridad empresarial, y las organizaciones dedican grandes esfuerzos a impedir que los atacantes obtengan acceso a las credenciales de los administradores.

Pero, ¿y si los atacantes pudieran simplemente confundir a los controladores de dominio (DC), haciendo que estos los identificaran como otra persona?

Hace algún tiempo, asistí a una charla de Yossi Sassi sobre técnicas de persistencia en Active Directory. Sassi presentó un concepto que yo no conocía: la posibilidad de añadir caracteres Unicode «invisibles» a los atributos de los objetos. Presentó esta posibilidad como una técnica de persistencia que permite crear usuarios que parecen tener el mismo nombre que otros usuarios legítimos ya existentes. Esta técnica puede confundir a los equipos de seguridad y de TI y retrasar considerablemente las investigaciones.

El tema despertó mi curiosidad. Me pregunté:

  • ¿Acepta Active Directory algún otro carácter «invisible»?
  • ¿Cómo se podría detectar de forma eficaz el uso indebido de estos caracteres?
  • ¿Tienen los caracteres ocultos otros usos, aparte de la persistencia?

Este artículo detalla mi investigación sobre estas cuestiones, que condujo al descubrimiento de dos nuevas vulnerabilidades de escalada de privilegios en Active Directory: KerberLoss (CVE-2026-25177) y ResetNightmare (CVE-2026-27912). Cada vulnerabilidad adopta un enfoque único para provocar confusión de identidades en los servidores de dominio (DC), lo que da lugar a diversas consecuencias. La segunda (y más grave) permite a un usuario con privilegios reducidos obtener al instante privilegios de administrador de dominio.


Investigación inicial: Unicode y Active Directory

Mis preguntas me llevaron por un interesante laberinto en torno a Unicode y el procesamiento LDAP del lado del servidor. Empecé buscando en Internet los caracteres Unicode que pueden aparecer invisibles y recopilándolos en una lista. Me interesaban especialmente los caracteres que aparecen invisibles dentro de los nombres de los objetos, ya que me parecía la forma más interesante de hacer un uso indebido de esta técnica.

Para empezar con mis pruebas, creé una cuenta de usuario de ejemplo llamada UniqueUser. Como era de esperar, no fue posible crear otra cuenta de usuario con el mismo nombre (Figura 1).

La creación de usuarios duplicados está bloqueada de forma predeterminada
Figura 1. La creación de usuarios duplicados está bloqueada de forma predeterminada

Sin embargo, al utilizar un carácter «invisible», pude crear una cuenta de usuario aparentemente idéntica (Figura 2).

Al añadir un carácter Unicode oculto a la cadena, el comando se ejecuta correctamente
Figura 2. Al añadir un carácter Unicode oculto a la cadena, el comando se ejecuta correctamente

La figura 2 muestra que la consola de PowerShell interpreta la cuenta resultante como si tuviera un espacio extraño (antes de «ser»). Sin embargo, al observar las dos cuentas en las herramientas gráficas de gestión de AD, parecen idénticas (figura 3).

Figura 3. Los distintos usuarios parecen idénticos debido a los caracteres ocultos

Utilizando este método básico, recorrí mi lista de caracteres Unicode, creando cuentas de usuario con cada uno de ellos. Como muestra la figura 4, algunos de los caracteres se interpretaron de una forma extraña, y desde luego no invisible, en AD.

Figura 4. Algunos caracteres Unicode se veían en lugar de estar ocultos

Tras borrar todo esto, me quedé con un directorio similar al de la figura 5.

Mi directorio tras eliminar los usuarios con caracteres visibles
Figura 5. Mi directorio tras eliminar los usuarios con caracteres visibles

Además, aunque mi script omitió algunos caracteres porque el DC no los aceptaba, también omitió otros porque el DC interpretó que el nombre de usuario ya existía. (En retrospectiva, esto era un presagio.) Para probar el mayor número posible de estos caracteres sin verme limitado por las restricciones de unicidad, también creé más nombres de usuario (Figura 6), cada uno de los cuales representaba un carácter invisible único oculto entre dos guiones («–»).

Creación de usuarios distintos para cada carácter Unicode oculto
Figura 6. Creación de usuarios distintos para cada carácter Unicode oculto

Llegados a este punto, estaba convencido de que mi lista de 385 caracteres invisibles respondía a mi primera pregunta de investigación. Ahora era el momento de abordar el reto de la detección.


Un enfoque de detección diferente

En su ponencia original, Sassi presentó una herramienta que permite detectar caracteres Unicode ocultos en objetos de AD. Me interesaba comprender cómo funciona esa herramienta. El script sigue un enfoque sencillo:

  • Crea un diccionario con 29 personajes «invisibles».
  • Obtener todas las propiedades de todos los objetos del dominio.
  • Recorre cada atributo.
    • Convierte el atributo en una matriz de caracteres.
    • Obtén el valor hexadecimal de cada carácter y compáralo con el del diccionario.

Este enfoque es muy completo. Sin embargo, me inclino por las detecciones que puedan ejecutarse de forma rutinaria y eficiente en entornos de producción, por lo que me preguntaba si el filtrado podría realizarse dentro de las propias solicitudes LDAP (es decir, en el lado del servidor) en lugar de procesar cada carácter individualmente en el lado del cliente.

Para averiguarlo, primero realicé una prueba sencilla para determinar si el DC podía procesar estos caracteres «tal cual». Convertí un carácter (0x200B) a su formato de cadena «invisible» y, a continuación, la copié y pegué en PowerShell (Gráfico 7).

Una consulta con el código 0x200B pegado entre «Unique» y «User»
Figura 7. Una consulta con el código 0x200B pegado entre «Unique» y «User»

¡De momento, todo va bien! Al pegar el carácter directamente en un filtro LDAP, solo se devolvió el objeto esperado. Sin embargo, cuando empecé a probar con diferentes caracteres, me encontré con algunas situaciones más extrañas.

Hice la misma prueba, pero esta vez utilicé el carácter 0x200C, que es otro carácter invisible. Como este carácter no superó las comprobaciones de unicidad de los usuarios, no tenía ningún usuario llamado Unique{0x200C}User que tenía en mi directorio en ese momento. Sin embargo, mi consulta siguió devolviendo un resultado (Figura 8).

Una consulta con el código 0x200C pegado entre «Unique» y «User»
Figura 8. Una consulta con 0x200C pegado entre «Unique» y «User»

Los más observadores quizá se den cuenta de que, en esta ocasión, el resultado no presenta ese extraño espaciado que observé al mostrar estos caracteres en la consola. Tras verificar el identificador de seguridad (SID) del usuario devuelto, confirmé que se trataba del nombre de usuario sin caracteres añadidos. El carácter Unicode del filtro fue ignorado, ya fuera por PowerShell o por el servidor de dominio (DC).

Si mi teoría fuera correcta, entonces modificar la consulta para buscar cualquier objeto con el 0x200C El carácter debería mostrar todos los objetos del directorio. Esta vez, he convertido el valor Unicode en la consola para que resulte más legible (Figura 9).

Al buscar un SamAccountName que contenga 0x200C, se muestran todas las identidades del dominio.
Figura 9. Al buscar un SamAccountName que contenga 0x200C, se muestran todas las identidades del dominio.

En ese momento, el comportamiento del servidor LDAP no era coherente; algunos caracteres se evaluaban y otros se ignoraban. Con el fin de descartar la posibilidad de que la cadena de filtro fuera la causa del problema, encontré el RFC 4515, que establece lo siguiente:

La representación como cadena de un filtro de búsqueda LDAP es una cadena de caracteres Unicode codificados en UTF-8.

El RFC también ofrece algunos ejemplos. Esto me hizo pensar que es posible convertir y consultar cualquier carácter Unicode, independientemente de si se puede imprimir o no. Basándome en el RFC, he creado la siguiente función para recibir un valor hexadecimal Unicode (por ejemplo, 0x200B) y devuelve su cadena compatible con el filtro LDAP (Figura 10).

La función Convert-UnicodeToLdapUtf8, basada en el RFC 4515
Figura 10. La función «Convert-UnicodeToLdapUtf8», basada en el RFC 4515

Comprobé que mi función realizaba correctamente la conversión utilizando el valor 0x200B, que ya había filtrado con éxito en mis pruebas anteriores (Figura 11).

Comprobación del funcionamiento de la función mediante la prueba 0x200B
Figura 11. Comprobación del funcionamiento de la función mediante la prueba de 0x200B

Tras comprobarlo, pasé a probar los caracteres que me daban problemas (Figura 12).

Prueba de la función con el código de error 0x200C
Figura 12. Prueba de la función con el código de error 0x200C

Por desgracia, ni siquiera seguir las indicaciones del RFC sirvió de nada. Al utilizar este método para buscar mis 385 caracteres invisibles con LDAP, observé tres categorías distintas de caracteres:

  • Caracteres filtrables: solo 106 de un total de 385
  • Caracteres que se consideran espacios en blanco: aunque no sean visibles en la interfaz gráfica de usuario, la función char devuelve todos los nombres de objetos que contengan espacios (por ejemplo, «Domain Admins», «Print Operators»).
  • Caracteres que el DC ignora por completo: la función «char» devuelve todos los objetos

A esas alturas ya estaba demasiado metido en el tema. Tenía que saber si había alguna forma de filtrar esos caracteres. Mientras pensaba en posibles cambios (aparte de la propia cadena de filtro), me pregunté si una de las Controles ampliados de LDAP podría ser de ayuda. Al repasar las diferentes opciones, la única que me llamó la atención fue LDAP_SERVER_SORT_OID. Aunque la descripción del control solo menciona el orden de clasificación, La documentación de AD lo indica en varias ocasiones que la presencia del control también afecta al comportamiento de la comparación de cadenas Unicode.

Para comprobarlo, creé una función que me permitía añadir fácilmente el LDAP_SERVER_SORT_OID control y consultar LDAP con cualquier «OID de regla de ordenación» que eligiera. A continuación, recreé una situación con la que me topé en un Foro de Microsoft. He creado dos usuarios:

  • Shai
  • Shäi II

Fíjate en la diferencia entre «a» (Unicode 0x0061) y «ä» (Unicode 0x00E4).

He comprobado la diferencia entre realizar una consulta LDAP sin el control ampliado (que, por defecto, utiliza el inglés de EE. UU.) y hacerlo con dicho control y una regla de ordenación («swedish»). El segundo método sí que modificó el resultado devuelto, no solo el orden de clasificación (Figura 13).

Las «reglas de ordenación» de distintos lenguajes devuelven objetos diferentes para el mismo filtro
Figura 13. Las «reglas de ordenación» de los distintos lenguajes devuelven objetos diferentes para el mismo filtro

Este comportamiento también se producía al utilizar mi Convert-UnicodeToLdapUtf8 función para convertir «ä» en su valor con caracteres de escape UTF-8 (Figura 14).

Las reglas de ordenación siguen funcionando de forma coherente al convertir a UTF-8
Figura 14. Las reglas de ordenación siguen comportándose de forma coherente al convertir a UTF-8

Tenía la esperanza de que quizá alguno de estos OID de reglas de ordenación pudiera «filtrar lo infiltrable» en lo que respecta a mi lista de caracteres invisibles.

He escrito un script que recorre cada regla de ordenación y consulta con ella cada carácter no filtrable. He llegado a la conclusión de que ninguna regla de ordenación hace que el DC «detecte» ninguno de los caracteres problemáticos.

Aquí terminó mi investigación sobre los caracteres LDAP invisibles desde el punto de vista de la detección, lo que me dejó con un problema sin resolver: hay caracteres Unicode que el servidor LDAP de Active Directory ignora por completo.

Sin embargo, este problema de detección ofrecía una interesante posibilidad ofensiva.


Cambiar de papel

En resumen:

  • Algunos caracteres Unicode no son interpretados correctamente por Active Directory, por lo que parecen invisibles.
  • Algunos de estos caracteres no pueden filtrarse mediante LDAP, lo que significa que, al filtrar por un valor «normal», podrían aparecer en los resultados valores que contengan dichos caracteres.

En esencia, hay un potencial para anular las restricciones de unicidad para cualquier atributo basado en Unicode. En mis primeras pruebas con SamAccountNamey cns, observé que Active Directory impide la creación de objetos duplicados que contengan caracteres no filtrables (y con razón). Sin embargo, esto no ocurría con todos los atributos.

En 2021, Microsoft publicó un parche para una vulnerabilidad identificada como CVE-2021-42282. El parche introdujo tres nuevas comprobaciones de veracidad:

  • Unicidad del nombre principal de usuario (UPN)
  • Unicidad del nombre principal del servicio (SPN)
  • Unicidad de los alias SPN

Cada uno de estos valores debe ser único en todo el bosque, y las tres comprobaciones se aplican de forma predeterminada en todo el bosque mediante el dSHeuristics atributo. Cualquier usuario con privilegios inferiores a los de administrador de dominio recibirá un «error de unicidad» al intentar establecer un valor que incumpla estas comprobaciones de unicidad.

Sin embargo, como se verá en las secciones siguientes, los caracteres que no se pueden filtrar pueden permitir a los usuarios con pocos privilegios eludir estos controles de verificación. Esta es la primera vulnerabilidad que descubrí. Debido a sus diversas repercusiones, la he denominado «KerberLoss»; Microsoft le ha asignado el identificador CVE-2026-25177.


KerberLoss: Empezando con los SPN

Para comprender el impacto de esta vulnerabilidad, primero es necesario conocer bien los nombres de entidad de servicio (SPN).


¿Qué son los nombres de entidad de servicio?

Los SPN son un concepto de Active Directory que suele malinterpretarse. Un SPN es la forma en que Kerberos identifica las instancias de servicio. En el contexto de Active Directory, un servicio es cualquier recurso al que se accede mediante una identificación y que, por lo general, requiere autenticación. Algunos ejemplos son los recursos compartidos de archivos SMB (cifs), las conexiones de Escritorio remoto (TERMSRV), LDAP y HTTP… todos ellos ejemplos de las denominadas «clases de servicio ».

Los servicios de una misma clase pueden ejecutarse en distintos hosts, y un mismo host puede proporcionar servicios de varias clases. Por lo tanto, un SPN debe incluir estos dos componentes, con la siguiente estructura básica:

<service class>/<host>

Nota: Los SPN también pueden incluir dos componentes adicionales opcionales, que quedan fuera del alcance de este documento.

Los conceptos básicos que se han mencionado anteriormente son bastante conocidos. Sin embargo, quiero destacar algunos puntos importantes:

  • En el mundo de Active Directory y Kerberos, un servicio está asociado a algún tipo de identidad. Puede tratarse de una cuenta de ordenador, una cuenta de usuario o una cuenta de servicio gestionada, pero debe haber una identidad detrás del servicio. Esto se debe a los principios criptográficos en los que se basa Kerberos. Los tickets de servicio se cifran utilizando el secreto perteneciente al «servicio de destino» (es decir, su identidad).
  • El objeto que representa cada identidad en Active Directory tiene un atributo denominado servicePrincipalName, que se utiliza para gestionar una lista de los SPN de la identidad.
  • Al solicitar un ticket de servicio de Kerberos, el Centro de Distribución de Claves (KDC) utiliza el SPN de la solicitud para identificar el servicio de destino. En este contexto, el servicio de destino es la identidad que posee el SPN correspondiente.
  • Por último, los tickets de Kerberos contienen una parte en texto claro y otra cifrada. El SPN se encuentra en la parte en texto claro del ticket. Dado que el SPN no está cifrado, podemos modificarlo en los tickets y transferirlos entre diferentes servicios de la misma identidad. Lo que importa es qué clave se utilizó para cifrar el ticket.


¿Qué son los alias de SPN?

Si alguna vez has administrado un dominio de Active Directory, probablemente te habrás dado cuenta de que cada ordenador tiene varios SPN predeterminados, incluidos los SPN con el HOST clase de servicio (HOST/computer). Para quienes no estén familiarizados con ellos, estos SPN pueden resultar bastante confusos.

La partición de configuración de Active Directory contiene un atributo denominado sPNMappings. Este atributo permite asignar los SPN a los denominados Alias de SPN. Por defecto, este atributo contiene un único valor, que asigna el HOST alias para los siguientes servicios:

alerter, appmgmt, cisvc, clipsrv, browser, dhcp, dnscache, replicator, eventlog, eventsystem, policyagent, oakley, dmserver, dns, mcsvc, fax, msiserver, ias, messenger, netlogon, netman, netdde, netddedsm, nmagent, plugplay, protectedstorage, rasman, rpclocator, rpc, rpcss, remoteaccess, rsvp, samss, scardsvr, scesrv, seclogon, scm, dcom, cifs, spooler, snmp, schedule, tapisrv, trksvr, trkwks, ups, time, wins, www, http, w3svc, iisadmin, msdtc

Al incorporarse al dominio, cada cuenta de ordenador de Active Directory recibe un HOST clase SPN. Cuando los usuarios intentan acceder a un servicio asignado a HOST (p. ej., cifs, http), el KDC cifra el ticket de servicio con la clave correspondiente a la cuenta con el HOST SPN.


Un caso límite interesante

La verificación de la unicidad de los alias de SPN, ya mencionada anteriormente, impide la creación de SPN asignados que entren en conflicto. Por ejemplo, si el bosque tiene un ordenador llamado Server, que tiene el HOST/Server SPN, asignación de la cifs/Server Se bloqueará el SPN hacia otro servidor, aunque el cifs/Server SPN no existe de forma explícita.

Ya he mencionado que la vulnerabilidad descubierta puede eludir esta comprobación de unicidad. Pero lo interesante es que el algoritmo de búsqueda de SPN siempre busca primero un SPN explícito. El algoritmo solo busca el alias asignado al SPN si no encuentra un SPN explícito.

Con esta introducción (bastante extensa) a los SPN, ya dispones de los conocimientos necesarios para comprender cómo se puede aprovechar esta vulnerabilidad con fines maliciosos.


Demostrar el impacto

Voy a mostrar varios casos prácticos. Para ello, utilizaré un entorno sencillo que contiene tres servidores miembros de dominio:

  • Servidor A
  • Servidor B
  • ServerC

El atacante está ejecutando el programa como un usuario sin privilegios llamado NotAdmin.


Escenario n.º 1: Ataque de denegación de servicio a servicios asignados a HOST

Para nuestro primer caso, supongamos que ServerB alberga un importante recurso compartido de archivos SMB. Los usuarios que acceden al recurso compartido solicitan tickets de servicio para cifs/SERVERB. Porque ServerB tiene el HOST/SERVERB SPN: por defecto, el servidor de dominio (DC) lo identifica como la cuenta que posee la clave de cifrado correspondiente al servicio de destino. Si NotAdmin tiene el permiso WriteSPN en ServerC, no pueden añadir el cifs/SERVERB SPN, ya que la verificación de la unicidad del alias SPN impide esta acción (Figura 15).

Los usuarios que no sean administradores del dominio no pueden configurar alias SPN que entren en conflicto.
Figura 15. Los usuarios que no sean administradores del dominio no pueden configurar alias SPN que entren en conflicto

Sin embargo, al utilizar un carácter invisible e imposible de filtrar e insertarlo en la cadena, NotAdmin consigue añadir el SPN conflictivo (Figura 16).

Al utilizar caracteres que no se pueden filtrar, es posible eludir la verificación de la unicidad de los alias SPN.
Figura 16. Al utilizar caracteres no filtrables, es posible eludir la verificación de la unicidad de los alias SPN.

Como ya es de esperar, el carácter no es completamente invisible en la consola de PowerShell. Sin embargo, sí lo es cuando se consulta dsa.msc (Figura 17).

dsa.msc muestra un SPN que parece legítimo
Figura 17. dsa.msc muestra un SPN que parece legítimo

Y, lo que es más importante, cuando alguien consulta el LDAP para obtener el cifs/SERVERB SPN, ServerC es el objeto que se devuelve (Figura 18).

El servidor LDAP no evalúa el carácter no filtrable al consultar los SPN.
Servidor 18. El servidor LDAP no evalúa el carácter no filtrable al consultar los SPN

En este caso, debido a la prioridad explícita de los SPN que he explicado anteriormente, cuando cualquier usuario del dominio intente acceder a ServerB a través de SMB, El KDC cifrará el ticket con ServerCla clave de…. Cuando el usuario intenta utilizar este ticket, ServerB no puede descifrarlo, lo que da lugar a un KRB_AP_ERR_MODIFIED error. Para el usuario medio, esto podría aparecer como varios mensajes ambiguos diferentes:

  • El nombre de red indicado ya no está disponible.
  • El nombre de la cuenta de destino es incorrecto.
  • No se puede encontrar la ruta «path» porque no existe.

Al eliminar el SPN falso, se restablece inmediatamente el acceso normal (Figura 19).

El SPN malicioso bloquea el acceso a SMB; al eliminar el SPN, el acceso se restablece de inmediato
Figura 19. El SPN malicioso bloquea el acceso a SMB; al eliminar el SPN, el acceso se restablece de inmediato

Disponer del permiso «WriteSPN» en cualquier Una cuenta de ordenador o de usuario del bosque permitía llevar a cabo un ataque de denegación de servicio (DoS) contra cualquier HOST-servicio asignado en el bosque, mediante el uso de caracteres que no se pueden filtrar. Figura 20 Ilustra esta situación.

Proceso para llevar a cabo un ataque de denegación de servicio (DoS) sobre servicios arbitrarios asignados a un HOST
Figura 20. Flujo de ejecución de un ataque DoS sobre un objetivo arbitrario HOST-servicios asignados


Escenario n.º 2: secuestro de SPN

Otra oportunidad interesante tiene que ver con los ataques de delegación restringida de Kerberos, ya que la delegación restringida clásica se configura mediante SPN. Para demostrarlo, he modificado un escenario del blog de Elad Shamir sobre el «SPN-jacking».

Nota: Este escenario requiere conocer los ataques de delegación de Kerberos (es decir, «el ataque S4U completo»). La explicación del concepto de delegación de Kerberos queda fuera del alcance de este documento.

En su publicación, Shamir presentó el siguiente escenario, en el que un atacante con acceso de administrador a ServerA quiere obtener acceso de administrador a ServerC. ServerA está configurado para la delegación restringida a cifs/ServerB, y el atacante tiene derechos de WriteSPN sobre ServerB y ServerC (Figura 21).

La configuración del laboratorio descrita en el artículo de Shamir
Figura 21. La configuración del laboratorio tal y como aparece en el artículo de Shamir

Shamir sugirió abordar la verificación de la unicidad de los alias SPN utilizando WriteSPN en ambos ServerB y ServerC, eliminando temporalmente el HOST/SERVERB SPN de ServerB, y solo entonces añadir cifs/SERVERB a ServerC. Ahora, el atacante puede llevar a cabo el ataque S4U completo utilizando ServerAla cuenta de… para obtener un ticket de servicio para un usuario con privilegios con el fin de… ServerC, antes de revertir los cambios.

Mediante el uso de KerberLoss, combinado con una precedencia explícita de SPN, un atacante puede evitar la necesidad de utilizar WriteSPN en el servicio intermedio. Para demostrarlo, he configurado mi entorno de pruebas tal y como se ilustra en la figura 22.

La configuración de mi laboratorio; ten en cuenta que NotAdmin no tiene el privilegio WriteSPN en el ServidorB
Figura 22. La configuración de mi laboratorio; fíjate en que NotAdmin no tiene el privilegio WriteSPN en ServerB

Al igual que en el ejemplo anterior de DoS, el atacante puede utilizar caracteres que no se pueden filtrar para provocar ServerC el cifs/SERVERB SPN, al eludir la comprobación de unicidad y crear una situación en la que las entradas para cifs/SERVERB se cifrará con ServerCla clave de (Figura 23).

Una vez más, al buscar la cuenta que contiene cifs/SERVERB, aparece ServerC
Figura 23. De nuevo, buscando la cuenta que contiene cifs/SERVERB devoluciones ServerC

Ahora, el atacante puede ejecutar todo el proceso de ataque S4U para obtener un ticket con privilegios para cifs/SERVERB (Figura 24).

Ejecutar el ataque S4U completo para obtener un ticket de administrador para cifs/ServerB
Figura 24. Ejecución del ataque S4U completo para obtener un ticket de administrador para cifs/ServerB

He conseguido sin problemas un ticket de servicio para un usuario administrador. Ahora voy a comprobar si el ticket se ha cifrado correctamente con ServerCes la clave. Como el SPN se encuentra en la parte no cifrada del ticket, puedo cambiarlo por cifs/ServerC y acceder al servidor. El acceso solo funcionará si el ticket está cifrado con ServerCla clave de…, no ServerB’s (Figura 25).

Se ha logrado comprometer ServerC
Figura 25. Compromiso logrado ServerC


Escenario n.º 3: Reducción del nivel de autenticación

Ya conocemos las consecuencias de crear SPN asignados que entran en conflicto. Pero, ¿qué ocurre con los SPN explícitos duplicados? Recordemos nuestra capacidad de provocar un ataque de denegación de servicio (DoS) mediante la asignación a HOST.

Cuando existen alias SPN conflictivos, al solicitar un ticket de servicio se localiza un SPN y se crea dicho ticket. Desde el punto de vista del servidor de dominio, Kerberos ha funcionado correctamente; el efecto DoS se produce porque el propio recurso no se puede descifrar el ticket, lo que da lugar a un KRB_AP_ERR_MODIFIED error. Sin embargo, si creamos un duplicado exacto de un SPN, el resultado es diferente.

En el caso de duplicados explícitos de SPN, cuando se solicita un ticket de servicio, el DC encuentra dos cuentas que tienen ese SPN. En este caso, el DC no puede «elegir» ¿Qué clave se debe utilizar para el billete? y, por lo tanto, devuelve un KDC_ERR_S_PRINCIPAL_UNKNOWN Error. En esta ocasión, el DC devuelve el error, lo que indica que la autenticación Kerberos ha fallado y hace que el cliente recurra a NTLM.

Esto significa que, al disponer del permiso «WriteSPN» en cualquier ordenador o cuenta de usuario del bosque, además de poder provocar un denegación de servicio (DoS) total en cualquier servicio asignado a un HOST del bosque, se podría obligar a cualquier servicio del bosque, esté o no asignado a un HOST, a utilizar únicamente NTLM (a menos que esté desactivado, lo que provocaría un DoS).

Desde el punto de vista del usuario, el acceso parece mantenerse con normalidad (Figura 26, Figura 27).

Tras configurar un SPN de HOST duplicado, el acceso en sí sigue funcionando
Figura 26. Tras configurar un duplicado HOST SPN: el acceso en sí sigue funcionando
Wireshark muestra que el servidor responde con el código de error KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN, lo que provoca que se recurra a NTLM.
Figura 27. Wireshark muestra que el servidor DC responde con el código de error KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN, lo que provoca el recurso a NTLM.

La figura 28 ilustra esta situación.

Procedimiento para obligar a servicios arbitrarios a recurrir a NTLM en lugar de Kerberos
Figura 28. Flujo para obligar a servicios arbitrarios a recurrir a NTLM en lugar de Kerberos


ResetNightmare: ¿Y qué hay de las UPN?

En mi búsqueda de un método directo para elevar privilegios, recurrí a los nombres principales de usuario (UPN). Teniendo en cuenta que la verificación de la unicidad de los UPN se rige por el mismo mecanismo que la verificación de la unicidad de los SPN, supuse acertadamente que se podría eludir de la misma manera (Figura 29).

Duplicar el UPN de DemoAdmin1 utilizando caracteres no filtrables
Figura 29. Duplicación del UPN de DemoAdmin1 utilizando caracteres no filtrables

La verificación de la unicidad se corrigió junto con una serie de otras vulnerabilidades descubiertas por Andrew Bartlett, entre las que destaca el ataque «Dollar Ticket/noPac» (CVE-2021-42287 + CVE-2021-42278), que permitía a cualquier usuario obtener al instante privilegios de administrador de dominio. Dado que el ataque se basaba en una confusión en los nombres de los servidores de dominio (DC), esperaba que KerberLoss me permitiera reactivar esta vulnerabilidad o descubrir otra similar. Para esto y para todas mis demás ideas, tenía que comprender si Kerberos utiliza los UPN y, en caso afirmativo, de qué manera.


Tipos de nombres de Kerberos

En Kerberos, un identificador de entidad se compone de un Realm y un PrincipalName. A PrincipalName está estructurado de la siguiente manera:

PrincipalName   ::= SEQUENCE {
	   name-type       [0] Int32,
	   name-string     [1] SEQUENCE OF KerberosString
}


En name-string El campo especifica el nombre como una cadena de Kerberos. Sin embargo, el name-string por sí solo no basta para identificar a un mandante. El name-type El campo especifica el tipo del nombre, lo que, en términos sencillos, significa cuál atributo Se examina en primer lugar para identificar al principal. El protocolo Kerberos ([RFC4120], sección 6.2) define varios valores posibles para este campo.

Active Directory suele utilizar el NT-PRINCIPAL tipo de nombre para identificar a los clientes de Kerberos, y se asigna a la cuenta SamAccountName. Al enviar solicitudes de Ticket Granting Ticket (TGT) de Kerberos, también es posible utilizar el NT-ENTERPRISE nombre del tipo, que localiza las cuentas por su UserPrincipalName (UPN). El nombre real del cliente que aparece en el ticket resultante puede ser el SamAccountName (NT-PRINCIPAL) o la UPN (NT-ENTERPRISE), y esto suele estar controlado por el Name-canonicalize bandera.

Por suerte, las herramientas habituales de Kerberos, como Rubeus e Impacket, ya incorporan la posibilidad de especificar qué tipo de nombre debe utilizarse en la solicitud de TGT, por lo que pude solicitar tickets con el NT-ENTERPRISE nombre-tipo.

Sin embargo, cuando intenté solicitar tickets con mi UPN duplicado, el DC siguió intentando autenticarme como el destinatario con privilegios, lo que provocó un error de «fallo en la preautenticación» (Figura 30).

Se produce un error al solicitar un TGT con un UPN duplicado
Figura 30. Fallo al solicitar un TGT con un UPN duplicado

Esto sí funcionó al eliminar el UPN de DemoAdmin1 , pero este método requeriría disponer de permisos de escritura sobre el objetivo, lo cual no es realista en el contexto de la escalada de privilegios (Figura 31).

La obtención de una clave para el UPN solo funciona si se elimina el UPN original del usuario de destino.
Figura 31. La obtención de un ticket para el UPN solo funciona cuando se elimina el UPN original del usuario de destino

Poco después, encontré una solución a este problema: en lugar de eludir la verificación de la unicidad del UPN utilizando caracteres que no se pueden filtrar, basta con que establezca mi UPN como SamAccountName de mi objetivo. Esto está permitido, ya que las cadenas no son idénticas (Figura 32).

Configurar el UPN del usuario sin privilegios con el SamAccountName del administrador del dominio
Figura 32. Configuración del UPN del usuario sin privilegios para que coincida con el del administrador del dominio SamAccountName

Ahora, al solicitar un ticket para DemoAdmin1 utilizando la contraseña de UPNUser, la operación fallará, tal y como era de esperar. Pero si cambiamos el tipo de nombre a NT-ENTERPRISE, puedo conseguir un billete a nombre de DemoAdmin1 (Figura 33).

Al cambiar el tipo de nombre, podemos obtener un ticket en el que figure el nombre del administrador del dominio.
Figura 33. Al cambiar el tipo de nombre, podemos obtener un ticket en el que figure el nombre del administrador del dominio.

Este método me permitió, básicamente, obtener un ticket con el nombre de cualquier usuario que quisiera. Aprovechando esto, intenté encontrar otra vulnerabilidad de confusión mediante diversos métodos, entre los que se incluyen:

  • De AS-REQ normal a TGS-REQ
  • Flujo del ataque «Dollar Ticket» modificado
  • S4U2: Abuso sexual contra uno mismo
  • Abuso de Kerberos en U2U
  • Ataque de denegación de servicio (DoS) en el inicio de sesión de usuario, tal y como menciona Andrew Bartlett
  • Activa la sincronización SyncJacking en modo «hard» o «soft»
  • Precedencia de los UPN entre dominios

Sin embargo, todos mis intentos de aprovechar los UPN para escalar privilegios fracasaron. Dependiendo del método y la herramienta concretos, me aparecían errores o se redirigía la solicitud al usuario correcto, sin privilegios. Analicé este comportamiento a fondo para averiguar por qué.


El parche CVE-2021-42287

Como ya se ha mencionado anteriormente, la vulnerabilidad «Dollar Ticket» provocaba una confusión en los nombres, similar a lo que yo intentaba conseguir aquí. Microsoft corrigió la vulnerabilidad añadiendo dos características importantes a Kerberos:

  • Los TGT devueltos siempre incluirán un certificado de atributos privilegiados (PAC), incluso si el cliente ha solicitado un ticket sin PAC.
  • El PAC de los TGT incluye ahora un campo denominado PAC_REQUESTOR_SID, que contiene el SID del cliente que solicitó el ticket.

Esto PAC_REQUESTOR_SID valor debe y, a continuación, se validará durante el TGS Exchange, lo que invalida el antiguo vector de ataque, en el que el atacante eliminaba la cuenta que había solicitado el TGT, haciendo que el servidor de dominio (DC) creyera que el TGT pertenecía, en realidad, al servidor de dominio con un nombre similar.

Este (excelente) parche tuvo el efecto secundario, un tanto molesto, de invalidar todos mis intentos de escalada de privilegios mediante la confusión de UPN. El PAC ahora siempre contenía mi SID original, y el servidor de dominio ignoraba por completo el nombre del cliente en mi ticket, basándose únicamente en el SID como fuente de referencia del ticket.

Justo cuando estaba a punto de dar por perdida la escalada de privilegios mediante UPN, decidí repasar por última vez mi lista de ideas de abuso pendientes, comprobando si alguna de ellas podría funcionar. Fue entonces cuando me topé con algo interesante.


Avance: (Ab)uso del protocolo de cambio de contraseña de Kerberos

Por defecto, todos los usuarios de Active Directory pueden cambiar su propia contraseña. Una forma de hacerlo es utilizar el protocolo «Kerberos Change Password and Set Password» de Microsoft, que especifica cómo se llevan a cabo los cambios de contraseña a través de Kerberos. El protocolo es extremadamente sencillo (el RFC solo tiene 7 páginas) y contiene un único mensaje de solicitud y un único mensaje de respuesta.

Microsoft utiliza los términos «cambiar contraseña» y «establecer contraseña» para diferenciar, respectivamente, entre el caso en que un usuario cambia su propia contraseña y el caso en que un administrador establece la contraseña de un usuario.

El protocolo recibe mensajes en el puerto 464 (kpasswd), con la estructura de solicitud que se muestra en la figura 34.

Mensaje de solicitud de cambio de contraseña de Kerberos
Figura 34: Mensaje de solicitud de cambio de contraseña de Kerberos

Las dos partes principales de este mensaje son el mensaje KRB-PRIV y la estructura AP-REQ.

El mensaje KRB-PRIV es, en esencia, una forma de enviar datos cifrados. Además, permite incluir datos personalizados. El protocolo aprovecha esta característica para incluir el valor de la nueva contraseña dentro de esta estructura (Figura 35).

Uso de KRB-PRIV en el protocolo de cambio de contraseña de Kerberos
Figura 35. Uso de KRB-PRIV en el protocolo Kerberos de cambio de contraseña

Lo más interesante es la estructura AP-REQ. Esta estructura contiene un ticket y un autenticador, que acredita la posesión legítima del ticket, ya que está cifrado con su clave de sesión (Figura 36).

La estructura AP-REQ, que contiene un ticket y un autenticador
Figura 36. La estructura AP-REQ, que contiene un ticket y un autenticador

En la mayoría de los casos con Kerberos, una solicitud TGS_REQ/TGS_REP da lugar a un ticket de servicio (y a la clave de sesión correspondiente). A continuación, esta respuesta se utiliza para construir el mensaje AP_REQ, que se envía al servicio para demostrar que se posee el ticket.

En el caso del protocolo de cambio de contraseña de Kerberos, el ticket de la estructura AP-REQ debe tener un ámbito limitado a la kadmin/changepw SPN. Sin embargo, se trata de un SPN propiedad de la cuenta krbtgt, y sabemos que lo único que importa es la clave de cifrado, así que un billete para kadmin/changepw es simplemente un TGT en el que se ha cambiado el SPN (sname).

Esto significa que lo único que necesitamos para cambiar la contraseña de un usuario es su TGT. También significa que el proceso que sigue un usuario para cambiar su contraseña mediante Kerberos es el que se muestra en la figura 37.

Flujo de una operación de cambio de contraseña de Kerberos
Figura 37. Flujo de una operación de cambio de contraseña en Kerberos

Lo interesante es que este flujo pasa directamente de un TGT-REQ a un AP-REQ, sin un TGS-REQ entre medias. Recuerda el parche que analizamos antes: El TGS-REQ es donde el PAC_REQUESTOR_SID se lleva a cabo la validación.

Teniendo en cuenta que ya podía solicitar un TGT con cualquier nombre de usuario (utilizando el NT-ENTERPRISE nombre tipo), si el PAC_REQUESTOR_SID Si no se hubiera aplicado la corrección aquí, el protocolo podría ser vulnerable.

Combinando todos los conocimientos que había adquirido en mis pruebas anteriores, me puse manos a la obra para intentarlo. Teniendo en cuenta que, por defecto, todos los usuarios de Active Directory tienen permisos para cambiar su propia contraseña, mi idea para aprovechar esta vulnerabilidad era la siguiente:

  1. Un atacante ha conseguido acceder a un usuario llamado UPNUser, que no tiene ningún permiso especial, salvo la capacidad de modificar su propio valor UPN.
  2. El atacante establece el UPN del usuario en el SamAccountName de la cuenta en cuestión; por ejemplo, DemoAdmin1.
    Esta acción no requiere eludir los controles de verificación de la unicidad de la UPN. DemoAdmin1El UPN real debería ser «DemoAdmin1@demo.lab», por lo que hay que configurar UPNUserla UPN de… a simplemente DemoAdmin1 está permitido (Figura 38).
Establecer el valor UPN de UPNUser en el SamAccountName del destinatario
Figura 38. Configuración del valor UPN de UPNUser con el SamAccountName del destino
  1. El atacante solicita un TGT para kadmin/changepw especificando DemoAdmin1 como nombre de usuario, NT-ENTERPRISE como tipo de nombre, y Contraseña de UPNUser.
  2. El DC devuelve un TGT_REP con un TGT para UPNUser (tal y como se indica en PAC_REQUESTOR_SID en el PAC), pero con el nombre de usuario DemoAdmin1(NT_ENTERPRISE), como Figura 39 espectáculos.
Se devuelve un TGT para DemoAdmin1 con el tipo de nombre NT-ENTERPRISE
Figura 39. Un TGT para DemoAdmin1 con el NT-ENTERPRISE Se devuelve el tipo de nombre
  1. Si se utiliza este ticket para enviar una solicitud de cambio de contraseña, se restablecerá la contraseña de UPNUser. Para ampliar sus privilegios, el atacante modifica o borra el valor UPN de UPNUser, de modo que ningún usuario tenga el UPN que figura en el ticket.
  2. Si intentas utilizar este ticket para una solicitud TGS_REQ tras el cambio de UPN, se producirá un KDC_ERR_TGT_REVOKED error, debido a la PAC_REQUESTOR_SID parche que impide la suplantación de identidad. Sin embargo, si se utiliza este ticket para crear la solicitud de cambio de contraseña, el cambio se lleva a cabo correctamente.
  3. Ahora, el atacante puede solicitar un nuevo TGT para DemoAdmin1, sin especificando el NT-ENTERPRISE nombre tipo. La solicitud ya funciona y el tipo de nombre del ticket es NT-PRINCIPAL, lo que indica que el billete pertenece al verdadero (SamAccountName) DemoAdmin1 usuario (Figura 40).
Un TGT para el usuario «Domain Admin» real
Figura 40. Un TGT para el usuario real «Domain Admin»

¡Éxito! Con solo poder escribir un UPN, ya hemos comprometido el dominio.

He denominado a esta vulnerabilidad «ResetNightmare»; se le ha asignado el identificador CVE-2026-27912. La vulnerabilidad permite que un atacante se haga con el control total del dominio si dispone de permisos de escritura genéricos sobre cualquier objeto de usuario u ordenador del dominio, o si puede crear objetos de usuario u ordenador en el dominio (excluyendo MachineAccountQuota).

La figura 41 ilustra el proceso de uso indebido de ResetNightmare.

Flujo del ataque «ResetNightmare»
Figura 41. Flujo del ataque «ResetNightmare»

El único otro requisito es que la contraseña del usuario de destino debe tener una antigüedad suficiente. Sin embargo, la antigüedad mínima predeterminada de la contraseña en Active Directory es de 1 día, por lo que es muy probable que la contraseña del usuario de destino cumpla este requisito.

Como ventaja adicional (gracias a Andrea Pierini), esta vulnerabilidad también puede combinarse con la técnica de «credenciales en la sombra», lo que permite una vía de ataque más sigilosa al aprovechar cuentas informáticas con permisos de escritura.

También he creado una herramienta comunitaria de código abierto, ResetNightmare, que implementa todo el flujo del ataque ResetNightmare, incluidos diferentes parámetros para personalizar su ejecución. La herramienta está escrita en PowerShell y utiliza Rubeus.exe y el módulo ActiveDirectory de PowerShell (Figura 42). Puedes encontrar la herramienta en GitHub.

Ejecución del archivo ResetNightmare.ps1
Figura 42. Ejecución de ResetNightmare.ps1


Detección y protección frente a KerberLoss y ResetNightmare

Los clientes de Semperis Directory Services Protector (DSP) pueden utilizar los siguientes indicadores de seguridad nuevos para detectar varias configuraciones erróneas mencionadas en este artículo:

  • La verificación de la unicidad de UPN o SPN está desactivada
  • Objetos que contienen caracteres Unicode ocultos
  • Objetos duplicados sospechosos que utilizan caracteres Unicode ocultos
  • Entidad principal sin privilegios capaz de establecer un nombre de entidad de servicio
  • Entidad principal sin privilegios capaz de establecer un nombre de entidad principal de usuario

Además, los clientes de « DSP » pueden detectar modificaciones anómalas de SPN y UPN mediante dos indicadores de compromiso (IoC):

  • Se ha añadido un nombre de entidad de servicio conflictivo (CVE-2026-25177)
  • Se ha añadido un nombre principal de usuario (UPN) que coincide con el nombre de cuenta SAM de otra cuenta (CVE-2026-27912)

Sin DSP, la mejor forma de detectar el uso indebido de ambas técnicas es configurar las SACL para auditar las modificaciones de los objetos de Active Directory. Una vez configuradas las SACL, se puede utilizar el ID de evento 5136 del registro de seguridad («Se ha modificado un objeto del servicio de directorio») en los controladores de dominio para detectar los cambios que dan lugar al impacto de la vulnerabilidad.

En el caso de KerberLoss, la entrada con el ID de evento 5136 mostrará la incorporación de un ServicePrincipalName que entra en conflicto con uno ya existente (Figura 43).

Una entrada del registro de seguridad que muestra la incorporación de un valor SPN conflictivo
Figura 43. Una entrada del registro de seguridad que muestra la incorporación de un valor SPN conflictivo

En ResetNightmare, la entrada del ID de evento 5136 mostrará la incorporación de un UserPrincipalName que se corresponde con un SamAccountName (Figura 44).

Una entrada del registro de seguridad que muestra la incorporación de un valor UPN que imita un SamAccountName ya existente
Figura 44. Una entrada del registro de seguridad que muestra la incorporación de un valor UPN que imita un SamAccountName ya existente

La mejor forma de prevenir estas vulnerabilidades es aplicar los parches a todos los servidores de dominio (DC). Microsoft publicó parches para KerberLoss (CVE-2026-25177) en marzo de 2026 y para ResetNightmare (CVE-2026-27912) en abril de 2026.

Además de aplicar parches, las organizaciones deben ceñirse al principio del privilegio mínimo y vigilar que no se añadan de forma anómala permisos que no sean los predeterminados. Unos permisos más restrictivos pueden dificultar el aprovechamiento de estas vulnerabilidades.


Calendario de divulgación

  • 26 de noviembre de 2025: Se descubre KerberLoss y se notifica al MSRC.
  • 17 de diciembre de 2025: Se descubre ResetNightmare y se notifica al MSRC.
  • 9 de enero de 2026: El MSRC confirma que ResetNightmare funciona tal y como se había informado.
  • 17 de enero de 2026: El MSRC confirma que KerberLoss funciona tal y como se ha informado.
  • 10 de marzo de 2026: Microsoft corrige KerberLoss (CVE-2026-25177) en el «Patch Tuesday» como una vulnerabilidad importante de elevación de privilegios.
  • 14 de abril de 2026: Microsoft corrige la vulnerabilidad «ResetNightmare» (CVE-2026-27912) como una vulnerabilidad importante de elevación de privilegios.


Agradecimientos

Queremos expresar nuestro especial agradecimiento a los siguientes investigadores, que han servido de gran inspiración para diversas partes de esta investigación:

  • Yossi Sassi (@Yossi_Sassi)
  • Andrew Bartlett
  • Elad Shamir (@elad_shamir)
  • Charlie Clark (@exploitph)
  • Will Schroeder (@harmj0y)
  • Andrea Pierini (@decoder_it)
  • Benjamin Delpy (@gentilkiwi)


Más recursos


Descargo de responsabilidad

Este contenido se proporciona únicamente con fines educativos e informativos. Su objetivo es promover la concienciación y la corrección responsable de las vulnerabilidades de seguridad que puedan existir en los sistemas que usted posee o está autorizado a probar. El uso no autorizado de esta información con fines maliciosos, explotación o acceso ilegal está estrictamente prohibido. Semperis no respalda ni aprueba ninguna actividad ilegal y declina toda responsabilidad derivada del uso indebido del material. Además, Semperis no garantiza la exactitud o integridad del contenido y no asume ninguna responsabilidad por los daños derivados de su uso.