Inheritance Explained, an Example, & Security Considerations

Rich
8 min readJan 19, 2023

--

TL;DR a simple example of how a [mis]configuration can create an escalation path, the importance of inheritance, and how to easily check for this sort of thing.

Welcome to Part XV of our Auditing AD Series!

Part I: 3 warm up questions to get us started

Part II: Who can reset the CISO’s password?

Part III: Who can execute DCSync?

Part IV: Who can modify the Domain Admins group?

Part V: Domain dominance in minutes via ACL abuse (i.e. why auditing AD matters)

Part VI: Why Allow statements matter a LOT more than Deny ones

Part VII: Sneaky persistence via hidden objects in AD

Part VIII: SDDL, what is it, does it matter?

Part IX: Do you know who owns your domain?

Part X: Who can push ransomware via Group Policy?

Part XI: Free ways to simplify auditing AD

Part XII: Sidenote on arcane rights like Self

Part XIII: Sidenote on the ScriptPath right

Part XIV: Self & so called “Effective Permissions”

Part XV: Inheritance Explained & an Example

Part XVI: Summary of our Auditing AD Series

Annex A: Scrubbing Group Policy for local admins

Annex B: What Property Sets in AD are, & why they matter

Annex C: Dangerous Rights & RE GUIDs Cheatsheet

Annex D: Mishky’s Blue Team Auditor

Annex E: Even ChatGPT gets this stuff wrong

Annex F: Get-ADPermission Cheatsheet

Annex G: Mishky’s Red Team Enumerate & Attack tools

Background

This scenario was prompted by someone’s question regarding how to delegate specifically the right to reset passwords on an OU. Normally you would also delegate the right to re-enable user accounts in the OU as users tend to lock out their account before they ask for a password reset.

Naturally we thought of security concerns involved, hence this scenario.

I had also been meaning to work inheritance into an example as all of our Set-Acl examples up until now did not include it. I’ll update the Set-Acl Cheatsheet later to include setting inheritance on an OU as well.

The Scenario

Management has decided that the ‘Cyber Manager’ should have the ability to add & remove members of Domain Admins. Since this makes them a Privileged User they were placed in that OU prior to delegation of that right.

Import-Module ActiveDirectory
Set-Location AD:
$ADRoot = (Get-ADDomain).DistinguishedName

New-ADUser "Cyber Manager" -DisplayName "Cyber Manager" -Enabled $true -Path "ou=privileged users,$ADRoot" -UserPrincipalName "CyberManager@test.local" -SamAccountName "CyberManager" -AccountPassword $(ConvertTo-SecureString "SomeSuperSecretPassword2023!!" -AsPlainText -Force)

#Give a user WriteProperty 'member' on a given group
$victim = (Get-ADGroup "Domain Admins" -Properties *).DistinguishedName
$acl = Get-ACL $victim
$user = New-Object System.Security.Principal.SecurityIdentifier (Get-ADUser "CyberManager").SID

#Allow specific WriteProperty 'member'
$acl.AddAccessRule((New-Object System.DirectoryServices.ActiveDirectoryAccessRule $user,"WriteProperty","ALLOW",([GUID]("bf9679c0–0de6–11d0-a285–00aa003049e2")).guid,"None",([GUID]("00000000–0000–0000–0000–000000000000")).guid))

#Apply above ACL rules
Set-ACL $victim $acl

Helpdesk is a member of the group Service Desk. Both this user and group are also in the Privileged User OU as the Service Desk group has been delegated password reset and re-enable rights on the VIPs OU.

Import-Module ActiveDirectory
Set-Location AD:
$ADRoot = (Get-ADDomain).DistinguishedName

New-ADGroup "Service Desk" -Path "ou=privileged users,$ADRoot" -DisplayName "Service Desk" -Description "Group for helpdesk folks, has privileges to reset pwds & re-enable users" -GroupScope Global
Add-ADGroupMember -Identity "Service Desk" -Members "Helpdesk"

#Give a group Password reset & re-enable over a given OU
$victim = (Get-ADOrganizationalUnit "ou=VIPs,dc=test,dc=local" -Properties *).DistinguishedName
$acl = Get-ACL $victim
$user = New-Object System.Security.Principal.SecurityIdentifier (Get-ADGroup -Identity "Service Desk").SID

#Allow specific password reset
$acl.AddAccessRule((New-Object System.DirectoryServices.ActiveDirectoryAccessRule $user,"ExtendedRight","ALLOW",([GUID]("00299570–246d-11d0-a768–00aa006e0529")).guid,"Descendents",([GUID]("bf967aba-0de6–11d0-a285–00aa003049e2")).guid))

#Allow specific WriteProperty on the Enabled attribute
$acl.AddAccessRule((New-Object System.DirectoryServices.ActiveDirectoryAccessRule $user,"WriteProperty","ALLOW",([GUID]("a8df73f2-c5ea-11d1-bbcb-0080c76670c0")).guid,"Descendents",([GUID]("bf967aba-0de6–11d0-a285–00aa003049e2")).guid))

#Apply above ACL rules
Set-ACL $victim $acl

Inheritance

We hadn’t talked about inheritance of rights much before, so I wanted to work this topic into a howto. In a security context there’s three types of inheritance to be aware of:

Note; don’t confuse “Descendents” with “descendants”, especially when you are querying. Descendant refers to someone who descends from someone else. Descendent refers to the act of moving downward.

Additionally inheritance can apply only to specific types of AD objects. Quoting selfadsi:

We wanted to give Service Desk specific rights to reset passwords and re-enable accounts for users in the VIPs OU. Hence we used InteritanceType Descendents with InheritedObjectType bf967aba-0de6–11d0-a285–00aa003049e2. Windows permissions are very granular and we can easily do this via PowerShell and a handy cheatsheet from sefladsi.

Exemption to inheritance

There is a detail to be aware of regarding inheritance; the adminCount. If a user was ever placed into a group that is protected by the AdminSDHolder then an attribute called ‘adminCount’ is added to their account and set to 1. If an account has an adminCount of 1 than it does not inherit from its OU, as seen below.

YaYa had added herself to Domain Admins in a previous howto, in spite of what a vendor’s tool thought was possible. Even if they are later removed this attribute stays.

This is a safety switch to stop sysadmins from shooting themselves in the foot. Without it a careless admin could move the Domain Admins group into an OU that the Service Desk had been given GenericAll on and someone in Service Desk could seize control of the domain before the admin realized the implications of their action.

Please note that this is a safety switch, NOT a security mechanism, much like PowerShell execution policy. It will NOT stop an attacker from shooting you in the foot on purpose.

Also, if you need to remove it from an account just do

Set-Aduser “yaya” -Replace @{adminCount=0}

Please note that this is for lab purposes only. It is NOT recommended to remove an account from Domain Admins in production and then let the person keep using it.

A full explanation of the AdminSDHolder, SDProp, adminCount, etc would become an entire howto on its own.

The [mis]configuration

Everything is great up until now. The members of service desk can help out the VIPs and the Cyber Manager can do … whatever it was that management thought they needed to do. In all honesty there’s a good chance that the Cyber Manager has no idea exactly what they can do.

That might be why they insisted that they should be in VIPs.

Move-ADObject “cn=Cyber Manager,ou=Privileged Users,$ADRoot” -TargetPath “ou=VIPs,$ADRoot”

The resulting security issue

Everyone in the Service Desk group now has a clear path to make themselves, or anyone really, a member of Domain Admins. They can then take whatever action they want.

This is because Cyber Manager can add or remove members of Domain Admins.

(Get-Acl (Get-ADGroup “Domain Admins”).DistinguishedName).Access | Where-Object {$_.IdentityReference -like “*CyberManager*”}

The members of Service Desk can impersonate the Cyber Manager at will.

(Get-Acl (Get-ADUser “CyberManager”).DistinguishedName).Access | Where-Object {$_.IdentityReference -like “*Service Desk*”}

How to check for this

This is where BloodHound really shines. BlueHound is still very new, but holds the promise to do the same, and more, from a Blue Team perspective. It can show all paths to Domain Admins, including those that pivot through a GPLink or dumping local credentials.

It will also point out this misconfiguration if you select Cyber Manager in the graph above.

We can also use free tools such as Mishky’s Blue Team version to check for stuff like this. (Full query is here.)

Key takeaway

All this is really just showing what can happen if you don’t follow best practice. AD doesn’t contain privilege escalation paths by default. It also is not vulnerable to Kerberoasting or ASREPRoasting by default.

(Pass-The-Ticket (PTT) is a bit more nuanced. The attacker would have to gain local admin on a workstation that has delegation enabled, a non-default setting, before they could abuse the default configuration.)

It is vulnerable to Pass-The-Hash (PTH) and Name Poisoning by default, however these can be easily mitigated.

Don’t get sloppy

Others have said it before, notably Trimarc, but I’ll reiterate. Plan your OU structure carefully. Create separate privileged user accounts and put them in the right OU. OU structure isn’t just about tidiness, organization, and getting a quick count of how many users or computers you have in a certain section or sub organization, although those are also important.

Summary

Plan your OUs out carefully, put privileged users in their own OU, have them use separate accounts for this naturally, delegate carefully, check on a set schedule, and fix any issues that you find. Windows permissions are incredibly granular. This is a good thing because one can delegate very precisely exactly what privilege should be held on what AD objects. One just has to know what they are doing, plan things out first, and audit.

References

Inheritance object types: http://www.selfadsi.org/deep-inside/ad-security-descriptors.htm

Descendant vs Descendent: https://cat.wordpandit.com/descendant-descendent/#:~:text=Descendant%2C%20used%20as%20a%20noun,its%20usage%20is%20less%20common.

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

Random AD inheritance stuff: https://www.windows-active-directory.com/object-permissions-active-directory.html

AdminSDHolder, SDProp, & adminCount: https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/plan/security-best-practices/appendix-c--protected-accounts-and-groups-in-active-directory

Set adminCount manually on an account: https://stackoverflow.com/questions/54029898/modify-admincount-to-zero

Trimarc on AD security best practices: https://www.hub.trimarcsecurity.com/post/ten-ways-to-improve-ad-security-quickly

DACLs, SACLs, etc: https://helgeklein.com/blog/permissions-a-primer-or-dacl-sacl-owner-sid-and-ace-explained/

--

--

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.