AWS Access Token Used from Multiple Addresses

This rule identifies potentially suspicious activity by detecting instances where a single IAM user's temporary session token is accessed from multiple IP addresses within a short time frame. Such behavior may suggest that an adversary has compromised temporary credentials and is utilizing them from various locations. To enhance detection accuracy and minimize false positives, the rule incorporates criteria that evaluate unique IP addresses, user agents, cities, and networks. These additional checks help distinguish between legitimate distributed access patterns and potential credential misuse. Detected activities are classified into different types based on the combination of unique indicators, with each classification assigned a fidelity score reflecting the likelihood of malicious behavior. High fidelity scores are given to patterns most indicative of threats, such as multiple unique IPs, networks, cities, and user agents. Medium and low fidelity scores correspond to less severe patterns, enabling security teams to effectively prioritize alerts.

Elastic rule (View on GitHub)

  1[metadata]
  2creation_date = "2025/04/11"
  3integration = ["aws"]
  4maturity = "production"
  5updated_date = "2025/07/16"
  6
  7[rule]
  8author = ["Elastic"]
  9description = """
 10This rule identifies potentially suspicious activity by detecting instances where a single IAM user's temporary session
 11token is accessed from multiple IP addresses within a short time frame. Such behavior may suggest that an adversary has
 12compromised temporary credentials and is utilizing them from various locations. To enhance detection accuracy and
 13minimize false positives, the rule incorporates criteria that evaluate unique IP addresses, user agents, cities, and
 14networks. These additional checks help distinguish between legitimate distributed access patterns and potential
 15credential misuse. Detected activities are classified into different types based on the combination of unique
 16indicators, with each classification assigned a fidelity score reflecting the likelihood of malicious behavior. High
 17fidelity scores are given to patterns most indicative of threats, such as multiple unique IPs, networks, cities, and
 18user agents. Medium and low fidelity scores correspond to less severe patterns, enabling security teams to effectively
 19prioritize alerts.
 20"""
 21false_positives = [
 22    """
 23    Highly distributed environments (e.g., globally deployed automation or edge nodes) may cause a single IAM user to
 24    appear from multiple IPs. Review the geolocation, network context, and user agent patterns to rule out benign use.
 25    """,
 26]
 27from = "now-32m"
 28interval = "5m"
 29language = "esql"
 30license = "Elastic License v2"
 31name = "AWS Access Token Used from Multiple Addresses"
 32note = """## Triage and Analysis
 33
 34### Investigating AWS Access Token Used from Multiple Addresses
 35
 36Access tokens are bound to a single user. Usage from multiple IP addresses may indicate the token was stolen and used elsewhere. By correlating this with additional detection criteria like multiple user agents, different cities, and different networks, we can improve the fidelity of the rule and help to eliminate false positives associated with expected behavior, like dual-stack IPV4/IPV6 usage.
 37
 38#### Possible Investigation Steps
 39
 40- **Identify the IAM User**: Examine the `aws.cloudtrail.user_identity.arn` stored in `user_id` and correlate with the `source.ips` stored in `ip_list` and `unique_ips` count to determine how widely the token was used.
 41- **Correlate Additional Detection Context**: Examine `activity_type` and `fidelity_score` to determine additional cities, networks or user agents associated with the token usage.
 42- **Determine Access Key Type**: Examine the `access_key_id` to determine whether the token is short-term (beginning with ASIA) or long-term (beginning with AKIA).
 43- **Check Recent MFA Events**: Determine whether the user recently enabled MFA, registered devices, or assumed a role using this token.
 44- **Review Workload Context**: Confirm whether the user was expected to be active across multiple cities, networks or user agent environments.
 45- **Trace Adversary Movement**: Pivot to related actions (e.g., `s3:ListBuckets`, `iam:ListUsers`, `sts:GetCallerIdentity`) to track further enumeration.
 46
 47### False Positive Analysis
 48
 49- Automation frameworks that rotate through multiple IPs or cloud functions with dynamic egress IPs may cause this alert to fire.
 50- Confirm geolocation and workload context before escalating.
 51
 52### Response and Remediation
 53
 54- **Revoke the Token**: Disable or rotate the IAM credentials and invalidate the temporary session token.
 55- **Audit the Environment**: Look for signs of lateral movement or data access during the token's validity.
 56- **Strengthen Controls**: Require MFA for high-privilege actions, restrict access via policy conditions (e.g., IP range or device).
 57
 58### References
 59
 60- [IAM Long-Term Credentials](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html)
 61- [STS Temporary Credentials](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp.html)
 62- [Using MFA with Temporary Credentials](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html)
 63- [AWS Threat Detection Use Cases](https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html)
 64"""
 65references = ["https://www.sygnia.co/blog/sygnia-investigation-bybit-hack/"]
 66risk_score = 47
 67rule_id = "0d92d30a-5f3e-4b71-bc3d-4a0c4914b7e0"
 68severity = "medium"
 69tags = [
 70    "Domain: Cloud",
 71    "Data Source: AWS",
 72    "Data Source: Amazon Web Services",
 73    "Data Source: AWS IAM",
 74    "Data Source: AWS CloudTrail",
 75    "Tactic: Initial Access",
 76    "Use Case: Identity and Access Audit",
 77    "Resources: Investigation Guide",
 78]
 79timestamp_override = "event.ingested"
 80type = "esql"
 81
 82query = '''
 83from logs-aws.cloudtrail* metadata _id, _version, _index
 84| where @timestamp > now() - 30 minutes
 85  and event.dataset == "aws.cloudtrail"
 86  and aws.cloudtrail.user_identity.arn is not null
 87  and aws.cloudtrail.user_identity.type == "IAMUser"
 88  and source.ip is not null
 89  and not (
 90    user_agent.original like "%Terraform%" or
 91    user_agent.original like "%Ansible%" or
 92    user_agent.original like "%Pulumni%"
 93  )
 94  and `source.as.organization.name` != "AMAZON-AES"
 95  and event.provider not in (
 96    "health.amazonaws.com", "monitoring.amazonaws.com", "notifications.amazonaws.com",
 97    "ce.amazonaws.com", "cost-optimization-hub.amazonaws.com",
 98    "servicecatalog-appregistry.amazonaws.com", "securityhub.amazonaws.com"
 99  )
100
101| eval
102  Esql.time_window_date_trunc = date_trunc(30 minutes, @timestamp),
103  Esql.aws_cloudtrail_user_identity_arn = aws.cloudtrail.user_identity.arn,
104  Esql.aws_cloudtrail_user_identity_access_key_id = aws.cloudtrail.user_identity.access_key_id,
105  Esql.source_ip = source.ip,
106  Esql.user_agent_original = user_agent.original,
107  Esql.source_ip_string = to_string(source.ip),
108  Esql.source_ip_user_agent_pair = concat(Esql.source_ip_string, " - ", user_agent.original),
109  Esql.source_ip_city_pair = concat(Esql.source_ip_string, " - ", source.geo.city_name),
110  Esql.source_geo_city_name = source.geo.city_name,
111  Esql.event_timestamp = @timestamp,
112  Esql.source_network_org_name = `source.as.organization.name`
113
114| stats
115  Esql.event_action_values = values(event.action),
116  Esql.event_provider_values = values(event.provider),
117  Esql.aws_cloudtrail_user_identity_access_key_id_values = values(Esql.aws_cloudtrail_user_identity_access_key_id),
118  Esql.aws_cloudtrail_user_identity_arn_values = values(Esql.aws_cloudtrail_user_identity_arn),
119  Esql.source_ip_values = values(Esql.source_ip),
120  Esql.user_agent_original_values = values(Esql.user_agent_original),
121  Esql.source_ip_user_agent_pair_values = values(Esql.source_ip_user_agent_pair),
122  Esql.source_geo_city_name_values = values(Esql.source_geo_city_name),
123  Esql.source_ip_city_pair_values = values(Esql.source_ip_city_pair),
124  Esql.source_network_org_name_values = values(Esql.source_network_org_name),
125  Esql.source_ip_count_distinct = count_distinct(Esql.source_ip),
126  Esql.user_agent_original_count_distinct = count_distinct(Esql.user_agent_original),
127  Esql.source_geo_city_name_count_distinct = count_distinct(Esql.source_geo_city_name),
128  Esql.source_network_org_name_count_distinct = count_distinct(Esql.source_network_org_name),
129  Esql.timestamp_first_seen = min(Esql.event_timestamp),
130  Esql.timestamp_last_seen = max(Esql.event_timestamp),
131  Esql.event_count = count()
132  by Esql.time_window_date_trunc, Esql.aws_cloudtrail_user_identity_access_key_id
133
134| eval
135  Esql.activity_type = case(
136    Esql.source_ip_count_distinct >= 2 and Esql.source_network_org_name_count_distinct >= 2 and Esql.source_geo_city_name_count_distinct >= 2 and Esql.user_agent_original_count_distinct >= 2, "multiple_ip_network_city_user_agent",
137    Esql.source_ip_count_distinct >= 2 and Esql.source_network_org_name_count_distinct >= 2 and Esql.source_geo_city_name_count_distinct >= 2, "multiple_ip_network_city",
138    Esql.source_ip_count_distinct >= 2 and Esql.source_geo_city_name_count_distinct >= 2, "multiple_ip_and_city",
139    Esql.source_ip_count_distinct >= 2 and Esql.source_network_org_name_count_distinct >= 2, "multiple_ip_and_network",
140    Esql.source_ip_count_distinct >= 2 and Esql.user_agent_original_count_distinct >= 2, "multiple_ip_and_user_agent",
141    "normal_activity"
142  ),
143  Esql.activity_fidelity_score = case(
144    Esql.activity_type == "multiple_ip_network_city_user_agent", "high",
145    Esql.activity_type == "multiple_ip_network_city", "high",
146    Esql.activity_type == "multiple_ip_and_city", "medium",
147    Esql.activity_type == "multiple_ip_and_network", "medium",
148    Esql.activity_type == "multiple_ip_and_user_agent", "low"
149  )
150
151| keep
152  Esql.time_window_date_trunc,
153  Esql.activity_type,
154  Esql.activity_fidelity_score,
155  Esql.event_count,
156  Esql.timestamp_first_seen,
157  Esql.timestamp_last_seen,
158  Esql.aws_cloudtrail_user_identity_arn_values,
159  Esql.aws_cloudtrail_user_identity_access_key_id_values,
160  Esql.event_action_values,
161  Esql.event_provider_values,
162  Esql.source_ip_values,
163  Esql.user_agent_original_values,
164  Esql.source_ip_user_agent_pair_values,
165  Esql.source_geo_city_name_values,
166  Esql.source_ip_city_pair_values,
167  Esql.source_network_org_name_values,
168  Esql.source_ip_count_distinct,
169  Esql.user_agent_original_count_distinct,
170  Esql.source_geo_city_name_count_distinct,
171  Esql.source_network_org_name_count_distinct
172
173| where Esql.activity_type != "normal_activity"
174'''
175
176
177[[rule.threat]]
178framework = "MITRE ATT&CK"
179[[rule.threat.technique]]
180id = "T1078"
181name = "Valid Accounts"
182reference = "https://attack.mitre.org/techniques/T1078/"
183[[rule.threat.technique.subtechnique]]
184id = "T1078.004"
185name = "Cloud Accounts"
186reference = "https://attack.mitre.org/techniques/T1078/004/"
187
188
189
190[rule.threat.tactic]
191id = "TA0001"
192name = "Initial Access"
193reference = "https://attack.mitre.org/tactics/TA0001/"

Triage and Analysis

Investigating AWS Access Token Used from Multiple Addresses

Access tokens are bound to a single user. Usage from multiple IP addresses may indicate the token was stolen and used elsewhere. By correlating this with additional detection criteria like multiple user agents, different cities, and different networks, we can improve the fidelity of the rule and help to eliminate false positives associated with expected behavior, like dual-stack IPV4/IPV6 usage.

Possible Investigation Steps

  • Identify the IAM User: Examine the aws.cloudtrail.user_identity.arn stored in user_id and correlate with the source.ips stored in ip_list and unique_ips count to determine how widely the token was used.
  • Correlate Additional Detection Context: Examine activity_type and fidelity_score to determine additional cities, networks or user agents associated with the token usage.
  • Determine Access Key Type: Examine the access_key_id to determine whether the token is short-term (beginning with ASIA) or long-term (beginning with AKIA).
  • Check Recent MFA Events: Determine whether the user recently enabled MFA, registered devices, or assumed a role using this token.
  • Review Workload Context: Confirm whether the user was expected to be active across multiple cities, networks or user agent environments.
  • Trace Adversary Movement: Pivot to related actions (e.g., s3:ListBuckets, iam:ListUsers, sts:GetCallerIdentity) to track further enumeration.

False Positive Analysis

  • Automation frameworks that rotate through multiple IPs or cloud functions with dynamic egress IPs may cause this alert to fire.
  • Confirm geolocation and workload context before escalating.

Response and Remediation

  • Revoke the Token: Disable or rotate the IAM credentials and invalidate the temporary session token.
  • Audit the Environment: Look for signs of lateral movement or data access during the token's validity.
  • Strengthen Controls: Require MFA for high-privilege actions, restrict access via policy conditions (e.g., IP range or device).

References

References

Related rules

to-top