AD-PRIV-007: Membership hidden through primaryGroupID¶
high Privileged access MITRE ATT&CK T1078.002, T1564 Reads: LDAP
Enabled accounts are made members of a privileged or domain controller group through primaryGroupID, which does not appear in the group's member list.
Also known as: primarygroupid
Why it matters¶
Every account has a primary group, stored as a RID in primaryGroupID (513 Domain
Users for users, 515 Domain Computers for computers, 516 Domain Controllers for DCs).
The account is a member of that group for every access check, but the membership is
not written to the group's member attribute or to the account's memberOf. Tools
that list members from member, including the Members tab and many scripts, do not
show it.
An attacker who had Domain Admin rights for a moment can set an account's
primaryGroupID to 512 and keep a domain admin that does not appear in Domain Admins.
Setting the primary group of a user or a workstation to 516 gives it every right granted
to Domain Controllers, such as Replicating Directory Changes All on the domain object
(half of what DCSync needs), again without any visible membership.
How ad-doctor detects it¶
For every enabled account in the LDAP snapshot, ad-doctor compares primaryGroupID
with two lists:
- users (not computers) whose primary group is 512 (Domain Admins), 518 (Schema Admins) or 519 (Enterprise Admins);
- any account that is not a registered DC whose primary group is 516 (Domain
Controllers), 521 (Read-only Domain Controllers) or 498 (Enterprise Read-only Domain
Controllers). A DC has
SERVER_TRUST_ACCOUNTorPARTIAL_SECRETS_ACCOUNTinuserAccountControl, and annTDSDSAobject when the snapshot holds that data: a flag alone does not count (AD-INF-014).
Examples: hidden_admin (primary group Domain Admins),
WS01$ (primary group Domain Controllers, but not a DC).
These accounts are also added back into the tier-0 groups for every other check, so AD-PRIV-001 counts them and AD-PATH-001 treats them as tier 0.
Attributes and probes read
primaryGroupIDuserAccountControl
Severity¶
Always high. The account holds tier-0 rights (or the rights of a domain controller) and the usual membership reviews do not show it, which is typical of a backdoor.
False positives and limits¶
- No legitimate configuration needs these values. Some old provisioning tools set
primaryGroupIDto an admin group when creating admin accounts; the fix is the same, with the account added to the group throughmemberinstead.
Fix¶
-
Find every account with a non-default primary group (read-only):
-
Investigate before changing anything. An unexplained value is a sign of a past compromise: check
whenChanged, the replication metadata ofprimaryGroupID(repadmin /showobjmeta) and who could write the attribute. -
Set the primary group back to 513 for users and 515 for computers (the same command ad-doctor writes with
--fixes). The account must already be a member of the target group, which Domain Users and Domain Computers normally are: -
If the account really needs the rights, add it to the group through
member(Add-ADGroupMember) so it shows in reviews, then reset the primary group. -
Rotate the credentials of the account and of anything it could reach while it held the hidden rights.
Verify¶
To accept the risk instead, add an entry to the file passed with --accept (see accepted risks):
[[accept]]
check = "AD-PRIV-007"
objects = ["..."] # optional; without it the whole check is accepted
reason = "..."
expires = 2027-03-31
Related checks¶
References¶
Microsoft and vendors
Specifications
MITRE ATT&CK
Available since 0.1.0.