Skip to content

Add gMSA abuse module for discovery and exploitation#1216

Open
goosvorbook wants to merge 4 commits intoPennyw0rth:mainfrom
goosvorbook:gmsa_abuse
Open

Add gMSA abuse module for discovery and exploitation#1216
goosvorbook wants to merge 4 commits intoPennyw0rth:mainfrom
goosvorbook:gmsa_abuse

Conversation

@goosvorbook
Copy link
Copy Markdown

@goosvorbook goosvorbook commented Apr 23, 2026

Description

Adds a new LDAP module gmsa_abuse that detects and exploits write rights on Group Managed Service Account (gMSA) objects to extract NT hashes.

NetExec already supports dumping gMSA passwords via --gmsa, but this requires the authenticated user to already be listed in msDS-GroupMSAMembership. This module covers the preceding step: discovering which principals have write rights on gMSA objects and exploiting those rights to grant themselves read access to the managed password.

Background: When a principal holds GenericWrite (or similar write rights) on a gMSA object in Active Directory, they can overwrite the msDS-GroupMSAMembership attribute — a security descriptor that controls who may read the gMSA's managed password. By replacing this SD with one that grants themselves access, the attacker can read msDS-ManagedPassword and recover the NT hash.

Module actions:

  • ACTION=find (default) — Enumerates all gMSA objects, reads their nTSecurityDescriptor via DACL control, and reports non-privileged trustees with GenericAll, GenericWrite, WriteDACL, WriteOwner, WriteProperties, or targeted WriteProperty on msDS-GroupMSAMembership. Results are deduplicated per trustee; built-in privileged groups are filtered automatically. Optionally filtered by PRINCIPAL=<account>.

  • ACTION=exploit — Given TARGET=<gMSA> and PRINCIPAL=<account>, patches msDS-GroupMSAMembership to grant the principal read access, reads msDS-ManagedPassword, outputs the NT hash in secretsdump format, and restores the original SD (or removes the attribute if it was absent before patching).

No new dependencies — uses impacket (ldaptypes, MODIFY_REPLACE, MODIFY_DELETE), ldap3 (security_descriptor_control), and Cryptodome.Hash.MD4, all already required by NetExec.

Technique references:

AI assistance: This module was developed with Claude Code (claude-sonnet-4-6). The module architecture, DACL parsing logic, security descriptor construction, and restore behaviour were designed and implemented collaboratively. The module was validated through live testing against a Windows Server 2019 domain controller. No independent manual code review was performed by the author.


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 Code / claude-sonnet-4-6 — see description)

Setup guide for the review

Attacker environment: Kali Linux, Python 3.11, NetExec run from source (pip install -e .)

Target: Windows Server 2019 (Build 17763), domain functional level 2016

AD setup required:

  1. Create a gMSA:
New-ADServiceAccount -Name svc_gmsa -DNSHostName dc01.domain.local -Enabled $true
  1. Grant a non-privileged test user GenericWrite on the gMSA object (via ADSI Edit or Set-Acl)

Test commands:

# Discovery — shows all non-admin trustees with write rights on any gMSA
netexec ldap <DC> -u <user> -p <pass> -M gmsa_abuse

# Filtered discovery
netexec ldap <DC> -u <user> -p <pass> -M gmsa_abuse -o ACTION=find PRINCIPAL=<user>

# Exploit — patches msDS-GroupMSAMembership, dumps hash, restores original SD
netexec ldap <DC> -u <user> -p <pass> -M gmsa_abuse -o ACTION=exploit TARGET=<gMSA_name> PRINCIPAL=<user>

Expected output (find):

[*] Found 2 gMSA account(s) — checking DACLs ...
[*] gMSA: svc_mgmt$               Trustee: helpdesk_operator          (S-1-5-21-<domain>-1234)  Rights: GenericWrite
[*]   -> Exploit: -M gmsa_abuse -o ACTION=exploit TARGET=svc_mgmt$ PRINCIPAL=<account>
[*] gMSA: svc_backup$             Trustee: backup_svc                 (S-1-5-21-<domain>-1337)  Rights: WriteProperties
[*]   -> Exploit: -M gmsa_abuse -o ACTION=exploit TARGET=svc_backup$ PRINCIPAL=<account>

Expected output (exploit):

[*] Principal '<user>' SID: S-1-5-21-<domain>-<rid>
[*] Target gMSA DN: CN=<gMSA_name>,CN=Managed Service Accounts,DC=<domain>
[*] Patching msDS-GroupMSAMembership to grant '<user>' read access ...
[+] msDS-GroupMSAMembership patched successfully
<gMSA_name>$:::aad3b435b51404eeaad3b435b51404ee:<nt_hash>:::
[+] NT hash: <nt_hash>
[+] msDS-GroupMSAMembership restored to original

Checklist

  • I have ran Ruff against my changes (ruff check nxc/modules/gmsa_abuse.pyAll checks passed!)
  • 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
  • I have performed a self-review of my own code (not an AI review)
  • 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)

This module allows for the discovery and exploitation of gMSA accounts by checking write rights on the msDS-GroupMSAMembership attribute. It provides functionality to enumerate gMSA objects and grant read access to their passwords.

Signed-off-by: Goos <23636293+goosvorbook@users.noreply.github.com>
Signed-off-by: Goos <23636293+goosvorbook@users.noreply.github.com>
@NeffIsBack
Copy link
Copy Markdown
Member

Hey and thanks for the PR! Definitely looks cool. Ima have to think about if we maybe could/should integrate it with the existing --gmsa flag or vice versa.

@NeffIsBack
Copy link
Copy Markdown
Member

You should read and review the code yourself at least once tho. Also, did you or the AI wrote the PR description? Could you include screenshots of a working example?

Signed-off-by: Goos <23636293+goosvorbook@users.noreply.github.com>
Signed-off-by: Goos <23636293+goosvorbook@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants