What Are Shadow Credentials?
Shadow credentials is a post-exploitation technique — popularised by Elad Shamir in 2021 and operationalised in tools like Whisker (C#) and pywhisker (Python) — that abuses the msDS-KeyCredentialLink attribute on Active Directory user and computer objects.
The msDS-KeyCredentialLink attribute stores raw Device Registration public key credentials used by Windows Hello for Business and Azure AD device authentication (the PKINIT Kerberos extension). When a device registers a Windows Hello credential, a key credential entry is added to its own AD object. What’s important for defenders: any principal with GenericWrite, GenericAll, WriteProperty, or AllExtendedRights over an AD object can write a new key credential entry to that object’s msDS-KeyCredentialLink.
An attacker with those permissions can:
- Generate a new key pair locally
- Write the public key into the target object’s
msDS-KeyCredentialLink - Authenticate as the target using PKINIT + the private key — without knowing or changing the target’s password
- Retrieve the target’s NT hash via the PKINIT TGT response (AS-REP decryption or U2U exchange)
The result is a durable credential backdoor that survives password resets and is invisible to most password-focused monitoring.
Detection Strategy
Detection has three layers: attribute write monitoring, Kerberos protocol anomalies, and tooling artefacts.
Layer 1 — Directory Service Change Auditing (Event 5136)
The most reliable detection is monitoring Windows Security Event ID 5136 (Directory Service Object Modified) for writes to msDS-KeyCredentialLink:
title: Shadow Credentials — msDS-KeyCredentialLink Attribute Write
id: a9b5f842-3d28-4f9c-8b2e-6d1e0f43c9a7
status: experimental
description: >
Detects writes to the msDS-KeyCredentialLink attribute on AD objects,
which may indicate a Shadow Credentials attack (Whisker / pywhisker).
author: SOC Analyst Hub
date: 2026-06-10
logsource:
product: windows
service: security
detection:
selection:
EventID: 5136
AttributeLDAPDisplayName: 'msDS-KeyCredentialLink'
OperationType: '%%14674' # Value Added
filter_legitimate:
SubjectUserName|endswith:
- '$' # Computer account writes (WHFB device reg)
ObjectClass: 'computer'
SubjectUserName: '%ObjectDN_CN%' # Object writing to itself (self-registration)
condition: selection and not filter_legitimate
falsepositives:
- Windows Hello for Business device registration by users
- Azure AD join device registration events
- Hybrid join synchronisation from Azure AD Connect
fields:
- SubjectUserName
- ObjectDN
- AttributeLDAPDisplayName
- AttributeValue
level: high
tags:
- attack.credential_access
- attack.persistence
- attack.t1556
Important tuning notes:
- Legitimate writes occur when a device registers Windows Hello for Business credentials: the
SubjectUserNamewill be the computer account (HOSTNAME$) writing to its own object. Filter these out by checking that the writing account matches the modified object. - Azure AD Connect in hybrid environments may sync key credential data. Add the AADC service account to your filter.
- Any write by a human user account to a user or computer object that is not the object itself should be treated as high-confidence malicious.
Layer 2 — Kerberos PKINIT Authentication Anomalies (Event 4768)
When an attacker uses the shadow credential to authenticate, the Kerberos AS-REQ will use certificate-based pre-authentication (PKINIT), generating Event ID 4768 with:
title: PKINIT Authentication from Non-Enrolled Machine
id: b8c2e947-1f5a-4d8e-9c3f-7a2b1e56d8f0
status: experimental
description: >
Detects Kerberos certificate-based (PKINIT) authentication from accounts
or machines that are not enrolled in Windows Hello for Business or other
certificate-based auth programmes.
logsource:
product: windows
service: security
detection:
selection:
EventID: 4768
CertIssuerName|contains: 'key trust'
PreAuthType: '17' # PKINIT
filter_expected_whfb:
# Exclude known enrolled WHFB or smart card users from your org
AccountName|contains: '<your-whfb-enrolled-users>'
condition: selection and not filter_expected_whfb
falsepositives:
- Smart card users
- Windows Hello for Business enrolled users
- Certificate-based Kerberos deployments
level: high
tags:
- attack.credential_access
- attack.t1556
KQL equivalent for Microsoft Sentinel:
SecurityEvent
| where EventID == 4768
| where tostring(EventData) contains "preauth_type>17" // PKINIT
| where AccountName !in (whfb_enrolled_users) // filter known enrollments
| project TimeGenerated, AccountName, IpAddress, Computer
| order by TimeGenerated desc
Layer 3 — Tooling Artefacts
Whisker (C#) and pywhisker (Python) both interact with LDAP to modify the attribute. They leave process and network artefacts:
title: Whisker Shadow Credentials Tool Execution
id: c7d3f158-2e4b-5a9f-0d7c-8f3a2b1e90c4
status: experimental
description: Detects command-line patterns consistent with Whisker or pywhisker execution
logsource:
product: windows
category: process_creation
detection:
whisker_cli:
CommandLine|contains:
- 'Whisker.exe add'
- 'Whisker.exe list'
- 'Whisker.exe remove'
pywhisker_flags:
CommandLine|contains:
- '--target-dn'
- '--attribute msDS-KeyCredentialLink'
condition: whisker_cli or pywhisker_flags
level: critical
tags:
- attack.credential_access
- attack.t1556
Hunting Queries
Hunt 1 — Find Accounts with Unexpectedly Populated msDS-KeyCredentialLink
Run this PowerShell to audit which objects in AD have msDS-KeyCredentialLink populated and compare against your expected WHFB enrolment list:
Import-Module ActiveDirectory
$populated = Get-ADObject -Filter {msDS-KeyCredentialLink -like '*'} `
-Properties msDS-KeyCredentialLink, DistinguishedName, ObjectClass, WhenChanged |
Select-Object Name, ObjectClass, WhenChanged, DistinguishedName,
@{N='KeyCount';E={$_.'msDS-KeyCredentialLink'.Count}}
# Flag computer objects with entries older than WHFB enrollment date
# Flag user objects with any entries if WHFB is not deployed
$populated | Where-Object { $_.ObjectClass -eq 'user' } |
Sort-Object WhenChanged -Descending |
Format-Table -AutoSize
Hunt 2 — Detect Recent msDS-KeyCredentialLink Writes via LDAP Logs
If you have LDAP query/modify audit logging (Windows LDAP logging or a product like Semperis or Tenable AD):
// Sentinel: query DirectoryServiceAudit or custom LDAP log table
union AuditLogs, DirectoryAuditLogs
| where OperationName =~ "Update user" or OperationName =~ "Update device"
| where TargetResources has "msDS-KeyCredentialLink"
| extend ModifiedBy = InitiatedBy.user.userPrincipalName
| extend TargetObject = TargetResources[0].displayName
| project TimeGenerated, ModifiedBy, TargetObject, OperationName
| order by TimeGenerated desc
Responding to a Shadow Credentials Alert
- Identify the writing account: The 5136 event logs the SubjectUserName. This is the compromised account used to write the shadow credential.
- Identify the target object: The ObjectDN in the 5136 event tells you whose credential was backdoored.
- Remove the shadow credential: Use Whisker
remove --target <target> --deviceid <id>from a privileged account, or clear the attribute directly in AD Users and Computers / ADSI Edit. - Confirm removal: Query
msDS-KeyCredentialLinkon the affected object and verify it is empty or contains only expected WHFB entries. - Investigate the writing account: The account that wrote the shadow credential is compromised. Initiate full investigation, reset credentials, review session history and lateral movement.
- Check for additional shadow credentials: Run the PowerShell hunt above across all objects — attackers often add shadow credentials to multiple high-value targets.
Defensive Controls
- Restrict msDS-KeyCredentialLink write permissions via Active Directory ACL review. Most accounts should not have GenericWrite over other user or computer objects. Audit your AD ACL inheritance structure — overly permissive delegations are the precondition for this attack.
- Tier your AD admin model: Accounts with broad AD write permissions should be restricted to dedicated admin workstations, not used for daily activities that involve internet browsing or email.
- Enable DS-Access auditing: Success and failure auditing for “Directory Service Changes” (category 4) is required to generate 5136 events. Verify this is enabled on all domain controllers.
- Deploy Tenable AD or Semperis DSP: Dedicated Active Directory threat detection products with real-time change monitoring will catch msDS-KeyCredentialLink modifications with lower tuning overhead than raw event log rules.