The Active Directory Access Control List Explained logo

The Active Directory Access Control List(AD ACL) is one of those rarely explained security risks with a profound impact. The root vulnerability of many Active Directory attacks comes down to weak permissions on AD objects. Domain lateral movement, escalation of domain privileges, and DCSync attacks are only possible through abusing the Active Directory Access Control List. Yet, I spent ten years as a Windows System Admin but never had to learn about the Active Directory Access Control List until I moved into Pentesting.

In this post, I will explain the Active Directory Access Control Lists, how they control rights/permissions, and how others inherit rights. This blog post serves as a reference point for other blogs exploring specific Active Directory attacks, like a DCSync Attack.

I use PowerShell-focused methods in this blog to audit and review AD ACLs since the GUI method is limited at scale. If you want a GUI-focused explanation, see the source list at the bottom of this post.


Auditing Active Directory With AD-PowerAdmin

Auditing Active Directory ACLs for weaknesses is a lot of work. So, I created a PowerShell module to do the hard work for me. AD-PowerAdmin is a tool I made to streamline Active Directory security tasks.

The Active Directory Access Control list auditing module can be used inside AD-PowerAdmin or as a standalone module.

AD-PowerAdmin AdAccessRights Commands Highlights

  • Get-AdAcl – Get the ACL of an AD object and return an array of ACE hashtables—an AD-optimized version of Get-ACL.
  • Get-ExtendedAcl – Convert an ACE into human-readable form, enumerate who can use the ACE, and create an easy-to-follow explanation of what the ACE does.
  • Get-AdGuid – Return a variable containing AD GUIDs, their human-readable name, and their objectClass.
  • And more!
git clone https://github.com/Brets0150/AD-PowerAdmin.git
cd ./AD-PowerAdmin
Import-Module .\Modules\AD-PowerAdmin_AdAccessRights.psd1 -Force

Get-AdAcl -AdObjectPath 'OU=Network.Groups,DC=acme,DC=com' | Get-ExtendedAcl

# There will be many ACEs, but I am only showing one here as an example.

AceApplicableTo          : OU=Network.Groups,DC=acme,DC=com
SecurityPrincipal        : BUILTIN\Pre-Windows 2000 Compatible Access
AdRights                 : ListChildren
Access                   : Allow
RightObjectName          : All
IsInherited              : True
Inheritance              : All
InheritedObjectTypeName  : Any
ExplainAce               : The "BUILTIN\Pre-Windows 2000 Compatible Access" group has Allow ListChildren rights to "All" objects, object attributes, and ExtendedRights on
						"OU=Network.Groups,DC=acme,DC=com", and all child descendent objects of "OU=Network.Groups,DC=acme,DC=com", with the AD objectClass of "Any".
SecurityPrincipalMembers : {@{SamAccountName=FL-222$; DistinguishedName=CN=FL-222,OU=Domain Controllers,DC=acme,DC=com; ObjectType=computer; RightObjectName=All; AdRights=ListChildren;
						InheritedRightFrom=BUILTIN\Pre-Windows 2000 Compatible Access; AceApplicableTo=OU=Network.Groups,DC=acme,DC=com}}

Active Directory Access Control List(ACL) Overview

An Access Control List (ACL) is a method for managing resource access. In this context, we’re focusing on the ACL in a Windows Active Directory Server, which is distinct from the ACL in the Windows file system (NTFS).

Read this long ass blog to understand AD ACL or Just run Bloodhound meme

An ACL comprises multiple Access Control Entries (ACEs). Each ACE specifies a right or a set of rights that one Active Directory (AD) object has over another. Furthermore, an ACE outlines how parent rights will pass down to child AD objects.

Rights, also called permissions, can apply to the entire object (object rights) or specific attributes of the object (attribute rights). These rights can propagate down, meaning that a right assigned at a higher level can affect all subordinate levels.

Every individual object inside an Active Directory domain has an ACL. For example, an OU called “US.SalesTeam” has an ACL. Inside that ACL is an ACE, which gives the “Update password” right to members of the “HelpDeskGroup.” We assigned the “HelpDeskGroup” rights at the object(US.SalesTeam) we want to give them privileges over.

-- Key Terms --
Access Control List(ACL) - A collection of Access Control Entries(ACE) applied to an object.

Access Control Entries(ACE) - An ACE defines another object's rights on the object the ACE is applied to and how the object's descendants inherit those rights.

Active Directory Object - An AD Object can be a User, Computer, Service Account, Group, Organization Unit(OU), or one of many types. Everything inside AD is an object. Each object contains a list of object attributes.  

AD Object Attributes - Object Attributes define what the object is and other data about the object. For example, the AD object attributes for the User account "Bob", has an "objectClass" of "User", "SamAccountName" of "Bob", "displayName" of "Bobby.M", etc.. 

Permissions vs Rights - These two terms are interchangable when discussing Windows ACEs, or file permissions.

Security Descriptor - A data structure that details an object's ownership, primary group, access permissions (DACL), and access attempt logging (SACL).

Gathering the Domain Root ACL with PowerShell

Breaking Down the AD ACE ObjectType meme

The Active Directory Domain Root object is the topmost object in the AD tree; everything is beneath it. Rights assigned at this level can affect the whole domain. If you are an attacker looking to perform a DCSync attack, the Domain Root object is where you would look for weak permission sets. Since the Domain Root object has such a high impact on security, and I originally wrote this explanation for a DCSync attack blog, our example moving forward is the ACL from this object.

We’ll use PowerShell to retrieve the ACL for the root domain object. This can be done from a domain-joined system with the ActiveDirectory PowerShell Module installed or directly from the domain controller. Let’s begin by executing the following commands.

# Get the Root Domain ACL and store it in the $ACL variable.
PS> $ACL = (Get-Acl "AD:$($(Get-ADDomain).DistinguishedName)").Access

# Same command as above, just spelled out.
PS> $ACL = (Get-Acl "AD:DC=acme,DC=com").Access

# This ACL lookup can be done on any AD Object using the objects DistinguishedName.
PS> $ACL = (Get-Acl "AD:OU=Network.Groups,DC=acme,DC=com").Access

# Output the contents of $ACL to console.
PS> $ACL

We now have the ACL(a list of ACEs) of the domain root stored in the “$ACL” variable. Next, we will review the ACEs and their attributes.


Understanding Active Directory Access Control Entries (ACE)

Each Access Control Entry (ACE) consists of ten attributes, which collectively define the “who” and the “what” of access rights. In essence, these attributes specify who has permission to perform specific actions on an object. To understand this better, let’s examine the “$ACL” we previously retrieved using the following PowerShell code.

# Output each ACE in the ACL. You can just type "$ACL" into the
#   console to output the data, but the "----" helps break up each ACE.
PS> foreach ($ACE in $ACL) { $ACE ; Write-Host "-----" }

# Lets filter for ACEs with the "ActiveDirectoryRights" of "GenericAll".
PS> foreach ($ACE in $ACL) {
    if ($ACE.ActiveDirectoryRights -like "*GenericAll*") {
        $ACE
        Write-Host "-----"
    }
}

Following the PowerShell code, you should have a long list of ACEs output to the console. Let’s look at one example, ACE, to start discussing what the ACE values mean.

ActiveDirectoryRights : GenericAll
InheritanceType       : Descendents
ObjectType            : 00000000-0000-0000-0000-000000000000
InheritedObjectType   : f0f8ffac-1191-11d0-a060-00aa006c33ed
ObjectFlags           : InheritedObjectAceTypePresent
AccessControlType     : Allow
IdentityReference     : ACME\Exchange Trusted Subsystem
IsInherited           : False
InheritanceFlags      : ContainerInherit
PropagationFlags      : InheritOnly
Active Directory Access Control Entry (ACE) are confusing meme

So, this is a lot of unclear information.

Thanks, Microsoft…

Let’s break down each attribute of the ACE.


Breaking Down the AD ACE

IdentityReference

The IdentityReference is the object that is getting the rights. Remember, an object can be anything within AD. The “ACME\Exchange Trusted Subsystem” group gets the rights in our above example. You can think of the “IdentityReference” as a Security Principal.

Security Principal - Refers to an entity that can be authenticated and authorized to access resources within the network. This entity can be a user, a group, or a computer - essentially any object that has a unique Security Identifier (SID). It cannot be an Organizational Unit(OU).

AccessControlType

This is an easy one. The “AccessControlType” states if the IdentityReference(AKA: the Security Principal) is Allowed or Denied the right. Generally, you will only ever see “Allow” values since if a right is not expressly allowed, then it is denied by default.

IsInherited

The “IsInherited” field tells you if this ACE was inherited from a parent object, true or false.

In our example above, we look at an ACE on the root of the ACME.com domain, so nothing is higher; there are no parent objects above it. Thus, we cannot inherit any rights; false. However, if we were to review the ACL of an OU somewhere else in AD, we would see ACEs inherited from parent objects; true.

ActiveDirectoryRights

Breaking Down the AD ACE ActiveDirectoryRights Images

The “ActiveDirectoryRights” defines the specific permissions the IdentityReference(Security Principal) is assigned to on an Active Directory (AD) object. These rights typically include straightforward permissions such as ReadProperty, WriteProperty, or DeleteProperty. However, they can also encompass more complex rights like ExtendedRights, and Generic rights, and various other values. The ActiveDirectoryRights section may include one or many of these rights. A complete list of rights and their definitions can be found here. You can think of the “ActiveDirectoryRights” like file permissions, where users may have read, write, or modify file permissions.

The “ExtendedRights” is a special permission to grant a specific right to an object. Extended rights are rights specific to an object type(objectClass). For example, the User object type will have a Change Password ExtendedRight, which could grant another object, like the Help-Desk group, the right to change a user’s password. The specific ExtendedRight is defined in the “ObjectType” section of the ACE.

ObjectType

The ObjectTypein an ACE designates the specific Active Directory object class, property, set of properties, or extended right that the Security Principal is allowed or denied access to; a permissions target. For example, I want the Security Principal(IdentityReference), “HelpDeskTeam,” to have WriteProperty(ActiveDirectoryRights) permissions on objects with the objectClass of User(GUID=bf967aba-0de6-11d0-a285-00aa003049e2). This would allow the Help Desk Team members to make changes to users’ AD accounts as part of their job role.

In an ACE, the ObjectType is defined using a GUID. The GUID can be looked up and converted to a human-readable name.

Note: The GUID “00000000-0000-0000-0000-000000000000” is a wildcard, implying all.

Let’s look at an example of an ObjectType with a specific ExtendedRight on the root domain.

ActiveDirectoryRights : ExtendedRight
InheritanceType       : None
ObjectType            : 1131f6ad-9c07-11d1-f79f-00c04fc2dcd2
InheritedObjectType   : 00000000-0000-0000-0000-000000000000
ObjectFlags           : ObjectAceTypePresent
AccessControlType     : Allow
IdentityReference     : ACME\Domain Controllers
IsInherited           : False
InheritanceFlags      : None
PropagationFlags      : None
Breaking Down the AD ACE ObjectType meme

So what exactly does “1131f6ad-9c07-11d1-f79f-00c04fc2dcd2” mean? What right does this grant? To answer this, we must look up the GUID in Active Directory. Why Microsoft couldn’t just include this information in the ACE output is beyond me, but I digress.

As I previously mentioned, the ObjectType can be one of four types: object class, property, set of properties, or extended right. The GUIDs for these four types can be looked up in two locations: the schemaIDGUID(classSchema & attributeSchema) and the rightGUID(controlAccessRight) in the AD configuration partition. Don’t worry about this too much, as we can create one variable with GUIDs and names of both schemaIDGUID and rightGUID and then use it to convert between GUID and name.

We will discuss the rightGUID now, and in the upcoming InheritedObjectType section, we will gather and discuss the schemaIDGUID. However, if you need to convert an ObjectType GUID, you must check both the rightGUID and schemaIDGUID.

We can create a variable with all the rightGUIDs, their GUID, and the GUID human-readable name. Use the following PowerShell commands to convert our GUID to a “right” name.

# Create a variable with all controlAccessRight, their GUID, and the GUID name.
PS> $RightGUIDs = Get-ADObject `
        -SearchBase "CN=Extended-Rights,$((Get-ADRootDSE).ConfigurationNamingContext)" `
        -LDAPFilter '(ObjectClass=controlAccessRight)' `
        -Properties Name, RightsGUID

# Lookup a GUID in the $RightGUIDs variable
PS> $RightGUIDs | Where-Object {$_.RightsGUID -eq '1131f6ad-9c07-11d1-f79f-00c04fc2dcd2'}

# Output
DistinguishedName      : CN=DS-Replication-Get-Changes-All,CN=Extended-Rights,CN=Configuration,DC=acme,DC=com
Name                   : DS-Replication-Get-Changes-All
ObjectClass            : controlAccessRight
ObjectGUID             : 32761725-5778-4703-b4cf-6285516ba6cb
RightsGUID             : 1131f6ad-9c07-11d1-f79f-00c04fc2dcd2

# NOTE: Do not confuse "ObjectGUID" & "RightsGUID", these are not the same.
#       We want the "RightsGUID".

Ok, so it turns out “1131f6ad-9c07-11d1-f79f-00c04fc2dcd2” equals “DS-Replication-Get-Changes-All.”

With this information, we can now understand the last example, ACE. Here it is again trimmed down.

ActiveDirectoryRights : ExtendedRight
InheritanceType       : None
ObjectType            : 1131f6ad-9c07-11d1-f79f-00c04fc2dcd2
AccessControlType     : Allow
IdentityReference     : ACME\Domain Controllers

ACE EXPLAINED: All group members of “ACME\Domain Controllers” are allowed the ExtendedRight of “DS-Replication-Get-Changes-All” on the root domain(remember we got this ACE by using “Get-ACL” on the domain root object; “AD:DC=acme,DC=com”).

Hey, look at that; that is the ACE that gives the Domain Controllers the right to do a DCSync!

InheritanceType, InheritanceFlags, & PropagationFlags

After a lot of reading and some tests, I figured out a shortcut to understanding how child objects inherit the ACE’s rights. The trick is to only pay attention to “InheritanceType” and ignore “InheritanceFlags” and “PropagationFlags”. The “InheritanceType” is a summary of the settings in “InheritanceFlags” and “PropagationFlags”; thus, you only need to look at the definition of InheritanceType.

The “InheritanceType” specifies how access permissions are passed down from a parent object to its child objects. This property determines the scope of inheritance for the permissions defined in the ACE. The InheritanceType can take on various values, each dictating a different inheritance behavior.

Definition of InheritanceTypes

NoneIndicates no inheritance. The ACE information is only used on the object on which the ACE is set. ACE information is not inherited by any descendents of the object.
AllIndicates inheritance that includes the object to which the ACE is applied, the object’s immediate children, and the descendents of the object’s children.
DescendentsIndicates inheritance that includes the object’s immediate children and the descendants of the object’s children, but not the object itself.
SelfAndChildren Indicates inheritance that includes the object itself and its immediate children. It does not include the descendents of its children.
ChildrenIndicates inheritance that includes the object’s immediate children only, not the object itself or the descendents of its children.
Source: MS Wiki on InheritanceTypes

Here is a diagram of the rights inheritance type in practice. Remember, the Security Principal(IdentityReference) is the one gaining the rights over the object and its descendant objects.

Active Directory Access Control List inheritance type diagram explained
Green objects have the inherent rights applied to them.

Now that we have a definition of the different InheritanceTypes, let’s apply this to the following ACE.

ActiveDirectoryRights : GenericAll
InheritanceType       : Descendents
ObjectType            : 00000000-0000-0000-0000-000000000000
InheritedObjectType   : bf967a9c-0de6-11d0-a285-00aa003049e2
ObjectFlags           : InheritedObjectAceTypePresent
AccessControlType     : Allow
IdentityReference     : ACME\Exchange Trusted Subsystem
IsInherited           : False
InheritanceFlags      : ContainerInherit
PropagationFlags      : InheritOnly

So, the ACE InheritanceType is “Descendents.” Let’s see how that is applied.

First, let’s define who is inheriting the ACE. We took the above example ACE from the root domain object. So, the domain root is the primary object.

Active Directory Access Control List Root of the ACME.com domain

The InheritanceType of descendantsIndicates inheritance that includes the object’s immediate children and the descendants of the object’s children, but not the object itself.

So, the group “ACME\Exchange Trusted Subsystem” has the “GenericAll” rights to the objects under ACME.com but not ACME.com itself.

Active Directory Access Control List InheritanceType of descendants

ACE EXPLAINED: This means the “ACME\Exchange Trusted Subsystem” group members have “GenericAll” rights to “ALL(ObjectType=00000000-0000-0000-0000-000000000000)” object attributes on objects nested within the “ACME.com” domain.

However, we have one more inheritance attribute we need to take into account before we have the whole picture: InheritedObjectType.

InheritedObjectType

The “InheritedObjectType” field specifies the type of child objects(User, Computer, OU, etc.) that the ACE will apply to when the ACE is inherited. So this allows us to limit the scope of control the Security Principal(IdentityReference) has to only the object types we want them to control.

The only problem is the ObjectType is in GUID form again. So, we will need to look the GUID up using PowerShell.

# Create a variable with all AD SchemaIDGuids, their GUID, and the GUID name.
PS> $SchemaIDGuids = Get-ADObject `
		-SearchBase (Get-ADRootDSE).SchemaNamingContext `
		-LDAPFilter '(SchemaIDGUID=*)' `
		-Properties Name, SchemaIDGUID


# Lookup a GUID in the $ExtendedRights variable
PS> $SchemaIDGuids | Where-Object {[Guid]$_.SchemaIDGUID -like "bf967a86-0de6-11d0-a285-00aa003049e2"}

# Output
DistinguishedName : CN=Group,CN=Schema,CN=Configuration,DC=amce,DC=com
Name              : Group
ObjectClass       : classSchema
ObjectGUID        : f9f6099b-982e-4f5e-a12c-aab57f8be045
SchemaIDGUID      : {156, 122, 150, 191...}

# NOTE: Do not confuse "ObjectGUID" & "SchemaIDGUID", these are not the same.
#       We want the "SchemaIDGUID".

In the above PowerShell, we convert the InheritedObjectType GUID to its human-readable name.

“bf967a9c-0de6-11d0-a285-00aa003049e2” == “Group”

Let’s review the ACE one more time.

ActiveDirectoryRights : GenericAll
InheritanceType       : Descendents
ObjectType            : 00000000-0000-0000-0000-000000000000
InheritedObjectType   : bf967a9c-0de6-11d0-a285-00aa003049e2
ObjectFlags           : InheritedObjectAceTypePresent
AccessControlType     : Allow
IdentityReference     : ACME\Exchange Trusted Subsystem
IsInherited           : False
InheritanceFlags      : ContainerInherit
PropagationFlags      : InheritOnly

ACE EXPLAINED: The “ACME\Exchange Trusted Subsystem” group members have “GenericAll” rights to ALL(ObjectType=00000000-0000-0000-0000-000000000000) object attributes on Groups(InheritedObjectType=bf967a9c-0de6-11d0-a285-00aa003049e2) objects nested within the “ACME.com” domain. Thus, the “ACME\Exchange Trusted Subsystem” group members can edit any attribute of groups within the ACME.com domain but cannot edit the ACME.com root object itself.

Active Directory Access Control List inheritanceType with InheritedObjectType diagram explained

ObjectFlags

Active Directory Access Control List ObjectFlags are dumb meme

The last one is “ObjectFlags.” Ignore this property. The “ObjectFlags” is redundant when trying to understand an ACE; its values only indicate if the “ObjectType” or the “InheritedObjectType” fields are not empty. Since we are already reading the values in those fields anyway, this is just extraneous information.

IdentityReference - The Security principle that the ACE allows or denies access rights over another object.

ActiveDirectoryRights -  The set of rights the ACE grants: Read, write, modify, etc..

ObjectType -  A property, set of properties, or extended right that the ACE controls the right to read or write on an object.

AccessControlType - Allow or Deny the right.

InheritanceType - The summary of inheritance that the ACE will pass down.

InheritedObjectType - The object type(ObjectClass: Group, User, OU, inetperson, etc.) that the ACE may apply to when the ACE is inherited. An inheritance filter based on the object type.

IsInherited - A true or false value that defines if the ACE was inherited from a parent object.

InheritanceFlags - Ignore
PropagationFlags - Ignore
ObjectFlags - Ignore

Blocking Access Control List Inheritance

Blocking Access Control List Inheritance meme

You may want to prevent a parent’s ACE from being passed to a child. To do this, you can go directly to the object you don’t want to inherit the rights and turn off rights inheritance. However, this is an all-or-nothing change. You cannot selectively block ACEs from being inherited.
If you did want to block a single Allow ACE from being inherited, you should not block inheritance but instead create a Deny ACE on the object to counteract the Allow.

For example, let’s say we have an OU called “All.Corp.Users” that has an ACE that grants(Allow) “WriteAll” rights to the “HelpDeskTeam” group; all descendants inherit this right. So the “HelpDeskTeam” group can edit anything within the “All.Corp.Users” OU. Within the “All.Corp.Users” OU is a sub-OU called “Executive.Corp.Users,” and we don’t want to allow the “HelpDeskTeam” group to edit users within this OU. At the “Executive.Corp.Users” OU, we should apply an ACE that denies WriteAll” rights to the “HelpDeskTeam” group. This works because non-inherited denied entries take presidents over inherited allowed rights.

The order of precedence(1 being highest, 4 being lowest) for denied rights is as follows.

  1. Non-inherited Deny Entries
  2. Non-inherited Allow Entries
  3. Inherited Deny Entries
  4. Inherited Allow Entries

So, denying permissions takes precedence over everything, but “non-inherited allow’ takes priority over “inherited deny.”


Wrapping-Up: Active Directory Access Control List

Active Directory Access Control List meme

The Active Directory Access Control List (ACL) is already tricky, but the only way to check and audit the AD ACL for domain objects makes it way more complicated than it needs to be. Also, the output you get from the ‘Get-ACL’ PowerShell command isn’t really set up for Active Directory. This means you need a lot more info and have to do extra parsing just to get a clear picture of an Access Control Entry (ACE).

The ACLs throughout the domain have complicated interactions that manual auditing cannot fully grasp. This is why the BloodHound & SharpHound tools are so valuable. BloodHound makes it simple to visualize and discover ACEs that lead from a basic-user to a Domain Admin. However, even if you run an ACE audit with BloodHound, you still need to understand the root vulnerability it is auditing and how these permissions escalation paths are created.

The AD ACL Epilogue – Rant

I set out with a goal to create a blog post on preventing DCSync attacks; then, I ran into this Microsoft mess. I, no joke, spent two days trying to understand the AD ACL. At which time, I melted my brain. There is a lack of good, clear information on this subject. Complicating the issue further are the ACE property names, which are similar in name and description to other non-ACL-related properties but are totally different and do not apply the same way. 

I purchased several of Amazon’s recently published best-selling books, specifically on Active Directory; we are talking 1000+ page books. Those books have chapters on the AD ACL and even list it as a security threat. But their advice on handling the security threats boiled down to “Yeah, the AD ACL, it’s a problem; you should, like, totally check that; good luck.” In my research, I found a blog post briefly describing what they learned from an Active Directory-specific training book published in 2004. So I hunted down this now two-decade-old book: Inside Active Directory Second Edition – A System Administrators Guide. To my surprise, this book was a godsend. Some things were outdated, but the underlying process and methodologies remained unchanged. 

It seems to me that the AD ACL was built several decades ago, and Microsoft has just been doing the bare minimum to give us a tool to manage it. This is why third-party tools like Bloodhound have become so valuable. The ability to quickly audit and review AD ACLs, similar to Bloodhound, should be baked into AD management tools. It should be easy to audit permissions and rights within the domain.


Sources: Active Directory Access Control List