AWS EC2 Bulk User Data Enumeration
Description
Identifies when the same AWS principal, from the same source IP, successfully calls EC2 "DescribeInstanceAttribute" for the "userData" attribute against more than 20 distinct instances within a 10-minute lookback. Instance user data often contains bootstrap scripts and hardcoded credentials, so retrieving it across many instances in a short window can indicate reconnaissance or credential harvesting. Known CSPM roles, AWS service invocations, and Terraform calls from major cloud and carrier networks are excluded.
Query · esql
from logs-aws.cloudtrail-*
| where KQL("""event.provider: "ec2.amazonaws.com" and event.action: "DescribeInstanceAttribute" and event.outcome: "success" and aws.cloudtrail.flattened.request_parameters.attribute: "userData" and source.ip: * and source.as.organization.name: * and not user.name: (*CrowdStrikeCSPMReader* or *OrcaSecurityRole* or *AikidoSecurityRole* or *streamsec-*) and not aws.cloudtrail.user_identity.invoked_by: ("AWS Internal" or "cloudformation.amazonaws.com" or "aidevops.amazonaws.com" or "elasticmapreduce.amazonaws.com" or "aiops.amazonaws.com")""")
and not (
user_agent.original like "*Terraform*"
and source.as.organization.name in (
"Amazon.com, Inc.",
"Google LLC",
"Microsoft Corporation",
"Verizon Business",
"AT&T Enterprises, LLC"
)
)
| grok aws.cloudtrail.request_parameters """instanceId=(?<Esql.instance_id>[^,}\]]+)"""
| where Esql.instance_id is not null
| stats
Esql.count_distinct_instance_id = count_distinct(Esql.instance_id),
Esql.aws_request_parameters_values = values(aws.cloudtrail.request_parameters),
Esql.user_agent_values = values(user_agent.original)
by
data_stream.namespace,
aws.cloudtrail.user_identity.arn,
aws.cloudtrail.user_identity.type,
source.as.organization.name,
source.ip,
source.`as`.number
| where Esql.count_distinct_instance_id > 20
| keep
Esql.count_distinct_instance_id,
data_stream.namespace,
aws.cloudtrail.user_identity.arn,
aws.cloudtrail.user_identity.type,
source.ip,
source.`as`.number,
source.as.organization.name,
Esql.aws_request_parameters_values,
Esql.user_agent_values
Investigation fields
Pivot points the source recommends for triage.
Esql.count_distinct_instance_idaws.cloudtrail.user_identity.arnaws.cloudtrail.user_identity.typesource.ipsource.`as`.numbersource.as.organization.nameEsql.aws_request_parameters_valuesEsql.user_agent_valuesdata_stream.namespace
Implementation guide
The AWS integration must collect CloudTrail management events into logs-aws.cloudtrail-*.
DescribeInstanceAttribute is a management event logged by default. source.ip and
source.as.organization.name must be populated, because events missing either field are excluded.
Known false positives
- Inventory jobs, configuration management, and security scanners that are not in the exclusion list may read `userData` across a large fleet. Confirm the principal ARN, source IP, ASN, and user agent against approved automation before treating the activity as malicious.
- Terraform running from an ASN other than Amazon, Google, Microsoft, Verizon, or AT&T is still in scope. A large apply or refresh can exceed 20 instances.
Analyst notes
Investigating AWS EC2 Bulk User Data Enumeration
EC2 userData is returned by DescribeInstanceAttribute when attribute is userData. It is frequently used for
bootstrap scripts and sometimes contains credentials or tokens. This rule alerts when one principal
(aws.cloudtrail.user_identity.arn), identity type, source IP, and source ASN reads that attribute for more than 20
distinct aws.cloudtrail.request_parameters values in the 10-minute lookback. For this API those values correspond to
distinct instance requests.
Possible investigation steps
- Review
aws.cloudtrail.user_identity.arnandaws.cloudtrail.user_identity.type. Confirm whether this identity is expected to read instance user data at fleet scale. - Review
Esql.count_distinct_instance_idandEsql.aws_request_parameters_values. Extract theinstanceIdvalues and check whether the instances belong to sensitive workloads. - Review
source.ip,source.as.organization.name, andEsql.user_agent_values. Unexpected ASNs or clients such as the AWS CLI or an SDK from an unfamiliar network are higher priority than a known automation host. - Search CloudTrail for the same principal and source IP in the surrounding hour for
ModifyInstanceAttribute,RunInstances,GetPasswordData,AssumeRole, and IAM changes. - If the instances are still available, inspect their current user data for secrets. Prefer AWS Secrets Manager or Parameter Store over credentials stored in user data.
False positive analysis
- Approved CSPM and inventory tools. This rule already excludes principal names matching CrowdStrike CSPM, Orca
Security, Aikido Security, Stream Security (
streamsec-*), andAWSReservedSSO_Poweruser. - Calls invoked by AWS Internal, CloudFormation, AI DevOps, EMR, or AIOps.
- Terraform user agents whose source ASN is Amazon, Google, Microsoft, Verizon, or AT&T.
- Add further exceptions by principal ARN or user agent when the behavior is documented and recurring.
Response and remediation
- If the activity is not authorized, revoke the role session or disable the access key and restrict the source IP.
- Rotate any credentials found in the retrieved user data and remove secrets from instance user data.
- Limit
ec2:DescribeInstanceAttributeto principals that need it.