Skip to content

feat: add acl_abuse LDAP module for ACE chain enumeration#1176

Open
sup3rDav3 wants to merge 2 commits intoPennyw0rth:mainfrom
sup3rDav3:feature/acl-abuse-module
Open

feat: add acl_abuse LDAP module for ACE chain enumeration#1176
sup3rDav3 wants to merge 2 commits intoPennyw0rth:mainfrom
sup3rDav3:feature/acl-abuse-module

Conversation

@sup3rDav3
Copy link

@sup3rDav3 sup3rDav3 commented Mar 27, 2026

Description

Adds a new LDAP module acl_abuse that enumerates abusable ACEs from a target
principal to other AD objects, surfacing attack paths with inline attack suggestions.

Detections include:

  • WriteDACL, GenericAll, WriteOwner on users, groups, computers, and domain root
  • ForceChangePassword via extended rights GUID
  • WriteProperty on member (group abuse), servicePrincipalName (Kerberoast path),
    msDS-KeyCredentialLink (shadow credentials path)
  • DS-Replication-Get-Changes + Get-Changes-All (DCSync path)

This module was developed with the assistance of Claude (Anthropic) via claude.ai.
Claude assisted with debugging LDAP/impacket attribute access and ACE mask value corrections. All code was reviewed, tested, and verified by the author against a live Windows Server 2022 domain controller.

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Deprecation of feature or functionality
  • This change requires a documentation update
  • This requires a third party update (such as Impacket, Dploot, lsassy, etc)
  • This PR was created with the assistance of AI (Claude via claude.ai — see description above)

Setup guide for the review

Environment:

  • Kali Linux (attacker machine)
  • Python 3.13
  • NetExec installed via poetry in dev mode

Target:

  • Windows Server 2022 domain controller
  • Domain: ad.local

Test setup — run on DC as Domain Admin:

# Create test accounts
New-ADUser -Name "attacker" -SamAccountName "attacker" -AccountPassword (ConvertTo-SecureString "YourPassword123!!" -AsPlainText -Force) -Enabled $true
New-ADUser -Name "victim" -SamAccountName "victim" -AccountPassword (ConvertTo-SecureString "YourPassword123!!" -AsPlainText -Force) -Enabled $true
New-ADUser -Name "svc_test" -SamAccountName "svc_test" -AccountPassword (ConvertTo-SecureString "YourPassword123!!" -AsPlainText -Force) -Enabled $true
New-ADGroup -Name "TestGroup" -SamAccountName "TestGroup" -GroupScope Global -GroupCategory Security

# Grant attacker WriteDACL on victim
$victim = Get-ADUser "victim"
$attacker = Get-ADUser "attacker"
$acl = Get-Acl "AD:$($victim.DistinguishedName)"
$acl.AddAccessRule((New-Object System.DirectoryServices.ActiveDirectoryAccessRule(
    $attacker.SID, "WriteDacl", "Allow")))
Set-Acl "AD:$($victim.DistinguishedName)" $acl

# Grant attacker GenericAll on Domain Admins
$da = Get-ADGroup "Domain Admins"
$acl2 = Get-Acl "AD:$($da.DistinguishedName)"
$acl2.AddAccessRule((New-Object System.DirectoryServices.ActiveDirectoryAccessRule(
    $attacker.SID, [System.DirectoryServices.ActiveDirectoryRights]::GenericAll, "Allow")))
Set-Acl "AD:$($da.DistinguishedName)" $acl2

# Grant ForceChangePassword on svc_test
$svc = Get-ADUser "svc_test"
$acl3 = Get-Acl "AD:$($svc.DistinguishedName)"
$acl3.AddAccessRule((New-Object System.DirectoryServices.ActiveDirectoryAccessRule(
    $attacker.SID, [System.DirectoryServices.ActiveDirectoryRights]::ExtendedRight, "Allow",
    [GUID]"00299570-246d-11d0-a768-00aa006e0529")))
Set-Acl "AD:$($svc.DistinguishedName)" $acl3

Run the module:

nxc ldap <DC_IP> -u attacker -p <password> -d <domain> -M acl_abuse
nxc ldap <DC_IP> -u attacker -p <password> -d <domain> -M acl_abuse -o SHOW_ALL=true
nxc ldap <DC_IP> -u attacker -p <password> -d <domain> -M acl_abuse -o TARGET_USER=otheruser
nxc ldap <DC_IP> -u attacker -p <password> -d <domain> -M acl_abuse -o OUTPUT_FILE=/tmp/findings.json

Expected output:

ACL_ABUSE  [CRITICAL] WriteDACL on victim -> Modify DACL to grant yourself GenericAll, then escalate
ACL_ABUSE  [CRITICAL] GenericAll on Domain Admins -> Full object control...
ACL_ABUSE  [+] ForceChangePassword on svc_test -> Reset target password without knowing current...

Screenshot:

image

Checklist:

  • I have ran Ruff against my changes
  • I have added or updated the tests/e2e_commands.txt file if necessary
  • If reliant on changes of third party dependencies, such as Impacket, dploot, lsassy, etc, I have linked the relevant PRs in those projects
  • I have linked relevant sources that describes the added technique (blog posts, documentation, etc)
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation (PR here: https://github.com/Pennyw0rth/NetExec-Wiki)

- Detects WriteDACL, GenericAll, WriteOwner on AD objects
- Detects ForceChangePassword via extended rights GUID
- Detects WriteProperty on member, servicePrincipalName, msDS-KeyCredentialLink
- Detects DS-Replication-Get-Changes and Get-Changes-All (DCSync path)
- Includes domain root object scanning for replication rights
- Attack suggestions printed inline for each finding
- Optional JSON export via OUTPUT_FILE
- Tested against Windows Server 2022 domain controller
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant