Back
Id3b4a8c72-5a2e-4f1e-b61a-9d8b2a6d7a21
RulenameTI Map URL entity to Web Session Events (ASIM Web Session schema)
DescriptionThis rule identifies Web Sessions where the full requested URL matches a known

malicious URL from Threat Intelligence sources. The rule uses the Advanced Security

Information Model (ASIM) and supports any web session source compliant with ASIM.
SeverityMedium
TacticsCommandAndControl
InitialAccess
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%20Intelligence%20%28NEW%29/Analytic%20Rules/URLEntity_imWebSession.yaml
Version1.0.1
Arm template3b4a8c72-5a2e-4f1e-b61a-9d8b2a6d7a21.json
Deploy To Azure
let HAS_ANY_MAX = 10000;
let dt_lookBack = 1h;
let ioc_lookBack = 14d;
// Extract URL-based Threat Intelligence indicators
let URL_TI =
  ThreatIntelIndicators
  | extend IndicatorType = replace(@"\[|\]|\""", "", tostring(split(ObservableKey, ":", 0)))
  | where IndicatorType == "url"
  | extend MaliciousUrl = tolower(ObservableValue)
  | extend TrafficLightProtocolLevel = tostring(parse_json(AdditionalFields).TLPLevel)
  | extend IndicatorId = tostring(split(Id, "--")[2])
  | where TimeGenerated >= ago(ioc_lookBack)
  | summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by Id, MaliciousUrl
  | where IsActive and (ValidUntil > now() or isempty(ValidUntil));
// Build a dynamic list of malicious URLs
let URL_TI_list =
  toscalar(
      URL_TI
      | summarize NIoCs = dcount(MaliciousUrl),
                  Urls = make_set(MaliciousUrl)
      | project Urls = iff(NIoCs > HAS_ANY_MAX, dynamic([]), Urls)
    );
// Match against ASIM Web Session events
URL_TI
| join kind=innerunique (
    _Im_WebSession(starttime=ago(dt_lookBack), url_has_any = URL_TI_list)
    | extend RequestedUrl = tolower(Url)
    | where isnotempty(RequestedUrl)
    | extend Event_TimeGenerated = TimeGenerated
  ) on $left.MaliciousUrl == $right.RequestedUrl
| where Event_TimeGenerated < ValidUntil
| summarize Event_TimeGenerated = arg_max(Event_TimeGenerated, *) by IndicatorId, RequestedUrl
| extend ParsedData = parse_json(Data)
| extend Description = tostring(ParsedData.description)
| extend ActivityGroupNames = extract(@"ActivityGroup:(\S+)", 1, tostring(ParsedData.labels))
| extend ThreatType = tostring(ParsedData.indicator_types[0])
| project
    Event_TimeGenerated,
    SrcIpAddr,
    RequestedUrl,
    IndicatorId,
    ThreatType,
    Confidence,
    ValidUntil,
    Description,
    ActivityGroupNames
entityMappings:
- entityType: IP
  fieldMappings:
  - identifier: Address
    columnName: SrcIpAddr
- entityType: URL
  fieldMappings:
  - identifier: Url
    columnName: RequestedUrl
name: TI Map URL entity to Web Session Events (ASIM Web Session schema)
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Threat%20Intelligence%20%28NEW%29/Analytic%20Rules/URLEntity_imWebSession.yaml
queryFrequency: 1h
triggerOperator: gt
queryPeriod: 14d
requiredDataConnectors:
- connectorId: SquidProxy
  dataTypes:
  - SquidProxy_CL
- connectorId: Zscaler
  dataTypes:
  - CommonSecurityLog
- connectorId: ThreatIntelligence
  dataTypes:
  - ThreatIntelIndicators
- connectorId: ThreatIntelligenceTaxii
  dataTypes:
  - ThreatIntelIndicators
- connectorId: MicrosoftDefenderThreatIntelligence
  dataTypes:
  - ThreatIntelIndicators
tactics:
- CommandAndControl
- InitialAccess
query: |
  let HAS_ANY_MAX = 10000;
  let dt_lookBack = 1h;
  let ioc_lookBack = 14d;
  // Extract URL-based Threat Intelligence indicators
  let URL_TI =
    ThreatIntelIndicators
    | extend IndicatorType = replace(@"\[|\]|\""", "", tostring(split(ObservableKey, ":", 0)))
    | where IndicatorType == "url"
    | extend MaliciousUrl = tolower(ObservableValue)
    | extend TrafficLightProtocolLevel = tostring(parse_json(AdditionalFields).TLPLevel)
    | extend IndicatorId = tostring(split(Id, "--")[2])
    | where TimeGenerated >= ago(ioc_lookBack)
    | summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by Id, MaliciousUrl
    | where IsActive and (ValidUntil > now() or isempty(ValidUntil));
  // Build a dynamic list of malicious URLs
  let URL_TI_list =
    toscalar(
        URL_TI
        | summarize NIoCs = dcount(MaliciousUrl),
                    Urls = make_set(MaliciousUrl)
        | project Urls = iff(NIoCs > HAS_ANY_MAX, dynamic([]), Urls)
      );
  // Match against ASIM Web Session events
  URL_TI
  | join kind=innerunique (
      _Im_WebSession(starttime=ago(dt_lookBack), url_has_any = URL_TI_list)
      | extend RequestedUrl = tolower(Url)
      | where isnotempty(RequestedUrl)
      | extend Event_TimeGenerated = TimeGenerated
    ) on $left.MaliciousUrl == $right.RequestedUrl
  | where Event_TimeGenerated < ValidUntil
  | summarize Event_TimeGenerated = arg_max(Event_TimeGenerated, *) by IndicatorId, RequestedUrl
  | extend ParsedData = parse_json(Data)
  | extend Description = tostring(ParsedData.description)
  | extend ActivityGroupNames = extract(@"ActivityGroup:(\S+)", 1, tostring(ParsedData.labels))
  | extend ThreatType = tostring(ParsedData.indicator_types[0])
  | project
      Event_TimeGenerated,
      SrcIpAddr,
      RequestedUrl,
      IndicatorId,
      ThreatType,
      Confidence,
      ValidUntil,
      Description,
      ActivityGroupNames
description: |
  This rule identifies Web Sessions where the full requested URL matches a known
  malicious URL from Threat Intelligence sources. The rule uses the Advanced Security
  Information Model (ASIM) and supports any web session source compliant with ASIM.
severity: Medium
kind: Scheduled
customDetails:
  EventTime: Event_TimeGenerated
  IoCExpirationTime: ValidUntil
  IoCConfidenceScore: Confidence
  IndicatorId: IndicatorId
  ActivityGroupNames: ActivityGroupNames
  IoCDescription: Description
  ThreatType: ThreatType
triggerThreshold: 0
id: 3b4a8c72-5a2e-4f1e-b61a-9d8b2a6d7a21
alertDetailsOverride:
  alertDescriptionFormat: A client with address {{SrcIpAddr}} requested the URL {{RequestedUrl}}, which is a known malicious URL associated with {{ThreatType}}. Review threat intelligence blade for further context.
  alertDisplayNameFormat: A web request from {{SrcIpAddr}} to malicious URL matched an IoC
version: 1.0.1
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/3b4a8c72-5a2e-4f1e-b61a-9d8b2a6d7a21')]",
      "kind": "Scheduled",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/3b4a8c72-5a2e-4f1e-b61a-9d8b2a6d7a21')]",
      "properties": {
        "alertDetailsOverride": {
          "alertDescriptionFormat": "A client with address {{SrcIpAddr}} requested the URL {{RequestedUrl}}, which is a known malicious URL associated with {{ThreatType}}. Review threat intelligence blade for further context.",
          "alertDisplayNameFormat": "A web request from {{SrcIpAddr}} to malicious URL matched an IoC"
        },
        "alertRuleTemplateName": "3b4a8c72-5a2e-4f1e-b61a-9d8b2a6d7a21",
        "customDetails": {
          "ActivityGroupNames": "ActivityGroupNames",
          "EventTime": "Event_TimeGenerated",
          "IndicatorId": "IndicatorId",
          "IoCConfidenceScore": "Confidence",
          "IoCDescription": "Description",
          "IoCExpirationTime": "ValidUntil",
          "ThreatType": "ThreatType"
        },
        "description": "This rule identifies Web Sessions where the full requested URL matches a known\nmalicious URL from Threat Intelligence sources. The rule uses the Advanced Security\nInformation Model (ASIM) and supports any web session source compliant with ASIM.\n",
        "displayName": "TI Map URL entity to Web Session Events (ASIM Web Session schema)",
        "enabled": true,
        "entityMappings": [
          {
            "entityType": "IP",
            "fieldMappings": [
              {
                "columnName": "SrcIpAddr",
                "identifier": "Address"
              }
            ]
          },
          {
            "entityType": "URL",
            "fieldMappings": [
              {
                "columnName": "RequestedUrl",
                "identifier": "Url"
              }
            ]
          }
        ],
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Threat%20Intelligence%20%28NEW%29/Analytic%20Rules/URLEntity_imWebSession.yaml",
        "query": "let HAS_ANY_MAX = 10000;\nlet dt_lookBack = 1h;\nlet ioc_lookBack = 14d;\n// Extract URL-based Threat Intelligence indicators\nlet URL_TI =\n  ThreatIntelIndicators\n  | extend IndicatorType = replace(@\"\\[|\\]|\\\"\"\", \"\", tostring(split(ObservableKey, \":\", 0)))\n  | where IndicatorType == \"url\"\n  | extend MaliciousUrl = tolower(ObservableValue)\n  | extend TrafficLightProtocolLevel = tostring(parse_json(AdditionalFields).TLPLevel)\n  | extend IndicatorId = tostring(split(Id, \"--\")[2])\n  | where TimeGenerated >= ago(ioc_lookBack)\n  | summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by Id, MaliciousUrl\n  | where IsActive and (ValidUntil > now() or isempty(ValidUntil));\n// Build a dynamic list of malicious URLs\nlet URL_TI_list =\n  toscalar(\n      URL_TI\n      | summarize NIoCs = dcount(MaliciousUrl),\n                  Urls = make_set(MaliciousUrl)\n      | project Urls = iff(NIoCs > HAS_ANY_MAX, dynamic([]), Urls)\n    );\n// Match against ASIM Web Session events\nURL_TI\n| join kind=innerunique (\n    _Im_WebSession(starttime=ago(dt_lookBack), url_has_any = URL_TI_list)\n    | extend RequestedUrl = tolower(Url)\n    | where isnotempty(RequestedUrl)\n    | extend Event_TimeGenerated = TimeGenerated\n  ) on $left.MaliciousUrl == $right.RequestedUrl\n| where Event_TimeGenerated < ValidUntil\n| summarize Event_TimeGenerated = arg_max(Event_TimeGenerated, *) by IndicatorId, RequestedUrl\n| extend ParsedData = parse_json(Data)\n| extend Description = tostring(ParsedData.description)\n| extend ActivityGroupNames = extract(@\"ActivityGroup:(\\S+)\", 1, tostring(ParsedData.labels))\n| extend ThreatType = tostring(ParsedData.indicator_types[0])\n| project\n    Event_TimeGenerated,\n    SrcIpAddr,\n    RequestedUrl,\n    IndicatorId,\n    ThreatType,\n    Confidence,\n    ValidUntil,\n    Description,\n    ActivityGroupNames\n",
        "queryFrequency": "PT1H",
        "queryPeriod": "P14D",
        "severity": "Medium",
        "subTechniques": [],
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "CommandAndControl",
          "InitialAccess"
        ],
        "techniques": [
          "T1071"
        ],
        "templateVersion": "1.0.1",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0
      },
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
    }
  ]
}