Get-Acl Cheatsheet

TL;DR cheatsheet on querying using Get-Acl. Background on ACLs & why they matter here, although this lab exercise probably makes the point best.

Welcome to Part III of our cheatsheet series!

Part I: Mimikatz cheatsheet

Part II: Set-Acl cheatsheet

Part III: Get-Acl cheatsheet

Part IV: Enumerating AD cheatsheet

Background

This is another seemingly simple command, right? It can be, but it really depends on exactly what you are looking for and how specific your query is. If all you want to do is see an ACL then by all means, just

(Get-Acl (Get-ADDomain).DistinguishedName).Access

However this is hardly useful by itself. Generally you will be looking either for who holds certain DangerousRights or what DangerousRights are held by a given user, like yourself.

We will dive into this by examining

DangerousRights table

DangerousRights (Sean Metcalf’s term):

Rights specific to the domain root, $root = (Get-ADDomain).DistinguishedName

Rights specific to OUs

Query for DangerousRights held by yourself

I call this one Mishky’s PowerView as it was inspired by PowerView’s Invoke-ACLScanner and Trimarc’s query of ADCS rights. You can tell how heavily Trimarc influenced it as we didn’t even change all their variable names.

Download Get-ADNestedGroups.ps1 from http://blog.tofte-it.dk/powershell-get-all-nested-groups-for-a-user-in-active-directory/ and import it first. Mishky’s PowerView relies on it to check all groups the given user is nested in. Invoke-ACLScanner doesn’t check for rights held by the all the groups the user is nested in.

#Run/import Get-ADNestedGroups.ps1 first! (Available from: http://blog.tofte-it.dk/powershell-get-all-nested-groups-for-a-user-in-active-directory/)
Import-Module ActiveDirectory
Import-Module .\Get-ADNestedGroups.ps1
Set-Location AD:
$ADRoot = (Get-ADDomain).DistinguishedName
$Accounts = (Get-ADUserNestedGroups (Get-ADUser "$env:username" -Properties *).DistinguishedName).Name$MyGroups = $Accounts.ForEach{[regex]::Escape($_)} -join '|'
$MyGroups.Replace('\','')
$AlsoCheck = "$env:username|Everyone|Authenticated Users|Domain Users"$ADCS_Objects = (Get-ADObject -Filter * -SearchBase $ADRoot).DistinguishedName$DangerousRights = "GenericAll|WriteDACL|WriteOwner|GenericWrite|WriteProperty|Self"$DangerousGUIDs = "1131f6aa-9c07-11d1-f79f-00c04fc2dcd2|1131f6ad-9c07-11d1-f79f-00c04fc2dcd2|00000000-0000-0000-0000-000000000000|00299570-246d-11d0-a768-00aa006e0529"$FishyGUIDs = "ab721a56-1e2f-11d0-9819-00aa0040529b|ab721a54-1e2f-11d0-9819-00aa0040529b"ForEach ($object in $ADCS_Objects)
{
$BadACE = (Get-Acl $object -ErrorAction SilentlyContinue).Access | Where-Object {(($_.IdentityReference -match $MyGroups) -or ($_.IdentityReference -match $AlsoCheck)) -and (($_.ActiveDirectoryRights -match $DangerousRights) -or ((($_.ActiveDirectoryRights -like "*ExtendedRight*") -and (($_.ObjectType -match $DangerousGUIDs) -or ($_.ObjectType -match $FishyGUIDs))))) -and ($_.AccessControlType -eq "Allow")}If ($BadACE)
{
Write-Host "Object: $object" -ForegroundColor Red
$BadACE
}
}

Back in the Set-Acl cheatsheet we listed examples that gave DCSync rights to a specific user and Self rights to a group. We then run Mishky’s PowerView as that user and it flags those three specific ACEs in the domain root’s ACL and lets us know what object this ACL applies to in red font.

Bear in mind that “DCSync rights” are two ExtendedRights with GUIDs, so there are two different ACEs. To recap, those two rights are DS-Get-Replication-Changes and DS-Get-Replication-Changes-All.

Naturally if you are in the GUI they have different names. Oh Microsoft, consistency is not their strong suit.

To my surprise, Mishky’s query didn’t really take any longer to run than PowerView’s Invoke-ACLScanner. It also doesn’t trip Defender :P

Breaking this down Barney Style

The basic syntax for querying an ACL is

$thing = (Get-ADUser $env:username –Prop *).DistinguishedName ; (Get-Acl “$thing”).Access

To look for specific things start tacking stuff to look for onto the end:

| Where-Object {$_.ObjectType -eq “00299570–246d-11d0-a768–00aa006e0529”}

To look for multiple conditions just start putting them inside parenthesis and use operators:

| Where-Object {($_.ActiveDirectoryRights –eq “ExtendedRight”) -and ((ObjectType -eq “00299570–246d-11d0-a768–00aa006e0529”) -or (ObjectType -eq “00000000–0000–0000–0000–000000000000”))}

This starts getting long, which is why we simply used a variable called $DangerousGUIDs.

Example query

Let’s say you want to see who has Self rights with either the specific “self-membership” GUID or all 0s on Domain Admins:

(Get-Acl (Get-ADGroup “Domain Admins”).DistinguishedName).Access | Where-Object {($_.ActiveDirectoryRights -like “*Self*”) -and (($_.ObjectType -eq “bf9679c0–0de6–11d0-a285–00aa003049e2”) -or ($_.ObjectType -eq “00000000–0000–0000–0000–000000000000”)) -and ($_.AccessControlType -eq “Allow”)}

Another example query

If you are looking for something really specific then you have to use the table of DangerousRights and then put the whole query together. This query is for who can pull NTLM hashes from NTDS.dit, aka DCSync:

$suspects = ((Get-ACL (Get-ADDomain).DistinguishedName).Access | Where {((($_.ActiveDirectoryRights -like “*ExtendedRight*”) -and (($_.ObjectType -eq “1131f6aa-9c07–11d1-f79f-00c04fc2dcd2”) -or ($_.ObjectType -eq “1131f6ad-9c07–11d1-f79f-00c04fc2dcd2”) -or ($_.ObjectType -eq “00000000–0000–0000–0000–000000000000”))) -or ($_.ActiveDirectoryRights -like “*GenericWrite*”) -or ($_.ActiveDirectoryRights -like “*GenericAll*”) -or ($_.ActiveDirectoryRights -like “*WriteDACL*”) -or ($_.ActiveDirectoryRights -like “*WriteOwner*”) -and ($_.AccessControlType -eq “Allow”))}).IdentityReference

These queries can get rather long, which is why it’s often simpler to match against a list:

(Get-Acl $object).Access | Where-Object {$_.ActiveDirectoryRights -match $DangerousRights}

Querying NTFS

Query the owner:

(Get-Acl -Path “I:”).Owner

Query the ACL:

(Get-Acl -Path “I:”).Access

You can then query for exactly what you are looking for using the same syntax as before:

(Get-Acl -Path “I:”).Access | Where-Object {($_.FileSystemRights -eq “FullControl”) -and ($_.AccessControlType -eq “Allow”)}

Microsoft being Microsoft, the rights that matter in a security context have NTFS specific names. A full list is here.

Some of the more important ones:

NTFS specific

NTFS privileges matter too. Tools like PowerUp.ps1 can automate finding executables that run as a higher privileged user but let lower level users write to them, for example, and then take advantage of this to elevate privileges.

Summary

The syntax itself is not all that tricky, you just have to know what to look for. That’s where the table of DangerousRights comes in. The parenthesis and operators can get tricky as it’s easy to forget a single parenthesis somewhere.

Hence using variables and lists to match to is much easier. It also allows you to do things like whitelist groups that you meant to delegate to and then query what groups have DangerousRights and are not whitelisted.

References

Ired team on DCSync specific rights: https://www.ired.team/offensive-security-experiments/active-directory-kerberos-abuse/dump-password-hashes-from-domain-controller-with-dcsync

Handy GUID table: https://www.powershellgallery.com/packages/DSACL/1.0.0/Content/DSACL.psm1

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

NTFS privileges: https://adamtheautomator.com/ntfs-permissions/

List of NTFS privileges as seen in PowerShell: https://docs.microsoft.com/en-us/dotnet/api/system.security.accesscontrol.filesystemrights?view=net-6.0

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
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.