Anomaly found in Network Session Traffic ASIM Network Session schema
Id | cd6def0d-3ef0-4d55-a7e3-faa96c46ba12 |
Rulename | Anomaly found in Network Session Traffic (ASIM Network Session schema) |
Description | The rule identifies anomalous pattern in network session traffic based on previously seen data, different Device Action, Network Protocol, Network Direction or overall volume. The rule utilize ASIM normalization, and is applied to any source which supports the ASIM Network Session schema |
Severity | Medium |
Tactics | CommandAndControl Discovery Exfiltration LateralMovement |
Techniques | T1095 T1071 T1046 T1030 T1210 |
Required data connectors | AIVectraStream AWSS3 AzureFirewall AzureMonitor(VMInsights) AzureNSG CheckPoint CiscoASA CiscoAsaAma CiscoMeraki Corelight Fortinet MicrosoftSysmonForLinux MicrosoftThreatProtection PaloAltoNetworks SecurityEvents WindowsForwardedEvents WindowsSecurityEvents Zscaler |
Kind | Scheduled |
Query frequency | 1d |
Query period | 14d |
Trigger threshold | 0 |
Trigger operator | gt |
Source Uri | https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Network Session Essentials/Analytic Rules/AnomalyFoundInNetworkSessionTraffic.yaml |
Version | 1.0.1 |
Arm template | cd6def0d-3ef0-4d55-a7e3-faa96c46ba12.json |
let min_t = ago(14d);
let max_t = now();
let dt = 1d;
let fieldForDvcAction = "DvcAction";
let fieldForNetworkDirection = "NetworkDirection";
let fieldForNetworkProtocol = "NetworkProtocol";
let AnomalyThreshold = 2.5;
let eps = materialize (_Im_NetworkSession | project TimeGenerated | where TimeGenerated > ago(5m) | count | extend Count = Count/300);
let maxSummarizedTime = toscalar (
union isfuzzy=true
(
NetworkCustomAnalytics_protocol_CL
| where EventTime_t > min_t
| summarize max_TimeGenerated=max(EventTime_t)
| extend max_TimeGenerated = datetime_add('minute',10,max_TimeGenerated)
),
(
print(min_t)
| project max_TimeGenerated = print_0
)
| summarize maxTimeGenerated = max(max_TimeGenerated)
);
let nosummary = materialize(
union isfuzzy=true
(
NetworkCustomAnalytics_protocol_CL
| where EventTime_t > ago(1d)
| project v = int(2)
),
(
print int(1)
| project v = print_0
)
| summarize maxv = max(v)
| extend nosum = (maxv > 1)
);
let allData = union isfuzzy=true
(
(datatable(exists:int, nosum:bool)[1,false] | where toscalar(eps) > 1000 | join (nosummary) on nosum) | join (
_Im_NetworkSession(starttime=todatetime(ago(2d)), endtime=now())
| where TimeGenerated > maxSummarizedTime
| summarize Count=count() by NetworkProtocol, DstPortNumber, DstAppName, NetworkDirection, DvcAction, bin(TimeGenerated,10m)
| extend EventTime = TimeGenerated, Count = toint(Count), DstPortNumber = toint(DstPortNumber), exists=int(1)
) on exists
| project-away exists, maxv, nosum*
),
(
(datatable(exists:int, nosum:bool)[1,false] | where toscalar(eps) between (501 .. 1000) | join (nosummary) on nosum) | join (
_Im_NetworkSession(starttime=todatetime(ago(3d)), endtime=now())
| where TimeGenerated > maxSummarizedTime
| summarize Count=count() by NetworkProtocol, DstPortNumber, DstAppName, NetworkDirection, DvcAction, bin(TimeGenerated,10m)
| extend EventTime = TimeGenerated, Count = toint(Count), DstPortNumber = toint(DstPortNumber), exists=int(1)
) on exists
| project-away exists, maxv, nosum*
),
(
(datatable(exists:int, nosum:bool)[1,false] | where toscalar(eps) <= 500 | join (nosummary) on nosum) | join (
_Im_NetworkSession(starttime=todatetime(ago(4d)), endtime=now())
| where TimeGenerated > maxSummarizedTime
| summarize Count=count() by NetworkProtocol, DstPortNumber, DstAppName, NetworkDirection, DvcAction, bin(TimeGenerated,10m)
| extend EventTime = TimeGenerated, Count = toint(Count), DstPortNumber = toint(DstPortNumber), exists=int(1)
) on exists
| project-away exists, maxv, nosum*
),
(
NetworkCustomAnalytics_protocol_CL
| where EventTime_t > min_t
| project-rename NetworkProtocol=NetworkProtocol_s, DstPortNumber=DstPortNumber_d, DstAppName=DstAppName_s, NetworkDirection=NetworkDirection_s, DvcAction=DvcAction_s, Count=count__d, EventTime=EventTime_t
| extend Count = toint(Count),DstPortNumber = toint(DstPortNumber)
)
;
let findVolumneBasedAnomaly = allData
| make-series total=sum(Count) on EventTime from min_t to max_t step dt
| extend (anomalies, score, baseline) = series_decompose_anomalies(total, AnomalyThreshold, -1, 'linefit')
| mv-expand anomalies, score, baseline, EventTime, total
| extend anomalies = toint(anomalies), score = toint(score), baseline = toint(baseline), EventTime = todatetime(EventTime), total = tolong(total)
| where EventTime >= ago(1d)
| where score >= 2*AnomalyThreshold
;
let findAnomalies = (field:string){
allData
| where isnotempty(column_ifexists(field,""))
| make-series total=sum(Count) on EventTime from min_t to max_t step dt by column_ifexists(field,"")
| extend (anomalies, score, baseline) = series_decompose_anomalies(total, AnomalyThreshold, -1, 'linefit')
| mv-expand anomalies, score, baseline, EventTime, total
| extend anomalies = toint(anomalies), score = toint(score), baseline = toint(baseline), EventTime = todatetime(EventTime), total = tolong(total)
| where EventTime >= ago(1d)
| where score >= 2*AnomalyThreshold
};
union findAnomalies(fieldForDvcAction), findAnomalies(fieldForNetworkDirection), findAnomalies(fieldForNetworkProtocol), findVolumneBasedAnomaly
| extend anomalyFieldType = case (isnotempty(column_ifexists(fieldForDvcAction,"")), "DvcAction",
isnotempty(column_ifexists(fieldForNetworkDirection,"")), "NetworkDirection",
isnotempty(column_ifexists(fieldForNetworkProtocol,"")), "NetworkProtocol",
"TotalVolume"
),
anomalyFieldValue = case (isnotempty(column_ifexists(fieldForDvcAction,"")), column_ifexists(fieldForDvcAction,""),
isnotempty(column_ifexists(fieldForNetworkDirection,"")), column_ifexists(fieldForNetworkDirection,""),
isnotempty(column_ifexists(fieldForNetworkProtocol,"")), column_ifexists(fieldForNetworkProtocol,""),
"Overall"
)
requiredDataConnectors:
- connectorId: AWSS3
dataTypes:
- AWSVPCFlow
- connectorId: MicrosoftThreatProtection
dataTypes:
- DeviceNetworkEvents
- connectorId: SecurityEvents
dataTypes:
- SecurityEvent
- connectorId: WindowsSecurityEvents
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: CiscoAsaAma
dataTypes:
- CommonSecurityLog
- connectorId: Corelight
dataTypes:
- Corelight_CL
- connectorId: AIVectraStream
dataTypes:
- VectraStream
- connectorId: CheckPoint
dataTypes:
- CommonSecurityLog
- connectorId: Fortinet
dataTypes:
- CommonSecurityLog
- connectorId: CiscoMeraki
dataTypes:
- Syslog
- CiscoMerakiNativePoller
status: Available
relevantTechniques:
- T1095
- T1071
- T1046
- T1030
- T1210
queryFrequency: 1d
id: cd6def0d-3ef0-4d55-a7e3-faa96c46ba12
eventGroupingSettings:
aggregationKind: AlertPerResult
customDetails:
Score: score
AnomalyFieldType: anomalyFieldType
AnomalyFieldValue: anomalyFieldValue
name: Anomaly found in Network Session Traffic (ASIM Network Session schema)
severity: Medium
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Network Session Essentials/Analytic Rules/AnomalyFoundInNetworkSessionTraffic.yaml
queryPeriod: 14d
description: |
'The rule identifies anomalous pattern in network session traffic based on previously seen data, different Device Action, Network Protocol, Network Direction or overall volume. The rule utilize [ASIM](https://aka.ms/AboutASIM) normalization, and is applied to any source which supports the ASIM Network Session schema'
triggerThreshold: 0
tactics:
- CommandAndControl
- Discovery
- Exfiltration
- LateralMovement
tags:
- Schema: ASimNetworkSessions
SchemaVersion: 0.2.4
query: |
let min_t = ago(14d);
let max_t = now();
let dt = 1d;
let fieldForDvcAction = "DvcAction";
let fieldForNetworkDirection = "NetworkDirection";
let fieldForNetworkProtocol = "NetworkProtocol";
let AnomalyThreshold = 2.5;
let eps = materialize (_Im_NetworkSession | project TimeGenerated | where TimeGenerated > ago(5m) | count | extend Count = Count/300);
let maxSummarizedTime = toscalar (
union isfuzzy=true
(
NetworkCustomAnalytics_protocol_CL
| where EventTime_t > min_t
| summarize max_TimeGenerated=max(EventTime_t)
| extend max_TimeGenerated = datetime_add('minute',10,max_TimeGenerated)
),
(
print(min_t)
| project max_TimeGenerated = print_0
)
| summarize maxTimeGenerated = max(max_TimeGenerated)
);
let nosummary = materialize(
union isfuzzy=true
(
NetworkCustomAnalytics_protocol_CL
| where EventTime_t > ago(1d)
| project v = int(2)
),
(
print int(1)
| project v = print_0
)
| summarize maxv = max(v)
| extend nosum = (maxv > 1)
);
let allData = union isfuzzy=true
(
(datatable(exists:int, nosum:bool)[1,false] | where toscalar(eps) > 1000 | join (nosummary) on nosum) | join (
_Im_NetworkSession(starttime=todatetime(ago(2d)), endtime=now())
| where TimeGenerated > maxSummarizedTime
| summarize Count=count() by NetworkProtocol, DstPortNumber, DstAppName, NetworkDirection, DvcAction, bin(TimeGenerated,10m)
| extend EventTime = TimeGenerated, Count = toint(Count), DstPortNumber = toint(DstPortNumber), exists=int(1)
) on exists
| project-away exists, maxv, nosum*
),
(
(datatable(exists:int, nosum:bool)[1,false] | where toscalar(eps) between (501 .. 1000) | join (nosummary) on nosum) | join (
_Im_NetworkSession(starttime=todatetime(ago(3d)), endtime=now())
| where TimeGenerated > maxSummarizedTime
| summarize Count=count() by NetworkProtocol, DstPortNumber, DstAppName, NetworkDirection, DvcAction, bin(TimeGenerated,10m)
| extend EventTime = TimeGenerated, Count = toint(Count), DstPortNumber = toint(DstPortNumber), exists=int(1)
) on exists
| project-away exists, maxv, nosum*
),
(
(datatable(exists:int, nosum:bool)[1,false] | where toscalar(eps) <= 500 | join (nosummary) on nosum) | join (
_Im_NetworkSession(starttime=todatetime(ago(4d)), endtime=now())
| where TimeGenerated > maxSummarizedTime
| summarize Count=count() by NetworkProtocol, DstPortNumber, DstAppName, NetworkDirection, DvcAction, bin(TimeGenerated,10m)
| extend EventTime = TimeGenerated, Count = toint(Count), DstPortNumber = toint(DstPortNumber), exists=int(1)
) on exists
| project-away exists, maxv, nosum*
),
(
NetworkCustomAnalytics_protocol_CL
| where EventTime_t > min_t
| project-rename NetworkProtocol=NetworkProtocol_s, DstPortNumber=DstPortNumber_d, DstAppName=DstAppName_s, NetworkDirection=NetworkDirection_s, DvcAction=DvcAction_s, Count=count__d, EventTime=EventTime_t
| extend Count = toint(Count),DstPortNumber = toint(DstPortNumber)
)
;
let findVolumneBasedAnomaly = allData
| make-series total=sum(Count) on EventTime from min_t to max_t step dt
| extend (anomalies, score, baseline) = series_decompose_anomalies(total, AnomalyThreshold, -1, 'linefit')
| mv-expand anomalies, score, baseline, EventTime, total
| extend anomalies = toint(anomalies), score = toint(score), baseline = toint(baseline), EventTime = todatetime(EventTime), total = tolong(total)
| where EventTime >= ago(1d)
| where score >= 2*AnomalyThreshold
;
let findAnomalies = (field:string){
allData
| where isnotempty(column_ifexists(field,""))
| make-series total=sum(Count) on EventTime from min_t to max_t step dt by column_ifexists(field,"")
| extend (anomalies, score, baseline) = series_decompose_anomalies(total, AnomalyThreshold, -1, 'linefit')
| mv-expand anomalies, score, baseline, EventTime, total
| extend anomalies = toint(anomalies), score = toint(score), baseline = toint(baseline), EventTime = todatetime(EventTime), total = tolong(total)
| where EventTime >= ago(1d)
| where score >= 2*AnomalyThreshold
};
union findAnomalies(fieldForDvcAction), findAnomalies(fieldForNetworkDirection), findAnomalies(fieldForNetworkProtocol), findVolumneBasedAnomaly
| extend anomalyFieldType = case (isnotempty(column_ifexists(fieldForDvcAction,"")), "DvcAction",
isnotempty(column_ifexists(fieldForNetworkDirection,"")), "NetworkDirection",
isnotempty(column_ifexists(fieldForNetworkProtocol,"")), "NetworkProtocol",
"TotalVolume"
),
anomalyFieldValue = case (isnotempty(column_ifexists(fieldForDvcAction,"")), column_ifexists(fieldForDvcAction,""),
isnotempty(column_ifexists(fieldForNetworkDirection,"")), column_ifexists(fieldForNetworkDirection,""),
isnotempty(column_ifexists(fieldForNetworkProtocol,"")), column_ifexists(fieldForNetworkProtocol,""),
"Overall"
)
kind: Scheduled
triggerOperator: gt
alertDetailsOverride:
alertDisplayNameFormat: Anomaly was observed with {{anomalyFieldValue}} Traffic
alertDescriptionFormat: Based on past data, anomaly was observed in {{anomalyFieldValue}} Traffic with a score of {{score}}.
version: 1.0.1
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"workspace": {
"type": "String"
}
},
"resources": [
{
"apiVersion": "2024-01-01-preview",
"id": "[concat(resourceId('Microsoft.OperationalInsights/workspaces/providers', parameters('workspace'), 'Microsoft.SecurityInsights'),'/alertRules/cd6def0d-3ef0-4d55-a7e3-faa96c46ba12')]",
"kind": "Scheduled",
"name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/cd6def0d-3ef0-4d55-a7e3-faa96c46ba12')]",
"properties": {
"alertDetailsOverride": {
"alertDescriptionFormat": "Based on past data, anomaly was observed in {{anomalyFieldValue}} Traffic with a score of {{score}}.",
"alertDisplayNameFormat": "Anomaly was observed with {{anomalyFieldValue}} Traffic"
},
"alertRuleTemplateName": "cd6def0d-3ef0-4d55-a7e3-faa96c46ba12",
"customDetails": {
"AnomalyFieldType": "anomalyFieldType",
"AnomalyFieldValue": "anomalyFieldValue",
"Score": "score"
},
"description": "'The rule identifies anomalous pattern in network session traffic based on previously seen data, different Device Action, Network Protocol, Network Direction or overall volume. The rule utilize [ASIM](https://aka.ms/AboutASIM) normalization, and is applied to any source which supports the ASIM Network Session schema'\n",
"displayName": "Anomaly found in Network Session Traffic (ASIM Network Session schema)",
"enabled": true,
"entityMappings": null,
"eventGroupingSettings": {
"aggregationKind": "AlertPerResult"
},
"OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Network Session Essentials/Analytic Rules/AnomalyFoundInNetworkSessionTraffic.yaml",
"query": "let min_t = ago(14d);\nlet max_t = now();\nlet dt = 1d;\nlet fieldForDvcAction = \"DvcAction\";\nlet fieldForNetworkDirection = \"NetworkDirection\";\nlet fieldForNetworkProtocol = \"NetworkProtocol\";\nlet AnomalyThreshold = 2.5;\nlet eps = materialize (_Im_NetworkSession | project TimeGenerated | where TimeGenerated > ago(5m) | count | extend Count = Count/300);\nlet maxSummarizedTime = toscalar (\n union isfuzzy=true \n (\n NetworkCustomAnalytics_protocol_CL\n | where EventTime_t > min_t\n | summarize max_TimeGenerated=max(EventTime_t)\n | extend max_TimeGenerated = datetime_add('minute',10,max_TimeGenerated)\n ),\n (\n print(min_t)\n | project max_TimeGenerated = print_0\n )\n | summarize maxTimeGenerated = max(max_TimeGenerated) \n );\nlet nosummary = materialize(\n union isfuzzy=true \n (\n NetworkCustomAnalytics_protocol_CL\n | where EventTime_t > ago(1d) \n | project v = int(2)\n ),\n (\n print int(1) \n | project v = print_0\n )\n | summarize maxv = max(v)\n | extend nosum = (maxv > 1)\n );\nlet allData = union isfuzzy=true \n (\n (datatable(exists:int, nosum:bool)[1,false] | where toscalar(eps) > 1000 | join (nosummary) on nosum) | join (\n _Im_NetworkSession(starttime=todatetime(ago(2d)), endtime=now())\n | where TimeGenerated > maxSummarizedTime\n | summarize Count=count() by NetworkProtocol, DstPortNumber, DstAppName, NetworkDirection, DvcAction, bin(TimeGenerated,10m)\n | extend EventTime = TimeGenerated, Count = toint(Count), DstPortNumber = toint(DstPortNumber), exists=int(1)\n ) on exists\n | project-away exists, maxv, nosum*\n ),\n (\n (datatable(exists:int, nosum:bool)[1,false] | where toscalar(eps) between (501 .. 1000) | join (nosummary) on nosum) | join (\n _Im_NetworkSession(starttime=todatetime(ago(3d)), endtime=now())\n | where TimeGenerated > maxSummarizedTime\n | summarize Count=count() by NetworkProtocol, DstPortNumber, DstAppName, NetworkDirection, DvcAction, bin(TimeGenerated,10m)\n | extend EventTime = TimeGenerated, Count = toint(Count), DstPortNumber = toint(DstPortNumber), exists=int(1)\n ) on exists\n | project-away exists, maxv, nosum*\n ),\n (\n (datatable(exists:int, nosum:bool)[1,false] | where toscalar(eps) <= 500 | join (nosummary) on nosum) | join (\n _Im_NetworkSession(starttime=todatetime(ago(4d)), endtime=now())\n | where TimeGenerated > maxSummarizedTime\n | summarize Count=count() by NetworkProtocol, DstPortNumber, DstAppName, NetworkDirection, DvcAction, bin(TimeGenerated,10m)\n | extend EventTime = TimeGenerated, Count = toint(Count), DstPortNumber = toint(DstPortNumber), exists=int(1)\n ) on exists\n | project-away exists, maxv, nosum*\n ),\n (\n NetworkCustomAnalytics_protocol_CL\n | where EventTime_t > min_t\n | project-rename NetworkProtocol=NetworkProtocol_s, DstPortNumber=DstPortNumber_d, DstAppName=DstAppName_s, NetworkDirection=NetworkDirection_s, DvcAction=DvcAction_s, Count=count__d, EventTime=EventTime_t\n | extend Count = toint(Count),DstPortNumber = toint(DstPortNumber) \n )\n;\nlet findVolumneBasedAnomaly = allData\n | make-series total=sum(Count) on EventTime from min_t to max_t step dt\n | extend (anomalies, score, baseline) = series_decompose_anomalies(total, AnomalyThreshold, -1, 'linefit') \n | mv-expand anomalies, score, baseline, EventTime, total\n | extend anomalies = toint(anomalies), score = toint(score), baseline = toint(baseline), EventTime = todatetime(EventTime), total = tolong(total)\n | where EventTime >= ago(1d)\n | where score >= 2*AnomalyThreshold\n ;\nlet findAnomalies = (field:string){\n allData\n | where isnotempty(column_ifexists(field,\"\"))\n | make-series total=sum(Count) on EventTime from min_t to max_t step dt by column_ifexists(field,\"\")\n | extend (anomalies, score, baseline) = series_decompose_anomalies(total, AnomalyThreshold, -1, 'linefit')\n | mv-expand anomalies, score, baseline, EventTime, total\n | extend anomalies = toint(anomalies), score = toint(score), baseline = toint(baseline), EventTime = todatetime(EventTime), total = tolong(total)\n | where EventTime >= ago(1d)\n | where score >= 2*AnomalyThreshold\n};\nunion findAnomalies(fieldForDvcAction), findAnomalies(fieldForNetworkDirection), findAnomalies(fieldForNetworkProtocol), findVolumneBasedAnomaly\n| extend anomalyFieldType = case (isnotempty(column_ifexists(fieldForDvcAction,\"\")), \"DvcAction\",\n isnotempty(column_ifexists(fieldForNetworkDirection,\"\")), \"NetworkDirection\",\n isnotempty(column_ifexists(fieldForNetworkProtocol,\"\")), \"NetworkProtocol\",\n \"TotalVolume\"\n ),\n anomalyFieldValue = case (isnotempty(column_ifexists(fieldForDvcAction,\"\")), column_ifexists(fieldForDvcAction,\"\"),\n isnotempty(column_ifexists(fieldForNetworkDirection,\"\")), column_ifexists(fieldForNetworkDirection,\"\"),\n isnotempty(column_ifexists(fieldForNetworkProtocol,\"\")), column_ifexists(fieldForNetworkProtocol,\"\"),\n \"Overall\"\n )\n",
"queryFrequency": "P1D",
"queryPeriod": "P14D",
"severity": "Medium",
"status": "Available",
"subTechniques": [],
"suppressionDuration": "PT1H",
"suppressionEnabled": false,
"tactics": [
"CommandAndControl",
"Discovery",
"Exfiltration",
"LateralMovement"
],
"tags": [
{
"Schema": "ASimNetworkSessions",
"SchemaVersion": "0.2.4"
}
],
"techniques": [
"T1030",
"T1046",
"T1071",
"T1095",
"T1210"
],
"templateVersion": "1.0.1",
"triggerOperator": "GreaterThan",
"triggerThreshold": 0
},
"type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
}
]
}