Techniques
Sample rules
AWS Service Quotas Multi-Region GetServiceQuota Requests
- source: elastic
- technicques:
- T1580
Description
Identifies when a single AWS principal makes GetServiceQuota API calls for the EC2 service quota L-1216C47A, across more than 10 AWS regions within a 30-second window. This quota represents the vCPU limit for on-demand EC2 instances. Adversaries commonly enumerate this quota across regions to assess capacity for large-scale instance deployment, including cryptocurrency mining, malware hosting, or command-and-control infrastructure. This behavior may indicate cloud infrastructure discovery using compromised credentials or a compromised workload.
Detection logic
from logs-aws.cloudtrail-* METADATA _id, _version, _index
// filter for GetServiceQuota API calls
| where
event.dataset == "aws.cloudtrail"
and event.provider == "servicequotas.amazonaws.com"
and event.action == "GetServiceQuota"
// truncate the timestamp to a 30-second window
| eval Esql.time_window_date_trunc = date_trunc(30 seconds, @timestamp)
// dissect request parameters to extract service and quota code
| dissect aws.cloudtrail.request_parameters "{%{?Esql.aws_cloudtrail_request_parameters_service_code_key}=%{Esql.aws_cloudtrail_request_parameters_service_code}, %{?quota_code_key}=%{Esql.aws_cloudtrail_request_parameters_quota_code}}"
// filter for EC2 service quota L-1216C47A (vCPU on-demand instances)
| where Esql.aws_cloudtrail_request_parameters_service_code == "ec2" and Esql.aws_cloudtrail_request_parameters_quota_code == "L-1216C47A"
// keep only the relevant fields
| keep
Esql.time_window_date_trunc,
aws.cloudtrail.user_identity.arn,
cloud.region,
Esql.aws_cloudtrail_request_parameters_service_code,
Esql.aws_cloudtrail_request_parameters_quota_code,
aws.cloudtrail.request_parameters,
@timestamp,
aws.cloudtrail.user_identity.type,
aws.cloudtrail.user_identity.access_key_id,
source.ip,
cloud.account.id,
user_agent.original,
source.as.organization.name,
data_stream.namespace
// count the number of unique regions and total API calls within the time window
| stats
Esql.cloud_region_count_distinct = count_distinct(cloud.region),
Esql.event_count = count(*),
Esql.aws_cloudtrail_request_parameters_values = VALUES(aws.cloudtrail.request_parameters),
Esql.event_timestamp_values = VALUES(@timestamp),
Esql.aws_cloudtrail_user_identity_type_values = VALUES(aws.cloudtrail.user_identity.type),
Esql.aws_cloudtrail_user_identity_access_key_id_values = VALUES(aws.cloudtrail.user_identity.access_key_id),
Esql.source_ip_values = VALUES(source.ip),
Esql.cloud_account_id_values = VALUES(cloud.account.id),
Esql.user_agent_original_values = VALUES(user_agent.original),
Esql.source_as_organization_name_values = VALUES(source.as.organization.name),
Esql.cloud_region_values = VALUES(cloud.region),
Esql.data_stream_namespace_values = VALUES(data_stream.namespace)
by Esql.time_window_date_trunc, aws.cloudtrail.user_identity.arn
// filter for API calls in more than 10 regions within the 30-second window
| where
Esql.cloud_region_count_distinct >= 10
and Esql.event_count >= 10