Detection rules › Kusto

GSA - Detect Protocol Changes for Destination Ports

Status
available
Severity
medium
Time window
8d
Group by
AlertTimeDstPort, AlertTimeProtocol, DestinationFqdn, SourceIp
Source
github.com/Azure/Azure-Sentinel

Identifies changes in the protocol used for specific destination ports, comparing the current runtime with a learned baseline. This can indicate potential protocol misuse or configuration changes. Configurable Parameters: - Learning period: The time range to establish the baseline. Default is set to 7 days. - Run time: The time range for current analysis. Default is set to 1 day.

MITRE ATT&CK coverage

TacticTechniques
Command & Control

Rule body

id: f6a8d6a5-3e9f-47c8-a8d5-1b2b9d3b7d6a
name: GSA - Detect Protocol Changes for Destination Ports
description: |
  Identifies changes in the protocol used for specific destination ports, comparing the current runtime with a learned baseline.
  This can indicate potential protocol misuse or configuration changes.
  Configurable Parameters:
  - Learning period: The time range to establish the baseline. Default is set to 7 days.
  - Run time: The time range for current analysis. Default is set to 1 day.
severity: Medium
status: Available
requiredDataConnectors:
  - connectorId: AzureActiveDirectory
    dataTypes:
      - NetworkAccessTrafficLogs
queryFrequency: 1h
queryPeriod: 8d
triggerOperator: gt
triggerThreshold: 1
tactics:
  - DefenseEvasion
  - Exfiltration
  - CommandAndControl
relevantTechniques:
  - T1571
query: |
  let LearningPeriod = 7d;
  let RunTime = 1d;
  let StartLearningPeriod = ago(LearningPeriod + RunTime);
  let EndRunTime = ago(RunTime);
  let LearningPortToProtocol = 
    NetworkAccessTraffic
    | where TimeGenerated between (StartLearningPeriod .. EndRunTime)
    | where isnotempty(DestinationPort)
    | summarize LearningTimeCount = count() by LearningTimeDstPort = DestinationPort, LearningTimeProtocol = TransportProtocol, SourceIp, DestinationFqdn;
  let AlertTimePortToProtocol = 
    NetworkAccessTraffic
    | where TimeGenerated between (EndRunTime .. now())
    | where isnotempty(DestinationPort)
    | summarize AlertTimeCount = count() by AlertTimeDstPort = DestinationPort, AlertTimeProtocol = TransportProtocol, SourceIp, DestinationFqdn;
  AlertTimePortToProtocol
    | join kind=leftouter (LearningPortToProtocol) on $left.AlertTimeDstPort == $right.LearningTimeDstPort and $left.SourceIp == $right.SourceIp and $left.DestinationFqdn == $right.DestinationFqdn
    | where isnotempty(LearningTimeProtocol) and isnotempty(AlertTimeProtocol) and LearningTimeProtocol != AlertTimeProtocol
    | project AlertTimeDstPort, AlertTimeProtocol, LearningTimeProtocol, SourceIp, DestinationFqdn
    | extend IPCustomEntity = SourceIp, FqdnCustomEntity = DestinationFqdn
entityMappings:
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: IPCustomEntity
  - entityType: URL
    fieldMappings:
      - identifier: Url
        columnName: FqdnCustomEntity
version: 1.0.4
kind: Scheduled

Stages and Predicates

Parameters

let LearningPeriod = 7d;
let RunTime = 1d;
let StartLearningPeriod = ago(LearningPeriod + RunTime);
let EndRunTime = ago(RunTime);

let AlertTimePortToProtocol is inlined into the numbered stages below.

Let binding: LearningPortToProtocol used in Stage 5

let LearningPortToProtocol = NetworkAccessTraffic
  | where TimeGenerated between (StartLearningPeriod .. EndRunTime)
  | where isnotempty(DestinationPort)
  | summarize LearningTimeCount = count() by LearningTimeDstPort = DestinationPort, LearningTimeProtocol = TransportProtocol, SourceIp, DestinationFqdn;

Stages 1 to 4 define let AlertTimePortToProtocol (the rule's main pipeline source); stages 5 to 8 run on it.

Stage 1: source

NetworkAccessTraffic

Stage 2: where

| where TimeGenerated between (EndRunTime .. now())

Stage 3: where

| where isnotempty(DestinationPort)

Stage 4: summarize

| summarize AlertTimeCount = count() by AlertTimeDstPort = DestinationPort, AlertTimeProtocol = TransportProtocol, SourceIp, DestinationFqdn

Stage 5: join

AlertTimePortToProtocol
| join kind=leftouter (LearningPortToProtocol) on $left.AlertTimeDstPort == $right.LearningTimeDstPort and $left.SourceIp == $right.SourceIp and $left.DestinationFqdn == $right.DestinationFqdn

Stage 6: where

| where isnotempty(LearningTimeProtocol) and isnotempty(AlertTimeProtocol) and LearningTimeProtocol != AlertTimeProtocol

Stage 7: project

| project AlertTimeDstPort, AlertTimeProtocol, LearningTimeProtocol, SourceIp, DestinationFqdn

Stage 8: extend

| extend IPCustomEntity = SourceIp, FqdnCustomEntity = DestinationFqdn

Indicators

These rows show field, operator, and value matches.

Output fields

These fields are emitted when the rule matches.

FieldSource
AlertTimeDstPortproject
AlertTimeProtocolproject
DestinationFqdnproject
LearningTimeProtocolproject
SourceIpproject
FqdnCustomEntityextend
IPCustomEntityextend