Back
Id4988c238-a118-442c-80bd-6c689a1b2e97
RulenameTI Map IP Entity to Duo Security
DescriptionThis query maps any IP indicators of compromise (IOCs) from threat intelligence (TI), by searching for matches in DuoSecurity.
SeverityMedium
TacticsCommandAndControl
TechniquesT1071
Required data connectorsCiscoDuoSecurity
MicrosoftDefenderThreatIntelligence
ThreatIntelligence
ThreatIntelligenceTaxii
KindScheduled
Query frequency1h
Query period14d
Trigger threshold0
Trigger operatorgt
Source Urihttps://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Threat%20Intelligence%20%28NEW%29/Analytic%20Rules/IPEntity_DuoSecurity.yaml
Version1.0.10
Arm template4988c238-a118-442c-80bd-6c689a1b2e97.json
Deploy To Azure
let dt_lookBack = 1h;
let ioc_lookBack = 14d;
ThreatIntelIndicators
//extract key part of kv pair
     | extend IndicatorType = replace(@"\[|\]|\""", "", tostring(split(ObservableKey, ":", 0)))
     | where IndicatorType in ("ipv4-addr", "ipv6-addr", "network-traffic")
     | extend NetworkSourceIP = toupper(ObservableValue)
     | extend TrafficLightProtocolLevel = tostring(parse_json(AdditionalFields).TLPLevel)
// Picking up only IOC's that contain the entities we want
| where TimeGenerated >= ago(ioc_lookBack)
// 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(NetworkSourceIP), NetworkSourceIP, NetworkSourceIP)
| extend TI_ipEntity = iff(isempty(TI_ipEntity) and isnotempty(NetworkSourceIP), NetworkSourceIP, TI_ipEntity)
| summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by Id, ObservableValue
| where IsActive and (ValidUntil > now() or isempty(ValidUntil))
 | join (
     CiscoDuo
     | where TimeGenerated >= ago(dt_lookBack)
     | where isnotempty(AccessDvcIpAddr)
     | extend Duo_TimeGenerated = IsoTimestamp
 )
 on $left.TI_ipEntity == $right.AccessDvcIpAddr
 | where TimeGenerated >= ago(ioc_lookBack)
 | summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by Id, ObservableValue
 | where IsActive and (ValidUntil > now() or isempty(ValidUntil))
 | extend Description = tostring(parse_json(Data).description)
 | extend ActivityGroupNames = extract(@"ActivityGroup:(\S+)", 1, tostring(parse_json(Data).labels))
 | project LatestIndicatorTime, Description, ActivityGroupNames, Id, ValidUntil, Confidence, Duo_TimeGenerated,
 TI_ipEntity, DstUserName, AuthFactor, EventResult, SrcAppName, EventType, TransactionId, SrcUserId, AccessDvcIpAddr, SrcGeoCity, AccessDvcLocationState, SrcGeoCountry
 | extend timestamp = Duo_TimeGenerated, Name = tostring(split(DstUserName, '@', 0)[0]), UPNSuffix = tostring(split(DstUserName, '@', 1)[0])
requiredDataConnectors:
- connectorId: ThreatIntelligence
  dataTypes:
  - ThreatIntelIndicators
- connectorId: ThreatIntelligenceTaxii
  dataTypes:
  - ThreatIntelIndicators
- connectorId: CiscoDuoSecurity
  dataTypes:
  - CiscoDuo
- connectorId: MicrosoftDefenderThreatIntelligence
  dataTypes:
  - ThreatIntelIndicators
description: |
  'This query maps any IP indicators of compromise (IOCs) from threat intelligence (TI), by searching for matches in DuoSecurity.'
version: 1.0.10
name: TI Map IP Entity to Duo Security
kind: Scheduled
queryPeriod: 14d
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Threat%20Intelligence%20%28NEW%29/Analytic%20Rules/IPEntity_DuoSecurity.yaml
entityMappings:
- entityType: Account
  fieldMappings:
  - identifier: FullName
    columnName: DstUserName
  - identifier: Name
    columnName: Name
  - identifier: UPNSuffix
    columnName: UPNSuffix
- entityType: IP
  fieldMappings:
  - identifier: Address
    columnName: AccessDvcIpAddr
relevantTechniques:
- T1071
query: |
  let dt_lookBack = 1h;
  let ioc_lookBack = 14d;
  ThreatIntelIndicators
  //extract key part of kv pair
       | extend IndicatorType = replace(@"\[|\]|\""", "", tostring(split(ObservableKey, ":", 0)))
       | where IndicatorType in ("ipv4-addr", "ipv6-addr", "network-traffic")
       | extend NetworkSourceIP = toupper(ObservableValue)
       | extend TrafficLightProtocolLevel = tostring(parse_json(AdditionalFields).TLPLevel)
  // Picking up only IOC's that contain the entities we want
  | where TimeGenerated >= ago(ioc_lookBack)
  // 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(NetworkSourceIP), NetworkSourceIP, NetworkSourceIP)
  | extend TI_ipEntity = iff(isempty(TI_ipEntity) and isnotempty(NetworkSourceIP), NetworkSourceIP, TI_ipEntity)
  | summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by Id, ObservableValue
  | where IsActive and (ValidUntil > now() or isempty(ValidUntil))
   | join (
       CiscoDuo
       | where TimeGenerated >= ago(dt_lookBack)
       | where isnotempty(AccessDvcIpAddr)
       | extend Duo_TimeGenerated = IsoTimestamp
   )
   on $left.TI_ipEntity == $right.AccessDvcIpAddr
   | where TimeGenerated >= ago(ioc_lookBack)
   | summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by Id, ObservableValue
   | where IsActive and (ValidUntil > now() or isempty(ValidUntil))
   | extend Description = tostring(parse_json(Data).description)
   | extend ActivityGroupNames = extract(@"ActivityGroup:(\S+)", 1, tostring(parse_json(Data).labels))
   | project LatestIndicatorTime, Description, ActivityGroupNames, Id, ValidUntil, Confidence, Duo_TimeGenerated,
   TI_ipEntity, DstUserName, AuthFactor, EventResult, SrcAppName, EventType, TransactionId, SrcUserId, AccessDvcIpAddr, SrcGeoCity, AccessDvcLocationState, SrcGeoCountry
   | extend timestamp = Duo_TimeGenerated, Name = tostring(split(DstUserName, '@', 0)[0]), UPNSuffix = tostring(split(DstUserName, '@', 1)[0])
id: 4988c238-a118-442c-80bd-6c689a1b2e97
triggerOperator: gt
queryFrequency: 1h
tactics:
- CommandAndControl
severity: Medium
triggerThreshold: 0
{
  "$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/4988c238-a118-442c-80bd-6c689a1b2e97')]",
      "kind": "Scheduled",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/4988c238-a118-442c-80bd-6c689a1b2e97')]",
      "properties": {
        "alertRuleTemplateName": "4988c238-a118-442c-80bd-6c689a1b2e97",
        "customDetails": null,
        "description": "'This query maps any IP indicators of compromise (IOCs) from threat intelligence (TI), by searching for matches in DuoSecurity.'\n",
        "displayName": "TI Map IP Entity to Duo Security",
        "enabled": true,
        "entityMappings": [
          {
            "entityType": "Account",
            "fieldMappings": [
              {
                "columnName": "DstUserName",
                "identifier": "FullName"
              },
              {
                "columnName": "Name",
                "identifier": "Name"
              },
              {
                "columnName": "UPNSuffix",
                "identifier": "UPNSuffix"
              }
            ]
          },
          {
            "entityType": "IP",
            "fieldMappings": [
              {
                "columnName": "AccessDvcIpAddr",
                "identifier": "Address"
              }
            ]
          }
        ],
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Threat%20Intelligence%20%28NEW%29/Analytic%20Rules/IPEntity_DuoSecurity.yaml",
        "query": "let dt_lookBack = 1h;\nlet ioc_lookBack = 14d;\nThreatIntelIndicators\n//extract key part of kv pair\n     | extend IndicatorType = replace(@\"\\[|\\]|\\\"\"\", \"\", tostring(split(ObservableKey, \":\", 0)))\n     | where IndicatorType in (\"ipv4-addr\", \"ipv6-addr\", \"network-traffic\")\n     | extend NetworkSourceIP = toupper(ObservableValue)\n     | extend TrafficLightProtocolLevel = tostring(parse_json(AdditionalFields).TLPLevel)\n// Picking up only IOC's that contain the entities we want\n| where TimeGenerated >= ago(ioc_lookBack)\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(NetworkSourceIP), NetworkSourceIP, NetworkSourceIP)\n| extend TI_ipEntity = iff(isempty(TI_ipEntity) and isnotempty(NetworkSourceIP), NetworkSourceIP, TI_ipEntity)\n| summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by Id, ObservableValue\n| where IsActive and (ValidUntil > now() or isempty(ValidUntil))\n | join (\n     CiscoDuo\n     | where TimeGenerated >= ago(dt_lookBack)\n     | where isnotempty(AccessDvcIpAddr)\n     | extend Duo_TimeGenerated = IsoTimestamp\n )\n on $left.TI_ipEntity == $right.AccessDvcIpAddr\n | where TimeGenerated >= ago(ioc_lookBack)\n | summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by Id, ObservableValue\n | where IsActive and (ValidUntil > now() or isempty(ValidUntil))\n | extend Description = tostring(parse_json(Data).description)\n | extend ActivityGroupNames = extract(@\"ActivityGroup:(\\S+)\", 1, tostring(parse_json(Data).labels))\n | project LatestIndicatorTime, Description, ActivityGroupNames, Id, ValidUntil, Confidence, Duo_TimeGenerated,\n TI_ipEntity, DstUserName, AuthFactor, EventResult, SrcAppName, EventType, TransactionId, SrcUserId, AccessDvcIpAddr, SrcGeoCity, AccessDvcLocationState, SrcGeoCountry\n | extend timestamp = Duo_TimeGenerated, Name = tostring(split(DstUserName, '@', 0)[0]), UPNSuffix = tostring(split(DstUserName, '@', 1)[0])\n",
        "queryFrequency": "PT1H",
        "queryPeriod": "P14D",
        "severity": "Medium",
        "subTechniques": [],
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "CommandAndControl"
        ],
        "techniques": [
          "T1071"
        ],
        "templateVersion": "1.0.10",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0
      },
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
    }
  ]
}