The PowerView PowerUsage Series #3
This is the third post in my âPowerView PowerUsageâ series, and follows the same Scenario/Solution/Explanation pattern as the previous entries. The original post contains a constantly updated list of the entire series.
Active Directory access control is something my workmates and I have been very interested in over the past year. So far, this has resulted in the release of BloodHoundâs ACL Attack Path Update, as well as work on Active Directory DACL backdooring by @_wald0 and myself (whitepaper here). This post will cover DACL enumeration for GPOs in a foreign domain.
Why care about this? Well, if you are able to edit a GPO, then you can gain control of any user or computer the GPO applies to. If your goal is to figure out specifically what objects a given GPO applies to, check out this line in the âPowerView-3.0-tricksâ gist.
The Scenario
Youâre on an engagement and want to know what security principals can edit GPOs in a foreign domain (in this case dev.testlab.local).
The Solution
Get-DomainObjectAcl -Domain 'dev.testlab.local' -LDAPFilter '(objectCategory=groupPolicyContainer)' -ResolveGUIDs | ? {
($_.SecurityIdentifier -match '^S-1-5-.*-[1-9]\d{3,}$') -and `
($_.ActiveDirectoryRights -match 'WriteProperty|GenericAll|GenericWrite|WriteDacl|WriteOwner')
} | % {
$PrincipalDN = Convert-ADName $_.SecurityIdentifier -OutputType DN
New-Object PSObject -Property @{'ObjectDN'=$_.ObjectDN ; 'PrincipalSID'=$_.SecurityIdentifier; 'PrincipalDN'=$PrincipalDN }
} | fl
GPO_ACL.ps1Â

The Explanation
First, we use PowerViewâs Get-DomainObjectACL to enumerate the ACEs for all group policy objects in a foreign domain. The -Domain âdev.testlab.localâ flag signals the query to run in the foreign domain, and the LDAP filter -LDAPFilter â(objectCategory=groupPolicyContainer)â indicates to only return group policy objects. The -ResolveGUIDs flag indicates that any target GUIDs in the ACEs should be resolved to their human readable names.
We then implement a custom filter with ? {âĤ} (Where-Object), only returning results where the SecurityIdentifier of the trustee/principal (the object that has the rights) matches the regex â^S-1â5-.*-[1â9]\d{3,}$â. This returns only results where the security identifier of the trustee has a relative identifier (RID) of -1000 and above, i.e. objects that are not built in like âDomain Adminsâ. The purpose of this filter is to reduce noise in an attempt to enumerate more âinterestingâ misconfigurations of non-standard domain users. The second part of the filter matches for rights in the ACE that indicate some type of control relationship (generic all rights, rights to change the owner, etc), i.e. some type of âobject takeoverâ primitive that allows for compromise of the target object. For more information on this type of relationship/attack, check out @wald0âs and my âAn ACE Up the Sleeveâ whitepaper.
From here, in order to add a bit more contextual information for the operator, we process each ACE result on the pipeline by way of % {âĤ} (ForEach-Object), and resolve the SecurityIdentifier of the ACE to a distinguished name by using PowerViewâs Convert-ADName with the -OutputType set to DN (distinguished name). We finish by using New-Object PSObject to create a new custom object in the middle of the pipeline that contains the information we care about, and pipe everything to fl (Format-List) for easy display.
Now that you know what accounts are able to edit these interesting GPOs, you could perform targeted account compromise of these accounts and use them to push malicious GPOs.
Originally published at harmj0y.