Hunting for Cobalt Strike and C2 Periodic Beaconing Using DeviceNetworkEvents

Detect outbound Command and Control beaconing patterns with low interval variance using statistical time-delta functions in Defender XDR KQL.

Dikshant Lather
2 min read ·
Hunting for Cobalt Strike and C2 Periodic Beaconing Using DeviceNetworkEvents

Hunting for Cobalt Strike and C2 Periodic Beaconing Using DeviceNetworkEvents

Command and Control implants periodically phone home to their listener to retrieve pending instructions (sleep/jitter cycles). While attackers introduce sleep jitter (e.g., 20% randomization) to evade static interval checks, mathematical delta analysis still reveals high regularity over extended observation windows.

Here is how to calculate interval standard deviations to unmask stealth C2 beacons.


Log Source

  • Microsoft Defender for Endpoint: DeviceNetworkEvents

C2 Beaconing KQL Hunting Script

// Detect Low-Variance Periodic Outbound Connections (C2 Heartbeat)
let timeWindow = 12h;
let minConnections = 30;
DeviceNetworkEvents
| where TimeGenerated >= ago(timeWindow)
| where ActionType == "ConnectionSuccess"
| where RemotePort in (80, 443, 8080, 8443)
// Filter out local and broadcast traffic
| where not(ipv4_is_private(RemoteIP))
| sort by DeviceName asc, RemoteIP asc, TimeGenerated asc
| serialize
| extend PrevTime = prev(TimeGenerated, 1),
         PrevDevice = prev(DeviceName, 1),
         PrevRemoteIP = prev(RemoteIP, 1)
| where DeviceName == PrevDevice and RemoteIP == PrevRemoteIP
| extend IntervalSeconds = datetime_diff('second', TimeGenerated, PrevTime)
| where IntervalSeconds between (10 .. 600) // Focus on regular beacon windows
| summarize 
    ConnectionCount = count(),
    AvgInterval = round(avg(IntervalSeconds), 1),
    StdDevInterval = round(stdev(IntervalSeconds), 1),
    MinInterval = min(IntervalSeconds),
    MaxInterval = max(IntervalSeconds)
    by DeviceName, InitiatingProcessFileName, RemoteIP, RemoteUrl
| where ConnectionCount >= minConnections
// Jitter ratio: a very low StdDev relative to AvgInterval indicates automated beaconing
| extend JitterRatio = round(StdDevInterval / AvgInterval, 2)
| where JitterRatio < 0.25 // Highly periodic signal
| project DeviceName, InitiatingProcessFileName, RemoteIP, RemoteUrl, ConnectionCount, AvgInterval, StdDevInterval, JitterRatio
| order by JitterRatio asc

Understanding the Math

  • Delta Serialization: datetime_diff('second', TimeGenerated, PrevTime) computes the exact seconds elapsed between consecutive packets sent to the destination.
  • Standard Deviation (stdev()): Human browsing exhibits random delays (stddev > 50s). A beacon configured with a 60s sleep and 10% jitter will stay tightly grouped around 54s to 66s, yielding a low JitterRatio.

MITRE ATT&CK Mapping

  • Tactic: Command and Control (TA0011)
  • Technique: Application Layer Protocol: Web Protocols (T1071.001)
Dikshant Lather
Written by

Dikshant Lather

Cyber Security & AI Architect

Responses (0)

Join the technical conversation or share implementation thoughts.

What are your thoughts?

Sign in to join the technical discussion or share feedback.

There are currently no responses for this story. Be the first to respond.