Skip to content

[New Rule] Excessive Secret or Key Retrieval from Azure Key Vault #4897

@terrancedejesus

Description

@terrancedejesus

Summary

We are missing detections for excessive secret or key retrieval from Azure Key Vault based on Azure Key Vault diagnostic logs (azure.platformlogs) that detail the specific operations called. As covered in the reference blog below, retrieval or listing is common post-identity compromise from a red teaming perspective. Although this could blend in with benign activity as well.

Ref: https://www.inversecos.com/2022/05/detection-and-compromise-azure-key.html

The following query was used on testing data from emulating this behavior in Azure. Note that we will need to add a setup guide about including Azure Key Vault diagnostic logs into the Event Hub that the Azure integration is enabled through. These logs are not enabled by default in Azure.

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 30-second windows
| EVAL time_window = DATE_TRUNC(1 minute, @timestamp)

// Aggregate identity, geo, resource, and activity info
| STATS
    // Who
    actor_name = VALUES(azure.platformlogs.identity.claim.upn),
    actor_unique_count = COUNT_DISTINCT(azure.platformlogs.identity.claim.upn),
    app_id = VALUES(azure.platformlogs.identity.claim.appid),
    object_id = VALUES(azure.platformlogs.identity.claim.upn),

    // Geo / Network
    source_ip = VALUES(source.ip),
    city_name = VALUES(geo.city_name),
    region_name = VALUES(geo.region_name),
    country_name = VALUES(geo.country_name),
    as_org = VALUES(source.as.organization.name),

    // What
    actions = VALUES(event.action),
    action_count = COUNT(*),
    distinct_actions = COUNT_DISTINCT(event.action),
    vaults_accessed = COUNT_DISTINCT(azure.resource.name),
    vault_names = VALUES(azure.resource.name),
    result_type = VALUES(azure.platformlogs.result_type),
    cloud_region = VALUES(cloud.region),

    // Metadata
    agent_name = VALUES(agent.name),
    subscription_id = VALUES(azure.subscription_id),
    resource_group = VALUES(azure.resource.group),
    resource_ids = VALUES(azure.resource.id)

BY
    time_window,
    azure.platformlogs.identity.claim.upn

// Optional filters for fidelity
| WHERE actor_unique_count == 1 and action_count >= 5 AND distinct_actions >= 2

| SORT time_window DESC

Metadata

Metadata

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions