Detect Cloud Service Dashboard in Google Chronicle
An adversary may use a cloud service dashboard GUI with stolen credentials to gain useful information from an operational cloud environment, such as specific services, resources, and features. Cloud service dashboards (AWS Management Console, Azure Portal, GCP Cloud Console) provide rich graphical interfaces that may expose more configuration details than programmatic API calls, allowing adversaries to enumerate running instances, storage buckets, IAM roles, network configurations, and security findings. Because dashboard access uses standard web browser sessions, it may blend into legitimate user activity and bypass controls focused on API-level telemetry. Scattered Spider, for example, abused AWS Systems Manager Inventory after gaining console access to identify lateral movement targets.
MITRE ATT&CK
- Tactic
- Discovery
- Technique
- T1538 Cloud Service Dashboard
- Canonical reference
- https://attack.mitre.org/techniques/T1538/
YARA-L Detection Query
rule t1538_cloud_service_dashboard_suspicious_access {
meta:
author = "df00tech"
description = "Detects suspicious cloud service dashboard access (T1538) via anomalous sign-ins to Azure Portal, AWS Management Console, or GCP Cloud Console with compound risk indicators"
mitre_attack_tactic = "Discovery"
mitre_attack_technique = "T1538"
severity = "MEDIUM"
priority = "MEDIUM"
created = "2026-04-20"
reference = "https://attack.mitre.org/techniques/T1538/"
events:
$login.metadata.event_type = "USER_LOGIN"
(
$login.target.application in nocase (
"Azure Portal",
"Microsoft Azure Portal",
"AWS Management Console",
"Google Cloud Console",
"Azure Active Directory Portal",
"Microsoft 365 admin center"
)
or $login.metadata.product_name in nocase (
"Azure Active Directory",
"Amazon CloudTrail",
"Google Cloud Identity"
)
)
(
$login.principal.location.country_or_region in (
"China", "Russia", "North Korea", "Iran", "Belarus", "Cuba", "Syria"
)
or $login.security_result.severity in ("HIGH", "CRITICAL")
or $login.extensions.auth.auth_details = "SINGLE_FACTOR"
or $login.security_result.action = "BLOCK"
or $login.target.user.attribute.roles.name = "Root"
)
$user = $login.principal.user.userid
condition:
$login
} Chronicle YARA-L 2.0 rule detecting T1538 Cloud Service Dashboard access by matching USER_LOGIN UDM events to cloud console application names and filtering on compound risk signals: high-risk country origin, single-factor authentication, elevated security result severity, blocked access attempts, or root account usage. Requires cloud identity log ingestion via Chronicle forwarders.
Data Sources
Required Tables
False Positives & Tuning
- Global enterprise users authenticating to cloud dashboards from high-risk geolocation codes due to regional business offices or partner network egress points in flagged countries
- Security teams conducting tabletop exercises or red team operations that generate blocked or single-factor cloud console login events during authorized testing windows
- Federated identity providers routing authentication through regions that appear as high-risk countries in geolocation databases due to IP space allocation mismatches
Other platforms for T1538
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 1 AWS Console Sign-In URL Generation via STS (Federated Access Simulation)
Expected signal: AWS CloudTrail: GetFederationToken event from userIdentity of the caller IAM user, with requestParameters showing the policy document. The ConsoleLogin event in CloudTrail (eventSource: signin.amazonaws.com) fires when the generated URL is clicked in a browser, with additionalEventData.MFAUsed=No and userIdentity.type=FederatedUser.
- Test 2 AWS Systems Manager Inventory Enumeration Post-Console-Access (Scattered Spider TTP)
Expected signal: AWS CloudTrail: DescribeInstanceInformation (eventName), ListInventoryEntries, and ListDocuments events under eventSource=ssm.amazonaws.com. All events carry the caller's IAM identity, source IP, userAgent (aws-cli or browser), and requestParameters. If called from a browser console session, the userIdentity.sessionContext will reference the console session.
- Test 3 Azure Portal Resource Enumeration via Azure CLI (Stolen Token Simulation)
Expected signal: AzureActivity table in Sentinel: Microsoft.Resources/subscriptions/read, Microsoft.Resources/resourceGroups/read, Microsoft.Compute/virtualMachines/read, Microsoft.Storage/storageAccounts/read events with Caller matching the authenticated user principal. AADSignInLogs: service principal or user sign-in event for Azure CLI app (appId: 04b07795-8ddb-461a-bbee-02f9e1bf7b46). All events carry the source IP of the machine running the CLI.
- Test 4 GCP Cloud Console Asset Enumeration via gcloud CLI
Expected signal: GCP Cloud Audit Logs: cloudresourcemanager.googleapis.com/projects.list, compute.instances.list, storage.buckets.list, iam.projects.getIamPolicy, and securitycenter.findings.list data access events. All entries include principalEmail (the caller), callerIp, userAgent (cloud-sdk/gcloud), and methodName. These logs appear in Cloud Audit Logs — Data Access log type and can be exported to Splunk via Pub/Sub or to Sentinel via the GCP connector.
References (7)
- https://attack.mitre.org/techniques/T1538/
- https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-event-reference-aws-console-sign-in-events.html
- https://cloud.google.com/security-command-center/docs/quickstart-scc-dashboard
- https://www.cisa.gov/news-events/cybersecurity-advisories/aa23-320a
- https://learn.microsoft.com/en-us/azure/active-directory/reports-monitoring/reference-azure-monitor-sign-ins-log-schema
- https://learn.microsoft.com/en-us/azure/azure-monitor/reference/tables/azureactivity
- https://docs.aws.amazon.com/systems-manager/latest/userguide/sysman-inventory-about.html
Response Playbook
Triage
- Identify the user account involved — is it a human user, service account, or root/break-glass account? Pull account creation date, recent password changes, and MFA enrollment status from the identity provider
- Geolocate the source IP using threat intelligence. Check if the IP is associated with residential ISPs, commercial VPNs, Tor exit nodes, or cloud hosting providers (which adversaries use as jump points). Compare to the user's usual sign-in geography
- Review the timeline of events immediately before and after the dashboard access — did the user recently authenticate to their email (potential phishing), reset their password, or have MFA disabled? Look for AAD audit events 30–60 minutes before the sign-in
- Check what the user did after logging into the console — in AWS, pull subsequent CloudTrail events by the same user session (sessionId); in Azure, query AzureActivity for resource enumeration events correlated by user principal
- Assess the authentication strength — was this a single-factor login? Was it a new device? Does the user have a Conditional Access policy that should have blocked this access from the source IP or country?
- Contact the user out-of-band (phone or Slack, not email — email may be compromised) to confirm whether they initiated this session. Do NOT rely solely on email confirmation if credentials were potentially stolen
Containment
- If the session is confirmed unauthorized: immediately revoke all active sessions in Azure AD (User > Revoke sessions) or AWS (IAM > Security credentials > Sign-in sessions invalidate), and disable the account pending investigation
- For AWS root account compromise: contact AWS Support immediately, change the root account password and MFA, and rotate all access keys. Root compromise requires immediate escalation to CISO
- If the adversary accessed AWS Systems Manager or similar inventory services (Scattered Spider TTP): isolate potentially enumerated EC2 instances by moving them to a restricted security group that blocks outbound traffic
- Rotate all credentials associated with the compromised identity — passwords, API keys, OAuth tokens, and service principal secrets
- Enable or strengthen Conditional Access / Service Control Policies to block access from the source IP range, ASN, or country for the duration of the investigation
- Preserve the CloudTrail / Azure audit logs for the relevant session before any log retention windows expire — export to a separate storage account that the compromised identity cannot access
Evidence Collection
- AWS CloudTrail: filter by userIdentity.arn and sessionContext.sessionIssuer for the full session — eventTime, eventName, requestParameters, responseElements for all API calls made during the console session
- Azure AD SigninLogs: collect IPAddress, LocationDetails, DeviceDetail, MfaDetail, AuthenticationDetails, ConditionalAccessPolicies for the specific sign-in event (correlate on CorrelationId)
- Azure Activity Log: query AzureActivity filtered by Caller == <compromised UPN> and TimeGenerated in the session window — shows all resource reads, writes, and enumerations made through the portal
- AWS CloudTrail GetConsoleURL and AssumeRole events: identify if the adversary used role chaining or console URL generation via the API before browser-based access
- Browser fingerprint artifacts from the dashboard session — UserAgent string, screen resolution, timezone offset (available in Azure AD SigninLogs DeviceDetail and AWS CloudTrail userAgent fields)
- Identity Protection risk events in Azure AD — pull all risk events for the user (sign-in risk, user risk, risky workloads) for correlation with the incident timeline
- DNS and proxy logs for the dashboard domains (console.aws.amazon.com, portal.azure.com, console.cloud.google.com) from the corporate network during the session window to identify if access originated from within or outside the perimeter
Escalation Criteria
- !Root/global administrator account used to access the cloud dashboard — any unauthorized root account console access is an automatic P1 incident requiring immediate CISO notification
- !Evidence of post-access enumeration: IAM policy reads, user/role listing, S3/storage account enumeration, EC2/VM inventory queries, or security service configuration reads within the same session
- !AWS Systems Manager Inventory or equivalent cloud asset enumeration APIs called after console login — this is a confirmed Scattered Spider TTP used to identify lateral movement targets
- !Console access followed immediately by resource modification: security group changes, new IAM user creation, storage access policy modifications, or MFA device removal for other accounts
- !Multiple geographic locations for the same user within an impossible travel timeframe (sign-in from US and EU within minutes)
- !Adversary accesses cloud console from a known malicious IP or ASN confirmed by threat intelligence — treat as confirmed compromise regardless of whether post-access activity is visible
Investigation Guide
Related Techniques
Forensic Artifacts
- >
AWS CloudTrail: ConsoleLogin event with eventSource=signin.amazonaws.com, MFAUsed field, and sourceIPAddress — authoritative record of all AWS Console sign-ins - >
AWS CloudTrail: GetConsoleURL event (eventName=GetConsoleURL) — generated when federated users or roles create a console sign-in URL via STS, often used by adversaries with temporary credentials - >
Azure AD SigninLogs table: CorrelationId field links all authentication events in a single sign-in flow; AuthenticationDetails shows each authentication step and whether MFA was satisfied - >
Azure AD AuditLogs table: track password resets, MFA configuration changes, and role assignments made by or to the compromised account in the period surrounding the incident - >
Azure Activity Log (AzureActivity table): every resource operation performed via Azure Portal leaves an entry with Caller (UPN), OperationNameValue, ResourceGroup, and clientIpAddress - >
AWS CloudTrail session events: all API calls made during the console session share a userIdentity.sessionContext.sessionIssuer value, allowing complete session reconstruction - >
Browser cache artifacts on the adversary's device: cloud console sessions generate substantial browser history, cookies, and cached credentials — relevant if endpoint forensics are possible - >
Identity Protection risk detections: Azure AD generates risk events (anonymizedIPAddress, unfamiliarFeatures, impossibleTravel, maliciousIPAddress) that may have been suppressed by the adversary timing the attack to avoid risky sign-in thresholds
Tuning Guidance
Cloud dashboard access is inherently noisy because it is a legitimate administrative interface. Start tuning by building an allowlist of expected source IP ranges (corporate VPN egress, named remote work IPs for key administrators) and excluding these from geographic anomaly alerts. For AWS, distinguish between human console logins and federated SSO logins (the latter often appear as AssumedRole events with a SAML issuer, not direct password auth) — the detection focus should be on direct password-based console logins without MFA. For Azure, leverage Conditional Access Named Locations to encode approved geographies and exclude them from the SigninLogs query, then alert only on logins from outside all named locations. The enumeration correlation hunting query will produce false positives for any administrator who performs routine infrastructure checks after logging in — tune by adding a minimum threshold of 10+ distinct enumeration operations and/or requiring the source IP to be outside the corporate IP range. In environments with heavy root account usage for billing access, consider a separate lower-severity alert for root logins that only escalates to high severity when root console login is followed by IAM or security configuration changes.
Hunting Queries
Hunt for accounts accessing cloud dashboards from multiple countries, multiple source IPs, or with repeated failed login attempts over a 7-day window. Legitimate users rarely sign into cloud portals from 3+ countries or 5+ distinct IPs in a week without a known travel or VPN explanation. High failure counts preceding a successful login indicate credential spraying or brute-force activity.
SigninLogs
| where TimeGenerated > ago(7d)
| where AppDisplayName has "Portal" or AppDisplayName has "Console"
| summarize
SignInCount = count(),
UniqueIPs = dcount(IPAddress),
Countries = make_set(tostring(LocationDetails.countryOrRegion)),
CountryCount = dcount(tostring(LocationDetails.countryOrRegion)),
FirstSeen = min(TimeGenerated),
LastSeen = max(TimeGenerated),
FailedCount = countif(ResultType != 0)
by UserPrincipalName, AppDisplayName
| where CountryCount >= 3 or UniqueIPs >= 5 or FailedCount > 5
| sort by CountryCount desc, UniqueIPs desc index=aws sourcetype=aws:cloudtrail eventName=ConsoleLogin
| bucket _time span=7d
| stats count as TotalLogins, dc(sourceIPAddress) as UniqueIPs, values(sourceIPAddress) as SourceIPs, values(awsRegion) as Regions, sum(eval(if('responseElements.ConsoleLogin'=="Failure",1,0))) as FailedLogins by 'userIdentity.arn'
| where UniqueIPs >= 3 OR FailedLogins > 5
| sort - UniqueIPs Hunt for successful cloud dashboard logins occurring outside normal business hours (before 06:00 or after 22:00 UTC). While some legitimate administrators work off-hours, repeated successful console logins at unusual times — especially combined with unfamiliar source IPs — are a strong indicator of unauthorized access using stolen credentials. Focus on accounts with 2+ off-hours logins on the same calendar day.
let CloudDashboardApps = dynamic(["Azure Portal", "Microsoft Azure Portal", "Azure Active Directory Portal"]);
SigninLogs
| where TimeGenerated > ago(14d)
| where AppDisplayName in (CloudDashboardApps)
| where ResultType == 0
| extend Hour = hourofday(TimeGenerated)
| extend IsOffHours = Hour < 6 or Hour > 22
| where IsOffHours
| summarize
OffHoursLogins = count(),
UniqueSourceIPs = dcount(IPAddress),
Countries = make_set(tostring(LocationDetails.countryOrRegion)),
Sessions = make_set(CorrelationId)
by UserPrincipalName, bin(TimeGenerated, 1d)
| where OffHoursLogins >= 2
| sort by OffHoursLogins desc index=aws sourcetype=aws:cloudtrail eventName=ConsoleLogin 'responseElements.ConsoleLogin'=Success
| eval hour=strftime(_time, "%H")
| eval is_off_hours=if(hour < "06" OR hour > "22", 1, 0)
| where is_off_hours=1
| stats count as OffHoursLogins, dc(sourceIPAddress) as UniqueIPs, values(sourceIPAddress) as SourceIPs, values(awsRegion) as Regions by 'userIdentity.arn', date_mday, date_month
| where OffHoursLogins >= 2
| sort - OffHoursLogins Hunt for cloud resource enumeration activity occurring within 30 minutes of a successful console login. This pattern — login followed immediately by broad read/list API calls — is consistent with adversary reconnaissance using stolen credentials. In AWS, focus on ListBuckets, DescribeInstances, ListRoles, ListUsers, and ListInventoryEntries (the Scattered Spider SSM TTP). In Azure, focus on resource reads across multiple ResourceGroups and storage account key listing.
// Hunt for enumeration activity immediately following cloud console login
let PortalSignIns = SigninLogs
| where TimeGenerated > ago(7d)
| where AppDisplayName has "Portal"
| where ResultType == 0
| project SignInTime = TimeGenerated, UserPrincipalName, IPAddress, CorrelationId;
AzureActivity
| where TimeGenerated > ago(7d)
| where OperationNameValue has_any ("list", "read", "get", "Microsoft.Resources/subscriptions/resources/read",
"Microsoft.Authorization/roleAssignments/read", "Microsoft.Storage/storageAccounts/listKeys/action",
"Microsoft.Compute/virtualMachines/read", "Microsoft.Network/virtualNetworks/read")
| project ActivityTime = TimeGenerated, Caller, OperationNameValue, ResourceGroup, clientIpAddress
| join kind=inner PortalSignIns on $left.Caller == $right.UserPrincipalName
| where ActivityTime between (SignInTime .. (SignInTime + 30min))
| summarize
EnumerationOps = count(),
OpsPerformed = make_set(OperationNameValue),
ResourceGroups = make_set(ResourceGroup)
by Caller, SignInTime, IPAddress
| where EnumerationOps >= 5
| sort by EnumerationOps desc index=aws sourcetype=aws:cloudtrail eventName=ConsoleLogin 'responseElements.ConsoleLogin'=Success
| eval login_time=_time
| eval username=coalesce('userIdentity.userName', 'userIdentity.arn')
| table login_time, username, sourceIPAddress
| join type=inner username
[search index=aws sourcetype=aws:cloudtrail (eventName=ListBuckets OR eventName=DescribeInstances OR eventName=ListRoles OR eventName=ListUsers OR eventName=GetCallerIdentity OR eventName=DescribeVpcs OR eventName=DescribeSecurityGroups OR eventName=ListInventoryEntries)
| eval event_time=_time
| eval username=coalesce('userIdentity.userName', 'userIdentity.arn')
| table event_time, username, eventName, awsRegion]
| where event_time > login_time AND event_time < (login_time + 1800)
| stats count as EnumerationOps, values(eventName) as OpsPerformed, values(awsRegion) as Regions by username, login_time, sourceIPAddress
| where EnumerationOps >= 3
| sort - EnumerationOps Atomic Red Team Tests
Simulates how adversaries with stolen IAM access keys generate a console sign-in URL to access the AWS Management Console via a browser without the original account password. Uses STS GetFederationToken to produce a temporary credential set and constructs the ConsoleURL endpoint. This is a documented technique used by adversaries to convert stolen API credentials into interactive console sessions. Requires valid AWS credentials in the environment.
Command
# Step 1: Get caller identity to confirm credential validity
aws sts get-caller-identity --output json
# Step 2: Generate federation token (simulates adversary obtaining console access from API keys)
aws sts get-federation-token \
--name "recon-session" \
--duration-seconds 3600 \
--policy '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"sts:GetFederationToken","Resource":"*"}]}' \
--output json > /tmp/fed_token.json
# Step 3: Extract credentials and construct console sign-in URL
ACCESS_KEY=$(jq -r '.Credentials.AccessKeyId' /tmp/fed_token.json)
SECRET_KEY=$(jq -r '.Credentials.SecretAccessKey' /tmp/fed_token.json)
SESSION_TOKEN=$(jq -r '.Credentials.SessionToken' /tmp/fed_token.json)
SESSION_JSON=$(python3 -c "import json; print(json.dumps({'sessionId': '$ACCESS_KEY', 'sessionKey': '$SECRET_KEY', 'sessionToken': '$SESSION_TOKEN'}))")
# This URL, when opened in a browser, provides Management Console access
SIGNIN_TOKEN=$(curl -s "https://signin.aws.amazon.com/federation?Action=getSigninToken&Session=$(python3 -c "import urllib.parse,sys; print(urllib.parse.quote(sys.argv[1]))" "$SESSION_JSON")" | jq -r '.SigninToken')
echo "Console URL: https://signin.aws.amazon.com/federation?Action=login&Issuer=example&Destination=https%3A%2F%2Fconsole.aws.amazon.com%2F&SigninToken=$SIGNIN_TOKEN" Cleanup
rm -f /tmp/fed_token.json Expected Telemetry
AWS CloudTrail: GetFederationToken event from userIdentity of the caller IAM user, with requestParameters showing the policy document. The ConsoleLogin event in CloudTrail (eventSource: signin.amazonaws.com) fires when the generated URL is clicked in a browser, with additionalEventData.MFAUsed=No and userIdentity.type=FederatedUser.
Expected Detection
KQL AWSCloudTrail query triggers on ConsoleLogin with MFAUsed=No. Hunting query detects console login followed by enumeration activity. The GetFederationToken event is also a useful hunting signal (eventName=GetFederationToken from a non-CI/CD context).
Replicates the specific AWS Systems Manager Inventory abuse documented for the Scattered Spider threat group. After obtaining cloud console access, adversaries used SSM Inventory to enumerate managed instances across the environment, identifying targets for lateral movement without needing direct network access to those systems. Requires AWS CLI with SSM read permissions.
Command
# Enumerate all managed instances visible via SSM (Scattered Spider lateral movement recon)
aws ssm describe-instance-information \
--output json \
--query 'InstanceInformationList[*].{InstanceId:InstanceId,PlatformName:PlatformName,IPAddress:IPAddress,ComputerName:ComputerName,PingStatus:PingStatus}'
# List SSM inventory for installed applications on all managed instances
aws ssm list-inventory-entries \
--instance-id $(aws ssm describe-instance-information --query 'InstanceInformationList[0].InstanceId' --output text 2>/dev/null || echo "i-00000000000000000") \
--type-name AWS:Application \
--output json 2>/dev/null || echo "No instances available in test environment"
# Enumerate all SSM documents (may reveal automation playbooks with embedded credentials)
aws ssm list-documents \
--filters Key=Owner,Values=Self \
--output json \
--query 'DocumentIdentifiers[*].{Name:Name,DocumentType:DocumentType,PlatformTypes:PlatformTypes}' Expected Telemetry
AWS CloudTrail: DescribeInstanceInformation (eventName), ListInventoryEntries, and ListDocuments events under eventSource=ssm.amazonaws.com. All events carry the caller's IAM identity, source IP, userAgent (aws-cli or browser), and requestParameters. If called from a browser console session, the userIdentity.sessionContext will reference the console session.
Expected Detection
Hunting query (KQL/SPL) for ListInventoryEntries and DescribeInstanceInformation within 30 minutes of a ConsoleLogin event triggers on this sequence. High volume of ssm: describe/list API calls from a new source IP or unusual account is a strong signal for post-console enumeration.
Simulates adversary behavior after obtaining Azure access tokens or credentials: uses Azure CLI to enumerate subscriptions, resource groups, virtual machines, and storage accounts — the same information visible in the Azure Portal dashboard. This represents the programmatic equivalent of clicking through Azure Portal tabs, and generates AzureActivity and AAD audit log entries identical to portal-based browsing.
Command
# Authenticate with Azure CLI (in a real attack, adversary uses stolen token or credentials)
# az login # Skipped in test — assumes prior authentication
# Enumerate subscriptions (top-level Azure Portal view)
az account list --output table
# Enumerate all resource groups (equivalent to Resource Groups dashboard tab)
az group list --output table --query '[*].{Name:name,Location:location,State:properties.provisioningState}'
# Enumerate virtual machines across all resource groups (equivalent to Virtual Machines dashboard)
az vm list --output table --query '[*].{Name:name,ResourceGroup:resourceGroup,Location:location,PowerState:powerState}'
# Enumerate storage accounts (equivalent to Storage Accounts dashboard tab)
az storage account list --output table --query '[*].{Name:name,ResourceGroup:resourceGroup,Location:location,Kind:kind}'
# Enumerate Azure AD users (equivalent to Users blade in Azure AD portal)
az ad user list --output table --query '[*].{UPN:userPrincipalName,DisplayName:displayName,AccountEnabled:accountEnabled}' 2>/dev/null || echo "Requires Azure AD Graph permissions" Expected Telemetry
AzureActivity table in Sentinel: Microsoft.Resources/subscriptions/read, Microsoft.Resources/resourceGroups/read, Microsoft.Compute/virtualMachines/read, Microsoft.Storage/storageAccounts/read events with Caller matching the authenticated user principal. AADSignInLogs: service principal or user sign-in event for Azure CLI app (appId: 04b07795-8ddb-461a-bbee-02f9e1bf7b46). All events carry the source IP of the machine running the CLI.
Expected Detection
Hunting query (Azure enumeration after portal sign-in) correlates these read operations with a preceding SigninLogs event for the Azure Portal or Azure CLI. KQL detection in AzureActivity for rapid sequential resource reads across multiple resource groups within a short window triggers on this pattern.
Simulates GCP Security Command Center and Cloud Asset Inventory enumeration — the GCP equivalent of the AWS SSM and Azure Portal enumeration techniques above. Adversaries with stolen GCP credentials use gcloud to replicate the asset discovery capabilities of the GCP Console, including listing all projects, compute instances, storage buckets, and IAM bindings — information that would be visible in the GCP Cloud Console dashboard.
Command
# Requires gcloud CLI installed and prior authentication with stolen credentials
# gcloud auth login # Skipped — assumes prior credential compromise
# List accessible GCP projects (top-level console navigation)
gcloud projects list --format='table(projectId, name, projectNumber)' 2>/dev/null || echo "Requires gcloud authentication"
# Enumerate compute instances (Compute Engine dashboard view)
gcloud compute instances list --format='table(name, zone, machineType, status, networkInterfaces[0].accessConfigs[0].natIP)' 2>/dev/null || echo "No compute access or not authenticated"
# Enumerate storage buckets (Cloud Storage dashboard view)
gsutil ls -L -b 2>/dev/null | grep -E '(gs://|Location|Storage class)' || echo "No storage access or not authenticated"
# Enumerate IAM bindings at project level (IAM & Admin dashboard view)
gcloud projects get-iam-policy $(gcloud config get-value project 2>/dev/null) --format=json 2>/dev/null || echo "No IAM read access or not authenticated"
# Query Security Command Center findings (mirrors GCP Command Center dashboard)
gcloud scc findings list $(gcloud projects describe $(gcloud config get-value project 2>/dev/null) --format='value(name)' 2>/dev/null) --format=table 2>/dev/null || echo "Requires Security Command Center API access" Expected Telemetry
GCP Cloud Audit Logs: cloudresourcemanager.googleapis.com/projects.list, compute.instances.list, storage.buckets.list, iam.projects.getIamPolicy, and securitycenter.findings.list data access events. All entries include principalEmail (the caller), callerIp, userAgent (cloud-sdk/gcloud), and methodName. These logs appear in Cloud Audit Logs — Data Access log type and can be exported to Splunk via Pub/Sub or to Sentinel via the GCP connector.
Expected Detection
Cloud Audit Log analysis for sequential list/enumeration API calls across multiple GCP services within a short time window from an unusual source IP. Correlation of GCP console login events (authenticationInfo.principalEmail, requestMetadata.callerIp) with subsequent API enumeration calls within the same session window.