Yuval Gordon Investigador de Segurança | Microsoft

Este artigo apresenta um novo ataque direccionado para as contas de serviço geridas em grupo (gMSA), denominado ataque "Golden GMSA", que permite aos atacantes descarregar atributos de chave de raiz do serviço de distribuição de chaves (KDS) e, em seguida, gerar a palavra-passe para todas as gMSAs associadas offline.

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 são habitualmente alteradas com regularidade, o que as coloca em risco, especialmente porque podem ser alvo de Kerberoasting ataques. A gMSA (group Managed Service Account; g minúsculo é um mistério) é um tipo especial de conta no Active Directory (AD) introduzido no Windows Server 2012 para resolver exactamente este problema. O único objectivo deste objecto é ser utilizado como uma conta de serviço, com a importante funcionalidade de rotação de palavras-passe. Uma conta gMSA pode ser utilizada por um ou mais servidores com serviços compatíveis.

A palavra-passe da gMSA é gerida pelo AD. É automaticamente alterada de 30 em 30 dias para uma palavra-passe gerada aleatoriamente de 256 bytes, tornando-a impossível de decifrar. Como 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 por trás desse tipo de conta é interessante. Os DCs graváveis gerem a palavra-passe da gMSA e rodam-na a cada 30 dias (por predefinição). Quando um servidor que utiliza esta conta precisa de utilizar a gMSA, começa por pedir a palavra-passe mais recente ao DC, recuperando um atributo chamado msDS-ManagedPassword. Este atributo é um BLOB (Binary Large Object) 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 é construída a pedido pelos DCs graváveis. Também sabemos que cada DC gravável pode construir o atributo, e o resultado será sempre o mesmo. Esta página mostra como a senha é gerada, mas não é detalhada o suficiente para permitir que nós mesmos a construamos.

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 ingredientes que o DC utiliza para gerar as palavras-passe, mas que nós não temos, são os seguintes atributos da chave de raiz 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 atacante descarrega os atributos relevantes de uma chave de raiz KDS e depois utiliza-os para gerar a palavra-passe para as contas gMSA associadas offline. O ataque Golden GMSA é algo semelhante ao ataque Golden Ticket, que permite aos atacantes que comprometem a conta krbtgt forjar Bilhetes de Concessão de Bilhetes (TGTs) desde que a palavra-passe 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 obter os atributos necessários de um objecto de chave de raiz KDS especificado ou utilizar valores fornecidos pelo utilizador para gerar uma GKE. A ferramenta também pode obter o msDS-ManagedPasswordID com base num SID gMSA e, claro, gerar a palavra-passe do 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.