EXPLORE
← Back to Explore
elastichighTTP

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.

MITRE ATT&CK

credential-accessdefense-evasion

Detection Query

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

Author

Elastic

Created

2026/01/26

Data Sources

OktaOkta System Logs

Tags

Domain: IdentityUse Case: Identity and Access AuditData Source: OktaData Source: Okta System LogsTactic: Credential AccessTactic: Lateral MovementResources: Investigation Guide
Raw Content
[metadata]
creation_date = "2026/01/26"
integration = ["okta"]
maturity = "production"
updated_date = "2026/03/24"

[rule]
author = ["Elastic"]
description = """
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.
"""
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.
    """,
]
from = "now-30m"
language = "esql"
license = "Elastic License v2"
name = "Okta AiTM Session Cookie Replay"
note = """## Triage and analysis

### Investigating Okta AiTM Session Cookie Replay

Adversary-in-the-Middle (AiTM) attacks use reverse proxies to intercept authentication flows, capturing session cookies after victims complete MFA. Attackers then replay these cookies from their own infrastructure to hijack authenticated sessions. This rule detects the post-capture phase by identifying sessions used from anomalous contexts.

This is an ES|QL aggregation-based rule. Pivot into raw events using the root session ID for full investigation context.

### Possible investigation steps

- Review the collected IP addresses from the alert to identify all IPs that accessed this session. Investigate geographic locations and ASN ownership for each IP.
- Examine the user agent values for non-browser user agents like `python-requests`, `curl`, or `Headless` browsers that indicate programmatic access.
- Check Okta's risk assessment fields. HIGH risk with reasons like "Anomalous Device" or "Anomalous Location" strengthens AiTM suspicion.
- Correlate the session start timestamp with the first replay attempt timestamp to understand the attack timeline.
- Query raw Okta events for the session ID to see all activity within this session, including accessed applications.
- Review proxy detection fields to determine if attacker requests originated from VPN/proxy infrastructure.
- Check the user's recent password reset or MFA enrollment events, as these may indicate account compromise leading to the AiTM attack.
- Contact the user to verify if they received phishing emails with links to suspicious login pages around the session start time.

### False positive analysis

- Legitimate VPN usage may cause IP address changes within a session. Check if both IPs belong to known corporate VPN ranges or the user's typical locations.
- Users traveling may show geographic IP changes. Correlate with travel schedules or expense reports if available.
- Browser extensions or security tools may modify user agents. Verify the user agent patterns match known tools in the environment.
- API integrations using user context may trigger non-browser UA detection. Exclude known service accounts.

### Response and remediation

- Immediately terminate all active sessions for the affected user via Okta Admin Console.
- Reset the user's password and require MFA re-enrollment to invalidate any captured credentials.
- Review and revoke any OAuth tokens or API keys associated with the user.
- Check Okta System Log for applications accessed during the suspicious session and assess data exposure.
- If downstream applications were accessed, coordinate with application owners to review access logs and potential data exfiltration.
- Block the attacker IP addresses at the network perimeter and add to threat intelligence feeds.
- Implement Okta sign-on policies that challenge or block sessions with HIGH risk scores or proxy detection.
- Consider enabling Okta ThreatInsight to automatically block known malicious IPs.
- Review email security logs for phishing attempts targeting the user around the session start time.
- Escalate to incident response if sensitive applications (AWS, Salesforce, email) were accessed from the attacker IP.
"""
references = [
    "https://www.bleepingcomputer.com/news/security/okta-sso-accounts-targeted-in-vishing-based-data-theft-attacks/",
    "https://reliaquest.com/blog/threat-spotlight-shinyhunters-data-breach-targets-salesforce-amid-scattered-spider-collaboration/",
    "https://securitylabs.datadoghq.com/articles/investigating-an-aitm-phishing-campaign-m365-okta/)",
    "https://www.microsoft.com/en-us/security/blog/2022/07/12/from-cookie-theft-to-bec-attackers-use-aitm-phishing-sites-as-entry-point-to-further-financial-fraud/",
    "https://www.elastic.co/security-labs/monitoring-okta-threats-with-elastic-security",
    "https://www.elastic.co/security-labs/starter-guide-to-understanding-okta",
]
risk_score = 73
rule_id = "9ed5d08f-aad6-4c03-838c-d686da887c2c"
severity = "high"
tags = [
    "Domain: Identity",
    "Use Case: Identity and Access Audit",
    "Data Source: Okta",
    "Data Source: Okta System Logs",
    "Tactic: Credential Access",
    "Tactic: Lateral Movement",
    "Resources: Investigation Guide",

]
timestamp_override = "event.ingested"
type = "esql"

query = '''
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
'''


[[rule.threat]]
framework = "MITRE ATT&CK"

[[rule.threat.technique]]
id = "T1539"
name = "Steal Web Session Cookie"
reference = "https://attack.mitre.org/techniques/T1539/"

[rule.threat.tactic]
id = "TA0006"
name = "Credential Access"
reference = "https://attack.mitre.org/tactics/TA0006/"

[[rule.threat]]
framework = "MITRE ATT&CK"

[[rule.threat.technique]]
id = "T1550"
name = "Use Alternate Authentication Material"
reference = "https://attack.mitre.org/techniques/T1550/"

[[rule.threat.technique.subtechnique]]
id = "T1550.004"
name = "Web Session Cookie"
reference = "https://attack.mitre.org/techniques/T1550/004/"

[rule.threat.tactic]
id = "TA0005"
name = "Defense Evasion"
reference = "https://attack.mitre.org/tactics/TA0005/"