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

Dataverse - New non-interactive identity granted access

Back
Id682e230c-e5da-4085-8666-701d1f1be7de
RulenameDataverse - New non-interactive identity granted access
DescriptionIdentifies API level access grants, either via the delegated permissions of a Microsoft Entra application or direct assignment within Dataverse as an application user.
SeverityInformational
TacticsPersistence
LateralMovement
PrivilegeEscalation
TechniquesT1098
T0859
T1078
Required data connectorsAzureActiveDirectory
Dataverse
KindScheduled
Query frequency1h
Query period14d
Trigger threshold0
Trigger operatorgt
Source Urihttps://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Microsoft Business Applications/Analytic Rules/Dataverse - New non-interactive identity granted access.yaml
Version3.2.0
Arm template682e230c-e5da-4085-8666-701d1f1be7de.json
Deploy To Azure
let dataverse_app_id = "00000007-0000-0000-c000-000000000000";
let query_frequency = 1h;
let azure_ad_changes = AuditLogs
    | where TimeGenerated >= ago(query_frequency)
    | where OperationName =~ 'Update application'
    | where TargetResources has dataverse_app_id
    | extend TargetAppName = tostring(TargetResources[0].displayName)
    | extend TargetAppId = tostring(TargetResources[0].id)
    | extend UserId = tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName)
    | extend ClientIp = tostring(parse_json(tostring(InitiatedBy.user)).ipAddress)
    | extend NewData = tostring(parse_json(tostring(parse_json(TargetResources)[0].modifiedProperties))[0].newValue)
    | where NewData has dataverse_app_id;
let dataverse_changes = DataverseActivity
    | where TimeGenerated >= ago(query_frequency)
    | where (Message == "Create" and EntityName == "systemuser" and parse_json(Fields)[0].Name == "applicationid")
    | extend TargetAppId = tostring(Fields[0].Value);
union azure_ad_changes, dataverse_changes
| extend
    CloudAppId = int(32780),
    AccountName = tostring(split(UserId, '@')[0]),
    UPNSuffix = tostring(split(UserId, '@')[1])
| project
    TimeGenerated,
    UserId,
    ClientIp,
    TargetAppName,
    TargetAppId,
    InstanceUrl,
    CloudAppId,
    AccountName,
    UPNSuffix
relevantTechniques:
- T1098
- T0859
- T1078
name: Dataverse - New non-interactive identity granted access
queryPeriod: 14d
triggerThreshold: 0
alertDetailsOverride:
  alertDescriptionFormat: '{{UserId}} granted access to an Azure AD app {{{TargetAppName}}. Check to validate this access was authorized.'
  alertDisplayNameFormat: Dataverse - new non-interactive access granted
id: 682e230c-e5da-4085-8666-701d1f1be7de
eventGroupingSettings:
  aggregationKind: AlertPerResult
severity: Informational
requiredDataConnectors:
- dataTypes:
  - DataverseActivity
  connectorId: Dataverse
- dataTypes:
  - AuditLogs
  connectorId: AzureActiveDirectory
description: Identifies API level access grants, either via the delegated permissions of a Microsoft Entra application or direct assignment within Dataverse as an application user.
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
- entityType: IP
  fieldMappings:
  - columnName: ClientIp
    identifier: Address
- entityType: Account
  fieldMappings:
  - columnName: TargetAppId
    identifier: AadUserId
tactics:
- Persistence
- LateralMovement
- PrivilegeEscalation
query: |
  let dataverse_app_id = "00000007-0000-0000-c000-000000000000";
  let query_frequency = 1h;
  let azure_ad_changes = AuditLogs
      | where TimeGenerated >= ago(query_frequency)
      | where OperationName =~ 'Update application'
      | where TargetResources has dataverse_app_id
      | extend TargetAppName = tostring(TargetResources[0].displayName)
      | extend TargetAppId = tostring(TargetResources[0].id)
      | extend UserId = tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName)
      | extend ClientIp = tostring(parse_json(tostring(InitiatedBy.user)).ipAddress)
      | extend NewData = tostring(parse_json(tostring(parse_json(TargetResources)[0].modifiedProperties))[0].newValue)
      | where NewData has dataverse_app_id;
  let dataverse_changes = DataverseActivity
      | where TimeGenerated >= ago(query_frequency)
      | where (Message == "Create" and EntityName == "systemuser" and parse_json(Fields)[0].Name == "applicationid")
      | extend TargetAppId = tostring(Fields[0].Value);
  union azure_ad_changes, dataverse_changes
  | extend
      CloudAppId = int(32780),
      AccountName = tostring(split(UserId, '@')[0]),
      UPNSuffix = tostring(split(UserId, '@')[1])
  | project
      TimeGenerated,
      UserId,
      ClientIp,
      TargetAppName,
      TargetAppId,
      InstanceUrl,
      CloudAppId,
      AccountName,
      UPNSuffix  
kind: Scheduled
triggerOperator: gt
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Microsoft Business Applications/Analytic Rules/Dataverse - New non-interactive identity granted access.yaml
queryFrequency: 1h
{
  "$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/682e230c-e5da-4085-8666-701d1f1be7de')]",
      "kind": "Scheduled",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/682e230c-e5da-4085-8666-701d1f1be7de')]",
      "properties": {
        "alertDetailsOverride": {
          "alertDescriptionFormat": "{{UserId}} granted access to an Azure AD app {{{TargetAppName}}. Check to validate this access was authorized.",
          "alertDisplayNameFormat": "Dataverse - new non-interactive access granted"
        },
        "alertRuleTemplateName": "682e230c-e5da-4085-8666-701d1f1be7de",
        "customDetails": null,
        "description": "Identifies API level access grants, either via the delegated permissions of a Microsoft Entra application or direct assignment within Dataverse as an application user.",
        "displayName": "Dataverse - New non-interactive identity granted access",
        "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"
              }
            ]
          },
          {
            "entityType": "IP",
            "fieldMappings": [
              {
                "columnName": "ClientIp",
                "identifier": "Address"
              }
            ]
          },
          {
            "entityType": "Account",
            "fieldMappings": [
              {
                "columnName": "TargetAppId",
                "identifier": "AadUserId"
              }
            ]
          }
        ],
        "eventGroupingSettings": {
          "aggregationKind": "AlertPerResult"
        },
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Microsoft Business Applications/Analytic Rules/Dataverse - New non-interactive identity granted access.yaml",
        "query": "let dataverse_app_id = \"00000007-0000-0000-c000-000000000000\";\nlet query_frequency = 1h;\nlet azure_ad_changes = AuditLogs\n    | where TimeGenerated >= ago(query_frequency)\n    | where OperationName =~ 'Update application'\n    | where TargetResources has dataverse_app_id\n    | extend TargetAppName = tostring(TargetResources[0].displayName)\n    | extend TargetAppId = tostring(TargetResources[0].id)\n    | extend UserId = tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName)\n    | extend ClientIp = tostring(parse_json(tostring(InitiatedBy.user)).ipAddress)\n    | extend NewData = tostring(parse_json(tostring(parse_json(TargetResources)[0].modifiedProperties))[0].newValue)\n    | where NewData has dataverse_app_id;\nlet dataverse_changes = DataverseActivity\n    | where TimeGenerated >= ago(query_frequency)\n    | where (Message == \"Create\" and EntityName == \"systemuser\" and parse_json(Fields)[0].Name == \"applicationid\")\n    | extend TargetAppId = tostring(Fields[0].Value);\nunion azure_ad_changes, dataverse_changes\n| extend\n    CloudAppId = int(32780),\n    AccountName = tostring(split(UserId, '@')[0]),\n    UPNSuffix = tostring(split(UserId, '@')[1])\n| project\n    TimeGenerated,\n    UserId,\n    ClientIp,\n    TargetAppName,\n    TargetAppId,\n    InstanceUrl,\n    CloudAppId,\n    AccountName,\n    UPNSuffix\n",
        "queryFrequency": "PT1H",
        "queryPeriod": "P14D",
        "severity": "Informational",
        "status": "Available",
        "subTechniques": [],
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "LateralMovement",
          "Persistence",
          "PrivilegeEscalation"
        ],
        "techniques": [
          "T1078",
          "T1098"
        ],
        "templateVersion": "3.2.0",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0
      },
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
    }
  ]
}