Potential Okta Brute Force (Multi-Source)
editPotential Okta Brute Force (Multi-Source)
editDetects potential brute force attacks against a single Okta user account from multiple source IPs, indicating attackers rotating through proxy infrastructure to evade IP-based detection.
Rule type: esql
Rule indices: None
Severity: medium
Risk score: 47
Runs every: 5m
Searches indices from: now-30m (Date Math format, see also Additional look-back time)
Maximum alerts per execution: 100
References:
- https://support.okta.com/help/s/article/Troubleshooting-Distributed-Brute-Force-andor-Password-Spray-attacks-in-Okta
- https://www.okta.com/identity-101/brute-force/
- https://developer.okta.com/docs/reference/api/event-types/
- https://www.elastic.co/security-labs/testing-okta-visibility-and-detection-dorothy
- https://www.elastic.co/security-labs/monitoring-okta-threats-with-elastic-security
- https://www.elastic.co/security-labs/starter-guide-to-understanding-okta
Tags:
- Domain: Identity
- Use Case: Identity and Access Audit
- Use Case: Threat Detection
- Data Source: Okta
- Data Source: Okta System Logs
- Tactic: Credential Access
- Resources: Investigation Guide
Version: 2
Rule authors:
- Elastic
Rule license: Elastic License v2
Investigation guide
editTriage and analysis
Investigating Potential Okta Brute Force (Multi-Source)
This rule identifies a single user account receiving failed authentication attempts from multiple unique source IPs. This pattern indicates attackers rotating through proxy infrastructure to evade IP-based detection while targeting a specific account.
Possible investigation steps
- Identify the targeted user account and determine if it has elevated privileges or sensitive access.
- Review the geographic distribution of source IPs for anomalies such as multiple countries or unusual locations.
- Examine the ASN ownership of source IPs for signs of proxy, VPN, or cloud infrastructure.
- Check if Okta flagged any of the sources as known threats or proxies.
- Determine if any authentication attempts succeeded following the failed attempts.
- Review the user’s recent activity for signs of account compromise.
False positive analysis
- Users traveling internationally with mobile devices may generate failed attempts from multiple locations.
- Service accounts accessed from distributed legitimate infrastructure may trigger this rule.
- Corporate VPN exit nodes spread across regions could appear as multiple IPs for a single user.
Response and remediation
- If attack is confirmed, reset the user’s password immediately.
- Review and potentially reset MFA for the targeted account.
- Block attacking IP addresses at the network perimeter.
- Consider implementing geo-restrictions for the targeted account if dispersed access is not expected.
- Monitor for any successful authentication that may indicate compromise.
Setup
editThe Okta Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.
Rule query
editFROM 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
// Create source mapping for analyst context
| EVAL Esql.source_info = CONCAT(
"{\"ip\":\"", COALESCE(okta.client.ip::STRING, "unknown"),
"\",\"country\":\"", COALESCE(client.geo.country_name, "unknown"),
"\",\"asn\":\"", COALESCE(source.as.organization.name, "unknown"),
"\",\"user_agent\":\"", COALESCE(okta.client.user_agent.raw_user_agent, "unknown"), "\"}"
)
| STATS
Esql.unique_source_ips = COUNT_DISTINCT(okta.client.ip),
Esql.total_attempts = COUNT(*),
Esql.unique_user_agents = COUNT_DISTINCT(okta.client.user_agent.raw_user_agent),
Esql.unique_dt_hashes = COUNT_DISTINCT(okta.debug_context.debug_data.dt_hash),
Esql.unique_asns = COUNT_DISTINCT(source.as.number),
Esql.unique_countries = COUNT_DISTINCT(client.geo.country_name),
Esql.first_seen = MIN(@timestamp),
Esql.last_seen = MAX(@timestamp),
Esql.source_ip_values = VALUES(okta.client.ip),
Esql.source_mapping = VALUES(Esql.source_info),
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.actor.alternate_id
| EVAL
Esql.attempts_per_ip = Esql.total_attempts * 1.0 / Esql.unique_source_ips,
Esql.duration_seconds = DATE_DIFF("seconds", Esql.first_seen, Esql.last_seen)
| WHERE
Esql.unique_source_ips >= 5
AND Esql.total_attempts >= 10
AND (
Esql.unique_countries >= 2 OR
Esql.unique_asns >= 3 OR
Esql.unique_source_ips >= 8 OR
Esql.unique_user_agents >= 3
)
| SORT Esql.unique_source_ips DESC
| KEEP Esql.*, okta.actor.alternate_id
Framework: MITRE ATT&CKTM
-
Tactic:
- Name: Credential Access
- ID: TA0006
- Reference URL: https://attack.mitre.org/tactics/TA0006/
-
Technique:
- Name: Brute Force
- ID: T1110
- Reference URL: https://attack.mitre.org/techniques/T1110/
-
Sub-technique:
- Name: Password Guessing
- ID: T1110.001
- Reference URL: https://attack.mitre.org/techniques/T1110/001/