Cloud Infrastructure Discovery
This detection identifies adversaries enumerating cloud infrastructure resources across AWS, Azure, and GCP environments. Attackers leverage cloud provider APIs and CLI tools to discover compute instances, storage buckets, databases, snapshots, and network configurations using compromised credentials. The detection monitors for high-volume or broad-scope API calls characteristic of automated enumeration tools like Pacu, bulk read operations across multiple resource types in short time windows, and enumeration patterns associated with threat actors like Scattered Spider and Storm-0501 who use cloud discovery to identify high-value targets before establishing persistence or staging data exfiltration.
let AwsDiscoveryAPIs = dynamic([
"DescribeInstances", "DescribeVolumes", "DescribeSnapshots", "DescribeImages",
"ListBuckets", "HeadBucket", "GetPublicAccessBlock", "GetBucketAcl", "GetBucketPolicy",
"DescribeDBInstances", "DescribeDBClusters", "DescribeDBSnapshots",
"DescribeSecurityGroups", "DescribeVpcs", "DescribeSubnets",
"DescribeNetworkInterfaces", "DescribeRouteTables", "DescribeInternetGateways",
"ListFunctions", "ListTables", "DescribeClusters", "GetCallerIdentity",
"ListRoles", "ListUsers", "ListBuckets", "DescribeLoadBalancers",
"DescribeAutoScalingGroups", "DescribeKeyPairs"
]);
let AzureDiscoveryOps = dynamic([
"microsoft.compute/virtualmachines/read",
"microsoft.storage/storageaccounts/read",
"microsoft.sql/servers/read",
"microsoft.network/virtualnetworks/read",
"microsoft.keyvault/vaults/read",
"microsoft.containerservice/managedclusters/read",
"microsoft.resources/subscriptions/resources/read"
]);
let lookback = 15m;
let BurstThreshold = 10;
let APISpreadThreshold = 5;
// AWS CloudTrail: detect burst enumeration
let AwsEnumeration = AWSCloudTrail
| where TimeGenerated >= ago(1h)
| where EventName in (AwsDiscoveryAPIs)
| where isnotempty(UserIdentityArn)
| summarize
DiscoveryCount = count(),
DistinctAPIs = dcount(EventName),
APIList = make_set(EventName, 50),
DistinctRegions = dcount(AWSRegion),
FirstSeen = min(TimeGenerated),
LastSeen = max(TimeGenerated),
SourceIPs = make_set(SourceIPAddress, 10)
by UserIdentityArn, UserIdentityAccountId, bin(TimeGenerated, lookback)
| where DiscoveryCount >= BurstThreshold or DistinctAPIs >= APISpreadThreshold
| extend CloudProvider = "AWS", Identity = UserIdentityArn, AccountId = UserIdentityAccountId
| project TimeGenerated, CloudProvider, Identity, AccountId, DiscoveryCount, DistinctAPIs, APIList, DistinctRegions, SourceIPs, FirstSeen, LastSeen;
// Azure Activity: detect bulk read enumeration
let AzureEnumeration = AzureActivity
| where TimeGenerated >= ago(1h)
| where tolower(OperationNameValue) in (AzureDiscoveryOps)
| where ActivityStatusValue =~ "Success"
| summarize
DiscoveryCount = count(),
DistinctOps = dcount(OperationNameValue),
OpList = make_set(OperationNameValue, 50),
DistinctResourceGroups = dcount(ResourceGroup),
FirstSeen = min(TimeGenerated),
LastSeen = max(TimeGenerated),
SourceIPs = make_set(CallerIpAddress, 10)
by Caller, SubscriptionId, bin(TimeGenerated, lookback)
| where DiscoveryCount >= BurstThreshold or DistinctOps >= APISpreadThreshold
| extend CloudProvider = "Azure", Identity = Caller, AccountId = SubscriptionId, APIList = OpList, DistinctRegions = DistinctResourceGroups
| project TimeGenerated, CloudProvider, Identity, AccountId, DiscoveryCount, DistinctAPIs = DistinctOps, APIList, DistinctRegions, SourceIPs, FirstSeen, LastSeen;
// Union and score
union AwsEnumeration, AzureEnumeration
| extend
RiskScore = case(
DistinctAPIs >= 10 and DiscoveryCount >= 50, 90,
DistinctAPIs >= 7 and DiscoveryCount >= 20, 70,
DistinctAPIs >= 5 or DiscoveryCount >= 10, 50,
30
)
| sort by RiskScore desc, DiscoveryCount desc
| project TimeGenerated, CloudProvider, Identity, AccountId, DiscoveryCount, DistinctAPIs, APIList, DistinctRegions, SourceIPs, FirstSeen, LastSeen, RiskScore Data Sources
Required Tables
False Positives
- Legitimate cloud management platforms (Terraform, Pulumi, CloudFormation) performing state refresh that enumerate all resources at plan/apply time
- Security posture management tools (Wiz, Prisma Cloud, Orca) performing scheduled asset inventory scans across the entire environment
- Cloud cost management and optimization tools (CloudHealth, Spot.io) querying instance and storage metadata for billing analysis
- CI/CD pipelines with infrastructure-as-code that execute bulk describe operations during deployment validation
- Cloud backup agents (Veeam, Cohesity) performing pre-backup infrastructure discovery to identify targets
References (10)
- https://attack.mitre.org/techniques/T1580/
- https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeInstances.html
- https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBuckets.html
- https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetPublicAccessBlock.html
- https://github.com/RhinoSecurityLabs/pacu
- https://www.mandiant.com/resources/m-trends-2020
- https://expel.com/blog/finding-evil-in-aws/
- https://www.microsoft.com/en-us/security/blog/2023/10/25/octo-tempest-crosses-boundaries-to-facilitate-extortion-encryption-and-destruction/
- https://cloud.google.com/sdk/gcloud/reference/compute/instances/list
- https://learn.microsoft.com/en-us/cli/azure/vm?view=azure-cli-latest#az-vm-list
Unlock Pro Content
Get the full detection package for T1580 including response playbook, investigation guide, and atomic red team tests.