Potential Shadow Credentials added to AD Object
Identify the modification of the msDS-KeyCredentialLink attribute in an Active Directory Computer or User Object. Attackers can abuse control over the object and create a key pair, append to raw public key in the attribute, and obtain persistent and stealthy access to the target user or computer object.
Elastic rule (View on GitHub)
1[metadata]
2creation_date = "2022/01/26"
3integration = ["system", "windows"]
4maturity = "production"
5updated_date = "2026/09/18"
6
7[rule]
8author = ["Elastic"]
9description = """
10Identify the modification of the msDS-KeyCredentialLink attribute in an Active Directory Computer or User Object.
11Attackers can abuse control over the object and create a key pair, append to raw public key in the attribute, and obtain
12persistent and stealthy access to the target user or computer object.
13"""
14false_positives = [
15 """
16 Azure AD Connect or ADFS provisioning can legitimately modify msDS-KeyCredentialLink when the writer account,
17 source, object class, target DN, bounded change set, and post-change authentication all match an expected workflow.
18 """,
19]
20from = "now-9m"
21index = ["winlogbeat-*", "logs-system.security*", "logs-windows.forwarded*"]
22language = "kuery"
23license = "Elastic License v2"
24name = "Potential Shadow Credentials added to AD Object"
25references = [
26 "https://posts.specterops.io/shadow-credentials-abusing-key-trust-account-mapping-for-takeover-8ee1a53566ab",
27 "https://www.thehacker.recipes/ad/movement/kerberos/shadow-credentials",
28 "https://github.com/OTRF/Set-AuditRule",
29 "https://cyberstoph.org/posts/2022/03/detecting-shadow-credentials/",
30]
31risk_score = 73
32rule_id = "79f97b31-480e-4e63-a7f4-ede42bf2c6de"
33severity = "high"
34tags = [
35 "Domain: Endpoint",
36 "OS: Windows",
37 "Use Case: Threat Detection",
38 "Tactic: Credential Access",
39 "Data Source: Active Directory",
40 "Resources: Investigation Guide",
41 "Use Case: Active Directory Monitoring",
42 "Data Source: Windows Security Event Logs",
43 "Noise: Low",
44 "Performance: Normal",
45 "Rule Type: Custom Query (KQL)",
46 "Platform: Windows",
47]
48timestamp_override = "event.ingested"
49type = "query"
50
51query = '''
52event.code:"5136" and host.os.type:"windows" and winlog.event_data.AttributeLDAPDisplayName:"msDS-KeyCredentialLink" and
53 winlog.event_data.AttributeValue :B\:828* and
54 not winlog.event_data.SubjectUserName: MSOL_* and
55 not winlog.event_data.ObjectClass: "msDS-Device"
56'''
57
58note = """## Triage and analysis
59
60### Investigating Potential Shadow Credentials added to AD Object
61
62#### Possible investigation steps
63
64- What object received the key-trust change?
65 - Focus: `winlog.event_data.ObjectDN`, `winlog.event_data.ObjectGUID`, `winlog.event_data.ObjectClass`, `winlog.event_data.OperationType`, and `winlog.event_data.AttributeValue`.
66 - Implication: escalate when a sensitive user or computer receives an added or replaced key-trust value outside recognized enrollment; lower suspicion only when the object class, DN, and operation fit the same identity-registration workflow.
67
68- Which account and logon session wrote the value?
69 - Focus: `winlog.event_data.SubjectUserSid`, `winlog.event_data.SubjectUserName`, `winlog.event_data.SubjectLogonId`, recovered `source.ip`, and `winlog.logon.type`. $investigate_0
70 - Hint: match alert `winlog.event_data.SubjectLogonId` to same `host.id` authentication events with `winlog.event_data.TargetLogonId`; if no 4624 matches, keep the session unresolved.
71 - Implication: escalate for an unexpected user, admin, service, or machine writer, or source/logon type outside the object's enrollment path; lower suspicion when writer and session match recognized provisioning or device registration.
72
73- Does the writer/object pair fit a recognized ADFS or Azure AD Connect-style path?
74 - Why: the abuse path writes authentication material, so service-looking writers still need source and change-set validation.
75 - Focus: compare `winlog.event_data.SubjectUserSid`, `winlog.event_data.SubjectUserName`, `winlog.event_data.ObjectClass`, `winlog.event_data.ObjectDN`, and `source.ip` to the expected service account, object type, and enrollment source.
76 - Implication: lower suspicion when recognized provisioning updates the expected object from the expected source; escalate when the writer is ad hoc, interactive, non-provisioning, object-class mismatched, or unexplained by source.
77
78- Was the logical change limited to this key credential?
79 - Focus: use same-operation 5136 events grouped by `winlog.event_data.OpCorrelationID`; compare `winlog.event_data.ObjectGUID`, `winlog.event_data.AttributeLDAPDisplayName`, `winlog.event_data.OperationType`, and `winlog.event_data.AttributeValue`. $investigate_1
80 - Implication: escalate when the operation touches unrelated objects, adds other authentication or delegation material, or removes cleanup evidence; lower suspicion when bounded to the expected object and enrollment attributes.
81
82- Did the modified identity authenticate after the change?
83 - Why: post-change authentication shows whether the new key material may already be in use.
84 - Focus: derive the principal from `winlog.event_data.ObjectDN`; review authentication events for `winlog.event_data.TargetUserName`, `winlog.event_data.TargetDomainName`, `source.ip`, `winlog.logon.type`, and `winlog.event_data.AuthenticationPackageName`.
85 - Hint: search after `@timestamp` for Target-side fields matching the derived principal; if `source.ip` is empty, lower origin confidence instead of treating absence as benign.
86 - Implication: escalate when the identity authenticates from a new source, unexpected logon type, or authentication path after the change; absence of follow-on use reduces urgency only when earlier evidence proves recognized provisioning.
87
88- Do related alerts change the scope beyond this object?
89 - Focus: recent alerts for the modifying account using `user.id` or `winlog.event_data.SubjectUserSid`. $investigate_2
90 - Hint: compare with alerts scoped to the modified object's `winlog.event_data.ObjectGUID`. $investigate_3
91 - Implication: broaden response when either scope shows privilege abuse, directory tampering, relay activity, or lateral movement; keep local when related alerts are quiet and local evidence resolves to one recognized workflow.
92
93- Escalate on the key-trust change plus any suspicious or unresolved object, writer session, `winlog.event_data.OpCorrelationID` scope, post-change authentication, or related-alert finding; close only when all evidence binds to one recognized provisioning workflow; preserve and escalate when evidence is mixed, incomplete, or uncorroborated.
94
95### False positive analysis
96
97- AutoPilot or WHfB device enrollment can cause a computer to write its own key credential. Confirm `winlog.event_data.SubjectUserName` matches the CN in `winlog.event_data.ObjectDN`, `winlog.event_data.ObjectClass` is "computer", `winlog.event_data.OpCorrelationID` is bounded, and no unexpected follow-on authentication occurs.
98- ADFS or Azure AD Connect provisioning can update key credentials on user or computer objects. Confirm `winlog.event_data.SubjectUserSid`, `winlog.event_data.ObjectDN`, recovered `source.ip`, bounded `winlog.event_data.OpCorrelationID`, and post-change authentication align with one named workflow. Keep open when ownership is unresolved.
99- Build exceptions from stable writer SID, object class or GUID, `host.id`, recovered source, and enrollment path across prior alerts. Avoid exceptions on "msDS-KeyCredentialLink", `user.name`, or host alone.
100
101### Response and remediation
102
103- Preserve a case export of the triggering 5136, recovered writer-session authentication events, `winlog.event_data.AttributeValue`, `winlog.event_data.ObjectGUID`, and `winlog.event_data.OpCorrelationID` before containment, reversal, or cleanup.
104- If confirmed benign, reverse temporary containment and document the exact workflow evidence: writer SID, object GUID/class, domain naming context, recovered source, bounded change set, and post-change authentication pattern. Keep any exception narrow and only for the recurring workflow.
105- If suspicious but unconfirmed, apply reversible controls to the writer first, such as heightened monitoring or temporary access review; restrict the modified identity only when object sensitivity or follow-on authentication shows active risk.
106- If confirmed malicious, contain the writer account or source system using `winlog.event_data.SubjectLogonId`, `source.ip`, `host.id`, and follow-on authentication evidence. Disable the writer first when its session performed unauthorized changes; disable or rotate the modified identity only when post-change authentication or object sensitivity shows active risk.
107- After containment, remove only the unauthorized key-trust value and verify rollback. Reset or rotate the modified identity according to `winlog.event_data.ObjectClass`: reset user passwords, rotate service credentials, or re-establish the expected computer trust path. Review the same `winlog.event_data.OpCorrelationID` or session for additional unauthorized changes.
108- Post-incident hardening: restrict write access to "msDS-KeyCredentialLink" to dedicated identity-management accounts, retain 5136 auditing on domain controllers, and record the confirmed provisioning workflow or abuse pattern for future triage.
109"""
110
111setup = """## Setup
112
113Audit Directory Service Changes must be enabled to generate the events used by this rule.
114Setup instructions: https://ela.st/audit-directory-service-changes
115"""
116
117[rule.investigation_fields]
118field_names = [
119 "@timestamp",
120 "user.id",
121 "winlog.event_data.SubjectUserSid",
122 "winlog.event_data.SubjectUserName",
123 "winlog.event_data.SubjectDomainName",
124 "winlog.event_data.SubjectLogonId",
125 "winlog.event_data.ObjectDN",
126 "winlog.event_data.ObjectGUID",
127 "winlog.event_data.ObjectClass",
128 "winlog.event_data.AttributeLDAPDisplayName",
129 "winlog.event_data.AttributeValue",
130 "winlog.event_data.OperationType",
131 "winlog.event_data.OpCorrelationID",
132 "host.name",
133 "host.id",
134]
135
136[transform]
137
138[[transform.investigate]]
139label = "Successful logon for the modifying session"
140description = ""
141providers = [
142 [
143 { excluded = false, field = "event.code", queryType = "phrase", value = "4624", valueType = "string" },
144 { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
145 { excluded = false, field = "winlog.event_data.TargetLogonId", queryType = "phrase", value = "{{winlog.event_data.SubjectLogonId}}", valueType = "string" }
146 ]
147]
148relativeFrom = "now-48h/h"
149relativeTo = "now"
150
151[[transform.investigate]]
152label = "Directory changes in the same operation"
153description = ""
154providers = [
155 [
156 { excluded = false, field = "event.code", queryType = "phrase", value = "5136", valueType = "string" },
157 { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
158 { excluded = false, field = "winlog.event_data.OpCorrelationID", queryType = "phrase", value = "{{winlog.event_data.OpCorrelationID}}", valueType = "string" }
159 ]
160]
161relativeFrom = "now-48h/h"
162relativeTo = "now"
163
164[[transform.investigate]]
165label = "Alerts associated with the modifying account"
166description = ""
167providers = [
168 [
169 { excluded = false, field = "event.kind", queryType = "phrase", value = "signal", valueType = "string" },
170 { excluded = false, field = "user.id", queryType = "phrase", value = "{{user.id}}", valueType = "string" }
171 ]
172]
173relativeFrom = "now-48h/h"
174relativeTo = "now"
175
176[[transform.investigate]]
177label = "Alerts associated with the modified object"
178description = ""
179providers = [
180 [
181 { excluded = false, field = "event.kind", queryType = "phrase", value = "signal", valueType = "string" },
182 { excluded = false, field = "winlog.event_data.ObjectGUID", queryType = "phrase", value = "{{winlog.event_data.ObjectGUID}}", valueType = "string" }
183 ]
184]
185relativeFrom = "now-48h/h"
186relativeTo = "now"
187
188[[rule.threat]]
189framework = "MITRE ATT&CK"
190
191[[rule.threat.technique]]
192id = "T1556"
193name = "Modify Authentication Process"
194reference = "https://attack.mitre.org/techniques/T1556/"
195
196[rule.threat.tactic]
197id = "TA0006"
198name = "Credential Access"
199reference = "https://attack.mitre.org/tactics/TA0006/"
200
201[[rule.threat]]
202framework = "MITRE ATT&CK"
203
204[[rule.threat.technique]]
205id = "T1098"
206name = "Account Manipulation"
207reference = "https://attack.mitre.org/techniques/T1098/"
208
209[rule.threat.tactic]
210id = "TA0003"
211name = "Persistence"
212reference = "https://attack.mitre.org/tactics/TA0003/"
Triage and analysis
Investigating Potential Shadow Credentials added to AD Object
Possible investigation steps
-
What object received the key-trust change?
- Focus:
winlog.event_data.ObjectDN,winlog.event_data.ObjectGUID,winlog.event_data.ObjectClass,winlog.event_data.OperationType, andwinlog.event_data.AttributeValue. - Implication: escalate when a sensitive user or computer receives an added or replaced key-trust value outside recognized enrollment; lower suspicion only when the object class, DN, and operation fit the same identity-registration workflow.
- Focus:
-
Which account and logon session wrote the value?
- Focus:
winlog.event_data.SubjectUserSid,winlog.event_data.SubjectUserName,winlog.event_data.SubjectLogonId, recoveredsource.ip, andwinlog.logon.type. $investigate_0 - Hint: match alert
winlog.event_data.SubjectLogonIdto samehost.idauthentication events withwinlog.event_data.TargetLogonId; if no 4624 matches, keep the session unresolved. - Implication: escalate for an unexpected user, admin, service, or machine writer, or source/logon type outside the object's enrollment path; lower suspicion when writer and session match recognized provisioning or device registration.
- Focus:
-
Does the writer/object pair fit a recognized ADFS or Azure AD Connect-style path?
- Why: the abuse path writes authentication material, so service-looking writers still need source and change-set validation.
- Focus: compare
winlog.event_data.SubjectUserSid,winlog.event_data.SubjectUserName,winlog.event_data.ObjectClass,winlog.event_data.ObjectDN, andsource.ipto the expected service account, object type, and enrollment source. - Implication: lower suspicion when recognized provisioning updates the expected object from the expected source; escalate when the writer is ad hoc, interactive, non-provisioning, object-class mismatched, or unexplained by source.
-
Was the logical change limited to this key credential?
- Focus: use same-operation 5136 events grouped by
winlog.event_data.OpCorrelationID; comparewinlog.event_data.ObjectGUID,winlog.event_data.AttributeLDAPDisplayName,winlog.event_data.OperationType, andwinlog.event_data.AttributeValue. $investigate_1 - Implication: escalate when the operation touches unrelated objects, adds other authentication or delegation material, or removes cleanup evidence; lower suspicion when bounded to the expected object and enrollment attributes.
- Focus: use same-operation 5136 events grouped by
-
Did the modified identity authenticate after the change?
- Why: post-change authentication shows whether the new key material may already be in use.
- Focus: derive the principal from
winlog.event_data.ObjectDN; review authentication events forwinlog.event_data.TargetUserName,winlog.event_data.TargetDomainName,source.ip,winlog.logon.type, andwinlog.event_data.AuthenticationPackageName. - Hint: search after
@timestampfor Target-side fields matching the derived principal; ifsource.ipis empty, lower origin confidence instead of treating absence as benign. - Implication: escalate when the identity authenticates from a new source, unexpected logon type, or authentication path after the change; absence of follow-on use reduces urgency only when earlier evidence proves recognized provisioning.
-
Do related alerts change the scope beyond this object?
- Focus: recent alerts for the modifying account using
user.idorwinlog.event_data.SubjectUserSid. $investigate_2 - Hint: compare with alerts scoped to the modified object's
winlog.event_data.ObjectGUID. $investigate_3 - Implication: broaden response when either scope shows privilege abuse, directory tampering, relay activity, or lateral movement; keep local when related alerts are quiet and local evidence resolves to one recognized workflow.
- Focus: recent alerts for the modifying account using
-
Escalate on the key-trust change plus any suspicious or unresolved object, writer session,
winlog.event_data.OpCorrelationIDscope, post-change authentication, or related-alert finding; close only when all evidence binds to one recognized provisioning workflow; preserve and escalate when evidence is mixed, incomplete, or uncorroborated.
False positive analysis
- AutoPilot or WHfB device enrollment can cause a computer to write its own key credential. Confirm
winlog.event_data.SubjectUserNamematches the CN inwinlog.event_data.ObjectDN,winlog.event_data.ObjectClassis "computer",winlog.event_data.OpCorrelationIDis bounded, and no unexpected follow-on authentication occurs. - ADFS or Azure AD Connect provisioning can update key credentials on user or computer objects. Confirm
winlog.event_data.SubjectUserSid,winlog.event_data.ObjectDN, recoveredsource.ip, boundedwinlog.event_data.OpCorrelationID, and post-change authentication align with one named workflow. Keep open when ownership is unresolved. - Build exceptions from stable writer SID, object class or GUID,
host.id, recovered source, and enrollment path across prior alerts. Avoid exceptions on "msDS-KeyCredentialLink",user.name, or host alone.
Response and remediation
- Preserve a case export of the triggering 5136, recovered writer-session authentication events,
winlog.event_data.AttributeValue,winlog.event_data.ObjectGUID, andwinlog.event_data.OpCorrelationIDbefore containment, reversal, or cleanup. - If confirmed benign, reverse temporary containment and document the exact workflow evidence: writer SID, object GUID/class, domain naming context, recovered source, bounded change set, and post-change authentication pattern. Keep any exception narrow and only for the recurring workflow.
- If suspicious but unconfirmed, apply reversible controls to the writer first, such as heightened monitoring or temporary access review; restrict the modified identity only when object sensitivity or follow-on authentication shows active risk.
- If confirmed malicious, contain the writer account or source system using
winlog.event_data.SubjectLogonId,source.ip,host.id, and follow-on authentication evidence. Disable the writer first when its session performed unauthorized changes; disable or rotate the modified identity only when post-change authentication or object sensitivity shows active risk. - After containment, remove only the unauthorized key-trust value and verify rollback. Reset or rotate the modified identity according to
winlog.event_data.ObjectClass: reset user passwords, rotate service credentials, or re-establish the expected computer trust path. Review the samewinlog.event_data.OpCorrelationIDor session for additional unauthorized changes. - Post-incident hardening: restrict write access to "msDS-KeyCredentialLink" to dedicated identity-management accounts, retain 5136 auditing on domain controllers, and record the confirmed provisioning workflow or abuse pattern for future triage.
References
Related rules
- Potential Kerberos Coercion via DNS-Based SPN Spoofing
- Sensitive Privilege SeEnableDelegationPrivilege assigned to a Principal
- Active Directory Forced Authentication from Linux Host - SMB Named Pipes
- AdminSDHolder Backdoor
- First Time Seen Account Performing DCSync