Elastic high stable kql

M365 or Entra ID Identity Sign-in from a Suspicious Source

This rule correlate Entra-ID or Microsoft 365 mail successful sign-in events with network security alerts by source address. Adversaries may trigger some network security alerts such as reputation or other anomalies before accessing cloud resources.

View Source

Detection Logic

from logs-o365.audit-*, logs-azure.signinlogs-*, .alerts-security.*
// filter for azure or m365 sign-in and external alerts with source.ip not null
| where to_ip(source.ip) is not null
  and (data_stream.dataset in ("o365.audit", "azure.signinlogs") or kibana.alert.rule.rule_id == "eb079c62-4481-4d6e-9643-3ca499df7aaa")
  and not cidr_match(
    to_ip(source.ip),
    "10.0.0.0/8", "127.0.0.0/8", "169.254.0.0/16", "172.16.0.0/12", "192.0.0.0/24", "192.0.0.0/29",
    "192.0.0.8/32", "192.0.0.9/32", "192.0.0.10/32", "192.0.0.170/32", "192.0.0.171/32", "192.0.2.0/24",
    "192.31.196.0/24", "192.52.193.0/24", "192.168.0.0/16", "192.88.99.0/24", "224.0.0.0/4",
    "100.64.0.0/10", "192.175.48.0/24", "198.18.0.0/15", "198.51.100.0/24", "203.0.113.0/24",
    "240.0.0.0/4", "::1", "FE80::/10", "FF00::/8"
  )

// capture relevant raw fields
| keep source.ip, event.action, event.outcome, data_stream.dataset, kibana.alert.rule.rule_id, event.category

// classify each source ip based on alert type
| eval
  Esql.source_ip_mail_access_case = case(data_stream.dataset == "o365.audit" and event.action == "MailItemsAccessed" and event.outcome == "success", to_ip(source.ip)),
  Esql.source_ip_azure_signin_case = case(data_stream.dataset == "azure.signinlogs" and event.outcome == "success", to_ip(source.ip)),
  Esql.source_ip_network_alert_case = case(kibana.alert.rule.rule_id == "eb079c62-4481-4d6e-9643-3ca499df7aaa" and not data_stream.dataset in ("o365.audit", "azure.signinlogs"), to_ip(source.ip))

// aggregate by source ip
| stats
    Esql.event_count = count(*),
    Esql.source_ip_mail_access_case_count_distinct = count_distinct(Esql.source_ip_mail_access_case),
    Esql.source_ip_azure_signin_case_count_distinct = count_distinct(Esql.source_ip_azure_signin_case),
    Esql.source_ip_network_alert_case_count_distinct = count_distinct(Esql.source_ip_network_alert_case),
    Esql.data_stream_dataset_count_distinct = count_distinct(data_stream.dataset),
    Esql.data_stream_dataset_values = values(data_stream.dataset),
    Esql.kibana_alert_rule_id_values = values(kibana.alert.rule.rule_id),
    Esql.event_category_values = values(event.category)
  by Esql.source_ip = to_ip(source.ip)

// correlation condition
| where
  Esql.source_ip_network_alert_case_count_distinct > 0
  and Esql.data_stream_dataset_count_distinct >= 2
  and (Esql.source_ip_mail_access_case_count_distinct > 0 or Esql.source_ip_azure_signin_case_count_distinct > 0)
  and Esql.event_count <= 100

False Positives

  • Custom network security rules that triggers on a proxy or gateway used by users to access Azure or O365.

Field Validations

Loading…

Comments (0)

Loading comments...