Elastic high stable kql
Okta AiTM Session Cookie Replay
Detects potential Adversary-in-the-Middle (AiTM) session cookie replay attacks against Okta. This rule identifies when an Okta session is used from multiple IP addresses or with suspicious non-browser user agents after initial authentication. AiTM attacks capture session cookies via phishing proxies (e.g., Evilginx, Modlishka) and replay them from attacker infrastructure, bypassing MFA. The detection correlates session start events with subsequent policy evaluations or SSO attempts that occur from different IPs or programmatic user agents.
Detection Logic
FROM logs-okta.system-*
// Filter to relevant event types for AiTM detection
| WHERE
okta.event_type IN ("user.session.start", "policy.evaluate_sign_on", "user.authentication.sso")
AND
okta.authentication_context.root_session_id IS NOT NULL
AND
okta.actor.alternate_id != "system@okta.com"
// Create event type flags
| EVAL Esql.is_session_start = okta.event_type == "user.session.start"
| EVAL Esql.is_policy_eval = okta.event_type == "policy.evaluate_sign_on"
| EVAL Esql.is_sso = okta.event_type == "user.authentication.sso"
| EVAL Esql.is_replay_event = Esql.is_policy_eval
OR Esql.is_sso
// Flag suspicious non-browser user agents
| EVAL Esql.is_suspicious_ua =
user_agent.original LIKE "python-requests*"
OR
user_agent.original LIKE "curl/*"
OR
user_agent.original LIKE "httpx*"
OR
user_agent.original LIKE "aiohttp*"
OR
user_agent.original LIKE "Go-http-client*"
OR
user_agent.original LIKE "*Headless*"
OR
user_agent.original LIKE "Java/*"
OR
user_agent.original LIKE "okhttp*"
// Aggregate by session
| STATS
Esql.session_start_count = SUM(CASE(Esql.is_session_start, 1, 0)),
Esql.replay_event_count = SUM(CASE(Esql.is_replay_event, 1, 0)),
Esql.session_start_time = MIN(CASE(Esql.is_session_start, @timestamp, null)),
Esql.first_replay_time = MIN(CASE(Esql.is_replay_event, @timestamp, null)),
Esql.last_replay_time = MAX(CASE(Esql.is_replay_event, @timestamp, null)),
Esql.session_start_ip = MAX(CASE(Esql.is_session_start, okta.client.ip, null)),
Esql.session_start_ua = MAX(CASE(Esql.is_session_start, user_agent.original, null)),
Esql.suspicious_ua_count = SUM(CASE(Esql.is_suspicious_ua, 1, 0)),
Esql.okta_client_ip_count_distinct = COUNT_DISTINCT(okta.client.ip),
Esql.user_agent_count_distinct = COUNT_DISTINCT(user_agent.original),
Esql.okta_client_ip_values = VALUES(okta.client.ip),
Esql.user_agent_values = VALUES(user_agent.original),
Esql.okta_event_type_values = VALUES(okta.event_type),
Esql.okta_outcome_result_values = VALUES(okta.outcome.result),
Esql.source_geo_country_name_values = VALUES(source.geo.country_name),
Esql.source_geo_city_name_values = VALUES(source.geo.city_name),
Esql.okta_debug_context_debug_data_risk_level_values = VALUES(okta.debug_context.debug_data.risk_level),
Esql.okta_debug_context_debug_data_risk_reasons_values = VALUES(okta.debug_context.debug_data.risk_reasons)
BY okta.authentication_context.root_session_id, okta.actor.alternate_id
// Detection conditions
| WHERE
Esql.session_start_count >= 1
AND Esql.replay_event_count >= 1
AND Esql.first_replay_time > Esql.session_start_time
AND (
(
Esql.okta_client_ip_count_distinct > 1
OR Esql.user_agent_count_distinct > 1
)
AND Esql.suspicious_ua_count > 0
)
| SORT Esql.session_start_time DESC
| KEEP Esql.*, okta.authentication_context.root_session_id, okta.actor.alternate_id False Positives
- ⚠ Users legitimately switching networks (e.g., VPN connect/disconnect, office to home) may trigger IP-based detection. Review the geographic distance and time between IP changes to assess legitimacy.
- ⚠ Automated integrations or scripts using service accounts with session cookies may trigger user-agent based detection. Consider excluding known automation accounts by okta.actor.alternate_id.
- ⚠ Mobile users switching between WiFi and cellular may show IP address changes. Correlate with device type and typical user behavior patterns.
Field Validations
Loading…
Comments (0)
Loading comments...