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

TI map IP entity to Web Session Events ASIM Web Session schema

Back
Id0548be6c-135e-4eb6-b9ff-14a09df62c77
RulenameTI map IP entity to Web Session Events (ASIM Web Session schema)
DescriptionThis rule identifies Web Sessions for which the source IP address is a known IoC. This rule uses the Advanced Security Information Model (ASIM) and supports any web session source that complies with ASIM.
SeverityMedium
TacticsCommandAndControl
TechniquesT1071
Required data connectorsMicrosoftDefenderThreatIntelligence
SquidProxy
ThreatIntelligence
ThreatIntelligenceTaxii
Zscaler
KindScheduled
Query frequency1h
Query period14d
Trigger threshold0
Trigger operatorgt
Source Urihttps://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Threat Intelligence (NEW)/Analytic Rules/IPEntity_imWebSession.yaml
Version1.2.10
Arm template0548be6c-135e-4eb6-b9ff-14a09df62c77.json
Deploy To Azure
let HAS_ANY_MAX = 10000;
let dt_lookBack = 1h;
let ioc_lookBack = 14d;
let IP_TI = 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)
  | 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 = NetworkSourceIP
  // Picking up only IOC's that contain the entities we want
  | where TI_ipEntity != "NO_IP"
  // 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."
  | extend ThreatType = tostring(Data.indicator_types[0])
  | extend IndicatorId = tostring(split(Id, "--")[2])
  | summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by IndicatorId, ObservableValue
  | where IsActive and (ValidUntil > now() or isempty(ValidUntil));
let IP_TI_list = toscalar(IP_TI
  | summarize NIoCs = dcount(TI_ipEntity), IoCs = make_set(TI_ipEntity)
  | project IoCs = iff(NIoCs > HAS_ANY_MAX, dynamic([]), IoCs));
IP_TI
   | project-reorder *, Tags, TrafficLightProtocolLevel, NetworkSourceIP, Type, TI_ipEntity
// 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 (
    _Im_WebSession (starttime = ago(dt_lookBack), srcipaddr_has_any_prefix = IP_TI_list)
    | where isnotempty(SrcIpAddr)
    // renaming time column so it is clear the log this came from
    | extend imNWS_TimeGenerated = TimeGenerated
  )
  on $left.TI_ipEntity == $right.SrcIpAddr
| where imNWS_TimeGenerated < ValidUntil
| summarize imNWS_TimeGenerated = arg_max(imNWS_TimeGenerated, *) by IndicatorId, DstIpAddr
| extend Description = tostring(parse_json(Data).description)
| extend ActivityGroupNames = extract(@"ActivityGroup:(\S+)", 1, tostring(parse_json(Data).labels))
| project imNWS_TimeGenerated, Description, ActivityGroupNames, IndicatorId, ThreatType, ValidUntil, Confidence, TI_ipEntity, Dvc, SrcIpAddr, DstIpAddr, Url
queryFrequency: 1h
description: |
    This rule identifies Web Sessions for which the source IP address is a known IoC. This rule uses the [Advanced Security Information Model (ASIM)](https://aka.ms/AboutASIM) and supports any web session source that complies with ASIM.
queryPeriod: 14d
name: TI map IP entity to Web Session Events (ASIM Web Session schema)
severity: Medium
tactics:
- CommandAndControl
query: |
  let HAS_ANY_MAX = 10000;
  let dt_lookBack = 1h;
  let ioc_lookBack = 14d;
  let IP_TI = 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)
    | 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 = NetworkSourceIP
    // Picking up only IOC's that contain the entities we want
    | where TI_ipEntity != "NO_IP"
    // 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."
    | extend ThreatType = tostring(Data.indicator_types[0])
    | extend IndicatorId = tostring(split(Id, "--")[2])
    | summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by IndicatorId, ObservableValue
    | where IsActive and (ValidUntil > now() or isempty(ValidUntil));
  let IP_TI_list = toscalar(IP_TI
    | summarize NIoCs = dcount(TI_ipEntity), IoCs = make_set(TI_ipEntity)
    | project IoCs = iff(NIoCs > HAS_ANY_MAX, dynamic([]), IoCs));
  IP_TI
     | project-reorder *, Tags, TrafficLightProtocolLevel, NetworkSourceIP, Type, TI_ipEntity
  // 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 (
      _Im_WebSession (starttime = ago(dt_lookBack), srcipaddr_has_any_prefix = IP_TI_list)
      | where isnotempty(SrcIpAddr)
      // renaming time column so it is clear the log this came from
      | extend imNWS_TimeGenerated = TimeGenerated
    )
    on $left.TI_ipEntity == $right.SrcIpAddr
  | where imNWS_TimeGenerated < ValidUntil
  | summarize imNWS_TimeGenerated = arg_max(imNWS_TimeGenerated, *) by IndicatorId, DstIpAddr
  | extend Description = tostring(parse_json(Data).description)
  | extend ActivityGroupNames = extract(@"ActivityGroup:(\S+)", 1, tostring(parse_json(Data).labels))
  | project imNWS_TimeGenerated, Description, ActivityGroupNames, IndicatorId, ThreatType, ValidUntil, Confidence, TI_ipEntity, Dvc, SrcIpAddr, DstIpAddr, Url  
id: 0548be6c-135e-4eb6-b9ff-14a09df62c77
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Threat Intelligence (NEW)/Analytic Rules/IPEntity_imWebSession.yaml
entityMappings:
- entityType: IP
  fieldMappings:
  - identifier: Address
    columnName: DstIpAddr
- entityType: IP
  fieldMappings:
  - identifier: Address
    columnName: SrcIpAddr
triggerThreshold: 0
requiredDataConnectors:
- connectorId: SquidProxy
  dataTypes:
  - SquidProxy_CL
- connectorId: Zscaler
  dataTypes:
  - CommonSecurityLog
- connectorId: ThreatIntelligence
  dataTypes:
  - ThreatIntelIndicators
- connectorId: ThreatIntelligenceTaxii
  dataTypes:
  - ThreatIntelIndicators
- connectorId: MicrosoftDefenderThreatIntelligence
  dataTypes:
  - ThreatIntelIndicators
alertDetailsOverride:
  alertDisplayNameFormat: The IP {{SrcIpAddr}} of the web request matches an IP IoC
  alertDescriptionFormat: The source address {{SrcIpAddr}} of the web request for the URL {{Url}} matches a known indicator of compromise of {{ThreatType}}. Consult the threat intelligence feed for more information about the indicator.
version: 1.2.10
customDetails:
  IoCConfidenceScore: Confidence
  ThreatType: ThreatType
  IoCExpirationTime: ValidUntil
  IndicatorId: IndicatorId
  EventTime: imNWS_TimeGenerated
  ActivityGroupNames: ActivityGroupNames
  IoCDescription: Description
triggerOperator: gt
kind: Scheduled
relevantTechniques:
- T1071
{
  "$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/0548be6c-135e-4eb6-b9ff-14a09df62c77')]",
      "kind": "Scheduled",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/0548be6c-135e-4eb6-b9ff-14a09df62c77')]",
      "properties": {
        "alertDetailsOverride": {
          "alertDescriptionFormat": "The source address {{SrcIpAddr}} of the web request for the URL {{Url}} matches a known indicator of compromise of {{ThreatType}}. Consult the threat intelligence feed for more information about the indicator.",
          "alertDisplayNameFormat": "The IP {{SrcIpAddr}} of the web request matches an IP IoC"
        },
        "alertRuleTemplateName": "0548be6c-135e-4eb6-b9ff-14a09df62c77",
        "customDetails": {
          "ActivityGroupNames": "ActivityGroupNames",
          "EventTime": "imNWS_TimeGenerated",
          "IndicatorId": "IndicatorId",
          "IoCConfidenceScore": "Confidence",
          "IoCDescription": "Description",
          "IoCExpirationTime": "ValidUntil",
          "ThreatType": "ThreatType"
        },
        "description": "This rule identifies Web Sessions for which the source IP address is a known IoC. This rule uses the [Advanced Security Information Model (ASIM)](https://aka.ms/AboutASIM) and supports any web session source that complies with ASIM.\n",
        "displayName": "TI map IP entity to Web Session Events (ASIM Web Session schema)",
        "enabled": true,
        "entityMappings": [
          {
            "entityType": "IP",
            "fieldMappings": [
              {
                "columnName": "DstIpAddr",
                "identifier": "Address"
              }
            ]
          },
          {
            "entityType": "IP",
            "fieldMappings": [
              {
                "columnName": "SrcIpAddr",
                "identifier": "Address"
              }
            ]
          }
        ],
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Threat Intelligence (NEW)/Analytic Rules/IPEntity_imWebSession.yaml",
        "query": "let HAS_ANY_MAX = 10000;\nlet dt_lookBack = 1h;\nlet ioc_lookBack = 14d;\nlet IP_TI = ThreatIntelIndicators\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  | 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 = NetworkSourceIP\n  // Picking up only IOC's that contain the entities we want\n  | where TI_ipEntity != \"NO_IP\"\n  // Exclude local addresses, using the ipv4_is_private operator\n  | where ipv4_is_private(TI_ipEntity) == false and TI_ipEntity !startswith \"fe80\" and TI_ipEntity !startswith \"::\" and TI_ipEntity !startswith \"127.\"\n  | extend ThreatType = tostring(Data.indicator_types[0])\n  | extend IndicatorId = tostring(split(Id, \"--\")[2])\n  | summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by IndicatorId, ObservableValue\n  | where IsActive and (ValidUntil > now() or isempty(ValidUntil));\nlet IP_TI_list = toscalar(IP_TI\n  | summarize NIoCs = dcount(TI_ipEntity), IoCs = make_set(TI_ipEntity)\n  | project IoCs = iff(NIoCs > HAS_ANY_MAX, dynamic([]), IoCs));\nIP_TI\n   | project-reorder *, Tags, TrafficLightProtocolLevel, NetworkSourceIP, Type, TI_ipEntity\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    _Im_WebSession (starttime = ago(dt_lookBack), srcipaddr_has_any_prefix = IP_TI_list)\n    | where isnotempty(SrcIpAddr)\n    // renaming time column so it is clear the log this came from\n    | extend imNWS_TimeGenerated = TimeGenerated\n  )\n  on $left.TI_ipEntity == $right.SrcIpAddr\n| where imNWS_TimeGenerated < ValidUntil\n| summarize imNWS_TimeGenerated = arg_max(imNWS_TimeGenerated, *) by IndicatorId, DstIpAddr\n| extend Description = tostring(parse_json(Data).description)\n| extend ActivityGroupNames = extract(@\"ActivityGroup:(\\S+)\", 1, tostring(parse_json(Data).labels))\n| project imNWS_TimeGenerated, Description, ActivityGroupNames, IndicatorId, ThreatType, ValidUntil, Confidence, TI_ipEntity, Dvc, SrcIpAddr, DstIpAddr, Url\n",
        "queryFrequency": "PT1H",
        "queryPeriod": "P14D",
        "severity": "Medium",
        "subTechniques": [],
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "CommandAndControl"
        ],
        "techniques": [
          "T1071"
        ],
        "templateVersion": "1.2.10",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0
      },
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
    }
  ]
}