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:

  1. Generate a new key pair locally
  2. Write the public key into the target object’s msDS-KeyCredentialLink
  3. Authenticate as the target using PKINIT + the private key — without knowing or changing the target’s password
  4. 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 SubjectUserName will 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

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

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

  1. Identify the writing account: The 5136 event logs the SubjectUserName. This is the compromised account used to write the shadow credential.
  2. Identify the target object: The ObjectDN in the 5136 event tells you whose credential was backdoored.
  3. 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.
  4. Confirm removal: Query msDS-KeyCredentialLink on the affected object and verify it is empty or contains only expected WHFB entries.
  5. Investigate the writing account: The account that wrote the shadow credential is compromised. Initiate full investigation, reset credentials, review session history and lateral movement.
  6. 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.