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
kind: Scheduled
name: TI Map URL entity to Web Session Events (ASIM Web Session schema)
triggerOperator: gt
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
queryFrequency: 1h
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.
id: 3b4a8c72-5a2e-4f1e-b61a-9d8b2a6d7a21
triggerThreshold: 0
queryPeriod: 14d
version: 1.0.1
customDetails:
  IoCExpirationTime: ValidUntil
  IndicatorId: IndicatorId
  ThreatType: ThreatType
  ActivityGroupNames: ActivityGroupNames
  IoCConfidenceScore: Confidence
  IoCDescription: Description
  EventTime: Event_TimeGenerated
relevantTechniques:
- T1071
severity: Medium
requiredDataConnectors:
- connectorId: SquidProxy
  dataTypes:
  - SquidProxy_CL
- connectorId: Zscaler
  dataTypes:
  - CommonSecurityLog
- connectorId: ThreatIntelligence
  dataTypes:
  - ThreatIntelIndicators
- connectorId: ThreatIntelligenceTaxii
  dataTypes:
  - ThreatIntelIndicators
- connectorId: MicrosoftDefenderThreatIntelligence
  dataTypes:
  - ThreatIntelIndicators
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Threat%20Intelligence%20%28NEW%29/Analytic%20Rules/URLEntity_imWebSession.yaml
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
tactics:
- CommandAndControl
- InitialAccess
entityMappings:
- fieldMappings:
  - identifier: Address
    columnName: SrcIpAddr
  entityType: IP
- fieldMappings:
  - identifier: Url
    columnName: RequestedUrl
  entityType: URL
{
  "$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"
    }
  ]
}