Back
Id7ab54aed-f97e-4202-a624-3cbd496c3b68
RulenameDelinea - Bulk secret export / access
DescriptionDetects a single user accessing or exporting an unusually large number of distinct secrets in

Delinea Secret Server within a short window. In addition to secret views, this rule also matches

export / download / retrieve operations, which are a stronger signal of vault scraping prior to

exfiltration (“secret hoarding”). Tune ’threshold’ to your environment’s normal access patterns.
SeverityMedium
TacticsCredentialAccess
Exfiltration
TechniquesT1555
T1212
Required data connectorsDelineaPlatformConnector
KindScheduled
Query frequency30m
Query period1h
Trigger threshold0
Trigger operatorgt
Source Urihttps://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Delinea%20Platform/Analytic%20Rules/DelineaMassSecretAccess.yaml
Version1.3.1
Arm template7ab54aed-f97e-4202-a624-3cbd496c3b68.json
Deploy To Azure
let threshold = 10;
// Must stay <= queryPeriod. Wider than queryFrequency so a burst that straddles two runs
// still reaches the threshold.
let lookback = 1h;
// Must equal queryFrequency. A user is only evaluated when a secret event of theirs was
// ingested since the previous run, so the next run does not re-alert on a burst it has
// already counted - see 'Delinea - Failed authentication spike'.
let newSince = 30m;
let secretEventPattern = @"(?i)\.Secret\.(Viewed|Exported|Downloaded|Retrieved|Copied)";
let secretEvents =
    DelineaAuditEvents_CL
    | where TimeGenerated > ago(lookback)
    | extend IngestedAt = ingestion_time()
    | extend d = parse_json(RawData)
    | extend EventName = tostring(d.eventType.name), SrcIP = tostring(d.source.host.network.ipAddress)
    | where EventName matches regex secretEventPattern;
let recentUsers = secretEvents | where IngestedAt > ago(newSince) | distinct User;
secretEvents
| where User in (recentUsers)
| extend IsExport = EventName has_any ("Exported", "Downloaded", "Retrieved", "Copied")
| summarize DistinctSecrets = dcount(SecretId), Secrets = make_set(SecretId, 50),
            TotalOperations = count(), Exports = countif(IsExport), Secret = take_any(SecretId),
            StartTime = min(TimeGenerated), EndTime = max(TimeGenerated)
        by User, SrcIP
| where DistinctSecrets >= threshold
| sort by DistinctSecrets desc
incidentConfiguration:
  groupingConfiguration:
    lookbackDuration: P1D
    reopenClosedIncident: false
    groupByEntities:
    - Account
    matchingMethod: Selected
    enabled: true
  createIncident: true
triggerOperator: gt
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Delinea%20Platform/Analytic%20Rules/DelineaMassSecretAccess.yaml
triggerThreshold: 0
id: 7ab54aed-f97e-4202-a624-3cbd496c3b68
kind: Scheduled
relevantTechniques:
- T1555
- T1212
version: 1.3.1
tactics:
- CredentialAccess
- Exfiltration
queryPeriod: 1h
queryFrequency: 30m
severity: Medium
name: Delinea - Bulk secret export / access
customDetails:
  DistinctSecrets: DistinctSecrets
  Exports: Exports
  TotalOperations: TotalOperations
requiredDataConnectors:
- connectorId: DelineaPlatformConnector
  dataTypes:
  - DelineaAuditEvents_CL
entityMappings:
- entityType: Account
  fieldMappings:
  - identifier: Name
    columnName: User
- entityType: IP
  fieldMappings:
  - identifier: Address
    columnName: SrcIP
description: |
  Detects a single user accessing or exporting an unusually large number of distinct secrets in
  Delinea Secret Server within a short window. In addition to secret views, this rule also matches
  export / download / retrieve operations, which are a stronger signal of vault scraping prior to
  exfiltration ("secret hoarding"). Tune 'threshold' to your environment's normal access patterns.
eventGroupingSettings:
  aggregationKind: AlertPerResult
status: Available
query: |
  let threshold = 10;
  // Must stay <= queryPeriod. Wider than queryFrequency so a burst that straddles two runs
  // still reaches the threshold.
  let lookback = 1h;
  // Must equal queryFrequency. A user is only evaluated when a secret event of theirs was
  // ingested since the previous run, so the next run does not re-alert on a burst it has
  // already counted - see 'Delinea - Failed authentication spike'.
  let newSince = 30m;
  let secretEventPattern = @"(?i)\.Secret\.(Viewed|Exported|Downloaded|Retrieved|Copied)";
  let secretEvents =
      DelineaAuditEvents_CL
      | where TimeGenerated > ago(lookback)
      | extend IngestedAt = ingestion_time()
      | extend d = parse_json(RawData)
      | extend EventName = tostring(d.eventType.name), SrcIP = tostring(d.source.host.network.ipAddress)
      | where EventName matches regex secretEventPattern;
  let recentUsers = secretEvents | where IngestedAt > ago(newSince) | distinct User;
  secretEvents
  | where User in (recentUsers)
  | extend IsExport = EventName has_any ("Exported", "Downloaded", "Retrieved", "Copied")
  | summarize DistinctSecrets = dcount(SecretId), Secrets = make_set(SecretId, 50),
              TotalOperations = count(), Exports = countif(IsExport), Secret = take_any(SecretId),
              StartTime = min(TimeGenerated), EndTime = max(TimeGenerated)
          by User, SrcIP
  | where DistinctSecrets >= threshold
  | sort by DistinctSecrets desc
{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "workspace": {
      "type": "String"
    }
  },
  "resources": [
    {
      "apiVersion": "2024-01-01-preview",
      "id": "[concat(resourceId('Microsoft.OperationalInsights/workspaces/providers', parameters('workspace'), 'Microsoft.SecurityInsights'),'/alertRules/7ab54aed-f97e-4202-a624-3cbd496c3b68')]",
      "kind": "Scheduled",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/7ab54aed-f97e-4202-a624-3cbd496c3b68')]",
      "properties": {
        "alertRuleTemplateName": "7ab54aed-f97e-4202-a624-3cbd496c3b68",
        "customDetails": {
          "DistinctSecrets": "DistinctSecrets",
          "Exports": "Exports",
          "TotalOperations": "TotalOperations"
        },
        "description": "Detects a single user accessing or exporting an unusually large number of distinct secrets in\nDelinea Secret Server within a short window. In addition to secret views, this rule also matches\nexport / download / retrieve operations, which are a stronger signal of vault scraping prior to\nexfiltration (\"secret hoarding\"). Tune 'threshold' to your environment's normal access patterns.\n",
        "displayName": "Delinea - Bulk secret export / access",
        "enabled": true,
        "entityMappings": [
          {
            "entityType": "Account",
            "fieldMappings": [
              {
                "columnName": "User",
                "identifier": "Name"
              }
            ]
          },
          {
            "entityType": "IP",
            "fieldMappings": [
              {
                "columnName": "SrcIP",
                "identifier": "Address"
              }
            ]
          }
        ],
        "eventGroupingSettings": {
          "aggregationKind": "AlertPerResult"
        },
        "incidentConfiguration": {
          "createIncident": true,
          "groupingConfiguration": {
            "enabled": true,
            "groupByEntities": [
              "Account"
            ],
            "lookbackDuration": "P1D",
            "matchingMethod": "Selected",
            "reopenClosedIncident": false
          }
        },
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Delinea%20Platform/Analytic%20Rules/DelineaMassSecretAccess.yaml",
        "query": "let threshold = 10;\n// Must stay <= queryPeriod. Wider than queryFrequency so a burst that straddles two runs\n// still reaches the threshold.\nlet lookback = 1h;\n// Must equal queryFrequency. A user is only evaluated when a secret event of theirs was\n// ingested since the previous run, so the next run does not re-alert on a burst it has\n// already counted - see 'Delinea - Failed authentication spike'.\nlet newSince = 30m;\nlet secretEventPattern = @\"(?i)\\.Secret\\.(Viewed|Exported|Downloaded|Retrieved|Copied)\";\nlet secretEvents =\n    DelineaAuditEvents_CL\n    | where TimeGenerated > ago(lookback)\n    | extend IngestedAt = ingestion_time()\n    | extend d = parse_json(RawData)\n    | extend EventName = tostring(d.eventType.name), SrcIP = tostring(d.source.host.network.ipAddress)\n    | where EventName matches regex secretEventPattern;\nlet recentUsers = secretEvents | where IngestedAt > ago(newSince) | distinct User;\nsecretEvents\n| where User in (recentUsers)\n| extend IsExport = EventName has_any (\"Exported\", \"Downloaded\", \"Retrieved\", \"Copied\")\n| summarize DistinctSecrets = dcount(SecretId), Secrets = make_set(SecretId, 50),\n            TotalOperations = count(), Exports = countif(IsExport), Secret = take_any(SecretId),\n            StartTime = min(TimeGenerated), EndTime = max(TimeGenerated)\n        by User, SrcIP\n| where DistinctSecrets >= threshold\n| sort by DistinctSecrets desc\n",
        "queryFrequency": "PT30M",
        "queryPeriod": "PT1H",
        "severity": "Medium",
        "status": "Available",
        "subTechniques": [],
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "CredentialAccess",
          "Exfiltration"
        ],
        "techniques": [
          "T1212",
          "T1555"
        ],
        "templateVersion": "1.3.1",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0
      },
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
    }
  ]
}