Hardening Active Directory: Shadow Credentials Defense Guide
Overview & Defensive Context#
In this morning's offensive breakdown, we deconstructed the mechanics of Active Directory Shadow Credentials (abusing msDS-KeyCredentialLinkper[MS-ADTS] 2.2.20 and Kerberos PKINIT per RFC 4556). We exposed how unprivileged principals possessing delegated write authority (GenericAll, GenericWrite, WriteOwner, WriteDacl, or explicit WriteProperty) can append synthetic public key credentials (KEYCREDENTIALLINK_BLOB) to user or computer objects via LDAP. This enables an attacker to request a Kerberos Ticket Granting Ticket (TGT) directly from the Key Distribution Center (KDC) via PKINIT, extract the target's static NTLM hash via UnPAC-the-hash, and achieve complete domain dominance—all while leaving the target's existing password completely untouched.
Standard enterprise perimeter defenses and endpoint detection and response (EDR) agents deployed on member workstations remain entirely oblivious to this attack path. Because all malicious interactions occur over internal domain protocols—LDAP/LDAPS (TCP 389/636) and Kerberos (TCP/UDP 88)—directly against Domain Controllers, host-based sensors see zero process execution or memory tampering on the victim's endpoint. Furthermore, traditional Active Directory monitoring relies heavily on Event ID 4724 (Password Reset Attempt) and Event ID 4738 (User Account Modified), neither of which fires during Shadow Credential injection.
[!IMPORTANT] By default, Active Directory does not log writes to the
msDS-KeyCredentialLinkattribute. Defending enterprise identity against Shadow Credentials requires implementing explicit System Access Control Lists (SACLs) for Directory Service Object Access, auditing Kerberos pre-authentication telemetry (Event ID 4768), enforcing strict DACL tiering, and deploying automated remediation pipelines.
Architecture Hardening: Multi-Tiered Active Directory Defense#
Securing Active Directory against Shadow Credentials requires establishing layered inspection and verification gates across directory permissions, cryptographic authentication, and telemetry ingestion.
flowchart TD
subgraph IdentityDACLBoundary ["Active Directory Object DACL Boundary"]
IdentityObject["Target Principal (User / Tier-0 Computer)"]
DACLFilter{"DACL Least-Privilege Gate (No GenericWrite / WriteDacl)"}
DropUnauthorized["Deny: Unauthorized Caller Cannot Write msDS-KeyCredentialLink"]
end
subgraph DirectoryAuditingLayer ["Directory Service Auditing & Telemetry Engine"]
SACLCheck{"Attribute SACL Active (Schema GUID: 5b47d60f...)"}
Event5136["Generate Security Event ID 5136 (Value Added)"]
SIEMPipeline["SIEM Real-Time Correlation Pipeline (Sigma Rule)"]
end
subgraph KDCPKINITLayer ["Kerberos KDC Authentication Gate (RFC 4556)"]
ASREQAuth{"Kerberos AS-REQ with PA-PK-AS-REQ (Pre-Auth 16/17)"}
EnrollmentVerify{"Device Enrollment Match (Entra ID / Intune WHfB)"}
Event4768["Log Event ID 4768: Audit Certificate / KeyID"]
TGTGrant["Issue Kerberos TGT with PAC"]
AlertAnomalous["Alert / Block: Unregistered Key / Non-WHfB PKINIT"]
end
IdentityObject --> DACLFilter
DACLFilter -->|Unauthorized Write Attempt| DropUnauthorized
DACLFilter -->|Legitimate Admin / WHfB Registration| SACLCheck
SACLCheck --> Event5136
Event5136 --> SIEMPipeline
IdentityObject -.->|Target Authenticates| ASREQAuth
ASREQAuth --> Event4768
ASREQAuth --> EnrollmentVerify
EnrollmentVerify -->|Valid Hardware Device Match| TGTGrant
EnrollmentVerify -->|Rogue Shadow Credential Key| AlertAnomalous
AlertAnomalous --> SIEMPipelineHardened Configurations & Policy Implementations#
To eliminate Shadow Credential vulnerabilities, blue teams must configure explicit auditing SACLs, restrict administrative delegation, and clean existing directory objects.
1. Enforcing System Access Control Lists (SACL) on msDS-KeyCredentialLink#
Because Active Directory does not audit attribute-level modifications by default, blue teams must deploy a SACL targeting the msDS-KeyCredentialLink attribute across the domain root or sensitive Organizational Units (OUs).
The following PowerShell script configures a SACL rule that audits write operations on msDS-KeyCredentialLink (Schema GUID: 5b47d60f-6090-40b2-9f37-2a4de45f4263) for Everyone:
## PowerShell: Deploying SACL on msDS-KeyCredentialLink for Domain Audit
Import-Module ActiveDirectory
$DomainDN = (Get-ADDomain).DistinguishedName
$DomainAcl = Get-Acl "AD:$DomainDN"
## Schema GUID for msDS-KeyCredentialLink attribute
$AttrGuid = [GUID]"5b47d60f-6090-40b2-9f37-2a4de45f4263"
## Define SACL: Audit 'WriteProperty' (Success) for 'Everyone'
$Identity = New-Object System.Security.Principal.SecurityIdentifier("S-1-1-0") # Everyone
$AuditRule = New-Object System.DirectoryServices.ActiveDirectoryAuditRule(
$Identity,
[System.DirectoryServices.ActiveDirectoryRights]::WriteProperty,
[System.Security.AccessControl.AuditFlags]::Success,
$AttrGuid,
[System.DirectoryServices.ActiveDirectorySecurityInheritance]::Descendents
)
## Commit SACL rule to Active Directory root
$DomainAcl.AddAuditRule($AuditRule)
Set-Acl -Path "AD:$DomainDN" -AclObject $DomainAcl
Write-Host "[+] SACL successfully committed to $DomainDN for msDS-KeyCredentialLink" -ForegroundColor Green
To activate this telemetry on Domain Controllers, the Advanced Audit Policy must be configured via Group Policy (GPO):
- Computer Configuration -> Policies -> Windows Settings -> Security Settings -> Advanced Audit Policy Configuration -> Audit Policies -> DS Access -> Audit Directory Service Changes: Enable Success.
2. Tier-0 DACL Sanitization & Least-Privilege Delegation#
Adversaries rely on latent administrative permissions to inject shadow credentials. Organizations must eliminate inbound write permissions held by non-Tier-0 identities over privileged accounts.
Run the following audit script to locate high-risk delegated permissions on sensitive user and computer objects:
## Audit all principals holding write rights over sensitive Active Directory objects
$Tier0OUs = @(
"OU=Domain Controllers,$DomainDN",
"OU=Tier0-Admins,$DomainDN",
"OU=Tier0-Servers,$DomainDN"
)
foreach ($OU in $Tier0OUs) {
$Objects = Get-ADObject -Filter * -SearchBase $OU
foreach ($Obj in $Objects) {
$Acl = Get-Acl "AD:$($Obj.DistinguishedName)"
$DangerousACEs = $Acl.Access | Where-Object {
$_.ActiveDirectoryRights -match "GenericAll|GenericWrite|WriteDacl|WriteOwner" -or
($_.ObjectType -eq $AttrGuid -and $_.AccessControlType -eq "Allow")
} | Where-Object {
$_.IdentityReference -notmatch "Domain Admins|Enterprise Admins|SYSTEM"
}
if ($DangerousACEs) {
Write-Warning "[!] Suspicious DACL discovered on: $($Obj.DistinguishedName)"
$DangerousACEs | Format-Table IdentityReference, ActiveDirectoryRights -AutoSize
}
}
}
Production Detection Queries & Telemetry#
Detecting Shadow Credentials requires dual-vector telemetry analysis: capturing LDAP modification events via Event ID 5136 and monitoring anomalous Kerberos PKINIT authentications via Event ID 4768.
1. Validated Sigma Rule: Shadow Credential Injected into AD Object#
This Sigma rule detects the addition of a msDS-KeyCredentialLink attribute to an Active Directory object, indicating potential Shadow Credential deployment:
title: Active Directory Shadow Credentials Injected
id: 4e2c8a19-5d3b-4f81-98ab-3f19e7b2d904
status: test
description: Detects the modification of an Active Directory object where a value is added to the msDS-KeyCredentialLink attribute.
references:
- https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/0168d667-e4e6-4d64-a5e2-63206775791a
- https://attack.mitre.org/techniques/T1098/
logsource:
product: windows
service: security
detection:
selection:
EventID: 5136
AttributeLDAPDisplayName: 'msDS-KeyCredentialLink'
OperationType: '%%14674' # Value Added
filter_legitimate_provisioning:
# Exclude legitimate automated device enrollment accounts (e.g., Azure AD Connect / Intune Sync)
SubjectUserName|endswith: '$'
SubjectDomainName: 'CORP'
condition: selection and not filter_legitimate_provisioning
falsepositives:
- Legitimate Windows Hello for Business (WHfB) user or device enrollment via Microsoft Entra Connect.
level: high
tags:
- attack.persistence
- attack.privilege_escalation
- attack.t1098
2. Correlating Kerberos PKINIT Telemetry (Event ID 4768)#
When an attacker leverages a planted shadow credential, the KDC generates Windows Security Event ID 4768 (A Kerberos authentication ticket (TGT) was requested). Blue teams must monitor for non-standard PKINIT authentications:
## KQL Detection Query (Microsoft Sentinel / Defender for Identity)
SecurityEvent
| where EventID == 4768
| extend PreAuthType = tostring(parse_json(EventData).PreAuthType)
| extend CertIssuerName = tostring(parse_json(EventData).CertIssuerName)
| extend TargetUserName = tostring(parse_json(EventData).TargetUserName)
| extend IPAddress = tostring(parse_json(EventData).IpAddress)
// Pre-Auth Type 16 = PKINIT (PA-PK-AS-REQ), 17 = PKINIT (PA-PK-AS-REP)
| where PreAuthType in ("16", "17")
// Alert when PKINIT is used by Tier-0 accounts that do not have smartcards provisioned
| where TargetUserName in ("Administrator", "krbtgt", "da-svc-backup") or TargetUserName endswith "_admin"
| project TimeGenerated, TargetUserName, IPAddress, PreAuthType, CertIssuerName
[!WARNING] If an organization has not deployed Windows Hello for Business or smartcard authentication, any occurrence of Event ID 4768 with
PreAuthType: 16or17represents high-confidence anomalous activity indicating either Shadow Credentials or AD CS certificate abuse.
Enterprise Mitigation Matrix#
The following matrix contrasts operational workarounds, immediate hotfixes, and sustainable architectural controls:
| Mitigation Layer | Technical Control | Operational Blast Radius | Performance Overhead | Security Guarantee |
|---|---|---|---|---|
| Workaround | Deploy attribute-level SACL on msDS-KeyCredentialLink and alert via SIEM |
Zero (passive auditing configuration) | Negligible (< 0.1% DC CPU) | Provides immediate detection visibility into all credential injections |
| Hotfix | Audit and purge unauthorized msDS-KeyCredentialLink values on Tier-0 accounts |
Low (requires validating active WHfB user enrollments before purging) | Zero | Instantly severs active persistence and blocks PKINIT TGT generation |
| Hotfix | Remove GenericAll, GenericWrite, and WriteDacl permissions on sensitive OUs |
Moderate (requires auditing service account dependencies before revocation) | Zero | Prevents non-administrative principals from tampering with directory attributes |
| Architectural Fix | Implement Active Directory Administrative Tiering (Enterprise Access Model) | High initial setup (shifts identity management into strict isolated tiers) | Zero runtime impact | Eliminates lateral and escalation paths from Tier-1/Tier-2 into Tier-0 assets |
| Architectural Fix | Enforce Cloud Kerberos Trust with hardware-backed TPM attestation | Moderate (requires Intune enrollment and modern Windows 11/10 clients) | Zero | Ensures directory keys are accepted only from attested TPM hardware chips |
Incident Response & Verification Playbook#
When an alert triggers for unauthorized msDS-KeyCredentialLink modification or anomalous PKINIT ticket issuance, execute the following containment and recovery steps:
Phase 1: Rapid Triage & Credential Inspection#
- Extract Injected KeyCredential Metadata:
Query the affected account's
msDS-KeyCredentialLinkattribute to inspect the binaryKEYCREDENTIALLINK_BLOBentries:
# Inspect raw KeyCredentialLink attribute values
$VictimDN = "CN=da-svc-backup,OU=AdminAccounts,DC=corp,DC=internal"
$RawCreds = (Get-ADUser -Identity $VictimDN -Properties "msDS-KeyCredentialLink")."msDS-KeyCredentialLink"
foreach ($Cred in $RawCreds) {
Write-Host "[*] Discovered KeyCredential: $Cred" -ForegroundColor Yellow
}
- Query Event ID 5136 to Identify Originating Principal: Inspect the Domain Controller audit log to identify who committed the modification:
Get-WinEvent -FilterHashtable @{
LogName = 'Security'
Id = 5136
StartTime = (Get-Date).AddHours(-4)
} | Where-Object {
$_.Message -match "msDS-KeyCredentialLink"
} | Select-Object TimeCreated, Message | Format-List
Phase 2: Containment & Credential Eviction#
- Purge the Malicious Key Credential Immediately:
Clear the
msDS-KeyCredentialLinkattribute to prevent the attacker from obtaining future Kerberos TGTs:
# Purge all shadow credentials from the compromised account
Set-ADUser -Identity $VictimDN -Clear "msDS-KeyCredentialLink"
Write-Host "[+] Cleared msDS-KeyCredentialLink on $VictimDN" -ForegroundColor Green
- Invalidate Active Kerberos Tickets and Reset Passwords Twice: Because the attacker may have extracted the NTLM hash via UnPAC-the-hash, execute an emergency password reset:
# Reset password twice to ensure history and Kerberos ticket invalidation
Set-ADAccountPassword -Identity $VictimDN -Reset -NewPassword (ConvertTo-SecureString "TempSecurePass987!" -AsPlainText -Force)
Start-Sleep -Seconds 5
Set-ADAccountPassword -Identity $VictimDN -Reset -NewPassword (ConvertTo-SecureString "FinalComplexPass321!" -AsPlainText -Force)
- Purge Domain Controller Kerberos Ticket Cache: If the compromised account was a Domain Controller or Domain Admin, invalidate active ticket sessions across all DCs:
# Purge Kerberos tickets on the DC
klist -li 0x3e7 purge
[!CAUTION] If a Domain Admin or Tier-0 service account was compromised, assume the adversary may have extracted the domain
krbtgtpassword. Plan and execute a two-stagekrbtgtpassword reset (with a 10-hour gap) to invalidate all existing Golden Tickets and forged TGTs across the forest.
Phase 3: Post-Remediation Verification Checklist#
- Verify Attribute Cleanliness: Confirm that the victim account's attribute is completely null:
(Get-ADUser -Identity $VictimDN -Properties "msDS-KeyCredentialLink")."msDS-KeyCredentialLink" -eq $null
Expected Output: True.
- Audit Surrounding Accounts in the Same OU: Ensure the adversary did not establish persistence across neighboring accounts:
Get-ADUser -Filter 'msDS-KeyCredentialLink -like "*"' -SearchBase "OU=AdminAccounts,DC=corp,DC=internal" | Select-Object SamAccountName, DistinguishedName
Comments
Post a Comment