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/