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

Dataverse - TI map IP to DataverseActivity

Back
Id56d5aa0c-d871-4167-ba13-61c2f0fd17bf
RulenameDataverse - TI map IP to DataverseActivity
DescriptionIdentifies a match in DataverseActivity from any IP IOC from Microsoft Sentinel Threat Intelligence.
SeverityMedium
TacticsInitialAccess
LateralMovement
Discovery
TechniquesT1078
T1199
T1133
T0886
T0859
T1428
T1021
T1210
T1526
T1580
Required data connectorsDataverse
MicrosoftDefenderThreatIntelligence
ThreatIntelligence
ThreatIntelligenceTaxii
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 - TI map IP to DataverseActivity.yaml
Version3.2.0
Arm template56d5aa0c-d871-4167-ba13-61c2f0fd17bf.json
Deploy To Azure
let dt_lookBack = 1h;
let ioc_lookBack = 14d;
ThreatIntelligenceIndicator
| where TimeGenerated >= ago(ioc_lookBack) and ExpirationDateTime > now()
| summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by IndicatorId
| where Active == true
// Picking up only IOC's that contain the entities we want
| where isnotempty(NetworkIP)
    or isnotempty(EmailSourceIpAddress)
    or isnotempty(NetworkDestinationIP)
    or isnotempty(NetworkSourceIP)
// As there is potentially more than 1 indicator type for matching IP, taking NetworkIP first, then others if that is empty.
// Taking the first non-empty value based on potential IOC match availability
| extend TI_ipEntity = iff(isnotempty(NetworkIP), NetworkIP, NetworkDestinationIP)
| extend TI_ipEntity = iff(isempty(TI_ipEntity) and isnotempty(NetworkSourceIP), NetworkSourceIP, TI_ipEntity)
| extend TI_ipEntity = iff(isempty(TI_ipEntity) and isnotempty(EmailSourceIpAddress), EmailSourceIpAddress, TI_ipEntity)
//Exclude local addresses, using the ipv4_is_private operator
| where ipv4_is_private(TI_ipEntity) == false
    and TI_ipEntity !startswith "fe80"
    and TI_ipEntity !startswith "::"
    and TI_ipEntity !startswith "127."
// using innerunique to keep perf fast and result set low, we only need one match to indicate potential malicious activity that needs to be investigated
| join kind=innerunique (
    DataverseActivity
    | where TimeGenerated >= ago(dt_lookBack)
    | where isnotempty(ClientIp)
    //Exclude local addresses, using the ipv4_is_private operator
    | where ipv4_is_private(ClientIp) == false
        and ClientIp !startswith "fe80"
        and ClientIp !startswith "::"
        and ClientIp !startswith "127."
    // renaming time column so it is clear the log this came from
    | extend DataverseActivity_TimeGenerated = TimeGenerated
    )
    on $left.TI_ipEntity == $right.ClientIp
| where DataverseActivity_TimeGenerated < ExpirationDateTime
| summarize DataverseActivity_TimeGenerated = arg_max(DataverseActivity_TimeGenerated, *) by IndicatorId, ClientIp
| project DataverseActivity_TimeGenerated, Description, ActivityGroupNames, IndicatorId, ThreatType, Url, ExpirationDateTime, ConfidenceScore,
    TI_ipEntity, ClientIp, NetworkIP, NetworkDestinationIP, NetworkSourceIP, EmailSourceIpAddress, InstanceUrl, UserId
| extend
    timestamp = DataverseActivity_TimeGenerated,
    AccountName = tostring(split(UserId, '@')[0]),
    UPNSuffix = tostring(split(UserId, '@')[0]),
    CloudAppId = int(32780)
relevantTechniques:
- T1078
- T1199
- T1133
- T0886
- T0859
- T1428
- T1021
- T1210
- T1526
- T1580
name: Dataverse - TI map IP to DataverseActivity
queryPeriod: 14d
triggerThreshold: 0
alertDetailsOverride:
  alertDescriptionFormat: Malicous IP {{ClientIp}} was found in {{InstanceUrl}} . User affected is {{UserId}}
  alertDisplayNameFormat: 'Dataverse - TI map IP in {{InstanceUrl}} '
id: 56d5aa0c-d871-4167-ba13-61c2f0fd17bf
eventGroupingSettings:
  aggregationKind: AlertPerResult
severity: Medium
requiredDataConnectors:
- dataTypes:
  - DataverseActivity
  connectorId: Dataverse
- dataTypes:
  - ThreatIntelligenceIndicator
  connectorId: ThreatIntelligence
- dataTypes:
  - ThreatIntelligenceIndicator
  connectorId: ThreatIntelligenceTaxii
- dataTypes:
  - ThreatIntelligenceIndicator
  connectorId: MicrosoftDefenderThreatIntelligence
- dataTypes:
  - ThreatIntelligenceIndicator
  connectorId: ThreatIntelligence
- dataTypes:
  - ThreatIntelligenceIndicator
  connectorId: ThreatIntelligenceTaxii
- dataTypes:
  - ThreatIntelligenceIndicator
  connectorId: MicrosoftDefenderThreatIntelligence
description: Identifies a match in DataverseActivity from any IP IOC from Microsoft Sentinel Threat Intelligence.
version: 3.2.0
status: Available
entityMappings:
- entityType: Account
  fieldMappings:
  - columnName: AccountName
    identifier: Name
  - columnName: UPNSuffix
    identifier: UPNSuffix
- entityType: IP
  fieldMappings:
  - columnName: ClientIp
    identifier: Address
- entityType: URL
  fieldMappings:
  - columnName: Url
    identifier: Url
- entityType: CloudApplication
  fieldMappings:
  - columnName: CloudAppId
    identifier: AppId
  - columnName: InstanceUrl
    identifier: InstanceName
tactics:
- InitialAccess
- LateralMovement
- Discovery
query: |
  let dt_lookBack = 1h;
  let ioc_lookBack = 14d;
  ThreatIntelligenceIndicator
  | where TimeGenerated >= ago(ioc_lookBack) and ExpirationDateTime > now()
  | summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by IndicatorId
  | where Active == true
  // Picking up only IOC's that contain the entities we want
  | where isnotempty(NetworkIP)
      or isnotempty(EmailSourceIpAddress)
      or isnotempty(NetworkDestinationIP)
      or isnotempty(NetworkSourceIP)
  // As there is potentially more than 1 indicator type for matching IP, taking NetworkIP first, then others if that is empty.
  // Taking the first non-empty value based on potential IOC match availability
  | extend TI_ipEntity = iff(isnotempty(NetworkIP), NetworkIP, NetworkDestinationIP)
  | extend TI_ipEntity = iff(isempty(TI_ipEntity) and isnotempty(NetworkSourceIP), NetworkSourceIP, TI_ipEntity)
  | extend TI_ipEntity = iff(isempty(TI_ipEntity) and isnotempty(EmailSourceIpAddress), EmailSourceIpAddress, TI_ipEntity)
  //Exclude local addresses, using the ipv4_is_private operator
  | where ipv4_is_private(TI_ipEntity) == false
      and TI_ipEntity !startswith "fe80"
      and TI_ipEntity !startswith "::"
      and TI_ipEntity !startswith "127."
  // using innerunique to keep perf fast and result set low, we only need one match to indicate potential malicious activity that needs to be investigated
  | join kind=innerunique (
      DataverseActivity
      | where TimeGenerated >= ago(dt_lookBack)
      | where isnotempty(ClientIp)
      //Exclude local addresses, using the ipv4_is_private operator
      | where ipv4_is_private(ClientIp) == false
          and ClientIp !startswith "fe80"
          and ClientIp !startswith "::"
          and ClientIp !startswith "127."
      // renaming time column so it is clear the log this came from
      | extend DataverseActivity_TimeGenerated = TimeGenerated
      )
      on $left.TI_ipEntity == $right.ClientIp
  | where DataverseActivity_TimeGenerated < ExpirationDateTime
  | summarize DataverseActivity_TimeGenerated = arg_max(DataverseActivity_TimeGenerated, *) by IndicatorId, ClientIp
  | project DataverseActivity_TimeGenerated, Description, ActivityGroupNames, IndicatorId, ThreatType, Url, ExpirationDateTime, ConfidenceScore,
      TI_ipEntity, ClientIp, NetworkIP, NetworkDestinationIP, NetworkSourceIP, EmailSourceIpAddress, InstanceUrl, UserId
  | extend
      timestamp = DataverseActivity_TimeGenerated,
      AccountName = tostring(split(UserId, '@')[0]),
      UPNSuffix = tostring(split(UserId, '@')[0]),
      CloudAppId = int(32780)  
kind: Scheduled
triggerOperator: gt
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Microsoft Business Applications/Analytic Rules/Dataverse - TI map IP to DataverseActivity.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/56d5aa0c-d871-4167-ba13-61c2f0fd17bf')]",
      "kind": "Scheduled",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/56d5aa0c-d871-4167-ba13-61c2f0fd17bf')]",
      "properties": {
        "alertDetailsOverride": {
          "alertDescriptionFormat": "Malicous IP {{ClientIp}} was found in {{InstanceUrl}} . User affected is {{UserId}}",
          "alertDisplayNameFormat": "Dataverse - TI map IP in {{InstanceUrl}} "
        },
        "alertRuleTemplateName": "56d5aa0c-d871-4167-ba13-61c2f0fd17bf",
        "customDetails": null,
        "description": "Identifies a match in DataverseActivity from any IP IOC from Microsoft Sentinel Threat Intelligence.",
        "displayName": "Dataverse - TI map IP to DataverseActivity",
        "enabled": true,
        "entityMappings": [
          {
            "entityType": "Account",
            "fieldMappings": [
              {
                "columnName": "AccountName",
                "identifier": "Name"
              },
              {
                "columnName": "UPNSuffix",
                "identifier": "UPNSuffix"
              }
            ]
          },
          {
            "entityType": "IP",
            "fieldMappings": [
              {
                "columnName": "ClientIp",
                "identifier": "Address"
              }
            ]
          },
          {
            "entityType": "URL",
            "fieldMappings": [
              {
                "columnName": "Url",
                "identifier": "Url"
              }
            ]
          },
          {
            "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 - TI map IP to DataverseActivity.yaml",
        "query": "let dt_lookBack = 1h;\nlet ioc_lookBack = 14d;\nThreatIntelligenceIndicator\n| where TimeGenerated >= ago(ioc_lookBack) and ExpirationDateTime > now()\n| summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by IndicatorId\n| where Active == true\n// Picking up only IOC's that contain the entities we want\n| where isnotempty(NetworkIP)\n    or isnotempty(EmailSourceIpAddress)\n    or isnotempty(NetworkDestinationIP)\n    or isnotempty(NetworkSourceIP)\n// As there is potentially more than 1 indicator type for matching IP, taking NetworkIP first, then others if that is empty.\n// Taking the first non-empty value based on potential IOC match availability\n| extend TI_ipEntity = iff(isnotempty(NetworkIP), NetworkIP, NetworkDestinationIP)\n| extend TI_ipEntity = iff(isempty(TI_ipEntity) and isnotempty(NetworkSourceIP), NetworkSourceIP, TI_ipEntity)\n| extend TI_ipEntity = iff(isempty(TI_ipEntity) and isnotempty(EmailSourceIpAddress), EmailSourceIpAddress, TI_ipEntity)\n//Exclude local addresses, using the ipv4_is_private operator\n| where ipv4_is_private(TI_ipEntity) == false\n    and TI_ipEntity !startswith \"fe80\"\n    and TI_ipEntity !startswith \"::\"\n    and TI_ipEntity !startswith \"127.\"\n// using innerunique to keep perf fast and result set low, we only need one match to indicate potential malicious activity that needs to be investigated\n| join kind=innerunique (\n    DataverseActivity\n    | where TimeGenerated >= ago(dt_lookBack)\n    | where isnotempty(ClientIp)\n    //Exclude local addresses, using the ipv4_is_private operator\n    | where ipv4_is_private(ClientIp) == false\n        and ClientIp !startswith \"fe80\"\n        and ClientIp !startswith \"::\"\n        and ClientIp !startswith \"127.\"\n    // renaming time column so it is clear the log this came from\n    | extend DataverseActivity_TimeGenerated = TimeGenerated\n    )\n    on $left.TI_ipEntity == $right.ClientIp\n| where DataverseActivity_TimeGenerated < ExpirationDateTime\n| summarize DataverseActivity_TimeGenerated = arg_max(DataverseActivity_TimeGenerated, *) by IndicatorId, ClientIp\n| project DataverseActivity_TimeGenerated, Description, ActivityGroupNames, IndicatorId, ThreatType, Url, ExpirationDateTime, ConfidenceScore,\n    TI_ipEntity, ClientIp, NetworkIP, NetworkDestinationIP, NetworkSourceIP, EmailSourceIpAddress, InstanceUrl, UserId\n| extend\n    timestamp = DataverseActivity_TimeGenerated,\n    AccountName = tostring(split(UserId, '@')[0]),\n    UPNSuffix = tostring(split(UserId, '@')[0]),\n    CloudAppId = int(32780)\n",
        "queryFrequency": "PT1H",
        "queryPeriod": "P14D",
        "severity": "Medium",
        "status": "Available",
        "subTechniques": [],
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "Discovery",
          "InitialAccess",
          "LateralMovement"
        ],
        "techniques": [
          "T1021",
          "T1078",
          "T1133",
          "T1199",
          "T1210",
          "T1526",
          "T1580"
        ],
        "templateVersion": "3.2.0",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0
      },
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
    }
  ]
}