Azure / Azure-Sentinel

Cloud-native SIEM for intelligent security analytics for your entire enterprise.
https://azure.microsoft.com/en-us/services/azure-sentinel/
MIT License
4.5k stars 2.96k forks source link

Condition Logic Issue | TI Map IP Entity to CommonSecurityLog #11069

Open geopd opened 2 weeks ago

geopd commented 2 weeks ago

Issue:

There appears to be a logic flaw in the "TI Map IP Entity to CommonSecurityLog" rule.

  1. The current implementation only takes into account the SourceIP when mapping to CS_ipEntity, which results in the DestinationIP being omitted.
  2. In firewall logs, both SourceIP and DestinationIP are present, and due to the existing if condition, when SourceIP is assigned to CS_ipEntity, the DestinationIP is not matched with threat intelligence.
  3. This causes detections based on DestinationIP to be missed.

image

Updated Query:

let dt_lookBack = 1h;
let ioc_lookBack = 14d;
let IP_Indicators = ThreatIntelligenceIndicator
  | where TimeGenerated >= ago(ioc_lookBack) and ExpirationDateTime > now()
  | summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by IndicatorId
  | where Active == true
  | extend TI_ipEntity = coalesce(NetworkIP, NetworkDestinationIP, NetworkSourceIP, EmailSourceIpAddress, "NO_IP")
  | where TI_ipEntity != "NO_IP"
  |  where ipv4_is_private(TI_ipEntity) == false and  TI_ipEntity !startswith "fe80" and TI_ipEntity !startswith "::" and TI_ipEntity !startswith "127.";
let CS_logs = CommonSecurityLog
  | where TimeGenerated >= ago(dt_lookBack)
  | extend MessageIP = extract_all(@'(\d+\.\d+\.\d+\.\d+)', Message)
  | extend CS_ipEntity1 = iff(isnotempty(SourceIP), SourceIP, iff(isnotempty(MessageIP), MessageIP[0], ""))
  | extend CS_ipEntity2 = iff(isnotempty(DestinationIP), DestinationIP, "")
  | extend CommonSecurityLog_TimeGenerated = TimeGenerated;
let join_CS_ipEntity1 = IP_Indicators
  | join kind=innerunique (CS_logs) on $left.TI_ipEntity == $right.CS_ipEntity1
  | where CommonSecurityLog_TimeGenerated < ExpirationDateTime
  | extend MatchedEntity = iff(TI_ipEntity == SourceIP, "SourceIP", "MessageIP");
let join_CS_ipEntity2 = IP_Indicators
  | join kind=innerunique (CS_logs) on $left.TI_ipEntity == $right.CS_ipEntity2
  | where CommonSecurityLog_TimeGenerated < ExpirationDateTime
  | extend MatchedEntity = "DestinationIP";
join_CS_ipEntity1
| union join_CS_ipEntity2
| summarize CommonSecurityLog_TimeGenerated = arg_max(CommonSecurityLog_TimeGenerated, *) by IndicatorId, CS_ipEntity1, CS_ipEntity2, MatchedEntity
| project timestamp = CommonSecurityLog_TimeGenerated, SourceIP, DestinationIP, MessageIP, Message, DeviceVendor, DeviceProduct, IndicatorId, ThreatType, ExpirationDateTime, ConfidenceScore, TI_ipEntity, CS_ipEntity1, CS_ipEntity2, MatchedEntity, LogSeverity, DeviceAction, Type

https://github.com/Azure/Azure-Sentinel/blob/8346b62bed3af440eb004ab84e9fa34095fb77d7/Solutions/Threat%20Intelligence/Analytic%20Rules/IPEntity_CustomSecurityLog.yaml#L48C9-L48C82

v-rusraut commented 2 days ago

Hi @geopd, Thanks for flagging this issue, we will investigate this issue and get back to you with some updates. Thanks!