This commit is contained in:
Pete Bryan 2021-08-06 14:12:37 -07:00
Родитель 8c900dafa2
Коммит e030abc8e7
25 изменённых файлов: 59 добавлений и 58 удалений

Просмотреть файл

@ -1,7 +1,7 @@
id: e0d57543-acbd-428b-bb96-24a67506f84d
name: Unused or Unsupported Cloud Regions
description: |
'Adversaries may create cloud instances in unused geographic service regions in order to evade detection.
'Adversaries may create cloud instances in unused geographic service regions in order to evade detection.
Access is usually obtained through compromising accounts used to manage cloud infrastructure.
Refer: https://attack.mitre.org/techniques/T1535/'
requiredDataConnectors:
@ -19,8 +19,8 @@ query: |
let lookback = starttime - 14d;
let midtime = starttime - 1d;
// Generating historical table of all events per AccountId and Region
let EventInfo_CurrentDay = materialize (AWSCloudTrail | where TimeGenerated >= between(starttime..endtime);
let EventInfo_historical = AWSCloudTrail | where TimeGenerated between (lookback..midtime)) | summarize max(TimeGenerated) by AWSRegion, UserIdentityAccountId;
let EventInfo_CurrentDay = materialize (AWSCloudTrail | where TimeGenerated between(starttime..endtime);
let EventInfo_historical = AWSCloudTrail | where TimeGenerated between (lookback..midtime)) | summarize max(TimeGenerated) by AWSRegion, UserIdentityAccountId;
// Doing Leftanti join to find new regions historically not seen for the same account.
let EventInfo_Unseen = materialize (
EventInfo_CurrentDay

Просмотреть файл

@ -1,11 +1,11 @@
id: 0ef8dee1-eb94-44c8-b59b-2eb096a4b983
name: S3 Bucket outbound Data transfer anomaly
description: |
'Identifies when an anomalous spike occur in data transfer from an S3 bucket based on GetObject API call and the BytesTransferredOut field.
The query leverages KQL built-in anomaly detection algorithms to find large deviations from baseline patterns.
'Identifies when an anomalous spike occur in data transfer from an S3 bucket based on GetObject API call and the BytesTransferredOut field.
The query leverages KQL built-in anomaly detection algorithms to find large deviations from baseline patterns.
Sudden increases in execution frequency of sensitive actions should be further investigated for malicious activity.
Manually change scorethreshold from 1.5 to 3 or higher to reduce the noise based on outliers flagged from the query criteria.
Read more about ingest custom logs using Logstash at https://github.com/Azure/Azure-Sentinel/wiki/Ingest-Custom-Logs-LogStash
Read more about ingest custom logs using Logstash at https://github.com/Azure/Azure-Sentinel/wiki/Ingest-Custom-Logs-LogStash
AWS S3 API GetObject at https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html
S3 LogStash Config: https://github.com/Azure/Azure-Sentinel/blob/master/Parsers/Logstash/input-aws_s3-output-loganalytics.conf
S3 KQL Parser: https://github.com/Azure/Azure-Sentinel/blob/master/Parsers/AwsS3BucketAPILogsParser.txt'
@ -23,10 +23,10 @@ query: |
let scorethreshold = 1.5;
// Preparing the time series data aggregated on BytesTransferredOut column in the form of multi-value array so that it can be used with time series anomaly function.
let TimeSeriesData=
AwsBucketAPILogs_CL
AwsBucketAPILogs_CL
| where EventTime between (lookback..endtime)
| where EventName == "GetObject"
| make-series Total=sum(BytesTransferredOut) on EventTime from startofday(ago(starttime)) to startofday(ago(endtime)) step timeframe;
| make-series Total=sum(BytesTransferredOut) on EventTime from startofday(starttime) to startofday(endtime) step timeframe;
// Use the time series data prepared in previous step with time series aomaly function to generate baseline pattern and flag the outlier based on scorethreshold value.
let TimeSeriesAlerts = TimeSeriesData
| extend (anomalies, score, baseline) = series_decompose_anomalies(Total, scorethreshold, -1, 'linefit')
@ -35,14 +35,14 @@ query: |
| project EventTime, Total, baseline, anomalies, score;
// Joining the flagged outlier from the previous step with the original dataset to present contextual information during the anomalyhour to analysts to conduct investigation or informed decistions.
TimeSeriesAlerts
| join
| join
(
AWSS3BucketAPILogParsed
AWSS3BucketAPILogParsed
| where EventTime between (startofday(lookback)..endofday(endtime))
| where EventName == "GetObject"
| summarize Total = sum(BytesTransferredOut), Files= makeset(Key) , max(EventTime) by bin(EventTime, 1h), EventSource,EventName, SourceIPAddress, UserIdentityType, UserIdentityArn, UserIdentityUserName, BucketName, Host, AuthenticationMethod, SessionMfaAuthenticated, SessionUserName
) on EventTime
| project AnomalyTime = max_EventTime, SourceIPAddress, UserIdentityType,UserIdentityUserName,SessionUserName, BucketName, Host, AuthenticationMethod, Files, Total, baseline, anomalies, score
| project AnomalyTime = max_EventTime, SourceIPAddress, UserIdentityType,UserIdentityUserName,SessionUserName, BucketName, Host, AuthenticationMethod, Files, Total, baseline, anomalies, score
| extend timestamp = AnomalyTime, AccountCustomEntity = SessionUserName , HostCustomEntity = Host, IPCustomEntity = SourceIPAddress
entityMappings:
- entityType: Account

Просмотреть файл

@ -3,11 +3,11 @@ name: Consent to Application discovery
description: |
'This query looks at the last 14 days for any "Consent to application" operation
occurs by a user or app. This could indicate that permissions to access the listed AzureApp
was provided to a malicious actor. Consent to appliction, Add service principal and
Add OAuth2PermissionGrant events should be rare. If available, additional context is added
from the AuditLogs based on CorrleationId from the same account that performed "Consent to
was provided to a malicious actor. Consent to appliction, Add service principal and
Add OAuth2PermissionGrant events should be rare. If available, additional context is added
from the AuditLogs based on CorrleationId from the same account that performed "Consent to
application".
For further information on AuditLogs please see
For further information on AuditLogs please see
https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-audit-activities
This may help detect the Oauth2 attack that can be initiated by this publicly available tool
https://github.com/fireeye/PwnAuth'
@ -23,41 +23,41 @@ query: |
let starttime = todatetime('{{StartTimeISO}}');
let endtime = todatetime('{{EndTimeISO}}');
let auditLookback = startttime - 14d;
let auditLookback = starttime - 14d;
// Setting threshold to 3 as a default, change as needed. Any operation that has been initiated by a user or app more than 3 times in the past 30 days will be exluded
let threshold = 3;
// Helper function to extract relevant fields from AuditLog events
let auditLogEvents = view (startTimeSpan:timespan) {
AuditLogs | where TimeGenerated >= ago(auditLookback)
| extend ModProps = TargetResources.[0].modifiedProperties
| extend IpAddress = iff(isnotempty(tostring(parse_json(tostring(InitiatedBy.user)).ipAddress)),
| extend IpAddress = iff(isnotempty(tostring(parse_json(tostring(InitiatedBy.user)).ipAddress)),
tostring(parse_json(tostring(InitiatedBy.user)).ipAddress), tostring(parse_json(tostring(InitiatedBy.app)).ipAddress))
| extend InitiatedBy = iff(isnotempty(tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName)),
| extend InitiatedBy = iff(isnotempty(tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName)),
tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName), tostring(parse_json(tostring(InitiatedBy.app)).displayName))
| extend TargetResourceName = tolower(tostring(TargetResources.[0].displayName))
| mvexpand ModProps
| extend PropertyName = tostring(ModProps.displayName), newValue = replace('\"',"",tostring(ModProps.newValue));
};
// Get just the InitiatedBy and CorrleationId so we can look at associated audit activity
// 2 other operations that can be part of malicious activity in this situation are
// 2 other operations that can be part of malicious activity in this situation are
// "Add OAuth2PermissionGrant" and "Add service principal", replace the below if you are interested in those as starting points for OperationName
let HistoricalConsent = auditLogEvents(auditLookback)
let HistoricalConsent = auditLogEvents(auditLookback)
| where OperationName == "Consent to application"
| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), OperationCount = count()
| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), OperationCount = count()
by Type, InitiatedBy, IpAddress, TargetResourceName, Category, OperationName, PropertyName, newValue, CorrelationId, Id
// Remove comment below to only include operations initiated by a user or app that is above the threshold for the last 30 days
//| where OperationCount > threshold
;
let Correlate = HistoricalConsent
let Correlate = HistoricalConsent
| summarize by InitiatedBy, CorrelationId;
// 2 other operations that can be part of malicious activity in this situation are
// 2 other operations that can be part of malicious activity in this situation are
// "Add OAuth2PermissionGrant" and "Add service principal", replace the below if you changed the starting OperationName above
let allOtherEvents = auditLogEvents(auditLookback)
let allOtherEvents = auditLogEvents(auditLookback)
| where OperationName != "Consent to application";
// Gather associated activity based on audit activity for "Consent to application" and InitiatedBy and CorrleationId
let CorrelatedEvents = Correlate
let CorrelatedEvents = Correlate
| join allOtherEvents on InitiatedBy, CorrelationId
| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated)
| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated)
by Type, InitiatedBy, IpAddress, TargetResourceName, Category, OperationName, PropertyName, newValue, CorrelationId, Id
;
// Union the results

Просмотреть файл

@ -1,7 +1,7 @@
id: 5c799718-b361-4a91-9cb2-0c291e602707
name: Rare Audit activity initiated by App
description: |
'Compares the current day to the last 14 days of audits to identify new audit activities by
'Compares the current day to the last 14 days of audits to identify new audit activities by
OperationName, InitiatedByApp, UserPrincipalName, PropertyName, newValue
This can be useful when attempting to track down malicious activity related to additions of new users,
additions to groups, removal from groups by Azure Apps and automated approvals.'
@ -21,8 +21,8 @@ query: |
let auditLookback = starttime - 14d;
let propertyIgnoreList = dynamic(["TargetId.UserType", "StsRefreshTokensValidFrom", "LastDirSyncTime", "DeviceOSVersion", "CloudDeviceOSVersion", "DeviceObjectVersion"]);
let appIgnoreList = dynamic(["Microsoft Azure AD Group-Based Licensing"]);
let AuditTrail = AuditLogs
| where TimeGenerated >= ago(auditLookback) and TimeGenerated < starttime
let AuditTrail = AuditLogs
| where TimeGenerated between(auditLookback..starttime)
| where isnotempty(tostring(parse_json(tostring(InitiatedBy.app)).displayName))
| extend InitiatedByApp = tostring(parse_json(tostring(InitiatedBy.app)).displayName)
| extend ModProps = TargetResources.[0].modifiedProperties
@ -48,10 +48,10 @@ query: |
| extend PropertyName = tostring(ModProps.displayName), newValue = tostring(parse_json(tostring(ModProps.newValue))[0])
| where PropertyName !in~ (propertyIgnoreList) and (PropertyName !~ "Action Client Name" and newValue !~ "DirectorySync") and (PropertyName !~ "Included Updated Properties" and newValue !~ "LastDirSyncTime")
| where InitiatedByApp !in~ (appIgnoreList) and OperationName !~ "Change user license"
| extend ModifiedProps = pack("PropertyName",PropertyName,"newValue",newValue, "Id", Id, "CorrelationId", CorrelationId)
| extend ModifiedProps = pack("PropertyName",PropertyName,"newValue",newValue, "Id", Id, "CorrelationId", CorrelationId)
| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), Activity = make_bag(ModifiedProps) by Type, InitiatedByApp, TargetUserPrincipalName, InitiatedByIpAddress, TargetResourceName, Category, OperationName, PropertyName;
let RareAudits = AccountMods | join kind= leftanti (
AuditTrail
AuditTrail
) on OperationName, InitiatedByApp, InitiatedByIpAddress, TargetUserPrincipalName;//, PropertyName; //uncomment if you want to see Rare Property changes.
RareAudits
| summarize StartTime = min(StartTimeUtc), EndTime = max(EndTimeUtc), make_set(Activity), make_set(PropertyName) by InitiatedByApp, OperationName, TargetUserPrincipalName, InitiatedByIpAddress, TargetResourceName

Просмотреть файл

@ -1,8 +1,8 @@
id: 81fd68a2-9ad6-4a1c-7bd7-18efe5c99081
name: Rare Custom Script Extension
description: |
'The Custom Script Extension downloads and executes scripts on Azure virtual machines. This extension is useful for post deployment configuration, software installation, or any other configuration or management tasks.
Scripts could be downloaded from external links, Azure storage, GitHub, or provided to the Azure portal at extension run time. This could also be used maliciously by an attacker.
'The Custom Script Extension downloads and executes scripts on Azure virtual machines. This extension is useful for post deployment configuration, software installation, or any other configuration or management tasks.
Scripts could be downloaded from external links, Azure storage, GitHub, or provided to the Azure portal at extension run time. This could also be used maliciously by an attacker.
The query tries to identify rare custom script extensions that have been executed in your envioenment'
requiredDataConnectors:
- connectorId: AzureActivity
@ -17,7 +17,7 @@ query: |
let starttime = todatetime('{{StartTimeISO}}');
let endtime = todatetime('{{EndTimeISO}}');
let Lookback = satarttime - 14d;
let CustomScriptExecution = AzureActivity
let CustomScriptExecution = AzureActivity
| where TimeGenerated >= Lookback
| where OperationName =~ "Create or Update Virtual Machine Extension"
| extend Settings = tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(parse_json(Properties).responseBody)).properties)).settings)))
@ -29,12 +29,12 @@ query: |
| where isnotempty(FileURI) and isnotempty(commandToExecute)
| summarize max(TimeGenerated), OperationCount = count() by Caller, Resource, CallerIpAddress, FileURI, commandToExecute;
let CurrentCustomScriptExecution = CustomScriptExecution
| where TimeGenerated beteeen (starttime..endtime)
| where TimeGenerated between (starttime..endtime)
| where isnotempty(FileURI) and isnotempty(commandToExecute)
| project TimeGenerated, ActivityStatus, OperationId, CorrelationId, ResourceId, CallerIpAddress, Caller, OperationName, Resource, ResourceGroup, FileURI, commandToExecute, FailureMessage = message_, HTTPRequest, Settings;
let RareCustomScriptExecution = CurrentCustomScriptExecution
| join kind= leftanti (LookbackCustomScriptExecution) on Caller, CallerIpAddress, FileURI, commandToExecute;
let IPCheck = RareCustomScriptExecution
let IPCheck = RareCustomScriptExecution
| summarize arg_max(TimeGenerated, OperationName), OperationIds = makeset(OperationId), CallerIpAddresses = makeset(CallerIpAddress) by ActivityStatus, CorrelationId, ResourceId, Caller, Resource, ResourceGroup, FileURI, commandToExecute, FailureMessage
| extend IPArray = arraylength(CallerIpAddresses);
//Get IPs for later summarization so all associated CorrelationIds and Caller actions have an IP. Success and Fails do not always have IP

Просмотреть файл

@ -10,14 +10,14 @@ tactics:
relevantTechniques:
- T1053
query: |
let starttime = todatetime('{{StartTimeISO}}');
let endtime = todatetime('{{EndTimeISO}}');
let lookback = 30d;
// Set the period for detections
// Get a list of previous Release Pipeline creators to exclude
let releaseusers = AzureDevOpsAuditing
| where TimeGenerated > ago(timeback) and TimeGenerated < starttime
| where TimeGenerated between(ago(lookback)..starttime)
| where OperationName =~ "Release.ReleasePipelineCreated"
// We want to look for users performing actions in specific organizations so we creat this userscope object to match on
| extend UserScope = strcat(ActorUPN, "-", ProjectName)

Просмотреть файл

@ -15,8 +15,6 @@ query: |
let EndLearningTime = starttime - LearningPeriod;
let NumberOfStds = 3;
let MinThreshold = 10.0;
let EndRunTime = StartTime - RunTime;
let EndLearningTime = StartTime + LearningPeriod;
let GitHubRepositoryDestroyEvents = (GitHubAudit
| where Action == "repo.destroy");
GitHubRepositoryDestroyEvents

Просмотреть файл

@ -24,7 +24,7 @@ query: |
| distinct AADClientId
| join kind=rightanti(
LAQueryLogs
| where TimeGenerated > between(starttime..endtime)
| where TimeGenerated between(starttime..endtime)
| where ResponseCode == 200 and RequestClientApp != "AppAnalytics" and AADEmail !contains "@"
)
on AADClientId

Просмотреть файл

@ -20,7 +20,7 @@ query: |
| where TimeGenerated between(startofday(ago(lookback))..starttime)
| summarize by AADEmail
| join kind = rightanti (LAQueryLogs
| where TimeGenerated between(starttime..endtime)
| where TimeGenerated between(starttime..endtime))
on AADEmail
| project TimeGenerated, AADEmail, QueryText, RequestClientApp, RequestTarget
| extend timestamp = TimeGenerated, AccountCustomEntity = AADEmail

Просмотреть файл

@ -18,7 +18,7 @@ query: |
let threshold = 0;
LAQueryLogs
| where TimeGenerated between(starttime..endtime)
| make-series rows = sum(ResponseRowCount) on TimeGenerated in range(ago(lookback), endtime, 1h)
| make-series rows = sum(ResponseRowCount) on TimeGenerated in range(starttime - lookback, endtime, 1h)
| extend (anomalies, score, baseline) = series_decompose_anomalies(rows,3, -1, 'linefit')
| mv-expand anomalies to typeof(int), score to typeof(double), TimeGenerated to typeof(datetime)
| where anomalies > threshold

Просмотреть файл

@ -20,7 +20,7 @@ query: |
let diff = 5;
let anomolous_users = (
LAQueryLogs
| where TimeGenerated between(startofday(ago(lookback))..startime)
| where TimeGenerated between(startofday(ago(lookback))..starttime)
| summarize score=sum(ResponseRowCount) by AADEmail
| join kind = fullouter (LAQueryLogs
| where TimeGenerated between(starttime..endtime)

Просмотреть файл

@ -12,7 +12,7 @@ relevantTechniques:
- T1020
query: |
let timeframe = 1h
let timeframe = 1h;
let threshold = 10;
LAQueryLogs
| where ResponseCode != 200

Просмотреть файл

@ -71,8 +71,8 @@ query: |
) on $left.InitiatedBy_Caller == $right.TargetUserName;
// union the user addition events and resource addition events and provide common column names, additionally pack the value, property and resource info to reduce result set.
UserAddWithResource
| union isfuzzy=true ResourceMatch
| union isfuzzy=true(ResourceMatch
| extend PropertySet = pack("Value", Value, "PropertyName_ResourceId", PropertyName_ResourceId)
| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), makeset(PropertySet) by Action, Type, TargetUserName, InitiatedBy_Caller, IpAddress, OperationName
| order by StartTimeUtc asc
| order by StartTimeUtc asc)
| extend timestamp = StartTimeUtc, AccountCustomEntity = TargetUserName, IPCustomEntity = IpAddress

Просмотреть файл

@ -16,7 +16,7 @@ query: |
let starttime = todatetime('{{StartTimeISO}}');
let endtime = todatetime('{{EndTimeISO}}');
let lookback = startime - 14d;
let lookback = starttime - 14d;
let historical_bots = (
OfficeActivity
| where TimeGenerated between(lookback..starttime)

Просмотреть файл

@ -18,7 +18,7 @@ query: |
let starttime = todatetime('{{StartTimeISO}}');
let endtime = todatetime('{{EndTimeISO}}');
let lookback = startime - 14d;
let lookback = starttime - 14d;
let historicalActivity=
OfficeActivity
| where TimeGenerated between(lookback..starttime)

Просмотреть файл

@ -16,7 +16,7 @@ query: |
let starttime = todatetime('{{StartTimeISO}}');
let endtime = todatetime('{{EndTimeISO}}');
let lookback = startime - 14d;
let lookback = starttime - 14d;
let historicalActivity=
OfficeActivity
| where RecordType == "SharePointFileOperation"

Просмотреть файл

@ -15,7 +15,7 @@ query: |
let starttime = todatetime('{{StartTimeISO}}');
let endtime = todatetime('{{EndTimeISO}}');
let lookback = startime - 14d;
let lookback = starttime - 14d;
let historicalActivity=
OfficeActivity
| where RecordType == "SharePointFileOperation"

Просмотреть файл

@ -14,7 +14,7 @@ query: |
let starttime = todatetime('{{StartTimeISO}}');
let endtime = todatetime('{{EndTimeISO}}');
let lookback = startime - 14d;
let lookback = starttime - 14d;
let historicalUA=
OfficeActivity
| where RecordType == "SharePointFileOperation"

Просмотреть файл

@ -11,7 +11,7 @@ tactics:
query: |
let starttime = todatetime('{{StartTimeISO}}');
let endtime = todatetime('{{EndTimeISO}}');
let lookback = startime - 14d;
let lookback = starttime - 14d;
let out_msg = ProofpointPOD
| where TimeGenerated between (lookback..starttime)
| where EventType == 'message'

Просмотреть файл

@ -17,7 +17,7 @@ query: |
let starttime = todatetime('{{StartTimeISO}}');
let endtime = todatetime('{{EndTimeISO}}');
let lookback = startime - 7d;
let lookback = starttime - 7d;
// For AD SID mappings - https://docs.microsoft.com/windows/security/identity-protection/access-control/active-directory-security-groups
let WellKnownLocalSID = "S-1-5-32-5[0-9][0-9]$";
// The SIDs for DnsAdmins and DnsUpdateProxy can be different than *-1102 and -*1103. Check these SIDs in your domain before running the query

Просмотреть файл

@ -19,7 +19,7 @@ query: |
let lookback = starttime - 14d;
let known_procs = (
SecurityEvent
| where TimeGenerated between(lookback..startime)
| where TimeGenerated between(lookback..starttime)
| where EventID == 4688
| where ParentProcessName hassuffix "w3wp.exe"
| extend ProcessHost = strcat(Process, "-", Computer)

Просмотреть файл

@ -24,7 +24,7 @@ query: |
| where TimeGenerated between(lookback..endtime)
| where EventID == 4688
| summarize FullCount = count()
, Count= countif(TimeGenerated between (startime .. endtime))
, Count= countif(TimeGenerated between (starttime .. endtime))
, min_TimeGenerated=min(TimeGenerated)
, max_TimeGenerated=max(TimeGenerated)
by Computer, NewProcessName

Просмотреть файл

@ -18,7 +18,7 @@ query: |
let lookback = startime - 14d;
let disabledAccounts = (){
SigninLogs
| where TimeGenerated between(lookback..starttime))
| where TimeGenerated between(lookback..starttime)
| where ResultType == 50057
| where ResultDescription =~ "User account is disabled. The account has been disabled by an administrator."
};

Просмотреть файл

@ -16,8 +16,11 @@ relevantTechniques:
- T1030
query: |
let starttime = todatetime('{{StartTimeISO}}');
let endtime = todatetime('{{EndTimeISO}}');
let TimeSeriesData =
Syslog
| where TimeGenerated between(starttime..endtime)
| where ProcessName contains "squid"
| extend URL = extract("(([A-Z]+ [a-z]{4,5}:\\/\\/)|[A-Z]+ )([^ :]*)",3,SyslogMessage),
SourceIP = extract("([0-9]+ )(([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3}))",2,SyslogMessage),
@ -30,7 +33,7 @@ query: |
contentType = extract("([a-z/]+$)",1,SyslogMessage)
| extend TLD = extract("\\.[a-z]*$",0,Domain)
| where isnotempty(Bytes)
| make-series TotalBytesSent=sum(Bytes) on TimeGenerated from startofday(ago(starttime)) to startofday(ago(endtime)) step timeframe by ProcessName;
| make-series TotalBytesSent=sum(Bytes) on TimeGenerated from startofday(starttime) to startofday(endtime) step timeframe by ProcessName;
TimeSeriesData
| extend (anomalies, score, baseline) = series_decompose_anomalies(TotalBytesSent,3, -1, 'linefit')
| extend timestamp = TimeGenerated