Yuval Gordon Investigador de seguridad | Microsoft

En este artículo se presenta un nuevo ataque dirigido a las cuentas de servicios gestionados en grupo (gMSA), denominado ataque "Golden GMSA", que permite a los atacantes volcar los atributos de la clave raíz del servicio de distribución de claves (KDS) y, a continuación, generar la contraseña de todas las gMSA asociadas sin conexión.

TL;DR

Un atacante con altos privilegios puede obtener todos los ingredientes para generar la contraseña de cualquier gMSA en el dominio en cualquier momento con dos pasos:

  1. Recuperar varios atributos de la clave raíz KDS del dominio
  2. Utiliza el GoldenGMSA para generar la contraseña de cualquier gMSA asociado a la clave, sin una cuenta privilegiada.

Lecturas relacionadas

gMSA 101

Por lo general, las contraseñas de las cuentas de servicio no se renuevan con regularidad, lo que las pone en peligro, sobre todo porque pueden ser atacadas mediante Kerberoasting ataques. A gMSA (group Managed Service Account; la g minúscula es un misterio) es un tipo especial de cuenta en Active Directory (AD) introducido en Windows Server 2012 para resolver exactamente este problema. El único propósito de este objeto es ser utilizado como una cuenta de servicio, con la importante característica de la rotación de contraseñas. Una cuenta gMSA puede ser utilizada por uno o más servidores con servicios compatibles.

La contraseña de la gMSA es gestionada por AD. Se rota automáticamente cada 30 días a una contraseña generada aleatoriamente de 256 bytes, lo que la hace inviable de descifrar. Como documentación de Microsoft describe:

Descripción del servicio de distribución de claves de Microsoft en MS Docs

La contraseña se calcula basándose en un secreto que cambia periódicamente y en atributos sin nombre de la gMSA. El secreto utilizado se almacena en el objeto clave raíz KDS.

¿Cómo es posible que la contraseña rote automáticamente?

La idea detrás de este tipo de cuenta es interesante. Los DCs con permisos de escritura gestionan la contraseña de la gMSA y la rotan cada 30 días (por defecto). Cuando un servidor que utiliza esta cuenta necesita utilizar la gMSA, primero solicita la contraseña más reciente al DC recuperando un atributo llamado msDS-ContraseñaGestionada. Este atributo es un Objeto Grande Binario (BLOB) que contiene la contraseña.

El atributo msDS-GroupMSAMembership de un gMSA especifica quién está autorizado a obtener la contraseña. El DC escribible, a su vez, utiliza este atributo para validar que la persona que llama está autorizada a obtenerla. Hasta aquí, podemos ver una forma directa de abusar de ello: Si un atacante obtiene acceso a una cuenta que tiene acceso a msDS-ManagedPassword, el atacante puede leer la contraseña para el gMSA específico.

Almacenamiento de contraseñas

Los DC no suelen almacenar contraseñas en sus bases de datos, sino sólo secretos derivados de contraseñas. Esto plantea una pregunta: Supongamos que el DC con permisos de escritura no almacena la contraseña en texto claro; ¿cómo puede recuperarse leyendo el atributo msDS-ManagedPassword? Resulta que msDS-ManagedPassword es un atributo atributo construidolo que significa que este atributo no se almacena en el AD, sino que se calcula cuando un usuario autorizado intenta leerlo.

¿Cómo se construye la msDS-ManagedPassword?

Ahora sabemos que la contraseña es construida bajo demanda por los DCs escribibles. También sabemos que cada DC escribible puede construir el atributo, y el resultado será siempre el mismo. Esta página muestra cómo se genera la contraseña, pero no es lo suficientemente detallada como para permitirnos construirla nosotros mismos.

Buscar la función que construye este atributo nos llevaría a ntdsai.dll!dbGetConstructedAtt, que es la función responsable de construir atributos.

dbGetManagedServiceAccountPassword

Podemos ver una llamada a dbGetManagedServiceAccountPasswordpero interesa sólo en la contraseña y no todo el ManagedPasswordBlob. En más en la función finalmente nos lleva nos a a llamada a la función KdsCli.dllKdsGetGmsaPasswordBasedOnKeyId.

KdsGetGmsaPasswordBasedOnKeyId

Repasemos los parámetros de esta función:

  • _SecurityDescriptor es un descriptor de seguridad (SD) predefinido, codificado en ntdsai.dll, que concede permisos de lectura y escritura a S-1-5-9 (controladores de dominio de empresa), como se muestra en la siguiente captura de pantalla:
gmsaSecurityDescriptor
  • _SID es el ObjectSID del gMSA deseado.
  • _MsdsManagedPasswordID es un atributo del objeto gMSA que, entre otras cosas, hace referencia por GUID a la instancia de la Clave Raíz KDS utilizada por el gMSA para la generación de contraseñas.
    No encontramos documentación formal para este atributo, pero más vueltas nos ayudaron a averiguar cómo construirlo nosotros mismos con los parámetros que se muestran en la captura de pantalla de abajo.
Msds_ManagedpasswordID
  • _OutPassword es un puntero a un buffer que almacenará la contraseña.
  • El tamaño de la contraseña es el número de bytes que se escribirán en OutPassword. Tiene un valor predeterminado de 256.

Recuperación de la clave y construcción de la contraseña

El flujo de ejecución llega finalmente a la función GetKeyFromKdsService, que invoca al método RPC GetKey.

getKeyStatus

Podemos ver que los parámetros coinciden con la documentación de [MS-GKDI]

Método GetKey

Nota interesante: GetKey realiza comprobaciones de acceso contra el TargetSD proporcionado por el llamante, lo que significa que podemos invocar esta función con un descriptor de seguridad que nos conceda acceso, y el DC devolverá una clave. Desafortunadamente, el SD también se utiliza en el cálculo de la clave. Así que, aunque siempre podemos cambiar el DS para saltarnos las comprobaciones de acceso, a menos que el DS proporcionado sea válido, obtendremos una clave inválida. El único descriptor de seguridad válido que da como resultado una clave válida es el codificado que mencionamos antes (gmsaSecurityDescriptor), otorgando acceso sólo a controladores de dominio empresariales (S-1-5-9).

Si el llamador tiene los permisos requeridos, este método genera una clave y la devuelve en una estructura Group Key Envelope (GKE). Después de obtener la clave, podemos finalmente llamar a kdscli.dll!_GenerateGmsaPassword para generar la contraseña.

GenerarContraseñaGmsa

Los parámetros sexto y séptimo son opcionales y no afectan a la contraseña. Por lo tanto, para este propósito, podemos simplemente establecerlos en null.

Recapitulemos de la generación de contraseñas gMSA

Una contraseña gMSA se genera llamando a una función que reside en kdscli.dll (no se exporta, por desgracia), que tenemos en cualquier endpoint de Windows. Llamar a esta función requiere tres cosas:

  1. SID 
  2. msds-ManagedPasswordID de la gMSA (puede recuperarse mediante una consulta LDAP)
  3. GKE, que puede generarse llamando al método GetKey en el DC con privilegios elevados a través de RPC.

Implementación de GetKey y generación de contraseñas offline

Hemos intentado simplificar al máximo la generación de contraseñas gMSA, hasta el punto de poder hacerlo offline. La única llamada RPC en el proceso es para GetKey. Así que decidimos revertirlo y portarlo a código C# que genera una GKE.

Descubrimos que la clave cambia periódicamente, como documenta Microsoft. Pero la clave se deriva de atributos del objeto clave raíz KDS y tres enteros (L0KeyID, L1KeyID, L2KeyID) derivados de una marca de tiempo, como se muestra en la siguiente captura de pantalla.

GetCurrentIntervalID

La marca de tiempo actual se almacena en el atributo msDS-ManagedPasswordID del gMSA, legible por todos los usuarios del dominio por defecto, por lo que podemos recuperar la marca de tiempo y generar esos enteros.

Los únicos ingredientes que el DC utiliza para generar las contraseñas, pero que nosotros no tenemos, son los siguientes atributos de la clave raíz KDS:

  • cn
  • msKds-SecretAgreementParam
  • msKds-RootKeyData
  • msKds-KDFParam
  • msKds-KDFAlgorithmID
  • msKds-CreateTime
  • msKds-UseStartTime
  • msKds-Versión
  • msKds-DomainID
  • msKds-PrivateKeyLength
  • msKds-PublicKeyLength
  • msKds-SecretAgreementAlgorithmID

La recuperación de esos atributos requiere derechos de lectura y ampliados sobre el objeto clave raíz KDS, que por defecto sólo tienen los administradores de dominio. Sin embargo, estos valores NO se modifican periódicamente.

Esto significa que si comprometemos esos valores, podemos usarlos para calcular un GKE para cualquier gMSA asociado con la clave raíz del KDS y generar su contraseña offline.

El ataque dorado de la GMSA 

El ataque Golden GMSA se produce cuando un atacante vuelca los atributos relevantes de una clave raíz KDS y luego los utiliza para generar la contraseña de las cuentas gMSA asociadas sin conexión. El ataque Golden GMSA es algo similar al ataque Golden Ticket, que permite a los atacantes que comprometen la cuenta krbtgt falsificar Ticket Granting Tickets (TGTs) mientras la contraseña krbtgt permanezca inalterada.

Una diferencia notable entre un ataque Golden Ticket y el ataque Golden GMSA es que no conocemos una forma de rotar el secreto de la clave raíz KDS. Por lo tanto, si una clave raíz KDS se ve comprometida, no hay forma de proteger los gMSAs asociados a ella. La única mitigación en tal escenario es crear nuevos gMSAs con una nueva clave raíz KDS.

Armar el ataque Golden GMSA

Hemos convertido el ataque Golden GMSA en una herramienta que puede descargar aquí.

La herramienta GoldenGMSA Attack puede recuperar los atributos necesarios de un objeto clave raíz KDS especificado o utilizar valores proporcionados por el usuario para generar un GKE. La herramienta también puede recuperar el msDS-ManagedPasswordID basado en un gMSA SID y, por supuesto, generar la contraseña del gMSA offline.

Un atacante puede potencialmente usar la contraseña para comprometer servicios que usan el gMSA falsificando un Silver Ticket u obteniendo un ticket de servicio Kerberos para cuentas privilegiadas a través de S4U2Self. Si la gMSA tiene privilegios elevados, el atacante podría utilizarla para comprometer otros recursos y, en algunos casos, comprometer todo el bosque.

Ejemplo de ataque Golden GMSA

Un atacante puede utilizar la herramienta GoldenGMSA para enumerar todos los gMSAs y sus claves raíz KDS asociadas. Un atacante con privilegios elevados también puede utilizar la herramienta GoldenGMSA para volcar las claves raíz KDS.

gMSA_Enumerar

El atacante puede utilizar posteriormente el KDS volcado root key BLOB para generar la contraseña de la gMSA completamente fuera de línea.

gMSA_Compute

La contraseña está codificada en Base64 porque podría incluir caracteres no imprimibles.

Detección de un ataque Golden GMSA

Evento 4662 se ha realizado una operación en un objeto

El compromiso de un KDS root kno genera eventos de seguridad por defecto. Los defensores deben configurar un SACL en el KDS root kos objetos para todos los que lean el sitio msKds-RootKeyData atributo. Una vez la lista de control de acceso al sistema (SACL) cualquier intento deintento de volcar los datos clave de un KDS root key generará evento de seguridad 4662 en el DC donde el tipo de objeto es msKds-ProvRootKey y el nombre no es un DCcomo se muestra en la siguiente captura de pantalla:

Defensa contra los ataques de Golden GMSA

Las cuentas de servicio gestionadas por grupo son una gran característica de Active Directory que mitiga algunos riesgos asociados a las cuentas de servicio, como los ataques Kerberoasting. Sin embargo, las contraseñas asociadas a las gMSA se generan utilizando entradas que no pueden rotarse si se ven comprometidas, lo que permite a los atacantes con altos privilegios volcar claves raíz KDS y generar las contraseñas de las gMSA asociadas sin conexión mientras existan.

Los defensores deben supervisar el acceso anormal a las claves raíz KDS, como los no DC que leen el atributo msKds-ProvRootKey y los eventos de inicio de sesión anormales vinculados a cuentas gMSA.