ADPRIV-020: AdminSDHolder Protected Object Audit

Platform
Active Directory
Category
AD Privileged Account Security
Severity
Critical
Zero Trust pillar
Identity (weight 2)
Golden fixtures
2
Branch coverage
Observed: fixtures prove the verdicts they exercise
Provenance
baseline

What it checks

The check binds to CN=AdminSDHolder,CN=System,DC=domain,DC=tld via LDAP and reads the nTSecurityDescriptor attribute. Every ACE in the DACL is parsed for trustee (IdentityReference / SID), ActiveDirectoryRights, AccessControlType, IsInherited, ObjectType GUID, and InheritedObjectType GUID. ACEs are compared against the Microsoft-documented baseline (SYSTEM, BUILTIN\Administrators, Domain Admins, Enterprise Admins, Authenticated Users with limited read, Pre-Windows 2000 Compatible Access on legacy domains, and the Enterprise Domain Controllers principal). Any of the following raise a finding: - A non-default trustee holding GenericAll, GenericWrite, WriteDacl, WriteOwner, WriteProperty, or AllExtendedRights - An explicit ACE granting the User-Force-Change-Password extended right (00299570-246d-11d0-a768-00aa006e0529) to a non-default principal - An ACE on the dSHeuristics-controlled adminCount-protected attribute set granted to a non-Tier-0 identity - Deny ACEs added to block defenders from reading or auditing the object - An ACE whose trustee resolves only as a raw SID (orphaned or foreign-domain principal) The check also reads the dSHeuristics attribute on CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,DC=domain,DC=tld to detect tampering with the protected-group list (the 16th character of dSHeuristics governs which groups SDProp protects).

Why it matters

AdminSDHolder is one of the highest-value persistence primitives in Active Directory. Write access to its DACL is functionally equivalent to permanent Domain Admin. SDProp (the Security Descriptor Propagator thread on the PDC emulator) re-copies the AdminSDHolder DACL onto every protected object on an hourly cycle, overwriting any defender remediation. An ACE planted on AdminSDHolder propagates within 60 minutes to Domain Admins, Enterprise Admins, Schema Admins, Administrators, Backup Operators, Print Operators, Server Operators, Account Operators, Replicator, Domain Controllers, Read-only Domain Controllers, Enterprise Read-only Domain Controllers, the Administrator account, and krbtgt. The attacker can then reset krbtgt to forge Golden Tickets, DCSync any account, and re-enter the environment at will. Because the ACE is re-applied every cycle, defenders who only clean up the protected groups (without cleaning AdminSDHolder itself) will see the attacker right come back automatically. This technique was first documented publicly by Sean Metcalf in 2015 and remains in the playbook of every mature adversary group, including the actors tracked by Mandiant as APT29 and the various ransomware affiliates that intrude via privilege escalation.

Attack path

1. Initial recon: the attacker enumerates AD ACLs with BloodHound (SharpHound -CollectionMethod ACL,DCOnly) or PowerView (Get-DomainObjectAcl -SearchBase "CN=AdminSDHolder,CN=System,DC=corp,DC=tld" -ResolveGUIDs). 2. Edge discovery: BloodHound surfaces a GenericAll, WriteDacl, WriteOwner, or AllExtendedRights edge from a compromised principal to the AdminSDHolder object. Common paths are over-delegated helpdesk groups, legacy service accounts with stale rights, or nested membership through an Exchange or Server Operators group. 3. ACE plant: with WriteDacl rights, the attacker adds an ACE granting their controlled principal FullControl. Example with PowerView: Add-DomainObjectAcl -TargetIdentity "CN=AdminSDHolder,CN=System,DC=corp,DC=tld" -PrincipalIdentity attacker -Rights All. Equivalent with dsacls: dsacls "CN=AdminSDHolder,..." /G attacker:GA. 4. Wait for SDProp: the PDC emulator runs SDProp every 60 minutes (registry value AdminSDProtectFrequency under HKLM\SYSTEM\CurrentControlSet\Services\NTDS\Parameters can change this, default is 3600 seconds). The attacker can force propagation immediately by writing FixUpInheritance = Yes to the RootDSE. 5. Persistence achieved: the ACE now exists on Domain Admins, Enterprise Admins, krbtgt, and every other protected object. The attacker can reset krbtgt twice for a Golden Ticket, run DCSync (mimikatz lsadump::dcsync, secretsdump.py), or add themselves to Domain Admins at any future date without needing the original compromised account. 6. Stealth refinement: the attacker may bury the ACE under inheritance flags, use a SID that no longer resolves to a name (orphaned SID), or use Dangerous Variant 2 from the SpecterOps ACE Up The Sleeve paper (a tightly-scoped ACE on a single inherited object type that does not show up in default DACL views). Some operators clear adminCount = 0 on accounts to remove them from the protected set after they finish, which itself is a detectable anomaly.

How Guerrilla assesses it

Guerrilla resolves the AdminSDHolder DN by appending CN=AdminSDHolder,CN=System, to the current Get-ADDomain.DistinguishedName and reads nTSecurityDescriptor via Get-ADObject -Properties nTSecurityDescriptor. The DACL is walked through the .NET ActiveDirectorySecurity.Access collection. Each ACE is normalized (IdentityReference resolved via SecurityIdentifier.Translate), classified as inherited / explicit, and compared against an embedded baseline of default trustees and rights. ObjectType GUIDs are mapped to their semantic names (User-Force-Change-Password, DS-Replication-Get-Changes, DS-Replication-Get-Changes-All, Self-Membership) using the schema GUID catalog. The check also reads the dSHeuristics attribute and the AdminSDProtectFrequency registry value (best-effort, requires remote registry) so any tampering with the SDProp cadence or the protected-group set is reported alongside the DACL findings. The check uses pure LDAP and does not require the AD PSDrive, so it works against any reachable DC, including DCs in domains where RSAT is not installed locally. Findings include the DN, trustee, rights mask, AccessControlType, IsInherited flag, and the resolved ObjectType GUID so a triage analyst can map each ACE back to its concrete capability.

Recommended value

AdminSDHolder ACL contains only default entries with no unauthorized or unexpected ACEs

Remediation

Review the AdminSDHolder ACL at CN=AdminSDHolder,CN=System,DC=domain using Get-ACL or ADSIEdit. Compare against the documented baseline. Remove any non-default ACEs immediately. Monitor for modifications to AdminSDHolder as part of ongoing security monitoring

Fixture-proven verdicts

Every verdict below is proven by a golden fixture in the module's gating test suite. This table derives from the last green run; it cannot be edited by hand.

Verdict scenarios for ADPRIV-020
ScenarioExpected verdict
no-dataNot Assessed
throttledNot Assessed

Framework mappings

NIST SP 800-53
AC-6, AC-3, AU-6
ANSSI
R6
CIS AD Benchmark
4.7.1
MITRE ATT&CK
T1222.001, T1078.002