Skip to content

Commit 3bfbafe

Browse files
authored
[Rule Tuning] AWS Access Token Used from Multiple Addresses (#5412)
* [Rule Tuning] AWS Access Token Used from Multiple Addresses This rule is extremely loud in telemetry ~2612 alerts in last 24 hours. There have also been a couple community requests for changes. - reduced the scope of the alerts to only surface the "high" fidelity_score cases for `"multiple_ip_network_city"` or `"multiple_ip_network_city_user_agent"` criteria. This reduced telemetry by ~90% - excluded 2 more benign service providers `support` which reduced volume by another 6%. - added the `data_stream.namespace` field as requested. - kept the rest of the rule logic visible so that if customers would like to broaden the scope of this rule again, they can duplicate the rules and revert back to the broader condition `Esql.activity_type != "normal_activity"`. This has been included as a comment in the rule query. I will keep an eye on this rule in telemetry to determine it's value moving forward. * nit IG format changes
1 parent 72a2b44 commit 3bfbafe

File tree

1 file changed

+20
-10
lines changed

1 file changed

+20
-10
lines changed

rules/integrations/aws/initial_access_iam_session_token_used_from_multiple_addresses.toml

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
creation_date = "2025/04/11"
33
integration = ["aws"]
44
maturity = "production"
5-
updated_date = "2025/09/02"
5+
updated_date = "2025/12/04"
66

77
[rule]
88
author = ["Elastic"]
@@ -35,7 +35,7 @@ note = """## Triage and Analysis
3535
3636
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.
3737
38-
#### Possible Investigation Steps
38+
#### Possible investigation steps
3939
4040
- **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.
4141
- **Correlate Additional Detection Context**: Examine `activity_type` and `fidelity_score` to determine additional cities, networks or user agents associated with the token usage.
@@ -44,18 +44,18 @@ Access tokens are bound to a single user. Usage from multiple IP addresses may i
4444
- **Review Workload Context**: Confirm whether the user was expected to be active across multiple cities, networks or user agent environments.
4545
- **Trace Adversary Movement**: Pivot to related actions (e.g., `s3:ListBuckets`, `iam:ListUsers`, `sts:GetCallerIdentity`) to track further enumeration.
4646
47-
### False Positive Analysis
47+
### False positive analysis
4848
4949
- Automation frameworks that rotate through multiple IPs or cloud functions with dynamic egress IPs may cause this alert to fire.
5050
- Confirm geolocation and workload context before escalating.
5151
52-
### Response and Remediation
52+
### Response and remediation
5353
5454
- **Revoke the Token**: Disable or rotate the IAM credentials and invalidate the temporary session token.
5555
- **Audit the Environment**: Look for signs of lateral movement or data access during the token's validity.
5656
- **Strengthen Controls**: Require MFA for high-privilege actions, restrict access via policy conditions (e.g., IP range or device).
5757
58-
### References
58+
### Additional information
5959
6060
- [IAM Long-Term Credentials](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html)
6161
- [STS Temporary Credentials](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp.html)
@@ -99,7 +99,8 @@ from logs-aws.cloudtrail* metadata _id, _version, _index
9999
"health.amazonaws.com", "monitoring.amazonaws.com", "notifications.amazonaws.com",
100100
"ce.amazonaws.com", "cost-optimization-hub.amazonaws.com",
101101
"servicecatalog-appregistry.amazonaws.com", "securityhub.amazonaws.com",
102-
"account.amazonaws.com", "budgets.amazonaws.com", "freetier.amazonaws.com"
102+
"account.amazonaws.com", "budgets.amazonaws.com", "freetier.amazonaws.com", "support.amazonaws.com",
103+
"support-console.amazonaws.com"
103104
)
104105
105106
| eval
@@ -114,7 +115,8 @@ from logs-aws.cloudtrail* metadata _id, _version, _index
114115
Esql.source_geo_city_name = source.geo.city_name,
115116
Esql.source_network_org_name = `source.as.organization.name`,
116117
Esql.source_ip_network_pair = concat(Esql.source_ip_string, "-", `source.as.organization.name`),
117-
Esql.event_timestamp = @timestamp
118+
Esql.event_timestamp = @timestamp,
119+
Esql.data_stream_namespace = data_stream.namespace
118120
119121
| stats
120122
Esql.event_action_values = values(event.action),
@@ -132,6 +134,7 @@ from logs-aws.cloudtrail* metadata _id, _version, _index
132134
Esql.user_agent_original_count_distinct = count_distinct(Esql.user_agent_original),
133135
Esql.source_geo_city_name_count_distinct = count_distinct(Esql.source_geo_city_name),
134136
Esql.source_network_org_name_count_distinct = count_distinct(Esql.source_network_org_name),
137+
Esql.data_stream_namespace_values = values(Esql.data_stream_namespace),
135138
Esql.timestamp_first_seen = min(Esql.event_timestamp),
136139
Esql.timestamp_last_seen = max(Esql.event_timestamp),
137140
Esql.event_count = count()
@@ -175,9 +178,15 @@ from logs-aws.cloudtrail* metadata _id, _version, _index
175178
Esql.source_ip_count_distinct,
176179
Esql.user_agent_original_count_distinct,
177180
Esql.source_geo_city_name_count_distinct,
178-
Esql.source_network_org_name_count_distinct
181+
Esql.source_network_org_name_count_distinct,
182+
Esql.data_stream_namespace_values
183+
184+
| where Esql.activity_fidelity_score == "high"
185+
186+
// this rule only alerts for "high" fidelity cases, to broaden the rule scope to include all activity
187+
// change the final condition to
188+
// | where Esql.activity_type != "normal_activity"
179189
180-
| where Esql.activity_type != "normal_activity"
181190
'''
182191

183192
[rule.investigation_fields]
@@ -201,7 +210,8 @@ field_names = [
201210
"Esql.source_ip_count_distinct",
202211
"Esql.user_agent_original_count_distinct",
203212
"Esql.source_geo_city_name_count_distinct",
204-
"Esql.source_network_org_name_count_distinct"
213+
"Esql.source_network_org_name_count_distinct",
214+
"Esql.data_stream_namespace_values"
205215
]
206216

207217

0 commit comments

Comments
 (0)