Back
Id347c6cb3-33d2-4753-b7f6-eab946a8cd51
RulenameGSA - TI URL Entity
DescriptionThis query identifies URL indicators of compromise (IOCs) from threat intelligence (TI) by searching for matches in GSA NetworkAccessTraffic.
SeverityMedium
TacticsCommandAndControl
TechniquesT1071
Required data connectorsAzureActiveDirectory
KindScheduled
Query frequency1h
Query period14d
Trigger threshold0
Trigger operatorgt
Source Urihttps://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Global%20Secure%20Access/Analytic%20Rules/GSA%20-%20TI%20URL%20Entity.yaml
Version1.0.1
Arm template347c6cb3-33d2-4753-b7f6-eab946a8cd51.json
Deploy To Azure
let dt_lookBack = 1h;
let ioc_lookBack = 14d;
let GSANetworkAccessTraffic_ = NetworkAccessTraffic
| where TimeGenerated >= ago(dt_lookBack)
| where TrafficType  == "internet"
| extend DestinationUrlToLower = tolower(DestinationUrl)
| project-rename GSANetworkAccessTraffic_TimeGenerated = TimeGenerated;
let GSANetworkAccessTrafficUrls =
    GSANetworkAccessTraffic_
    | where isnotempty(DestinationUrl)
    | extend Url = tolower(DestinationUrl)
    | distinct Url;
ThreatIntelIndicators
  | extend IndicatorType = replace(@'[\[\]"]', "", tostring(split(ObservableKey, ":", 0)))
  | where IndicatorType == "url"
  | extend Url = ObservableValue
  | extend TrafficLightProtocolLevel = tostring(parse_json(AdditionalFields).TLPLevel)
  | where TimeGenerated >= ago(ioc_lookBack)
  | extend Url = tolower(Url)
  | where Url in (GSANetworkAccessTrafficUrls)
  | summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by Id, ObservableValue
  | where IsActive and (ValidUntil > now() or isempty(ValidUntil))
  | extend Description = tostring(parse_json(Data).description)
  | where Description !contains_cs "State: inactive;" and Description !contains_cs "State: falsepos;"
  | project-reorder *, Tags, TrafficLightProtocolLevel, Url, Type
  | join kind=innerunique (GSANetworkAccessTraffic_) on $left.Url == $right.DestinationUrlToLower
  | where isempty(ValidUntil) or GSANetworkAccessTraffic_TimeGenerated < ValidUntil
  | extend GSAThreatType = ThreatType
| summarize GSANetworkAccessTraffic_TimeGenerated = arg_max(GSANetworkAccessTraffic_TimeGenerated, *) by Id, DestinationUrl
| project-reorder *,
    Tags,
    Confidence,
    TrafficLightProtocolLevel,
    Type,
    UserPrincipalName,
    UserId,
    DeviceId,
    InitiatingProcessName,
    GSAThreatType,
    DestinationIp,
    DestinationFqdn,
    DestinationUrl,
    DestinationPort,
    SourceIp,
    SourcePort,
    HttpUserAgent
query: |
  let dt_lookBack = 1h;
  let ioc_lookBack = 14d;
  let GSANetworkAccessTraffic_ = NetworkAccessTraffic
  | where TimeGenerated >= ago(dt_lookBack)
  | where TrafficType  == "internet"
  | extend DestinationUrlToLower = tolower(DestinationUrl)
  | project-rename GSANetworkAccessTraffic_TimeGenerated = TimeGenerated;
  let GSANetworkAccessTrafficUrls =
      GSANetworkAccessTraffic_
      | where isnotempty(DestinationUrl)
      | extend Url = tolower(DestinationUrl)
      | distinct Url;
  ThreatIntelIndicators
    | extend IndicatorType = replace(@'[\[\]"]', "", tostring(split(ObservableKey, ":", 0)))
    | where IndicatorType == "url"
    | extend Url = ObservableValue
    | extend TrafficLightProtocolLevel = tostring(parse_json(AdditionalFields).TLPLevel)
    | where TimeGenerated >= ago(ioc_lookBack)
    | extend Url = tolower(Url)
    | where Url in (GSANetworkAccessTrafficUrls)
    | summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by Id, ObservableValue
    | where IsActive and (ValidUntil > now() or isempty(ValidUntil))
    | extend Description = tostring(parse_json(Data).description)
    | where Description !contains_cs "State: inactive;" and Description !contains_cs "State: falsepos;"
    | project-reorder *, Tags, TrafficLightProtocolLevel, Url, Type
    | join kind=innerunique (GSANetworkAccessTraffic_) on $left.Url == $right.DestinationUrlToLower
    | where isempty(ValidUntil) or GSANetworkAccessTraffic_TimeGenerated < ValidUntil
    | extend GSAThreatType = ThreatType
  | summarize GSANetworkAccessTraffic_TimeGenerated = arg_max(GSANetworkAccessTraffic_TimeGenerated, *) by Id, DestinationUrl
  | project-reorder *,
      Tags,
      Confidence,
      TrafficLightProtocolLevel,
      Type,
      UserPrincipalName,
      UserId,
      DeviceId,
      InitiatingProcessName,
      GSAThreatType,
      DestinationIp,
      DestinationFqdn,
      DestinationUrl,
      DestinationPort,
      SourceIp,
      SourcePort,
      HttpUserAgent
triggerOperator: gt
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Global%20Secure%20Access/Analytic%20Rules/GSA%20-%20TI%20URL%20Entity.yaml
queryPeriod: 14d
tactics:
- CommandAndControl
id: 347c6cb3-33d2-4753-b7f6-eab946a8cd51
kind: Scheduled
version: 1.0.1
name: GSA - TI URL Entity
status: Available
description: |
  This query identifies URL indicators of compromise (IOCs) from threat intelligence (TI) by searching for matches in GSA NetworkAccessTraffic.
queryFrequency: 1h
entityMappings:
- entityType: Account
  fieldMappings:
  - columnName: UserPrincipalName
    identifier: Name
- entityType: IP
  fieldMappings:
  - columnName: SourceIp
    identifier: Address
- entityType: URL
  fieldMappings:
  - columnName: DestinationUrl
    identifier: Url
- entityType: Process
  fieldMappings:
  - columnName: InitiatingProcessName
    identifier: CommandLine
requiredDataConnectors:
- dataTypes:
  - NetworkAccessTrafficLogs
  connectorId: AzureActiveDirectory
relevantTechniques:
- T1071
triggerThreshold: 0
severity: Medium
{
  "$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/347c6cb3-33d2-4753-b7f6-eab946a8cd51')]",
      "kind": "Scheduled",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/347c6cb3-33d2-4753-b7f6-eab946a8cd51')]",
      "properties": {
        "alertRuleTemplateName": "347c6cb3-33d2-4753-b7f6-eab946a8cd51",
        "customDetails": null,
        "description": "This query identifies URL indicators of compromise (IOCs) from threat intelligence (TI) by searching for matches in GSA NetworkAccessTraffic.\n",
        "displayName": "GSA - TI URL Entity",
        "enabled": true,
        "entityMappings": [
          {
            "entityType": "Account",
            "fieldMappings": [
              {
                "columnName": "UserPrincipalName",
                "identifier": "Name"
              }
            ]
          },
          {
            "entityType": "IP",
            "fieldMappings": [
              {
                "columnName": "SourceIp",
                "identifier": "Address"
              }
            ]
          },
          {
            "entityType": "URL",
            "fieldMappings": [
              {
                "columnName": "DestinationUrl",
                "identifier": "Url"
              }
            ]
          },
          {
            "entityType": "Process",
            "fieldMappings": [
              {
                "columnName": "InitiatingProcessName",
                "identifier": "CommandLine"
              }
            ]
          }
        ],
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Global%20Secure%20Access/Analytic%20Rules/GSA%20-%20TI%20URL%20Entity.yaml",
        "query": "let dt_lookBack = 1h;\nlet ioc_lookBack = 14d;\nlet GSANetworkAccessTraffic_ = NetworkAccessTraffic\n| where TimeGenerated >= ago(dt_lookBack)\n| where TrafficType  == \"internet\"\n| extend DestinationUrlToLower = tolower(DestinationUrl)\n| project-rename GSANetworkAccessTraffic_TimeGenerated = TimeGenerated;\nlet GSANetworkAccessTrafficUrls =\n    GSANetworkAccessTraffic_\n    | where isnotempty(DestinationUrl)\n    | extend Url = tolower(DestinationUrl)\n    | distinct Url;\nThreatIntelIndicators\n  | extend IndicatorType = replace(@'[\\[\\]\"]', \"\", tostring(split(ObservableKey, \":\", 0)))\n  | where IndicatorType == \"url\"\n  | extend Url = ObservableValue\n  | extend TrafficLightProtocolLevel = tostring(parse_json(AdditionalFields).TLPLevel)\n  | where TimeGenerated >= ago(ioc_lookBack)\n  | extend Url = tolower(Url)\n  | where Url in (GSANetworkAccessTrafficUrls)\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  | where Description !contains_cs \"State: inactive;\" and Description !contains_cs \"State: falsepos;\"\n  | project-reorder *, Tags, TrafficLightProtocolLevel, Url, Type\n  | join kind=innerunique (GSANetworkAccessTraffic_) on $left.Url == $right.DestinationUrlToLower\n  | where isempty(ValidUntil) or GSANetworkAccessTraffic_TimeGenerated < ValidUntil\n  | extend GSAThreatType = ThreatType\n| summarize GSANetworkAccessTraffic_TimeGenerated = arg_max(GSANetworkAccessTraffic_TimeGenerated, *) by Id, DestinationUrl\n| project-reorder *,\n    Tags,\n    Confidence,\n    TrafficLightProtocolLevel,\n    Type,\n    UserPrincipalName,\n    UserId,\n    DeviceId,\n    InitiatingProcessName,\n    GSAThreatType,\n    DestinationIp,\n    DestinationFqdn,\n    DestinationUrl,\n    DestinationPort,\n    SourceIp,\n    SourcePort,\n    HttpUserAgent\n",
        "queryFrequency": "PT1H",
        "queryPeriod": "P14D",
        "severity": "Medium",
        "status": "Available",
        "subTechniques": [],
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "CommandAndControl"
        ],
        "techniques": [
          "T1071"
        ],
        "templateVersion": "1.0.1",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0
      },
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
    }
  ]
}