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)
queryPeriod: 14d
description: Identifies a match in DataverseActivity from any IP IOC from Microsoft Sentinel Threat Intelligence.
tactics:
- InitialAccess
- LateralMovement
- Discovery
version: 3.2.0
relevantTechniques:
- T1078
- T1199
- T1133
- T0886
- T0859
- T1428
- T1021
- T1210
- T1526
- T1580
name: Dataverse - TI map IP to DataverseActivity
severity: Medium
triggerOperator: gt
entityMappings:
- fieldMappings:
  - identifier: Name
    columnName: AccountName
  - identifier: UPNSuffix
    columnName: UPNSuffix
  entityType: Account
- fieldMappings:
  - identifier: Address
    columnName: ClientIp
  entityType: IP
- fieldMappings:
  - identifier: Url
    columnName: Url
  entityType: URL
- fieldMappings:
  - identifier: AppId
    columnName: CloudAppId
  - identifier: InstanceName
    columnName: InstanceUrl
  entityType: CloudApplication
alertDetailsOverride:
  alertDescriptionFormat: Malicous IP {{ClientIp}} was found in {{InstanceUrl}} . User affected is {{UserId}}
  alertDisplayNameFormat: 'Dataverse - TI map IP in {{InstanceUrl}} '
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Microsoft Business Applications/Analytic Rules/Dataverse - TI map IP to DataverseActivity.yaml
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
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)  
status: Available
triggerThreshold: 0
queryFrequency: 1h
kind: Scheduled
id: 56d5aa0c-d871-4167-ba13-61c2f0fd17bf
eventGroupingSettings:
  aggregationKind: AlertPerResult
{
  "$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"
    }
  ]
}