Detect Cloud Service Discovery in Microsoft Sentinel
Adversaries who have gained access to a cloud environment may enumerate cloud services, resources, and configurations to identify valuable targets, understand security controls, and plan follow-on actions. This includes enumerating Azure resources via Azure Resource Manager API, Microsoft Graph API calls to list applications and service principals, AWS service enumeration via Pacu or direct CLI, and discovery of security services such as GuardDuty, Defender for Cloud, CloudTrail, and logging configurations. Tools like Stormspotter, AADInternals, and ROADTools automate this reconnaissance and are commonly observed in pre-ransomware and espionage campaigns.
MITRE ATT&CK
- Tactic
- Discovery
- Technique
- T1526 Cloud Service Discovery
- Canonical reference
- https://attack.mitre.org/techniques/T1526/
KQL Detection Query
// Detection 1: Azure Resource Manager bulk enumeration
let EnumerationWindow = 10m;
let ListOperationThreshold = 20;
AzureActivity
| where TimeGenerated > ago(1h)
| where ActivityStatusValue =~ "Success"
| where OperationNameValue has_any ("list", "List", "LIST")
or OperationNameValue has_any ("/read", "/get", "/Get")
| where CategoryValue !in ("Policy", "Alert", "Autoscale")
| summarize
OperationCount = count(),
DistinctOperations = dcount(OperationNameValue),
DistinctResourceTypes = dcount(tostring(split(ResourceId, "/")[3])),
DistinctSubscriptions = dcount(SubscriptionId),
OperationList = make_set(OperationNameValue, 30),
ResourceList = make_set(ResourceId, 30)
by Caller, CallerIpAddress, bin(TimeGenerated, EnumerationWindow)
| where OperationCount >= ListOperationThreshold or DistinctResourceTypes >= 8
| extend RiskScore = case(
DistinctResourceTypes >= 15, "Critical",
DistinctResourceTypes >= 8, "High",
OperationCount >= 50, "High",
"Medium"
)
| project TimeGenerated, Caller, CallerIpAddress, OperationCount, DistinctOperations, DistinctResourceTypes, DistinctSubscriptions, RiskScore, OperationList, ResourceList
| sort by DistinctResourceTypes desc, OperationCount desc
// ---
// Detection 2: Microsoft Graph API service enumeration (via AuditLogs)
// Run separately
// AuditLogs
// | where TimeGenerated > ago(1h)
// | where Category in ("Core Directory", "Application Management", "Policy")
// | where OperationName has_any (
// "Get servicePrincipal", "List servicePrincipals",
// "Get application", "List applications",
// "Get policy", "List policies",
// "Get organization", "Get domain",
// "Get directoryRole", "List directoryRoles",
// "List roleAssignments", "List groupMembers"
// )
// | extend InitiatedByUser = tostring(InitiatedBy.user.userPrincipalName)
// | extend InitiatedByApp = tostring(InitiatedBy.app.displayName)
// | extend SourceIP = tostring(InitiatedBy.user.ipAddress)
// | summarize
// EnumOperations = count(),
// DistinctOps = dcount(OperationName),
// OperationSet = make_set(OperationName, 20)
// by InitiatedByUser, InitiatedByApp, SourceIP, bin(TimeGenerated, 10m)
// | where EnumOperations >= 10 or DistinctOps >= 5
// | sort by EnumOperations desc Detects bulk cloud service enumeration via Azure Resource Manager. The primary query identifies callers who issue many List/Get/Read operations across multiple resource types within a short window — a pattern consistent with tools like Stormspotter, AADInternals, ROADTools, and manual reconnaissance. DistinctResourceTypes is the strongest signal: legitimate users rarely enumerate 8+ distinct Azure resource type namespaces in 10 minutes. The commented-out secondary query uses AuditLogs to detect Microsoft Graph API enumeration of applications, service principals, policies, and directory roles — run as a separate rule. Both can be combined with DistinctSubscriptions > 1 to flag cross-subscription recon.
Data Sources
Required Tables
False Positives & Tuning
- Cloud infrastructure automation tools (Terraform, Pulumi, Bicep) performing state refresh operations that enumerate all resource types across a subscription
- Azure Security Center, Microsoft Defender for Cloud, or third-party CSPM platforms performing continuous posture assessments that enumerate resources
- DevOps pipelines with service principals that run 'az resource list' or similar commands during environment validation steps
- Cloud governance tools (Azure Policy compliance scans, Azure Advisor) that regularly enumerate resources to generate recommendations
- IT administrators conducting authorized cloud inventory or migration assessments using tools like Azure Migrate or Azure Resource Graph
Other platforms for T1526
Testing Methodology
Validate this detection against 4 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 1Azure Resource Enumeration via Azure CLI
Expected signal: AzureActivity log entries for each az CLI command with OperationNameValue containing Microsoft.Compute/virtualMachines/read, Microsoft.Network/virtualNetworks/read, Microsoft.Storage/storageAccounts/read, Microsoft.KeyVault/vaults/read, Microsoft.Web/sites/read, Microsoft.ContainerService/managedClusters/read, Microsoft.Security/autoProvisioningSettings/read. Caller will be the authenticated user or service principal. CallerIpAddress will reflect the source machine's IP.
- Test 2Entra ID Enumeration via AADInternals PowerShell Module
Expected signal: AuditLogs entries with Category='Core Directory' for tenant and domain read operations. User-Agent field in AdditionalDetails will contain 'AADInternals'. SigninLogs will show authentication events for the token acquisition. MicrosoftGraphActivityLogs (if enabled) will show HTTP GET requests to /v1.0/organization, /v1.0/domains, /v1.0/servicePrincipals with User-Agent='AADInternals'.
- Test 3Microsoft Graph API Service Principal Enumeration via PowerShell
Expected signal: AuditLogs entries: OperationName='List servicePrincipals', 'List applications', 'List directoryRoles', 'Get organization', 'Get policy' with Category='Core Directory' and 'ApplicationManagement'. InitiatedBy will reflect the authenticated user. MicrosoftGraphActivityLogs will show GET requests to /v1.0/servicePrincipals, /v1.0/applications, /v1.0/directoryRoles, /v1.0/organization, /v1.0/policies/authorizationPolicy.
- Test 4AWS Cloud Service Discovery via Pacu Framework
Expected signal: AWS CloudTrail logs: DescribeTrails, ListDetectors, DescribeInstances, ListRoles, ListBuckets, ListFunctions, ListClusters, ListSecrets events with eventSource matching cloudtrail.amazonaws.com, guardduty.amazonaws.com, ec2.amazonaws.com, iam.amazonaws.com, s3.amazonaws.com, lambda.amazonaws.com, ecs.amazonaws.com, secretsmanager.amazonaws.com. userAgent will contain 'aws-cli'. sourceIPAddress will reflect the caller's IP.
References (12)
- https://attack.mitre.org/techniques/T1526/
- https://docs.microsoft.com/en-us/rest/api/resources/
- https://docs.microsoft.com/en-us/previous-versions/azure/ad/graph/howto/azure-ad-graph-api-operations-overview
- https://github.com/Azure/Stormspotter
- https://github.com/RhinoSecurityLabs/pacu
- https://o365blog.com/aadinternals/
- https://github.com/dirkjanm/ROADtools
- https://learn.microsoft.com/en-us/azure/azure-monitor/reference/tables/azureactivity
- https://learn.microsoft.com/en-us/azure/azure-monitor/reference/tables/auditlogs
- https://learn.microsoft.com/en-us/graph/microsoft-graph-activity-logs-overview
- https://www.microsoft.com/en-us/security/blog/2024/09/26/midnight-blizzard-conducts-large-scale-spear-phishing-campaign-using-rdp-files/
- https://github.com/redcanaryco/atomic-red-team/blob/master/atomics/T1526/T1526.md
Unlock Pro Content
Get the full detection package for T1526 including response playbook, investigation guide, and atomic red team tests.