Skip to content

Event Correlation

Threat hunting in Microsoft Sentinel often requires linking seemingly unrelated events across diverse log sources to uncover hidden attack patterns. Event correlation techniques leverage structured querying (e.g., KQL) to identify temporal, behavioral, or contextual relationships between events, enabling analysts to detect threats that evade traditional detection rules.


Time-Based Correlation

Time-based correlation identifies sequences of events that occur within a defined time window, such as a login failure followed by a successful login, or a file download preceded by network traffic to a suspicious IP.

Example: Detecting a "credential stuffing" attack by correlating failed login attempts with subsequent successful logins.

let failedLogins = datatable(TimeStamp: datetime, User: string, Status: string)
[
    datetime(2023-10-01T08:00:00), "user1", "Failed",
    datetime(2023-10-01T08:01:00), "user2", "Failed",
    datetime(2023-10-01T08:02:00), "user3", "Failed"
];
let successfulLogins = datatable(TimeStamp: datetime, User: string)
[
    datetime(2023-10-01T08:05:00), "user1",
    datetime(2023-10-01T08:10:00), "user2"
];
failedLogins
| join (successfulLogins) on (User)
| where TimeStamp of successfulLogins - TimeStamp of failedLogins < 5m
| project User, Failed_Time = TimeStamp of failedLogins, Success_Time = TimeStamp of successfulLogins

Note: Adjust the time window (5m) based on your environment’s normal behavior. Use extend for more complex temporal logic (e.g., overlapping events).


Behavioral Correlation

Behavioral correlation identifies deviations from baseline activity, such as unusual access times, unexpected file modifications, or atypical command executions.

Example: Flagging logins occurring outside of typical hours.

SecurityEvent
| where EventId == 4624
| summarize AvgLoginTime = avg(Timestamp) by User
| extend NormalHours = 8..17
| where (hour(AvgLoginTime) < 8 or hour(AvgLoginTime) > 17)
| project User, AvgLoginTime

Note: Combine with summarize and bin for time-series analysis. Use machine learning models (e.g., in Sentinel’s built-in rules) for automated baseline detection.


IoC-Based Correlation

Indicators of Compromise (IoCs) such as IPs, hashes, or domains can be used to correlate events across logs. This is critical for identifying known malicious activity.

Example: Filtering logs for connections to a known malicious IP.

let maliciousIPs = datatable(IP: string)
[
    "192.168.1.100",
    "10.0.0.50"
];
NetworkTraffic
| where SourceIP in (maliciousIPs.IP)
| project Timestamp, SourceIP, DestinationIP, Protocol

Note: Store IoCs in a centralized table (e.g., a CSV file) and use join or in for efficient filtering. Update IoC lists regularly using threat intelligence feeds.


Cross-Source Correlation

Cross-source correlation links events from different systems (e.g., firewall logs, endpoint logs, and application logs) to reconstruct attack sequences.

Example: Linking a firewall rule bypass with a subsequent file download.

let firewallEvents = datatable(TimeStamp: datetime, SourceIP: string, DestinationIP: string)
[
    datetime(2023-10-01T09:00:00), "192.168.1.10", "10.0.0.50"
];
let fileDownloads = datatable(TimeStamp: datetime, User: string, FilePath: string)
[
    datetime(2023-10-01T09:05:00), "user1", "C:\\malicious.exe"
];
firewallEvents
| join fileDownloads on (SourceIP == "10.0.0.50" and DestinationIP == "192.168.1.10")
| project TimeStamp, SourceIP, DestinationIP, FilePath

Note: Use common fields (e.g., IP addresses, user IDs) as join keys. Validate correlations against contextual data to avoid false positives.


Key takeaways

  • Time-based correlation helps detect sequential threats like credential stuffing.
  • Behavioral analysis identifies anomalies in user or system activity.
  • IoC-based correlation links events to known malicious entities.
  • Cross-source correlation reconstructs attack paths by merging logs from multiple systems.
  • Always validate correlations with contextual evidence to reduce false positives.