Yuval Gordon Investigador de seguridad | Microsoft

Cómo los atacantes potenciales pueden lograr la persistencia de privilegios en un DC a través de DnsAdmins

El equipo de investigación de Semperis ha ampliado recientemente una investigación anterior que mostraba un abuso de funciones en el entorno de Windows Active Directory (AD), en el que los usuarios del grupo DnsAdmins podían cargar una DLL arbitraria en un servicio DNS que se ejecutaba en un controlador de dominio. Yuval Gordon, del Equipo de Investigación de Semperis, amplió esta investigación para mostrar cómo se puede superar un problema con la técnica anterior, y para mostrar que un adversario podría utilizar esta táctica para dejar una puerta trasera no detectada en el Directorio Activo de una empresa, un riesgo de seguridad significativo.

En un post en Medium en 2017, investigadores de seguridad mostraron cómo los usuarios del grupo DnsAdmins podían utilizar una "característica" en el protocolo de gestión de DNS de Microsoft para hacer que el servicio DNS cargue cualquier DLL. Este servicio se ejecuta en los Controladores de Dominio como NT AuthoritySystem, lo que permite a los DnsSAdmins escalar privilegios a SYSTEM en los DC (con permisos iguales al menos a los Administradores de Dominio). Este "bonito truco", como lo llamó el investigador original, Shay Ber, puede ser útil para los equipos rojos que exploran la escalada de privilegios AD y es una puerta trasera potencial para los atacantes en el controlador de dominio.

Lecturas relacionadas

En este post, ampliaré la investigación de Shay Ber mostrando cómo superar un problema con la técnica anterior y cómo hacerla más sigilosa. También revisaré los permisos necesarios para demostrar que un adversario podría utilizar esta táctica para dejar una puerta trasera a DC que probablemente no se notaría y podría eludir algunas herramientas.

Para recapitular la investigación previa realizada por Shay Ber y Nikhil Mittal, mostraron que es posible cargar una DLL arbitraria en un servicio DNS que se ejecuta en un Controlador de Dominio a través de los siguientes pasos:

  1. El atacante necesita ser parte del grupo DnsAdmins para ejecutar dnscmd y apuntar el servicio a un DLL en una ruta UNC.
  2. El atacante reinicia el servicio DNS usando "sc.exe stop/start dns"-esto es una limitación ya que las configuraciones por defecto no permiten a los usuarios de DnsAdmins parar e iniciar servicios.

Mi investigación amplía la comprensión de esta capacidad de ataque de las siguientes maneras:

  1. No es estrictamente necesario formar parte de DnsAdmins para llevar a cabo este ataque, sino únicamente tener acceso de lectura/escritura al contenedor MicrosoftDNS y acceso RPC al DC.
  2. Es posible reiniciar el servicio DNS sólo con los privilegios indicados en 1.

Por lo tanto, es posible para un atacante con privilegios suficientes crear/actualizar un usuario con permisos mínimos y sólo acceso directo de lectura/escritura al contenedor MicrosoftDNS. En la mayoría de los casos, este usuario pasaría "desapercibido", ya que los permisos del contenedor rara vez se supervisan. Este usuario podría pasar desapercibido y podría ser utilizado para ejecutar comandos arbitrarios con privilegios DC SYSTEM cargando una DLL en el proceso DNS.

Antecedentes de la investigación

Hace tres años, en el post de Medium "Feature, not bug: DnsAdmin to DC compromise in one line", Shay Ber señaló que cualquier miembro del grupo DnsAdmins podía hacer que el servicio DNS Server cargara una DLL como NT AuthoritySystem en el DC en el siguiente reinicio del servicio.

DnsAdmins por defecto no tiene el permiso requerido para reiniciar el servicio en el DC remotamente, lo que significa que los atacantes que quieran abusar de ello tendrán que esperar (o usar otros métodos) hasta que el servidor o servicio se reinicie para hacer correr su payload.

Mi misión de investigación era buscar una forma de forzar el reinicio del servicio o cargar la DLL instantáneamente y hacerlo de la forma más sigilosa posible. (Aunque tuviera los permisos para reiniciar usando sc.exe, generaría numerosos logs y probablemente sería detectado). Este enfoque resultó ser sorprendentemente fácil, pero tuvo algunas consecuencias inesperadas. Antes de seguir leyendo, recomiendo leer primero la investigación original de Ber.

Un nuevo comienzo
Empecé simplemente revisando las especificaciones MS-DNSP, buscando cualquier mención de la palabra Restart (Reiniciar) cuando me encontré con lo siguiente:

Reiniciar pszOperación
Figura 1: Reinicio de pszOperation

Esta línea indica que uno de los comandos que el servidor acepta (pszOperation) en R_DnssrvOperation es restart, que (como era de esperar) reiniciará el proceso del servidor DNS. ¡Suena perfecto!

Para hacerme la vida más fácil, miré la documentación de la herramienta dnscmd (herramienta CLI para la gestión de servidores DNS) y busqué una forma de utilizarla para enviar un comando de reinicio al servidor DNS, pero no encontré nada.

Pensé que debía buscar "reiniciar" en las cadenas de la herramienta y (sorprendentemente), ahí estaba:

Figura 2 Cadena de reinicio dentro de las cadenas de dnscmd
Figura 2: Cadena Restart dentro de las cadenas de dnscmd

Aunque ni la documentación de Microsoft ni la ayuda de la herramienta lo mencionan, existe un modificador "/Restart" que puedes utilizar en dnscmd para activar el reinicio del proceso de un servidor DNS.

Figura 3 Llamada exitosa al comando de reinicio
Figura 3: Llamada exitosa al comando de reinicio

El servicio activó un reinicio interno, llamando a una función interna llamada "reloadShutdown" y luego arrancando todo de nuevo sin terminar el proceso, a diferencia de un reinicio regular del servicio.

Así que ya sabía cómo activar una recarga y cargar la DLL al instante, pero ¿cuáles eran los permisos necesarios?

Volviendo a la documentación, la comprobación inicial de cualquier operación DNS sería probar las credenciales del cliente para el privilegio de Lectura contra el contenedor MicrosoftDNS. El privilegio de escritura contra el mismo objeto también es necesario para nuestras operaciones específicas (restart y ServerLevelPluginDll).

A estas alturas ya había disparado una recarga, haciendo que el servicio cargara la DLL enviada anteriormente (el comando mostrado en la sección del escenario) y dejando menos rastros tras de sí, ya que no se estaban generando logs sobre el reinicio del servicio o la creación de procesos.

Los registros que se generaron, ambos en el registro del Servidor DNS, fueron el Evento ID 770 (se ha cargado un plugin DLL a nivel de servidor) y el Evento ID 140:

Figura 4: Entradas de registro del servidor DNS

En la siguiente sección, explicaré por qué se genera este error. Si quieres saltarte los detalles, puedes saltar a la sección de "impacto potencial".

El error
Algo inesperado ocurrió al ejecutar el comando de reinicio: La DLL se cargó (como era de esperar), y el servicio continuó ejecutándose, pero se generó el siguiente registro en el log del Servidor DNS:

Figura 5: Registro de errores generado tras la operación de reinicio
Figura 5: Registro de errores generado tras la operación de reinicio

La comprobación del código de error mostró que había un problema con el punto final RPC (0x6cc - El punto final es un duplicado.).

Cuando intenté enviar cualquier otro comando al mismo servidor DNS, utilizando dnscmd, de repente nada funcionó:

Figura 6 Nada funciona
Figura 6: Nada funciona

Ni siquiera la consola de gestión de DNS funcionaba ahora:

Figura 7 Más errores
Figura 7: Más errores

Para entender lo que estaba fallando, utilicé ApiMonitor y vi que había un problema con el registro del endpoint después del reinicio.

Al reiniciar el servicio del servidor DNS de la forma habitual (por ejemplo, services.msc), el servicio se detiene y se inicia sin que se genere ningún error. Por lo tanto, el siguiente paso que tomé fue ver por qué un error no fue lanzado aquí a diferencia de cuando una recarga utilizando el comando /restart está siendo transmitida al servidor.

Sin embargo, ocurrió algo interesante. Tanto el reinicio como la recarga del servicio fallaron en la misma llamada a la API.

Ese mensaje te suena, ¿verdad? El servicio falló al desregistrar el endpoint RPC y luego generó un error duplicado al intentar utilizar el endpoint.

La explicación detrás del hecho de que no hubo errores posteriores después de un reinicio del servicio es que cuando se produce el reinicio del servicio, el proceso sale, lo que provoca que el endpoint se desregistre automáticamente. Esto no ocurre cuando se activa una recarga del servicio (el proceso no se reinicia, por lo que no se produce la salida del proceso).

Impacto potencial

Utilizando estos métodos, un atacante puede ejecutar DLL arbitrarias dentro del contexto de seguridad del servicio DNS.

Dado que el servicio DNS suele ejecutarse en controladores de dominio, esta vulnerabilidad ofrece a los atacantes la oportunidad de escalar privilegios para cualquier usuario del dominio que esté bajo su control. Como se describe en la siguiente sección, además de avanzar en su ataque actual, las características específicas de las ACL del contenedor Active Director ofrecen a los atacantes la oportunidad de crear "administradores durmientes" y usuarios sin privilegios que pueden escalar privilegios a voluntad.

Para que estos ataques funcionen, un atacante debe tener lo siguiente:

  • Dnscmd (no es necesario pero ahorra tiempo y esfuerzo)
  • RPC abierto a DC
  • Permisos de lectura y escritura en el contenedor MicrosoftDNS (en el contenedor del sistema)

Ejemplo de escenario

Los atacantes que logran comprometer a un usuario en el grupo DnsAdmin pueden expandir su posición de varias maneras. Además de la escalada de privilegios inmediata al usuario SYSTEM en un DC (permitiéndoles añadir usuarios Administradores de Dominio o incluso obtener una Skeleton Key), también pueden dar a un usuario con pocos privilegios la capacidad de elevar privilegios asignándole acceso de Lectura/Escritura al contenedor MicrosoftDNS como parte de su ataque inicial.

Este usuario podría ser creado por el atacante, o por un usuario existente con una contraseña comprometida o un SPN conocido para su posterior kerberoasting. Mientras que los grupos privilegiados de AD, como los administradores de dominio, a menudo se supervisan de cerca, las ACL de objetos exactos son notoriamente difíciles de supervisar con eficacia. Esto crea una situación en la que los usuarios parecen no tener privilegios pero, en realidad, pueden reiniciar el servicio DNS e inyectar DLL de nuevo para recuperar el acceso privilegiado, proporcionando una puerta trasera persistente en el entorno.

Figura 8: Usuarios del dominio

En la captura de pantalla anterior, el usuario "haxer" parece un usuario sin privilegios porque sólo es miembro de los usuarios del dominio. Pero todo lo que necesita para convertirse en Administrador de Dominio es tener RPC al DC y acceso de escritura a un recurso compartido accesible por el DC.

En este ejemplo, la DLL iniciará un intérprete de comandos en la carga que recibirá comandos de un archivo en un recurso compartido (command.txt) y escribirá la salida en otro archivo en el mismo recurso compartido (out.txt).

El atacante inicia sesión como usuario "haxer", actualmente no miembro de ningún grupo privilegiado, y crea un recurso compartido con acceso de lectura/escritura para todo el mundo con su DLL maliciosa en él:

Figura 9: El atacante inicia sesión como "haxer".

Ahora todo lo que el atacante necesita hacer es registrar la DLL como ServerLevelPluginDll en el DC, activar un reinicio del servicio, y comenzar a enviar comandos usando el archivo que él creará:

Figura 10: Registro de la DLL

Es importante recordar dos aspectos de este escenario:

  1. Si el DC no puede acceder a la ruta enviada como ServerLevelPluginDLL, el activador de reinicio hará que el servicio DNS finalice y el servicio no podrá iniciarse de nuevo hasta que el DC pueda acceder a la ruta o ésta se elimine del registro del DC. (Y como DnsAdmin, probablemente no podremos iniciar el servicio cuando esté caído).
  2. Debido al error descrito anteriormente, activar una recarga causará problemas con la duplicación del RPC Endpoint, y no podremos enviar más comandos ni activar otro reinicio:
Figura 11: El comando de reinicio falla

Registro y detección

Aquí hay algunos pasos que las compañías pueden tomar para registrar y detectar una intrusión potencial. Primero, es importante notar que si el proceso del Servidor DNS fue reiniciado usando el reinicio pszOperation, NO generará un registro con Event ID 7036 porque esto no es un reinicio de servicio.

1. Se creará el ID de evento 770 en el registro Servidor DNS en el DC cuando cargue la DLL después de un reinicio, con la ruta DLL especificada.

Figura 12: Evento 770 registrado

2. El ID de evento 140 se creará cuando se active un reinicio utilizando R_DnssrvOperation (sólo debido al error; lo ideal es que esto no ocurra en el futuro).

Figura 13: Evento 140 registrado

3. Supervise los cambios de ntSecurityDescriptor en MicrosoftDNS y el grupo DnsAdmins (ID de evento 5136).

4. Supervisar la adición de miembros al grupo DnsAdmins.

5 Trate a los usuarios y grupos que ya tienen esos permisos como Administradores de Dominio y monitorícelos en consecuencia.

6. Los usuarios y grupos con esos permisos deben añadirse al grupo Usuarios protegidos para mejorar la protección.

7. Utilizando IPSIDS, puede monitorizar las peticiones R_DnssrvOperation y R_DnssrvOperation2 desde ordenadores no administrados a servidores DNS.

8. Supervise los cambios en la ruta del registro "HKLMSYSTEMCurrentControlSetServicesDNSParametersServerLevelPluginDLL" en los servidores DNS.

Protección del servicio DNS de Microsoft

Al implementar estas mejores prácticas de registro y detección, su organización puede protegerse contra un escenario en el que los usuarios que ya tienen permisos para administrar el DNS puedan aprovecharlo para comprometer un controlador de dominio, o dejar una puerta trasera sigilosa en el dominio para intrusos no deseados.