Detection rules › Kusto
Hunt for accounts with leaked credentials
This query searches for accounts where Exposure Management detected leaked credentials. This query is correlated with the IdentityInfo table, mainly because you can easily create a detection of this rule if you would like to.
Rule body yaml
IdentityInfo
| summarize arg_max(TimeGenerated, AccountUpn, AccountDisplayName, AccountDomain, CriticalityLevel, DistinguishedName) by AccountObjectId
| join kind=inner (
ExposureGraphNodes
// Get accounts with Leaked Credentials
| where NodeProperties.rawData.hasAdLeakedCredentials == "true" or NodeProperties.rawData.hasLeakedCredentials == "true"
// Get the AAD Object ID
| mv-expand EntityIds
| where EntityIds.type == "AadObjectId"
| extend AccountObjectId = extract('objectid=(.*)', 1, tostring(EntityIds.id))
| extend HasAdLeakedCredentials = tostring(NodeProperties.rawData.hasAdLeakedCredentials),
HasLeakedCredentials = tostring(NodeProperties.rawData.hasLeakedCredentials)
| distinct NodeLabel, AccountObjectId, HasAdLeakedCredentials, HasLeakedCredentials
) on AccountObjectId
Stages and Predicates
Stage 1: source
IdentityInfo
Stage 2: summarize
| summarize arg_max(TimeGenerated, AccountUpn, AccountDisplayName, AccountDomain, CriticalityLevel, DistinguishedName) by AccountObjectId
Stage 3: join
| join kind=inner (
ExposureGraphNodes
| where NodeProperties.rawData.hasAdLeakedCredentials == "true" or NodeProperties.rawData.hasLeakedCredentials == "true"
| mv-expand EntityIds
| where EntityIds.type == "AadObjectId"
| extend AccountObjectId = extract('objectid=(.*)', 1, tostring(EntityIds.id))
| extend HasAdLeakedCredentials = tostring(NodeProperties.rawData.hasAdLeakedCredentials),
HasLeakedCredentials = tostring(NodeProperties.rawData.hasLeakedCredentials)
| distinct NodeLabel, AccountObjectId, HasAdLeakedCredentials, HasLeakedCredentials
) on AccountObjectId
Indicators
Each row is a field, operator, and value that the rule matches. The corpus column counts how many other rules in the catalog look for the same combination: high numbers point to widely-used, community-vetted indicators. Blank or 1 shows that the indicator is specific to this rule.
| Field | Kind | Values |
|---|---|---|
hasAdLeakedCredentials | eq |
|
hasLeakedCredentials | eq |
|
type | eq |
|
Output fields
Fields the rule emits when it matches. Chronicle authors list these in the outcome block; they appear on the detection and $risk_score drives alerting. Sentinel / Defender XDR rules build them up through project / summarize / extend stages. Sentinel maps these into alert fields via entityMappings and customDetails; Defender XDR custom detections surface them as alert fields directly.
| Field | Source |
|---|---|
AccountObjectId | summarize |