Wird das primaryGroupID-Attribut eines Benutzerkontos auf 512 gesetzt, wird es bei jeder Anmeldung zu einem vollwertigen Mitglied der Domain Admins. Das ist PrimaryGroupID Spoofing: versteckte Domain Admins Active Directory selbst rechnet den Wert direkt in das Kerberos-Token des Kontos ein — aber ADSI Edit, ein roher LDAP-Filter (member=...) und die meisten Audit-Exporte sehen davon nichts, weil sie nur die eine Hälfte dessen abfragen, wie AD Gruppenmitgliedschaft tatsächlich berechnet.
Was ist die primaryGroupID
Jedes Active-Directory-Benutzer- und Computerobjekt trägt ein primaryGroupID-Attribut: eine einzelne Ganzzahl, die die Relative Identifier (RID) der primären Gruppe des Kontos speichert. Es ist ein Überbleibsel aus den POSIX-Kompatibilitätsanforderungen von Windows NT, aus einer Zeit vor verschachtelten Gruppen in AD, und bleibt heute meist unangetastet auf seinem Standardwert — so sehr, dass ein aktueller r/activedirectory-Thread schlicht fragte, wofür das Feld „Primary Group" auf einem Benutzerobjekt eigentlich gut ist.
Die Standardwerte, abgeglichen mit Microsofts eigener Dokumentation zur Ereignisüberwachung und mit Semperis' Forschung zu diesem Attribut:
| Objekttyp | Standard-primaryGroupID | Gruppenname |
|---|---|---|
| Benutzer | 513 | Domain Users |
| Computer | 515 | Domain Computers |
| Domain Controller | 516 | Domain Controllers |
| Read-only DC | 521 | Read-only Domain Controllers |
Der für diesen Artikel entscheidende Wert: RID 512 ist Domain Admins.
Anders als gewöhnliche Gruppenmitgliedschaft — die im mehrwertigen member-Attribut des Gruppenobjekts liegt, mit einem passenden memberOf-Rückverweis am Benutzer — wird die primäre Gruppenmitgliedschaft ausschließlich am Konto gespeichert, als eine einzige Ganzzahl. Das Gruppenobjekt selbst verzeichnet darüber gar nichts.
Wie Active Directory tatsächlich berechnet, „wer in dieser Gruppe ist"
„Wer ist in Domain Admins" ist kein einzelnes Lookup. Die effektive Mitgliedschaft ist die Vereinigung zweier getrennter Dinge:
- Jedes Konto, das im
member-Attribut der Domain-Admins-Gruppe aufgeführt ist. - Jedes Konto, dessen
primaryGroupID-Attribut gleich 512 ist — der RID von Domain Admins — unabhängig davon, was immember-Attribut steht.
Nur die erste Hälfte ist am Gruppenobjekt gespeichert. Die zweite Hälfte liegt vollständig am Konto, und am Gruppenobjekt vermerkt nichts, dass diese Verknüpfung existiert. Tools, die Mitgliedschaft durch direkte Abfrage des Gruppenobjekts auflösen, rekonstruieren beide Hälften und zeigen das vollständige Bild. Tools, die nur den rohen member-Wert lesen, sehen nur die erste Hälfte.
TrustedSecs Forschung zu diesem Verhalten (Brandon Colley, veröffentlicht im Januar 2026) zeigt die Trennung direkt: Eine Abfrage von Get-ADGroupMember "Domain Admins" gegen die Gruppe liefert ein Konto, dessen Domain-Admins-Zugriff ausschließlich aus primaryGroupID stammt — das Cmdlet löst die Vereinigung auf. Active Directory Users and Computers und das Active Directory Administrative Center verhalten sich beim Öffnen des Members-Tabs der Gruppe genauso. Dieselbe Forschung zeigt aber, dass zwei Tools auf der anderen Seite der Trennlinie landen:
- ADSI Edit, das direkt das
member-Attribut durchsucht, listet das Konto nicht auf. - Ein roher LDAP-Filter wie
(member=CN=...)— auf dem Typ, aus dem die meisten selbstgebauten Export-Skripte, CSV-basierten Reporting-Jobs und SIEM-Ingest-Pipelines aufgebaut sind — übersieht es aus demselben Grund: Er fragt genau das Attribut ab, das nie berührt wurde.
Dieselbe Forschung zeigt eine zweite, engere Lücke: Get-ADGroupMember -Recursive durchläuft verschachtelte Gruppen, um die Mitgliedschaft zu erweitern, erfasst aber kein Konto, dessen primäre Gruppe auf eine Gruppe gesetzt ist, die innerhalb von Domain Admins verschachtelt ist, statt auf Domain Admins selbst. Rekursion erweitert die member-Kette; sie führt die primaryGroupID-Vereinigung nicht auf jeder Verschachtelungsebene erneut aus — derselbe transitive blinde Fleck, der bereits bei gefährlicher Gruppenverschachtelung behandelt wurde.
PrimaryGroupID Spoofing: Versteckte Domain Admins Active Directory nie auflistet
Ein Angreifer (oder ein Skript) mit Schreibzugriff auf das primaryGroupID-Attribut eines Zielbenutzers — ein irgendwo eine OU hinunter delegiertes GenericWrite-, GenericAll- oder eingegrenztes WriteProperty-Recht, dieselbe Klasse von ACL-Missbrauch, die BloodHound auf Benutzerobjekten bereits kartiert — setzt es auf 512. Active Directory akzeptiert dieses Schreiben nur bei einem Konto, das bereits ein explizites Mitglied der Zielgruppe ist — Microsofts eigene Anleitung zum programmatischen Setzen der primären Gruppe und Tenables Forschung zu diesem Attribut bestätigen beide, dass ein blankes Set-ADUser -Replace @{primaryGroupID=512} bei einem Konto scheitert, das noch nicht Mitglied ist, und dass nur ein Directory-Service-Bypass wie DCShadow es bei einem Konto setzen kann, das nie Mitglied war. Der gewöhnliche Weg sind drei Befehle, nicht einer:
Add-ADGroupMember -Identity "Domain Admins" -Members jdoe
Set-ADUser -Identity jdoe -Replace @{primaryGroupID=512}
Remove-ADGroupMember -Identity "Domain Admins" -Members jdoe -Confirm:$false
Bei der nächsten Kerberos-TGT-Anforderung des Kontos wird die primäre Gruppen-RID genau wie jede andere Gruppen-SID in das Token gefaltet. Das Konto authentifiziert sich nun mit Domain-Admins-äquivalentem Zugriff. Sobald der dritte Befehl abgeschlossen ist, steht das member-Attribut von Domain Admins wieder auf seiner ursprünglichen Liste — ein geplanter Diff von Gruppenexporten oder ein statisches Lesen des member-Attributs hat danach nichts mehr zu finden, auch wenn das kurze Hinzufügen und Entfernen jeweils ein Standard-Ereignis für Gruppenmitgliedschaftsänderungen auf dem Weg dorthin auslöst — im Gegensatz zu einem periodischen Export-Diff hat ein Echtzeit-Alarm auf genau diese Ereignisse also durchaus einen Moment, um es zu erfassen. Deshalb liest sich die Technik als PrimaryGroupID Spoofing: versteckte Domain Admins Active Directory selbst in jedes Token einrechnet, die aber die Kontrolle, die neue Admins erfassen soll, nie zu sehen bekommt.
Sicherheitsforscher Yuval Gordon dokumentiert in einem Beitrag auf Semperis' Blog eine weitere Erweiterung dieser Idee: die primaryGroupID-Änderung mit einem Deny-Read-Zugriffssteuerungseintrag auf das eigene primaryGroupID-Attribut des Benutzers zu koppeln, sodass selbst die vereinigungsbewussten Tools (ADUC, Get-ADGroupMember) den Wert nicht mehr lesen und die Mitgliedschaft gar nicht mehr melden können. Es ist eine reale Technik — aber Gordon macht deutlich, wo sie versagt:
„Dieser coole Trick funktioniert nicht bei Mitgliedern geschützter Gruppen wie Domain Admins... diese Technik funktioniert nicht bei Mitgliedern einer Gruppe, die durch den SDPROP-Prozess und AdminSDHolder geschützt ist, da wir uns auf die DACL verlassen, die in diesem Fall etwa jede Stunde einfach wieder auf die DACL von AdminSDHolder zurückgesetzt wird."
AdminSDHolders SDProp-Zyklus (etwa alle 60 Minuten) wendet erneut eine Vorlagen-ACL auf jedes Konto an, das er als Mitglied einer geschützten Gruppe betrachtet — das löscht den Deny-ACE. Weil eine reine primaryGroupID=512-Änderung die DACL des Kontos überhaupt nicht berührt, setzt SDProp sie nicht zurück — es entschärft nur den Deny-ACE-Versteck-Trick, nicht den zugrunde liegenden Spoof. Gordons eigenes Arbeitsbeispiel zielt auf eine ungeschützte Testgruppe statt auf DnsAdmins selbst — derselbe Beitrag merkt aber gesondert an, dass die Technik auch bei gewöhnlichen Gruppen wie DnsAdmins funktioniert, das seinen eigenen bekannten Weg zu Domain Admins hat. Die einfache Variante — primaryGroupID direkt auf 512 setzen, ohne den ACE — ist von AdminSDHolder ohnehin unberührt, und genau deshalb lohnt es sich, direkt darauf zu prüfen.
Erkennung
Das ist ein Fall, in dem die Überwachung von Windows-Ereignis-IDs tatsächlich zu Ihren Gunsten arbeitet. Microsofts eigene Referenz zur Sicherheitsüberwachung für Event-ID 4738 („Ein Benutzerkonto wurde geändert", unter der Unterkategorie Audit User Account Management) dokumentiert ein Feld Primary Group ID in den geänderten Attributdaten des Ereignisses, und die eigene Überwachungsempfehlung stellt es klar:
| Zu überwachendes Feld | Grund für die Überwachung |
|---|---|
| Primary Group ID ist nicht 513 | Normalerweise ist der Primary-Group-Wert für Domänen- und lokale Benutzer 513. Andere Werte sollten überwacht werden. |
Zwei unabhängige Prüfungen, die den beiden Dingen entsprechen, die tatsächlich erfasst werden müssen:
Echtzeit — die Änderung selbst überwachen
Ist Audit User Account Management aktiviert, löst jedes Schreiben von primaryGroupID Event-ID 4738 auf dem verarbeitenden DC aus, mit der neuen RID im Feld Primary Group ID. Alarmieren Sie bei jedem 4738, in dem dieses Feld belegt ist und der neue Wert nicht 513 ist (bzw. 515/516/521 für Computer und DCs).
Zeitpunktbezogen — nach bereits gespooften Konten fahnden
TrustedSecs Forschung liefert dafür einen direkten Einzeiler:
Get-ADUser -property primaryGroup,primaryGroupID -Filter {-not(primaryGroupID -like "513")}
Gegen eine Domäne mit einer sauberen Baseline ausgeführt, sollten die einzigen Treffer Domain Controller (516), RODCs (521) und — falls Ihre Umgebung sie noch vorsieht — POSIX-gemappte Dienstkonten mit dokumentiertem Grund sein. Jedes gewöhnliche Benutzerkonto mit 512, oder jede privilegierte RID, die es nicht haben sollte, ist ein Befund.
Keine der beiden Prüfungen hängt davon ab, das Domain-Admins-Gruppenobjekt überhaupt zu lesen — genau das ist der Punkt. Ein Review, das auf Get-ADGroupMember "Domain Admins" direkt gegen die Gruppe aufbaut, würde es laut derselben Forschung ebenfalls erfassen; ein Review, das auf einem LDAP-Export des member-Attributs aufbaut, oder ein Tool, das diesen Export als Wahrheit behandelt, wird es nicht.
Remediation
- Führen Sie die obige Suche über jede Domäne im Forest durch, nicht nur die, die Domain Admins hostet — PrimaryGroupID-Missbrauch gegen eine verschachtelte/lokale Gruppe in einer Kind-Domäne ist für
member-Attribut-Exporte genauso unsichtbar. - Setzen Sie jedes nicht konforme Konto zurück auf seinen korrekten Standardwert (513 für Standardbenutzer), sofern kein dokumentierter, aktueller Geschäftsgrund für einen anderen Wert vorliegt.
- Aktivieren Sie Audit User Account Management auf allen Domain Controllern, falls noch nicht geschehen, damit Event-ID 4738 tatsächlich erzeugt und an Ihr SIEM weitergeleitet wird.
- Bauen Sie jedes automatisierte Privileged-Access-Review, das
memberdirekt abfragt — via ADSI Edit, einen rohen(member=...)-LDAP-Filter oder ein gleich gebautes Export-Skript — so um, dass es stattdessenGet-ADGroupMembergegen die Gruppe aufruft oder explizit eineprimaryGroupID-Suche mit einbezieht. Das Review, das das Sicherheitsnetz sein sollte, ist genau die Kontrolle, die diese Technik aushebelt. - Prüfen Sie, wer
WriteProperty/GenericWrite/GenericAllauf Benutzerobjekten hält und wer Mitglieder zu Domain Admins selbst hinzufügen kann — der gewöhnliche Weg zu dieser Technik braucht beides: das Recht, das Zielkonto kurz zu Domain Admins hinzuzufügen, und das Recht, dessenprimaryGroupIDzu schreiben. Jedes einzelne davon, unterhalb der eingebauten Admin-OUs delegiert, ist für sich genommen ein Befund.
Wie EtcSec das erkennt
Die PRIMARYGROUPID_SPOOFING-Prüfung von EtcSec führt als laufende Kontrolle dieselbe Art von Suche durch: Jedes Audit vergleicht die primaryGroupID jedes Kontos mit ihrem erwarteten Standardwert und markiert Konten, deren primäre Gruppe ohne dokumentierten Grund abweicht — und schließt damit genau die Lücke, die ein reiner member-Attribut-Export offenlässt. Befunde erscheinen zusammen mit dem Schreibrechte-Review (ACL_WRITE_PROPERTY_EXTENDED), das zeigt, wer die Änderung überhaupt vornehmen könnte, und zusammen mit der Überwachung privilegierter Gruppen (PRIVILEGED_GROUP_MEMBER_CHANGES), sodass Sie direkt nebeneinander sehen, welche Rechteeskalationspfade Ihre member-Attribut-Alarmierung tatsächlich abdeckt.
Entdecken Sie die Identity-Security-Seiten zu diesem Thema
