LoFP LoFP / legitimate use of the `describeinstances` api call by an aws resource that requires information about instances in multiple regions.

Techniques

Sample rules

AWS EC2 Multi-Region DescribeInstances API Calls

Description

Identifies when a single AWS resource is making DescribeInstances API calls in more than 10 regions within a 30-second window. This could indicate a potential threat actor attempting to discover the AWS infrastructure across multiple regions 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.

Detection logic

from logs-aws.cloudtrail-* metadata _id, _version, _index

// filter for DescribeInstances API calls
| where event.dataset == "aws.cloudtrail"
  and event.provider == "ec2.amazonaws.com"
  and event.action == "DescribeInstances"

// truncate the timestamp to a 30-second window
| eval Esql.time_window_date_trunc = date_trunc(30 seconds, @timestamp)

// keep only the relevant raw fields
| keep 
    Esql.time_window_date_trunc, 
    aws.cloudtrail.user_identity.arn, 
    cloud.region, 
    cloud.account.id,
    aws.cloudtrail.user_identity.access_key_id,
    aws.cloudtrail.user_identity.type,
    user_agent.original,
    source.as.organization.name,
    source.ip,
    @timestamp,
    data_stream.namespace    

// count the number of unique regions and total API calls within the 30-second window
| stats
    Esql.cloud_region_count_distinct = count_distinct(cloud.region),
    Esql.event_count = count(*),
    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.user_agent_original_values = VALUES(user_agent.original),
    Esql.source_as_organization_name_values = VALUES(source.as.organization.name),
    Esql.cloud_account_id_values = VALUES(cloud.account.id),
    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 resources making DescribeInstances API calls in more than 10 regions within the 30-second window
| where Esql.cloud_region_count_distinct >= 10 and Esql.event_count >= 10