Analytic rule catalog
TI Map IP Entity to Duo Security
Back
| Id | 4988c238-a118-442c-80bd-6c689a1b2e97 |
| Rulename | TI Map IP Entity to Duo Security |
| Description | This query maps any IP indicators of compromise (IOCs) from threat intelligence (TI), by searching for matches in DuoSecurity. |
| Severity | Medium |
| Tactics | CommandAndControl |
| Techniques | T1071 |
| Required data connectors | CiscoDuoSecurity MicrosoftDefenderThreatIntelligence ThreatIntelligence ThreatIntelligenceTaxii |
| Kind | Scheduled |
| Query frequency | 1h |
| Query period | 14d |
| Trigger threshold | 0 |
| Trigger operator | gt |
| Source Uri | https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Threat%20Intelligence%20%28NEW%29/Analytic%20Rules/IPEntity_DuoSecurity.yaml |
| Version | 1.0.10 |
| Arm template | 4988c238-a118-442c-80bd-6c689a1b2e97.json |
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"
}
]
}