Passwords are only one of the keys that unlock a Kerberos account. Since Windows introduced certificate logon and Windows Hello for Business, an account can also authenticate with a public/private key pair. That alternative authenticator is the whole story of this page: if you can add a key you control to a target account, you can log in as that account without ever knowing its password — and then pull its NT hash back out of the ticket for good measure. This is the mechanism behind the "shadow credentials" edges you see in BloodHound and on the Attack-Path map.
The theme: own the key material, not the secret. A password reset is loud and disruptive; adding a key credential is quiet, reversible, and grants exactly the same logon capability.
PKINIT in one section
Normal Kerberos (recap on the Kerberos page) proves
your identity to the KDC with a key derived from your password. PKINIT
(Public Key Cryptography for Initial Authentication) replaces that step: in the
AS-REQ you present a certificate and sign the request with the matching
private key. The KDC validates the certificate (its issuer must be trusted for authentication
— the NTAuth store, for AD CS certs) and, satisfied, issues a
TGT. From that point you have a normal Kerberos
session. This is exactly how smart-card logon and
AD CS certificate abuse (ESC1 and friends) end up
producing a TGT.
Key Trust vs Cert Trust — why no CA is needed
There are two ways an account can be bound to a key:
| Model | How the key is trusted |
|---|---|
| Cert Trust | A certificate issued by a CA in the NTAuth store (this is AD CS / ESC territory) |
| Key Trust | A raw public key stored on the account object in the msDS-KeyCredentialLink attribute — no CA involved |
Key Trust is what Windows Hello for Business uses: the device generates a key pair and
publishes the public key to msDS-KeyCredentialLink; the KDC will then accept a
PKINIT logon signed by the matching private key. Crucially, populating that attribute needs
no certificate authority at all — just write access to the attribute. That is the
opening.
The Shadow Credentials attack
If you can write msDS-KeyCredentialLink on a target user or computer — because
you hold GenericWrite, GenericAll, WriteProperty on
that specific attribute, or the AddKeyCredentialLink right (all common
ACL findings) — you simply add your own key
credential to the account. You now hold a private key the KDC will accept for that identity,
so you PKINIT as them:
pywhisker -d <domain> -u <user> -p '<pass>' --target <victim> --action add
# pywhisker writes the KeyCredential and hands you a PFX + its password, then:
gettgtpkinit.py -cert-pfx victim.pfx -pfx-pass <pfx_pass> <domain>/<victim> victim.ccache
# or the one-shot with Certipy:
certipy shadow auto -u <user>@<domain> -p '<pass>' -account <victim>
certipy shadow auto is the fast path: it adds the key, authenticates, retrieves
the TGT, and (see below) prints the NT hash, then cleans up the attribute. Because the change
is a single attribute write and is trivially removed, it is far stealthier than resetting a
password — the victim never notices a login problem.
Requirements & constraints
| Requirement | Why |
|---|---|
| A KDC that supports PKINIT | The DC needs a domain-controller / KDC certificate; most modern domains have one (often via an installed AD CS) |
Write access to msDS-KeyCredentialLink on the target | The core requirement — usually from an ACL edge |
| 2016+ functional level in practice | Key Trust / composite identity support |
If there is no PKINIT-capable KDC, the raw key logon will not work — but the same
attribute-write can still be paired with AD CS certificate mapping abuses. Shadow Credentials
is also the natural payload when you relay to
LDAP: relay a machine account, write its msDS-KeyCredentialLink, and you own
the computer.
UnPAC-the-Hash — getting the NT hash back
Certificate logon gives you Kerberos, but a lot of the environment still speaks NTLM, and you
may want the account's NT hash for pass-the-hash.
PKINIT provides it. When the KDC issues a TGT to a PKINIT client, it can include a
PAC_CREDENTIAL_INFO structure containing the account's NTLM secret, precisely so
that Kerberos-authenticated users can still perform NTLM authentication to downstream
services. Ask for those credentials and the ticket hands you the NT hash:
Rubeus.exe asktgt /user:<victim> /certificate:<pfx> /password:<pfx_pass> /getcredentials /nowrap
# or with certipy, which prints the hash after authenticating:
certipy auth -pfx victim.pfx -dc-ip <dc_ip>
This is the "UnPAC-the-hash" trick: it converts certificate access into a reusable NT hash, unifying the certificate and hash worlds. It is why an AD CS ESC1, a shadow credential, or a relayed machine account all ultimately land you at the same place — a hash and a ticket for the victim.
Where it sits in the bigger picture
- ACL abuse gives you the attribute write → Shadow Credentials.
- AD CS ESC1/ESC3/etc. give you a cert → the same PKINIT logon, minus the attribute write.
- Relay to LDAP gives you the write over a coerced machine → Shadow Credentials on a computer, then RBCD or Silver-ticket its services.
- UnPAC-the-hash then converts any of the above into an NT hash for pass-the-hash and ticket attacks.
Detection & defence
| Control | Effect |
|---|---|
Audit writes to msDS-KeyCredentialLink (directory change event 5136) | A key-credential added to a user/computer by an unexpected principal is the primary signal |
Tighten who can write that attribute; review GenericWrite/GenericAll edges in BloodHound | Removes the precondition entirely |
| Enforce strong certificate mapping (KB5014754) and the SID security extension | Blunts weak-mapping abuses that pair with PKINIT |
| Monitor PKINIT AS-REQ (4768 with certificate info) from unusual hosts | Catches the logon step |
| Protect the KDC/AD CS trust and the NTAuth store | Controls which certificates the KDC will ever accept |
The takeaway
Shadow Credentials weaponises a legitimate feature — key-based logon — by adding a key you
control to an account you can write. It is quiet, reversible, and grants full logon as the
target; UnPAC-the-hash then extracts the NT hash from the resulting ticket so the access
works everywhere, NTLM included. Watch msDS-KeyCredentialLink like a hawk, prune
the ACL edges that let low-privileged principals write it, and remember that certificates,
key credentials and hashes are three doors into the same room. Tools (pywhisker, Certipy,
Rubeus, gettgtpkinit) are in the Toolkit.