Back
Id4ef07345-5d89-4f5b-9c64-a180d81a6176
RulenameGSA - TI Domain Entity
DescriptionThis query identifies Domain 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%20Domain%20Entity.yaml
Arm template4ef07345-5d89-4f5b-9c64-a180d81a6176.json
Deploy To Azure
let dt_lookBack = 1h;
let ioc_lookBack = 14d;
let NetworkAccessTraff_ = NetworkAccessTraffic
| where TimeGenerated >= ago(dt_lookBack)
| where TrafficType == "internet"
| where isnotempty(DestinationFqdn)
| extend Domain = extract(@'([^.]+\.[^.]+)$', 1, DestinationFqdn)
| project-rename GSANetworkAccessTraffic_TimeGenerated = TimeGenerated;
let NetworkAccessTraffiDomains =
    NetworkAccessTraff_
    | distinct Domain;
ThreatIntelIndicators
  | extend IndicatorType = replace(@'\[|\]|"""', "", tostring(split(ObservableKey, ":", 0)))
  | where IndicatorType == "domain-name"
  | extend DomainName = tolower(ObservableValue)
  | where TimeGenerated >= ago(ioc_lookBack)
  | extend IndicatorId = tostring(split(Id, "--")[2])
  | where DomainName in (NetworkAccessTraffiDomains)
  | summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by Id, ObservableValue
  | where IsActive and (ValidUntil > now() or isempty(ValidUntil))
  | extend Description = tostring(parse_json(Data).description)
  | extend TrafficLightProtocolLevel = tostring(parse_json(AdditionalFields).TLPLevel)
  | where Description !contains_cs "State: inactive;" and Description !contains_cs "State: falsepos;"
  | project-reorder *, IsActive, Tags, TrafficLightProtocolLevel, DomainName, Type
  | join kind=innerunique (NetworkAccessTraff_) on $left.DomainName == $right.Domain
  | extend GSAThreatType = ThreatType
  | summarize GSANetworkAccessTraffic_TimeGenerated = arg_max(GSANetworkAccessTraffic_TimeGenerated, *) by Id, DestinationFqdn
  | project-reorder *,
    Tags,
    TrafficLightProtocolLevel,
    Type,
    DomainName,
    UserPrincipalName,
    UserId,
    DeviceId,
    InitiatingProcessName,
    GSAThreatType,
    DestinationUrl,
    DestinationPort,
    SourceIp,
    SourcePort,
    HttpUserAgent
name: GSA - TI Domain Entity
triggerOperator: gt
query: |
  let dt_lookBack = 1h;
  let ioc_lookBack = 14d;
  let NetworkAccessTraff_ = NetworkAccessTraffic
  | where TimeGenerated >= ago(dt_lookBack)
  | where TrafficType == "internet"
  | where isnotempty(DestinationFqdn)
  | extend Domain = extract(@'([^.]+\.[^.]+)$', 1, DestinationFqdn)
  | project-rename GSANetworkAccessTraffic_TimeGenerated = TimeGenerated;
  let NetworkAccessTraffiDomains =
      NetworkAccessTraff_
      | distinct Domain;
  ThreatIntelIndicators
    | extend IndicatorType = replace(@'\[|\]|"""', "", tostring(split(ObservableKey, ":", 0)))
    | where IndicatorType == "domain-name"
    | extend DomainName = tolower(ObservableValue)
    | where TimeGenerated >= ago(ioc_lookBack)
    | extend IndicatorId = tostring(split(Id, "--")[2])
    | where DomainName in (NetworkAccessTraffiDomains)
    | summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by Id, ObservableValue
    | where IsActive and (ValidUntil > now() or isempty(ValidUntil))
    | extend Description = tostring(parse_json(Data).description)
    | extend TrafficLightProtocolLevel = tostring(parse_json(AdditionalFields).TLPLevel)
    | where Description !contains_cs "State: inactive;" and Description !contains_cs "State: falsepos;"
    | project-reorder *, IsActive, Tags, TrafficLightProtocolLevel, DomainName, Type
    | join kind=innerunique (NetworkAccessTraff_) on $left.DomainName == $right.Domain
    | extend GSAThreatType = ThreatType
    | summarize GSANetworkAccessTraffic_TimeGenerated = arg_max(GSANetworkAccessTraffic_TimeGenerated, *) by Id, DestinationFqdn
    | project-reorder *,
      Tags,
      TrafficLightProtocolLevel,
      Type,
      DomainName,
      UserPrincipalName,
      UserId,
      DeviceId,
      InitiatingProcessName,
      GSAThreatType,
      DestinationUrl,
      DestinationPort,
      SourceIp,
      SourcePort,
      HttpUserAgent
queryFrequency: 1h
description: |
  This query identifies Domain indicators of compromise (IOCs) from threat intelligence (TI) by searching for matches in GSA NetworkAccessTraffic.
id: 4ef07345-5d89-4f5b-9c64-a180d81a6176
triggerThreshold: 0
queryPeriod: 14d
kind: Scheduled
status: Available
severity: Medium
requiredDataConnectors:
- connectorId: AzureActiveDirectory
  dataTypes:
  - NetworkAccessTrafficLogs
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Global%20Secure%20Access/Analytic%20Rules/GSA%20-%20TI%20Domain%20Entity.yaml
relevantTechniques:
- T1071
tactics:
- CommandAndControl
entityMappings:
- fieldMappings:
  - identifier: Name
    columnName: UserPrincipalName
  entityType: Account
- fieldMappings:
  - identifier: Address
    columnName: SourceIp
  entityType: IP
- fieldMappings:
  - identifier: Url
    columnName: DestinationFqdn
  entityType: URL
- fieldMappings:
  - identifier: CommandLine
    columnName: InitiatingProcessName
  entityType: Process
{
  "$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/4ef07345-5d89-4f5b-9c64-a180d81a6176')]",
      "kind": "Scheduled",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/4ef07345-5d89-4f5b-9c64-a180d81a6176')]",
      "properties": {
        "alertRuleTemplateName": "4ef07345-5d89-4f5b-9c64-a180d81a6176",
        "customDetails": null,
        "description": "This query identifies Domain indicators of compromise (IOCs) from threat intelligence (TI) by searching for matches in GSA NetworkAccessTraffic.\n",
        "displayName": "GSA - TI Domain Entity",
        "enabled": true,
        "entityMappings": [
          {
            "entityType": "Account",
            "fieldMappings": [
              {
                "columnName": "UserPrincipalName",
                "identifier": "Name"
              }
            ]
          },
          {
            "entityType": "IP",
            "fieldMappings": [
              {
                "columnName": "SourceIp",
                "identifier": "Address"
              }
            ]
          },
          {
            "entityType": "URL",
            "fieldMappings": [
              {
                "columnName": "DestinationFqdn",
                "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%20Domain%20Entity.yaml",
        "query": "let dt_lookBack = 1h;\nlet ioc_lookBack = 14d;\nlet NetworkAccessTraff_ = NetworkAccessTraffic\n| where TimeGenerated >= ago(dt_lookBack)\n| where TrafficType == \"internet\"\n| where isnotempty(DestinationFqdn)\n| extend Domain = extract(@'([^.]+\\.[^.]+)$', 1, DestinationFqdn)\n| project-rename GSANetworkAccessTraffic_TimeGenerated = TimeGenerated;\nlet NetworkAccessTraffiDomains =\n    NetworkAccessTraff_\n    | distinct Domain;\nThreatIntelIndicators\n  | extend IndicatorType = replace(@'\\[|\\]|\"\"\"', \"\", tostring(split(ObservableKey, \":\", 0)))\n  | where IndicatorType == \"domain-name\"\n  | extend DomainName = tolower(ObservableValue)\n  | where TimeGenerated >= ago(ioc_lookBack)\n  | extend IndicatorId = tostring(split(Id, \"--\")[2])\n  | where DomainName in (NetworkAccessTraffiDomains)\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 TrafficLightProtocolLevel = tostring(parse_json(AdditionalFields).TLPLevel)\n  | where Description !contains_cs \"State: inactive;\" and Description !contains_cs \"State: falsepos;\"\n  | project-reorder *, IsActive, Tags, TrafficLightProtocolLevel, DomainName, Type\n  | join kind=innerunique (NetworkAccessTraff_) on $left.DomainName == $right.Domain\n  | extend GSAThreatType = ThreatType\n  | summarize GSANetworkAccessTraffic_TimeGenerated = arg_max(GSANetworkAccessTraffic_TimeGenerated, *) by Id, DestinationFqdn\n  | project-reorder *,\n    Tags,\n    TrafficLightProtocolLevel,\n    Type,\n    DomainName,\n    UserPrincipalName,\n    UserId,\n    DeviceId,\n    InitiatingProcessName,\n    GSAThreatType,\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.0",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0
      },
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
    }
  ]
}