Detection rules › Kusto

TI map IP entity to Network Session Events (ASIM Network Session schema)

Status
available
Severity
medium
Time window
14d
Group by
Id, IoCIP, ObservableValue, TI_ipEntity
Source
github.com/Azure/Azure-Sentinel

'This rule identifies a match Network Sessions for which the source or destination IP address is a known IoC. This analytic rule uses ASIM and supports any built-in or custom source that supports the ASIM NetworkSession schema'

MITRE ATT&CK coverage

TacticTechniques
Command & ControlT1071 Application Layer Protocol

Rule body kusto

id: 54f4ceb4-fd83-4633-b5b0-c0de9feb8890
name: TI map IP entity to Network Session Events (ASIM Network Session schema)
description: |
  'This rule identifies a match Network Sessions for which the source or destination IP address is a known IoC. This analytic rule uses [ASIM](https://aka.ms/AboutASIM) and supports any built-in or custom source that supports the ASIM NetworkSession schema'
severity: Medium
status: Available
requiredDataConnectors:
  - connectorId: AWSS3
    dataTypes:
      - AWSVPCFlow
  - connectorId: MicrosoftThreatProtection
    dataTypes:
      - DeviceNetworkEvents
  - connectorId: SecurityEvents
    dataTypes:
      - SecurityEvent
  - connectorId: WindowsForwardedEvents
    dataTypes:
      - WindowsEvent
  - connectorId: Zscaler
    dataTypes:
      - CommonSecurityLog
  - connectorId: MicrosoftSysmonForLinux
    dataTypes:
      - Syslog
  - connectorId: PaloAltoNetworks
    dataTypes:
      - CommonSecurityLog
  - connectorId: AzureMonitor(VMInsights)
    dataTypes:
      - VMConnection
  - connectorId: AzureFirewall
    dataTypes:
      - AzureDiagnostics
  - connectorId: AzureNSG
    dataTypes:
      - AzureDiagnostics
  - connectorId: CiscoASA
    dataTypes:
      - CommonSecurityLog
  - connectorId: Corelight
    dataTypes:
      - Corelight_CL
  - connectorId: AIVectraStream
    dataTypes:
      - VectraStream
  - connectorId: CheckPoint
    dataTypes:
      - CommonSecurityLog
  - connectorId: Fortinet
    dataTypes:
      - CommonSecurityLog
  - connectorId: MicrosoftDefenderThreatIntelligence
    dataTypes:
      - ThreatIntelIndicators
  - connectorId: CiscoMeraki
    dataTypes:
      - Syslog
      - CiscoMerakiNativePoller
  - connectorId: ThreatIntelligenceTaxii
    dataTypes:
      - ThreatIntelIndicators

queryFrequency: 1h
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - CommandAndControl
relevantTechniques:
  - T1071
query: |
  let dt_lookBack = 1h;
  let ioc_lookBack = 14d;
  let IP_TI = materialize (
    ThreatIntelIndicators
    //extract key part of kv pair
       | extend IndicatorType = replace(@"\[|\]|\""", "", tostring(split(ObservableKey, ":", 0)))
       | where IndicatorType in ("ipv4-addr", "ipv6-addr", "network-traffic")
       | extend NetworkSourceIP = toupper(ObservableValue)
       | extend TrafficLightProtocolLevel = tostring(parse_json(AdditionalFields).TLPLevel)
    | where TimeGenerated >= ago(ioc_lookBack)
    | extend TI_ipEntity = NetworkSourceIP
    | where TI_ipEntity != "NO_IP"
    | summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by Id, ObservableValue
    | where IsActive and (ValidUntil > now() or isempty(ValidUntil))
  );
  IP_TI
     | project-reorder *, Tags, TrafficLightProtocolLevel, NetworkSourceIP, Type, TI_ipEntity
    // using innerunique to keep perf fast and result set low, we only need one match to indicate potential malicious activity that needs to be investigated
   | join kind=innerunique 
   (
     _Im_NetworkSession (starttime=ago(dt_lookBack))
     | where isnotempty(SrcIpAddr)
     | summarize imNWS_mintime=min(TimeGenerated), imNWS_maxtime=max(TimeGenerated) by SrcIpAddr, DstIpAddr, Dvc, EventProduct, EventVendor 
     | lookup (IP_TI | project TI_ipEntity, IsActive) on $left.SrcIpAddr == $right.TI_ipEntity
     | project-rename SrcMatch = IsActive
     | lookup (IP_TI | project TI_ipEntity, IsActive) on $left.DstIpAddr == $right.TI_ipEntity
     | project-rename DstMatch = IsActive
     | where SrcMatch or DstMatch
     | extend 
         IoCIP = iff(SrcMatch, SrcIpAddr, DstIpAddr),
         IoCDirection = iff(SrcMatch, "Source", "Destination")
   )on $left.TI_ipEntity == $right.IoCIP
   | where imNWS_mintime < ValidUntil
   | extend Description = tostring(parse_json(Data).description)
   | extend ActivityGroupNames = extract(@"ActivityGroup:(\S+)", 1, tostring(parse_json(Data).labels))
   | project imNWS_mintime, imNWS_maxtime, Description, ActivityGroupNames, Id, Type, ValidUntil, Confidence, SrcIpAddr, DstIpAddr, IoCDirection, IoCIP, Dvc, EventVendor, EventProduct
entityMappings:
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: IoCIP
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: SrcIpAddr
customDetails:
  EventStartTime: imNWS_mintime
  EventEndTime: imNWS_maxtime
  IoCDescription: Description
  ActivityGroupNames: ActivityGroupNames
  IndicatorId: Id
  ThreatType: Type
  IoCExpirationTime: ValidUntil
  IoCConfidenceScore: Confidence
  IoCIPDirection: IoCDirection

alertDetailsOverride:
  alertDisplayNameFormat: A network session {{IoCDirection}} address {{IoCIP}} matched an IoC. 
  alertDescriptionFormat: The {{IoCDirection}} address {{IoCIP}} of a network session  matched a known indicator of compromise of {{Type}}. Consult the threat intelligence blead for more information on the indicator.

tags:
  - Schema: ASIMNetworkSession
    SchemaVersion: 0.2.4

version: 1.2.9
kind: Scheduled

Stages and Predicates

Parameters

let dt_lookBack = 1h;
let ioc_lookBack = 14d;

The stages below define let IP_TI (the rule's main pipeline source).

Stage 1: source

ThreatIntelIndicators

Stage 2: extend

| extend IndicatorType = replace(@"\[|\]|\""", "", tostring(split(ObservableKey, ":", 0)))

Stage 3: where

| where IndicatorType in ("ipv4-addr", "ipv6-addr", "network-traffic")

Stage 4: extend

| extend NetworkSourceIP = toupper(ObservableValue)

Stage 5: extend

| extend TrafficLightProtocolLevel = tostring(parse_json(AdditionalFields).TLPLevel)

Stage 6: where

| where TimeGenerated >= ago(ioc_lookBack)

Stage 7: extend

| extend TI_ipEntity = NetworkSourceIP

Stage 8: where

| where TI_ipEntity != "NO_IP"

Stage 9: summarize

| summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by Id, ObservableValue

Stage 10: where

| where IsActive and (ValidUntil > now() or isempty(ValidUntil))

The stages below run on IP_TI (the outer pipeline).

Stage 11: project-reorder

IP_TI
| project-reorder *, Tags, TrafficLightProtocolLevel, NetworkSourceIP, Type, TI_ipEntity

Stage 12: join

| join kind=innerunique 
 (
   _Im_NetworkSession (starttime=ago(dt_lookBack))
   | where isnotempty(SrcIpAddr)
   | summarize imNWS_mintime=min(TimeGenerated), imNWS_maxtime=max(TimeGenerated) by SrcIpAddr, DstIpAddr, Dvc, EventProduct, EventVendor 
   | lookup (IP_TI | project TI_ipEntity, IsActive) on $left.SrcIpAddr == $right.TI_ipEntity
   | project-rename SrcMatch = IsActive
   | lookup (IP_TI | project TI_ipEntity, IsActive) on $left.DstIpAddr == $right.TI_ipEntity
   | project-rename DstMatch = IsActive
   | where SrcMatch or DstMatch
   | extend 
       IoCIP = iff(SrcMatch, SrcIpAddr, DstIpAddr),
       IoCDirection = iff(SrcMatch, "Source", "Destination")
 )on $left.TI_ipEntity == $right.IoCIP

Stage 13: where

| where imNWS_mintime < ValidUntil

Stage 14: extend

| extend Description = tostring(parse_json(Data).description)

Stage 15: extend

| extend ActivityGroupNames = extract(@"ActivityGroup:(\S+)", 1, tostring(parse_json(Data).labels))

Stage 16: project

| project imNWS_mintime, imNWS_maxtime, Description, ActivityGroupNames, Id, Type, ValidUntil, Confidence, SrcIpAddr, DstIpAddr, IoCDirection, IoCIP, Dvc, EventVendor, EventProduct

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.

FieldKindValues
IndicatorTypein
  • ipv4-addr transforms: cased
  • ipv6-addr transforms: cased
  • network-traffic transforms: cased
SrcIpAddris_not_null
  • (no value, null check)
TI_ipEntityne
  • NO_IP transforms: cased
ValidUntilis_null
  • (no value, null check)
imNWS_mintimelt
  • ValidUntil transforms: cased

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.

FieldSource
ActivityGroupNamesproject
Confidenceproject
Descriptionproject
DstIpAddrproject
Dvcproject
EventProductproject
EventVendorproject
Idproject
IoCDirectionproject
IoCIPproject
SrcIpAddrproject
Typeproject
ValidUntilproject
imNWS_maxtimeproject
imNWS_mintimeproject