Skip to content

AD-INF-007: BadSuccessor: dMSA creation rights outside tier 0

high   Infrastructure   MITRE ATT&CK T1098, T1136.002   Reads: LDAP

On a Windows Server 2025 domain, principals outside tier 0 can create a delegated managed service account (dMSA) and use it to inherit any account's rights (BadSuccessor).

Also known as: badsuccessor

Why it matters

Windows Server 2025 added delegated managed service accounts (dMSA) to replace legacy service accounts. During a migration, the KDC gives a dMSA the privileges of the account it supersedes: it reads msDS-ManagedAccountPrecededByLink on the dMSA and puts the superseded account's SIDs into the dMSA's ticket.

The KDC trusted that link without checking that the old account agreed to the migration. Anyone who can create a dMSA in some OU or container, which only takes CreateChild for that class (or ownership or full control of the OU), can create one, point msDS-ManagedAccountPrecededByLink at a domain admin or krbtgt, and request a ticket as that dMSA. The result carries the victim's privileges, and the ticket response also holds the victim's keys. This works as soon as one Windows Server 2025 DC exists in the domain.

The August 2025 updates (CVE-2025-53779) narrowed this rather than ending it. The write to the link still succeeds, but the KDC now refuses a one-sided link and wants a mutual pairing that looks like a real migration. Akamai's analysis of the patch shows what is left: someone who controls a dMSA and also the target account object still gets the target's privileges and keys, which is less than BadSuccessor gave, but with different telemetry from DCSync or shadow credentials. So the delegated creation rights stay a tier-0 path on unpatched DCs, and on patched DCs they still give control over the OU and a route for abuse after a compromise.

Golden dMSA is a separate route that does not use the link at all. With the forest's KDS root key, which takes SYSTEM on a DC or Enterprise Admin rights to dump, Semperis shows that an attacker can work out dMSA passwords from a small set of candidates and needs no further privileged access. ad-doctor does not check for it.

How ad-doctor detects it

The check runs only when the domain looks like it has Windows Server 2025: a domain functional level of 10, or a domain controller whose operatingSystem contains 2025. It then reports, from the security descriptors in the LDAP snapshot:

  • every OU, container or the domain object owned by a principal outside tier 0 (an owner can always rewrite the DACL to grant itself CreateChild), as <object>: <principal> (owner);
  • every ACE for a principal outside tier 0 (CREATOR OWNER excluded) that allows creating msDS-DelegatedManagedServiceAccount objects (CreateChild on that class or on all classes, or GenericAll), or that is a takeover right (WriteDacl, WriteOwner, GenericWrite, write to all properties), as <object>: <principal>;
  • every existing dMSA whose msDS-ManagedAccountPrecededByLink already points at a privileged account or krbtgt, as <dMSA>: dMSA superseding <victim>. An ordinary user normally cannot do this one: dMSAs grant Authenticated Users no read access by default, so they do not come back at all (checked in the lab with adreader). On a 2025 domain, when no dMSA is visible the report has a note saying so, and the finding text repeats it. Run the scan with an account that can read them to cover this part.

Tier 0 here is SYSTEM, Enterprise Domain Controllers, Administrators, the built-in Administrator, Domain, Enterprise and Schema Admins, the domain controller and RODC groups, plus Account, Server, Print and Backup Operators. Only allow ACEs are read. In the lab, the finding object is Lab: ou_admin.

Attributes and probes read
  • nTSecurityDescriptor
  • msDS-ManagedAccountPrecededByLink
  • msDS-Behavior-Version
  • operatingSystem

Severity

Always high: creating one dMSA and pointing it at a domain admin or krbtgt is a direct domain compromise.

False positives and limits

  • No Windows Server 2025 DC yet. The check stays silent; it does not report rights that would become dangerous after a 2025 DC is added. Re-run it before promoting one.
  • Patched DCs. The August 2025 updates stop the one-sided link, not every abuse of a migration pairing, and ad-doctor does not check the patch level. The rights reported here still give control over the OU and its objects; review them rather than accepting them wholesale.

Fix

  1. Install the August 2025 (or later) cumulative updates on every Windows Server 2025 domain controller (CVE-2025-53779).
  2. List who can create objects in the reported OUs.

    (Get-Acl 'AD:OU=Lab,DC=corp,DC=example').Access |
        Where-Object { $_.ActiveDirectoryRights -match 'CreateChild|GenericAll|WriteDacl|WriteOwner' } |
        Select-Object IdentityReference, ActiveDirectoryRights, ObjectType, InheritanceType
    
  3. Remove the rights, or narrow CreateChild to the object classes the delegated team really needs (users, groups, computers). With dsacls, show the ACL first, then remove the principal's ACEs:

    dsacls "OU=Lab,DC=corp,DC=example"
    dsacls "OU=Lab,DC=corp,DC=example" /R "CORP\ou_admin"
    
  4. Give non-tier-0 owners' objects back to Domain Admins:

    $p = 'AD:OU=Lab,DC=corp,DC=example'; $acl = Get-Acl $p
    $acl.SetOwner([System.Security.Principal.NTAccount]'CORP\Domain Admins')
    Set-Acl $p $acl -WhatIf
    
  5. Inspect existing dMSAs that supersede privileged accounts and delete those nobody created on purpose:

    Get-ADServiceAccount -Filter * -Properties msDS-ManagedAccountPrecededByLink |
        Where-Object 'msDS-ManagedAccountPrecededByLink' |
        Select-Object Name, 'msDS-ManagedAccountPrecededByLink'
    

Verify

ad-doctor scan dc01.corp.example --ldaps -u 'CORP\auditor' --only AD-INF-007

To accept the risk instead, add an entry to the file passed with --accept (see accepted risks):

[[accept]]
check = "AD-INF-007"
objects = ["..."]        # optional; without it the whole check is accepted
reason = "..."
expires = 2027-03-31

References

Microsoft and vendors

Research

MITRE ATT&CK

Available since 0.1.0.