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"
  5updated_date = "2026/01/16"
  6
  7[rule]
  8author = ["Elastic"]
  9description = """
 10Detects when a single AWS resource is running multiple read-only, discovery API calls in a 10-second window. This
 11behavior could indicate an actor attempting to discover the AWS infrastructure using compromised credentials or a
 12compromised instance. Adversaries may use this information to identify potential targets for further exploitation or to
 13gain a better understanding of the target's infrastructure.
 14"""
 15false_positives = [
 16    """
 17    Administrators or automated systems may legitimately perform multiple `Describe`, `List`, `Get` and `Generate` API calls in a short
 18    time frame. Verify the user identity and the purpose of the API calls to determine if the behavior is expected.
 19    """,
 20]
 21from = "now-6m"
 22language = "esql"
 23license = "Elastic License v2"
 24name = "AWS Discovery API Calls via CLI from a Single Resource"
 25note = """## Triage and analysis
 26
 27### Investigating AWS Discovery API Calls via CLI from a Single Resource
 28
 29This 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.  
 30High 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.  
 31
 32#### Possible Investigation Steps
 33
 34**Identify the actor and session context**
 35- **Actor ARN (`aws.cloudtrail.user_identity.arn`)**: Determine which IAM user, role, or service principal performed the actions.  
 36  - Check whether this identity normally performs enumeration activity or belongs to automation infrastructure.  
 37- **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.  
 38- **Access key (`Esql.aws_cloudtrail_user_identity_access_key_id_values`)** – Identify which specific access key or temporary credential was used.  
 39  - 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.  
 40- **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).
 41
 42**Assess the API call pattern and intent**
 43- **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.  
 44- **API actions (`Esql.event_action_values`)**: Review which discovery APIs were invoked.  
 45  - Focus on services such as EC2 (`DescribeInstances`), IAM (`ListRoles`, `ListAccessKeys`), S3 (`ListBuckets`), and KMS (`ListKeys`), which adversaries frequently query to map assets.  
 46- **Service providers (`Esql.event_provider_values`)**: Identify which AWS services were targeted.  
 47  - Multi-service enumeration (IAM + EC2 + S3) suggests broad discovery rather than a specific diagnostic task.  
 48- **Time window (`Esql.time_window_date_trunc`)**: Verify whether activity occurred during normal maintenance windows or outside expected hours.
 49
 50**Analyze the source and origin**
 51- **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.  
 52  - Compare with known corporate CIDR ranges, VPC flow logs, or guardrail baselines.  
 53- **Source organization (`Esql.source_as_organization_name_values`)**: Review the associated ASN or organization.  
 54  - If the ASN belongs to a commercial ISP or VPN service, investigate possible credential compromise or remote attacker usage.
 55
 56**Correlate with additional events**
 57- Search CloudTrail for the same `aws.cloudtrail.user_identity.arn` or `aws_cloudtrail_user_identity_access_key_id_values` within ±30 minutes.  
 58  - Look for follow-on actions such as `GetCallerIdentity`, `AssumeRole`, `CreateAccessKey`, or data access (`GetObject`, `CopySnapshot`).  
 59  - Correlate this enumeration with authentication anomalies or privilege-related findings.  
 60- Cross-reference `Esql.cloud_account_id_values` with other alerts for lateral or privilege escalation patterns.
 61
 62### False positive analysis
 63
 64Legitimate, high-frequency API activity may originate from:
 65- **Inventory or compliance automation**: Scripts or tools such as AWS Config, Cloud Custodian, or custom CMDB collection performing periodic Describe/List calls.  
 66- **Operational monitoring systems**: DevOps pipelines, Terraform, or deployment verifiers enumerating resources.  
 67- **Security tooling**: Security scanners performing asset discovery across services.
 68
 69Validate by confirming:
 70- Whether the `aws.cloudtrail.user_identity.arn` corresponds to a documented automation or monitoring identity.  
 71- That the observed `Esql.event_action_values` match known inventory or cost-reporting workflows.  
 72- Timing alignment with approved maintenance schedules.
 73
 74### Response and remediation
 75
 76If the activity is unexpected or originates from unrecognized credentials, follow AWS’s incident-handling guidance:
 77
 78**Contain**
 79- Temporarily disable or rotate the access key (`Esql.aws_cloudtrail_user_identity_access_key_id_values`) using IAM.  
 80- Restrict outbound connectivity for the instance or resource from which the API calls originated.
 81
 82**Investigate**
 83- Retrieve full CloudTrail logs for the actor and `Esql.time_window_date_trunc` interval.  
 84- Identify any subsequent write or privilege-modification actions.  
 85- Review associated IAM policies for excessive permissions.
 86
 87**Recover and Harden**
 88- Rotate credentials, enforce MFA on human users, and tighten IAM role trust policies.  
 89- Implement AWS Config rules or SCPs to monitor and restrict large-scale enumeration.
 90
 91**Post-Incident Actions**
 92- Document the finding and response in your organization’s IR management system.  
 93- Update detection logic or allow-lists for known benign automation.  
 94- Validate recovery by confirming no new suspicious discovery bursts occur.
 95
 96### Additional information
 97
 98- **AWS Documentation**
 99  - [CloudTrail Event Reference](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-event-reference.html)
100  - [AWS Security Incident Response Guide](https://docs.aws.amazon.com/whitepapers/latest/aws-security-incident-response-guide/aws-security-incident-response-guide.pdf)
101- **AWS Playbook Resources**
102  - [AWS Incident Response Playbooks](https://github.com/aws-samples/aws-incident-response-playbooks/tree/c151b0dc091755fffd4d662a8f29e2f6794da52c/playbooks)
103  - [AWS Customer Playbook Framework](https://github.com/aws-samples/aws-customer-playbook-framework)
104
105"""
106references = ["https://stratus-red-team.cloud/attack-techniques/AWS/aws.discovery.ec2-enumerate-from-instance/"]
107risk_score = 21
108rule_id = "74f45152-9aee-11ef-b0a5-f661ea17fbcd"
109severity = "low"
110tags = [
111    "Domain: Cloud",
112    "Data Source: AWS",
113    "Data Source: AWS EC2",
114    "Data Source: AWS IAM",
115    "Data Source: AWS S3",
116    "Data Source: AWS Cloudtrail",
117    "Data Source: AWS RDS",
118    "Data Source: AWS Lambda",
119    "Data Source: AWS STS",
120    "Data Source: AWS KMS",
121    "Data Source: AWS SES",
122    "Data Source: AWS Cloudfront",
123    "Data Source: AWS DynamoDB",
124    "Data Source: AWS Elastic Load Balancing",
125    "Use Case: Threat Detection",
126    "Tactic: Discovery",
127    "Resources: Investigation Guide",
128]
129timestamp_override = "event.ingested"
130type = "esql"
131
132query = '''
133from logs-aws.cloudtrail-* metadata _id, _version, _index
134// create time window buckets of 10 seconds
135| eval Esql.time_window_date_trunc = date_trunc(10 seconds, @timestamp)
136
137| where
138    event.dataset == "aws.cloudtrail"
139    // filter on CloudTrail audit logs for IAM, EC2, S3, etc.
140    and event.provider in (
141      "iam.amazonaws.com",
142      "ec2.amazonaws.com",
143      "s3.amazonaws.com",
144      "rds.amazonaws.com",
145      "lambda.amazonaws.com",
146      "dynamodb.amazonaws.com",
147      "kms.amazonaws.com",
148      "cloudfront.amazonaws.com",
149      "elasticloadbalancing.amazonaws.com", 
150      "cloudtrail.amazonaws.com",
151      "sts.amazonaws.com",
152      "ses.amazonaws.com"
153    )
154    // ignore AWS service actions
155    and aws.cloudtrail.user_identity.type != "AWSService"
156    // filter for aws-cli specifically
157    and user_agent.name == "aws-cli"
158    // exclude DescribeCapacityReservations events related to AWS Config
159    and event.action != "DescribeCapacityReservations"
160
161// filter for Describe, Get, List, and Generate API calls
162| where true in (
163    starts_with(event.action, "Describe"),
164    starts_with(event.action, "Get"),
165    starts_with(event.action, "List"),
166    starts_with(event.action, "Generate")
167)
168
169// extract owner, identity type, and actor from the ARN
170| dissect aws.cloudtrail.user_identity.arn "%{}::%{Esql_priv.aws_cloudtrail_user_identity_arn_owner}:%{Esql.aws_cloudtrail_user_identity_arn_type}/%{Esql.aws_cloudtrail_user_identity_arn_roles}"
171
172| where starts_with(Esql.aws_cloudtrail_user_identity_arn_roles, "AWSServiceRoleForConfig") != true
173
174// keep relevant fields (preserving ECS fields and computed time window)
175| keep 
176    @timestamp, 
177    Esql.time_window_date_trunc, 
178    event.action, 
179    aws.cloudtrail.user_identity.arn, 
180    aws.cloudtrail.user_identity.type, 
181    aws.cloudtrail.user_identity.access_key_id, 
182    source.ip, 
183    cloud.account.id, 
184    event.provider, 
185    user_agent.name, 
186    source.as.organization.name, 
187    cloud.region,
188    data_stream.namespace
189
190// count the number of unique API calls per time window and actor
191| stats
192    Esql.event_action_count_distinct = count_distinct(event.action),
193    Esql.event_action_values = VALUES(event.action),
194    Esql.event_timestamp_values = VALUES(@timestamp),
195    Esql.aws_cloudtrail_user_identity_type_values = VALUES(aws.cloudtrail.user_identity.type),
196    Esql.aws_cloudtrail_user_identity_access_key_id_values = VALUES(aws.cloudtrail.user_identity.access_key_id),
197    Esql.source_ip_values = VALUES(source.ip),
198    Esql.cloud_account_id_values = VALUES(cloud.account.id),
199    Esql.event_provider_values = VALUES(event.provider),
200    Esql.user_agent_name_values = VALUES(user_agent.name),
201    Esql.source_as_organization_name_values = VALUES(source.as.organization.name),
202    Esql.cloud_region_values = VALUES(cloud.region),
203    Esql.data_stream_namespace_values = VALUES(data_stream.namespace)
204  by Esql.time_window_date_trunc, aws.cloudtrail.user_identity.arn
205
206// filter for more than 5 unique API calls per 10s window
207| where Esql.event_action_count_distinct > 5
208'''
209
210
211[[rule.threat]]
212framework = "MITRE ATT&CK"
213[[rule.threat.technique]]
214id = "T1580"
215name = "Cloud Infrastructure Discovery"
216reference = "https://attack.mitre.org/techniques/T1580/"
217
218
219[rule.threat.tactic]
220id = "TA0007"
221name = "Discovery"
222reference = "https://attack.mitre.org/tactics/TA0007/"
223
224[rule.investigation_fields]
225field_names = [
226  "Esql.event_action_count_distinct", 
227  "Esql.time_window_date_trunc", 
228  "aws.cloudtrail.user_identity.arn", 
229  "Esql.aws_cloudtrail_user_identity_type_values",
230  "Esql.aws_cloudtrail_user_identity_access_key_id_values", 
231  "Esql.source_ip_values", 
232  "Esql.source_as_organization_name_values", 
233  "Esql.event_provider_values", 
234  "Esql.event_action_values", 
235  "Esql.cloud_account_id_values",
236  "Esql.cloud_region_values",
237  "Esql.data_stream_namespace_values"
238  ]

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-keys to determine when they were last used or rotated.
  • 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.
  • 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.arn or aws_cloudtrail_user_identity_access_key_id_values within ±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.
  • Cross-reference Esql.cloud_account_id_values with 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.arn corresponds to a documented automation or monitoring identity.
  • That the observed Esql.event_action_values match 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_trunc interval.
  • 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

References

Related rules

to-top