Skip to content

ManageGPLink

Copy page

Summary

Forestall ACL Alias ManageGPLink
AD Alias Write gPLink
Affected Object Types OU
Exploitation Certainty Likely
Attribute GP-Link
Attribute Guid f30e3bbe-9ff0-11d1-b603-0000f80367c1
AD Right WriteProperty

Description

The ManageGPLink permission in Active Directory allows an account to link or unlink Group Policy Objects (GPOs) to an Organizational Unit (OU), domain, or site. This permission is crucial for administrators to manage the distribution and application of policies across different segments of the network, ensuring that users and computers receive the appropriate configurations and security settings.

However, if misconfigured, the ManageGPLink permission can introduce significant security vulnerabilities. An attacker with this permission can link a malicious GPO to an OU, thereby affecting all users and computers within that OU. This could enable the attacker to execute arbitrary code, deploy malware, or alter security settings across multiple systems. Exploiting this vulnerability could lead to unauthorized access, privilege escalation, and widespread compromise of network resources.

Identification

PowerShell

Active Directory Module

Using the ActiveDirectory PowerShell module, you can enumerate ManageGPLink entries.

1. Find-ManageGPLink function

function Find-ManageGPLink {
[CmdletBinding()]
param(
[Parameter(
Position = 0,
ValueFromPipeline = $true,
ValueFromPipelineByPropertyName = $true
)] [string[]]$Target, [Parameter(Position = 1)][string]$OutputPath = "ManageGPLink.csv")
begin {
Import-Module ActiveDirectory -ErrorAction Stop
$allowType = [System.Security.AccessControl.AccessControlType]::Allow
$writeRight = [System.DirectoryServices.ActiveDirectoryRights]::WriteProperty
$gpLinkGuid = [Guid]"f30e3bbe-9ff0-11d1-b603-0000f80367c1"
$results = [System.Collections.Generic.List[PSObject]]::new()
}
process {
if ($Target) {
try {$ous = $Target | ForEach-Object { Get-ADOrganizationalUnit -Identity $_ -ErrorAction Stop }
}
catch { Write-Warning "Failed to resolve one or more OUs: $_" ;return}
}
else { $ous = Get-ADOrganizationalUnit -Filter * }
foreach ($ou in $ous) {
$ouDN = $ou.DistinguishedName
(Get-Acl -Path "AD:$ouDN").Access |
Where-Object {
$_.AccessControlType -eq $allowType -and
($_.ActiveDirectoryRights -band $writeRight) -eq $writeRight -and
$_.ObjectType -eq $gpLinkGuid -and
-not $_.IsInherited
} |
ForEach-Object {
$obj = [PSCustomObject]@{
VulnerableOU = $ouDN
Account = $_.IdentityReference.Value
Rights = $_.ActiveDirectoryRights
}
$results.Add($obj)
}
}
}
end {
try {
$results | Export-Csv -Path $OutputPath -NoTypeInformation -Force
Write-Host "Results exported to $OutputPath"
}
catch { Write-Warning "Failed to write CSV to '$OutputPath': $_"}
}
}

2. Scan all domain OUs.

Find-ManageGPLink

3. Scan a specific OU

Find-ManageGPLink -Target "OU=Workstations,DC=forestall,DC=labs"

.NET Directory Services

By leveraging PowerShell’s built-in .NET DirectoryServices namespace, you can enumerate ManageGPLink entries without relying on any external modules or dependencies.

1. Find-ManageGPLink function

function Find-ManageGPLinkSimple {
[CmdletBinding()]
param([string]$Target)
$allowType = [System.Security.AccessControl.AccessControlType]::Allow
$writeRight = [System.DirectoryServices.ActiveDirectoryRights]::WriteProperty
$gpLinkGuid = [Guid]"f30e3bbe-9ff0-11d1-b603-0000f80367c1"
if ($Target) {
Write-Verbose "Binding directly to object: $Target"
try { $entries = @( New-Object System.DirectoryServices.DirectoryEntry("LDAP://$Target") )}
catch {Write-Error "Failed to bind to '$Target': $_" ; return }
}
else {
Write-Verbose "Binding to local RootDSE..."
try {
$root = New-Object System.DirectoryServices.DirectoryEntry("LDAP://RootDSE")
$baseDN = $root.Properties["defaultNamingContext"].Value
$ldapPath = "LDAP://$baseDN"
$searchRoot = New-Object System.DirectoryServices.DirectoryEntry($ldapPath)
Write-Verbose "Searching for all OUs under $ldapPath..."
$searcher = [System.DirectoryServices.DirectorySearcher]::new($searchRoot)
$searcher.Filter = "(objectCategory=organizationalUnit)"
$searcher.PageSize = 1000
[void]$searcher.PropertiesToLoad.Add("distinguishedName")
$hits = $searcher.FindAll()
Write-Verbose "Found $($hits.Count) OU(s)."
}
catch {
Write-Error "LDAP enumeration failed: $_" ; return
}
$entries = foreach ($hit in $hits) {
try { $hit.GetDirectoryEntry() }
catch { Write-Warning "Could not bind entry: $_"; continue }
}
}
$found = foreach ($entry in $entries) {
$dn = $entry.distinguishedName
Write-Verbose "Checking ACLs on: $dn"
try {
$acl = $entry.ObjectSecurity
$aces = $acl.GetAccessRules($true, $true, [System.Security.Principal.SecurityIdentifier])
}
catch {
Write-Warning "Could not read ACL for $dn : $_"
continue
}
foreach ($ace in $aces) {
if (
$ace.AccessControlType -eq $allowType -and
($ace.ActiveDirectoryRights -band $writeRight) -eq $writeRight -and
$ace.ObjectType -eq $gpLinkGuid -and
-not $ace.IsInherited
) {
$who = try {
$ace.IdentityReference.Translate([System.Security.Principal.NTAccount]).Value
} catch {
$ace.IdentityReference.Value
}
[PSCustomObject]@{
OU = $dn.ToString();
Account = $who
Rights = $ace.ActiveDirectoryRights
}
}
}
}
if ($found) {
$found | Export-Csv -Path ".\ManageGPLinkAcls.csv" -NoTypeInformation -Encoding UTF8
Write-Host "Exported $($found.Count) entr$(if($found.Count -eq 1){'y'}else{'ies'}) to ManageGPLinkAcls.csv"
}
else {Write-Host "No 'gplink' ACLs found."}
}

2. Scan all domain OUs.

Find-ManageGPLinkSimple

3. Scan a specific OU

Find-ManageGPLinkSimple -Target "OU=Workstations,DC=forestall,DC=labs"

Exploitation

This edge is exploitable only if you already control an existing Group Policy Object or have the privileges to create a new one.

With the WriteProperty right on the OU’s gPLink attribute, an attacker can inject or modify the list of GPOs linked to that OU. Once a malicious GPO is linked, every computer and user within the OU will process its settings at the next Group Policy refresh. For a step‑by‑step exploit walkthrough and PowerShell examples, see the GPOWrite edge. For how linked GPOs are represented in the graph, see the GPLINK edge.

This capability is granted by broader permissions on the OU, domain, or site. A principal holding GenericAll, GenericWrite, or Owner over the container can write the gPLink attribute and abuse this edge.

Windows

An attacker can create a new or modify gPLink with these cmdlets on Windows. (You should import the GroupPolicy module by running GroupPolicy)

To create a new GPO:

New-GPLink -Name "<GPO to be added>" -Target "<Vulnerable OUs distinguishedName>"

Example:

New-GPLink -Name "Admins_GPO" -Target "OU=Hackers,DC=forestall,DC=labs"

To update a GPO link:

Set-GPLink -Name "<GPO to be added>" -Target "<Vulnerable OUs distinguishedName>"

Example:

Set-GPLink -Name "Admins_GPO" -Target "OU=Hackers,DC=forestall,DC=labs"

After adding a GPLink, attackers can control objects in the OU. For further exploitation details, please refer to GPOWrite.

Set Link using powershell

Set Link using powershell

Linux

Open a PowerShell session and run PowerShell commands on Linux systems with this cmdlet (Impacket tools should be installed before running the command):

impacket-psexec '<domain>/<user login name>:<password>@<IP Address>'

Example:

impacket-psexec 'FORESTALL/ANGEL_ROSA:[email protected]'
Execute using PsExec

Execute using PsExec

Mitigation

Dangerous Access Control Entries should be removed by following the steps below.

1. Open Active Directory Users and Computers, and activate the Advanced Features option.

2. Double-click the affected OU and open the Security tab.

3. In this tab, click the Advanced button and open the dangerous Access Control Entry.

4. Remove the Write gPLink right.

5. Click OK and Apply to confirm and save your changes.

ADUC

ADUC

Detection

Adding new Access Control Entries to Active Directory objects changes the ntSecurityDescriptor attribute of the objects themselves. These changes can be detected with the 5136 and 4662 Event IDs to identify dangerous modifications.

Event ID Description Fields/Attributes References
5136 A directory service object was modified. AttributeLDAPDisplayName: gPLink, ObjectDN (the OU), New/Old Value https://learn.microsoft.com/en-us/windows/security/threat-protection/auditing/event-5136
4662 An operation was performed on an object. AccessMask / Properties indicating write to gPLink https://learn.microsoft.com/en-us/windows/security/threat-protection/auditing/event-4662

References

New-GPLink (Microsoft Docs)

OUnedPy: Exploiting Hidden Organizational Units ACL Attack Vectors in Active Directory (Synacktiv)

Was this page helpful?

Thank you for your feedback.