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/09/02"
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 aws.cloudtrail.user_identity.access_key_id is not null
90 and not (
91 user_agent.original like "*Terraform*" or
92 user_agent.original like "*Ansible*" or
93 user_agent.original like "*Pulumi*"
94 )
95 and `source.as.organization.name` != "AMAZON-AES"
96 and not ((
97 `source.as.organization.name` == "AMAZON-02" and aws.cloudtrail.event_category == "Data"))
98 and event.provider not in (
99 "health.amazonaws.com", "monitoring.amazonaws.com", "notifications.amazonaws.com",
100 "ce.amazonaws.com", "cost-optimization-hub.amazonaws.com",
101 "servicecatalog-appregistry.amazonaws.com", "securityhub.amazonaws.com",
102 "account.amazonaws.com", "budgets.amazonaws.com", "freetier.amazonaws.com"
103 )
104
105| eval
106 Esql.time_window_date_trunc = date_trunc(30 minutes, @timestamp),
107 Esql.aws_cloudtrail_user_identity_arn = aws.cloudtrail.user_identity.arn,
108 Esql.aws_cloudtrail_user_identity_access_key_id = aws.cloudtrail.user_identity.access_key_id,
109 Esql.source_ip = source.ip,
110 Esql.user_agent_original = user_agent.original,
111 Esql.source_ip_string = to_string(source.ip),
112 Esql.source_ip_user_agent_pair = concat(Esql.source_ip_string, " - ", user_agent.original),
113 Esql.source_ip_city_pair = concat(Esql.source_ip_string, " - ", source.geo.city_name),
114 Esql.source_geo_city_name = source.geo.city_name,
115 Esql.source_network_org_name = `source.as.organization.name`,
116 Esql.source_ip_network_pair = concat(Esql.source_ip_string, "-", `source.as.organization.name`),
117 Esql.event_timestamp = @timestamp
118
119| stats
120 Esql.event_action_values = values(event.action),
121 Esql.event_provider_values = values(event.provider),
122 Esql.aws_cloudtrail_user_identity_access_key_id_values = values(Esql.aws_cloudtrail_user_identity_access_key_id),
123 Esql.aws_cloudtrail_user_identity_arn_values = values(Esql.aws_cloudtrail_user_identity_arn),
124 Esql.source_ip_values = values(Esql.source_ip),
125 Esql.user_agent_original_values = values(Esql.user_agent_original),
126 Esql.source_ip_user_agent_pair_values = values(Esql.source_ip_user_agent_pair),
127 Esql.source_geo_city_name_values = values(Esql.source_geo_city_name),
128 Esql.source_ip_city_pair_values = values(Esql.source_ip_city_pair),
129 Esql.source_network_org_name_values = values(Esql.source_network_org_name),
130 Esql.source_ip_network_pair_values = values(Esql.source_ip_network_pair),
131 Esql.source_ip_count_distinct = count_distinct(Esql.source_ip),
132 Esql.user_agent_original_count_distinct = count_distinct(Esql.user_agent_original),
133 Esql.source_geo_city_name_count_distinct = count_distinct(Esql.source_geo_city_name),
134 Esql.source_network_org_name_count_distinct = count_distinct(Esql.source_network_org_name),
135 Esql.timestamp_first_seen = min(Esql.event_timestamp),
136 Esql.timestamp_last_seen = max(Esql.event_timestamp),
137 Esql.event_count = count()
138 by Esql.time_window_date_trunc, Esql.aws_cloudtrail_user_identity_access_key_id
139
140| eval
141 Esql.activity_type = case(
142 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",
143 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",
144 Esql.source_ip_count_distinct >= 2 and Esql.source_geo_city_name_count_distinct >= 2, "multiple_ip_and_city",
145 Esql.source_ip_count_distinct >= 2 and Esql.source_network_org_name_count_distinct >= 2, "multiple_ip_and_network",
146 Esql.source_ip_count_distinct >= 2 and Esql.user_agent_original_count_distinct >= 2, "multiple_ip_and_user_agent",
147 "normal_activity"
148 ),
149 Esql.activity_fidelity_score = case(
150 Esql.activity_type == "multiple_ip_network_city_user_agent", "high",
151 Esql.activity_type == "multiple_ip_network_city", "high",
152 Esql.activity_type == "multiple_ip_and_city", "medium",
153 Esql.activity_type == "multiple_ip_and_network", "medium",
154 Esql.activity_type == "multiple_ip_and_user_agent", "low"
155 )
156
157| keep
158 Esql.time_window_date_trunc,
159 Esql.activity_type,
160 Esql.activity_fidelity_score,
161 Esql.event_count,
162 Esql.timestamp_first_seen,
163 Esql.timestamp_last_seen,
164 Esql.aws_cloudtrail_user_identity_arn_values,
165 Esql.aws_cloudtrail_user_identity_access_key_id_values,
166 Esql.event_action_values,
167 Esql.event_provider_values,
168 Esql.source_ip_values,
169 Esql.user_agent_original_values,
170 Esql.source_ip_user_agent_pair_values,
171 Esql.source_geo_city_name_values,
172 Esql.source_ip_city_pair_values,
173 Esql.source_network_org_name_values,
174 Esql.source_ip_network_pair_values,
175 Esql.source_ip_count_distinct,
176 Esql.user_agent_original_count_distinct,
177 Esql.source_geo_city_name_count_distinct,
178 Esql.source_network_org_name_count_distinct
179
180| where Esql.activity_type != "normal_activity"
181'''
182
183[rule.investigation_fields]
184field_names = [
185 "Esql.timestamp_first_seen",
186 "Esql.timestamp_last_seen",
187 "Esql.activity_type",
188 "Esql.activity_fidelity_score",
189 "Esql.event_count",
190 "Esql.aws_cloudtrail_user_identity_arn_values",
191 "Esql.aws_cloudtrail_user_identity_access_key_id_values",
192 "Esql.event_action_values",
193 "Esql.event_provider_values",
194 "Esql.source_ip_values",
195 "Esql.user_agent_original_values",
196 "Esql.source_ip_user_agent_pair_values",
197 "Esql.source_geo_city_name_values",
198 "Esql.source_ip_city_pair_values",
199 "Esql.source_network_org_name_values",
200 "Esql.source_ip_network_pair_values",
201 "Esql.source_ip_count_distinct",
202 "Esql.user_agent_original_count_distinct",
203 "Esql.source_geo_city_name_count_distinct",
204 "Esql.source_network_org_name_count_distinct"
205]
206
207
208[[rule.threat]]
209framework = "MITRE ATT&CK"
210[[rule.threat.technique]]
211id = "T1078"
212name = "Valid Accounts"
213reference = "https://attack.mitre.org/techniques/T1078/"
214[[rule.threat.technique.subtechnique]]
215id = "T1078.004"
216name = "Cloud Accounts"
217reference = "https://attack.mitre.org/techniques/T1078/004/"
218
219
220
221[rule.threat.tactic]
222id = "TA0001"
223name = "Initial Access"
224reference = "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 inuser_id
and correlate with thesource.ips
stored inip_list
andunique_ips
count to determine how widely the token was used. - Correlate Additional Detection Context: Examine
activity_type
andfidelity_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
- AWS IAM Virtual MFA Device Registration Attempt with Session Token
- AWS IAM Create User via Assumed Role on EC2 Instance
- AWS IAM Assume Role Policy Update
- AWS IAM Customer-Managed Policy Attached to Role by Rare User
- AWS IAM AdministratorAccess Policy Attached to Group