Series · 3 partsActive Directory Architecture & InternalsPart 3 · You are here
- 1Multi-Forest Active Directory Architecture: How Forests, Trusts, DNS, and Tiered Services Actually Work
- 2Inside Kerberos Delegation: Why Multi-Tier Windows Apps Need It (and Why It Breaks)
- 3Active Directory as a Directed Graph: How Security Descriptors and Object ACLs Actually WorkYou are here
Why Active Directory Behaves Like a Directed Graph Database
When an administrator opens Active Directory Users and Computers, the directory appears as a hierarchical tree of Organizational Units (OUs). However, this organizational hierarchy merely dictates where objects reside in LDAP (distinguishedName); it conveys virtually nothing about administrative control relationships.
Under the hood, Active Directory attaches a binary nTSecurityDescriptor ([MS-DTYP §2.4.6]) attribute to every directory object in ntds.dit. Within this security descriptor resides an ordered Discretionary Access Control List (DACL) consisting of Access Control Entries (ACEs). Each ACE explicitly pairs an authenticated identity (Trustee SID) with a specific set of operations (AccessMask and optional ObjectType GUID) over the target object. When directory objects are treated as nodes and non-default ACE entries as directed edges, the directory transforms into a complex directed graph.
In GOAD (Game of Active Directory), BloodHound maps an unbroken eight-hop path in sevenkingdoms.local starting from tywin.lannister (whose cleartext password is recovered from a SYSVOL script) straight to the Forest Root Domain Controller KINGSLANDING$ (192.168.56.10). Deconstructing this path reveals how Windows Security Reference Monitor (SRM) access checks translate into administrative takeover.
nTSecurityDescriptor: The Security Reference Monitor (SRM) parses DACL entries (ACEs) against caller token SIDs to establish attack graph edges.1. Anatomy of an Object-Specific ACE (ACCESS_ALLOWED_OBJECT_ACE)
Unlike NTFS filesystem permissions where access masks simply encode generic read, write, and execute flags, Active Directory objects represent rich schema entities containing dozens of distinct attributes (member, servicePrincipalName, msDS-KeyCredentialLink) and specialized operations (User-Force-Change-Password, DS-Replication-Get-Changes-All).
To provide fine-grained delegation without exhausting bits in a 32-bit mask, Active Directory utilizes Object-Specific ACEs (ACCESS_ALLOWED_OBJECT_ACE, Type 0x05):
AccessMask(ActiveDirectoryRights): Encodes the operational class (0x00000020 = ADS_RIGHT_DS_WRITE_PROP,0x00000100 = ADS_RIGHT_DS_CONTROL_ACCESS,0x00040000 = WRITE_DAC,0x00080000 = WRITE_OWNER,0x10000000 = GENERIC_ALL).ObjectType(128-bit GUID): Restricts theAccessMaskto a specific attribute schema GUID or Extended Right GUID. WhenObjectTypeis null (GUID_NULL), the permission applies unconditionally to all attributes or operations across the object.
Inspecting non-inherited ACE entries across the eight targets in sevenkingdoms.local using impacket-dacledit:
Principal (Trustee SID) RightName Inherited Target Object (SID)
--------------------------------------- ------------------- --------- ---------------------------------------------
TYWIN.LANNISTER (...-1113) ForceChangePassword False JAIME.LANNISTER (...-1114)
JAIME.LANNISTER (...-1114) GenericWrite False JOFFREY.BARATHEON (...-1118)
JOFFREY.BARATHEON (...-1118) WriteDacl False TYRON.LANNISTER (...-1116)
TYRON.LANNISTER (...-1116) AddSelf False SMALL COUNCIL (...-1108)
SMALL COUNCIL (...-1108) AddMember False DRAGONSTONE (...-1109)
DRAGONSTONE (...-1109) WriteOwner False KINGSGUARD (...-1110)
KINGSGUARD (...-1110) GenericAll False STANNIS.BARATHEON (...-1120)
STANNIS.BARATHEON (...-1120) GenericAll False KINGSLANDING.SEVENKINGDOMS.LOCAL (...-1001)
sevenkingdoms.local: from entry point tywin.lannister through password resets, shadow credentials, DACL rewrites, group nesting, and object ownership to Tier-0 Forest Root takeover via RBCD and DCSync.2. Extended Rights: Operations Beyond Attribute Writes
Hop 1 demonstrates why the two-part ACE exists. A user password cannot be updated by setting a cleartext string over LDAP: unicodePwd requires specialized protocol wrapping. Resetting a password without knowing the existing credential is an Extended Right (ADS_RIGHT_DS_CONTROL_ACCESS / 0x100):
$ impacket-dacledit -action read -principal tywin.lannister -target jaime.lannister \
'sevenkingdoms.local/samwell.tarly:Heartsbane' -dc-ip 192.168.56.10
[*] ACE[0] info:
[*] ACE Type : ACCESS_ALLOWED_OBJECT_ACE
[*] AccessMask : ControlAccess (0x00000100)
[*] ObjectType : User-Force-Change-Password (00299570-246d-11d0-a768-00aa006e0529)
When AccessMask contains 0x00000100, the KDC resolves ObjectType against CN=Extended-Rights,CN=Configuration:
00299570-246d-11d0-a768-00aa006e0529(User-Force-Change-Password): Permitstywin.lannisterto issue RPCSamrSetInformationUser(net rpc password) or LDAPS password modifications (bloodyAD set password) againstjaime.lannister.1131f6ad-9c07-11d1-f79f-00c04fc2dcd2(DS-Replication-Get-Changes-All): When granted on the domain partition root (DC=sevenkingdoms,DC=local), permits non-DC accounts to invokeDRSGetNCChanges(DCSync), retrieving password hashes forest-wide.
3. Property Writes: Scoped Rights vs. GenericWrite
Hops 2, 4, and 5 illustrate property write delegation:
AddMember(SMALL COUNCILtoDRAGONSTONE):AccessMask = 0x20(WriteProperty) filtered byObjectType = bf9679c0-0de6-11d0-a285-00aa003049e2(the schema GUID for thememberattribute). Any member ofSMALL COUNCILcan append arbitrary user accounts intoDRAGONSTONE.AddSelf(tyron.lannistertoSMALL COUNCIL): CombinesADS_RIGHT_DS_SELF(0x08) with theSelf-MembershipGUID (bf9679c0-0de6-11d0-a285-00aa003049e2).tyron.lannisteris restricted strictly to appending his own identity to the group.GenericWrite(jaime.lannistertojoffrey.baratheon): GrantsWriteProperty(0x20) across all non-protected attributes without GUID filtering. Crucially,GenericWritelacksControlAccess(0x100), sojaimecannot directly force-resetjoffrey’s password.
Instead, GenericWrite enables three modern takeover primitives:
- Shadow Credentials (
msDS-KeyCredentialLink): Injecting an X.509 certificate public key structure intomsDS-KeyCredentialLink(5b47d60f-6090-40b2-9f37-2a4de88f3063) allows acquiring a Kerberos TGT and recovering the user’s NT hash via PKINIT without altering the user’s password. - Targeted Kerberoasting (
servicePrincipalName): Writing a fake SPN toservicePrincipalName, requesting a service ticket, and cracking the password hash offline. - Computer RBCD (
msDS-AllowedToActOnBehalfOfOtherIdentity): When the target is a computer, writing a machine account SID intomsDS-AllowedToActOnBehalfOfOtherIdentityenablesS4U2Proxyexecution asAdministrator.
4. Security Descriptor Manipulation: WriteDacl, WriteOwner, and GenericAll
Hops 3, 6, 7, and 8 target the nTSecurityDescriptor binary structure itself:
WriteDacl(0x00040000,joffreytotyron): Grants permission to rewrite the target’s DACL, permitting the injection of an explicitGenericAllACE.WriteOwner(0x00080000,DRAGONSTONEtoKINGSGUARD): Permits changing the object’s Owner SID. Under Windows SRM architecture ([MS-DTYP]), an object’s Owner inherently possesses implicitREAD_CONTROLandWRITE_DAC(0x00040000) permissions, even if the DACL explicitly denies access. Consequently,WriteOwneris mathematically equivalent toWriteDacl.GenericAll(0x10000000,stannistoKINGSLANDING$): Encompasses all standard, specific, and generic rights. HoldingGenericAllon a Domain Controller computer object enables immediate takeover via RBCD or Shadow Credentials, resulting inDCSyncdomain dominance.
Telemetry and Defensive Engineering
Directory Access Control Telemetry Matrix
| Event ID | Log Provider | Event Name | Technical Context |
|---|---|---|---|
5136 | Directory Service Changes | A Directory Object Was Modified | Logs attribute modifications including nTSecurityDescriptor, msDS-KeyCredentialLink, and msDS-AllowedToActOnBehalfOfOtherIdentity. |
4724 | Security | Password Reset Attempt | Tracks execution of User-Force-Change-Password extended right. |
4728 / 4732 / 4756 | Security | Member Added to Security Group | Logs additions to global, domain local, or universal security groups. |
4738 | Security | User Account Modified | Monitors additions of servicePrincipalName (Targeted Kerberoasting). |
// KQL Query: Detect Unauthorized Modifications to Active Directory Security Descriptors
SecurityEvent
| where EventID == 5136
| where AttributeLDAPDisplayName in~ ("nTSecurityDescriptor", "msDS-AllowedToActOnBehalfOfOtherIdentity", "msDS-KeyCredentialLink")
| project TimeGenerated, Computer, SubjectUserName, ObjectDN, AttributeLDAPDisplayName, OperationType
Remediation and Boundary Enforcement
- Enforce AdminSDHolder Protection: High-privilege objects (Domain Admins, Enterprise Admins) must remain protected by
AdminSDHolder. TheSDPropprocess runs every 60 minutes to overwrite unauthorized DACL alterations. - Audit Tier-0 Object Ownership: Ensure object ownership (
Owner SID) on Tier-0 accounts and groups is strictly assigned toDomain AdminsorEnterprise Admins. - Eliminate Transitive Permission Chains: Use BloodHound to audit and prune transitive permission chains linking Tier-2 or Tier-1 identities to Tier-0 assets.
Summary of ACL Primitives
| Right Name | Binary Representation (AccessMask + ObjectType) | GOAD Exploit Step | Execution Primitive | Detection Telemetry |
|---|---|---|---|---|
ForceChangePassword | 0x00000100 (ControlAccess) + User-Force-Change-Password | tywin → jaime | Overwrite unicodePwd via RPC/SAMR or LDAPS. | Event ID 4724; restrict helpdesk reset delegation. |
GenericWrite | 0x00020028 (ReadControl | Self | WriteProp) | jaime → joffrey | Shadow Credentials (msDS-KeyCredentialLink) or RBCD. | Event ID 5136 on sensitive LDAP attributes. |
AddSelf / AddMember | 0x00000008 / 0x00000020 + member GUID | tyron → SMALL COUNCIL → DRAGONSTONE | Inject user DN into group member attribute. | Event IDs 4728, 4732, 4756. |
WriteDacl | 0x00040000 (WRITE_DAC) | joffrey → tyron | Inject GenericAll ACE into target DACL. | Event ID 5136 on nTSecurityDescriptor. |
WriteOwner | 0x00080000 (WRITE_OWNER) | DRAGONSTONE → KINGSGUARD | Change Owner SID to gain implicit WRITE_DAC. | Event ID 5136; audit non-default object owners. |
GenericAll | 0x10000000 (GENERIC_ALL) | stannis → KINGSLANDING$ | Full object control; RBCD or Shadow Credentials on DC. | Protect Tier-0 with AdminSDHolder / SDProp. |
Evidence and limits
The ACE dumps, GUIDs, and eight-hop examples come from the GOAD directory used in Part 3. impacket-dacledit output was compared with the corresponding BloodHound edges and the Microsoft definitions of ACCESS_ALLOWED_OBJECT_ACE, access masks, and object-specific rights. The article therefore treats BloodHound as a path finder and the directory security descriptor as the authority.
This is not an exhaustive Windows authorization model. Inheritance, deny ACE ordering, AdminSDHolder, protected objects, validated writes, and application-specific checks can change effective access. A graph edge is a testable hypothesis until the precise ACE and target behavior are verified; the examples here were verified only in the isolated GOAD lab.
References
- Microsoft Open Specifications,
[MS-ADTS]§5.1.3 Authorization: learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts - Microsoft Open Specifications,
[MS-DTYP]§2.4.6SECURITY_DESCRIPTORandACEStructures: learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp - Orange Cyberdefense, GOAD (Game of Active Directory): orange-cyberdefense.github.io/GOAD
- MITRE ATT&CK, File and Directory Permissions Modification: Windows (
T1222.001): attack.mitre.org/techniques/T1222/001
How current is this note?
The latest source-review, content-update, or publication date is shown.
Primary public records were checked. Environment-specific behavior remains outside the claim unless separately reproduced.

