SelfMembership

Summary

FSProtect ACL Alias

SelfMembership

AD Alias

Add/remove self from member

Affected Object Types

Groups

Exploitation Certainty

Certain

AD Attribute

Member

AD Attribute Guid

bf9679c0-0de6-11d0-a285-00aa003049e2

AD Right

Self

Description

The SelfMembership permission allows a user to add themself as a member of a group in Active Directory, facilitating streamlined group management within the directory hierarchy. This permission operates as a Self access right on the target's member attribute.

However, if misconfigured, this permission can introduce a security risk. An attacker can leverage the SelfMembership permission via the Add-ADGroupMember command to add themself to a domain group, thereby gaining unauthorized access. Exploiting this vulnerability could allow for privilege escalation and persistent access within the system.

Identification

PowerShell

Active Directory Module

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

1. Find-SelfMembership Function

function Find-SelfMembership {
    [CmdletBinding()]
    param ([string]$Target,[string]$SearchBase = $null,[string]$OutputPath  = "SelfMembershipAcls.csv")
    Import-Module ActiveDirectory -ErrorAction Stop
    Write-Host "Gathering Active Directory ACLs for explicit Self permissions on the 'member' attribute..."
    $AccessControlType              = [System.Security.AccessControl.AccessControlType]::Allow
    $ActiveDirectoryRights          = [System.DirectoryServices.ActiveDirectoryRights]::Self
    $MemberAttributeGuid            = "bf9679c0-0de6-11d0-a285-00aa003049e2"
    if ($Target) {
        Write-Host "Filtering to group '$Target'..."
        try {
            $objectsToScan = @(
                Get-ADGroup -Identity $Target `
                            -Properties nTSecurityDescriptor `
                            -ErrorAction Stop
            )
        }
        catch {
            Write-Error "Failed to retrieve group '$Target': $($_.Exception.Message)"
            return
        }
    }
    else {
        $adGroupParams = @{
            Filter       = "*"
            Properties   = "nTSecurityDescriptor"
            ErrorAction  = "Stop"
        }
        if ($SearchBase) {
            $adGroupParams["SearchBase"] = $SearchBase
            Write-Host "Searching for all group objects within '$SearchBase'..."
        }
        else {Write-Host "Searching for all group objects in the domain..." }
        try {$objectsToScan = Get-ADGroup @adGroupParams }
        catch {
            Write-Error "Failed to retrieve Active Directory objects: $($_.Exception.Message)"
            return
        }
    }
    if (-not $objectsToScan) {
        Write-Output "No group objects found matching the criteria."
        return
    }
    $foundAcls = foreach ($obj in $objectsToScan) {
        $dn = $obj.DistinguishedName
        try {
            $acl = Get-Acl -Path "AD:$dn"
            foreach ($ace in $acl.Access) {
                if (
                    $ace.AccessControlType -eq $AccessControlType -and
                    $ace.ActiveDirectoryRights -band $ActiveDirectoryRights -and
                    $ace.ObjectType -eq $MemberAttributeGuid -and
                    -not $ace.IsInherited
                ) {
                    [PSCustomObject]@{
                        Group   = $dn
                        Trustee = $ace.IdentityReference.Value
                    }
                }
            }
        }
        catch {Write-Warning "Could not retrieve ACL for '$dn': $($_.Exception.Message)" }
    }
    if ($foundAcls) {
        $count = $foundAcls.Count
        Write-Host "Found $count group object(s) with explicit Self permissions on 'member'."
        try {
            $foundAcls | Export-Csv -Path $OutputPath -NoTypeInformation -Encoding UTF8
            Write-Host "Results exported to '$OutputPath'."
        }
        catch {  Write-Error "Failed to export to CSV '$OutputPath': $($_.Exception.Message)" }
    } else { Write-Output "No explicit Self-member ACLs found on any scanned group."}
}

2. Scan all domain groups in the domain

Find-SelfMembership

3. Scan specific group

Find-SelfMembership -Target "Backup Operators"

4. Using SearchBase to limit the searching scope

Find-SelfMembership -SearchBase "CN=Users,DC=Forestall,DC=Labs"

.NET Directory Services

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

1. Find-SelfMembershipSimple Function

function Find-SelfMembershipSimple {
    [CmdletBinding()]
    param([string]$Target= $null, [string]$SearchBase= $null,  [string]$OutputPath= "SelfMembershipAcls.csv" )
    $memberGuid = [guid]"bf9679c0-0de6-11d0-a285-00aa003049e2"
    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 RootDSE..."
        try {
            $root      = New-Object System.DirectoryServices.DirectoryEntry("LDAP://RootDSE")
            $baseDN    = $root.Properties["defaultNamingContext"].Value
            $ldapPath  = if ($SearchBase) { "LDAP://$SearchBase" } else { "LDAP://$baseDN" }
            $searchRoot= New-Object System.DirectoryServices.DirectoryEntry($ldapPath)
            Write-Verbose "Searching for all group objects under $ldapPath..."
            $searcher = [System.DirectoryServices.DirectorySearcher]::new($searchRoot)
            $searcher.Filter           = "(objectCategory=group)"
            $searcher.PageSize         = 1000
            [void]$searcher.PropertiesToLoad.Add("distinguishedName")
            $hits = $searcher.FindAll()
            Write-Verbose "Found $($hits.Count) group(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 [System.Security.AccessControl.AccessControlType]::Allow -and
                ($ace.ActiveDirectoryRights -band [System.DirectoryServices.ActiveDirectoryRights]::Self) -and
                ($ace.ObjectType           -eq $memberGuid) -and
                (-not $ace.IsInherited)
            ) {
                $who = try {
                    $ace.IdentityReference.Translate([System.Security.Principal.NTAccount]).Value
                } catch {
                    $ace.IdentityReference.Value
                }
                [PSCustomObject]@{
                    Group   = $dn
                    Trustee = $who
                }
            }
        }
    }
    if ($found) {
        $found | Export-Csv -Path $OutputPath -NoTypeInformation -Encoding UTF8
        Write-Host "Exported $($found.Count) entr$(if($found.Count -eq 1){'y'}else{'ies'}) to $OutputPath"
    }
    else { Write-Host "No 'member' Self ACLs found."}
}

2. Scan all domain groups in the domain

Find-SelfMembershipSimple

3. Scan a specific group

Find-SelfMembershipSimple -Target "CN=Backup Operators,CN=Builtin,DC=forestall,DC=labs"

4. Using SearchBase to limit the searching scope

Find-SelfMembershipSimple -SearchBase "CN=Builtin,DC=forestall,DC=labs"

Active Directory Users and Computers

1. Open Active Directory Users and Computers on your Windows server.

2. Right-click on the group name.

3. Select Properties from the context menu.

4. In the Properties window, navigate to the Security tab.

5. Click on the Advanced button to open the Advanced Security Settings dialog.

6. In the Advanced Security Settings window, locate and select the relevant Access Control Entry (ACE) for the user or group you wish to configure.

7. Click Edit to modify the selected ACE.

8. In the permissions list, locate and check the option Add/remove self from member Permission.

9. Click OK to save your changes and close the dialogs.

Exploitation

Windows

an attacker can add itself to a group with this cmdlet.

Add-ADGroupMember -Identity "<Vulnerable Group>" -Members "<yourself>"

Example:

Add-ADGroupMember -Identity 'Domain Admins' -Members 'Attacker'

Linux

Add self to group using bloodyAD

bloodyAD --host <dchost> -d <domain> -u <user>> -p '<pass>' add groupMember "<target group>" <user>

Example:

bloodyAD --host FSDC01.forestall.labs -d forestall.labs -u adam -p 'Temp123!' add groupMember "Account Operators" adam

Mitigation

Access Control Entries identified as dangerous should be removed by following the steps below.

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

2. Double click the affected object and open Security tab.

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

4. Remove the rights that are marked as dangerous.

5. Click OK and Apply buttons for saving changes.

Detection

Adding new Access Control Entries on the Active Directory objects changes the ntSecurityDescriptor attribute of the objects themselves. These changes can be detected with Event IDs 5136 and 4662.. Adding new members to security groups in Active Directory changes the member attribute of the groups themselves. These changes can be detected with the 4756, 4728, and 4732 Event IDs to identify potentially risky group modifications.

Event ID
Description
Fields/Attributes
References

5136

A directory service object was modified.

ntSecurityDescriptor

https://learn.microsoft.com/en-us/windows/security/threat-protection/auditing/event-5136

4662

An operation was performed on an object.

AccessList, AccessMask

https://learn.microsoft.com/en-us/windows/security/threat-protection/auditing/event-4662

4756

A member was added to a security-enabled universal group

Member, TargetUserName, SubjectUserName, MemberName

https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/auditing/audit-security-group-management

4728

A member was added to a security-enabled global group

Member, TargetUserName, SubjectUserName, MemberName

https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/auditing/audit-security-group-management

4732

A member was added to a security-enabled local group

Member, TargetUserName, SubjectUserName, MemberName

https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/auditing/event-4732

References

Last updated

Was this helpful?