Yuval Gordon Investigador de Segurança | Microsoft

Este artigo apresenta um novo ataque que tem como alvo as Contas de Serviço Geridas em Grupo (gMSA), denominado «ataque Golden GMSA», que permite aos atacantes extrair os atributos da chave raiz do Serviço de Distribuição de Chaves (KDS) e, em seguida, gerar offline a palavra-passe para todas as gMSAs associadas. 

TL;DR

Um atacante com privilégios elevados pode obter todos os ingredientes para gerar a palavra-passe de qualquer gMSA no domínio em qualquer altura com dois passos:

  1. Recuperar vários atributos da chave de raiz KDS no domínio
  2. Utilizar o GoldenGMSA para gerar a palavra-passe de qualquer gMSA associada à chave, sem uma conta privilegiada.

Leitura relacionada

Noções básicas de gMSA

As palavras-passe das contas de serviço não costumam ser atualizadas regularmente, o que as coloca em risco, especialmente porque podem ser alvo de ataques através de ataques de Kerberoasting ataques. Uma gMSA (conta de serviço gerida por grupo; o «g» minúsculo é um mistério) é um tipo especial de conta no Active Directory (AD) introduzido no Windows Server 2012 para resolver exatamente este problema. O único objetivo deste objeto é ser utilizado como conta de serviço, com a importante funcionalidade de rotação de senhas. Uma conta gMSA pode ser utilizada por um ou mais servidores com serviços compatíveis. 

A palavra-passe do gMSA é gerida pelo AD. É alterada automaticamente a cada 30 dias para uma palavra-passe gerada aleatoriamente com 256 bytes, tornando-a impossível de descodificar. Como descreve a documentação da Microsoft descreve:

Descrição do Microsoft Key Distribution Service do MS Docs

A palavra-passe é calculada com base num segredo que muda periodicamente e em atributos sem nome da gMSA. O segredo utilizado é armazenado no objecto de chave de raiz do KDS.

Palavra-passe de rotação automática - como é que isso é possível?

A ideia subjacente a este tipo de conta é interessante. Os controladores de domínio (DC) com permissão de gravação gerem a palavra-passe da gMSA e procedem à sua rotação a cada 30 dias (por predefinição). Quando um servidor que utiliza esta conta precisa de recorrer à gMSA, solicita primeiro a palavra-passe mais recente ao DC, recuperando um atributo denominado msDS-ManagedPassword. Este atributo é um Objeto Binário de Grande Tamanho (BLOB) que contém a palavra-passe.

O atributo msDS-GroupMSAMembership de um gMSA especifica quem está autorizado a obter a palavra-passe. O DC gravável, por sua vez, usa esse atributo para validar que o chamador está autorizado a obtê-lo. Até agora, podemos ver uma maneira simples de abusar dela: Se um atacante obtiver acesso a uma conta que tenha acesso a msDS-ManagedPassword, o atacante pode ler a palavra-passe para a gMSA específica.

Armazenamento de palavras-passe

Os DCs não costumam armazenar palavras-passe nas suas bases de dados, mas apenas segredos derivados de palavras-passe. Isso levanta uma questão: Suponhamos que o CD gravável não armazena a palavra-passe em texto claro; como é que esta pode ser recuperada através da leitura do atributo msDS-ManagedPassword? Acontece que msDS-ManagedPassword é um atributo atributo construídoo que significa que este atributo não está armazenado no AD, mas é calculado quando um utilizador autorizado tenta lê-lo.

Como é construída a msDS-ManagedPassword?

Sabemos agora que a palavra-passe é criada sob demanda pelos DCs graváveis. Sabemos também que qualquer DC gravável pode criar o atributo, e o resultado será sempre o mesmo. Esta página mostra como a senha é gerada, mas não é suficientemente detalhada para nos permitir construí-la nós próprios.  

Procurar a função que constrói este atributo levar-nos-ia a ntdsai.dll!dbGetConstructedAtt, que é a função responsável pela construção de atributos.

dbGetManagedServiceAccountPassword

Podemos ver uma chamada para dbGetManagedServiceAccountPasswordmas nós estamos interessados apenas na a palavra-passe em vez de todo o ManagedPasswordBlob. Investigando mais na a função acaba por nos levar nos a a chamada para a função KdsCli.dll!KdsGetGmsaPasswordBasedOnKeyId.

KdsGetGmsaPasswordBasedOnKeyId

Vamos rever os parâmetros desta função: 

  • _SecurityDescriptor é um descritor de segurança (SD) predefinido, codificado no ntdsai.dll, que concede permissões de leitura e escrita a S-1-5-9 (controladores de domínio empresarial), como se mostra na seguinte captura de ecrã:
gmsaSecurityDescriptor
  • _SID é o ObjectSID da gMSA pretendida.
  • _MsdsManagedPasswordID é um atributo do objecto gMSA que, entre outras coisas, referencia por GUID a instância da chave raiz KDS utilizada pelo gMSA para a geração de palavras-passe.
    Não encontrámos documentação formal para este atributo, mas uma análise mais aprofundada ajudou-nos a descobrir como construí-lo nós próprios com os parâmetros apresentados na captura de ecrã abaixo.
Msds_ManagedpasswordID
  • _OutPassword é um ponteiro para uma memória intermédia que irá armazenar a palavra-passe.
  • O tamanho da palavra-passe é o número de bytes que serão escritos em OutPassword. Tem um valor codificado de 256.

Recuperar a chave e construir a palavra-passe

O fluxo de execução acaba por chegar à função GetKeyFromKdsService, que invoca o método RPC GetKey.

getKeyStatus

Podemos ver que os parâmetros correspondem à documentação do [MS-GKDI]

Método GetKey

Nota interessante: GetKey efectua verificações de acesso em relação ao TargetSD fornecido pelo chamador, o que significa que podemos invocar esta função com um descritor de segurança que nos concede acesso, e o DC devolverá uma chave. Infelizmente, o SD também é utilizado no cálculo da chave. Assim, apesar de podermos sempre alterar o SD para contornar as verificações de acesso, a menos que o SD fornecido seja válido, obteremos uma chave inválida. O único descritor de segurança válido que resulta numa chave válida é o descritor codificado que mencionámos anteriormente (gmsaSecurityDescriptor), que concede acesso apenas a controladores de domínio empresarial (S-1-5-9).

Se o chamador tiver as permissões necessárias, este método gera uma chave e devolve-a numa estrutura de Envelope de Chave de Grupo (GKE). Depois de obter a chave, podemos finalmente chamar kdscli.dll!_GenerateGmsaPassword para gerar a palavra-passe.

GerarGmsaPassword

O sexto e o sétimo parâmetros são opcionais e não afectam a palavra-passe. Assim, para este efeito, podemos simplesmente defini-los como nulos.

Recapitulação da geração de palavras-passe gMSA

Uma palavra-passe gMSA é gerada chamando uma função que reside em kdscli.dll (não exportada, infelizmente), que temos em qualquer ponto de extremidade do Windows. Chamar esta função requer três coisas:

  1. SID 
  2. msds-ManagedPasswordID da gMSA (pode ser recuperado através de uma consulta LDAP)
  3. GKE, que pode ser gerado chamando o método GetKey no CD com privilégios elevados através de RPC

Implementação de GetKey e geração de palavras-passe offline

Tentámos simplificar a geração de palavras-passe gMSA tanto quanto possível, na medida em que podia ser feita offline. A única chamada RPC no processo é para GetKey. Então, decidimos reverter e portá-lo para o código C# que gera um GKE.

Descobrimos que a chave muda periodicamente, conforme documentado pela Microsoft. Mas a chave é derivada de atributos do objecto de chave de raiz KDS e de três números inteiros (L0KeyID, L1KeyID, L2KeyID) derivados de um carimbo de data/hora, como mostra a seguinte captura de ecrã.

GetCurrentIntervalID

O carimbo de data/hora actual é armazenado no atributo msDS-ManagedPasswordID do gMSA, legível por todos os utilizadores do domínio por predefinição, pelo que podemos obter o carimbo de data/hora e gerar esses números inteiros.

Os únicos elementos que o DC utiliza para gerar as palavras-passe, mas que não temos, são os seguintes atributos da chave raiz do KDS: 

  • cn
  • msKds-SecretAgreementParam
  • msKds-RootKeyData
  • msKds-KDFParam
  • msKds-KDFAlgorithmID
  • msKds-CreateTime
  • msKds-UseStartTime
  • msKds-Versão
  • msKds-DomainID
  • msKds-PrivateKeyLength
  • msKds-PublicKeyLength
  • msKds-SecretAgreementAlgorithmID

A recuperação desses atributos requer direitos de leitura e alargados no objecto de chave de raiz KDS, que apenas os administradores de domínio têm por predefinição. No entanto, esses valores NÃO são alterados periodicamente.

Isto significa que, se comprometermos esses valores, podemos utilizá-los para calcular uma GKE para qualquer gMSA associado à chave de raiz do KDS e gerar a sua palavra-passe offline.

O ataque dourado da GMSA 

O ataque Golden GMSA ocorre quando um invasor extrai os atributos relevantes de uma chave raiz KDS e, em seguida, os utiliza para gerar offline a palavra-passe das contas gMSA associadas. O ataque Golden GMSA é, de certa forma, semelhante ao ataque Golden Ticket, que permite aos invasores que comprometem a conta krbtgt falsificar Ticket Granting Tickets (TGTs), desde que a palavra-passe da conta krbtgt permaneça inalterada. 

Uma diferença notável entre um ataque Golden Ticket e o ataque Golden GMSA é que não temos conhecimento de uma forma de rodar o segredo da chave de raiz do KDS. Por conseguinte, se uma chave de raiz do KDS for comprometida, não há maneira de proteger os gMSAs associados a ela. A única atenuação neste cenário é criar novas gMSAs com uma nova chave de raiz KDS.

Armamento do ataque Golden GMSA

Transformámos o ataque Golden GMSA numa ferramenta que pode descarregar aqui.

A ferramenta GoldenGMSA Attack pode recuperar os atributos necessários a partir de um objeto de chave raiz KDS especificado ou utilizar valores fornecidos pelo utilizador para gerar uma GKE. A ferramenta também pode recuperar o msDS-ManagedPasswordID com base num SID de gMSA e, claro, gerar a palavra-passe da gMSA offline. 

Um atacante pode potencialmente usar a senha para comprometer os serviços que usam o gMSA forjando um Silver Ticket ou obtendo um ticket de serviço Kerberos para contas privilegiadas através do S4U2Self. Se o gMSA tiver privilégios elevados, o atacante pode usá-lo para comprometer outros recursos e, em alguns casos, comprometer toda a floresta.

Exemplo de ataque GMSA dourado

Um atacante pode usar a ferramenta GoldenGMSA para enumerar todos os gMSAs e suas chaves raiz KDS associadas. Um atacante com privilégios elevados pode também utilizar a ferramenta GoldenGMSA para descarregar as chaves de raiz do KDS.

gMSA_Enumerate

O atacante pode mais tarde usar o KDS descarregado root key BLOB para gerar a palavra-passe do gMSA completamente offline.

gMSA_Computar

A palavra-passe é codificada em Base64 porque pode incluir caracteres não imprimíveis.

Detectar um ataque Golden GMSA

Evento 4662: foi executada uma operação num objecto

O compromisso de um KDS root knão gera eventos de segurança por defeito. Os defensores devem configurar um SACL no o KDS root key objectos para todos os que lêem o msKds-RootKeyData atributo. Uma vez que a lista de controlo de acesso ao sistema (SACL) estiver configurada, qualquertentativa de descarregar os dados-chave de um KDS root key irá gerar evento de segurança 4662 no CD onde o tipo de objecto é msKds-ProvRootKey e o nome da conta não é um DCcomo demonstrado na seguinte captura de ecrã:

Defesa contra ataques da Golden GMSA

As contas de serviço geridas por grupos são uma excelente funcionalidade do Active Directory que atenua alguns riscos associados às contas de serviço, como os ataques Kerberoasting. No entanto, as palavras-passe associadas às gMSAs são geradas utilizando entradas que não podem ser rodadas se forem comprometidas, permitindo que os atacantes com privilégios elevados descarreguem as chaves de raiz do KDS e gerem as palavras-passe das gMSAs associadas offline enquanto existirem.

Os defensores devem monitorizar o acesso anormal às chaves de raiz do KDS, tais como DCs que não lêem o atributo msKds-ProvRootKey e eventos de início de sessão anormais associados a contas gMSA.