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

Dataverse - User bulk retrieval outside normal activity

Back
Id08cb7ffc-59c6-4e7d-88e0-327371c9431b
RulenameDataverse - User bulk retrieval outside normal activity
DescriptionIdentifies users retrieving significantly more records from Dataverse than they have previously in the past 2 weeks.
SeverityLow
TacticsExfiltration
TechniquesT1048
Required data connectorsDataverse
KindScheduled
Query frequency1d
Query period14d
Trigger threshold0
Trigger operatorgt
Source Urihttps://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Microsoft Business Applications/Analytic Rules/Dataverse - User bulk retrieval outside normal activity.yaml
Version3.2.0
Arm template08cb7ffc-59c6-4e7d-88e0-327371c9431b.json
Deploy To Azure
let baseline_time = 14d;
let detection_time = 1d;
DataverseActivity
| where TimeGenerated between(ago(baseline_time) .. ago(detection_time - 1d))
| where Message == "RetrieveMultiple"
| extend numQueryCount = todouble(QueryResults)
| extend QueryCount = iif(QueryResults contains ",", todouble(countof(tostring(QueryResults), ',') + 1), numQueryCount)
| extend QueryCount = iif(isnotempty(QueryCount), QueryCount, double(1))
| summarize sum(QueryCount) by UserId
| extend HistoricalBaseline = sum_QueryCount
| join kind=inner (
    DataverseActivity
    | where TimeGenerated > ago(detection_time)
    | where Message == "RetrieveMultiple"
    | extend numQueryCount = todouble(QueryResults)
    | extend QueryCount = iif(QueryResults contains ",", todouble(countof(tostring(QueryResults), ',') + 1), numQueryCount)
    | extend QueryCount = iif(isnotempty(QueryCount), QueryCount, double(1))
    | summarize sum(QueryCount) by UserId
    | extend CurrentExportRate = sum_QueryCount)
    on UserId
| where CurrentExportRate > HistoricalBaseline
| project UserId, HistoricalBaseline, CurrentExportRate
| join kind=inner(
    DataverseActivity
    | where TimeGenerated > ago(detection_time)
    | where Message == "RetrieveMultiple"
    | extend numQueryCount = todouble(QueryResults)
    | extend QueryCount = iif(QueryResults contains ",", todouble(countof(tostring(QueryResults), ',') + 1), numQueryCount)
    | extend QueryCount = iif(isnotempty(QueryCount), QueryCount, double(1)))
    on UserId
| summarize
    QuerySizes = make_set(QueryCount),
    MostRecentQuery = max(TimeGenerated),
    IPs = make_set(ClientIp),
    UserAgents = make_set(UserAgent),
    Entities = make_set(EntityName),
    Queries = make_set(Query)
    by UserId, InstanceUrl, HistoricalBaseline, CurrentExportRate
| extend
    AccountName = tostring(split(UserId, '@')[0]),
    UPNSuffix = tostring(split(UserId, '@')[1]),
    CloudAppId = int(32780)
| project
    MostRecentQuery,
    UserId,
    IPs,
    UserAgents,
    InstanceUrl,
    Queries,
    QuerySizes,
    Entities,
    HistoricalBaseline,
    CurrentExportRate,
    AccountName,
    UPNSuffix,
    CloudAppId
relevantTechniques:
- T1048
name: Dataverse - User bulk retrieval outside normal activity
queryPeriod: 14d
triggerThreshold: 0
customDetails: {}
alertDetailsOverride:
  alertDescriptionFormat: '{{UserId}} exported {{CurrentExportRate}} records, far beyond the historical baseline of {{{HistoricalBaseline}}.'
  alertDisplayNameFormat: Dataverse - Bulk record retrieval outside of normal activity
id: 08cb7ffc-59c6-4e7d-88e0-327371c9431b
eventGroupingSettings:
  aggregationKind: AlertPerResult
severity: Low
requiredDataConnectors:
- dataTypes:
  - DataverseActivity
  connectorId: Dataverse
description: Identifies users retrieving significantly more records from Dataverse than they have previously in the past 2 weeks.
version: 3.2.0
status: Available
entityMappings:
- entityType: Account
  fieldMappings:
  - columnName: AccountName
    identifier: Name
  - columnName: UPNSuffix
    identifier: UPNSuffix
- entityType: CloudApplication
  fieldMappings:
  - columnName: CloudAppId
    identifier: AppId
  - columnName: InstanceUrl
    identifier: InstanceName
tactics:
- Exfiltration
query: |
  let baseline_time = 14d;
  let detection_time = 1d;
  DataverseActivity
  | where TimeGenerated between(ago(baseline_time) .. ago(detection_time - 1d))
  | where Message == "RetrieveMultiple"
  | extend numQueryCount = todouble(QueryResults)
  | extend QueryCount = iif(QueryResults contains ",", todouble(countof(tostring(QueryResults), ',') + 1), numQueryCount)
  | extend QueryCount = iif(isnotempty(QueryCount), QueryCount, double(1))
  | summarize sum(QueryCount) by UserId
  | extend HistoricalBaseline = sum_QueryCount
  | join kind=inner (
      DataverseActivity
      | where TimeGenerated > ago(detection_time)
      | where Message == "RetrieveMultiple"
      | extend numQueryCount = todouble(QueryResults)
      | extend QueryCount = iif(QueryResults contains ",", todouble(countof(tostring(QueryResults), ',') + 1), numQueryCount)
      | extend QueryCount = iif(isnotempty(QueryCount), QueryCount, double(1))
      | summarize sum(QueryCount) by UserId
      | extend CurrentExportRate = sum_QueryCount)
      on UserId
  | where CurrentExportRate > HistoricalBaseline
  | project UserId, HistoricalBaseline, CurrentExportRate
  | join kind=inner(
      DataverseActivity
      | where TimeGenerated > ago(detection_time)
      | where Message == "RetrieveMultiple"
      | extend numQueryCount = todouble(QueryResults)
      | extend QueryCount = iif(QueryResults contains ",", todouble(countof(tostring(QueryResults), ',') + 1), numQueryCount)
      | extend QueryCount = iif(isnotempty(QueryCount), QueryCount, double(1)))
      on UserId
  | summarize
      QuerySizes = make_set(QueryCount),
      MostRecentQuery = max(TimeGenerated),
      IPs = make_set(ClientIp),
      UserAgents = make_set(UserAgent),
      Entities = make_set(EntityName),
      Queries = make_set(Query)
      by UserId, InstanceUrl, HistoricalBaseline, CurrentExportRate
  | extend
      AccountName = tostring(split(UserId, '@')[0]),
      UPNSuffix = tostring(split(UserId, '@')[1]),
      CloudAppId = int(32780)
  | project
      MostRecentQuery,
      UserId,
      IPs,
      UserAgents,
      InstanceUrl,
      Queries,
      QuerySizes,
      Entities,
      HistoricalBaseline,
      CurrentExportRate,
      AccountName,
      UPNSuffix,
      CloudAppId  
kind: Scheduled
triggerOperator: gt
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Microsoft Business Applications/Analytic Rules/Dataverse - User bulk retrieval outside normal activity.yaml
queryFrequency: 1d
{
  "$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/08cb7ffc-59c6-4e7d-88e0-327371c9431b')]",
      "kind": "Scheduled",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/08cb7ffc-59c6-4e7d-88e0-327371c9431b')]",
      "properties": {
        "alertDetailsOverride": {
          "alertDescriptionFormat": "{{UserId}} exported {{CurrentExportRate}} records, far beyond the historical baseline of {{{HistoricalBaseline}}.",
          "alertDisplayNameFormat": "Dataverse - Bulk record retrieval outside of normal activity"
        },
        "alertRuleTemplateName": "08cb7ffc-59c6-4e7d-88e0-327371c9431b",
        "customDetails": {},
        "description": "Identifies users retrieving significantly more records from Dataverse than they have previously in the past 2 weeks.",
        "displayName": "Dataverse - User bulk retrieval outside normal activity",
        "enabled": true,
        "entityMappings": [
          {
            "entityType": "Account",
            "fieldMappings": [
              {
                "columnName": "AccountName",
                "identifier": "Name"
              },
              {
                "columnName": "UPNSuffix",
                "identifier": "UPNSuffix"
              }
            ]
          },
          {
            "entityType": "CloudApplication",
            "fieldMappings": [
              {
                "columnName": "CloudAppId",
                "identifier": "AppId"
              },
              {
                "columnName": "InstanceUrl",
                "identifier": "InstanceName"
              }
            ]
          }
        ],
        "eventGroupingSettings": {
          "aggregationKind": "AlertPerResult"
        },
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Microsoft Business Applications/Analytic Rules/Dataverse - User bulk retrieval outside normal activity.yaml",
        "query": "let baseline_time = 14d;\nlet detection_time = 1d;\nDataverseActivity\n| where TimeGenerated between(ago(baseline_time) .. ago(detection_time - 1d))\n| where Message == \"RetrieveMultiple\"\n| extend numQueryCount = todouble(QueryResults)\n| extend QueryCount = iif(QueryResults contains \",\", todouble(countof(tostring(QueryResults), ',') + 1), numQueryCount)\n| extend QueryCount = iif(isnotempty(QueryCount), QueryCount, double(1))\n| summarize sum(QueryCount) by UserId\n| extend HistoricalBaseline = sum_QueryCount\n| join kind=inner (\n    DataverseActivity\n    | where TimeGenerated > ago(detection_time)\n    | where Message == \"RetrieveMultiple\"\n    | extend numQueryCount = todouble(QueryResults)\n    | extend QueryCount = iif(QueryResults contains \",\", todouble(countof(tostring(QueryResults), ',') + 1), numQueryCount)\n    | extend QueryCount = iif(isnotempty(QueryCount), QueryCount, double(1))\n    | summarize sum(QueryCount) by UserId\n    | extend CurrentExportRate = sum_QueryCount)\n    on UserId\n| where CurrentExportRate > HistoricalBaseline\n| project UserId, HistoricalBaseline, CurrentExportRate\n| join kind=inner(\n    DataverseActivity\n    | where TimeGenerated > ago(detection_time)\n    | where Message == \"RetrieveMultiple\"\n    | extend numQueryCount = todouble(QueryResults)\n    | extend QueryCount = iif(QueryResults contains \",\", todouble(countof(tostring(QueryResults), ',') + 1), numQueryCount)\n    | extend QueryCount = iif(isnotempty(QueryCount), QueryCount, double(1)))\n    on UserId\n| summarize\n    QuerySizes = make_set(QueryCount),\n    MostRecentQuery = max(TimeGenerated),\n    IPs = make_set(ClientIp),\n    UserAgents = make_set(UserAgent),\n    Entities = make_set(EntityName),\n    Queries = make_set(Query)\n    by UserId, InstanceUrl, HistoricalBaseline, CurrentExportRate\n| extend\n    AccountName = tostring(split(UserId, '@')[0]),\n    UPNSuffix = tostring(split(UserId, '@')[1]),\n    CloudAppId = int(32780)\n| project\n    MostRecentQuery,\n    UserId,\n    IPs,\n    UserAgents,\n    InstanceUrl,\n    Queries,\n    QuerySizes,\n    Entities,\n    HistoricalBaseline,\n    CurrentExportRate,\n    AccountName,\n    UPNSuffix,\n    CloudAppId\n",
        "queryFrequency": "P1D",
        "queryPeriod": "P14D",
        "severity": "Low",
        "status": "Available",
        "subTechniques": [],
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "Exfiltration"
        ],
        "techniques": [
          "T1048"
        ],
        "templateVersion": "3.2.0",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0
      },
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
    }
  ]
}