Detection rules › Kusto

Potential Password Spray Attack

Status
available
Severity
medium
Time window
5m
Group by
City, Country, client_ipAddress_s
Source
github.com/Azure/Azure-Sentinel

This query searches for failed attempts to log into the Okta console from more than 15 various users within a 5 minute timeframe from the same source. This is a potential indication of a password spray attack.

MITRE ATT&CK coverage

TacticTechniques
Credential AccessT1110.003 Brute Force: Password Spraying

Event coverage

Rules detecting the same action

Other rules on this platform that filter on the same API call or operation.

Rule body kusto

id: e27dd7e5-4367-4c40-a2b7-fcd7e7a8a508
name: Potential Password Spray Attack
description: |
  'This query searches for failed attempts to log into the Okta console from more than 15 various users within a 5 minute timeframe from the same source. This is a potential indication of a password spray attack.'
severity: Medium
status: Available
requiredDataConnectors:
  - connectorId: OktaSSO
    dataTypes:
      - Okta_CL
  - connectorId: OktaSSOv2
    dataTypes:
      - OktaSSO
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - CredentialAccess
relevantTechniques:
  - T1110.003
query: |
  let FailureThreshold = 15;
  let FailedEvents = OktaSSO
  | where eventType_s =~ "user.session.start"and outcome_reason_s in ("VERIFICATION_ERROR","INVALID_CREDENTIALS")
  | summarize dcount(actor_alternateId_s) by client_ipAddress_s, bin(TimeGenerated, 5m)
  | where dcount_actor_alternateId_s > FailureThreshold
  | project client_ipAddress_s, TimeGenerated;
  OktaSSO
  | where eventType_s =~ "user.session.start"and outcome_reason_s in ("VERIFICATION_ERROR","INVALID_CREDENTIALS")
  | summarize Users = make_set(actor_alternateId_s) by client_ipAddress_s, City = column_ifexists('client_geographicalContext_city_s', ""), Country = column_ifexists('client_geographicalContext_country_s', ""), bin(TimeGenerated, 5m)
  | join kind=inner (FailedEvents) on client_ipAddress_s, TimeGenerated
  | sort by TimeGenerated desc
entityMappings:
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: client_ipAddress_s
version: 1.1.1
kind: Scheduled

Stages and Predicates

Parameters

let FailureThreshold = 15;

Let binding: FailedEvents

let FailedEvents = OktaSSO
| where eventType_s =~ "user.session.start"and outcome_reason_s in ("VERIFICATION_ERROR","INVALID_CREDENTIALS")
| summarize dcount(actor_alternateId_s) by client_ipAddress_s, bin(TimeGenerated, 5m)
| where dcount_actor_alternateId_s > FailureThreshold
| project client_ipAddress_s, TimeGenerated;

Derived from FailureThreshold.

Stage 1: source

OktaSSO

Stage 2: where

| where eventType_s =~ "user.session.start"and outcome_reason_s in ("VERIFICATION_ERROR","INVALID_CREDENTIALS")

Stage 3: summarize

| summarize Users = make_set(actor_alternateId_s) by client_ipAddress_s, City = column_ifexists('client_geographicalContext_city_s', ""), Country = column_ifexists('client_geographicalContext_country_s', ""), bin(TimeGenerated, 5m)

Stage 4: join

| join kind=inner (FailedEvents) on client_ipAddress_s, TimeGenerated

Stage 5: sort

| sort by TimeGenerated desc

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
dcount_actor_alternateId_sgt
  • 15 transforms: cased
eventType_seq
  • user.session.start
outcome_reason_sin
  • INVALID_CREDENTIALS transforms: cased
  • VERIFICATION_ERROR 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
Citysummarize
Countrysummarize
Userssummarize
client_ipAddress_ssummarize