DACL Primer

Rich
8 min readNov 14, 2024

--

TL;DR DACLs are the very basis of security in Windows. We have seen some misinformation out there though, so this is a ‘break it down Barney style’ primer on DACLs.

Welcome to Part XIX of our ‘Back to the Basics’ series!

Part I: NTDS.dit vs SAM

Part II: Ownership Matters

Part III: Recovering from a Crash

Part IV: Setting up a Simple Honeypot Account

Part V: Automating DC Deployment

Part VI: Sometimes it’s the dumbest thing

Part VII: Merry Christmas, macros, & Base64

Part VIII: Why old 0 Days make great teaching tools

Part IX: PowerShell & PS1s without PowerShell.exe

Part X: Ownership & so called “effective permissions”

Part XI: Windows Event Forwarding & SACLs

Part XII: Poorly planned honeypots & other Bad Ideas

Part XIII: Setting up a simple honey token

Part XIV: Smartcards and Pass-the-Hash

Part XV: Forwarding logs to Sentinel & basic alerts

Part XVI: Automating VM deployments in Hyper-V

Part XVII: Migrating the lab from ESXi to Hyper-V

Part XVIII: Centrally managing Hyper-V & Live Migrations

Part XIX: DACL Primer

Background

None of this is new, in fact none of it is even new here. We already ran a 16 part series on auditing DACLs in AD, added 7 annexes to it, ran a few exercises on querying and abusing DACLs in NTFS, created Red and Blue Team queries, and created Mishky’s AD Range that includes enumeration and abuse of DACLs on AD CS templates.

Back when I was first studying up for the MCSA I was creating and configuring test.local and of course Googling a lot. I read Sean Metcalf’s excellent material, William Panek’s book, countless articles on Microsoft Learn, and I stumbled on a certain vendor’s blog. I was probably Googling “AD security” or something similar.

Back then I thought that vendor was really smart. They certainly think they are, one can tell from the language they use. The thing was, the more I learned and as I progressed through MCSA, CRTP, etc the more I realized a few things:

However I would not have bothered writing a Back to the Basics article on DACLs just because of that. We already covered most of the above in our Auditing AD Series, not to mention our Get-Acl and Set-Acl cheatsheets. A recent post I saw on LinkedIn prompted this.

Apparently a Back to the Basics primer on DACLs is required.

An example ACE

Invoke-Command -VMName "US-DC" {Import-Module ActiveDirectory ; Set-Location AD: ; (Get-Acl (Get-ADOrganizationalUnit -Filter {Name -eq "Server_Admins"}).DistinguishedName).Access | Where-Object {$_.IdentityReference -like "*Helpdesk*"} } -Credential $ChildDomainAdminCredObject

Let’s ‘break this down Barney Style’.

  • PSComputerName & RunspaceId are only seen if you run this query via PowerShell Direct in Hyper-V. They are not part of the DACL.
  • ActiveDirectoryRights: Pretty self explanatory, see our ‘Dangerous Rights’ cheatsheet for more info
  • InheritanceType: 3 possible values, listed below. See this for more info
 _________________________________________________________________________
| None | applies only to the OU |
| Descendents | applies only to the objects in the OU, not the OU itself |
| All | applies to the OU and the objects in it |
-------------------------------------------------------------------------
  • ObjectType: GUIDs specify specific attributes, extended rights, etc. See SelfADSI or similar cheatsheet.
  • InheritedObjectType: specifies what type of AD object the right applies to. All 0s means all objects.
 _______________________________________________________________
| Object Class | GUID |
| -----------------------|--------------------------------------|
| Organizational Units | bf967aa5–0de6–11d0-a285–00aa003049e2 |
| Computer | bf967a86–0de6–11d0-a285–00aa003049e2 |
| User | bf967aba-0de6–11d0-a285–00aa003049e2 |
| Groups | bf967a9c-0de6–11d0-a285–00aa003049e2 |
| Contacts | 5cb41ed0–0e4c-11d0-a286–00aa003049e2 |
---------------------------------------------------------------
  • ObjectFlags: 3 possible values; None, ObjectTypePresent, InheritedObjectAceTypePresent
  • AccessControlType: either ‘Allow’ or ‘Deny’
  • IdentityReference: who has this right, shown as <domain>\<account or group>
  • IsInherited: Pretty self explanatory, False means the right is set at this object, not inherited
  • InheritanceFlags: 3 possible values; None, ContainerInherit, ObjectInherit
  • PropagationFlags: 3 possible values; None, NoPropagateInherit, InheritOnly

What’s a child container vs a child leaf object? Excellent question. A child container object can contain other objects, a leaf cannot. Example containers are OUs, examples of leafs are users, computers, printers, etc. Yes, Microsoft can be maddening with their verbiage. An OU is also a container, but a container is also something like the Users container that exists in AD by default.

This example gives the Helpdesk Tier II group Reset Password and Enable rights on user accounts in the Server_Admins OU. Why would helpdesk be able to reset Server Admins passwords? Another excellent question, and why this example comes from Mishky’s AD Range.

An example NTFS DACL

Invoke-Command -VMName "Research-DC" {(Get-Acl "C:\HTTPsCertificates.json").Access} -Credential $CousinDomainAdminCredObject

This also comes from Mishky’s AD Range and shows the DACL on an exported AD CS template. Guess what rights everyone else has on this file, “effective” or otherwise?

An important note RE DACLs in Windows

Windows uses DACLs for everything from AD to NTFS to registry keys. There are even DACLs that dictate what groups are allowed to use WMI.

The owner of an object in Windows has implicit read rights and can modify the DACL regardless of what is stated in the DACL. Domain Admins can seize ownership of AD objects. Local Administrators can seize ownership of NTFS objects.

All others are implicitly denied if there is no ACE allowing them access. This means there are always deny statements in Windows DACLs even if they are not explicitly stated.

That’s what makes this statement by a certain vendor on LinkedIn so nonsensical.

If the Iron Dome was like Windows then all one would have to do is avoid putting an ACE in their DACL that allows hostile fire.

More odd statements from that vendor

Here is a small sample of statements from over the years.

https://blog.paramountdefenses.com/2020/05/active-directory-security-for-cyber-security-experts.html
https://www.active-directory-security.com/2020/02/bloodhound-for-ad-is-bloody-inaccurate.html
https://www.active-directory-security.com/2017/02/

Missing the forest for the trees

This is actually a rather funny saying when it’s applied to Active Directory.

The reason I had thought that this vendor sounded smart at first was because I didn’t yet know how to enumerate, abuse, set, tweak, etc DACLs and SACLs.

Once I learned a little though I realized something; so called “effective permissions” are really just a subset of permissions.

Free tools like BloodHound aren’t inaccurate at all. They are letting you know that an Allow statement is there, because one is there. The beauty of BloodHound lies in the ‘so what’. It maps out how an attacker could get from A to B by abusing a daisy chain of misconfigured Allows in DACLs to escalate their privileges. At the same time it shows the Blue Team where the ‘choke points’ are in these escalation paths so they can prioritize what to fix first. It does all this for free.

All the Deny statements in the world mean jack all if the attacker can seize ownership, if they can leave the group that is denied, or if they can modify the DACL. If a group should not have certain rights then don’t put an allow statement in that gives it to them. If a user should not have certain rights then do not put them in the group that holds those rights.

If you fix the Allows then you don’t have to worry about the Denys. If you don’t fix the Allows then Denys are likely to only make your Misconfiguration Debt worse, and leave gaps a clever attacker can slip through.

Deny in a default AD environment

Microsoft knows. That’s why this is just about the only Deny in a default AD environment.

Import-Module ActiveDirectory
Set-Location AD:

$Objects = (Get-ADObject -Filter * -Properties *).DistinguishedName
ForEach($Object in $Objects)
{
If((Get-Acl $Object).Access | Where-Object {$_.AccessControlType -eq "Deny"})
{
$Object
(Get-Acl $Object).Access | Where-Object {$_.AccessControlType -eq "Deny"}
}
}

Why is it there? Another excellent question. Ever wondered what this checkbox does in the background?

Summary

However as we already saw, there’s a huge number of implicit Deny statements on every object in AD, every file, every registry key, etc etc. If someone is not the Owner, can’t seize ownership by nature of being an Administrator, and is not given a right in an Allow ACE then they do not have that right.

Some call that “bloody inaccurate”, but it is how Windows works, not to mention SWs, RTRs, FWs, etc etc.

Some though are just interested in marketing, and believe that APTs don’t already know this stuff.

Here at test.local we like free. It’s why our Medium isn’t paywalled, it’s why everything we have done is on GitHub, it’s why Linus Torvalds is our hero and we don’t particularly care for Steve Jobs.

To Microsoft’s credit, they give away evaluation copies of their stuff for free. Their exams are cheap and renewal is free. Microsoft Learn contains a wealth of information for free. PowerShell is open source. Today Microsoft has more employees contributing to open source on GitHub than either Google or Red Hat.

Microsoft has really turned their ship around and come a long way from the laughing stock security wise that they were in the 90s and early 00s. They’re a completely different company now. They are no longer the “open source is cancer” company of Steve Ballmer. Hell even he has now admitted that he was wrong.

References

An ACE up the Sleeve whitepaper: https://specterops.io/wp-content/uploads/sites/3/2022/06/an_ace_up_the_sleeve.pdf

SelfADSI: http://www.selfadsi.org/deep-inside/ad-security-descriptors.htm

Attributes matched to GUIDs: https://learn.microsoft.com/en-us/windows/win32/adschema/attributes-all

Extended Rights matched to GUIDs: https://learn.microsoft.com/en-us/windows/win32/adschema/extended-rights

Self Rights, aka Validated Writes, matched to GUIDs: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/20504d60-43ec-458f-bc7a-754eb64446df

Property Sets matched to GUIDs: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/177c0db5-fa12-4c31-b75a-473425ce9cca

InheritanceFlags: https://learn.microsoft.com/en-us/dotnet/api/system.security.accesscontrol.inheritanceflags?view=net-8.0

ObjectFlags: https://learn.microsoft.com/en-us/dotnet/api/system.security.accesscontrol.objectaceflags?view=net-8.0

PropagationFlags: https://learn.microsoft.com/en-us/dotnet/api/system.security.accesscontrol.propagationflags?view=net-8.0

Container vs leaf: https://www.serveracademy.com/blog/what-is-active-directory/#:~:text=Container%20AD%20Objects%20%E2%80%93%20these%20are,User%2C%20Computer%2C%20and%20printer.

--

--

Rich
Rich

Written by Rich

I work various IT jobs & like Windows domain security as a hobby. Most of what’s here is my notes from auditing or the lab.

No responses yet