Yuval Gordon Sicherheitsforscher | Microsoft

In diesem Artikel wird ein neuer Angriff auf Group Managed Service Accounts (gMSA) vorgestellt, der als "Goldener GMSA"-Angriff bezeichnet wird. Er ermöglicht es Angreifern, die Root-Schlüsselattribute des Key Distribution Service (KDS) auszulesen und dann das Passwort für alle zugehörigen gMSAs offline zu generieren.

TL;DR

Ein Angreifer mit hohen Privilegien kann jederzeit in zwei Schritten alle Zutaten für die Generierung des Passworts einer beliebigen gMSA in der Domäne erhalten:

  1. Rufen Sie mehrere Attribute aus dem KDS-Stammschlüssel in der Domäne ab
  2. Verwenden Sie die GoldenGMSA um das Passwort einer beliebigen gMSA zu generieren, die mit dem Schlüssel verbunden ist, ohne ein privilegiertes Konto.

Verwandte Lektüre

gMSA 101

Die Passwörter von Dienstkonten werden in der Regel nicht regelmäßig gewechselt, was sie einem Risiko aussetzt, insbesondere weil sie durch Kerberoasting Angriffe. A gMSA (group Managed Service Account; klein geschriebenes g ist ein Geheimnis) ist ein spezieller Kontotyp in Active Directory (AD), der in Windows Server 2012 eingeführt wurde, um genau dieses Problem zu lösen. Der einzige Zweck dieses Objekts ist die Verwendung als Dienstkonto mit der wichtigen Funktion der Passwortrotation. Ein gMSA-Konto kann von einem oder mehreren Servern mit kompatiblen Diensten verwendet werden.

Das Passwort der gMSA wird von AD verwaltet. Es wird automatisch alle 30 Tage auf ein zufällig generiertes Passwort von 256 Bytes geändert, so dass es nicht geknackt werden kann. Wie Microsoft-Dokumentation beschreibt:

Microsoft Key Distribution Service Beschreibung aus MS Docs

Das Passwort wird auf der Grundlage eines Geheimnisses, das sich regelmäßig ändert, und unbenannter Attribute der gMSA berechnet. Das verwendete Geheimnis ist im KDS-Stammschlüsselobjekt gespeichert.

Automatisch rotierendes Passwort - wie kann das sein?

Die Idee hinter dieser Art von Konto ist interessant. Die beschreibbaren DCs verwalten das Passwort der gMSA und wechseln es alle 30 Tage (standardmäßig). Wenn ein Server, der dieses Konto verwendet, die gMSA benutzen muss, fordert er zunächst das neueste Passwort vom DC an, indem er ein Attribut namens msDS-ManagedPassword. Dieses Attribut ist ein Binary Large Object (BLOB), das das Kennwort enthält.

Das msDS-GroupMSAMembership-Attribut einer gMSA gibt an, wer das Kennwort erhalten darf. Die beschreibbare DC wiederum verwendet dieses Attribut, um zu überprüfen, ob der Anrufer berechtigt ist, es zu erhalten. Bis jetzt sehen wir einen einfachen Weg, dies zu missbrauchen: Wenn sich ein Angreifer Zugang zu einem Konto verschafft, das Zugriff auf msDS-ManagedPassword hat, kann der Angreifer das Kennwort für die spezifische gMSA lesen.

Passwort speichern

DCs speichern in der Regel keine Passwörter in ihren Datenbanken, sondern nur von Passwörtern abgeleitete Geheimnisse. Das wirft eine Frage auf: Angenommen, die beschreibbare DC speichert das Klartext-Passwort nicht. Wie kann es dann durch Lesen des Attributs msDS-ManagedPassword abgerufen werden? Es stellt sich heraus, dass msDS-ManagedPassword ein konstruiertes Attributist, d.h. dieses Attribut ist nicht im AD gespeichert, sondern wird berechnet, wenn ein autorisierter Benutzer versucht, es zu lesen.

Wie ist das msDS-ManagedPassword aufgebaut?

Wir wissen jetzt, dass das Passwort bei Bedarf von den beschreibbaren DCs erstellt wird. Wir wissen auch, dass jede beschreibbare DC das Attribut konstruieren kann und das Ergebnis immer dasselbe sein wird. Diese Seite zeigt, wie das Kennwort generiert wird, ist aber nicht detailliert genug, um es selbst zu konstruieren.

Die Suche nach der Funktion, die dieses Attribut konstruiert, würde uns zu ntdsai.dll!dbGetConstructedAtt führen, der Funktion, die für die Konstruktion von Attributen verantwortlich ist.

dbGetManagedServiceAccountPassword

Wir sehen einen Aufruf von dbGetManagedServiceAccountPassword, aber wir sind interessiert nur an das Kennwort und nicht die gesamte ManagedPasswordBlob. Unter weiter in der Funktion führt schließlich zu uns zu a Aufruf der der Funktion KdsCli.dll!KdsGetGmsaPasswordBasedOnKeyId.

KdsGetGmsaPasswordBasedOnKeyId

Schauen wir uns die Parameter dieser Funktion an:

  • _SecurityDescriptor ist ein vordefinierter Sicherheitsdeskriptor (SD), der in der ntdsai.dll fest einkodiert ist und Lese- und Schreibrechte für S-1-5-9 (Unternehmensdomänencontroller) gewährt, wie im folgenden Screenshot gezeigt:
gmsaSecurityDescriptor
  • _SID ist die ObjectSID der gewünschten gMSA.
  • _MsdsManagedPasswordID ist ein Attribut des gMSA-Objekts, das u.a. per GUID auf die KDS Root Key-Instanz verweist, die von der gMSA für die Passwortgenerierung verwendet wird.
    Wir haben keine formale Dokumentation für dieses Attribut gefunden, aber durch weiteres Nachforschen konnten wir herausfinden, wie wir es selbst mit den im Screenshot unten gezeigten Parametern konstruieren können.
Msds_ManagedpasswordID
  • _OutPassword ist ein Zeiger auf einen Puffer, in dem das Passwort gespeichert wird.
  • Passwortgröße ist die Anzahl der Bytes, die in OutPassword geschrieben werden. Der Wert ist hartkodiert und beträgt 256.

Abrufen des Schlüssels und Erstellen des Passworts

Der Ausführungsfluss gelangt schließlich zur Funktion GetKeyFromKdsService, die die RPC-Methode aufruft GetKey.

getKeyStatus

Wir können sehen, dass die Parameter mit der Dokumentation von [MS-GKDI]

GetKey-Methode

Interessante Anmerkung: GetKey führt Zugriffsprüfungen gegen die vom Aufrufer angegebene TargetSD durch, d.h. wir können diese Funktion mit einer Sicherheitsbeschreibung aufrufen, die uns Zugriff gewährt, und der DC wird einen Schlüssel zurückgeben. Leider wird die SD auch für die Berechnung des Schlüssels verwendet. Auch wenn wir den SD ändern können, um die Zugriffsprüfungen zu umgehen, erhalten wir einen ungültigen Schlüssel, wenn der SD nicht gültig ist. Der einzige gültige Sicherheitsdeskriptor, der zu einem gültigen Schlüssel führt, ist der bereits erwähnte fest kodierte Deskriptor (gmsaSecurityDescriptor), der nur Zugriff auf Unternehmensdomänencontroller (S-1-5-9) gewährt.

Wenn der Aufrufer über die erforderlichen Berechtigungen verfügt, erzeugt diese Methode einen Schlüssel und gibt ihn in einer Group Key Envelope (GKE) Struktur zurück. Nachdem wir den Schlüssel erhalten haben, können wir schließlich kdscli.dll!_GenerateGmsaPassword aufrufen, um das Passwort zu generieren.

GenerateGmsaPassword

Der sechste und siebte Parameter sind optional und haben keinen Einfluss auf das Passwort. Für diesen Zweck können wir sie also einfach auf null setzen.

Wiederholung der gMSA Passwortgenerierung

Ein gMSA-Passwort wird durch den Aufruf einer Funktion generiert, die sich in der kdscli.dll befindet (leider nicht exportiert), die wir auf jedem Windows-Endpunkt haben. Der Aufruf dieser Funktion erfordert drei Dinge:

  1. SID 
  2. msds-ManagedPasswordID der gMSA (kann mit Hilfe einer LDAP-Abfrage abgefragt werden)
  3. GKE, der durch den Aufruf der GetKey-Methode auf dem DC mit hohen Privilegien über RPC erzeugt werden kann

Implementierung von GetKey und Offline-Passwortgenerierung

Wir haben versucht, die Generierung von gMSA-Passwörtern so weit wie möglich zu vereinfachen, so dass sie offline durchgeführt werden kann. Der einzige RPC-Aufruf in diesem Prozess ist der für GetKey. Also haben wir beschlossen, den Prozess umzukehren und in C#-Code zu portieren, der einen GKE erzeugt.

Wir haben festgestellt, dass sich der Schlüssel regelmäßig ändert, wie von Microsoft dokumentiert. Der Schlüssel wird jedoch aus Attributen des KDS-Root-Schlüsselobjekts und drei Ganzzahlen (L0KeyID, L1KeyID, L2KeyID) abgeleitet, die von einem Zeitstempel abgeleitet sind, wie im folgenden Screenshot zu sehen ist.

GetCurrentIntervalID

Der aktuelle Zeitstempel ist im msDS-ManagedPasswordID-Attribut der gMSA gespeichert, das standardmäßig von allen Domänenbenutzern gelesen werden kann, so dass wir den Zeitstempel abrufen und diese Ganzzahlen erzeugen können.

Die einzigen Zutaten, die der DC zur Generierung der Passwörter verwendet, die wir aber nicht haben, sind die folgenden Attribute des KDS-Stammschlüssels:

  • cn
  • msKds-SecretAgreementParam
  • msKds-RootKeyData
  • msKds-KDFParam
  • msKds-KDFAlgorithmID
  • msKds-CreateTime
  • msKds-UseStartTime
  • msKds-Version
  • msKds-DomainID
  • msKds-PrivateKeyLength
  • msKds-PublicKeyLength
  • msKds-SecretAgreementAlgorithmID

Das Abrufen dieser Attribute erfordert Lese- und erweiterte Rechte für das KDS-Root-Schlüsselobjekt, die standardmäßig nur Domänenadministratoren haben. Diese Werte werden jedoch NICHT regelmäßig geändert.

Das heißt, wenn wir diese Werte kompromittieren, können wir sie verwenden, um einen GKE für jede gMSA zu berechnen, die mit dem KDS-Stammschlüssel verbunden ist, und ihr Passwort offline zu generieren.

Der Angriff der Goldenen GMSA 

Der Golden GMSA-Angriff erfolgt, wenn ein Angreifer die relevanten Attribute eines KDS-Root-Schlüssels ausspäht und sie dann verwendet, um das Kennwort für zugehörige gMSA-Konten offline zu generieren. Der Golden GMSA-Angriff ähnelt in gewisser Weise dem Golden Ticket-Angriff, der es Angreifern, die das krbtgt-Konto kompromittieren, ermöglicht, Ticket Granting Tickets (TGTs) zu fälschen, solange das krbtgt-Kennwort unverändert bleibt.

Ein bemerkenswerter Unterschied zwischen einem Golden-Ticket-Angriff und dem Golden-GMSA-Angriff besteht darin, dass uns keine Möglichkeit bekannt ist, das Geheimnis des KDS-Stammschlüssels zu drehen. Deshalb, wenn ein KDS-Stammschlüssel kompromittiert wird, gibt es keine Möglichkeit, die mit ihm verbundenen gMSAs zu schützen. Die einzige Abhilfe in einem solchen Szenario besteht darin, neue gMSAs mit einem neuen KDS-Stammschlüssel zu erstellen.

Der Angriff auf die Goldene GMSA als Waffe

Wir haben den Golden GMSA-Angriff in einem Tool bewaffnet, das Sie hier herunterladen können hier.

Das Tool GoldenGMSA Attack kann die erforderlichen Attribute von einem angegebenen KDS-Root-Schlüsselobjekt abrufen oder vom Benutzer bereitgestellte Werte verwenden, um einen GKE zu erzeugen. Das Tool kann auch die msDS-ManagedPasswordID auf der Grundlage einer gMSA-SID abrufen und natürlich das Passwort der gMSA offline generieren.

Ein Angreifer kann das Passwort verwenden, um Dienste zu kompromittieren, die die gMSA nutzen, indem er ein Silver Ticket fälscht oder ein Kerberos-Service-Ticket für privilegierte Konten über S4U2Self erlangt. Wenn die gMSA über hohe Privilegien verfügt, kann der Angreifer sie nutzen, um andere Ressourcen zu kompromittieren und in einigen Fällen sogar den gesamten Forest zu kompromittieren.

Beispiel eines Goldenen GMSA-Angriffs

Ein Angreifer kann das GoldenGMSA-Tool verwenden, um alle gMSAs und die zugehörigen KDS-Stammschlüssel aufzuzählen. Ein Angreifer mit hohen Rechten kann das GoldenGMSA-Tool auch verwenden, um die KDS-Root-Schlüssel auszulesen.

gMSA_Enumerate

Der Angreifer kann später die gedumpten KDS root key BLOB um das Passwort zu generieren der gMSA komplett offline zu generieren.

gMSA_berechnen

Das Passwort ist Base64-kodiert, da es nicht druckbare Zeichen enthalten könnte.

Erkennen eines Golden GMSA-Angriffs

Ereignis 4662 eine Operation wurde an einem Objekt durchgeführt

Der Kompromiss eines einer KDS root key erzeugt standardmäßig keine Sicherheitsereignisse. Verteidiger sollten eine SACL konfigurieren auf dem KDS root key Objekte für jeden, der liest die msKds-RootKeyData Attribut. Sobald die System-Zugriffskontrollliste (SACL) konfiguriert ist, wird jederVersuch, die Dump die Schlüsseldaten eines KDS root key erzeugt Sicherheitsereignis 4662 auf dem DC wobei die Objekttyp ist. msKds-ProvRootKey und das Konto Name ist nicht ein DCist, wie der folgende Screenshot zeigt:

Verteidigung gegen Golden GMSA-Angriffe

Gruppenverwaltete Dienstkonten sind eine großartige Active Directory-Funktion, die einige mit Dienstkonten verbundene Risiken wie Kerberoasting-Angriffe abmildert. Die mit gMSAs verknüpften Kennwörter werden jedoch mit Eingaben generiert, die nicht gedreht werden können, wenn sie kompromittiert werden. Dies ermöglicht es Angreifern mit hohen Privilegien, KDS-Root-Schlüssel auszulesen und die Kennwörter der verknüpften gMSAs offline zu generieren, solange sie existieren.

Verteidiger sollten anormale Zugriffe auf KDS-Root-Schlüssel überwachen, wie z.B. das Lesen des Attributs msKds-ProvRootKey durch Nicht-DCs und anormale Anmeldeereignisse im Zusammenhang mit gMSA-Konten.