Detection rules › Kusto

Hunt for accounts with leaked credentials

Group by
AccountObjectId
Author
Robbe Van den Daele
Source
github.com/HybridBrothers/Hunting-Queries-Detection-Rules

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.

FieldKindValues
hasAdLeakedCredentialseq
  • true transforms: cased
hasLeakedCredentialseq
  • true transforms: cased
typeeq
  • AadObjectId transforms: cased

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.

FieldSource
AccountObjectIdsummarize