Detection rules › Kusto

GSA - Detect Connections Outside Operational Hours

Status
available
Severity
high
Time window
1d
Source
github.com/Azure/Azure-Sentinel

This query identifies connections that occur outside of the defined operational hours. It helps in monitoring and flagging any unusual activity that may occur during non-business hours, indicating potential security concerns or policy violations.

MITRE ATT&CK coverage

Rule body kusto

id: 4c9f0a9e-44d7-4c9b-b7f0-f6a6e0d8f8fa
name: GSA - Detect Connections Outside Operational Hours
description: |
  This query identifies connections that occur outside of the defined operational hours. It helps in monitoring and flagging any unusual activity that may occur during non-business hours, indicating potential security concerns or policy violations.
severity: High
status: Available
requiredDataConnectors:
  - connectorId: AzureActiveDirectory
    dataTypes:
      - NetworkAccessTrafficLogs
queryFrequency: 1h
queryPeriod: 24h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - InitialAccess
relevantTechniques:
  - T1078
  - T1133
query: |
  let starttime = todatetime('{{StartTimeISO}}');
  let endtime = todatetime('{{EndTimeISO}}');
  let operational_start_hour = 8; // Start of operational hours (8 AM)
  let operational_end_hour = 18; // End of operational hours (6 PM)
  NetworkAccessTraffic
  | where TimeGenerated between (starttime .. endtime)
  | extend HourOfDay = datetime_part('hour', TimeGenerated)
  | where HourOfDay < operational_start_hour or HourOfDay >= operational_end_hour
  | project TimeGenerated, UserPrincipalName, SourceIp, DestinationIp, DestinationPort, Action, DeviceId, DeviceOperatingSystem, ConnectionId
  | extend IPCustomEntity = SourceIp, AccountCustomEntity = UserPrincipalName
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: Name
        columnName: AccountCustomEntity
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: IPCustomEntity
version: 1.0.2
kind: Scheduled

Stages and Predicates

Parameters

let starttime = todatetime('{{StartTimeISO}}');
let endtime = todatetime('{{EndTimeISO}}');
let operational_start_hour = 8;
let operational_end_hour = 18;

Stage 1: source

NetworkAccessTraffic

Stage 2: where

| where TimeGenerated between (starttime .. endtime)

Stage 3: extend

| extend HourOfDay = datetime_part('hour', TimeGenerated)

Stage 4: where

| where HourOfDay < operational_start_hour or HourOfDay >= operational_end_hour

Stage 5: project

| project TimeGenerated, UserPrincipalName, SourceIp, DestinationIp, DestinationPort, Action, DeviceId, DeviceOperatingSystem, ConnectionId

Stage 6: extend

| extend IPCustomEntity = SourceIp, AccountCustomEntity = UserPrincipalName

Indicators

Each row is a field, operator, and value that the rule matches. The corpus column counts how many other rules in the catalog look for the same combination: high numbers point to widely-used, community-vetted indicators. Blank or 1 shows that the indicator is specific to this rule.

FieldKindValues
HourOfDayge
  • 18 transforms: cased
HourOfDaylt
  • 8 transforms: cased
TimeGeneratedge
  • starttime
TimeGeneratedle
  • endtime

Output fields

Fields the rule emits when it matches. Chronicle authors list these in the outcome block; they appear on the detection and $risk_score drives alerting. Sentinel / Defender XDR rules build them up through project / summarize / extend stages. Sentinel maps these into alert fields via entityMappings and customDetails; Defender XDR custom detections surface them as alert fields directly.

FieldSource
Actionproject
ConnectionIdproject
DestinationIpproject
DestinationPortproject
DeviceIdproject
DeviceOperatingSystemproject
SourceIpproject
TimeGeneratedproject
UserPrincipalNameproject
AccountCustomEntityextend
IPCustomEntityextend