Credential Access (TA0006)(external, opens in a new tab or window)
text code block:FROM logs-okta.system-* METADATA _id, _version, _index | WHERE event.dataset == "okta.system" AND (event.action LIKE "user.authentication.*" OR event.action == "user.session.start") AND okta.outcome.reason IN ("INVALID_CREDENTIALS", "LOCKED_OUT") AND okta.actor.alternate_id IS NOT NULL // Primary authn endpoint; sessions API provides additional coverage AND ( okta.debug_context.debug_data.request_uri == "/api/v1/authn" OR okta.debug_context.debug_data.request_uri LIKE "/api/v1/sessions*" ) // Track whether each event has a device token | EVAL has_dt_hash = CASE(okta.debug_context.debug_data.dt_hash IS NOT NULL, 1, 0) // Aggregate by IP + user to detect single-user brute force | STATS Esql.unique_dt_hashes = COUNT_DISTINCT(okta.debug_context.debug_data.dt_hash), Esql.total_attempts = COUNT(*), Esql.attempts_with_dt = SUM(has_dt_hash), Esql.unique_user_agents = COUNT_DISTINCT(okta.client.user_agent.raw_user_agent), Esql.first_seen = MIN(@timestamp), Esql.last_seen = MAX(@timestamp), Esql.dt_hash_values = VALUES(okta.debug_context.debug_data.dt_hash), Esql.event_action_values = VALUES(event.action), Esql.user_agent_values = VALUES(okta.client.user_agent.raw_user_agent), Esql.device_values = VALUES(okta.client.device), Esql.is_proxy_values = VALUES(okta.security_context.is_proxy), Esql.geo_country_values = VALUES(client.geo.country_name), Esql.geo_city_values = VALUES(client.geo.city_name), Esql.source_asn_values = VALUES(source.as.number), Esql.source_asn_org_values = VALUES(source.as.organization.name), Esql.threat_suspected_values = VALUES(okta.debug_context.debug_data.threat_suspected), Esql.risk_level_values = VALUES(okta.debug_context.debug_data.risk_level), Esql.risk_reasons_values = VALUES(okta.debug_context.debug_data.risk_reasons) BY okta.client.ip, okta.actor.alternate_id // Calculate automation detection metrics (float-safe division) | EVAL Esql.dt_coverage = Esql.attempts_with_dt * 1.0 / Esql.total_attempts, Esql.dt_per_attempt = Esql.unique_dt_hashes * 1.0 / Esql.total_attempts // Detection branches: // A) Many unique DT hashes relative to attempts = tooling generating new tokens per attempt // B) High attempts + very low DT coverage = cookie-less automation (no DT sent at all) // C) Multiple user agents for same user = evasion or automation | WHERE (Esql.unique_dt_hashes >= 7 AND Esql.total_attempts >= 10 AND Esql.dt_per_attempt >= 0.5) OR (Esql.total_attempts >= 12 AND Esql.dt_coverage < 0.15) OR (Esql.total_attempts >= 10 AND Esql.unique_user_agents >= 5) | SORT Esql.total_attempts DESC | KEEP Esql.*, okta.client.ip, okta.actor.alternate_id
Install detection rules in Elastic Security
Detect Potential Okta Brute Force (Device Token Rotation) in the Elastic Security detection engine by installing this rule into your Elastic Stack.
To setup this rule, check out the installation guide for Prebuilt Security Detection Rules(external, opens in a new tab or window).