Adversaries may be establishing persistent communication with untrusted public networks through repetitive beaconing patterns in wire data traffic. SOC teams should proactively hunt for this behavior in Azure Sentinel to identify potential C2 channels and mitigate lateral movement risks.
KQL Query
let lookback = 1d;
let TimeDeltaThreshold = 10;
let TotalEventsThreshold = 15;
let PercentBeaconThreshold = 95;
WireData
| where TimeGenerated > ago(lookback)
| where ipv4_is_private(RemoteIP) == false
| project TimeGenerated , LocalIP , LocalPortNumber , RemoteIP, RemotePortNumber, ReceivedBytes, SentBytes
| sort by LocalIP asc,TimeGenerated asc, RemoteIP asc, RemotePortNumber asc
| serialize
| extend nextTimeGenerated = next(TimeGenerated, 1), nextLocalIP = next(LocalIP, 1)
| extend TimeDeltainSeconds = datetime_diff('second',nextTimeGenerated,TimeGenerated)
| where LocalIP == nextLocalIP
//Whitelisting criteria/ threshold criteria
| where TimeDeltainSeconds > TimeDeltaThreshold
| where RemotePortNumber != "0"
| project TimeGenerated, TimeDeltainSeconds, LocalIP, LocalPortNumber,RemoteIP,RemotePortNumber, ReceivedBytes, SentBytes
| summarize count(), sum(ReceivedBytes), sum(SentBytes), make_list(TimeDeltainSeconds) by TimeDeltainSeconds, bin(TimeGenerated, 1h), LocalIP, RemoteIP, RemotePortNumber
| summarize (MostFrequentTimeDeltaCount, MostFrequentTimeDeltainSeconds)=arg_max(count_, TimeDeltainSeconds), TotalEvents=sum(count_), TotalSentBytes=sum(sum_SentBytes),TotalReceivedBytes=sum(sum_ReceivedBytes) by bin(TimeGenerated, 1h), LocalIP, RemoteIP, RemotePortNumber
| where TotalEvents > TotalEventsThreshold
| extend BeaconPercent = MostFrequentTimeDeltaCount/toreal(TotalEvents) * 100
| where BeaconPercent > PercentBeaconThreshold
| extend timestamp = TimeGenerated, IPCustomEntity = RemoteIP
id: 33aa0e01-87e2-43ea-87f9-2f7e3ff1d532
name: Detect beacon like pattern based on repetitive time intervals in Wire Data Traffic
description: |
'Query identifies beaconing patterns from Wire Data logs. Uses KQL functions to calculate time delta and find beaconing percentage. Results of beaconing to untrusted public networks can be investigated.'
description_detailed: |
'This query will identify beaconing patterns from Wire Data logs based on timedelta patterns. The query leverages various KQL functions
to calculate time delta and then compare it with total events observed in a day to find percentage of beaconing.
Results of such beaconing patterns to untrusted public networks can be a good starting point for investigation.
References: Blog about creating dataset to identify network beaconing via repetitive time intervals seen against total traffic
between same source-destination pair.
http://www.austintaylor.io/detect/beaconing/intrusion/detection/system/command/control/flare/elastic/stack/2017/06/10/detect-beaconing-with-flare-elasticsearch-and-intrusion-detection-systems/'
requiredDataConnectors:
- connectorId: AzureMonitor(WireData)
dataTypes:
- WireData
tactics:
- CommandAndControl
relevantTechniques:
- T1071
- T1571
query: |
let lookback = 1d;
let TimeDeltaThreshold = 10;
let TotalEventsThreshold = 15;
let PercentBeaconThreshold = 95;
WireData
| where TimeGenerated > ago(lookback)
| where ipv4_is_private(RemoteIP) == false
| project TimeGenerated , LocalIP , LocalPortNumber , RemoteIP, RemotePortNumber, ReceivedBytes, SentBytes
| sort by LocalIP asc,TimeGenerated asc, RemoteIP asc, RemotePortNumber asc
| serialize
| extend nextTimeGenerated = next(TimeGenerated, 1), nextLocalIP = next(LocalIP, 1)
| extend TimeDeltainSeconds = datetime_diff('second',nextTimeGenerated,TimeGenerated)
| where LocalIP == nextLocalIP
//Whitelisting criteria/ threshold criteria
| where TimeDeltainSeconds > TimeDeltaThreshold
| where RemotePortNumber != "0"
| project TimeGenerated, TimeDeltainSeconds, LocalIP, LocalPortNumber,RemoteIP,RemotePortNumber, ReceivedBytes, SentBytes
| summarize count(), sum(ReceivedBytes), sum(SentBytes), make_list(TimeDeltainSeconds) by TimeDeltainSeconds, bin(TimeGenerated, 1h), LocalIP, RemoteIP, RemotePortNumber
| summarize (MostFrequentTimeDeltaCount, MostFrequentTimeDeltainSeconds)=arg_max(count_, TimeDeltainSeconds), TotalEvents=sum(count_), TotalSentBytes=sum(sum_SentBytes),TotalReceivedBytes=sum(sum_ReceivedBytes) by bin(TimeGenerated, 1h), LocalIP, RemoteIP, RemotePortNumber
| where TotalEvents > TotalEventsThreshold
| extend BeaconPercent = MostFrequentTimeDeltaCount/toreal(TotalEvents) * 100
| where BeaconPercent > PercentBeaconThreshold
| extend timestamp = TimeGenerated, IPCustomEntity = RemoteIP
version: 1.0.2
metadata:
source:
kind: Community
author:
name: Shain
support:
tier: Community
categories:
Scenario: Scheduled System Backup Using a Backup Tool
Description: A legitimate backup tool (e.g., Veeam, Acronis) is configured to transfer data to a public cloud storage service (e.g., AWS S3, Azure Blob Storage) at regular intervals, mimicking a beaconing pattern.
Filter/Exclusion: Exclude traffic originating from known backup tools or associated IP ranges (e.g., AWS S3 endpoints, Azure Blob Storage endpoints). Use process.name or tool.name to filter out backup processes.
Scenario: Network Time Protocol (NTP) Synchronization
Description: NTP clients (e.g., Windows NTP client, ntpdate) synchronize time with public NTP servers (e.g., pool.ntp.org) at regular intervals, which can be misinterpreted as beaconing.
Filter/Exclusion: Exclude traffic to known NTP server IP ranges (e.g., 203.108.12.1, 132.163.12.10) or use destination.port to filter out NTP traffic on port 123.
Scenario: Scheduled Job for Log Aggregation or Monitoring
Description: A scheduled job (e.g., using cron, Task Scheduler, or Ansible) sends logs or metrics to a centralized logging system (e.g., ELK Stack, Splunk, Datadog) at fixed intervals, creating a repetitive pattern.
Filter/Exclusion: Exclude traffic to known log aggregation systems (e.g., splunk, elasticsearch, datadog) or use process.name to filter out scheduled job processes.
Scenario: Remote Management Tool with Periodic Heartbeats
Description: A remote management tool (e.g., Ansible, Puppet, Chef) sends periodic heartbeat packets