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.
What is T1580 Cloud Infrastructure Discovery?
Cloud Infrastructure Discovery (T1580) maps to the Discovery tactic — the adversary is trying to figure out your environment in MITRE ATT&CK.
This page provides production-ready detection logic for Cloud Infrastructure Discovery, covering the data sources and telemetry it touches: AWS CloudTrail (via Sentinel connector), Azure Activity Logs. The queries below are rated high severity at medium confidence, and ship for 7 SIEM platforms — KQL, SPL, Elastic, QRadar, Sumo, YARA-L, LogScale.
MITRE ATT&CK
- Tactic
- Discovery
- Technique
- T1580 Cloud Infrastructure Discovery
- Canonical reference
- https://attack.mitre.org/techniques/T1580/
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 Detects high-volume or broad-scope cloud infrastructure enumeration across AWS and Azure by correlating API call volumes and API diversity from a single identity within a 15-minute window. Fires when an identity makes 10+ discovery API calls or calls 5+ distinct discovery APIs in the window, which is characteristic of automated enumeration tools. Scores risk based on API spread and volume to prioritize true positives.
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
Sigma rule & cross-platform mapping
The detection logic for Cloud Infrastructure Discovery (T1580) above is provided in a vendor-neutral
form so you can deploy it on any SIEM. The same logic is shipped here as native
KQL (Microsoft Sentinel / Defender), SPL (Splunk), Elastic (Elastic Security (EQL)), QRadar (IBM QRadar (AQL)), Sumo (Sumo Logic CSE), YARA-L (Google Chronicle / SecOps), LogScale (CrowdStrike LogScale (CQL)) queries. In Sigma terms, this detection targets the
following logsource:
logsource:
product: azure Browse the community-maintained Sigma rules for this technique:
Platform-specific guides for T1580
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
Testing Methodology
Validate this detection against 3 adversary techniques from Atomic Red Team. Each test below lists the behaviour to exercise and the telemetry you should expect to see. Executable commands and cleanup steps are available with Pro.
- Test 1AWS Infrastructure Enumeration via CLI
Expected signal: CloudTrail management events for: GetCallerIdentity, DescribeInstances (multiple regions), ListBuckets, GetPublicAccessBlock, GetBucketAcl, DescribeDBInstances, DescribeKeyPairs, DescribeSecurityGroups — all appearing within a short time window from the same identity and source IP
- Test 2Azure Infrastructure Enumeration via Azure CLI
Expected signal: Azure Activity Log entries for operations: 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/resourcegroups/read — all from same caller within a short window
- Test 3Automated Cloud Enumeration with Pacu (AWS Exploitation Framework)
Expected signal: CloudTrail management events with UserAgent containing 'pacu' or 'Boto3' (Pacu uses Boto3 SDK). Expect 50+ API calls across ec2:DescribeInstances, ec2:DescribeVolumes, ec2:DescribeSnapshots, s3:ListBuckets, iam:ListUsers, iam:ListRoles, iam:ListPolicies, rds:DescribeDBInstances, lambda:ListFunctions within minutes from a single identity
Response Playbook
Triage
- Step 1: Identify the IAM identity — determine if it is a human user, service account, or IAM role. Check `UserIdentityArn` in AWS or `Caller` in Azure. Human users performing automated enumeration at scale are higher priority than expected service accounts.
- Step 2: Review the specific APIs called. Cross-reference `APIList` against the identity's normal job function. A developer calling `DescribeInstances` is expected; the same identity also calling `GetBucketAcl`, `DescribeDBInstances`, and `ListRoles` in one session suggests recon breadth inconsistent with their role.
- Step 3: Check the source IP addresses from `SourceIPs`. Validate against the identity's known IP history using `AWSCloudTrail | where UserIdentityArn == "<identity>" | summarize by SourceIPAddress` over the past 30 days. New or unexpected geographic locations or cloud IP ranges (not the org's egress IPs) are significant.
- Step 4: Determine if the activity was performed via CLI, SDK, or console. AWS CloudTrail `UserAgent` field reveals if Pacu, Boto3, AWS CLI, or the web console was used. Pacu's user agent contains 'Pacu'. Boto3 default user agents indicate scripted access.
- Step 5: Calculate the time window of enumeration. Very short burst windows (all calls within 2-5 minutes) indicate automated tooling. Manual console activity is typically spread over 15+ minutes.
- Step 6: Check if the identity has recently authenticated from a new location or device by querying `AADSignInLogs` (Azure) or CloudTrail `ConsoleLogin` events (AWS) for the past 24 hours.
- Step 7: Assess whether any discovery was followed by mutating API calls (PutBucketPolicy, ModifyInstanceAttribute, CreateUser) which would indicate the recon is being acted upon.
- Step 8: Check for lateral movement indicators — if the same source IP or identity appears in other cloud accounts within the organization (cross-account assume role activity in CloudTrail `AssumeRole` events).
Containment
- If identity is confirmed compromised: immediately rotate or revoke the access key (AWS: `aws iam delete-access-key --access-key-id <key>` / Azure: revoke app registration secret or disable user in Entra ID) and force sign-out of all active sessions.
- Apply a deny-all IAM policy to the compromised identity as a temporary measure while preserving audit trails: `aws iam put-user-policy --user-name <user> --policy-name EmergencyDeny --policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Deny","Action":"*","Resource":"*"}]}'`
- If the source IP is non-corporate and the activity is confirmed malicious, add the IP to network-level deny lists via WAF, Security Group rules, or Azure NSG to block further access from that endpoint.
- Enable CloudTrail or Azure Diagnostic Logs data event logging on S3/storage buckets identified during the enumeration period if not already enabled, to capture any subsequent access attempts.
- For AWS: check if any new IAM users, roles, or access keys were created after the enumeration window using `aws iam list-users` with date filters. Disable any suspicious accounts created post-enumeration.
- Notify the cloud account owner and relevant stakeholders. For multi-account environments, alert the cloud security team to check for lateral movement to connected accounts via AWS Organizations or Azure Management Groups.
Evidence Collection
- Export full CloudTrail event history for the compromised identity for at least 72 hours prior to and after the detected activity: `aws cloudtrail lookup-events --lookup-attributes AttributeKey=Username,AttributeValue=<user> --start-time <72h-ago> --end-time <now>` and save as JSON.
- Capture the complete list of resources that were enumerated by extracting `RequestParameters` and `ResponseElements` from the raw CloudTrail events for the affected time window — this establishes exactly what the adversary learned.
- Collect VPC Flow Logs for the source IP addresses during the enumeration window to identify any data transfer or lateral movement attempts via network traffic.
- Export IAM credential report for the affected account: `aws iam generate-credential-report && aws iam get-credential-report` — review for access key age, last used times, and MFA status.
- For Azure: export Azure Activity Log entries for the affected identity using `az monitor activity-log list --caller <identity> --start-time <72h-ago>` and preserve the raw JSON.
- Capture AWS Config or Azure Resource Graph snapshots showing the state of discovered resources at the time of the incident for evidence of what was exposed and potentially targeted.
- Preserve CloudTrail management events in the S3 bucket for the affected time period before any log rotation policies apply. Request a log archive from the CloudTrail S3 bucket for the incident window.
Escalation Criteria
- ! Escalate immediately if the enumeration is followed by any mutating API calls (bucket policy changes, security group modifications, new IAM user/key creation) within the same session — indicates active exploitation, not just recon.
- ! Escalate if the identity that performed enumeration is a high-privilege role (Administrator, SecurityAudit, PowerUser) or a service account used by production systems, as the blast radius of compromise is significantly higher.
- ! Escalate if cross-account enumeration is detected (CloudTrail AssumeRole events showing the compromised identity pivoting to other accounts) — indicates the adversary is mapping the full organizational cloud footprint.
- ! Escalate if the source IP resolves to a known threat actor infrastructure, Tor exit node, VPN provider, or residential proxy service — indicates deliberate obfuscation.
- ! Escalate if sensitive resource types were specifically targeted in the enumeration: KMS keys (`ListKeys`, `DescribeKey`), Secrets Manager (`ListSecrets`), SSM Parameter Store parameters (`DescribeParameters`), or database snapshots — these indicate pre-exfiltration positioning.
- ! Escalate if Pacu, ScoutSuite, CloudMapper, or other known cloud exploitation framework user agents are identified in the CloudTrail `UserAgent` field.
Investigation Guide
Forensic Artifacts
- >
AWS CloudTrail management events in S3 — contains full API call history including EventName, UserIdentityArn, SourceIPAddress, UserAgent, RequestParameters, and ResponseElements for all discovery API calls - >
AWS CloudTrail `userAgent` field — reveals the SDK/tool used (Pacu, Boto3, aws-cli, ScoutSuite) based on the HTTP user agent string in each API call - >
AWS IAM credential report — shows access key creation date, last used date, last used region, and MFA status for all IAM users in the account - >
Azure Activity Log entries — stored in Log Analytics workspace or Storage Account, contains operationName, caller identity, callerIpAddress, and resource group context - >
Azure Sign-in Logs — correlate with Activity Log entries to identify the authentication event that preceded enumeration, revealing client app, device, and location - >
VPC Flow Logs (AWS) or NSG Flow Logs (Azure) — network-level evidence of connections from the source IP during the enumeration window, showing destination ports and data transfer volumes - >
AWS Config snapshots — record the configuration state of all enumerated resources at the time of discovery, establishing what the adversary observed - >
~/.aws/credentials and ~/.aws/config on compromised endpoints — if the attack originated from a compromised EC2 instance, instance metadata service (IMDS) query logs may reveal credential theft via `169.254.169.254` - >
Bash/PowerShell command history on compromised systems — may contain explicit cloud CLI enumeration commands used interactively
Tuning Guidance
Begin tuning by identifying all service accounts and automation tools that perform legitimate cloud enumeration in your environment. Create allowlists for known IAM role ARNs and source IP CIDR ranges associated with CSPM tools (Wiz, Prisma Cloud), infrastructure-as-code pipelines (Terraform runner IPs), and backup agents. Increase the burst thresholds for environments with frequent IaC deployments — Terraform plan operations can trigger 50+ describe calls in seconds. Add CloudTrail `UserAgent` filters to exclude known management tools (aws-sdk-java, terraform, aws-cli/2.x from known IPs). For Azure, exclude calls where `Caller` matches service principal names associated with your monitoring platforms. Tune the time window from 15 minutes to 5 minutes if you want higher sensitivity to rapid automated tools at the cost of more false positives from IaC operations. For the sensitive resource hunting query, exceptions should be rare and carefully reviewed before exclusion.
Hunting Queries
Hunts for cross-account cloud infrastructure discovery where an adversary assumes a role in one account and uses it to enumerate resources in multiple other accounts — a pattern indicating organizational cloud footprint mapping by threat actors like Scattered Spider.
// Hunt for cross-account enumeration via AssumeRole chains followed by discovery
AWSCloudTrail
| where TimeGenerated >= ago(7d)
| where EventName == "AssumeRole"
| extend AssumedRoleArn = tostring(parse_json(ResponseElements).assumedRoleUser.arn)
| join kind=inner (
AWSCloudTrail
| where EventName in ("DescribeInstances", "ListBuckets", "DescribeDBInstances", "ListRoles", "GetCallerIdentity")
| extend Identity = tostring(parse_json(UserIdentity).arn)
) on $left.AssumedRoleArn == $right.Identity
| summarize
AssumedRoles = make_set(AssumedRoleArn),
DiscoveryAPIs = make_set(EventName1),
DiscoveryCount = count(),
AffectedAccounts = make_set(RecipientAccountId)
by UserIdentityArn, SourceIPAddress
| where array_length(AffectedAccounts) > 1
| sort by DiscoveryCount desc index=* sourcetype="aws:cloudtrail" eventName="AssumeRole"
| eval assumed_arn='responseElements.assumedRoleUser.arn'
| join type=inner assumed_arn [
search index=* sourcetype="aws:cloudtrail"
eventName IN ("DescribeInstances", "ListBuckets", "DescribeDBInstances", "ListRoles", "GetCallerIdentity")
| eval assumed_arn='userIdentity.arn'
| table assumed_arn, eventName, recipientAccountId, sourceIPAddress
]
| stats dc(recipientAccountId) as affected_accounts, values(eventName) as discovery_apis, count as total_calls
by userIdentity.arn, sourceIPAddress
| where affected_accounts > 1
| sort -affected_accounts Hunts specifically for known cloud exploitation framework user agents (Pacu, ScoutSuite, CloudMapper, Prowler) in CloudTrail logs — these tools are commonly used by adversaries and red teams for automated cloud infrastructure discovery and are identifiable by their distinctive HTTP user agent strings.
// Hunt for known cloud exploitation tool user agents in CloudTrail
AWSCloudTrail
| where TimeGenerated >= ago(30d)
| where UserAgent has_any ("pacu", "scoutsuite", "cloudmapper", "prowler", "cloudsplaining", "weirdaaws", "python-requests", "nuclei")
| summarize
ToolCalls = count(),
DistinctAPIs = dcount(EventName),
APIs = make_set(EventName, 30),
AccountIds = make_set(RecipientAccountId),
SourceIPs = make_set(SourceIPAddress)
by UserIdentityArn, UserAgent, bin(TimeGenerated, 1h)
| sort by ToolCalls desc index=* sourcetype="aws:cloudtrail"
| eval ua=lower(userAgent)
| where match(ua, "pacu|scoutsuite|cloudmapper|prowler|cloudsplaining|weirdaaws")
| stats count as tool_calls, dc(eventName) as distinct_apis, values(eventName) as apis,
dc(recipientAccountId) as accounts, values(sourceIPAddress) as source_ips
by userIdentity.arn, userAgent
| sort -tool_calls Hunts for enumeration of high-sensitivity cloud resources — secrets (Secrets Manager, SSM Parameter Store), encryption keys (KMS), and database/compute snapshots — which represent pre-exfiltration reconnaissance identifying data the adversary may attempt to steal or leverage for further access.
// Hunt for enumeration of sensitive resources: secrets, keys, and snapshots
AWSCloudTrail
| where TimeGenerated >= ago(14d)
| where EventName in (
"ListSecrets", "GetSecretValue", "DescribeSecret",
"ListKeys", "DescribeKey", "GetKeyPolicy",
"DescribeParameters", "GetParameter", "GetParameters",
"DescribeDBSnapshots", "DescribeDBClusterSnapshots",
"DescribeSnapshots", "ListAliases"
)
| summarize
SensitiveAPICalls = count(),
DistinctSensitiveAPIs = dcount(EventName),
APIs = make_set(EventName),
ResourcesAccessed = make_set(tostring(parse_json(RequestParameters)))
by UserIdentityArn, SourceIPAddress, bin(TimeGenerated, 1h)
| where SensitiveAPICalls >= 3 or DistinctSensitiveAPIs >= 2
| extend SensitivityScore = SensitiveAPICalls * 2 + DistinctSensitiveAPIs * 5
| sort by SensitivityScore desc index=* sourcetype="aws:cloudtrail"
eventName IN (
"ListSecrets", "GetSecretValue", "DescribeSecret",
"ListKeys", "DescribeKey", "GetKeyPolicy",
"DescribeParameters", "GetParameter",
"DescribeDBSnapshots", "DescribeSnapshots"
)
| bin _time span=1h
| stats count as sensitive_calls, dc(eventName) as distinct_sensitive_apis,
values(eventName) as apis
by _time, userIdentity.arn, sourceIPAddress
| where sensitive_calls >= 3 OR distinct_sensitive_apis >= 2
| eval sensitivity_score=(sensitive_calls * 2) + (distinct_sensitive_apis * 5)
| sort -sensitivity_score Atomic Red Team Tests
Simulates an adversary using compromised AWS credentials to enumerate compute instances, S3 buckets, and database infrastructure across all available regions — mimicking the initial discovery phase of attacks like Scattered Spider.
Command
# Prerequisites: AWS CLI installed and configured with test credentials
# Ensure credentials have read-only permissions to avoid unintended changes
# Step 1: Identify the account and user context
aws sts get-caller-identity
# Step 2: Enumerate EC2 instances across multiple regions
for region in us-east-1 us-west-2 eu-west-1 ap-southeast-1; do
echo "=== Region: $region ==="
aws ec2 describe-instances --region $region --query 'Reservations[*].Instances[*].[InstanceId,State.Name,InstanceType,PublicIpAddress,Tags[?Key==`Name`].Value|[0]]' --output table 2>/dev/null
done
# Step 3: List all S3 buckets
aws s3api list-buckets --query 'Buckets[*].[Name,CreationDate]' --output table
# Step 4: Check bucket public access and ACLs on first bucket found
FIRST_BUCKET=$(aws s3api list-buckets --query 'Buckets[0].Name' --output text)
aws s3api get-public-access-block --bucket $FIRST_BUCKET 2>/dev/null || echo "No public access block configured"
aws s3api get-bucket-acl --bucket $FIRST_BUCKET 2>/dev/null
# Step 5: Enumerate RDS instances
aws rds describe-db-instances --query 'DBInstances[*].[DBInstanceIdentifier,DBInstanceStatus,Engine,Endpoint.Address]' --output table 2>/dev/null
# Step 6: Enumerate key pairs and security groups
aws ec2 describe-key-pairs --output table
aws ec2 describe-security-groups --query 'SecurityGroups[*].[GroupId,GroupName,Description]' --output table 2>/dev/null | head -50 Cleanup
# No cleanup required — all operations were read-only
# Remove test credentials if temporary: aws configure set aws_access_key_id '' && aws configure set aws_secret_access_key '' Expected Telemetry
CloudTrail management events for: GetCallerIdentity, DescribeInstances (multiple regions), ListBuckets, GetPublicAccessBlock, GetBucketAcl, DescribeDBInstances, DescribeKeyPairs, DescribeSecurityGroups — all appearing within a short time window from the same identity and source IP
Expected Detection
Alert fires on the KQL/SPL detection within the 15-minute bucket when DescribeInstances (x4 for multi-region) + ListBuckets + GetPublicAccessBlock + GetBucketAcl + DescribeDBInstances + DescribeKeyPairs + DescribeSecurityGroups = 10+ distinct calls, crossing both count and API diversity thresholds
Simulates adversarial enumeration of Azure compute, storage, and database resources using the Azure CLI with compromised credentials, generating Activity Log events matching the detection query.
Command
# Prerequisites: Azure CLI (az) installed and authenticated
# Use: az login --use-device-code with test/restricted service principal
# Step 1: Identify subscription context
az account show
az account list --output table
# Step 2: Enumerate all virtual machines across subscription
az vm list --output table --query '[*].[name,location,resourceGroup,powerState]'
# Step 3: Enumerate storage accounts
az storage account list --output table --query '[*].[name,location,resourceGroup,primaryEndpoints.blob]'
# Step 4: Enumerate SQL servers and databases
az sql server list --output table 2>/dev/null
az sql db list --resource-group $(az group list --query '[0].name' -o tsv) --server $(az sql server list --query '[0].name' -o tsv) --output table 2>/dev/null
# Step 5: Enumerate virtual networks and subnets
az network vnet list --output table --query '[*].[name,location,resourceGroup,addressSpace.addressPrefixes]'
# Step 6: Enumerate Key Vaults
az keyvault list --output table --query '[*].[name,location,resourceGroup]'
# Step 7: Enumerate AKS clusters
az aks list --output table --query '[*].[name,location,resourceGroup,kubernetesVersion]' 2>/dev/null
# Step 8: Enumerate resource groups (broad scope)
az group list --output table Cleanup
# No cleanup required — all read-only operations
# Sign out test credentials: az logout Expected Telemetry
Azure Activity Log entries for operations: 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/resourcegroups/read — all from same caller within a short window
Expected Detection
Alert fires on AzureActivity detection branch when 7+ distinct read operations are observed within the 15-minute window from the same caller, scoring at RiskScore=70 based on API spread exceeding the APISpreadThreshold of 5
Simulates the use of Pacu, a known AWS exploitation framework explicitly referenced in MITRE ATT&CK T1580 procedure examples, to perform automated multi-service infrastructure discovery. This generates distinctive user agent strings detectable by the hunting query.
Command
# Prerequisites: Python 3.8+, pip
# Install Pacu in an isolated test environment
python3 -m pip install pacu
# Launch Pacu and run discovery modules
# Create a new session using test credentials
pacu << 'EOF'
new_session test_discovery
set_keys
<TEST_ACCESS_KEY_ID>
<TEST_SECRET_ACCESS_KEY>
run ec2__enum
run s3__bucket_finder
run iam__enum_users_roles_policies_groups
run rds__enum
run lambda__enum
quit
EOF
# Alternative: Run individual Pacu modules non-interactively for specific resource types
# pacu --session test_session --module-name ec2__enum --exec
# Verify Pacu user agent appears in CloudTrail (check after ~5 minutes for CT delivery)
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=EventName,AttributeValue=DescribeInstances \
--start-time $(date -d '10 minutes ago' --iso-8601=seconds) \
--query 'Events[*].CloudTrailEvent' --output text | python3 -c "import sys,json; [print(json.loads(l).get('userAgent','')) for l in sys.stdin if l.strip()]" Cleanup
# Remove Pacu and test session data
pip uninstall -y pacu
rm -rf ~/.local/lib/python*/site-packages/pacu/
rm -f pacu.db
# Revoke test access keys in AWS IAM console or via: aws iam delete-access-key --access-key-id <TEST_KEY> Expected Telemetry
CloudTrail management events with UserAgent containing 'pacu' or 'Boto3' (Pacu uses Boto3 SDK). Expect 50+ API calls across ec2:DescribeInstances, ec2:DescribeVolumes, ec2:DescribeSnapshots, s3:ListBuckets, iam:ListUsers, iam:ListRoles, iam:ListPolicies, rds:DescribeDBInstances, lambda:ListFunctions within minutes from a single identity
Expected Detection
Main detection fires immediately on volume (50+ calls) and API diversity (7+ distinct APIs) thresholds, scoring RiskScore=90. The hunting query for known tool user agents additionally fires, identifying 'pacu' in the CloudTrail UserAgent field — providing dual-signal confirmation of adversarial tooling