Microsoft Sentinel Analytic Rules
cloudbrothers.infoAzure Sentinel RepoToggle Dark/Light/Auto modeToggle Dark/Light/Auto modeToggle Dark/Light/Auto modeBack to homepage

Mass secret retrieval from Azure Key Vault

Back
Id24f8c234-d1ff-40ec-8b73-96b17a3a9c1c
RulenameMass secret retrieval from Azure Key Vault
DescriptionIdentifies mass secret retrieval from Azure Key Vault observed by a single user.

Mass secret retrival crossing a certain threshold is an indication of credential dump operations or mis-configured applications.

You can tweak the EventCountThreshold based on average count seen in your environment

and also filter any known sources (IP/Account) and useragent combinations based on historical analysis to further reduce noise
SeverityLow
TacticsCredentialAccess
TechniquesT1003
Required data connectorsAzureKeyVault
KindScheduled
Query frequency1d
Query period1d
Trigger threshold0
Trigger operatorgt
Source Urihttps://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Azure Key Vault/Analytic Rules/KeyvaultMassSecretRetrieval.yaml
Version1.0.7
Arm template24f8c234-d1ff-40ec-8b73-96b17a3a9c1c.json
Deploy To Azure
let DistinctSecretsThreshold = 10;
let EventCountThreshold = 50;
// To avoid any False Positives, filtering using AppId is recommended.
// The AppId 509e4652-da8d-478d-a730-e9d4a1996ca4 has been added in the query as it corresponds to Azure Resource Graph performing VaultGet operations for indexing and syncing all tracked resources across Azure.
// The AppId 8cae6e77-e04e-42ce-b5cb-50d82bce26b1 has been added as it correspond to Microsoft Policy Insights Provider Data Plane performing VaultGet operations for policies checks.
let AllowedAppId = dynamic(["509e4652-da8d-478d-a730-e9d4a1996ca4","8cae6e77-e04e-42ce-b5cb-50d82bce26b1"]);
let OperationList = dynamic(["SecretGet", "KeyGet", "VaultGet"]);
AzureDiagnostics
| where OperationName in (OperationList) and ResourceType =~ "VAULTS"
| where not(identity_claim_appid_g in (AllowedAppId) and OperationName == 'VaultGet')
| extend
    ResourceId,
    ResultType = column_ifexists("ResultType", ""),
    identity_claim_http_schemas_microsoft_com_identity_claims_objectidentifier_g = column_ifexists("identity_claim_http_schemas_microsoft_com_identity_claims_objectidentifier_g", ""),
    identity_claim_http_schemas_xmlsoap_org_ws_2005_05_identity_claims_upn_s = column_ifexists("identity_claim_http_schemas_xmlsoap_org_ws_2005_05_identity_claims_upn_s", ""),
    identity_claim_oid_g = column_ifexists("identity_claim_oid_g", ""),
    identity_claim_upn_s = column_ifexists("identity_claim_upn_s", "")
| extend
    CallerObjectId = iff(isempty(identity_claim_oid_g), identity_claim_http_schemas_microsoft_com_identity_claims_objectidentifier_g, identity_claim_oid_g),
    CallerObjectUPN = iff(isempty(identity_claim_upn_s), identity_claim_http_schemas_xmlsoap_org_ws_2005_05_identity_claims_upn_s, identity_claim_upn_s)
| as _Retrievals
| where CallerObjectId in (toscalar(
    _Retrievals
    | where ResultType == "Success"
    | summarize Count = dcount(requestUri_s) by OperationName, CallerObjectId
    | where Count > DistinctSecretsThreshold
    | summarize make_set(CallerObjectId,10000)
))
| extend
    requestUri_s = column_ifexists("requestUri_s", ""),
    id_s = column_ifexists("id_s", ""),
    CallerIPAddress = column_ifexists("CallerIPAddress", ""),
    clientInfo_s = column_ifexists("clientInfo_s", "")
| summarize
    EventCount = count(),
    StartTime = min(TimeGenerated),
    EndTime = max(TimeGenerated),
    ResourceList = make_set(Resource, 50),
    OperationNameList = make_set(OperationName, 50),
    RequestURLList = make_set(requestUri_s, 50),
    ResourceId = max(ResourceId),
    CallerIPList = make_set(CallerIPAddress, 50),
    clientInfo_sList = make_set(clientInfo_s, 50),
    CallerIPMax = max(CallerIPAddress)
    by ResourceType, ResultType, identity_claim_appid_g, CallerObjectId, CallerObjectUPN
    | where EventCount > EventCountThreshold
| project-reorder StartTime, EndTime, EventCount, ResourceId,ResourceType,identity_claim_appid_g, CallerObjectId, CallerObjectUPN, ResultType, ResourceList, OperationNameList, RequestURLList, CallerIPList, clientInfo_sList
| extend timestamp = EndTime
name: Mass secret retrieval from Azure Key Vault
status: Available
triggerThreshold: 0
severity: Low
tactics:
- CredentialAccess
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Azure Key Vault/Analytic Rules/KeyvaultMassSecretRetrieval.yaml
entityMappings:
- entityType: Account
  fieldMappings:
  - columnName: CallerObjectId
    identifier: Name
- entityType: IP
  fieldMappings:
  - columnName: CallerIPMax
    identifier: Address
queryPeriod: 1d
queryFrequency: 1d
version: 1.0.7
triggerOperator: gt
description: |
  'Identifies mass secret retrieval from Azure Key Vault observed by a single user. 
  Mass secret retrival crossing a certain threshold is an indication of credential dump operations or mis-configured applications. 
  You can tweak the EventCountThreshold based on average count seen in your environment 
  and also filter any known sources (IP/Account) and useragent combinations based on historical analysis to further reduce noise'  
query: |
  let DistinctSecretsThreshold = 10;
  let EventCountThreshold = 50;
  // To avoid any False Positives, filtering using AppId is recommended.
  // The AppId 509e4652-da8d-478d-a730-e9d4a1996ca4 has been added in the query as it corresponds to Azure Resource Graph performing VaultGet operations for indexing and syncing all tracked resources across Azure.
  // The AppId 8cae6e77-e04e-42ce-b5cb-50d82bce26b1 has been added as it correspond to Microsoft Policy Insights Provider Data Plane performing VaultGet operations for policies checks.
  let AllowedAppId = dynamic(["509e4652-da8d-478d-a730-e9d4a1996ca4","8cae6e77-e04e-42ce-b5cb-50d82bce26b1"]);
  let OperationList = dynamic(["SecretGet", "KeyGet", "VaultGet"]);
  AzureDiagnostics
  | where OperationName in (OperationList) and ResourceType =~ "VAULTS"
  | where not(identity_claim_appid_g in (AllowedAppId) and OperationName == 'VaultGet')
  | extend
      ResourceId,
      ResultType = column_ifexists("ResultType", ""),
      identity_claim_http_schemas_microsoft_com_identity_claims_objectidentifier_g = column_ifexists("identity_claim_http_schemas_microsoft_com_identity_claims_objectidentifier_g", ""),
      identity_claim_http_schemas_xmlsoap_org_ws_2005_05_identity_claims_upn_s = column_ifexists("identity_claim_http_schemas_xmlsoap_org_ws_2005_05_identity_claims_upn_s", ""),
      identity_claim_oid_g = column_ifexists("identity_claim_oid_g", ""),
      identity_claim_upn_s = column_ifexists("identity_claim_upn_s", "")
  | extend
      CallerObjectId = iff(isempty(identity_claim_oid_g), identity_claim_http_schemas_microsoft_com_identity_claims_objectidentifier_g, identity_claim_oid_g),
      CallerObjectUPN = iff(isempty(identity_claim_upn_s), identity_claim_http_schemas_xmlsoap_org_ws_2005_05_identity_claims_upn_s, identity_claim_upn_s)
  | as _Retrievals
  | where CallerObjectId in (toscalar(
      _Retrievals
      | where ResultType == "Success"
      | summarize Count = dcount(requestUri_s) by OperationName, CallerObjectId
      | where Count > DistinctSecretsThreshold
      | summarize make_set(CallerObjectId,10000)
  ))
  | extend
      requestUri_s = column_ifexists("requestUri_s", ""),
      id_s = column_ifexists("id_s", ""),
      CallerIPAddress = column_ifexists("CallerIPAddress", ""),
      clientInfo_s = column_ifexists("clientInfo_s", "")
  | summarize
      EventCount = count(),
      StartTime = min(TimeGenerated),
      EndTime = max(TimeGenerated),
      ResourceList = make_set(Resource, 50),
      OperationNameList = make_set(OperationName, 50),
      RequestURLList = make_set(requestUri_s, 50),
      ResourceId = max(ResourceId),
      CallerIPList = make_set(CallerIPAddress, 50),
      clientInfo_sList = make_set(clientInfo_s, 50),
      CallerIPMax = max(CallerIPAddress)
      by ResourceType, ResultType, identity_claim_appid_g, CallerObjectId, CallerObjectUPN
      | where EventCount > EventCountThreshold
  | project-reorder StartTime, EndTime, EventCount, ResourceId,ResourceType,identity_claim_appid_g, CallerObjectId, CallerObjectUPN, ResultType, ResourceList, OperationNameList, RequestURLList, CallerIPList, clientInfo_sList
  | extend timestamp = EndTime  
relevantTechniques:
- T1003
id: 24f8c234-d1ff-40ec-8b73-96b17a3a9c1c
requiredDataConnectors:
- dataTypes:
  - KeyVaultData
  connectorId: AzureKeyVault
kind: Scheduled
{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "workspace": {
      "type": "String"
    }
  },
  "resources": [
    {
      "apiVersion": "2023-02-01-preview",
      "id": "[concat(resourceId('Microsoft.OperationalInsights/workspaces/providers', parameters('workspace'), 'Microsoft.SecurityInsights'),'/alertRules/24f8c234-d1ff-40ec-8b73-96b17a3a9c1c')]",
      "kind": "Scheduled",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/24f8c234-d1ff-40ec-8b73-96b17a3a9c1c')]",
      "properties": {
        "alertRuleTemplateName": "24f8c234-d1ff-40ec-8b73-96b17a3a9c1c",
        "customDetails": null,
        "description": "'Identifies mass secret retrieval from Azure Key Vault observed by a single user. \nMass secret retrival crossing a certain threshold is an indication of credential dump operations or mis-configured applications. \nYou can tweak the EventCountThreshold based on average count seen in your environment \nand also filter any known sources (IP/Account) and useragent combinations based on historical analysis to further reduce noise'\n",
        "displayName": "Mass secret retrieval from Azure Key Vault",
        "enabled": true,
        "entityMappings": [
          {
            "entityType": "Account",
            "fieldMappings": [
              {
                "columnName": "CallerObjectId",
                "identifier": "Name"
              }
            ]
          },
          {
            "entityType": "IP",
            "fieldMappings": [
              {
                "columnName": "CallerIPMax",
                "identifier": "Address"
              }
            ]
          }
        ],
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Azure Key Vault/Analytic Rules/KeyvaultMassSecretRetrieval.yaml",
        "query": "let DistinctSecretsThreshold = 10;\nlet EventCountThreshold = 50;\n// To avoid any False Positives, filtering using AppId is recommended.\n// The AppId 509e4652-da8d-478d-a730-e9d4a1996ca4 has been added in the query as it corresponds to Azure Resource Graph performing VaultGet operations for indexing and syncing all tracked resources across Azure.\n// The AppId 8cae6e77-e04e-42ce-b5cb-50d82bce26b1 has been added as it correspond to Microsoft Policy Insights Provider Data Plane performing VaultGet operations for policies checks.\nlet AllowedAppId = dynamic([\"509e4652-da8d-478d-a730-e9d4a1996ca4\",\"8cae6e77-e04e-42ce-b5cb-50d82bce26b1\"]);\nlet OperationList = dynamic([\"SecretGet\", \"KeyGet\", \"VaultGet\"]);\nAzureDiagnostics\n| where OperationName in (OperationList) and ResourceType =~ \"VAULTS\"\n| where not(identity_claim_appid_g in (AllowedAppId) and OperationName == 'VaultGet')\n| extend\n    ResourceId,\n    ResultType = column_ifexists(\"ResultType\", \"\"),\n    identity_claim_http_schemas_microsoft_com_identity_claims_objectidentifier_g = column_ifexists(\"identity_claim_http_schemas_microsoft_com_identity_claims_objectidentifier_g\", \"\"),\n    identity_claim_http_schemas_xmlsoap_org_ws_2005_05_identity_claims_upn_s = column_ifexists(\"identity_claim_http_schemas_xmlsoap_org_ws_2005_05_identity_claims_upn_s\", \"\"),\n    identity_claim_oid_g = column_ifexists(\"identity_claim_oid_g\", \"\"),\n    identity_claim_upn_s = column_ifexists(\"identity_claim_upn_s\", \"\")\n| extend\n    CallerObjectId = iff(isempty(identity_claim_oid_g), identity_claim_http_schemas_microsoft_com_identity_claims_objectidentifier_g, identity_claim_oid_g),\n    CallerObjectUPN = iff(isempty(identity_claim_upn_s), identity_claim_http_schemas_xmlsoap_org_ws_2005_05_identity_claims_upn_s, identity_claim_upn_s)\n| as _Retrievals\n| where CallerObjectId in (toscalar(\n    _Retrievals\n    | where ResultType == \"Success\"\n    | summarize Count = dcount(requestUri_s) by OperationName, CallerObjectId\n    | where Count > DistinctSecretsThreshold\n    | summarize make_set(CallerObjectId,10000)\n))\n| extend\n    requestUri_s = column_ifexists(\"requestUri_s\", \"\"),\n    id_s = column_ifexists(\"id_s\", \"\"),\n    CallerIPAddress = column_ifexists(\"CallerIPAddress\", \"\"),\n    clientInfo_s = column_ifexists(\"clientInfo_s\", \"\")\n| summarize\n    EventCount = count(),\n    StartTime = min(TimeGenerated),\n    EndTime = max(TimeGenerated),\n    ResourceList = make_set(Resource, 50),\n    OperationNameList = make_set(OperationName, 50),\n    RequestURLList = make_set(requestUri_s, 50),\n    ResourceId = max(ResourceId),\n    CallerIPList = make_set(CallerIPAddress, 50),\n    clientInfo_sList = make_set(clientInfo_s, 50),\n    CallerIPMax = max(CallerIPAddress)\n    by ResourceType, ResultType, identity_claim_appid_g, CallerObjectId, CallerObjectUPN\n    | where EventCount > EventCountThreshold\n| project-reorder StartTime, EndTime, EventCount, ResourceId,ResourceType,identity_claim_appid_g, CallerObjectId, CallerObjectUPN, ResultType, ResourceList, OperationNameList, RequestURLList, CallerIPList, clientInfo_sList\n| extend timestamp = EndTime\n",
        "queryFrequency": "P1D",
        "queryPeriod": "P1D",
        "severity": "Low",
        "status": "Available",
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "CredentialAccess"
        ],
        "techniques": [
          "T1003"
        ],
        "templateVersion": "1.0.7",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0
      },
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
    }
  ]
}