Access Controls
Overview
ACLs can be enumerated with PowerView, but it is much easier with BloodHound.
In Windows and Active Directory (AD), access to resources is determined by the interaction between access tokens, security descriptors, and access control lists (ACLs). Together, these components define who can access an object and what actions they are allowed to perform.
Access Tokens
When a user authenticates, Windows generates an access token that represents the user’s security context. This token includes the user’s Security Identifier (SID), the SIDs of any groups they belong to, assigned privileges, and other contextual information.
Every process started by the user inherits a primary token, which determines what the process can do. In some cases, a thread may use an impersonation token to temporarily act as another user and perform actions with different privileges.
Each securable object, such as a file, share, user, or group, contains a security descriptor that stores its security configuration. When access is requested, the object compares the requester’s token with its ACL to determine whether the operation should be allowed or denied.
Security Identifiers
A Security Identifier (SID) is a unique and immutable value assigned to each security principal, including users and groups. Local SIDs are generated by the Local Security Authority (LSA), while domain SIDs are created by a domain controller (DC). The SID format follows the structure:
S-R-X-YS
Indicates a SID.
R
The revision (always 1).
X
Represents the issuing authority.
Y
Contains the domain or machine identifier and the Relative Identifier (RID). The RID uniquely identifies an account within a domain or system. RIDs below 1000 typically correspond to built‑in or well‑known accounts.
Some example SIDs can be found below.
S-1-5-<domain>-500
Domain Administrator
S-1-5-21-<machine>-500
Local Administrator
S-1-5-21-<machine>-501
Guest account
S-1-5-21-<domain>-513
Domain users
S-1-5-21-<domain>-516
Domain Controllers
Security Descriptors
A security descriptor stores all security information for an object. It is implemented through the SECURITY_DESCRIPTOR structure and contains the owner, primary group, auditing rules, and access control rules.
Security descriptors can be absolute, which use pointers to reference security information, or self‑relative, which store all data in a contiguous block suitable for storage or transmission. The former is the form typically encountered when working with Windows objects.The most relevant components for access control are:
A 16-bit set of bit flags that qualify the meaning of an SD or its components. Its value, when retrieved with the function GetSecurityDescriptorControl, can include a combination of 13 bits flags. One of those, SE_DACL_PRESENT, Indicates an SD that has a DACL. If not set, or if set and the DACL is NULL, the SD allows full access to everyone. An empty DACL permits access to no one.
Owner / Group
Contain a pointer to the SID of the object's owner and primary group, respectively. Object owners are always granted full control of the SD, as they are granted the access rights RIGHT_WRITE_DAC (WriteDacl) and RIGHT_READ_CONTROL (ReadControl) implicitly.
Contains Access Control Entries (ACEs) that dictate the types of access attempts that generate audit records in the security event log of a DC; therefore, a SACL allows administrators to log access attempts to securable objects.
DACL
Holds ACEs that dictate what principals have control rights over a specific object.
AD includes a protective mechanism known as the Security Descriptor Propagator (SDProp). This background process maintains the integrity of permissions on highly privileged accounts and groups, such as Domain Admins and Enterprise Admins. Its primary function is to periodically reapply a secure, default security descriptor to these protected objects, ensuring that unauthorized or malicious changes to their ACLs do not persist.
For example, if an attacker or administrator modifies the permissions of a protected group by granting elevated rights to another account, these changes are typically overwritten when SDProp runs. By default, this process executes every 60 minutes, restoring the correct and controlled permissions. As a result, SDProp acts as a safeguard and consistency mechanism, effectively resetting ACLs on critical AD objects and helping to prevent long-term privilege escalation.
Access Control Lists
In AD, access to objects is governed by two main types of Access Control Lists (ACLs): the Discretionary Access Control List (DACL) and the System Access Control List (SACL).
The DACL defines which users or security principals, also known as trustees, are allowed or denied specific types of access to an object. It determines who can read, write, modify, or take ownership of the object and its attributes. This makes the DACL the primary mechanism used to enforce access control in AD. Each DACL consists of multiple Access Control Entries (ACEs), where each ACE represents a single rule that grants or denies permissions to a specific trustee. These entries typically specify the security identifier (SID) of the principal, the rights granted or denied, and the object to which the permissions apply. Importantly, if an object does not have a DACL, the system grants full access to everyone, which highlights the critical role DACLs play in maintaining security.
The SACL, by contrast, is used for auditing rather than access enforcement. It specifies which types of access attempts, whether successful or failed, should be recorded in the system’s security event log. This allows administrators to monitor access to sensitive resources and supports security investigations, compliance, and forensic analysis.
User DACLs can be enumerated/modified using the built-in dsacls or PowerShell (Get-Acl, Set-Acl), as well as PowerView's Get-DomainObjectAcl and Add-DomainObjectAcl. AccessChk (part of Sysinternals) can be used to enumerate the DACL of a process.
On Linux, dacledit.py can be used for that purpose.
Manually enumerating the DACL of a single object can be useful in specific situations; however, this approach does not scale well in large AD environments. Because an enterprise domain may contain thousands of objects and complex permission relationships, reviewing individual DACLs does not provide a complete view of effective access or privilege escalation paths.
Tools such as BloodHound address this challenge by collecting and correlating ACL data across the entire domain. By representing permissions as graph relationships, BloodHound enables security analysts to identify indirect and abusable access rights more efficiently. BloodHound organizes control rights into two main categories:
Inbound control rights focus on permissions that directly affect a specific object, which is conceptually similar to reviewing that object’s DACL.
Outbound control rights aggregate and correlate all references to the object’s SID across every DACL in the domain. This broader perspective reveals where an account or group has influence, even when that control is indirect or inherited.
Access Control Entries
An ACL consists of multiple Access Control Entries (ACEs).

An ACE can be read as follows: SecurityIdentifier has ActiveDirectoryRights on ObjectDN:
Each ACE contains a SID identifying a user or group and an access mask that specifies allowed or denied rights. When access is requested, Windows evaluates ACEs in order to determine the effective permissions.
There are several ACE types, but the most relevant can be found below.
Allows a particular security principal (user or group) to access an AD object, such as a user account or group, by specifying which permissions the security principal can perform on the object, such as read, write, or modify.
Applied to an object and grants access to the object itself and any child objects it contains. Can grant a security principal the necessary permissions to access an object and its child objects without applying separate ACEs to each child object.
Denies a particular security principal access to an AD object by specifying which permissions the security principal is not allowed to perform on the object.
Applied to an object and restricts access to the object itself and any child objects it contains. Prevents a security principal from accessing an object and its child objects without having to apply separate ACEs to each child object.
Each ACE contains a 32‑bit access mask that defines specific rights.

For AD objects, the access mask contains a combination of the below values (X indicates bits that are ignored).

From a security and attack perspective, the most relevant permissions are listed below.
GenericAll
(GA)
Allows creating or deleting child objects, deleting a subtree, reading and writing properties, examining child objects and the object itself, adding and removing the object from the directory, and reading or writing with an extended right. This is equivalent to the object-specific access rights bits (DE | RC | WD | WO | CC | DC | DT | RP | WP | LC | LO | CR | VW) for AD objects.
GenericExecute
(GX)
Allows reading permissions on and listing the contents of a container object. This is equivalent to the object-specific access rights bits (RC | LC) for AD objects.
GenericWrite
(GW)
Allows reading permissions on this object, writing all the properties on this object, and performing all validated writes to this object. This is equivalent to the object-specific access rights bits (RC | WP | VW) for AD objects.
GenericRead
(GR)
Allows reading permissions on this object, reading all the properties on this object, listing this object name when the parent container is listed, and listing the object's contents if it is a container. This is equivalent to the object-specific access rights bits (RC | LC | RP | LO) for AD objects.
WriteDacl
(WD)
Allows modifying the object's security descriptor’s DACL.
WriteOwner
(WO)
Allows modifying the object's security descriptor's owner. A user can only take ownership of an object but cannot transfer ownership of an object to other users.
ReadControl
(RC)
Allows reading the data from the object's security descriptor. This does not include the data of the SACL.
Delete
(DE)
Allows deleting the object.
CR
Allows performing an operation controlled by a control access right. The ObjectType member of an ACE can contain a GUID that identifies the control access right. If ObjectType does not contain a GUID, the ACE controls the right to perform all control access right controlled operations associated with the object. Also referred to as AllExtendedRights, especially when ObjectType does not contain a GUID.
WP
Allows writing properties of the object. The ObjectType member of an ACE can contain a GUID that identifies a property set or an attribute. If ObjectType does not contain a GUID, the ACE controls the right to write all object's attributes.
VW
Allows performing an operation controlled by a validated write access right. The ObjectType member of an ACE can contain a GUID that identifies the validated write. If ObjectType does not contain a GUID, the ACE controls the rights to perform all validated write operations associated with the object. Also referred to as Self.
Active Directory also defines extended rights, which control sensitive operations such as password resets and directory replication. Important examples include:
Allows a user's account password to be reset without knowing the old one. This is in contrast to User-Change-Password, which does require knowing the old password.
Required to replicate changes from a given Naming Context. Required for DCSync.
Allows the replication of secret domain data. Required for DCSync attack.
Similarly, validated writes allow controlled modifications to specific attributes, such as adding oneself to a group (Self-Membership) or modifying Service Principal Names (Validated-SPN).
Mandatory Integrity Control
Windows uses MIC to restrict access between processes based on their integrity levels. This prevents lower-trust processes from modifying higher-trust objects, even if they have the right permissions. Processes and objects inherit the integrity level of the user who creates them, unless the executable has a low integrity level, in which case any process it starts will also have a low level. Lower-integrity processes cannot modify higher-integrity objects. From Windows Vista onwards, there are five integrity levels:
System: Used by kernel-mode processes withSYSTEMprivilegesHigh: Assigned to processes withadminprivilegesMedium: The default for standard user processesLow: Used for sandboxed processes (e.g., web browsers)Untrusted: The most restricted level, assigned to risky processes
Integrity levels can be checked using Process Explorer (process integrity), via the whoami /groups command (user integrity), and via the icalcs command (file integrity).
User Account Control
UAC is a security feature that prevents unauthorized privilege escalation by restricting applications to standard user privileges, even if the user is an Administrator. When an Administrator logs in, Windows creates two access tokens:
Standard User Token (default, used for regular tasks)
Administrator Token (activated only when elevated privileges are required)
To use admin privileges, the user must confirm a UAC prompt. For example, if a privileged account is compromised, typing
whoami /privin a normal shell won't reveal all privileges. We will need to open an elevated shell and use the UAC prompt to reveal all privileges.
UAC ensures applications run at the right privilege level, protects system files and registry keys from accidental or malicious changes, and prevents malware from gaining full control of the system without user approval. Processes run at four different integrity levels:
System→ Kernel-mode processes withSYSTEMprivilegesHigh→ Used for administrative tasksMedium→ Default level for standard user applicationsLow→ Used for sandboxed processes (e.g., web browsers)
Being an
Administratordoes not mean all processes run with high integrity by default. UAC ensures privilege separation, requiring explicit approval for elevated actions. Attackers and penetration testers often seek to bypass UAC to execute processes at high integrity, allowing unrestricted access to system resources.
Last updated