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