Summary
Both attackers and defenders often overlook misconfigured discretionary access control lists
(DACLs
) within an Active Directory environment. For attackers, abusing misconfigured DACLs
can allow not only horizontal and vertical privilege escalation and lateral movement within an AD environment, but can also lead to a complete compromise of the domain.
DACL Attacks I
covers common attacks against misconfigured DACLs within an Active Directory environment. We will first understand DACLs and Security Descriptors, their internal structure and various members, and how they work. Then, we will learn about Access Control Entries (ACEs) and their implications within a DACL, and we will go over the interpretation of some access mask bits that interest us. We will also identify abusable object-specific and validated writes access rights.
Subsequently, we will then start enumerating DACLs from Windows and Linux and abusing/attacking misconfigured ones. By carrying out these attacks, we will gain access to privileged resources, escalate privileges horizontally and vertically, and move laterally across the target Active Directory network.
In this module, we will cover the following:
- DACLs Overview
- DACLs Enumeration
- Targeted Kerberoasting
- AddMember Abuse
- Password Abuse
- Granting Rights and Ownership
CREST CPSA/CRT
-related Sections:
- All sections
CREST CCT INF
-related Sections:
- All sections
This module is broken down into sections with accompanying hands-on exercises to practice each of the tactics and techniques that we cover. The module ends with a practical hands-on skills assessment to gauge your understanding of the various topic areas.
As you work through the module, you will see example commands and command output for the topics introduced. It is worth reproducing as many of these examples as possible to reinforce further the concepts presented in each section.
The module is classified as "Hard" as it assumes a working knowledge of the Linux command line and an understanding of information security fundamentals.
A firm grasp of the following modules can be considered a prerequisite for the successful completion of this module:
- Networking Fundamentals
- Linux Fundamentals
- Windows Fundamentals
- Introduction To Active Directory
- Active Directory Enumeration & Attacks
- Password Attacks
DACLs Overview
Within the Windows security ecosystem, tokens
and security descriptors
are the two main variables of the object security equation. While tokens
identify the security context of a process or a thread, security descriptors
contain the security information associated with an object. To achieve the Confidentiality
pillar of the CIA
triad, many operating systems and directory services utilize access control lists
(ACLs
), "a mechanism that implements access control for a system resource by enumerating the system entities that are permitted to access the resource and stating, either implicitly or explicitly, the access modes granted to each entity", according to RFC4949.
Remember that access control policies dictate what types of access are permitted, under what circumstances, and by whom. The four general categories of access control policies are Discretionary access control
(DAC
), Mandatory access control
(MAC
), Role-based access control
(RBAC
), and Attribute-based access control
(ABAC
).
DAC
, the traditional method of implementing access control, controls access based on the requestor's identity and access rules stating what requestors are (or are not) allowed to do. It is discretionary
because an entity might have access rights that permit it, by its own volition, to enable another entity to access some resource; this is in contrast to MAC
, in which the entity having access to a resource may not, just by its own volition, enable another entity to access that resource. Windows is an example of a DAC
operating system, which utilizes Discretionary access control lists
(DACLs
).
The image below shows the DACL
/ACL
for the user account forend
in Active Directory Users and Computers
(ADUC
). Each item under Permission entries
makes up the DACL
for the user account. In contrast, the individual entries (such as Full Control
or Change Password
) are Access Control Entries
(ACEs
) showing the access rights granted over this user object to various users and groups.
DACLs
are part of the bigger picture of security descriptors
. Let us review security descriptors to understand them better and their roles within the access control model.
Security Descriptors
In Windows, every object (also known as securable objects) has a security descriptor
data structure that specifies who can perform what actions on the object. The security descriptor
is a binary data structure that, although it can vary in length and exact contents, can contain six main fields:
-
Revision Number
: TheSRM
(Security Reference Monitor
) version of the security model used to create the descriptor. -
Control Flags
: Optional modifiers that define the behavior/characteristics of the security descriptor. -
Owner SID
: The object's ownerSID
. -
Group SID
: The object's primary groupSID
. Only the Windows POSIX subsystem utilized this member (before being discontinued), and most AD environments now ignore it. -
Discretionary access control list
(DACL
): Specifies who has what access to the object - throughout theDACL Attacks
mini-modules, our primary focus will be abusing and attacking these. -
System access control list
(SACL
): Specifies which operations by which users should be logged in the security audit log and the explicit integrity level of an object.
Internally, Windows represents a security descriptor
via the SECURITY_DESCRIPTOR struct:
typedef struct _SECURITY_DESCRIPTOR {
BYTE Revision;
BYTE Sbz1;
SECURITY_DESCRIPTOR_CONTROL Control;
PSID Owner;
PSID Group;
PACL Sacl;
PACL Dacl;
} SECURITY_DESCRIPTOR, *PISECURITY_DESCRIPTOR;
A security descriptor
can be one of two forms, absolute or self-relative; absolute security descriptors
contain pointers to the information (i.e., not the actual information itself), as in the SECURITY_DESCRIPTOR
struct above, and these are the ones that we will encounter when interacting with Windows objects, whether AD ones or not.
Self-relative security descriptors
are not very different: instead of storing pointers, they store the actual data of a security descriptor
in a contiguous memory block. These are meant to store a security descriptor on a disk or transmit it over the wire.
Four of the seven members of the SECURITY_DESCRIPTOR
struct matter to us for the exploitation of DACLs
; therefore, we will review them to understand what they are.
Control
The Control
member is of type SECURITY_DESCRIPTOR_CONTROL, a 16-bit set of bit flags that qualify the meaning of a security descriptor
or its components. The value of Control
, when retrieved with the function GetSecurityDescriptorControl, can include a combination of 13 bits flags:
Flag | Hexadecimal Representation |
---|---|
SE_DACL_AUTO_INHERIT_REQ | 0x0100 |
SE_DACL_AUTO_INHERITED | 0x0400 |
SE_DACL_DEFAULTED | 0x0008 |
SE_DACL_PRESENT | 0x0004 |
SE_DACL_PROTECTED | 0x1000 |
SE_GROUP_DEFAULTED | 0x0002 |
SE_OWNER_DEFAULTED | 0x0001 |
SE_SACL_AUTO_INHERIT_REQ | 0x0200 |
SE_SACL_AUTO_INHERITED | 0x0800 |
SE_SACL_DEFAULTED | 0x0008 |
SE_SACL_PRESENT | 0x0010 |
SE_SACL_PROTECTED | 0x2000 |
SE_SELF_RELATIVE | 0x8000 |
These binary flags can be added to represent any combinations. For example, if the value of Control
is 0x8014
, it signifies the presence of the SE_DACL_PRESENT
, SE_SACL_PRESENT
, and SE_SELF_RELATIVE
flags.
One important flag for us to know about is SE_DACL_PRESENT:
Flag | Meaning |
---|---|
SE_DACL_PRESENT |
Indicates a security descriptor that has a DACL . If not set, or if set and the DACL is NULL , the security descriptor allows full access to everyone. An empty DACL permits access to no one. |
Owner
The Owner
and Group
members contain a pointer to the Security Identifier
(SID
) of the object's owner and primary group, respectively. Object owners are always granted full control of the security descriptor
, as they are granted the access rights RIGHT_WRITE_DAC
(WriteDacl
) and RIGHT_READ_CONTROL
(ReadControl
) implicitly.
Sacl and Dacl
In Windows, SACL
(System access control list
) and DACL
(Discretionary access control lists
) are the two types of access control lists
(ACLs
), each consisting of a header
and zero or more access control entries
(ACEs
). (Throughout security literature, when the term ACL
is used, it usually refers to DACL
, especially for Windows systems.)
A SACL contains ACEs
that dictate the types of access attempts that generate audit records in the security event log
of a domain controller; therefore, a SACL
allows administrators to log access attempts to securable objects
. There are two types of ACEs
within a SACL
, system audit
ACEs
and system audit-object
ACEs
.
While a DACL
holds ACEs
that dictate what principals have control rights over a specific object. Internally within Windows, a DACL
consists of an ACL followed by an ordered list of zero or more ACEs
(the same applies to SACLs
). Below is the struct definition of an ACL
(recognizing these struct definitions will help us later on when viewing a security descriptor
from the kernel's point of view):
typedef struct _ACL {
BYTE AclRevision;
BYTE Sbz1;
WORD AclSize;
WORD AceCount;
WORD Sbz2;
} ACL;
Generic and Object-specific ACEs
An ACE contains a set of user rights and a SID
that identifies a principal for whom the rights are allowed, denied, or audited. Below is the structure of a generic ACE
:
Windows represents an ACE
internally via the struct ACE_HEADER:
typedef struct _ACE_HEADER {
BYTE AceType;
BYTE AceFlags;
WORD AceSize;
} ACE_HEADER;
In a DACL
, there can be nine types of ACEs
, each having the struct ACE_HEADER
as a member, in addition to the Mask member (which is of type ACCESS_MASK and defines the standard, specific, and generic rights) and SidStart
(which holds the first 32 bits of the trustee's SID
):
- Access Allowed
- Access Denied
- Access Allowed Object
- Access Denied Object
- Access Allowed Callback
- Access Denied Callback
- Access Allowed Object Callback
- Conditional Claims
Four main types of ACEs
are important for us to understand:
ACE | Implication |
---|---|
ACCESS_ALLOWED_ACE | Allows a particular security principal (user or group) to access an Active Directory object , such as a user account or group. An Access Allowed ACE specifies which permissions the security principal can perform on the object, such as read, write, or modify. |
ACCESS_ALLOWED_OBJECT_ACE | A specific type of Access Allowed ACE that is applied to an object and grants access to the object itself and any child objects it contains. An Access Allowed Object ACE can grant a security principal the necessary permissions to access an object and its child objects without applying separate ACEs to each child object. |
ACCESS_DENIED_ACE | Denies a particular security principal access to an Active Directory object , such as a user account or group. An Access Denied ACE specifies which permissions the security principal is not allowed to perform on the object, such as read, write, or modify. |
ACCESS_DENIED_OBJECT_ACE | A specific type of Access Denied ACE that is applied to an object and restricts access to the object itself and any child objects it contains. An Access Denied Object ACE prevents a security principal from accessing an object and its child objects without having to apply separate ACEs to each child object. |
As you may have noticed, some ACEs
include the keyword Object
, these are object-specific ACEs used only within Active Directory
. In addition to the members of generic ACEs
structure, object-specific ACEs
contain the members:
-
ObjectType
: AGUID
containing a type ofchild object
, aproperty set
orproperty
, anextended right
, or avalidated write
. -
InheritedObjectType
: Specifies the type ofchild object
that caninherit
theACE
. -
Flags
: Indicates whether the membersObjectType
andInheritedObjectType
are present via a set of bit flags.
Viewing DACLs of AD Objects Manually
After a brief understanding of the fields of a security descriptor
and before we start auditing and enumerating DACLs
with automated tools, let us inspect them manually for both AD and non-AD objects (specifcally, processes
).
Using dsacls
dsacls (the command-line equivalent to the Security
tab in the Properties
dialog box of ADUC
) is a native Windows binary that can display and change ACEs
/permissions
in ACLs
of AD objects. Let us view the ACLs
for the user Yolanda
within the domain inlanefreight.local
:
Using dsacls to view the ACLs of Yolanda
PS C:\Users\Administrator> dsacls.exe "cn=Yolanda,cn=users,dc=inlanefreight,dc=local"
Owner: INLANEFREIGHT\Domain Admins
Group: INLANEFREIGHT\Domain Admins
Access list:
Allow INLANEFREIGHT\Domain Admins FULL CONTROL
Allow BUILTIN\Account Operators FULL CONTROL
Allow NT AUTHORITY\Authenticated Users
SPECIAL ACCESS
READ PERMISSONS
Allow NT AUTHORITY\SELF SPECIAL ACCESS
READ PERMISSONS
LIST CONTENTS
READ PROPERTY
LIST OBJECT
Allow NT AUTHORITY\SYSTEM FULL CONTROL
Allow BUILTIN\Pre-Windows 2000 Compatible Access
SPECIAL ACCESS <Inherited from parent>
READ PERMISSONS
LIST CONTENTS
READ PROPERTY
LIST OBJECT
Allow INLANEFREIGHT\luna SPECIAL ACCESS <Inherited from parent>
WRITE PERMISSIONS
<SNIP>
We can be more specific by fetching out the permissions that other users have against Yolanda
; for example, let us enumerate the permissions that Pedro
only has over Yolanda
:
Using dsacls to view the Permissions Pedro has over Yolanda
PS C:\Users\Administrator> dsacls.exe "cn=Yolanda,cn=users,dc=inlanefreight,dc=local" | Select-String "Pedro"
Allow INLANEFREIGHT\pedro Reset Password
Using PowerShell with DirectoryServices and ActiveDirectorySecurity
Now, we will do the same as above but with PowerShell
. The DirectorySearcher class within the .NET
System.DirectoryServices namespace contains the SecurityMasks property that will allow us to access the DACL
of the object's security descriptor
. First, we need to get the security descriptor
of the AD object Yolanda
as a binary blob:
PS C:\Users\Administrator> $directorySearcher = New-Object System.DirectoryServices.DirectorySearcher('(samaccountname=Yolanda)')
PS C:\Users\Administrator> $directorySearcher.SecurityMasks = [System.DirectoryServices.SecurityMasks]::Dacl -bor [System.DirectoryServices.SecurityMasks]::Owner
PS C:\Users\Administrator> $binarySecurityDescriptor = $directorySearcher.FindOne().Properties.ntsecuritydescriptor[0]
PS C:\Users\Administrator> Write-Host -NoNewline $binarySecurityDescriptor
1 0 4 140 44 7 0 0 0 0 0 0 0 0 0 0 20 0 0 0 4 0 24 7 42 0 0 0 5 0 56 0 0 1 0 0 1 0 0 0 112 149 41 0 109 36 208 17 167 104 0 170 0 110 5 41 1 5 0 0 0 0 0 5 21 0 0 0 45 212 142 75 184 149 12 71 100 136 127 96 9 18 0 0 5 0 56 0 16 0 0 0 1 0 0 0 0 66 22 76 192 32 208 17 167 104 0 170 0 110 5 41 1 5 0 0 0 0 0 5 21 0 0 0 45 212 142 75 184 149 12 71 100 136 127 96 41 2 0 0 5 0 56 0 16 0 0 0 1 0 0 0 16 32 32 95 165 121 208 17 144 32 0 192 79 194 212 207 1 5 0 0 0 0 0 5 21 0 0 0 45 212 142 75 184 149 12 71 100 136 127 96 41 2 0 0 5 0 56 0 16 0 0 0 1 0 0 0 64 194 10 188 169 121 208 17 144 32 0 192 79 194 212 207 1 5 0 0 0 0 0 5 21 0 0 0 45 212 142 75 184 149 12 71 100 136 127 96 41 2 0 0 5 0 56 0 16 0 0 0 1 0 0 0 248 136 112 3 225 10 210 17 180 34 0 160 201 104 249 57 1 5 0 0 0 0 0 5 21 0 0 0 45 212 142 75 184 149 12 71 100 136 127 96 41 2 0 0 5 0 56 0 48 0 0 0 1 0 0 0 127 122 150 191 230 13 208 17 162 133 0 170 0 48 73 226 1 5 0 0 0 0 0 5 21 0 0 0 45 212 142 75 184 149 12 71 100 136 127 96 5 2 0 0 5 0 44 0 16 0 0 0 1 0 0 0 29 177 169 70 174 96 90 64 183 232 255 138 88 212 86 210 1 2 0 0 0 0 0 5 32 0 0 0 48 2 0 0 5 0 44 0 48 0 0 0 1 0 0 0 28 154 182 109 34 148 209 17 174 189 0 0 248 3 103 193 1 2 0 0 0 0 0 5 32 0 0 0 49 2 0 0 5 0 44 0 48 0 0 0 1 0 0 0 98 188 5 88 201 189 40 68 165 226 133 106 15 76 24 94 1 2 0 0 0 0 0 5 32 0 0 0 49 2 0 0 5 0 40 0 0 1 0 0 1 0 0 0 83 26 114 171 47 30 208 17 152 25 0 170 0 64 82 155 1 1 0 0 0 0 0 1 0 0 0 0 5 0 40 0 0 1 0 0 1 0 0 0 83 26 114 171 47 30 208 17 152 25 0 170 0 64 82 155 1 1 0 0 0 0 0 5 10 0 0 0 5 0 40 0 0 1 0 0 1 0 0 0 84 26 114 171 47 30 208 17 152 25 0 170 0 64 82 155 1 1 0 0 0 0 0 5 10 0 0 0 5 0 40 0 0 1 0 0 1 0 0 0 86 26 114 171 47 30 208 17 152 25 0 170 0 64 82 155 1 1 0 0 0 0 0 5 10 0 0 0 5 0 40 0 16 0 0 0 1 0 0 0 66 47 186 89 162 121 208 17 144 32 0 192 79 194 211 207 1 1 0 0 0 <SNIP>
Now that we have the security descriptor
for Yolanda
as a binary blob, we need to parse it using the function SetSecurityDescriptorBinaryForm from the class ActiveDirectorySecurity. Then we can view all of the ACEs
of Yolanda
:
PS C:\Users\Administrator> $parsedSecurityDescriptor = New-Object System.DirectoryServices.ActiveDirectorySecurity
PS C:\Users\Administrator> $parsedSecurityDescriptor.SetSecurityDescriptorBinaryForm($binarySecurityDescriptor)
PS C:\Users\Administrator> $parsedSecurityDescriptor.Access
ActiveDirectoryRights : GenericRead
InheritanceType : None
ObjectType : 00000000-0000-0000-0000-000000000000
InheritedObjectType : 00000000-0000-0000-0000-000000000000
ObjectFlags : None
AccessControlType : Allow
IdentityReference : NT AUTHORITY\SELF
IsInherited : False
InheritanceFlags : None
PropagationFlags : None
ActiveDirectoryRights : ReadControl
InheritanceType : None
ObjectType : 00000000-0000-0000-0000-000000000000
InheritedObjectType : 00000000-0000-0000-0000-000000000000
ObjectFlags : None
AccessControlType : Allow
IdentityReference : NT AUTHORITY\Authenticated Users
IsInherited : False
InheritanceFlags : None
PropagationFlags : None
ActiveDirectoryRights : GenericAll
InheritanceType : None
ObjectType : 00000000-0000-0000-0000-000000000000
InheritedObjectType : 00000000-0000-0000-0000-000000000000
ObjectFlags : None
AccessControlType : Allow
IdentityReference : NT AUTHORITY\SYSTEM
IsInherited : False
InheritanceFlags : None
PropagationFlags : None
<SNIP>
We can also be more specific and fetch out the permissions that Pedro
only has over Yolanda
:
Using PowerShell to view the Permissions Pedro has over Yolanda
PS C:\Users\Administrator> $parsedSecurityDescriptor.Access | Where-Object {$_.IdentityReference -like '*Pedro*'}
ActiveDirectoryRights : ExtendedRight
InheritanceType : None
ObjectType : 00299570-246d-11d0-a768-00aa006e0529
InheritedObjectType : 00000000-0000-0000-0000-000000000000
ObjectFlags : ObjectAceTypePresent
AccessControlType : Allow
IdentityReference : INLANEFREIGHT\pedro
IsInherited : False
InheritanceFlags : None
PropagationFlags : None
Viewing DACLs of Processes
Local Kernel Debugging
To view the DACL
of the process explorer.exe
internally, we need to deference the SecurityDescriptor
pointer within the ObjectHeader
member of explorer.exe
(which can be done with local kernel debugging
and WinDbg). This will enable us to examine how the Windows kernel sees a security descriptor
:
lkd> !sd 0xffffd08f`3b15a12f & -10
->Revision: 0x1
->Sbz1 : 0x0
->Control : 0x8814
SE_DACL_PRESENT
SE_SACL_PRESENT
SE_SACL_AUTO_INHERITED
SE_SELF_RELATIVE
->Owner : S-1-5-21-1220085036-3517073048-2454771104-1008
->Group : S-1-5-21-1220085036-3517073048-2454771104-513
->Dacl :
->Dacl : ->AclRevision: 0x2
->Dacl : ->Sbz1 : 0x0
->Dacl : ->AclSize : 0x5c
->Dacl : ->AceCount : 0x3
->Dacl : ->Sbz2 : 0x0
->Dacl : ->Ace[0]: ->AceType: ACCESS_ALLOWED_ACE_TYPE
->Dacl : ->Ace[0]: ->AceFlags: 0x0
->Dacl : ->Ace[0]: ->AceSize: 0x24
->Dacl : ->Ace[0]: ->Mask : 0x001fffff
->Dacl : ->Ace[0]: ->SID: S-1-5-21-1220085036-3517073048-2454771104-1008
->Dacl : ->Ace[1]: ->AceType: ACCESS_ALLOWED_ACE_TYPE
->Dacl : ->Ace[1]: ->AceFlags: 0x0
->Dacl : ->Ace[1]: ->AceSize: 0x14
->Dacl : ->Ace[1]: ->Mask : 0x001fffff
->Dacl : ->Ace[1]: ->SID: S-1-5-18
->Dacl : ->Ace[2]: ->AceType: ACCESS_ALLOWED_ACE_TYPE
->Dacl : ->Ace[2]: ->AceFlags: 0x0
->Dacl : ->Ace[2]: ->AceSize: 0x1c
->Dacl : ->Ace[2]: ->Mask : 0x00121411
->Dacl : ->Ace[2]: ->SID: S-1-5-5-0-191017
->Sacl :
->Sacl : ->AclRevision: 0x2
->Sacl : ->Sbz1 : 0x0
->Sacl : ->AclSize : 0x1c
->Sacl : ->AceCount : 0x1
->Sacl : ->Sbz2 : 0x0
->Sacl : ->Ace[0]: ->AceType: SYSTEM_MANDATORY_LABEL_ACE_TYPE
->Sacl : ->Ace[0]: ->AceFlags: 0x0
->Sacl : ->Ace[0]: ->AceSize: 0x14
->Sacl : ->Ace[0]: ->Mask : 0x00000003
->Sacl : ->Ace[0]: ->SID: S-1-16-8192
Using AccessChk
AccessChk is part of the Sysinternals suite that enables viewing the specific access rights
granted to users or groups. For example, to view the security descriptor
of the process explorer.exe
, we can use the -l
parameter:
PS C:\Users\Admin\Downloads\AccessChk> .\accesschk64.exe -p "explorer.exe" -l
Accesschk v6.15 - Reports effective permissions for securable objects
Copyright (C) 2006-2022 Mark Russinovich
Sysinternals - www.sysinternals.com
[8992] explorer.exe
DESCRIPTOR FLAGS:
[SE_DACL_PRESENT]
[SE_SACL_PRESENT]
[SE_SACL_AUTO_INHERITED]
[SE_SELF_RELATIVE]
OWNER: 3L1T3\Admin
LABEL: Medium Mandatory Level
SYSTEM_MANDATORY_LABEL_NO_WRITE_UP
SYSTEM_MANDATORY_LABEL_NO_READ_UP
[0] ACCESS_ALLOWED_ACE_TYPE: 3L1T3\Admin
PROCESS_ALL_ACCESS
[1] ACCESS_ALLOWED_ACE_TYPE: NT AUTHORITY\SYSTEM
PROCESS_ALL_ACCESS
[2] ACCESS_ALLOWED_ACE_TYPE: 3L1T3\Admin-S-1-5-5-0-191017
PROCESS_QUERY_INFORMATION
PROCESS_QUERY_LIMITED_INFORMATION
PROCESS_TERMINATE
PROCESS_VM_READ
SYNCHRONIZE
READ_CONTROL
DACLs
, as per our explanation, consist of an ACL
data structure followed by an ordered list of zero or more ACE
data structures. The only difference between the DACLs
of AD objects and normal objects is the value that members such as Mask
can have.
Coming Next
After having a brief understanding of security descriptors
and DACLs
, we will go over how to enumerate and audit DACLs
of objects within an AD environment using automated tools such as dacledit.py
, PowerView
, and BloodHound
.