AWS Discovery API Calls via CLI from a Single Resource
Detects when a single AWS resource is running multiple read-only, discovery API calls in a 10-second window. This behavior could indicate an actor attempting to discover the AWS infrastructure using compromised credentials or a compromised instance. Adversaries may use this information to identify potential targets for further exploitation or to gain a better understanding of the target's infrastructure.
Elastic rule (View on GitHub)
1[metadata]
2creation_date = "2024/11/04"
3integration = ["aws"]
4maturity = "production"
5min_stack_comments = "Changing min stack to 9.3.0, the latest minimum supported version for 9.X releases."
6min_stack_version = "9.3.0"
7updated_date = "2026/09/18"
8
9[rule]
10author = ["Elastic"]
11description = """
12Detects when a single AWS resource is running multiple read-only, discovery API calls in a 10-second window. This
13behavior could indicate an actor attempting to discover the AWS infrastructure using compromised credentials or a
14compromised instance. Adversaries may use this information to identify potential targets for further exploitation or to
15gain a better understanding of the target's infrastructure.
16"""
17false_positives = [
18 """
19 Administrators or automated systems may legitimately perform multiple `Describe`, `List`, `Get` and `Generate` API
20 calls in a short time frame. Verify the user identity and the purpose of the API calls to determine if the behavior
21 is expected.
22 """,
23]
24from = "now-6m"
25language = "esql"
26license = "Elastic License v2"
27name = "AWS Discovery API Calls via CLI from a Single Resource"
28note = """## Triage and analysis
29
30### Investigating AWS Discovery API Calls via CLI from a Single Resource
31
32This rule detects when a single AWS identity executes more than five unique discovery-related API calls (`Describe*`, `List*`, `Get*`, or `Generate*`) within a 10-second window using the AWS CLI.
33High volumes of diverse “read-only” API calls in such a short period can indicate scripted reconnaissance, often an early phase of compromise after credential exposure or access to a compromised EC2 instance.
34
35### Possible investigation steps
36
37**Identify the actor and session context**
38- **Actor ARN (`aws.cloudtrail.user_identity.arn`)**: Determine which IAM user, role, or service principal performed the actions.
39 - Check whether this identity normally performs enumeration activity or belongs to automation infrastructure.
40- **Identity type (`Esql.aws_cloudtrail_user_identity_arn_type`)**: Validate if the caller is a human IAM user, assumed role, or federated identity. Unusual types (e.g., temporary credentials from an unfamiliar role) may indicate lateral movement.
41- **Access key (`Esql.aws_cloudtrail_user_identity_access_key_id_values`)** – Identify which specific access key or temporary credential was used.
42 - If multiple suspicious keys are found, use AWS IAM console or `aws iam list-access-keys` to determine when they were last used or rotated.
43- **Account (`Esql.cloud_account_id_values`)** – Confirm which AWS account was affected and whether it matches the intended operational context (e.g., production vs. sandbox).
44
45**Assess the API call pattern and intent**
46- **Distinct action count (`Esql.event_action_count_distinct`)**: Note how many unique API calls occurred within each 10-second window. Counts far above normal operational baselines may indicate scripted reconnaissance.
47- **API actions (`Esql.event_action_values`)**: Review which discovery APIs were invoked.
48 - Focus on services such as EC2 (`DescribeInstances`), IAM (`ListRoles`, `ListAccessKeys`), S3 (`ListBuckets`), and KMS (`ListKeys`), which adversaries frequently query to map assets.
49- **Service providers (`Esql.event_provider_values`)**: Identify which AWS services were targeted.
50 - Multi-service enumeration (IAM + EC2 + S3) suggests broad discovery rather than a specific diagnostic task.
51- **Time window (`Esql.time_window_date_trunc`)**: Verify whether activity occurred during normal maintenance windows or outside expected hours.
52
53**Analyze the source and origin**
54- **Source IP (`Esql.source_ip_values`)**: Check the originating IPs to determine whether the calls came from a known internal host, an EC2 instance, or an unfamiliar external network.
55 - Compare with known corporate CIDR ranges, VPC flow logs, or guardrail baselines.
56- **Source organization (`Esql.source_as_organization_name_values`)**: Review the associated ASN or organization.
57 - If the ASN belongs to a commercial ISP or VPN service, investigate possible credential compromise or remote attacker usage.
58
59**Correlate with additional events**
60- Search CloudTrail for the same `aws.cloudtrail.user_identity.arn` or `aws_cloudtrail_user_identity_access_key_id_values` within ±30 minutes.
61 - Look for follow-on actions such as `GetCallerIdentity`, `AssumeRole`, `CreateAccessKey`, or data access (`GetObject`, `CopySnapshot`).
62 - Correlate this enumeration with authentication anomalies or privilege-related findings.
63- Cross-reference `Esql.cloud_account_id_values` with other alerts for lateral or privilege escalation patterns.
64
65### False positive analysis
66
67Legitimate, high-frequency API activity may originate from:
68- **Inventory or compliance automation**: Scripts or tools such as AWS Config, Cloud Custodian, or custom CMDB collection performing periodic Describe/List calls.
69- **Operational monitoring systems**: DevOps pipelines, Terraform, or deployment verifiers enumerating resources.
70- **Security tooling**: Security scanners performing asset discovery across services.
71
72Validate by confirming:
73- Whether the `aws.cloudtrail.user_identity.arn` corresponds to a documented automation or monitoring identity.
74- That the observed `Esql.event_action_values` match known inventory or cost-reporting workflows.
75- Timing alignment with approved maintenance schedules.
76
77### Response and remediation
78
79If the activity is unexpected or originates from unrecognized credentials, follow AWS’s incident-handling guidance:
80
81**Contain**
82- Temporarily disable or rotate the access key (`Esql.aws_cloudtrail_user_identity_access_key_id_values`) using IAM.
83- Restrict outbound connectivity for the instance or resource from which the API calls originated.
84
85**Investigate**
86- Retrieve full CloudTrail logs for the actor and `Esql.time_window_date_trunc` interval.
87- Identify any subsequent write or privilege-modification actions.
88- Review associated IAM policies for excessive permissions.
89
90**Recover and Harden**
91- Rotate credentials, enforce MFA on human users, and tighten IAM role trust policies.
92- Implement AWS Config rules or SCPs to monitor and restrict large-scale enumeration.
93
94**Post-Incident Actions**
95- Document the finding and response in your organization’s IR management system.
96- Update detection logic or allow-lists for known benign automation.
97- Validate recovery by confirming no new suspicious discovery bursts occur.
98
99### Additional information
100
101- **AWS Documentation**
102 - [CloudTrail Event Reference](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-event-reference.html)
103 - [AWS Security Incident Response Guide](https://docs.aws.amazon.com/whitepapers/latest/aws-security-incident-response-guide/aws-security-incident-response-guide.pdf)
104- **AWS Playbook Resources**
105 - [AWS Incident Response Playbooks](https://github.com/aws-samples/aws-incident-response-playbooks/tree/c151b0dc091755fffd4d662a8f29e2f6794da52c/playbooks)
106 - [AWS Customer Playbook Framework](https://github.com/aws-samples/aws-customer-playbook-framework)
107
108"""
109references = [
110 "https://stratus-red-team.cloud/attack-techniques/AWS/aws.discovery.ec2-enumerate-from-instance/",
111 "https://kudelskisecurity.com/research/investigating-two-variants-of-the-trivy-supply-chain-compromise",
112]
113risk_score = 21
114rule_id = "74f45152-9aee-11ef-b0a5-f661ea17fbcd"
115severity = "low"
116tags = [
117 "Domain: Cloud",
118 "Data Source: AWS",
119 "Data Source: AWS EC2",
120 "Data Source: AWS IAM",
121 "Data Source: AWS S3",
122 "Data Source: AWS CloudTrail",
123 "Data Source: AWS RDS",
124 "Data Source: AWS Lambda",
125 "Data Source: AWS STS",
126 "Data Source: AWS KMS",
127 "Data Source: AWS SES",
128 "Data Source: AWS Cloudfront",
129 "Data Source: AWS DynamoDB",
130 "Data Source: AWS Elastic Load Balancing",
131 "Data Source: AWS Organizations",
132 "Use Case: Threat Detection",
133 "Tactic: Discovery",
134 "Resources: Investigation Guide",
135 "Noise: Medium",
136 "Performance: Normal",
137 "Rule Type: ES|QL",
138 "Platform: AWS",
139 "Service: AWS IAM",
140 "Service: AWS S3",
141 "Service: AWS EC2",
142 "Service: AWS Lambda",
143 "Service: AWS RDS",
144 "Service: AWS KMS",
145 "Service: AWS STS",
146 "Service: AWS SES",
147 "Service: AWS DynamoDB",
148]
149timestamp_override = "event.ingested"
150type = "esql"
151
152query = '''
153from logs-aws.cloudtrail-* metadata _id, _version, _index
154// create time window buckets of 10 seconds
155| eval Esql.time_window_date_trunc = date_trunc(10 seconds, @timestamp)
156
157| where
158 data_stream.dataset == "aws.cloudtrail"
159
160 // exclude service account and console behavior
161 and source.ip IS NOT NULL
162 and aws.cloudtrail.session_credential_from_console IS NULL
163 and event.provider in (
164 "iam.amazonaws.com",
165 "ec2.amazonaws.com",
166 "s3.amazonaws.com",
167 "rds.amazonaws.com",
168 "lambda.amazonaws.com",
169 "dynamodb.amazonaws.com",
170 "kms.amazonaws.com",
171 "cloudfront.amazonaws.com",
172 "elasticloadbalancing.amazonaws.com",
173 "cloudtrail.amazonaws.com",
174 "sts.amazonaws.com",
175 "ses.amazonaws.com",
176 "organizations.amazonaws.com"
177 )
178 // ignore AWS service actions
179 and aws.cloudtrail.user_identity.type != "AWSService"
180 // filter for aws-cli specifically
181 and user_agent.name == "aws-cli"
182 // exclude DescribeCapacityReservations events related to AWS Config
183 and event.action != "DescribeCapacityReservations"
184 and user.name != "AWSServiceRoleForConfig"
185
186// filter for Describe, Get, List, and Generate API calls
187| where true in (
188 starts_with(event.action, "Describe"),
189 starts_with(event.action, "Get"),
190 starts_with(event.action, "List"),
191 starts_with(event.action, "Generate")
192)
193
194// keep relevant fields (preserving ECS fields and computed time window)
195| keep
196 @timestamp,
197 Esql.time_window_date_trunc,
198 event.action,
199 aws.cloudtrail.user_identity.arn,
200 aws.cloudtrail.user_identity.type,
201 aws.cloudtrail.user_identity.access_key_id,
202 source.ip,
203 cloud.account.id,
204 event.provider,
205 user_agent.name,
206 source.as.organization.name,
207 cloud.region,
208 data_stream.namespace
209
210// count the number of unique API calls per time window and actor
211| stats
212 Esql.event_action_count_distinct = count_distinct(event.action),
213 Esql.event_action_values = VALUES(event.action),
214 Esql.event_timestamp_values = VALUES(@timestamp),
215 Esql.aws_cloudtrail_user_identity_type_values = VALUES(aws.cloudtrail.user_identity.type),
216 Esql.aws_cloudtrail_user_identity_access_key_id_values = VALUES(aws.cloudtrail.user_identity.access_key_id),
217 Esql.source_ip_values = VALUES(source.ip),
218 Esql.cloud_account_id_values = VALUES(cloud.account.id),
219 Esql.event_provider_values = VALUES(event.provider),
220 Esql.user_agent_name_values = VALUES(user_agent.name),
221 Esql.source_as_organization_name_values = VALUES(source.as.organization.name),
222 Esql.cloud_region_values = VALUES(cloud.region),
223 Esql.data_stream_namespace_values = VALUES(data_stream.namespace)
224 by Esql.time_window_date_trunc, aws.cloudtrail.user_identity.arn
225
226// filter for more than 5 unique API calls per 10s window
227| where Esql.event_action_count_distinct > 5
228
229| keep
230 aws.cloudtrail.user_identity.arn,
231 Esql.time_window_date_trunc,
232 Esql.event_action_count_distinct,
233 Esql.event_action_values,
234 Esql.event_timestamp_values,
235 Esql.aws_cloudtrail_user_identity_type_values,
236 Esql.aws_cloudtrail_user_identity_access_key_id_values,
237 Esql.source_ip_values,
238 Esql.cloud_account_id_values,
239 Esql.event_provider_values,
240 Esql.user_agent_name_values,
241 Esql.source_as_organization_name_values,
242 Esql.cloud_region_values,
243 Esql.data_stream_namespace_values
244'''
245
246
247[[rule.threat]]
248framework = "MITRE ATT&CK"
249[[rule.threat.technique]]
250id = "T1087"
251name = "Account Discovery"
252reference = "https://attack.mitre.org/techniques/T1087/"
253[[rule.threat.technique.subtechnique]]
254id = "T1087.004"
255name = "Cloud Account"
256reference = "https://attack.mitre.org/techniques/T1087/004/"
257
258
259[[rule.threat.technique]]
260id = "T1526"
261name = "Cloud Service Discovery"
262reference = "https://attack.mitre.org/techniques/T1526/"
263
264[[rule.threat.technique]]
265id = "T1580"
266name = "Cloud Infrastructure Discovery"
267reference = "https://attack.mitre.org/techniques/T1580/"
268
269
270[rule.threat.tactic]
271id = "TA0007"
272name = "Discovery"
273reference = "https://attack.mitre.org/tactics/TA0007/"
274
275[rule.investigation_fields]
276field_names = [
277 "Esql.event_action_count_distinct",
278 "Esql.time_window_date_trunc",
279 "aws.cloudtrail.user_identity.arn",
280 "Esql.aws_cloudtrail_user_identity_type_values",
281 "Esql.aws_cloudtrail_user_identity_access_key_id_values",
282 "Esql.source_ip_values",
283 "Esql.source_as_organization_name_values",
284 "Esql.event_provider_values",
285 "Esql.event_action_values",
286 "Esql.event_timestamp_values",
287 "Esql.cloud_account_id_values",
288 "Esql.cloud_region_values",
289 "Esql.data_stream_namespace_values",
290]
Triage and analysis
Investigating AWS Discovery API Calls via CLI from a Single Resource
This rule detects when a single AWS identity executes more than five unique discovery-related API calls (Describe*, List*, Get*, or Generate*) within a 10-second window using the AWS CLI.
High volumes of diverse “read-only” API calls in such a short period can indicate scripted reconnaissance, often an early phase of compromise after credential exposure or access to a compromised EC2 instance.
Possible investigation steps
Identify the actor and session context
- Actor ARN (
aws.cloudtrail.user_identity.arn): Determine which IAM user, role, or service principal performed the actions.- Check whether this identity normally performs enumeration activity or belongs to automation infrastructure.
- Identity type (
Esql.aws_cloudtrail_user_identity_arn_type): Validate if the caller is a human IAM user, assumed role, or federated identity. Unusual types (e.g., temporary credentials from an unfamiliar role) may indicate lateral movement. - Access key (
Esql.aws_cloudtrail_user_identity_access_key_id_values) – Identify which specific access key or temporary credential was used.- If multiple suspicious keys are found, use AWS IAM console or
aws iam list-access-keysto determine when they were last used or rotated.
- If multiple suspicious keys are found, use AWS IAM console or
- Account (
Esql.cloud_account_id_values) – Confirm which AWS account was affected and whether it matches the intended operational context (e.g., production vs. sandbox).
Assess the API call pattern and intent
- Distinct action count (
Esql.event_action_count_distinct): Note how many unique API calls occurred within each 10-second window. Counts far above normal operational baselines may indicate scripted reconnaissance. - API actions (
Esql.event_action_values): Review which discovery APIs were invoked.- Focus on services such as EC2 (
DescribeInstances), IAM (ListRoles,ListAccessKeys), S3 (ListBuckets), and KMS (ListKeys), which adversaries frequently query to map assets.
- Focus on services such as EC2 (
- Service providers (
Esql.event_provider_values): Identify which AWS services were targeted.- Multi-service enumeration (IAM + EC2 + S3) suggests broad discovery rather than a specific diagnostic task.
- Time window (
Esql.time_window_date_trunc): Verify whether activity occurred during normal maintenance windows or outside expected hours.
Analyze the source and origin
- Source IP (
Esql.source_ip_values): Check the originating IPs to determine whether the calls came from a known internal host, an EC2 instance, or an unfamiliar external network.- Compare with known corporate CIDR ranges, VPC flow logs, or guardrail baselines.
- Source organization (
Esql.source_as_organization_name_values): Review the associated ASN or organization.- If the ASN belongs to a commercial ISP or VPN service, investigate possible credential compromise or remote attacker usage.
Correlate with additional events
- Search CloudTrail for the same
aws.cloudtrail.user_identity.arnoraws_cloudtrail_user_identity_access_key_id_valueswithin ±30 minutes.- Look for follow-on actions such as
GetCallerIdentity,AssumeRole,CreateAccessKey, or data access (GetObject,CopySnapshot). - Correlate this enumeration with authentication anomalies or privilege-related findings.
- Look for follow-on actions such as
- Cross-reference
Esql.cloud_account_id_valueswith other alerts for lateral or privilege escalation patterns.
False positive analysis
Legitimate, high-frequency API activity may originate from:
- Inventory or compliance automation: Scripts or tools such as AWS Config, Cloud Custodian, or custom CMDB collection performing periodic Describe/List calls.
- Operational monitoring systems: DevOps pipelines, Terraform, or deployment verifiers enumerating resources.
- Security tooling: Security scanners performing asset discovery across services.
Validate by confirming:
- Whether the
aws.cloudtrail.user_identity.arncorresponds to a documented automation or monitoring identity. - That the observed
Esql.event_action_valuesmatch known inventory or cost-reporting workflows. - Timing alignment with approved maintenance schedules.
Response and remediation
If the activity is unexpected or originates from unrecognized credentials, follow AWS’s incident-handling guidance:
Contain
- Temporarily disable or rotate the access key (
Esql.aws_cloudtrail_user_identity_access_key_id_values) using IAM. - Restrict outbound connectivity for the instance or resource from which the API calls originated.
Investigate
- Retrieve full CloudTrail logs for the actor and
Esql.time_window_date_truncinterval. - Identify any subsequent write or privilege-modification actions.
- Review associated IAM policies for excessive permissions.
Recover and Harden
- Rotate credentials, enforce MFA on human users, and tighten IAM role trust policies.
- Implement AWS Config rules or SCPs to monitor and restrict large-scale enumeration.
Post-Incident Actions
- Document the finding and response in your organization’s IR management system.
- Update detection logic or allow-lists for known benign automation.
- Validate recovery by confirming no new suspicious discovery bursts occur.
Additional information
- AWS Documentation
- AWS Playbook Resources
References
Related rules
- AWS Lateral Movement from Kubernetes SA via AssumeRoleWithWebIdentity
- AWS EC2 Role GetCallerIdentity from New Source AS Organization
- AWS IAM API Calls via Temporary Session Tokens
- AWS IAM Sensitive Operations via Lambda Execution Role
- AWS S3 Object Encryption Using External KMS Key