Credential Access (TA0006)(external, opens in a new tab or window)
text code block:from logs-azure.platformlogs-* metadata _id, _index // Filter for Azure Key Vault read operations | where event.dataset == "azure.platformlogs" and event.action in ( "VaultGet", "KeyGet", "KeyList", "KeyListVersions", "KeyGetDeleted", "KeyListDeleted", "SecretGet", "SecretList", "SecretListVersions", "SecretGetDeleted", "SecretListDeleted", "CertificateGet", "CertificateList", "CertificateListVersions", "CertificateGetDeleted", "CertificateListDeleted", "CertificatePolicyGet", "CertificateContactsGet", "CertificateIssuerGet", "CertificateIssuersList" ) // Truncate timestamps into 1-minute windows | eval Esql.time_window_date_trunc = date_trunc(1 minute, @timestamp) // Aggregate identity, geo, resource, and activity info | stats Esql_priv.azure_platformlogs_identity_claim_upn_values = values(azure.platformlogs.identity.claim.upn), Esql.azure_platformlogs_identity_claim_upn_count_distinct = count_distinct(azure.platformlogs.identity.claim.upn), Esql.azure_platformlogs_identity_claim_appid_values = values(azure.platformlogs.identity.claim.appid), Esql.source_ip_values = values(source.ip), Esql.source_geo_city_values = values(source.geo.city_name), Esql.source_geo_region_values = values(source.geo.region_name), Esql.source_geo_country_values = values(source.geo.country_name), Esql.source_as_organization_name_values = values(source.as.organization.name), Esql.event_action_values = values(event.action), Esql.event_count = count(*), Esql.event_action_count_distinct = count_distinct(event.action), Esql.azure_resource_name_count_distinct = count_distinct(azure.resource.name), Esql.azure_resource_name_values = values(azure.resource.name), Esql.azure_platformlogs_result_type_values = values(azure.platformlogs.result_type), Esql.cloud_region_values = values(cloud.region), Esql.agent_name_values = values(agent.name), Esql.azure_subscription_id_values = values(azure.subscription_id), Esql.azure_resource_group_values = values(azure.resource.group), Esql.azure_resource_id_values = values(azure.resource.id) by Esql.time_window_date_trunc, azure.platformlogs.identity.claim.upn // keep relevant fields | keep Esql.time_window_date_trunc, Esql_priv.azure_platformlogs_identity_claim_upn_values, Esql.azure_platformlogs_identity_claim_upn_count_distinct, Esql.azure_platformlogs_identity_claim_appid_values, Esql.source_ip_values, Esql.source_geo_city_values, Esql.source_geo_region_values, Esql.source_geo_country_values, Esql.source_as_organization_name_values, Esql.event_action_values, Esql.event_count, Esql.event_action_count_distinct, Esql.azure_resource_name_count_distinct, Esql.azure_resource_name_values, Esql.azure_platformlogs_result_type_values, Esql.cloud_region_values, Esql.agent_name_values, Esql.azure_subscription_id_values, Esql.azure_resource_group_values, Esql.azure_resource_id_values // Filter for suspiciously high volume of distinct Key Vault reads by a single actor | where Esql.azure_platformlogs_identity_claim_upn_count_distinct == 1 and Esql.event_count >= 10 and Esql.event_action_count_distinct >= 2 | sort Esql.time_window_date_trunc desc
Install detection rules in Elastic Security
Detect Azure Key Vault Excessive Secret or Key Retrieved in the Elastic Security detection engine by installing this rule into your Elastic Stack.
To setup this rule, check out the installation guide for Prebuilt Security Detection Rules(external, opens in a new tab or window).