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

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

@ -1,11 +1,11 @@
id: 0ef8dee1-eb94-44c8-b59b-2eb096a4b983 id: 0ef8dee1-eb94-44c8-b59b-2eb096a4b983
name: S3 Bucket outbound Data transfer anomaly name: S3 Bucket outbound Data transfer anomaly
description: | description: |
'Identifies when an anomalous spike occur in data transfer from an S3 bucket based on GetObject API call and the BytesTransferredOut field. '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. 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. 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. 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 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 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' S3 KQL Parser: https://github.com/Azure/Azure-Sentinel/blob/master/Parsers/AwsS3BucketAPILogsParser.txt'
@ -23,10 +23,10 @@ query: |
let scorethreshold = 1.5; 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. // 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= let TimeSeriesData=
AwsBucketAPILogs_CL AwsBucketAPILogs_CL
| where EventTime between (lookback..endtime) | where EventTime between (lookback..endtime)
| where EventName == "GetObject" | 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. // 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 let TimeSeriesAlerts = TimeSeriesData
| extend (anomalies, score, baseline) = series_decompose_anomalies(Total, scorethreshold, -1, 'linefit') | extend (anomalies, score, baseline) = series_decompose_anomalies(Total, scorethreshold, -1, 'linefit')
@ -35,14 +35,14 @@ query: |
| project EventTime, Total, baseline, anomalies, score; | 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. // 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 TimeSeriesAlerts
| join | join
( (
AWSS3BucketAPILogParsed AWSS3BucketAPILogParsed
| where EventTime between (startofday(lookback)..endofday(endtime)) | where EventTime between (startofday(lookback)..endofday(endtime))
| where EventName == "GetObject" | 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 | 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 ) 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 | extend timestamp = AnomalyTime, AccountCustomEntity = SessionUserName , HostCustomEntity = Host, IPCustomEntity = SourceIPAddress
entityMappings: entityMappings:
- entityType: Account - entityType: Account

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

@ -3,11 +3,11 @@ name: Consent to Application discovery
description: | description: |
'This query looks at the last 14 days for any "Consent to application" operation '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 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 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 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 from the AuditLogs based on CorrleationId from the same account that performed "Consent to
application". 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 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 This may help detect the Oauth2 attack that can be initiated by this publicly available tool
https://github.com/fireeye/PwnAuth' https://github.com/fireeye/PwnAuth'
@ -23,41 +23,41 @@ query: |
let starttime = todatetime('{{StartTimeISO}}'); let starttime = todatetime('{{StartTimeISO}}');
let endtime = todatetime('{{EndTimeISO}}'); 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 // 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; let threshold = 3;
// Helper function to extract relevant fields from AuditLog events // Helper function to extract relevant fields from AuditLog events
let auditLogEvents = view (startTimeSpan:timespan) { let auditLogEvents = view (startTimeSpan:timespan) {
AuditLogs | where TimeGenerated >= ago(auditLookback) AuditLogs | where TimeGenerated >= ago(auditLookback)
| extend ModProps = TargetResources.[0].modifiedProperties | 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)) 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)) tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName), tostring(parse_json(tostring(InitiatedBy.app)).displayName))
| extend TargetResourceName = tolower(tostring(TargetResources.[0].displayName)) | extend TargetResourceName = tolower(tostring(TargetResources.[0].displayName))
| mvexpand ModProps | mvexpand ModProps
| extend PropertyName = tostring(ModProps.displayName), newValue = replace('\"',"",tostring(ModProps.newValue)); | extend PropertyName = tostring(ModProps.displayName), newValue = replace('\"',"",tostring(ModProps.newValue));
}; };
// Get just the InitiatedBy and CorrleationId so we can look at associated audit activity // 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 // "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" | 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 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 // 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 //| where OperationCount > threshold
; ;
let Correlate = HistoricalConsent let Correlate = HistoricalConsent
| summarize by InitiatedBy, CorrelationId; | 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 // "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"; | where OperationName != "Consent to application";
// Gather associated activity based on audit activity for "Consent to application" and InitiatedBy and CorrleationId // 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 | 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 by Type, InitiatedBy, IpAddress, TargetResourceName, Category, OperationName, PropertyName, newValue, CorrelationId, Id
; ;
// Union the results // Union the results

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

@ -1,7 +1,7 @@
id: 5c799718-b361-4a91-9cb2-0c291e602707 id: 5c799718-b361-4a91-9cb2-0c291e602707
name: Rare Audit activity initiated by App name: Rare Audit activity initiated by App
description: | 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 OperationName, InitiatedByApp, UserPrincipalName, PropertyName, newValue
This can be useful when attempting to track down malicious activity related to additions of new users, 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.' additions to groups, removal from groups by Azure Apps and automated approvals.'
@ -21,8 +21,8 @@ query: |
let auditLookback = starttime - 14d; let auditLookback = starttime - 14d;
let propertyIgnoreList = dynamic(["TargetId.UserType", "StsRefreshTokensValidFrom", "LastDirSyncTime", "DeviceOSVersion", "CloudDeviceOSVersion", "DeviceObjectVersion"]); let propertyIgnoreList = dynamic(["TargetId.UserType", "StsRefreshTokensValidFrom", "LastDirSyncTime", "DeviceOSVersion", "CloudDeviceOSVersion", "DeviceObjectVersion"]);
let appIgnoreList = dynamic(["Microsoft Azure AD Group-Based Licensing"]); let appIgnoreList = dynamic(["Microsoft Azure AD Group-Based Licensing"]);
let AuditTrail = AuditLogs let AuditTrail = AuditLogs
| where TimeGenerated >= ago(auditLookback) and TimeGenerated < starttime | where TimeGenerated between(auditLookback..starttime)
| where isnotempty(tostring(parse_json(tostring(InitiatedBy.app)).displayName)) | where isnotempty(tostring(parse_json(tostring(InitiatedBy.app)).displayName))
| extend InitiatedByApp = tostring(parse_json(tostring(InitiatedBy.app)).displayName) | extend InitiatedByApp = tostring(parse_json(tostring(InitiatedBy.app)).displayName)
| extend ModProps = TargetResources.[0].modifiedProperties | extend ModProps = TargetResources.[0].modifiedProperties
@ -48,10 +48,10 @@ query: |
| extend PropertyName = tostring(ModProps.displayName), newValue = tostring(parse_json(tostring(ModProps.newValue))[0]) | 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 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" | 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; | 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 ( let RareAudits = AccountMods | join kind= leftanti (
AuditTrail AuditTrail
) on OperationName, InitiatedByApp, InitiatedByIpAddress, TargetUserPrincipalName;//, PropertyName; //uncomment if you want to see Rare Property changes. ) on OperationName, InitiatedByApp, InitiatedByIpAddress, TargetUserPrincipalName;//, PropertyName; //uncomment if you want to see Rare Property changes.
RareAudits RareAudits
| summarize StartTime = min(StartTimeUtc), EndTime = max(EndTimeUtc), make_set(Activity), make_set(PropertyName) by InitiatedByApp, OperationName, TargetUserPrincipalName, InitiatedByIpAddress, TargetResourceName | 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 id: 81fd68a2-9ad6-4a1c-7bd7-18efe5c99081
name: Rare Custom Script Extension name: Rare Custom Script Extension
description: | 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. '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. 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' The query tries to identify rare custom script extensions that have been executed in your envioenment'
requiredDataConnectors: requiredDataConnectors:
- connectorId: AzureActivity - connectorId: AzureActivity
@ -17,7 +17,7 @@ query: |
let starttime = todatetime('{{StartTimeISO}}'); let starttime = todatetime('{{StartTimeISO}}');
let endtime = todatetime('{{EndTimeISO}}'); let endtime = todatetime('{{EndTimeISO}}');
let Lookback = satarttime - 14d; let Lookback = satarttime - 14d;
let CustomScriptExecution = AzureActivity let CustomScriptExecution = AzureActivity
| where TimeGenerated >= Lookback | where TimeGenerated >= Lookback
| where OperationName =~ "Create or Update Virtual Machine Extension" | 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))) | 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) | where isnotempty(FileURI) and isnotempty(commandToExecute)
| summarize max(TimeGenerated), OperationCount = count() by Caller, Resource, CallerIpAddress, FileURI, commandToExecute; | summarize max(TimeGenerated), OperationCount = count() by Caller, Resource, CallerIpAddress, FileURI, commandToExecute;
let CurrentCustomScriptExecution = CustomScriptExecution let CurrentCustomScriptExecution = CustomScriptExecution
| where TimeGenerated beteeen (starttime..endtime) | where TimeGenerated between (starttime..endtime)
| where isnotempty(FileURI) and isnotempty(commandToExecute) | where isnotempty(FileURI) and isnotempty(commandToExecute)
| project TimeGenerated, ActivityStatus, OperationId, CorrelationId, ResourceId, CallerIpAddress, Caller, OperationName, Resource, ResourceGroup, FileURI, commandToExecute, FailureMessage = message_, HTTPRequest, Settings; | project TimeGenerated, ActivityStatus, OperationId, CorrelationId, ResourceId, CallerIpAddress, Caller, OperationName, Resource, ResourceGroup, FileURI, commandToExecute, FailureMessage = message_, HTTPRequest, Settings;
let RareCustomScriptExecution = CurrentCustomScriptExecution let RareCustomScriptExecution = CurrentCustomScriptExecution
| join kind= leftanti (LookbackCustomScriptExecution) on Caller, CallerIpAddress, FileURI, commandToExecute; | 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 | 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); | 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 //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: relevantTechniques:
- T1053 - T1053
query: | query: |
let starttime = todatetime('{{StartTimeISO}}'); let starttime = todatetime('{{StartTimeISO}}');
let endtime = todatetime('{{EndTimeISO}}'); let endtime = todatetime('{{EndTimeISO}}');
let lookback = 30d; let lookback = 30d;
// Set the period for detections // Set the period for detections
// Get a list of previous Release Pipeline creators to exclude // Get a list of previous Release Pipeline creators to exclude
let releaseusers = AzureDevOpsAuditing let releaseusers = AzureDevOpsAuditing
| where TimeGenerated > ago(timeback) and TimeGenerated < starttime | where TimeGenerated between(ago(lookback)..starttime)
| where OperationName =~ "Release.ReleasePipelineCreated" | where OperationName =~ "Release.ReleasePipelineCreated"
// We want to look for users performing actions in specific organizations so we creat this userscope object to match on // 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) | extend UserScope = strcat(ActorUPN, "-", ProjectName)

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

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

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

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

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

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

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

@ -18,7 +18,7 @@ query: |
let threshold = 0; let threshold = 0;
LAQueryLogs LAQueryLogs
| where TimeGenerated between(starttime..endtime) | 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') | 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) | mv-expand anomalies to typeof(int), score to typeof(double), TimeGenerated to typeof(datetime)
| where anomalies > threshold | where anomalies > threshold

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

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

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

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

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

@ -71,8 +71,8 @@ query: |
) on $left.InitiatedBy_Caller == $right.TargetUserName; ) 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. // 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 UserAddWithResource
| union isfuzzy=true ResourceMatch | union isfuzzy=true(ResourceMatch
| extend PropertySet = pack("Value", Value, "PropertyName_ResourceId", PropertyName_ResourceId) | 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 | 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 | extend timestamp = StartTimeUtc, AccountCustomEntity = TargetUserName, IPCustomEntity = IpAddress

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -17,7 +17,7 @@ query: |
let starttime = todatetime('{{StartTimeISO}}'); let starttime = todatetime('{{StartTimeISO}}');
let endtime = todatetime('{{EndTimeISO}}'); 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 // 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]$"; 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 // 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 lookback = starttime - 14d;
let known_procs = ( let known_procs = (
SecurityEvent SecurityEvent
| where TimeGenerated between(lookback..startime) | where TimeGenerated between(lookback..starttime)
| where EventID == 4688 | where EventID == 4688
| where ParentProcessName hassuffix "w3wp.exe" | where ParentProcessName hassuffix "w3wp.exe"
| extend ProcessHost = strcat(Process, "-", Computer) | extend ProcessHost = strcat(Process, "-", Computer)

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

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

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

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

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

@ -16,8 +16,11 @@ relevantTechniques:
- T1030 - T1030
query: | query: |
let starttime = todatetime('{{StartTimeISO}}');
let endtime = todatetime('{{EndTimeISO}}');
let TimeSeriesData = let TimeSeriesData =
Syslog Syslog
| where TimeGenerated between(starttime..endtime)
| where ProcessName contains "squid" | where ProcessName contains "squid"
| extend URL = extract("(([A-Z]+ [a-z]{4,5}:\\/\\/)|[A-Z]+ )([^ :]*)",3,SyslogMessage), | 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), 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) contentType = extract("([a-z/]+$)",1,SyslogMessage)
| extend TLD = extract("\\.[a-z]*$",0,Domain) | extend TLD = extract("\\.[a-z]*$",0,Domain)
| where isnotempty(Bytes) | 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 TimeSeriesData
| extend (anomalies, score, baseline) = series_decompose_anomalies(TotalBytesSent,3, -1, 'linefit') | extend (anomalies, score, baseline) = series_decompose_anomalies(TotalBytesSent,3, -1, 'linefit')
| extend timestamp = TimeGenerated | extend timestamp = TimeGenerated