Detection rules › Kusto
Palo Alto - potential beaconing detected
'Identifies beaconing patterns from Palo Alto Network traffic logs based on recurrent timedelta patterns. The query leverages various KQL functions to calculate time deltas and then compares it with total events observed in a day to find percentage of beaconing. This outbound beaconing pattern to untrusted public networks should be investigated for any malware callbacks or data exfiltration attempts. Reference Blog: https://medium.com/@HuntOperator/detect-beaconing-with-flare-elastic-stack-and-intrusion-detection-systems-110dc74e0c56 https://techcommunity.microsoft.com/t5/microsoft-sentinel-blog/detect-network-beaconing-via-intra-request-time-delta-patterns/ba-p/779586'
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Command & Control | T1071 Application Layer Protocol, T1571 Non-Standard Port |
Rule body kusto
id: f0be259a-34ac-4946-aa15-ca2b115d5feb
name: Palo Alto - potential beaconing detected
description: |
'Identifies beaconing patterns from Palo Alto Network traffic logs based on recurrent timedelta patterns.
The query leverages various KQL functions to calculate time deltas and then compares it with total events observed in a day to find percentage of beaconing.
This outbound beaconing pattern to untrusted public networks should be investigated for any malware callbacks or data exfiltration attempts.
Reference Blog:
https://medium.com/@HuntOperator/detect-beaconing-with-flare-elastic-stack-and-intrusion-detection-systems-110dc74e0c56
https://techcommunity.microsoft.com/t5/microsoft-sentinel-blog/detect-network-beaconing-via-intra-request-time-delta-patterns/ba-p/779586'
severity: Low
status: Available
requiredDataConnectors:
- connectorId: CefAma
dataTypes:
- CommonSecurityLog
queryFrequency: 1d
queryPeriod: 2d
triggerOperator: gt
triggerThreshold: 0
tactics:
- CommandAndControl
relevantTechniques:
- T1071
- T1571
query: |
let starttime = 2d;
let endtime = 1d;
let TimeDeltaThreshold = 25;
let TotalEventsThreshold = 30;
let MostFrequentTimeDeltaThreshold = 25;
let PercentBeaconThreshold = 80;
CommonSecurityLog
| where DeviceVendor == "Palo Alto Networks" and Activity == "TRAFFIC"
| where TimeGenerated between (startofday(ago(starttime))..startofday(ago(endtime)))
| where ipv4_is_private(DestinationIP)== false
| project TimeGenerated, DeviceName, SourceUserID, SourceIP, SourcePort, DestinationIP, DestinationPort, ReceivedBytes, SentBytes
| sort by SourceIP asc,TimeGenerated asc, DestinationIP asc, DestinationPort asc
| serialize
| extend nextTimeGenerated = next(TimeGenerated, 1), nextSourceIP = next(SourceIP, 1)
| extend TimeDeltainSeconds = datetime_diff('second',nextTimeGenerated,TimeGenerated)
| where SourceIP == nextSourceIP
//Whitelisting criteria/ threshold criteria
| where TimeDeltainSeconds > TimeDeltaThreshold
| summarize count(), sum(ReceivedBytes), sum(SentBytes)
by TimeDeltainSeconds, bin(TimeGenerated, 1h), DeviceName, SourceUserID, SourceIP, DestinationIP, DestinationPort
| summarize (MostFrequentTimeDeltaCount, MostFrequentTimeDeltainSeconds) = arg_max(count_, TimeDeltainSeconds), TotalEvents=sum(count_), TotalSentBytes = sum(sum_SentBytes), TotalReceivedBytes = sum(sum_ReceivedBytes)
by bin(TimeGenerated, 1h), DeviceName, SourceUserID, SourceIP, DestinationIP, DestinationPort
| where TotalEvents > TotalEventsThreshold and MostFrequentTimeDeltaCount > MostFrequentTimeDeltaThreshold
| extend BeaconPercent = MostFrequentTimeDeltaCount/toreal(TotalEvents) * 100
| where BeaconPercent > PercentBeaconThreshold
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: SourceUserID
- entityType: Host
fieldMappings:
- identifier: FullName
columnName: DeviceName
- entityType: IP
fieldMappings:
- identifier: Address
columnName: DestinationIP
version: 1.0.7
kind: Scheduled
Stages and Predicates
Parameters
let starttime = 2d;
let endtime = 1d;
let TimeDeltaThreshold = 25;
let TotalEventsThreshold = 30;
let MostFrequentTimeDeltaThreshold = 25;
let PercentBeaconThreshold = 80;
Stage 1: source
CommonSecurityLog
Stage 2: where
| where DeviceVendor == "Palo Alto Networks" and Activity == "TRAFFIC"
Stage 3: where
| where TimeGenerated between (startofday(ago(starttime))..startofday(ago(endtime)))
Stage 4: where
| where ipv4_is_private(DestinationIP)== false
Stage 5: project
| project TimeGenerated, DeviceName, SourceUserID, SourceIP, SourcePort, DestinationIP, DestinationPort, ReceivedBytes, SentBytes
Stage 6: sort
| sort by SourceIP asc,TimeGenerated asc, DestinationIP asc, DestinationPort asc
Stage 7: kusto:serialize
| serialize
Stage 8: extend
| extend nextTimeGenerated = next(TimeGenerated, 1), nextSourceIP = next(SourceIP, 1)
Stage 9: extend
| extend TimeDeltainSeconds = datetime_diff('second',nextTimeGenerated,TimeGenerated)
Stage 10: where
| where SourceIP == nextSourceIP
Stage 11: where
| where TimeDeltainSeconds > TimeDeltaThreshold
Stage 12: summarize
| summarize count(), sum(ReceivedBytes), sum(SentBytes)
by TimeDeltainSeconds, bin(TimeGenerated, 1h), DeviceName, SourceUserID, SourceIP, DestinationIP, DestinationPort
Stage 13: summarize
| summarize (MostFrequentTimeDeltaCount, MostFrequentTimeDeltainSeconds) = arg_max(count_, TimeDeltainSeconds), TotalEvents=sum(count_), TotalSentBytes = sum(sum_SentBytes), TotalReceivedBytes = sum(sum_ReceivedBytes)
by bin(TimeGenerated, 1h), DeviceName, SourceUserID, SourceIP, DestinationIP, DestinationPort
Stage 14: where
| where TotalEvents > TotalEventsThreshold and MostFrequentTimeDeltaCount > MostFrequentTimeDeltaThreshold
Stage 15: extend
| extend BeaconPercent = MostFrequentTimeDeltaCount/toreal(TotalEvents) * 100
Stage 16: where
| where BeaconPercent > PercentBeaconThreshold
Exclusions
Top-level NOT(...) conjuncts: predicates this rule actively suppresses.
| Field | Kind | Excluded values |
|---|---|---|
DestinationIP | cidr_match | 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16, 127.0.0.0/8 |
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.
| Field | Kind | Values |
|---|---|---|
Activity | eq |
|
BeaconPercent | gt |
|
DeviceVendor | eq |
|
MostFrequentTimeDeltaCount | gt |
|
SourceIP | eq |
|
TimeDeltainSeconds | gt |
|
TotalEvents | gt |
|
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.
| Field | Source |
|---|---|
DestinationIP | summarize |
DestinationPort | summarize |
DeviceName | summarize |
MostFrequentTimeDeltaCount | summarize |
SourceIP | summarize |
SourceUserID | summarize |
TotalEvents | summarize |
TotalReceivedBytes | summarize |
TotalSentBytes | summarize |
BeaconPercent | extend |