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
queryFrequency: 30m
entityMappings:
- fieldMappings:
  - columnName: User
    identifier: Name
  entityType: Account
- fieldMappings:
  - columnName: SrcIP
    identifier: Address
  entityType: IP
incidentConfiguration:
  createIncident: true
  groupingConfiguration:
    groupByEntities:
    - Account
    reopenClosedIncident: false
    matchingMethod: Selected
    lookbackDuration: P1D
    enabled: true
triggerThreshold: 0
triggerOperator: gt
severity: Medium
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Delinea%20Platform/Analytic%20Rules/DelineaMassSecretAccess.yaml
eventGroupingSettings:
  aggregationKind: AlertPerResult
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
tactics:
- CredentialAccess
- Exfiltration
queryPeriod: 1h
customDetails:
  DistinctSecrets: DistinctSecrets
  Exports: Exports
  TotalOperations: TotalOperations
relevantTechniques:
- T1555
- T1212
requiredDataConnectors:
- connectorId: DelineaPlatformConnector
  dataTypes:
  - DelineaAuditEvents_CL
id: 7ab54aed-f97e-4202-a624-3cbd496c3b68
kind: Scheduled
version: 1.3.1
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.
status: Available
name: Delinea - Bulk secret export / access
{
  "$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"
    }
  ]
}