GPO abuse (SharpGPOAbuse, Restricted Groups)
Group Policy Objects (GPOs) are AD objects with their own DACL: if a user has WriteDacl, WriteOwner, GenericWrite or GenericAll over a GPO, they can inject directives into it and make the machines that apply it run changes chosen by the attacker. It is a branch of ACL abuse that escalates from a permission over one object to code execution on many hosts.
Enumeration
First you locate the GPOs and who has write rights over them. With PowerView, from a domain-joined machine:
Get-DomainGPO | select displayname # GPO inventory
$sid = Convert-NameToSid "Domain Users"
Get-DomainGPO | Get-ObjectAcl | ? { $_.SecurityIdentifier -eq $sid } # what "Domain Users" can write
Get-GPO -Guid <GUID> # name from a GUIDFrom Linux, BloodHound flags the GPO edge with write rights, and netexec with the gpp_autologin/gpp_password module covers the case of credentials stored in SYSVOL (see gpp-cpassword).
Exploitation
The cleanest vector is Restricted Groups (--AddLocalAdmin): the GPO forces clients to add a user to the local Administrators group. When the GPO applies to the DC (for example, the Default Domain Policy), the DC itself obeys and the attacker becomes Local Admin of the DC, then SYSTEM with psexec.
.\SharpGPOAbuse.exe --AddLocalAdmin --GPOName "Default Domain Policy" --UserAccount <me>
gpupdate /forceOther SharpGPOAbuse primitives:
--AddUserRights SeTakeOwnershipPrivilege(more surgical, less noise)--AddComputerScript/--AddUserScript(logon/startup script)--AddComputerTask(scheduled task as SYSTEM on the client)
From Linux without touching Windows, pyGPOAbuse does the same (it creates an immediate task that runs a command on the next gpupdate, every 90 min by default):
pygpoabuse.py <domain>/<me>:<pw> -gpo-id <GUID> -command 'net localgroup administrators <me> /add'Nuance. BloodHound models the GPO→OU→objects relationships: GPO GPLink OU, OU Contains User/Computer. The real escalation is the full composition, not just having write access to the GPO: you have to check which OU it is linked to and which objects hang off it. The change is not immediate: the client applies it on the next gpupdate cycle. Modifying a GPO leaves a trail in SYSVOL and in gPCFileSysPath, and modern EDRs alert on changes to Default Domain Policy.
How to detect it. Editing the GPO leaves two parallel trails: in the directory, an Event ID 5136 (a directory service object was modified) on the GPO object (typically the versionNumber or gPCMachineExtensionNames attribute); on disk, changes to the SYSVOL files under \Policies\{GUID}\ that a FIM catches on the fly. Application on the client delivers the payload: --AddLocalAdmin generates a 4732 (member added to local Administrators group) on each affected machine, and --AddComputerTask a 4698 (a scheduled task was created) as SYSTEM. That the touched GPO is the Default Domain Policy or the Default Domain Controllers Policy raises any of those events to an incident.
Defence. Audit who holds WriteDacl/WriteOwner/GenericWrite over Tier-0 GPOs (Default Domain Policy, Default Domain Controllers Policy). Monitor gPCFileSysPath changes and SYSVOL content with a FIM. Use Restricted Groups only on specific OUs, never on Default Domain Policy. It is a sibling of cPassword in GPP and leads to execution as SYSTEM.
Machines where it's used
- VaultProving Grounds Practice