Fixes
This commit is contained in:
Родитель
8c900dafa2
Коммит
e030abc8e7
|
@ -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
|
||||||
|
|
Загрузка…
Ссылка в новой задаче