Directory Permissions¶
Every object in Active Directory has an access control list, the same idea as NTFS. A normal user with Write on an OU can reset the passwords of every account in it; Write on a group lets them add themselves; Write on the domain root lets them grant themselves the replication rights that dump every hash. These are the ACLs the STIG calls out, plus how to read and fix them.
The tool¶
dsacls is built in and prints an object's ACL. dsa.msc → View → Advanced Features → right-click → Properties → Security shows the same thing with checkboxes. PowerShell's Get-Acl works with the AD: drive once the ActiveDirectory module is loaded.
dsacls "DC=corp,DC=local"
dsacls "OU=Staff,DC=corp,DC=local"
dsacls "CN=Domain Admins,CN=Users,DC=corp,DC=local"
Look for FULL CONTROL, WRITE, WRITE PROPERTY, WRITE PERMISSIONS, WRITE OWNER, or Reset Password granted to Everyone, Authenticated Users, Domain Users, Domain Computers, or a specific non-admin account. Read rights for Authenticated Users are normal; the directory is meant to be readable.
Remove an entry:
dsacls "OU=Staff,DC=corp,DC=local" /R "CORP\bob"
/R removes every ACE for that account on that object. Re-run dsacls to confirm.
Objects that must stay at their defaults¶
| Object | STIG | Default that matters |
|---|---|---|
| The domain root | WN22-DC-000150, 000180 | Authenticated Users: Read only. Anonymous logon: nothing. dsHeuristics not set to allow anonymous LDAP. |
| Domain Controllers OU | WN22-DC-000100 | Authenticated Users Read; Domain Admins, Enterprise Admins, SYSTEM Full Control; ENTERPRISE DOMAIN CONTROLLERS special |
| OUs the organization created | WN22-DC-000110 | Same shape. Any extra Allow beyond Read for a non-admin needs the README to explain it (a help desk group that resets passwords, for instance) |
| GPOs (the Policies container and each GPO) | WN22-DC-000090 | Authenticated Users Read and Apply; edit rights for Domain Admins, Enterprise Admins, SYSTEM only. See Group Policy and SYSVOL. |
| AdminSDHolder | Its ACL is copied to every protected group and admin account once an hour. A Write entry here for a normal user becomes Write on Domain Admins within the hour. |
A fast sweep for non-default write access across the directory:
Import-Module ActiveDirectory
$skip = 'NT AUTHORITY\SYSTEM','NT AUTHORITY\SELF','CORP\Domain Admins','CORP\Enterprise Admins','BUILTIN\Administrators','CORP\Key Admins','CORP\Enterprise Key Admins','NT AUTHORITY\ENTERPRISE DOMAIN CONTROLLERS','CREATOR OWNER'
Get-ADObject -Filter * -SearchScope Subtree | ForEach-Object {
(Get-Acl "AD:\$($_.DistinguishedName)").Access | Where {
$_.AccessControlType -eq 'Allow' -and $_.IdentityReference -notin $skip -and
$_.ActiveDirectoryRights -match 'Write|GenericAll|WriteDacl|WriteOwner|ExtendedRight'
} | Select @{n='Object';e={$_.DistinguishedName}}, IdentityReference, ActiveDirectoryRights
}
Replace CORP with the domain's NetBIOS name. On a small competition domain this runs in seconds; each line is an entry to explain or remove. Some default entries survive the filter (Account Operators, Print Operators, Exchange groups if present); read the identity before removing it.
Replication rights¶
Two extended rights on the domain root, Replicating Directory Changes and Replicating Directory Changes All, let the holder ask the DC for every password hash the way a second DC would. Only Domain Controllers, Enterprise Domain Controllers, Administrators, Domain Admins, and Enterprise Admins hold them by default.
dsacls "DC=corp,DC=local" | findstr /i "Replicating"
Any other name on those lines is someone who can dump the domain. Remove with dsacls "DC=corp,DC=local" /R "CORP\name".
The directory's own files¶
The database (ntds.dit) and its logs are the hashes on disk (STIG WN22-DC-000070). Defaults: SYSTEM and Administrators with Full control, inherited, nothing else.
icacls C:\Windows\NTDS
Users or a named account here means someone can copy the database. Remove the entry. The STIG also wants the database on a different volume from user data (WN22-DC-000120), which is a build-time decision you can note but not change on an image.
Verify¶
dsacls "DC=corp,DC=local" | findstr /i "Replicating"
icacls C:\Windows\NTDS
Run the PowerShell sweep and confirm the list contains only entries the README explains.
Example¶
The sweep lists CORP\jsmith with GenericAll on CN=Domain Admins,CN=Users,DC=corp,DC=local, and CORP\Domain Users with WriteDacl on OU=Servers,DC=corp,DC=local. Neither is in the README. dsacls "CN=Domain Admins,..." /R "CORP\jsmith" and dsacls "OU=Servers,..." /R "CORP\Domain Users". Then check whether jsmith already used the right: Get-ADGroupMember "Domain Admins" and the 4728 events from the Domain Auditing page.