diff --git a/Solutions/Azure Activity/Analytic Rules/SubscriptionMigration.yaml b/Solutions/Azure Activity/Analytic Rules/SubscriptionMigration.yaml
index c8ea1f70700..faff4de7fc6 100644
--- a/Solutions/Azure Activity/Analytic Rules/SubscriptionMigration.yaml
+++ b/Solutions/Azure Activity/Analytic Rules/SubscriptionMigration.yaml
@@ -7,6 +7,7 @@ description: |
Once moved, threat actors may deploy resources and perform malicious activities such as crypto mining.
This is a technique known as "subscription hijacking". More information can be found here: https://techcommunity.microsoft.com/t5/microsoft-365-defender-blog/hunt-for-compromised-azure-subscriptions-using-microsoft/ba-p/3607121'
severity: Low
+status: Available
requiredDataConnectors:
- connectorId: AzureActivity
dataTypes:
diff --git a/Solutions/Azure Activity/Data/Solution_AzureActivity.json b/Solutions/Azure Activity/Data/Solution_AzureActivity.json
index 059b374a5a2..7985ead138f 100644
--- a/Solutions/Azure Activity/Data/Solution_AzureActivity.json
+++ b/Solutions/Azure Activity/Data/Solution_AzureActivity.json
@@ -3,7 +3,7 @@
"Author": "Microsoft - support@microsoft.com",
"Logo": "",
"Description": "The [Azure Activity](https://docs.microsoft.com/azure/azure-monitor/essentials/activity-log) solution for Microsoft Sentinel enables you to ingest Azure Activity Administrative, Security, Service Health, Alert, Recommendation, Policy, Autoscale and Resource Health [logs](https://docs.microsoft.com/azure/azure-monitor/reference/tables/azureactivity) using Diagnostic Settings into Microsoft Sentinel.",
- "Data Connectors": [
+ "Data Connectors": [
"Data Connectors/AzureActivity.json"
],
"Hunting Queries": [
@@ -21,7 +21,7 @@
"Hunting Queries/Granting_Permissions_to_Account.yaml",
"Hunting Queries/PortOpenedForAzureResource.yaml",
"Hunting Queries/Rare_Custom_Script_Extension.yaml",
- "Hunting Queries/Machine_Learning_Creation.yaml"
+ "Hunting Queries/Machine_Learning_Creation.yaml"
],
"Analytic Rules": [
"Analytic Rules/AADHybridHealthADFSNewServer.yaml",
@@ -30,25 +30,40 @@
"Analytic Rules/Creating_Anomalous_Number_Of_Resources_detection.yaml",
"Analytic Rules/Creation_of_Expensive_Computes_in_Azure.yaml",
"Analytic Rules/Granting_Permissions_To_Account_detection.yaml",
+ "Analytic Rules/Machine_Learning_Creation.yaml",
"Analytic Rules/NRT-AADHybridHealthADFSNewServer.yaml",
"Analytic Rules/NRT_Creation_of_Expensive_Computes_in_Azure.yaml",
"Analytic Rules/New-CloudShell-User.yaml",
"Analytic Rules/NewResourceGroupsDeployedTo.yaml",
"Analytic Rules/RareOperations.yaml",
- "Analytic Rules/TimeSeriesAnomaly_Mass_Cloud_Resource_Deletions.yaml",
- "Analytic Rules/SubscriptionMigration.yaml",
- "Analytic Rules/Machine_Learning_Creation.yaml"
-
+ "Analytic Rules/SubscriptionMigration.yaml",
+ "Analytic Rules/TimeSeriesAnomaly_Mass_Cloud_Resource_Deletions.yaml"
],
"Workbooks": [
"Workbooks/AzureActivity.json",
"Workbooks/AzureServiceHealthWorkbook.json"
],
"BasePath": "C:\\GitHub\\Azure-Sentinel\\solutions\\Azure Activity",
- "Version": "3.0.4",
"Metadata": "SolutionMetadata.json",
"TemplateSpec": true,
"StaticDataConnectorIds": [
"AzureActivity"
- ]
-}
\ No newline at end of file
+ ],
+ "XDR Detections": [
+ "XDR Detections/AADHybridHealthADFSNewServer.yaml",
+ "XDR Detections/AADHybridHealthADFSServiceDelete.yaml",
+ "XDR Detections/AADHybridHealthADFSSuspApp.yaml",
+ "XDR Detections/Creating_Anomalous_Number_Of_Resources_detection.yaml",
+ "XDR Detections/Creation_of_Expensive_Computes_in_Azure.yaml",
+ "XDR Detections/Granting_Permissions_To_Account_detection.yaml",
+ "XDR Detections/Machine_Learning_Creation.yaml",
+ "XDR Detections/NRT-AADHybridHealthADFSNewServer.yaml",
+ "XDR Detections/NRT_Creation_of_Expensive_Computes_in_Azure.yaml",
+ "XDR Detections/New-CloudShell-User.yaml",
+ "XDR Detections/NewResourceGroupsDeployedTo.yaml",
+ "XDR Detections/RareOperations.yaml",
+ "XDR Detections/SubscriptionMigration.yaml",
+ "XDR Detections/TimeSeriesAnomaly_Mass_Cloud_Resource_Deletions.yaml"
+ ],
+ "Version": "3.1.2"
+}
diff --git a/Solutions/Azure Activity/Hunting Queries/Machine_Learning_Creation.yaml b/Solutions/Azure Activity/Hunting Queries/Machine_Learning_Creation.yaml
index ab8a4765784..7f661ad84a0 100644
--- a/Solutions/Azure Activity/Hunting Queries/Machine_Learning_Creation.yaml
+++ b/Solutions/Azure Activity/Hunting Queries/Machine_Learning_Creation.yaml
@@ -43,4 +43,4 @@ entityMappings:
- identifier: ResourceId
columnName: _ResourceId
-version: 1.0
+version: "1.0"
diff --git a/Solutions/Azure Activity/Package/3.1.2.zip b/Solutions/Azure Activity/Package/3.1.2.zip
new file mode 100644
index 00000000000..d7ef600c97f
Binary files /dev/null and b/Solutions/Azure Activity/Package/3.1.2.zip differ
diff --git a/Solutions/Azure Activity/Package/createUiDefinition.json b/Solutions/Azure Activity/Package/createUiDefinition.json
index 4349553c2d5..fbc38a5735a 100644
--- a/Solutions/Azure Activity/Package/createUiDefinition.json
+++ b/Solutions/Azure Activity/Package/createUiDefinition.json
@@ -6,7 +6,7 @@
"config": {
"isWizard": false,
"basics": {
- "description": "
\n\n**Note:** Please refer to the following before installing the solution: \n\n• Review the solution [Release Notes](https://github.com/Azure/Azure-Sentinel/tree/master/Solutions/Azure%20Activity/ReleaseNotes.md)\n\n • There may be [known issues](https://aka.ms/sentinelsolutionsknownissues) pertaining to this Solution, please refer to them before installing.\n\nThe [Azure Activity](https://docs.microsoft.com/azure/azure-monitor/essentials/activity-log) solution for Microsoft Sentinel enables you to ingest Azure Activity Administrative, Security, Service Health, Alert, Recommendation, Policy, Autoscale and Resource Health [logs](https://docs.microsoft.com/azure/azure-monitor/reference/tables/azureactivity) using Diagnostic Settings into Microsoft Sentinel.\n\n**Data Connectors:** 1, **Workbooks:** 2, **Analytic Rules:** 14, **Hunting Queries:** 15\n\n[Learn more about Microsoft Sentinel](https://aka.ms/azuresentinel) | [Learn more about Solutions](https://aka.ms/azuresentinelsolutionsdoc)",
+ "description": "
\n\n**Note:** Please refer to the following before installing the solution: \n\n• Review the solution [Release Notes](https://github.com/Azure/Azure-Sentinel/tree/master/Solutions/Azure%20Activity/ReleaseNotes.md)\n\n • There may be [known issues](https://aka.ms/sentinelsolutionsknownissues) pertaining to this Solution, please refer to them before installing.\n\nThe [Azure Activity](https://docs.microsoft.com/azure/azure-monitor/essentials/activity-log) solution for Microsoft Sentinel enables you to ingest Azure Activity Administrative, Security, Service Health, Alert, Recommendation, Policy, Autoscale and Resource Health [logs](https://docs.microsoft.com/azure/azure-monitor/reference/tables/azureactivity) using Diagnostic Settings into Microsoft Sentinel.\n\n**Data Connectors:** 1, **Workbooks:** 2, **Analytic Rules:** 14, **XDR Detections:** 14, **Hunting Queries:** 15\n\n[Learn more about Microsoft Sentinel](https://aka.ms/azuresentinel) | [Learn more about Solutions](https://aka.ms/azuresentinelsolutionsdoc)",
"subscription": {
"resourceProviders": [
"Microsoft.OperationsManagement/solutions",
@@ -51,6 +51,47 @@
}
],
"steps": [
+ {
+ "name": "contentSelection",
+ "label": "Content selection",
+ "elements": [
+ {
+ "name": "DeployAnalyticsRule",
+ "type": "Microsoft.Common.CheckBox",
+ "label": "DeployAnalyticsRule",
+ "defaultValue": true,
+ "toolTip": "Deploy the Microsoft Sentinel analytic rules carried by this solution (ContentKind AnalyticsRule and its AnalyticsRuleTemplate registration face)."
+ },
+ {
+ "name": "DeployWorkbook",
+ "type": "Microsoft.Common.CheckBox",
+ "label": "DeployWorkbook",
+ "defaultValue": true,
+ "toolTip": "Deploy the Microsoft Sentinel workbook content and its Content Hub registration carried by this solution (ContentKind Workbook and WorkbookTemplate)."
+ },
+ {
+ "name": "DeployDataConnector",
+ "type": "Microsoft.Common.CheckBox",
+ "label": "DeployDataConnector",
+ "defaultValue": true,
+ "toolTip": "Deploy the data connectors carried by this solution, together with their metadata and catalog entries (ContentKind DataConnector, ResourceDataConnector and DataType)."
+ },
+ {
+ "name": "DeployCustomDetection",
+ "type": "Microsoft.Common.CheckBox",
+ "label": "DeployCustomDetection",
+ "defaultValue": false,
+ "toolTip": "Deploy the XDR-native custom detection resources and their Content Hub registrations (ContentKind CustomDetection and CustomDetectionTemplate). Independent of DeployAnalyticsRule: both kinds can be selected together. Existing analytic-rule instances are not disabled or removed. CD enabled or disabled status is controlled separately from this deployment switch."
+ },
+ {
+ "name": "DeployHuntingQuery",
+ "type": "Microsoft.Common.CheckBox",
+ "label": "DeployHuntingQuery",
+ "defaultValue": true,
+ "toolTip": "Deploy the Microsoft Sentinel hunting queries carried by this solution."
+ }
+ ]
+ },
{
"name": "dataconnectors",
"label": "Data Connectors",
@@ -244,13 +285,13 @@
{
"name": "analytic7",
"type": "Microsoft.Common.Section",
- "label": "NRT Microsoft Entra ID Hybrid Health AD FS New Server",
+ "label": "Azure Machine Learning Write Operations",
"elements": [
{
"name": "analytic7-text",
"type": "Microsoft.Common.TextBlock",
"options": {
- "text": "This detection uses AzureActivity logs (Administrative category) to identify the creation or update of a server instance in an Microsoft Entra ID Hybrid Health AD FS service.\nA threat actor can create a new AD Health ADFS service and create a fake server instance to spoof AD FS signing logs. There is no need to compromise an on-premises AD FS server.\nThis can be done programmatically via HTTP requests to Azure. More information in this blog: https://o365blog.com/post/hybridhealthagent/"
+ "text": "Shows the most prevalent users who perform write operations on Azure Machine Learning resources. List the common source IP address for each of those accounts. If an operation is not from those IP addresses, it may be worthy of investigation."
}
}
]
@@ -258,13 +299,13 @@
{
"name": "analytic8",
"type": "Microsoft.Common.Section",
- "label": "NRT Creation of expensive computes in Azure",
+ "label": "NRT Microsoft Entra ID Hybrid Health AD FS New Server",
"elements": [
{
"name": "analytic8-text",
"type": "Microsoft.Common.TextBlock",
"options": {
- "text": "Identifies the creation of large size or expensive VMs (with GPUs or with a large number of virtual CPUs) in Azure.\nAn adversary may create new or update existing virtual machines to evade defenses or use them for cryptomining purposes.\nFor Windows/Linux Vm Sizes, see https://docs.microsoft.com/azure/virtual-machines/windows/sizes \nAzure VM Naming Conventions, see https://docs.microsoft.com/azure/virtual-machines/vm-naming-conventions"
+ "text": "This detection uses AzureActivity logs (Administrative category) to identify the creation or update of a server instance in an Microsoft Entra ID Hybrid Health AD FS service.\nA threat actor can create a new AD Health ADFS service and create a fake server instance to spoof AD FS signing logs. There is no need to compromise an on-premises AD FS server.\nThis can be done programmatically via HTTP requests to Azure. More information in this blog: https://o365blog.com/post/hybridhealthagent/"
}
}
]
@@ -272,13 +313,13 @@
{
"name": "analytic9",
"type": "Microsoft.Common.Section",
- "label": "New CloudShell User",
+ "label": "NRT Creation of expensive computes in Azure",
"elements": [
{
"name": "analytic9-text",
"type": "Microsoft.Common.TextBlock",
"options": {
- "text": "Identifies when a user creates an Azure CloudShell for the first time.\nMonitor this activity to ensure only the expected users are using CloudShell."
+ "text": "Identifies the creation of large size or expensive VMs (with GPUs or with a large number of virtual CPUs) in Azure.\nAn adversary may create new or update existing virtual machines to evade defenses or use them for cryptomining purposes.\nFor Windows/Linux Vm Sizes, see https://docs.microsoft.com/azure/virtual-machines/windows/sizes \nAzure VM Naming Conventions, see https://docs.microsoft.com/azure/virtual-machines/vm-naming-conventions"
}
}
]
@@ -286,13 +327,13 @@
{
"name": "analytic10",
"type": "Microsoft.Common.Section",
- "label": "Suspicious Resource deployment",
+ "label": "New CloudShell User",
"elements": [
{
"name": "analytic10-text",
"type": "Microsoft.Common.TextBlock",
"options": {
- "text": "Identifies when a rare Resource and ResourceGroup deployment occurs by a previously unseen caller."
+ "text": "Identifies when a user creates an Azure CloudShell for the first time.\nMonitor this activity to ensure only the expected users are using CloudShell."
}
}
]
@@ -300,13 +341,13 @@
{
"name": "analytic11",
"type": "Microsoft.Common.Section",
- "label": "Rare subscription-level operations in Azure",
+ "label": "Suspicious Resource deployment",
"elements": [
{
"name": "analytic11-text",
"type": "Microsoft.Common.TextBlock",
"options": {
- "text": "This query looks for a few sensitive subscription-level events based on Azure Activity Logs. For example, this monitors for the operation name 'Create or Update Snapshot', which is used for creating backups but could be misused by attackers to dump hashes or extract sensitive information from the disk."
+ "text": "Identifies when a rare Resource and ResourceGroup deployment occurs by a previously unseen caller."
}
}
]
@@ -314,13 +355,13 @@
{
"name": "analytic12",
"type": "Microsoft.Common.Section",
- "label": "Mass Cloud resource deletions Time Series Anomaly",
+ "label": "Rare subscription-level operations in Azure",
"elements": [
{
"name": "analytic12-text",
"type": "Microsoft.Common.TextBlock",
"options": {
- "text": "This query generates the baseline pattern of cloud resource deletions by an individual and generates an anomaly when any unusual spike is detected. These anomalies from unusual or privileged users could be an indication of a cloud infrastructure takedown by an adversary."
+ "text": "This query looks for a few sensitive subscription-level events based on Azure Activity Logs. For example, this monitors for the operation name 'Create or Update Snapshot', which is used for creating backups but could be misused by attackers to dump hashes or extract sensitive information from the disk."
}
}
]
@@ -342,13 +383,13 @@
{
"name": "analytic14",
"type": "Microsoft.Common.Section",
- "label": "Azure Machine Learning Write Operations",
+ "label": "Mass Cloud resource deletions Time Series Anomaly",
"elements": [
{
"name": "analytic14-text",
"type": "Microsoft.Common.TextBlock",
"options": {
- "text": "Shows the most prevalent users who perform write operations on Azure Machine Learning resources. List the common source IP address for each of those accounts. If an operation is not from those IP addresses, it may be worthy of investigation."
+ "text": "This query generates the baseline pattern of cloud resource deletions by an individual and generates an anomaly when any unusual spike is detected. These anomalies from unusual or privileged users could be an indication of a cloud infrastructure takedown by an adversary."
}
}
]
@@ -593,7 +634,12 @@
"outputs": {
"workspace-location": "[first(map(filter(basics('getLAWorkspace').value, (filter) => and(contains(toLower(filter.id), toLower(resourceGroup().name)),equals(filter.name,basics('workspace')))), (item) => item.location))]",
"location": "[location()]",
- "workspace": "[basics('workspace')]"
+ "workspace": "[basics('workspace')]",
+ "DeployAnalyticsRule": "[steps('contentSelection').DeployAnalyticsRule]",
+ "DeployWorkbook": "[steps('contentSelection').DeployWorkbook]",
+ "DeployDataConnector": "[steps('contentSelection').DeployDataConnector]",
+ "DeployCustomDetection": "[steps('contentSelection').DeployCustomDetection]",
+ "DeployHuntingQuery": "[steps('contentSelection').DeployHuntingQuery]"
}
}
}
diff --git a/Solutions/Azure Activity/Package/mainTemplate.json b/Solutions/Azure Activity/Package/mainTemplate.json
index 59e86ca8d7f..63d94040933 100644
--- a/Solutions/Azure Activity/Package/mainTemplate.json
+++ b/Solutions/Azure Activity/Package/mainTemplate.json
@@ -43,13 +43,48 @@
"metadata": {
"description": "Name for the workbook"
}
+ },
+ "DeployAnalyticsRule": {
+ "type": "bool",
+ "defaultValue": true,
+ "metadata": {
+ "description": "Deploy the Microsoft Sentinel analytic rules carried by this solution (ContentKind AnalyticsRule and its AnalyticsRuleTemplate registration face)."
+ }
+ },
+ "DeployWorkbook": {
+ "type": "bool",
+ "defaultValue": true,
+ "metadata": {
+ "description": "Deploy the Microsoft Sentinel workbook content and its Content Hub registration carried by this solution (ContentKind Workbook and WorkbookTemplate)."
+ }
+ },
+ "DeployDataConnector": {
+ "type": "bool",
+ "defaultValue": true,
+ "metadata": {
+ "description": "Deploy the data connectors carried by this solution, together with their metadata and catalog entries (ContentKind DataConnector, ResourceDataConnector and DataType)."
+ }
+ },
+ "DeployCustomDetection": {
+ "type": "bool",
+ "defaultValue": false,
+ "metadata": {
+ "description": "Deploy the XDR-native custom detection resources and their Content Hub registrations (ContentKind CustomDetection and CustomDetectionTemplate). Independent of DeployAnalyticsRule: both kinds can be selected together. Existing analytic-rule instances are not disabled or removed. CD enabled or disabled status is controlled separately from this deployment switch."
+ }
+ },
+ "DeployHuntingQuery": {
+ "type": "bool",
+ "defaultValue": true,
+ "metadata": {
+ "description": "Deploy the Microsoft Sentinel hunting queries carried by this solution."
+ }
}
},
"variables": {
"email": "support@microsoft.com",
"_email": "[variables('email')]",
"_solutionName": "Azure Activity",
- "_solutionVersion": "3.0.4",
+ "_solutionVersion": "3.1.2",
"solutionId": "azuresentinel.azure-sentinel-solution-azureactivity",
"_solutionId": "[variables('solutionId')]",
"uiConfigId1": "AzureActivity",
@@ -132,7 +167,7 @@
"huntingQueryTemplateSpecName14": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-hq-',uniquestring('81fd68a2-9ad6-4a1c-7bd7-18efe5c99081')))]"
},
"huntingQueryObject15": {
- "huntingQueryVersion15": "1",
+ "huntingQueryVersion15": "1.0",
"_huntingQuerycontentId15": "26d116bd-324b-4bb8-b102-d4a282607ad7",
"huntingQueryTemplateSpecName15": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-hq-',uniquestring('26d116bd-324b-4bb8-b102-d4a282607ad7')))]"
},
@@ -179,46 +214,46 @@
"_analyticRulecontentProductId6": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','b2c15736-b9eb-4dae-8b02-3016b6a45a32','-', '2.0.2')))]"
},
"analyticRuleObject7": {
- "analyticRuleVersion7": "2.0.3",
- "_analyticRulecontentId7": "ec491363-5fe7-4eff-b68e-f42dcb76fcf6",
- "analyticRuleId7": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', 'ec491363-5fe7-4eff-b68e-f42dcb76fcf6')]",
- "analyticRuleTemplateSpecName7": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring('ec491363-5fe7-4eff-b68e-f42dcb76fcf6')))]",
- "_analyticRulecontentProductId7": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','ec491363-5fe7-4eff-b68e-f42dcb76fcf6','-', '2.0.3')))]"
+ "analyticRuleVersion7": "1.0.0",
+ "_analyticRulecontentId7": "68c89998-8052-4c80-a1f6-9d81060b6d57",
+ "analyticRuleId7": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', '68c89998-8052-4c80-a1f6-9d81060b6d57')]",
+ "analyticRuleTemplateSpecName7": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring('68c89998-8052-4c80-a1f6-9d81060b6d57')))]",
+ "_analyticRulecontentProductId7": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','68c89998-8052-4c80-a1f6-9d81060b6d57','-', '1.0.0')))]"
},
"analyticRuleObject8": {
"analyticRuleVersion8": "2.0.3",
- "_analyticRulecontentId8": "56fe0db0-6779-46fa-b3c5-006082a53064",
- "analyticRuleId8": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', '56fe0db0-6779-46fa-b3c5-006082a53064')]",
- "analyticRuleTemplateSpecName8": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring('56fe0db0-6779-46fa-b3c5-006082a53064')))]",
- "_analyticRulecontentProductId8": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','56fe0db0-6779-46fa-b3c5-006082a53064','-', '2.0.3')))]"
+ "_analyticRulecontentId8": "ec491363-5fe7-4eff-b68e-f42dcb76fcf6",
+ "analyticRuleId8": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', 'ec491363-5fe7-4eff-b68e-f42dcb76fcf6')]",
+ "analyticRuleTemplateSpecName8": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring('ec491363-5fe7-4eff-b68e-f42dcb76fcf6')))]",
+ "_analyticRulecontentProductId8": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','ec491363-5fe7-4eff-b68e-f42dcb76fcf6','-', '2.0.3')))]"
},
"analyticRuleObject9": {
"analyticRuleVersion9": "2.0.3",
- "_analyticRulecontentId9": "6d7214d9-4a28-44df-aafb-0910b9e6ae3e",
- "analyticRuleId9": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', '6d7214d9-4a28-44df-aafb-0910b9e6ae3e')]",
- "analyticRuleTemplateSpecName9": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring('6d7214d9-4a28-44df-aafb-0910b9e6ae3e')))]",
- "_analyticRulecontentProductId9": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','6d7214d9-4a28-44df-aafb-0910b9e6ae3e','-', '2.0.3')))]"
+ "_analyticRulecontentId9": "56fe0db0-6779-46fa-b3c5-006082a53064",
+ "analyticRuleId9": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', '56fe0db0-6779-46fa-b3c5-006082a53064')]",
+ "analyticRuleTemplateSpecName9": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring('56fe0db0-6779-46fa-b3c5-006082a53064')))]",
+ "_analyticRulecontentProductId9": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','56fe0db0-6779-46fa-b3c5-006082a53064','-', '2.0.3')))]"
},
"analyticRuleObject10": {
- "analyticRuleVersion10": "2.0.4",
- "_analyticRulecontentId10": "9fb57e58-3ed8-4b89-afcf-c8e786508b1c",
- "analyticRuleId10": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', '9fb57e58-3ed8-4b89-afcf-c8e786508b1c')]",
- "analyticRuleTemplateSpecName10": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring('9fb57e58-3ed8-4b89-afcf-c8e786508b1c')))]",
- "_analyticRulecontentProductId10": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','9fb57e58-3ed8-4b89-afcf-c8e786508b1c','-', '2.0.4')))]"
+ "analyticRuleVersion10": "2.0.3",
+ "_analyticRulecontentId10": "6d7214d9-4a28-44df-aafb-0910b9e6ae3e",
+ "analyticRuleId10": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', '6d7214d9-4a28-44df-aafb-0910b9e6ae3e')]",
+ "analyticRuleTemplateSpecName10": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring('6d7214d9-4a28-44df-aafb-0910b9e6ae3e')))]",
+ "_analyticRulecontentProductId10": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','6d7214d9-4a28-44df-aafb-0910b9e6ae3e','-', '2.0.3')))]"
},
"analyticRuleObject11": {
- "analyticRuleVersion11": "2.0.3",
- "_analyticRulecontentId11": "23de46ea-c425-4a77-b456-511ae4855d69",
- "analyticRuleId11": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', '23de46ea-c425-4a77-b456-511ae4855d69')]",
- "analyticRuleTemplateSpecName11": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring('23de46ea-c425-4a77-b456-511ae4855d69')))]",
- "_analyticRulecontentProductId11": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','23de46ea-c425-4a77-b456-511ae4855d69','-', '2.0.3')))]"
+ "analyticRuleVersion11": "2.0.4",
+ "_analyticRulecontentId11": "9fb57e58-3ed8-4b89-afcf-c8e786508b1c",
+ "analyticRuleId11": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', '9fb57e58-3ed8-4b89-afcf-c8e786508b1c')]",
+ "analyticRuleTemplateSpecName11": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring('9fb57e58-3ed8-4b89-afcf-c8e786508b1c')))]",
+ "_analyticRulecontentProductId11": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','9fb57e58-3ed8-4b89-afcf-c8e786508b1c','-', '2.0.4')))]"
},
"analyticRuleObject12": {
- "analyticRuleVersion12": "2.0.4",
- "_analyticRulecontentId12": "ed43bdb7-eaab-4ea4-be52-6951fcfa7e3b",
- "analyticRuleId12": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', 'ed43bdb7-eaab-4ea4-be52-6951fcfa7e3b')]",
- "analyticRuleTemplateSpecName12": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring('ed43bdb7-eaab-4ea4-be52-6951fcfa7e3b')))]",
- "_analyticRulecontentProductId12": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','ed43bdb7-eaab-4ea4-be52-6951fcfa7e3b','-', '2.0.4')))]"
+ "analyticRuleVersion12": "2.0.3",
+ "_analyticRulecontentId12": "23de46ea-c425-4a77-b456-511ae4855d69",
+ "analyticRuleId12": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', '23de46ea-c425-4a77-b456-511ae4855d69')]",
+ "analyticRuleTemplateSpecName12": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring('23de46ea-c425-4a77-b456-511ae4855d69')))]",
+ "_analyticRulecontentProductId12": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','23de46ea-c425-4a77-b456-511ae4855d69','-', '2.0.3')))]"
},
"analyticRuleObject13": {
"analyticRuleVersion13": "1.0.1",
@@ -228,11 +263,11 @@
"_analyticRulecontentProductId13": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','48c026d8-7f36-4a95-9568-6f1420d66e37','-', '1.0.1')))]"
},
"analyticRuleObject14": {
- "analyticRuleVersion14": "1.0.0",
- "_analyticRulecontentId14": "68c89998-8052-4c80-a1f6-9d81060b6d57",
- "analyticRuleId14": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', '68c89998-8052-4c80-a1f6-9d81060b6d57')]",
- "analyticRuleTemplateSpecName14": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring('68c89998-8052-4c80-a1f6-9d81060b6d57')))]",
- "_analyticRulecontentProductId14": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','68c89998-8052-4c80-a1f6-9d81060b6d57','-', '1.0.0')))]"
+ "analyticRuleVersion14": "2.0.4",
+ "_analyticRulecontentId14": "ed43bdb7-eaab-4ea4-be52-6951fcfa7e3b",
+ "analyticRuleId14": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', 'ed43bdb7-eaab-4ea4-be52-6951fcfa7e3b')]",
+ "analyticRuleTemplateSpecName14": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring('ed43bdb7-eaab-4ea4-be52-6951fcfa7e3b')))]",
+ "_analyticRulecontentProductId14": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','ed43bdb7-eaab-4ea4-be52-6951fcfa7e3b','-', '2.0.4')))]"
},
"workbookVersion1": "2.0.0",
"workbookContentId1": "AzureActivityWorkbook",
@@ -259,7 +294,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
- "description": "Azure Activity data connector with template version 3.0.4",
+ "description": "Azure Activity data connector with template version 3.1.2",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('dataConnectorVersion1')]",
@@ -341,7 +376,8 @@
"contentProductId": "[variables('_dataConnectorcontentProductId1')]",
"id": "[variables('_dataConnectorcontentProductId1')]",
"version": "[variables('dataConnectorVersion1')]"
- }
+ },
+ "condition": "[parameters('DeployDataConnector')]"
},
{
"type": "Microsoft.OperationalInsights/workspaces/providers/metadata",
@@ -371,7 +407,8 @@
"email": "support@microsoft.com",
"link": "https://support.microsoft.com/"
}
- }
+ },
+ "condition": "[parameters('DeployDataConnector')]"
},
{
"name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',variables('_dataConnectorContentId1'))]",
@@ -407,7 +444,8 @@
],
"id": "[variables('_uiConfigId1')]"
}
- }
+ },
+ "condition": "[parameters('DeployDataConnector')]"
},
{
"type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates",
@@ -418,7 +456,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
- "description": "AnalyticsRulesAdministrativeOperations_HuntingQueries Hunting Query with template version 3.0.4",
+ "description": "AnalyticsRulesAdministrativeOperations_HuntingQueries Hunting Query with template version 3.1.2",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('huntingQueryObject1').huntingQueryVersion1]",
@@ -492,7 +530,8 @@
"contentProductId": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject1')._huntingQuerycontentId1,'-', '2.0.2')))]",
"id": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject1')._huntingQuerycontentId1,'-', '2.0.2')))]",
"version": "2.0.2"
- }
+ },
+ "condition": "[parameters('DeployHuntingQuery')]"
},
{
"type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates",
@@ -503,7 +542,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
- "description": "AnomalousAzureOperationModel_HuntingQueries Hunting Query with template version 3.0.4",
+ "description": "AnomalousAzureOperationModel_HuntingQueries Hunting Query with template version 3.1.2",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('huntingQueryObject2').huntingQueryVersion2]",
@@ -577,7 +616,8 @@
"contentProductId": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject2')._huntingQuerycontentId2,'-', '2.0.0')))]",
"id": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject2')._huntingQuerycontentId2,'-', '2.0.0')))]",
"version": "2.0.0"
- }
+ },
+ "condition": "[parameters('DeployHuntingQuery')]"
},
{
"type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates",
@@ -588,7 +628,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
- "description": "Anomalous_Listing_Of_Storage_Keys_HuntingQueries Hunting Query with template version 3.0.4",
+ "description": "Anomalous_Listing_Of_Storage_Keys_HuntingQueries Hunting Query with template version 3.1.2",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('huntingQueryObject3').huntingQueryVersion3]",
@@ -662,7 +702,8 @@
"contentProductId": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject3')._huntingQuerycontentId3,'-', '2.0.1')))]",
"id": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject3')._huntingQuerycontentId3,'-', '2.0.1')))]",
"version": "2.0.1"
- }
+ },
+ "condition": "[parameters('DeployHuntingQuery')]"
},
{
"type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates",
@@ -673,7 +714,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
- "description": "AzureAdministrationFromVPS_HuntingQueries Hunting Query with template version 3.0.4",
+ "description": "AzureAdministrationFromVPS_HuntingQueries Hunting Query with template version 3.1.2",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('huntingQueryObject4').huntingQueryVersion4]",
@@ -747,7 +788,8 @@
"contentProductId": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject4')._huntingQuerycontentId4,'-', '2.0.1')))]",
"id": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject4')._huntingQuerycontentId4,'-', '2.0.1')))]",
"version": "2.0.1"
- }
+ },
+ "condition": "[parameters('DeployHuntingQuery')]"
},
{
"type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates",
@@ -758,7 +800,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
- "description": "AzureNSG_AdministrativeOperations_HuntingQueries Hunting Query with template version 3.0.4",
+ "description": "AzureNSG_AdministrativeOperations_HuntingQueries Hunting Query with template version 3.1.2",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('huntingQueryObject5').huntingQueryVersion5]",
@@ -832,7 +874,8 @@
"contentProductId": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject5')._huntingQuerycontentId5,'-', '2.0.1')))]",
"id": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject5')._huntingQuerycontentId5,'-', '2.0.1')))]",
"version": "2.0.1"
- }
+ },
+ "condition": "[parameters('DeployHuntingQuery')]"
},
{
"type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates",
@@ -843,7 +886,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
- "description": "AzureRunCommandFromAzureIP_HuntingQueries Hunting Query with template version 3.0.4",
+ "description": "AzureRunCommandFromAzureIP_HuntingQueries Hunting Query with template version 3.1.2",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('huntingQueryObject6').huntingQueryVersion6]",
@@ -917,7 +960,8 @@
"contentProductId": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject6')._huntingQuerycontentId6,'-', '2.1.1')))]",
"id": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject6')._huntingQuerycontentId6,'-', '2.1.1')))]",
"version": "2.1.1"
- }
+ },
+ "condition": "[parameters('DeployHuntingQuery')]"
},
{
"type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates",
@@ -928,7 +972,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
- "description": "AzureSentinelConnectors_AdministrativeOperations_HuntingQueries Hunting Query with template version 3.0.4",
+ "description": "AzureSentinelConnectors_AdministrativeOperations_HuntingQueries Hunting Query with template version 3.1.2",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('huntingQueryObject7').huntingQueryVersion7]",
@@ -1002,7 +1046,8 @@
"contentProductId": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject7')._huntingQuerycontentId7,'-', '2.0.1')))]",
"id": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject7')._huntingQuerycontentId7,'-', '2.0.1')))]",
"version": "2.0.1"
- }
+ },
+ "condition": "[parameters('DeployHuntingQuery')]"
},
{
"type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates",
@@ -1013,7 +1058,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
- "description": "AzureSentinelWorkbooks_AdministrativeOperation_HuntingQueries Hunting Query with template version 3.0.4",
+ "description": "AzureSentinelWorkbooks_AdministrativeOperation_HuntingQueries Hunting Query with template version 3.1.2",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('huntingQueryObject8').huntingQueryVersion8]",
@@ -1087,7 +1132,8 @@
"contentProductId": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject8')._huntingQuerycontentId8,'-', '2.0.1')))]",
"id": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject8')._huntingQuerycontentId8,'-', '2.0.1')))]",
"version": "2.0.1"
- }
+ },
+ "condition": "[parameters('DeployHuntingQuery')]"
},
{
"type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates",
@@ -1098,7 +1144,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
- "description": "AzureVirtualNetworkSubnets_AdministrativeOperationset_HuntingQueries Hunting Query with template version 3.0.4",
+ "description": "AzureVirtualNetworkSubnets_AdministrativeOperationset_HuntingQueries Hunting Query with template version 3.1.2",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('huntingQueryObject9').huntingQueryVersion9]",
@@ -1172,7 +1218,8 @@
"contentProductId": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject9')._huntingQuerycontentId9,'-', '2.0.1')))]",
"id": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject9')._huntingQuerycontentId9,'-', '2.0.1')))]",
"version": "2.0.1"
- }
+ },
+ "condition": "[parameters('DeployHuntingQuery')]"
},
{
"type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates",
@@ -1183,7 +1230,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
- "description": "Common_Deployed_Resources_HuntingQueries Hunting Query with template version 3.0.4",
+ "description": "Common_Deployed_Resources_HuntingQueries Hunting Query with template version 3.1.2",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('huntingQueryObject10').huntingQueryVersion10]",
@@ -1257,7 +1304,8 @@
"contentProductId": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject10')._huntingQuerycontentId10,'-', '2.0.1')))]",
"id": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject10')._huntingQuerycontentId10,'-', '2.0.1')))]",
"version": "2.0.1"
- }
+ },
+ "condition": "[parameters('DeployHuntingQuery')]"
},
{
"type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates",
@@ -1268,7 +1316,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
- "description": "Creating_Anomalous_Number_Of_Resources_HuntingQueries Hunting Query with template version 3.0.4",
+ "description": "Creating_Anomalous_Number_Of_Resources_HuntingQueries Hunting Query with template version 3.1.2",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('huntingQueryObject11').huntingQueryVersion11]",
@@ -1342,7 +1390,8 @@
"contentProductId": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject11')._huntingQuerycontentId11,'-', '2.0.1')))]",
"id": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject11')._huntingQuerycontentId11,'-', '2.0.1')))]",
"version": "2.0.1"
- }
+ },
+ "condition": "[parameters('DeployHuntingQuery')]"
},
{
"type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates",
@@ -1353,7 +1402,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
- "description": "Granting_Permissions_to_Account_HuntingQueries Hunting Query with template version 3.0.4",
+ "description": "Granting_Permissions_to_Account_HuntingQueries Hunting Query with template version 3.1.2",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('huntingQueryObject12').huntingQueryVersion12]",
@@ -1427,7 +1476,8 @@
"contentProductId": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject12')._huntingQuerycontentId12,'-', '2.0.1')))]",
"id": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject12')._huntingQuerycontentId12,'-', '2.0.1')))]",
"version": "2.0.1"
- }
+ },
+ "condition": "[parameters('DeployHuntingQuery')]"
},
{
"type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates",
@@ -1438,7 +1488,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
- "description": "PortOpenedForAzureResource_HuntingQueries Hunting Query with template version 3.0.4",
+ "description": "PortOpenedForAzureResource_HuntingQueries Hunting Query with template version 3.1.2",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('huntingQueryObject13').huntingQueryVersion13]",
@@ -1512,7 +1562,8 @@
"contentProductId": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject13')._huntingQuerycontentId13,'-', '2.0.1')))]",
"id": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject13')._huntingQuerycontentId13,'-', '2.0.1')))]",
"version": "2.0.1"
- }
+ },
+ "condition": "[parameters('DeployHuntingQuery')]"
},
{
"type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates",
@@ -1523,7 +1574,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
- "description": "Rare_Custom_Script_Extension_HuntingQueries Hunting Query with template version 3.0.4",
+ "description": "Rare_Custom_Script_Extension_HuntingQueries Hunting Query with template version 3.1.2",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('huntingQueryObject14').huntingQueryVersion14]",
@@ -1597,7 +1648,8 @@
"contentProductId": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject14')._huntingQuerycontentId14,'-', '2.0.2')))]",
"id": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject14')._huntingQuerycontentId14,'-', '2.0.2')))]",
"version": "2.0.2"
- }
+ },
+ "condition": "[parameters('DeployHuntingQuery')]"
},
{
"type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates",
@@ -1608,7 +1660,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
- "description": "Machine_Learning_Creation_HuntingQueries Hunting Query with template version 3.0.4",
+ "description": "Machine_Learning_Creation_HuntingQueries Hunting Query with template version 3.1.2",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('huntingQueryObject15').huntingQueryVersion15]",
@@ -1679,10 +1731,11 @@
"contentId": "[variables('huntingQueryObject15')._huntingQuerycontentId15]",
"contentKind": "HuntingQuery",
"displayName": "Azure Machine Learning Write Operations",
- "contentProductId": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject15')._huntingQuerycontentId15,'-', '1')))]",
- "id": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject15')._huntingQuerycontentId15,'-', '1')))]",
- "version": "1"
- }
+ "contentProductId": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject15')._huntingQuerycontentId15,'-', '1.0')))]",
+ "id": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject15')._huntingQuerycontentId15,'-', '1.0')))]",
+ "version": "1.0"
+ },
+ "condition": "[parameters('DeployHuntingQuery')]"
},
{
"type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates",
@@ -1693,7 +1746,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
- "description": "AADHybridHealthADFSNewServer_AnalyticalRules Analytics Rule with template version 3.0.4",
+ "description": "AADHybridHealthADFSNewServer_AnalyticalRules Analytics Rule with template version 3.1.2",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('analyticRuleObject1').analyticRuleVersion1]",
@@ -1721,10 +1774,10 @@
"status": "Available",
"requiredDataConnectors": [
{
+ "connectorId": "AzureActivity",
"dataTypes": [
"AzureActivity"
- ],
- "connectorId": "AzureActivity"
+ ]
}
],
"tactics": [
@@ -1735,30 +1788,30 @@
],
"entityMappings": [
{
+ "entityType": "Account",
"fieldMappings": [
{
- "columnName": "Caller",
- "identifier": "FullName"
+ "identifier": "FullName",
+ "columnName": "Caller"
},
{
- "columnName": "Name",
- "identifier": "Name"
+ "identifier": "Name",
+ "columnName": "Name"
},
{
- "columnName": "UPNSuffix",
- "identifier": "UPNSuffix"
+ "identifier": "UPNSuffix",
+ "columnName": "UPNSuffix"
}
- ],
- "entityType": "Account"
+ ]
},
{
+ "entityType": "IP",
"fieldMappings": [
{
- "columnName": "CallerIpAddress",
- "identifier": "Address"
+ "identifier": "Address",
+ "columnName": "CallerIpAddress"
}
- ],
- "entityType": "IP"
+ ]
}
]
}
@@ -1803,7 +1856,8 @@
"contentProductId": "[variables('analyticRuleObject1')._analyticRulecontentProductId1]",
"id": "[variables('analyticRuleObject1')._analyticRulecontentProductId1]",
"version": "[variables('analyticRuleObject1').analyticRuleVersion1]"
- }
+ },
+ "condition": "[parameters('DeployAnalyticsRule')]"
},
{
"type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates",
@@ -1814,7 +1868,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
- "description": "AADHybridHealthADFSServiceDelete_AnalyticalRules Analytics Rule with template version 3.0.4",
+ "description": "AADHybridHealthADFSServiceDelete_AnalyticalRules Analytics Rule with template version 3.1.2",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('analyticRuleObject2').analyticRuleVersion2]",
@@ -1842,10 +1896,10 @@
"status": "Available",
"requiredDataConnectors": [
{
+ "connectorId": "AzureActivity",
"dataTypes": [
"AzureActivity"
- ],
- "connectorId": "AzureActivity"
+ ]
}
],
"tactics": [
@@ -1859,30 +1913,30 @@
],
"entityMappings": [
{
+ "entityType": "Account",
"fieldMappings": [
{
- "columnName": "Caller",
- "identifier": "FullName"
+ "identifier": "FullName",
+ "columnName": "Caller"
},
{
- "columnName": "Name",
- "identifier": "Name"
+ "identifier": "Name",
+ "columnName": "Name"
},
{
- "columnName": "UPNSuffix",
- "identifier": "UPNSuffix"
+ "identifier": "UPNSuffix",
+ "columnName": "UPNSuffix"
}
- ],
- "entityType": "Account"
+ ]
},
{
+ "entityType": "IP",
"fieldMappings": [
{
- "columnName": "CallerIpAddress",
- "identifier": "Address"
+ "identifier": "Address",
+ "columnName": "CallerIpAddress"
}
- ],
- "entityType": "IP"
+ ]
}
]
}
@@ -1927,7 +1981,8 @@
"contentProductId": "[variables('analyticRuleObject2')._analyticRulecontentProductId2]",
"id": "[variables('analyticRuleObject2')._analyticRulecontentProductId2]",
"version": "[variables('analyticRuleObject2').analyticRuleVersion2]"
- }
+ },
+ "condition": "[parameters('DeployAnalyticsRule')]"
},
{
"type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates",
@@ -1938,7 +1993,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
- "description": "AADHybridHealthADFSSuspApp_AnalyticalRules Analytics Rule with template version 3.0.4",
+ "description": "AADHybridHealthADFSSuspApp_AnalyticalRules Analytics Rule with template version 3.1.2",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('analyticRuleObject3').analyticRuleVersion3]",
@@ -1966,10 +2021,10 @@
"status": "Available",
"requiredDataConnectors": [
{
+ "connectorId": "AzureActivity",
"dataTypes": [
"AzureActivity"
- ],
- "connectorId": "AzureActivity"
+ ]
}
],
"tactics": [
@@ -1982,30 +2037,30 @@
],
"entityMappings": [
{
+ "entityType": "Account",
"fieldMappings": [
{
- "columnName": "Caller",
- "identifier": "FullName"
+ "identifier": "FullName",
+ "columnName": "Caller"
},
{
- "columnName": "Name",
- "identifier": "Name"
+ "identifier": "Name",
+ "columnName": "Name"
},
{
- "columnName": "UPNSuffix",
- "identifier": "UPNSuffix"
+ "identifier": "UPNSuffix",
+ "columnName": "UPNSuffix"
}
- ],
- "entityType": "Account"
+ ]
},
{
+ "entityType": "IP",
"fieldMappings": [
{
- "columnName": "CallerIpAddress",
- "identifier": "Address"
+ "identifier": "Address",
+ "columnName": "CallerIpAddress"
}
- ],
- "entityType": "IP"
+ ]
}
]
}
@@ -2050,7 +2105,8 @@
"contentProductId": "[variables('analyticRuleObject3')._analyticRulecontentProductId3]",
"id": "[variables('analyticRuleObject3')._analyticRulecontentProductId3]",
"version": "[variables('analyticRuleObject3').analyticRuleVersion3]"
- }
+ },
+ "condition": "[parameters('DeployAnalyticsRule')]"
},
{
"type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates",
@@ -2061,7 +2117,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
- "description": "Creating_Anomalous_Number_Of_Resources_detection_AnalyticalRules Analytics Rule with template version 3.0.4",
+ "description": "Creating_Anomalous_Number_Of_Resources_detection_AnalyticalRules Analytics Rule with template version 3.1.2",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('analyticRuleObject4').analyticRuleVersion4]",
@@ -2089,10 +2145,10 @@
"status": "Available",
"requiredDataConnectors": [
{
+ "connectorId": "AzureActivity",
"dataTypes": [
"AzureActivity"
- ],
- "connectorId": "AzureActivity"
+ ]
}
],
"tactics": [
@@ -2103,39 +2159,39 @@
],
"entityMappings": [
{
+ "entityType": "Account",
"fieldMappings": [
{
- "columnName": "Caller",
- "identifier": "FullName"
+ "identifier": "FullName",
+ "columnName": "Caller"
},
{
- "columnName": "Name",
- "identifier": "Name"
+ "identifier": "Name",
+ "columnName": "Name"
},
{
- "columnName": "UPNSuffix",
- "identifier": "UPNSuffix"
+ "identifier": "UPNSuffix",
+ "columnName": "UPNSuffix"
}
- ],
- "entityType": "Account"
+ ]
},
{
+ "entityType": "Account",
"fieldMappings": [
{
- "columnName": "AadUserId",
- "identifier": "AadUserId"
+ "identifier": "AadUserId",
+ "columnName": "AadUserId"
}
- ],
- "entityType": "Account"
+ ]
},
{
+ "entityType": "IP",
"fieldMappings": [
{
- "columnName": "CallerIpAddress",
- "identifier": "Address"
+ "identifier": "Address",
+ "columnName": "CallerIpAddress"
}
- ],
- "entityType": "IP"
+ ]
}
]
}
@@ -2180,7 +2236,8 @@
"contentProductId": "[variables('analyticRuleObject4')._analyticRulecontentProductId4]",
"id": "[variables('analyticRuleObject4')._analyticRulecontentProductId4]",
"version": "[variables('analyticRuleObject4').analyticRuleVersion4]"
- }
+ },
+ "condition": "[parameters('DeployAnalyticsRule')]"
},
{
"type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates",
@@ -2191,7 +2248,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
- "description": "Creation_of_Expensive_Computes_in_Azure_AnalyticalRules Analytics Rule with template version 3.0.4",
+ "description": "Creation_of_Expensive_Computes_in_Azure_AnalyticalRules Analytics Rule with template version 3.1.2",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('analyticRuleObject5').analyticRuleVersion5]",
@@ -2219,10 +2276,10 @@
"status": "Available",
"requiredDataConnectors": [
{
+ "connectorId": "AzureActivity",
"dataTypes": [
"AzureActivity"
- ],
- "connectorId": "AzureActivity"
+ ]
}
],
"tactics": [
@@ -2233,39 +2290,39 @@
],
"entityMappings": [
{
+ "entityType": "Account",
"fieldMappings": [
{
- "columnName": "Caller",
- "identifier": "FullName"
+ "identifier": "FullName",
+ "columnName": "Caller"
},
{
- "columnName": "Name",
- "identifier": "Name"
+ "identifier": "Name",
+ "columnName": "Name"
},
{
- "columnName": "UPNSuffix",
- "identifier": "UPNSuffix"
+ "identifier": "UPNSuffix",
+ "columnName": "UPNSuffix"
}
- ],
- "entityType": "Account"
+ ]
},
{
+ "entityType": "Host",
"fieldMappings": [
{
- "columnName": "ComputerName",
- "identifier": "HostName"
+ "identifier": "HostName",
+ "columnName": "ComputerName"
}
- ],
- "entityType": "Host"
+ ]
},
{
+ "entityType": "IP",
"fieldMappings": [
{
- "columnName": "CallerIpAddress",
- "identifier": "Address"
+ "identifier": "Address",
+ "columnName": "CallerIpAddress"
}
- ],
- "entityType": "IP"
+ ]
}
]
}
@@ -2310,7 +2367,8 @@
"contentProductId": "[variables('analyticRuleObject5')._analyticRulecontentProductId5]",
"id": "[variables('analyticRuleObject5')._analyticRulecontentProductId5]",
"version": "[variables('analyticRuleObject5').analyticRuleVersion5]"
- }
+ },
+ "condition": "[parameters('DeployAnalyticsRule')]"
},
{
"type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates",
@@ -2321,7 +2379,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
- "description": "Granting_Permissions_To_Account_detection_AnalyticalRules Analytics Rule with template version 3.0.4",
+ "description": "Granting_Permissions_To_Account_detection_AnalyticalRules Analytics Rule with template version 3.1.2",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('analyticRuleObject6').analyticRuleVersion6]",
@@ -2349,16 +2407,16 @@
"status": "Available",
"requiredDataConnectors": [
{
+ "connectorId": "AzureActivity",
"dataTypes": [
"AzureActivity"
- ],
- "connectorId": "AzureActivity"
+ ]
},
{
+ "connectorId": "BehaviorAnalytics",
"dataTypes": [
"IdentityInfo"
- ],
- "connectorId": "BehaviorAnalytics"
+ ]
}
],
"tactics": [
@@ -2371,30 +2429,30 @@
],
"entityMappings": [
{
+ "entityType": "Account",
"fieldMappings": [
{
- "columnName": "Caller",
- "identifier": "FullName"
+ "identifier": "FullName",
+ "columnName": "Caller"
},
{
- "columnName": "Name",
- "identifier": "Name"
+ "identifier": "Name",
+ "columnName": "Name"
},
{
- "columnName": "UPNSuffix",
- "identifier": "UPNSuffix"
+ "identifier": "UPNSuffix",
+ "columnName": "UPNSuffix"
}
- ],
- "entityType": "Account"
+ ]
},
{
+ "entityType": "IP",
"fieldMappings": [
{
- "columnName": "CallerIpAddress",
- "identifier": "Address"
+ "identifier": "Address",
+ "columnName": "CallerIpAddress"
}
- ],
- "entityType": "IP"
+ ]
}
]
}
@@ -2439,7 +2497,8 @@
"contentProductId": "[variables('analyticRuleObject6')._analyticRulecontentProductId6]",
"id": "[variables('analyticRuleObject6')._analyticRulecontentProductId6]",
"version": "[variables('analyticRuleObject6').analyticRuleVersion6]"
- }
+ },
+ "condition": "[parameters('DeployAnalyticsRule')]"
},
{
"type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates",
@@ -2450,7 +2509,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
- "description": "NRT-AADHybridHealthADFSNewServer_AnalyticalRules Analytics Rule with template version 3.0.4",
+ "description": "Machine_Learning_Creation_AnalyticalRules Analytics Rule with template version 3.1.2",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('analyticRuleObject7').analyticRuleVersion7]",
@@ -2461,59 +2520,71 @@
"type": "Microsoft.SecurityInsights/AlertRuleTemplates",
"name": "[variables('analyticRuleObject7')._analyticRulecontentId7]",
"apiVersion": "2023-02-01-preview",
- "kind": "NRT",
+ "kind": "Scheduled",
"location": "[parameters('workspace-location')]",
"properties": {
- "description": "This detection uses AzureActivity logs (Administrative category) to identify the creation or update of a server instance in an Microsoft Entra ID Hybrid Health AD FS service.\nA threat actor can create a new AD Health ADFS service and create a fake server instance to spoof AD FS signing logs. There is no need to compromise an on-premises AD FS server.\nThis can be done programmatically via HTTP requests to Azure. More information in this blog: https://o365blog.com/post/hybridhealthagent/",
- "displayName": "NRT Microsoft Entra ID Hybrid Health AD FS New Server",
+ "description": "Shows the most prevalent users who perform write operations on Azure Machine Learning resources. List the common source IP address for each of those accounts. If an operation is not from those IP addresses, it may be worthy of investigation.",
+ "displayName": "Azure Machine Learning Write Operations",
"enabled": false,
- "query": "AzureActivity\n| where CategoryValue =~ 'Administrative'\n| where ResourceProviderValue =~ 'Microsoft.ADHybridHealthService'\n| where _ResourceId has 'AdFederationService'\n| where OperationNameValue =~ 'Microsoft.ADHybridHealthService/services/servicemembers/action'\n| extend claimsJson = parse_json(Claims)\n| extend AppId = tostring(claimsJson.appid), AccountName = tostring(claimsJson.name), Name = tostring(split(Caller,'@',0)[0]), UPNSuffix = tostring(split(Caller,'@',1)[0])\n| project-away claimsJson\n",
- "severity": "Medium",
+ "query": "AzureActivity\n| where ResourceProviderValue == \"MICROSOFT.MACHINELEARNINGSERVICES\" // Filter activities related to Microsoft Machine Learning Services\n| extend SCOPE = tostring(parse_json(Authorization).scope) // Parse Authorization scope as string\n| extend subname = split(Hierarchy, \"/\") // Split Hierarchy to extract Subscription Name and ID\n| extend ['Subscription Name'] = subname[-2], ['Subscription ID'] = subname[-1] // Extract Subscription Name and ID\n| extend Properties = parse_json(Properties) // Parse Properties as JSON\n| extend Properties_entity = tostring(Properties.entity) // Cast Properties.entity to string\n| where isnotempty(Properties_entity) // Filter activities where Properties.entity is not empty\n// | where Properties_entity contains \"deepseek\" // Filter activities where Properties.entity contains \"deepseek\"\n| where OperationNameValue contains \"write\" // Filter activities where OperationNameValue contains \"write\"\n| where OperationNameValue !contains \"MICROSOFT.AUTHORIZATION/ROLEASSIGNMENTS/WRITE\" // Exclude role assignments\n| extend LLM = tostring(split(Properties_entity, \"/\")[-1]) // Extract the last segment of Properties_entity and cast it to string\n| distinct TimeGenerated, tostring(['Subscription Name']), ResourceGroup, tostring(['Subscription ID']), Caller, CallerIpAddress, OperationNameValue, LLM, _ResourceId // Select distinct relevant fields for output\n",
+ "queryFrequency": "P1D",
+ "queryPeriod": "P1D",
+ "severity": "Low",
"suppressionDuration": "PT1H",
"suppressionEnabled": false,
+ "triggerOperator": "GreaterThan",
+ "triggerThreshold": 0,
"status": "Available",
"requiredDataConnectors": [
{
+ "connectorId": "AzureActivity",
"dataTypes": [
"AzureActivity"
- ],
- "connectorId": "AzureActivity"
+ ]
}
],
"tactics": [
- "DefenseEvasion"
+ "InitialAccess",
+ "Execution",
+ "Impact"
],
"techniques": [
- "T1578"
+ "T1078",
+ "T1059",
+ "T1496"
],
"entityMappings": [
{
+ "entityType": "Account",
"fieldMappings": [
{
- "columnName": "Caller",
- "identifier": "FullName"
- },
- {
- "columnName": "Name",
- "identifier": "Name"
- },
+ "identifier": "Name",
+ "columnName": "Caller"
+ }
+ ]
+ },
+ {
+ "entityType": "IP",
+ "fieldMappings": [
{
- "columnName": "UPNSuffix",
- "identifier": "UPNSuffix"
+ "identifier": "Address",
+ "columnName": "CallerIpAddress"
}
- ],
- "entityType": "Account"
+ ]
},
{
+ "entityType": "AzureResource",
"fieldMappings": [
{
- "columnName": "CallerIpAddress",
- "identifier": "Address"
+ "identifier": "ResourceId",
+ "columnName": "_ResourceId"
}
- ],
- "entityType": "IP"
+ ]
}
- ]
+ ],
+ "eventGroupingSettings": {
+ "aggregationKind": "SingleAlert"
+ }
}
},
{
@@ -2552,11 +2623,12 @@
"contentSchemaVersion": "3.0.0",
"contentId": "[variables('analyticRuleObject7')._analyticRulecontentId7]",
"contentKind": "AnalyticsRule",
- "displayName": "NRT Microsoft Entra ID Hybrid Health AD FS New Server",
+ "displayName": "Azure Machine Learning Write Operations",
"contentProductId": "[variables('analyticRuleObject7')._analyticRulecontentProductId7]",
"id": "[variables('analyticRuleObject7')._analyticRulecontentProductId7]",
"version": "[variables('analyticRuleObject7').analyticRuleVersion7]"
- }
+ },
+ "condition": "[parameters('DeployAnalyticsRule')]"
},
{
"type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates",
@@ -2567,7 +2639,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
- "description": "NRT_Creation_of_Expensive_Computes_in_Azure_AnalyticalRules Analytics Rule with template version 3.0.4",
+ "description": "NRT-AADHybridHealthADFSNewServer_AnalyticalRules Analytics Rule with template version 3.1.2",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('analyticRuleObject8').analyticRuleVersion8]",
@@ -2581,20 +2653,20 @@
"kind": "NRT",
"location": "[parameters('workspace-location')]",
"properties": {
- "description": "Identifies the creation of large size or expensive VMs (with GPUs or with a large number of virtual CPUs) in Azure.\nAn adversary may create new or update existing virtual machines to evade defenses or use them for cryptomining purposes.\nFor Windows/Linux Vm Sizes, see https://docs.microsoft.com/azure/virtual-machines/windows/sizes \nAzure VM Naming Conventions, see https://docs.microsoft.com/azure/virtual-machines/vm-naming-conventions",
- "displayName": "NRT Creation of expensive computes in Azure",
+ "description": "This detection uses AzureActivity logs (Administrative category) to identify the creation or update of a server instance in an Microsoft Entra ID Hybrid Health AD FS service.\nA threat actor can create a new AD Health ADFS service and create a fake server instance to spoof AD FS signing logs. There is no need to compromise an on-premises AD FS server.\nThis can be done programmatically via HTTP requests to Azure. More information in this blog: https://o365blog.com/post/hybridhealthagent/",
+ "displayName": "NRT Microsoft Entra ID Hybrid Health AD FS New Server",
"enabled": false,
- "query": "let tokens = dynamic([\"416\",\"208\",\"192\",\"128\",\"120\",\"96\",\"80\",\"72\",\"64\",\"48\",\"44\",\"40\",\"nc12\",\"nc24\",\"nv24\"]);\nlet operationList = dynamic([\"microsoft.compute/virtualmachines/write\", \"microsoft.resources/deployments/write\"]);\nAzureActivity\n| where OperationNameValue in~ (operationList)\n| where ActivityStatusValue startswith \"Accept\"\n| where Properties has 'vmSize'\n| extend parsed_property= parse_json(tostring((parse_json(Properties).responseBody))).properties\n| extend vmSize = tostring((parsed_property.hardwareProfile).vmSize)\n| mv-apply token=tokens to typeof(string) on (where vmSize contains token)\n| extend ComputerName = tostring((parsed_property.osProfile).computerName)\n| project TimeGenerated, OperationNameValue, ActivityStatusValue, Caller, CallerIpAddress, ComputerName, vmSize\n| extend Name = tostring(split(Caller,'@',0)[0]), UPNSuffix = tostring(split(Caller,'@',1)[0])\n",
+ "query": "AzureActivity\n| where CategoryValue =~ 'Administrative'\n| where ResourceProviderValue =~ 'Microsoft.ADHybridHealthService'\n| where _ResourceId has 'AdFederationService'\n| where OperationNameValue =~ 'Microsoft.ADHybridHealthService/services/servicemembers/action'\n| extend claimsJson = parse_json(Claims)\n| extend AppId = tostring(claimsJson.appid), AccountName = tostring(claimsJson.name), Name = tostring(split(Caller,'@',0)[0]), UPNSuffix = tostring(split(Caller,'@',1)[0])\n| project-away claimsJson\n",
"severity": "Medium",
"suppressionDuration": "PT1H",
"suppressionEnabled": false,
"status": "Available",
"requiredDataConnectors": [
{
+ "connectorId": "AzureActivity",
"dataTypes": [
"AzureActivity"
- ],
- "connectorId": "AzureActivity"
+ ]
}
],
"tactics": [
@@ -2605,39 +2677,30 @@
],
"entityMappings": [
{
+ "entityType": "Account",
"fieldMappings": [
{
- "columnName": "Caller",
- "identifier": "FullName"
+ "identifier": "FullName",
+ "columnName": "Caller"
},
{
- "columnName": "Name",
- "identifier": "Name"
+ "identifier": "Name",
+ "columnName": "Name"
},
{
- "columnName": "UPNSuffix",
- "identifier": "UPNSuffix"
- }
- ],
- "entityType": "Account"
- },
- {
- "fieldMappings": [
- {
- "columnName": "ComputerName",
- "identifier": "HostName"
+ "identifier": "UPNSuffix",
+ "columnName": "UPNSuffix"
}
- ],
- "entityType": "Host"
+ ]
},
{
+ "entityType": "IP",
"fieldMappings": [
{
- "columnName": "CallerIpAddress",
- "identifier": "Address"
+ "identifier": "Address",
+ "columnName": "CallerIpAddress"
}
- ],
- "entityType": "IP"
+ ]
}
]
}
@@ -2678,11 +2741,12 @@
"contentSchemaVersion": "3.0.0",
"contentId": "[variables('analyticRuleObject8')._analyticRulecontentId8]",
"contentKind": "AnalyticsRule",
- "displayName": "NRT Creation of expensive computes in Azure",
+ "displayName": "NRT Microsoft Entra ID Hybrid Health AD FS New Server",
"contentProductId": "[variables('analyticRuleObject8')._analyticRulecontentProductId8]",
"id": "[variables('analyticRuleObject8')._analyticRulecontentProductId8]",
"version": "[variables('analyticRuleObject8').analyticRuleVersion8]"
- }
+ },
+ "condition": "[parameters('DeployAnalyticsRule')]"
},
{
"type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates",
@@ -2693,7 +2757,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
- "description": "New-CloudShell-User_AnalyticalRules Analytics Rule with template version 3.0.4",
+ "description": "NRT_Creation_of_Expensive_Computes_in_Azure_AnalyticalRules Analytics Rule with template version 3.1.2",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('analyticRuleObject9').analyticRuleVersion9]",
@@ -2704,61 +2768,66 @@
"type": "Microsoft.SecurityInsights/AlertRuleTemplates",
"name": "[variables('analyticRuleObject9')._analyticRulecontentId9]",
"apiVersion": "2023-02-01-preview",
- "kind": "Scheduled",
+ "kind": "NRT",
"location": "[parameters('workspace-location')]",
"properties": {
- "description": "Identifies when a user creates an Azure CloudShell for the first time.\nMonitor this activity to ensure only the expected users are using CloudShell.",
- "displayName": "New CloudShell User",
+ "description": "Identifies the creation of large size or expensive VMs (with GPUs or with a large number of virtual CPUs) in Azure.\nAn adversary may create new or update existing virtual machines to evade defenses or use them for cryptomining purposes.\nFor Windows/Linux Vm Sizes, see https://docs.microsoft.com/azure/virtual-machines/windows/sizes \nAzure VM Naming Conventions, see https://docs.microsoft.com/azure/virtual-machines/vm-naming-conventions",
+ "displayName": "NRT Creation of expensive computes in Azure",
"enabled": false,
- "query": "let match_window = 3m;\nAzureActivity\n| where ResourceGroup has \"cloud-shell\"\n| where (OperationNameValue =~ \"Microsoft.Storage/storageAccounts/listKeys/action\")\n| where ActivityStatusValue =~ \"Success\"\n| extend TimeKey = bin(TimeGenerated, match_window), AzureIP = CallerIpAddress\n| join kind = inner\n(AzureActivity\n| where ResourceGroup has \"cloud-shell\"\n| where (OperationNameValue =~ \"Microsoft.Storage/storageAccounts/write\")\n| extend TimeKey = bin(TimeGenerated, match_window), UserIP = CallerIpAddress\n) on Caller, TimeKey\n| summarize count() by TimeKey, Caller, ResourceGroup, SubscriptionId, TenantId, AzureIP, UserIP, HTTPRequest, Type, Properties, CategoryValue, OperationList = strcat(OperationNameValue, ' , ', OperationNameValue1)\n| extend Name = tostring(split(Caller,'@',0)[0]), UPNSuffix = tostring(split(Caller,'@',1)[0])\n",
- "queryFrequency": "P1D",
- "queryPeriod": "P1D",
- "severity": "Low",
+ "query": "let tokens = dynamic([\"416\",\"208\",\"192\",\"128\",\"120\",\"96\",\"80\",\"72\",\"64\",\"48\",\"44\",\"40\",\"nc12\",\"nc24\",\"nv24\"]);\nlet operationList = dynamic([\"microsoft.compute/virtualmachines/write\", \"microsoft.resources/deployments/write\"]);\nAzureActivity\n| where OperationNameValue in~ (operationList)\n| where ActivityStatusValue startswith \"Accept\"\n| where Properties has 'vmSize'\n| extend parsed_property= parse_json(tostring((parse_json(Properties).responseBody))).properties\n| extend vmSize = tostring((parsed_property.hardwareProfile).vmSize)\n| mv-apply token=tokens to typeof(string) on (where vmSize contains token)\n| extend ComputerName = tostring((parsed_property.osProfile).computerName)\n| project TimeGenerated, OperationNameValue, ActivityStatusValue, Caller, CallerIpAddress, ComputerName, vmSize\n| extend Name = tostring(split(Caller,'@',0)[0]), UPNSuffix = tostring(split(Caller,'@',1)[0])\n",
+ "severity": "Medium",
"suppressionDuration": "PT1H",
"suppressionEnabled": false,
- "triggerOperator": "GreaterThan",
- "triggerThreshold": 0,
"status": "Available",
"requiredDataConnectors": [
{
+ "connectorId": "AzureActivity",
"dataTypes": [
"AzureActivity"
- ],
- "connectorId": "AzureActivity"
+ ]
}
],
"tactics": [
- "Execution"
+ "DefenseEvasion"
],
"techniques": [
- "T1059"
+ "T1578"
],
"entityMappings": [
{
+ "entityType": "Account",
"fieldMappings": [
{
- "columnName": "Caller",
- "identifier": "FullName"
+ "identifier": "FullName",
+ "columnName": "Caller"
},
{
- "columnName": "Name",
- "identifier": "Name"
+ "identifier": "Name",
+ "columnName": "Name"
},
{
- "columnName": "UPNSuffix",
- "identifier": "UPNSuffix"
+ "identifier": "UPNSuffix",
+ "columnName": "UPNSuffix"
}
- ],
- "entityType": "Account"
+ ]
},
{
+ "entityType": "Host",
"fieldMappings": [
{
- "columnName": "UserIP",
- "identifier": "Address"
+ "identifier": "HostName",
+ "columnName": "ComputerName"
}
- ],
- "entityType": "IP"
+ ]
+ },
+ {
+ "entityType": "IP",
+ "fieldMappings": [
+ {
+ "identifier": "Address",
+ "columnName": "CallerIpAddress"
+ }
+ ]
}
]
}
@@ -2799,11 +2868,12 @@
"contentSchemaVersion": "3.0.0",
"contentId": "[variables('analyticRuleObject9')._analyticRulecontentId9]",
"contentKind": "AnalyticsRule",
- "displayName": "New CloudShell User",
+ "displayName": "NRT Creation of expensive computes in Azure",
"contentProductId": "[variables('analyticRuleObject9')._analyticRulecontentProductId9]",
"id": "[variables('analyticRuleObject9')._analyticRulecontentProductId9]",
"version": "[variables('analyticRuleObject9').analyticRuleVersion9]"
- }
+ },
+ "condition": "[parameters('DeployAnalyticsRule')]"
},
{
"type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates",
@@ -2814,7 +2884,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
- "description": "NewResourceGroupsDeployedTo_AnalyticalRules Analytics Rule with template version 3.0.4",
+ "description": "New-CloudShell-User_AnalyticalRules Analytics Rule with template version 3.1.2",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('analyticRuleObject10').analyticRuleVersion10]",
@@ -2828,12 +2898,12 @@
"kind": "Scheduled",
"location": "[parameters('workspace-location')]",
"properties": {
- "description": "Identifies when a rare Resource and ResourceGroup deployment occurs by a previously unseen caller.",
- "displayName": "Suspicious Resource deployment",
+ "description": "Identifies when a user creates an Azure CloudShell for the first time.\nMonitor this activity to ensure only the expected users are using CloudShell.",
+ "displayName": "New CloudShell User",
"enabled": false,
- "query": "// Add or remove operation names below as per your requirements. For operations lists, please refer to https://learn.microsoft.com/en-us/Azure/role-based-access-control/resource-provider-operations#all\nlet szOperationNames = dynamic([\"Microsoft.Compute/virtualMachines/write\", \"Microsoft.Resources/deployments/write\", \"Microsoft.Resources/subscriptions/resourceGroups/write\"]);\nlet starttime = 14d;\nlet endtime = 1d;\nlet RareCaller = AzureActivity\n| where TimeGenerated between (ago(starttime) .. ago(endtime))\n| where OperationNameValue in~ (szOperationNames)\n| summarize count() by CallerIpAddress, Caller, OperationNameValue, bin(TimeGenerated,1d)\n// Returns all the records from the right side that don't have matches from the left.\n| join kind=rightantisemi (\nAzureActivity\n| where TimeGenerated > ago(endtime)\n| where OperationNameValue in~ (szOperationNames)\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), ActivityTimeStamp = make_set(TimeGenerated,100), ActivityStatusValue = make_set(ActivityStatusValue,100), CorrelationIds = make_set(CorrelationId,100), ResourceGroups = make_set(ResourceGroup,100), ResourceIds = make_set(_ResourceId,100), ActivityCountByCallerIPAddress = count()\nby CallerIpAddress, Caller, OperationNameValue) on CallerIpAddress, Caller, OperationNameValue;\nRareCaller\n| extend Name = iif(Caller has '@',tostring(split(Caller,'@',0)[0]),\"\")\n| extend UPNSuffix = iif(Caller has '@',tostring(split(Caller,'@',1)[0]),\"\")\n| extend AadUserId = iif(Caller !has '@',Caller,\"\")\n",
+ "query": "let match_window = 3m;\nAzureActivity\n| where ResourceGroup has \"cloud-shell\"\n| where (OperationNameValue =~ \"Microsoft.Storage/storageAccounts/listKeys/action\")\n| where ActivityStatusValue =~ \"Success\"\n| extend TimeKey = bin(TimeGenerated, match_window), AzureIP = CallerIpAddress\n| join kind = inner\n(AzureActivity\n| where ResourceGroup has \"cloud-shell\"\n| where (OperationNameValue =~ \"Microsoft.Storage/storageAccounts/write\")\n| extend TimeKey = bin(TimeGenerated, match_window), UserIP = CallerIpAddress\n) on Caller, TimeKey\n| summarize count() by TimeKey, Caller, ResourceGroup, SubscriptionId, TenantId, AzureIP, UserIP, HTTPRequest, Type, Properties, CategoryValue, OperationList = strcat(OperationNameValue, ' , ', OperationNameValue1)\n| extend Name = tostring(split(Caller,'@',0)[0]), UPNSuffix = tostring(split(Caller,'@',1)[0])\n",
"queryFrequency": "P1D",
- "queryPeriod": "P14D",
+ "queryPeriod": "P1D",
"severity": "Low",
"suppressionDuration": "PT1H",
"suppressionEnabled": false,
@@ -2842,53 +2912,44 @@
"status": "Available",
"requiredDataConnectors": [
{
+ "connectorId": "AzureActivity",
"dataTypes": [
"AzureActivity"
- ],
- "connectorId": "AzureActivity"
+ ]
}
],
"tactics": [
- "Impact"
+ "Execution"
],
"techniques": [
- "T1496"
+ "T1059"
],
"entityMappings": [
{
+ "entityType": "Account",
"fieldMappings": [
{
- "columnName": "Caller",
- "identifier": "FullName"
+ "identifier": "FullName",
+ "columnName": "Caller"
},
{
- "columnName": "Name",
- "identifier": "Name"
+ "identifier": "Name",
+ "columnName": "Name"
},
{
- "columnName": "UPNSuffix",
- "identifier": "UPNSuffix"
- }
- ],
- "entityType": "Account"
- },
- {
- "fieldMappings": [
- {
- "columnName": "AadUserId",
- "identifier": "AadUserId"
+ "identifier": "UPNSuffix",
+ "columnName": "UPNSuffix"
}
- ],
- "entityType": "Account"
+ ]
},
{
+ "entityType": "IP",
"fieldMappings": [
{
- "columnName": "CallerIpAddress",
- "identifier": "Address"
+ "identifier": "Address",
+ "columnName": "UserIP"
}
- ],
- "entityType": "IP"
+ ]
}
]
}
@@ -2929,11 +2990,12 @@
"contentSchemaVersion": "3.0.0",
"contentId": "[variables('analyticRuleObject10')._analyticRulecontentId10]",
"contentKind": "AnalyticsRule",
- "displayName": "Suspicious Resource deployment",
+ "displayName": "New CloudShell User",
"contentProductId": "[variables('analyticRuleObject10')._analyticRulecontentProductId10]",
"id": "[variables('analyticRuleObject10')._analyticRulecontentProductId10]",
"version": "[variables('analyticRuleObject10').analyticRuleVersion10]"
- }
+ },
+ "condition": "[parameters('DeployAnalyticsRule')]"
},
{
"type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates",
@@ -2944,7 +3006,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
- "description": "RareOperations_AnalyticalRules Analytics Rule with template version 3.0.4",
+ "description": "NewResourceGroupsDeployedTo_AnalyticalRules Analytics Rule with template version 3.1.2",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('analyticRuleObject11').analyticRuleVersion11]",
@@ -2958,10 +3020,10 @@
"kind": "Scheduled",
"location": "[parameters('workspace-location')]",
"properties": {
- "description": "This query looks for a few sensitive subscription-level events based on Azure Activity Logs. For example, this monitors for the operation name 'Create or Update Snapshot', which is used for creating backups but could be misused by attackers to dump hashes or extract sensitive information from the disk.",
- "displayName": "Rare subscription-level operations in Azure",
+ "description": "Identifies when a rare Resource and ResourceGroup deployment occurs by a previously unseen caller.",
+ "displayName": "Suspicious Resource deployment",
"enabled": false,
- "query": "let starttime = 14d;\nlet endtime = 1d;\n// The number of operations above which an IP address is considered an unusual source of role assignment operations\nlet alertOperationThreshold = 5;\n// Add or remove operation names below as per your requirements. For operations lists, please refer to https://learn.microsoft.com/en-us/Azure/role-based-access-control/resource-provider-operations#all\nlet SensitiveOperationList = dynamic([\"microsoft.compute/snapshots/write\", \"microsoft.network/networksecuritygroups/write\", \"microsoft.storage/storageaccounts/listkeys/action\"]);\nlet SensitiveActivity = AzureActivity\n| where OperationNameValue in~ (SensitiveOperationList) or OperationNameValue hassuffix \"listkeys/action\"\n| where ActivityStatusValue =~ \"Success\";\nSensitiveActivity\n| where TimeGenerated between (ago(starttime) .. ago(endtime))\n| summarize count() by CallerIpAddress, Caller, OperationNameValue, bin(TimeGenerated,1d)\n| where count_ >= alertOperationThreshold\n// Returns all the records from the right side that don't have matches from the left\n| join kind = rightanti (\nSensitiveActivity\n| where TimeGenerated >= ago(endtime)\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), ActivityTimeStamp = make_list(TimeGenerated), ActivityStatusValue = make_list(ActivityStatusValue), CorrelationIds = make_list(CorrelationId), ResourceGroups = make_list(ResourceGroup), ResourceIds = make_list(_ResourceId), ActivityCountByCallerIPAddress = count()\nby CallerIpAddress, Caller, OperationNameValue\n| where ActivityCountByCallerIPAddress >= alertOperationThreshold\n) on CallerIpAddress, Caller, OperationNameValue\n| extend Name = tostring(split(Caller,'@',0)[0]), UPNSuffix = tostring(split(Caller,'@',1)[0])\n",
+ "query": "// Add or remove operation names below as per your requirements. For operations lists, please refer to https://learn.microsoft.com/en-us/Azure/role-based-access-control/resource-provider-operations#all\nlet szOperationNames = dynamic([\"Microsoft.Compute/virtualMachines/write\", \"Microsoft.Resources/deployments/write\", \"Microsoft.Resources/subscriptions/resourceGroups/write\"]);\nlet starttime = 14d;\nlet endtime = 1d;\nlet RareCaller = AzureActivity\n| where TimeGenerated between (ago(starttime) .. ago(endtime))\n| where OperationNameValue in~ (szOperationNames)\n| summarize count() by CallerIpAddress, Caller, OperationNameValue, bin(TimeGenerated,1d)\n// Returns all the records from the right side that don't have matches from the left.\n| join kind=rightantisemi (\nAzureActivity\n| where TimeGenerated > ago(endtime)\n| where OperationNameValue in~ (szOperationNames)\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), ActivityTimeStamp = make_set(TimeGenerated,100), ActivityStatusValue = make_set(ActivityStatusValue,100), CorrelationIds = make_set(CorrelationId,100), ResourceGroups = make_set(ResourceGroup,100), ResourceIds = make_set(_ResourceId,100), ActivityCountByCallerIPAddress = count()\nby CallerIpAddress, Caller, OperationNameValue) on CallerIpAddress, Caller, OperationNameValue;\nRareCaller\n| extend Name = iif(Caller has '@',tostring(split(Caller,'@',0)[0]),\"\")\n| extend UPNSuffix = iif(Caller has '@',tostring(split(Caller,'@',1)[0]),\"\")\n| extend AadUserId = iif(Caller !has '@',Caller,\"\")\n",
"queryFrequency": "P1D",
"queryPeriod": "P14D",
"severity": "Low",
@@ -2972,46 +3034,53 @@
"status": "Available",
"requiredDataConnectors": [
{
+ "connectorId": "AzureActivity",
"dataTypes": [
"AzureActivity"
- ],
- "connectorId": "AzureActivity"
+ ]
}
],
"tactics": [
- "CredentialAccess",
- "Persistence"
+ "Impact"
],
"techniques": [
- "T1003",
- "T1098"
+ "T1496"
],
"entityMappings": [
{
+ "entityType": "Account",
"fieldMappings": [
{
- "columnName": "Caller",
- "identifier": "FullName"
+ "identifier": "FullName",
+ "columnName": "Caller"
},
{
- "columnName": "Name",
- "identifier": "Name"
+ "identifier": "Name",
+ "columnName": "Name"
},
{
- "columnName": "UPNSuffix",
- "identifier": "UPNSuffix"
+ "identifier": "UPNSuffix",
+ "columnName": "UPNSuffix"
}
- ],
- "entityType": "Account"
+ ]
},
{
+ "entityType": "Account",
"fieldMappings": [
{
- "columnName": "CallerIpAddress",
- "identifier": "Address"
+ "identifier": "AadUserId",
+ "columnName": "AadUserId"
}
- ],
- "entityType": "IP"
+ ]
+ },
+ {
+ "entityType": "IP",
+ "fieldMappings": [
+ {
+ "identifier": "Address",
+ "columnName": "CallerIpAddress"
+ }
+ ]
}
]
}
@@ -3052,11 +3121,12 @@
"contentSchemaVersion": "3.0.0",
"contentId": "[variables('analyticRuleObject11')._analyticRulecontentId11]",
"contentKind": "AnalyticsRule",
- "displayName": "Rare subscription-level operations in Azure",
+ "displayName": "Suspicious Resource deployment",
"contentProductId": "[variables('analyticRuleObject11')._analyticRulecontentProductId11]",
"id": "[variables('analyticRuleObject11')._analyticRulecontentProductId11]",
"version": "[variables('analyticRuleObject11').analyticRuleVersion11]"
- }
+ },
+ "condition": "[parameters('DeployAnalyticsRule')]"
},
{
"type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates",
@@ -3067,7 +3137,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
- "description": "TimeSeriesAnomaly_Mass_Cloud_Resource_Deletions_AnalyticalRules Analytics Rule with template version 3.0.4",
+ "description": "RareOperations_AnalyticalRules Analytics Rule with template version 3.1.2",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('analyticRuleObject12').analyticRuleVersion12]",
@@ -3081,13 +3151,13 @@
"kind": "Scheduled",
"location": "[parameters('workspace-location')]",
"properties": {
- "description": "This query generates the baseline pattern of cloud resource deletions by an individual and generates an anomaly when any unusual spike is detected. These anomalies from unusual or privileged users could be an indication of a cloud infrastructure takedown by an adversary.",
- "displayName": "Mass Cloud resource deletions Time Series Anomaly",
+ "description": "This query looks for a few sensitive subscription-level events based on Azure Activity Logs. For example, this monitors for the operation name 'Create or Update Snapshot', which is used for creating backups but could be misused by attackers to dump hashes or extract sensitive information from the disk.",
+ "displayName": "Rare subscription-level operations in Azure",
"enabled": false,
- "query": "let starttime = 14d;\nlet endtime = 1d;\nlet timeframe = 1d;\nlet TotalEventsThreshold = 25;\nlet TimeSeriesData = AzureActivity \n| where TimeGenerated between (startofday(ago(starttime))..startofday(now())) \n| where OperationNameValue endswith \"delete\" \n| project TimeGenerated, Caller \n| make-series Total = count() on TimeGenerated from startofday(ago(starttime)) to startofday(now()) step timeframe by Caller;\nTimeSeriesData \n| extend (anomalies, score, baseline) = series_decompose_anomalies(Total, 3, -1, 'linefit') \n| mv-expand Total to typeof(double), TimeGenerated to typeof(datetime), anomalies to typeof(double), score to typeof(double), baseline to typeof(long) \n| where TimeGenerated >= startofday(ago(endtime)) \n| where anomalies > 0 \n| project Caller, TimeGenerated, Total, baseline, anomalies, score \n| where Total > TotalEventsThreshold and baseline > 0 \n| join (AzureActivity \n| where TimeGenerated > startofday(ago(endtime)) \n| where OperationNameValue endswith \"delete\" \n| summarize count(), make_set(OperationNameValue,100), make_set(_ResourceId,100) by bin(TimeGenerated, timeframe), Caller ) on TimeGenerated, Caller \n| extend Name = iif(Caller has '@',tostring(split(Caller,'@',0)[0]),\"\")\n| extend UPNSuffix = iif(Caller has '@',tostring(split(Caller,'@',1)[0]),\"\")\n| extend AadUserId = iif(Caller !has '@',Caller,\"\")\n",
+ "query": "let starttime = 14d;\nlet endtime = 1d;\n// The number of operations above which an IP address is considered an unusual source of role assignment operations\nlet alertOperationThreshold = 5;\n// Add or remove operation names below as per your requirements. For operations lists, please refer to https://learn.microsoft.com/en-us/Azure/role-based-access-control/resource-provider-operations#all\nlet SensitiveOperationList = dynamic([\"microsoft.compute/snapshots/write\", \"microsoft.network/networksecuritygroups/write\", \"microsoft.storage/storageaccounts/listkeys/action\"]);\nlet SensitiveActivity = AzureActivity\n| where OperationNameValue in~ (SensitiveOperationList) or OperationNameValue hassuffix \"listkeys/action\"\n| where ActivityStatusValue =~ \"Success\";\nSensitiveActivity\n| where TimeGenerated between (ago(starttime) .. ago(endtime))\n| summarize count() by CallerIpAddress, Caller, OperationNameValue, bin(TimeGenerated,1d)\n| where count_ >= alertOperationThreshold\n// Returns all the records from the right side that don't have matches from the left\n| join kind = rightanti (\nSensitiveActivity\n| where TimeGenerated >= ago(endtime)\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), ActivityTimeStamp = make_list(TimeGenerated), ActivityStatusValue = make_list(ActivityStatusValue), CorrelationIds = make_list(CorrelationId), ResourceGroups = make_list(ResourceGroup), ResourceIds = make_list(_ResourceId), ActivityCountByCallerIPAddress = count()\nby CallerIpAddress, Caller, OperationNameValue\n| where ActivityCountByCallerIPAddress >= alertOperationThreshold\n) on CallerIpAddress, Caller, OperationNameValue\n| extend Name = tostring(split(Caller,'@',0)[0]), UPNSuffix = tostring(split(Caller,'@',1)[0])\n",
"queryFrequency": "P1D",
"queryPeriod": "P14D",
- "severity": "Medium",
+ "severity": "Low",
"suppressionDuration": "PT1H",
"suppressionEnabled": false,
"triggerOperator": "GreaterThan",
@@ -3095,44 +3165,46 @@
"status": "Available",
"requiredDataConnectors": [
{
+ "connectorId": "AzureActivity",
"dataTypes": [
"AzureActivity"
- ],
- "connectorId": "AzureActivity"
+ ]
}
],
"tactics": [
- "Impact"
+ "CredentialAccess",
+ "Persistence"
],
"techniques": [
- "T1485"
+ "T1003",
+ "T1098"
],
"entityMappings": [
{
+ "entityType": "Account",
"fieldMappings": [
{
- "columnName": "Caller",
- "identifier": "FullName"
+ "identifier": "FullName",
+ "columnName": "Caller"
},
{
- "columnName": "Name",
- "identifier": "Name"
+ "identifier": "Name",
+ "columnName": "Name"
},
{
- "columnName": "UPNSuffix",
- "identifier": "UPNSuffix"
+ "identifier": "UPNSuffix",
+ "columnName": "UPNSuffix"
}
- ],
- "entityType": "Account"
+ ]
},
{
+ "entityType": "IP",
"fieldMappings": [
{
- "columnName": "AadUserId",
- "identifier": "AadUserId"
+ "identifier": "Address",
+ "columnName": "CallerIpAddress"
}
- ],
- "entityType": "Account"
+ ]
}
]
}
@@ -3173,11 +3245,12 @@
"contentSchemaVersion": "3.0.0",
"contentId": "[variables('analyticRuleObject12')._analyticRulecontentId12]",
"contentKind": "AnalyticsRule",
- "displayName": "Mass Cloud resource deletions Time Series Anomaly",
+ "displayName": "Rare subscription-level operations in Azure",
"contentProductId": "[variables('analyticRuleObject12')._analyticRulecontentProductId12]",
"id": "[variables('analyticRuleObject12')._analyticRulecontentProductId12]",
"version": "[variables('analyticRuleObject12').analyticRuleVersion12]"
- }
+ },
+ "condition": "[parameters('DeployAnalyticsRule')]"
},
{
"type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates",
@@ -3188,7 +3261,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
- "description": "SubscriptionMigration_AnalyticalRules Analytics Rule with template version 3.0.4",
+ "description": "SubscriptionMigration_AnalyticalRules Analytics Rule with template version 3.1.2",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('analyticRuleObject13').analyticRuleVersion13]",
@@ -3216,10 +3289,10 @@
"status": "Available",
"requiredDataConnectors": [
{
+ "connectorId": "AzureActivity",
"dataTypes": [
"AzureActivity"
- ],
- "connectorId": "AzureActivity"
+ ]
}
],
"tactics": [
@@ -3230,30 +3303,30 @@
],
"entityMappings": [
{
+ "entityType": "AzureResource",
"fieldMappings": [
{
- "columnName": "_ResourceId",
- "identifier": "ResourceId"
+ "identifier": "ResourceId",
+ "columnName": "_ResourceId"
}
- ],
- "entityType": "AzureResource"
+ ]
},
{
+ "entityType": "Account",
"fieldMappings": [
{
- "columnName": "Caller",
- "identifier": "FullName"
+ "identifier": "FullName",
+ "columnName": "Caller"
},
{
- "columnName": "Name",
- "identifier": "Name"
+ "identifier": "Name",
+ "columnName": "Name"
},
{
- "columnName": "UPNSuffix",
- "identifier": "UPNSuffix"
+ "identifier": "UPNSuffix",
+ "columnName": "UPNSuffix"
}
- ],
- "entityType": "Account"
+ ]
}
],
"eventGroupingSettings": {
@@ -3264,8 +3337,8 @@
"DestinationTenantId": "DestinationTenantId"
},
"alertDetailsOverride": {
- "alertDisplayNameFormat": "Subscription {{SubscriptionId}} changed tenants\n",
- "alertDescriptionFormat": "The user {{Caller}} moved a subscription:\n\n{{Summary}}\n\nIf this was not expected, it may indicate a subscription hijacking event.\n"
+ "alertDescriptionFormat": "The user {{Caller}} moved a subscription:\n\n{{Summary}}\n\nIf this was not expected, it may indicate a subscription hijacking event.\n",
+ "alertDisplayNameFormat": "Subscription {{SubscriptionId}} changed tenants\n"
}
}
},
@@ -3309,7 +3382,8 @@
"contentProductId": "[variables('analyticRuleObject13')._analyticRulecontentProductId13]",
"id": "[variables('analyticRuleObject13')._analyticRulecontentProductId13]",
"version": "[variables('analyticRuleObject13').analyticRuleVersion13]"
- }
+ },
+ "condition": "[parameters('DeployAnalyticsRule')]"
},
{
"type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates",
@@ -3320,7 +3394,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
- "description": "Machine_Learning_Creation_AnalyticalRules Analytics Rule with template version 3.0.4",
+ "description": "TimeSeriesAnomaly_Mass_Cloud_Resource_Deletions_AnalyticalRules Analytics Rule with template version 3.1.2",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('analyticRuleObject14').analyticRuleVersion14]",
@@ -3334,13 +3408,13 @@
"kind": "Scheduled",
"location": "[parameters('workspace-location')]",
"properties": {
- "description": "Shows the most prevalent users who perform write operations on Azure Machine Learning resources. List the common source IP address for each of those accounts. If an operation is not from those IP addresses, it may be worthy of investigation.",
- "displayName": "Azure Machine Learning Write Operations",
+ "description": "This query generates the baseline pattern of cloud resource deletions by an individual and generates an anomaly when any unusual spike is detected. These anomalies from unusual or privileged users could be an indication of a cloud infrastructure takedown by an adversary.",
+ "displayName": "Mass Cloud resource deletions Time Series Anomaly",
"enabled": false,
- "query": "AzureActivity\n| where ResourceProviderValue == \"MICROSOFT.MACHINELEARNINGSERVICES\" // Filter activities related to Microsoft Machine Learning Services\n| extend SCOPE = tostring(parse_json(Authorization).scope) // Parse Authorization scope as string\n| extend subname = split(Hierarchy, \"/\") // Split Hierarchy to extract Subscription Name and ID\n| extend ['Subscription Name'] = subname[-2], ['Subscription ID'] = subname[-1] // Extract Subscription Name and ID\n| extend Properties = parse_json(Properties) // Parse Properties as JSON\n| extend Properties_entity = tostring(Properties.entity) // Cast Properties.entity to string\n| where isnotempty(Properties_entity) // Filter activities where Properties.entity is not empty\n// | where Properties_entity contains \"deepseek\" // Filter activities where Properties.entity contains \"deepseek\"\n| where OperationNameValue contains \"write\" // Filter activities where OperationNameValue contains \"write\"\n| where OperationNameValue !contains \"MICROSOFT.AUTHORIZATION/ROLEASSIGNMENTS/WRITE\" // Exclude role assignments\n| extend LLM = tostring(split(Properties_entity, \"/\")[-1]) // Extract the last segment of Properties_entity and cast it to string\n| distinct TimeGenerated, tostring(['Subscription Name']), ResourceGroup, tostring(['Subscription ID']), Caller, CallerIpAddress, OperationNameValue, LLM, _ResourceId // Select distinct relevant fields for output\n",
+ "query": "let starttime = 14d;\nlet endtime = 1d;\nlet timeframe = 1d;\nlet TotalEventsThreshold = 25;\nlet TimeSeriesData = AzureActivity \n| where TimeGenerated between (startofday(ago(starttime))..startofday(now())) \n| where OperationNameValue endswith \"delete\" \n| project TimeGenerated, Caller \n| make-series Total = count() on TimeGenerated from startofday(ago(starttime)) to startofday(now()) step timeframe by Caller;\nTimeSeriesData \n| extend (anomalies, score, baseline) = series_decompose_anomalies(Total, 3, -1, 'linefit') \n| mv-expand Total to typeof(double), TimeGenerated to typeof(datetime), anomalies to typeof(double), score to typeof(double), baseline to typeof(long) \n| where TimeGenerated >= startofday(ago(endtime)) \n| where anomalies > 0 \n| project Caller, TimeGenerated, Total, baseline, anomalies, score \n| where Total > TotalEventsThreshold and baseline > 0 \n| join (AzureActivity \n| where TimeGenerated > startofday(ago(endtime)) \n| where OperationNameValue endswith \"delete\" \n| summarize count(), make_set(OperationNameValue,100), make_set(_ResourceId,100) by bin(TimeGenerated, timeframe), Caller ) on TimeGenerated, Caller \n| extend Name = iif(Caller has '@',tostring(split(Caller,'@',0)[0]),\"\")\n| extend UPNSuffix = iif(Caller has '@',tostring(split(Caller,'@',1)[0]),\"\")\n| extend AadUserId = iif(Caller !has '@',Caller,\"\")\n",
"queryFrequency": "P1D",
- "queryPeriod": "P1D",
- "severity": "Low",
+ "queryPeriod": "P14D",
+ "severity": "Medium",
"suppressionDuration": "PT1H",
"suppressionEnabled": false,
"triggerOperator": "GreaterThan",
@@ -3348,54 +3422,46 @@
"status": "Available",
"requiredDataConnectors": [
{
+ "connectorId": "AzureActivity",
"dataTypes": [
"AzureActivity"
- ],
- "connectorId": "AzureActivity"
+ ]
}
],
"tactics": [
- "InitialAccess",
- "Execution",
"Impact"
],
"techniques": [
- "T1078",
- "T1059",
- "T1496"
+ "T1485"
],
"entityMappings": [
{
+ "entityType": "Account",
"fieldMappings": [
{
- "columnName": "Caller",
- "identifier": "Name"
- }
- ],
- "entityType": "Account"
- },
- {
- "fieldMappings": [
+ "identifier": "FullName",
+ "columnName": "Caller"
+ },
{
- "columnName": "CallerIpAddress",
- "identifier": "Address"
+ "identifier": "Name",
+ "columnName": "Name"
+ },
+ {
+ "identifier": "UPNSuffix",
+ "columnName": "UPNSuffix"
}
- ],
- "entityType": "IP"
+ ]
},
{
+ "entityType": "Account",
"fieldMappings": [
{
- "columnName": "_ResourceId",
- "identifier": "ResourceId"
+ "identifier": "AadUserId",
+ "columnName": "AadUserId"
}
- ],
- "entityType": "AzureResource"
+ ]
}
- ],
- "eventGroupingSettings": {
- "aggregationKind": "SingleAlert"
- }
+ ]
}
},
{
@@ -3434,11 +3500,12 @@
"contentSchemaVersion": "3.0.0",
"contentId": "[variables('analyticRuleObject14')._analyticRulecontentId14]",
"contentKind": "AnalyticsRule",
- "displayName": "Azure Machine Learning Write Operations",
+ "displayName": "Mass Cloud resource deletions Time Series Anomaly",
"contentProductId": "[variables('analyticRuleObject14')._analyticRulecontentProductId14]",
"id": "[variables('analyticRuleObject14')._analyticRulecontentProductId14]",
"version": "[variables('analyticRuleObject14').analyticRuleVersion14]"
- }
+ },
+ "condition": "[parameters('DeployAnalyticsRule')]"
},
{
"type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates",
@@ -3449,7 +3516,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
- "description": "AzureActivity Workbook with template version 3.0.4",
+ "description": "AzureActivity Workbook with template version 3.1.2",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('workbookVersion1')]",
@@ -3467,7 +3534,7 @@
},
"properties": {
"displayName": "[parameters('workbook1-name')]",
- "serializedData": "{\"version\":\"Notebook/1.0\",\"items\":[{\"type\":9,\"content\":{\"version\":\"KqlParameterItem/1.0\",\"query\":\"\",\"parameters\":[{\"id\":\"52bfbd84-1639-480c-bda5-bfc87fd81832\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"TimeRange\",\"type\":4,\"isRequired\":true,\"value\":{\"durationMs\":604800000},\"typeSettings\":{\"selectableValues\":[{\"durationMs\":300000},{\"durationMs\":900000},{\"durationMs\":1800000},{\"durationMs\":3600000},{\"durationMs\":14400000},{\"durationMs\":43200000},{\"durationMs\":86400000},{\"durationMs\":172800000},{\"durationMs\":259200000},{\"durationMs\":604800000},{\"durationMs\":1209600000},{\"durationMs\":2419200000},{\"durationMs\":2592000000},{\"durationMs\":5184000000},{\"durationMs\":7776000000}]}},{\"id\":\"eeb5dcf9-e898-46af-9c12-d91d97e13cd3\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"Caller\",\"type\":2,\"isRequired\":true,\"multiSelect\":true,\"quote\":\"'\",\"delimiter\":\",\",\"query\":\"AzureActivity\\r\\n| summarize by Caller\",\"value\":[\"value::all\"],\"typeSettings\":{\"additionalResourceOptions\":[\"value::all\"],\"selectAllValue\":\"All\"},\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},{\"id\":\"46375a76-7ae1-4d7e-9082-4191531198a9\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"ResourceGroup\",\"type\":2,\"isRequired\":true,\"multiSelect\":true,\"quote\":\"'\",\"delimiter\":\",\",\"query\":\"AzureActivity\\r\\n| summarize by ResourceGroup\",\"value\":[\"value::all\"],\"typeSettings\":{\"resourceTypeFilter\":{\"microsoft.resources/resourcegroups\":true},\"additionalResourceOptions\":[\"value::all\"],\"selectAllValue\":\"All\"},\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"}],\"style\":\"pills\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},\"name\":\"parameters - 2\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let data = AzureActivity\\r\\n| where \\\"{Caller:lable}\\\" == \\\"All\\\" or \\\"{Caller:lable}\\\" == \\\"All\\\" or Caller in ({Caller})\\r\\n| where \\\"{ResourceGroup:lable}\\\" == \\\"All\\\" or \\\"{ResourceGroup:lable}\\\" == \\\"All\\\" or ResourceGroup in ({ResourceGroup});\\r\\ndata\\r\\n| summarize Count = count() by ResourceGroup\\r\\n| join kind = fullouter (datatable(ResourceGroup:string)['Medium', 'high', 'low']) on ResourceGroup\\r\\n| project ResourceGroup = iff(ResourceGroup == '', ResourceGroup1, ResourceGroup), Count = iff(ResourceGroup == '', 0, Count)\\r\\n| join kind = inner (data\\r\\n | make-series Trend = count() default = 0 on TimeGenerated from {TimeRange:start} to {TimeRange:end} step {TimeRange:grain} by ResourceGroup)\\r\\n on ResourceGroup\\r\\n| project-away ResourceGroup1, TimeGenerated\\r\\n| extend ResourceGroups = ResourceGroup\\r\\n| union (\\r\\n data \\r\\n | summarize Count = count() \\r\\n | extend jkey = 1\\r\\n | join kind=inner (data\\r\\n | make-series Trend = count() default = 0 on TimeGenerated from {TimeRange:start} to {TimeRange:end} step {TimeRange:grain}\\r\\n | extend jkey = 1) on jkey\\r\\n | extend ResourceGroup = 'All', ResourceGroups = '*' \\r\\n)\\r\\n| order by Count desc\\r\\n| take 10\",\"size\":4,\"exportToExcelOptions\":\"visible\",\"title\":\"Top 10 active resource groups\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"tiles\",\"tileSettings\":{\"titleContent\":{\"columnMatch\":\"ResourceGroup\",\"formatter\":1,\"formatOptions\":{\"showIcon\":true}},\"leftContent\":{\"columnMatch\":\"Count\",\"formatter\":12,\"formatOptions\":{\"palette\":\"auto\",\"showIcon\":true},\"numberFormat\":{\"unit\":17,\"options\":{\"maximumSignificantDigits\":3,\"maximumFractionDigits\":2}}},\"secondaryContent\":{\"columnMatch\":\"Trend\",\"formatter\":9,\"formatOptions\":{\"palette\":\"blueOrange\",\"showIcon\":true}},\"showBorder\":false}},\"name\":\"query - 3\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"AzureActivity\\r\\n| where \\\"{Caller:lable}\\\" == \\\"All\\\" or Caller in ({Caller})\\r\\n| where \\\"{ResourceGroup:lable}\\\" == \\\"All\\\" or ResourceGroup in ({ResourceGroup})\\r\\n| summarize deletions = countif(OperationNameValue hassuffix \\\"delete\\\"), creations = countif(OperationNameValue hassuffix \\\"write\\\"), updates = countif(OperationNameValue hassuffix \\\"write\\\"), Activities = count(OperationNameValue) by bin_at(TimeGenerated, 1h, now())\\r\\n\",\"size\":0,\"exportToExcelOptions\":\"visible\",\"title\":\"Activities over time\",\"color\":\"gray\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"linechart\",\"graphSettings\":{\"type\":0}},\"name\":\"query - 1\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"AzureActivity\\r\\n| where \\\"{Caller:lable}\\\" == \\\"All\\\" or Caller in ({Caller})\\r\\n| where \\\"{ResourceGroup:lable}\\\" == \\\"All\\\" or ResourceGroup in ({ResourceGroup})\\r\\n| summarize deletions = countif(OperationNameValue hassuffix \\\"Delete\\\"), creations = countif(OperationNameValue hassuffix \\\"write\\\"), updates = countif(OperationNameValue hassuffix \\\"write\\\"), Activities = count() by Caller\\r\\n\",\"size\":1,\"exportToExcelOptions\":\"visible\",\"title\":\"Caller activities\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"Caller\",\"formatter\":0,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"deletions\",\"formatter\":4,\"formatOptions\":{\"showIcon\":true,\"aggregation\":\"Count\"}},{\"columnMatch\":\"creations\",\"formatter\":4,\"formatOptions\":{\"palette\":\"purple\",\"showIcon\":true,\"aggregation\":\"Count\"}},{\"columnMatch\":\"updates\",\"formatter\":4,\"formatOptions\":{\"palette\":\"gray\",\"showIcon\":true,\"aggregation\":\"Count\"}},{\"columnMatch\":\"Activities\",\"formatter\":4,\"formatOptions\":{\"palette\":\"greenDark\",\"linkTarget\":\"GenericDetails\",\"linkIsContextBlade\":true,\"showIcon\":true,\"aggregation\":\"Count\",\"workbookContext\":{\"componentIdSource\":\"workbook\",\"resourceIdsSource\":\"workbook\",\"templateIdSource\":\"static\",\"templateId\":\"https://go.microsoft.com/fwlink/?linkid=874159&resourceId=%2Fsubscriptions%2F44e4eff8-1fcb-4a22-a7d6-992ac7286382%2FresourceGroups%2FSOC&featureName=Workbooks&itemId=%2Fsubscriptions%2F44e4eff8-1fcb-4a22-a7d6-992ac7286382%2Fresourcegroups%2Fsoc%2Fproviders%2Fmicrosoft.insights%2Fworkbooks%2F4c195aec-747f-40bb-addb-934acb3ec646&name=CiscoASA&func=NavigateToPortalFeature&type=workbook\",\"typeSource\":\"workbook\",\"gallerySource\":\"workbook\"}}}],\"sortBy\":[{\"itemKey\":\"$gen_bar_updates_3\",\"sortOrder\":2}]}},\"name\":\"query - 1\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"AzureActivity \\r\\n| where \\\"{Caller:lable}\\\" == \\\"All\\\" or Caller in ({Caller})\\r\\n| where \\\"{ResourceGroup:lable}\\\" == \\\"All\\\" or ResourceGroup in ({ResourceGroup})\\r\\n| summarize Informational = countif(Level == \\\"Informational\\\"), Warning = countif(Level == \\\"Warning\\\"), Error = countif(Level == \\\"Error\\\") by bin_at(TimeGenerated, 1h, now())\\r\\n\",\"size\":0,\"exportToExcelOptions\":\"visible\",\"title\":\"Activities by log level over time\",\"color\":\"redBright\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"scatterchart\",\"tileSettings\":{\"showBorder\":false},\"graphSettings\":{\"type\":2,\"topContent\":{\"columnMatch\":\"Error\",\"formatter\":12,\"formatOptions\":{\"showIcon\":true}},\"hivesContent\":{\"columnMatch\":\"TimeGenerated\",\"formatter\":1,\"formatOptions\":{\"showIcon\":true}},\"nodeIdField\":\"Error\",\"sourceIdField\":\"Error\",\"targetIdField\":\"Error\",\"staticNodeSize\":100,\"groupByField\":\"TimeGenerated\",\"hivesMargin\":5}},\"name\":\"query - 4\"}],\"fromTemplateId\":\"sentinel-AzureActivity\",\"$schema\":\"https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json\"}\r\n",
+ "serializedData": "{\"version\":\"Notebook/1.0\",\"items\":[{\"type\":9,\"content\":{\"version\":\"KqlParameterItem/1.0\",\"query\":\"\",\"parameters\":[{\"id\":\"52bfbd84-1639-480c-bda5-bfc87fd81832\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"TimeRange\",\"type\":4,\"isRequired\":true,\"value\":{\"durationMs\":604800000},\"typeSettings\":{\"selectableValues\":[{\"durationMs\":300000},{\"durationMs\":900000},{\"durationMs\":1800000},{\"durationMs\":3600000},{\"durationMs\":14400000},{\"durationMs\":43200000},{\"durationMs\":86400000},{\"durationMs\":172800000},{\"durationMs\":259200000},{\"durationMs\":604800000},{\"durationMs\":1209600000},{\"durationMs\":2419200000},{\"durationMs\":2592000000},{\"durationMs\":5184000000},{\"durationMs\":7776000000}]}},{\"id\":\"eeb5dcf9-e898-46af-9c12-d91d97e13cd3\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"Caller\",\"type\":2,\"isRequired\":true,\"multiSelect\":true,\"quote\":\"'\",\"delimiter\":\",\",\"query\":\"AzureActivity\\r\\n| summarize by Caller\",\"value\":[\"value::all\"],\"typeSettings\":{\"additionalResourceOptions\":[\"value::all\"],\"selectAllValue\":\"All\"},\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},{\"id\":\"46375a76-7ae1-4d7e-9082-4191531198a9\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"ResourceGroup\",\"type\":2,\"isRequired\":true,\"multiSelect\":true,\"quote\":\"'\",\"delimiter\":\",\",\"query\":\"AzureActivity\\r\\n| summarize by ResourceGroup\",\"value\":[\"value::all\"],\"typeSettings\":{\"resourceTypeFilter\":{\"microsoft.resources/resourcegroups\":true},\"additionalResourceOptions\":[\"value::all\"],\"selectAllValue\":\"All\"},\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"}],\"style\":\"pills\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},\"name\":\"parameters - 2\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let data = AzureActivity\\r\\n| where \\\"{Caller:lable}\\\" == \\\"All\\\" or \\\"{Caller:lable}\\\" == \\\"All\\\" or Caller in ({Caller})\\r\\n| where \\\"{ResourceGroup:lable}\\\" == \\\"All\\\" or \\\"{ResourceGroup:lable}\\\" == \\\"All\\\" or ResourceGroup in ({ResourceGroup});\\r\\ndata\\r\\n| summarize Count = count() by ResourceGroup\\r\\n| join kind = fullouter (datatable(ResourceGroup:string)['Medium', 'high', 'low']) on ResourceGroup\\r\\n| project ResourceGroup = iff(ResourceGroup == '', ResourceGroup1, ResourceGroup), Count = iff(ResourceGroup == '', 0, Count)\\r\\n| join kind = inner (data\\r\\n | make-series Trend = count() default = 0 on TimeGenerated from {TimeRange:start} to {TimeRange:end} step {TimeRange:grain} by ResourceGroup)\\r\\n on ResourceGroup\\r\\n| project-away ResourceGroup1, TimeGenerated\\r\\n| extend ResourceGroups = ResourceGroup\\r\\n| union (\\r\\n data \\r\\n | summarize Count = count() \\r\\n | extend jkey = 1\\r\\n | join kind=inner (data\\r\\n | make-series Trend = count() default = 0 on TimeGenerated from {TimeRange:start} to {TimeRange:end} step {TimeRange:grain}\\r\\n | extend jkey = 1) on jkey\\r\\n | extend ResourceGroup = 'All', ResourceGroups = '*' \\r\\n)\\r\\n| order by Count desc\\r\\n| take 10\",\"size\":4,\"exportToExcelOptions\":\"visible\",\"title\":\"Top 10 active resource groups\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"tiles\",\"tileSettings\":{\"titleContent\":{\"columnMatch\":\"ResourceGroup\",\"formatter\":1,\"formatOptions\":{\"showIcon\":true}},\"leftContent\":{\"columnMatch\":\"Count\",\"formatter\":12,\"formatOptions\":{\"palette\":\"auto\",\"showIcon\":true},\"numberFormat\":{\"unit\":17,\"options\":{\"maximumSignificantDigits\":3,\"maximumFractionDigits\":2}}},\"secondaryContent\":{\"columnMatch\":\"Trend\",\"formatter\":9,\"formatOptions\":{\"palette\":\"blueOrange\",\"showIcon\":true}},\"showBorder\":false}},\"name\":\"query - 3\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"AzureActivity\\r\\n| where \\\"{Caller:lable}\\\" == \\\"All\\\" or Caller in ({Caller})\\r\\n| where \\\"{ResourceGroup:lable}\\\" == \\\"All\\\" or ResourceGroup in ({ResourceGroup})\\r\\n| summarize deletions = countif(OperationNameValue hassuffix \\\"delete\\\"), creations = countif(OperationNameValue hassuffix \\\"write\\\"), updates = countif(OperationNameValue hassuffix \\\"write\\\"), Activities = count(OperationNameValue) by bin_at(TimeGenerated, 1h, now())\\r\\n\",\"size\":0,\"exportToExcelOptions\":\"visible\",\"title\":\"Activities over time\",\"color\":\"gray\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"linechart\",\"graphSettings\":{\"type\":0}},\"name\":\"query - 1\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"AzureActivity\\r\\n| where \\\"{Caller:lable}\\\" == \\\"All\\\" or Caller in ({Caller})\\r\\n| where \\\"{ResourceGroup:lable}\\\" == \\\"All\\\" or ResourceGroup in ({ResourceGroup})\\r\\n| summarize deletions = countif(OperationNameValue hassuffix \\\"Delete\\\"), creations = countif(OperationNameValue hassuffix \\\"write\\\"), updates = countif(OperationNameValue hassuffix \\\"write\\\"), Activities = count() by Caller\\r\\n\",\"size\":1,\"exportToExcelOptions\":\"visible\",\"title\":\"Caller activities\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"Caller\",\"formatter\":0,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"deletions\",\"formatter\":4,\"formatOptions\":{\"showIcon\":true,\"aggregation\":\"Count\"}},{\"columnMatch\":\"creations\",\"formatter\":4,\"formatOptions\":{\"palette\":\"purple\",\"showIcon\":true,\"aggregation\":\"Count\"}},{\"columnMatch\":\"updates\",\"formatter\":4,\"formatOptions\":{\"palette\":\"gray\",\"showIcon\":true,\"aggregation\":\"Count\"}},{\"columnMatch\":\"Activities\",\"formatter\":4,\"formatOptions\":{\"palette\":\"greenDark\",\"linkTarget\":\"GenericDetails\",\"linkIsContextBlade\":true,\"showIcon\":true,\"aggregation\":\"Count\",\"workbookContext\":{\"componentIdSource\":\"workbook\",\"resourceIdsSource\":\"workbook\",\"templateIdSource\":\"static\",\"templateId\":\"https://go.microsoft.com/fwlink/?linkid=874159&resourceId=%2Fsubscriptions%2F44e4eff8-1fcb-4a22-a7d6-992ac7286382%2FresourceGroups%2FSOC&featureName=Workbooks&itemId=%2Fsubscriptions%2F44e4eff8-1fcb-4a22-a7d6-992ac7286382%2Fresourcegroups%2Fsoc%2Fproviders%2Fmicrosoft.insights%2Fworkbooks%2F4c195aec-747f-40bb-addb-934acb3ec646&name=CiscoASA&func=NavigateToPortalFeature&type=workbook\",\"typeSource\":\"workbook\",\"gallerySource\":\"workbook\"}}}],\"sortBy\":[{\"itemKey\":\"$gen_bar_updates_3\",\"sortOrder\":2}]}},\"name\":\"query - 1\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"AzureActivity \\r\\n| where \\\"{Caller:lable}\\\" == \\\"All\\\" or Caller in ({Caller})\\r\\n| where \\\"{ResourceGroup:lable}\\\" == \\\"All\\\" or ResourceGroup in ({ResourceGroup})\\r\\n| summarize Informational = countif(Level == \\\"Informational\\\"), Warning = countif(Level == \\\"Warning\\\"), Error = countif(Level == \\\"Error\\\") by bin_at(TimeGenerated, 1h, now())\\r\\n\",\"size\":0,\"exportToExcelOptions\":\"visible\",\"title\":\"Activities by log level over time\",\"color\":\"redBright\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"scatterchart\",\"tileSettings\":{\"showBorder\":false},\"graphSettings\":{\"type\":2,\"topContent\":{\"columnMatch\":\"Error\",\"formatter\":12,\"formatOptions\":{\"showIcon\":true}},\"hivesContent\":{\"columnMatch\":\"TimeGenerated\",\"formatter\":1,\"formatOptions\":{\"showIcon\":true}},\"nodeIdField\":\"Error\",\"sourceIdField\":\"Error\",\"targetIdField\":\"Error\",\"staticNodeSize\":100,\"groupByField\":\"TimeGenerated\",\"hivesMargin\":5}},\"name\":\"query - 4\"}],\"fromTemplateId\":\"sentinel-AzureActivity\",\"$schema\":\"https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json\"}\n",
"version": "1.0",
"sourceId": "[variables('workspaceResourceId')]",
"category": "sentinel"
@@ -3526,7 +3593,8 @@
"contentProductId": "[variables('_workbookcontentProductId1')]",
"id": "[variables('_workbookcontentProductId1')]",
"version": "[variables('workbookVersion1')]"
- }
+ },
+ "condition": "[parameters('DeployWorkbook')]"
},
{
"type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates",
@@ -3537,7 +3605,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
- "description": "AzureServiceHealthWorkbook Workbook with template version 3.0.4",
+ "description": "AzureServiceHealthWorkbook Workbook with template version 3.1.2",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('workbookVersion2')]",
@@ -3555,7 +3623,7 @@
},
"properties": {
"displayName": "[parameters('workbook2-name')]",
- "serializedData": "{\"version\":\"Notebook/1.0\",\"items\":[{\"type\":1,\"content\":{\"json\":\"## Azure Activity Logs for Azure Service Health Analysis Workbook\"},\"name\":\"text - 1\"},{\"type\":9,\"content\":{\"version\":\"KqlParameterItem/1.0\",\"crossComponentResources\":[\"{Subscription}\"],\"parameters\":[{\"id\":\"76e0f423-6828-47f3-aa86-522604bbbc6f\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"Subscription\",\"type\":6,\"description\":\"Azure Subscription where is the Log Analytics with Activity Logs informaiton\",\"isRequired\":true,\"query\":\"summarize by subscriptionId\\r\\n| project value = strcat(\\\"/subscriptions/\\\",subscriptionId), label = subscriptionId\\r\\n| order by value \",\"crossComponentResources\":[\"value::all\"],\"typeSettings\":{\"showDefault\":false},\"timeContext\":{\"durationMs\":86400000},\"queryType\":1,\"resourceType\":\"microsoft.resourcegraph/resources\",\"value\":\"/subscriptions/fcb7d51b-418f-45a9-8418-5c0f17e343c8\"},{\"id\":\"ea100a5b-3c79-4761-8235-6a7989c83da5\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"LAworkspace\",\"label\":\"Log Analytics workspace\",\"type\":5,\"description\":\"Log Analytics workspace where the Activity Logs information is sent\",\"isRequired\":true,\"query\":\"where type == 'microsoft.operationalinsights/workspaces'\\r\\n| project id\\r\\n| order by id asc\",\"crossComponentResources\":[\"{Subscription}\"],\"typeSettings\":{\"showDefault\":false},\"timeContext\":{\"durationMs\":86400000},\"queryType\":1,\"resourceType\":\"microsoft.resourcegraph/resources\",\"value\":\"\"},{\"id\":\"6b112ffe-a3a2-4b9e-a17a-c4ea5af739d7\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"TimeRange\",\"type\":4,\"typeSettings\":{\"selectableValues\":[{\"durationMs\":3600000},{\"durationMs\":86400000},{\"durationMs\":259200000},{\"durationMs\":604800000},{\"durationMs\":1209600000},{\"durationMs\":2592000000}],\"allowCustom\":true},\"timeContext\":{\"durationMs\":86400000},\"value\":{\"durationMs\":2592000000}}],\"style\":\"pills\",\"queryType\":1,\"resourceType\":\"microsoft.resourcegraph/resources\"},\"name\":\"parameters - 0\"},{\"type\":9,\"content\":{\"version\":\"KqlParameterItem/1.0\",\"crossComponentResources\":[\"{LAworkspace}\"],\"parameters\":[{\"id\":\"2fb175cb-a2b6-4dd3-9473-886a8db4cd9c\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"TrackingID_P\",\"label\":\"Tracking ID\",\"type\":2,\"isRequired\":true,\"multiSelect\":true,\"quote\":\"'\",\"delimiter\":\",\",\"query\":\"AzureActivity\\r\\n| where CategoryValue == \\\"ServiceHealth\\\"\\r\\n| extend TrackingId = tostring(Properties_d.trackingId)\\r\\n| distinct TrackingId\\r\\n| order by TrackingId asc\",\"crossComponentResources\":[\"{LAworkspace}\"],\"typeSettings\":{\"additionalResourceOptions\":[\"value::all\"],\"selectAllValue\":\"All\",\"showDefault\":false},\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"value\":[\"value::all\"]}],\"style\":\"pills\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},\"name\":\"parameters - 3\"},{\"type\":12,\"content\":{\"version\":\"NotebookGroup/1.0\",\"groupType\":\"editable\",\"items\":[{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"AzureActivity\\r\\n| where CategoryValue == \\\"ServiceHealth\\\" \\r\\n| summarize TimeGenerated=arg_max(TimeGenerated,*) by SubscriptionId\\r\\n| extend SubscriptionId == strcat('/subscriptions/', SubscriptionId)\",\"size\":1,\"showAnalytics\":true,\"title\":\"Subscriptions Impacted\",\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"crossComponentResources\":[\"{LAworkspace}\"],\"visualization\":\"tiles\",\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"TimeGenerated\",\"formatter\":0,\"formatOptions\":{\"customColumnWidthSetting\":\"22ch\"}},{\"columnMatch\":\"TrackingId\",\"formatter\":7,\"formatOptions\":{\"linkTarget\":\"GenericDetails\",\"linkIsContextBlade\":true,\"customColumnWidthSetting\":\"14ch\"}},{\"columnMatch\":\"Status\",\"formatter\":18,\"formatOptions\":{\"thresholdsOptions\":\"icons\",\"thresholdsGrid\":[{\"operator\":\"==\",\"thresholdValue\":\"Active\",\"representation\":\"2\",\"text\":\"{0}{1}\"},{\"operator\":\"==\",\"thresholdValue\":\"Resolved\",\"representation\":\"Resolved\",\"text\":\"{0}{1}\"},{\"operator\":\"Default\",\"representation\":\"more\",\"text\":\"{0}{1}\"}],\"customColumnWidthSetting\":\"12ch\"}},{\"columnMatch\":\"Impact Start Time\",\"formatter\":5},{\"columnMatch\":\"Level\",\"formatter\":18,\"formatOptions\":{\"thresholdsOptions\":\"icons\",\"thresholdsGrid\":[{\"operator\":\"==\",\"thresholdValue\":\"Information\",\"representation\":\"info\",\"text\":\"{0}{1}\"},{\"operator\":\"==\",\"thresholdValue\":\"Warning\",\"representation\":\"warning\",\"text\":\"{0}{1}\"},{\"operator\":\"==\",\"thresholdValue\":\"Error\",\"representation\":\"error\",\"text\":\"{0}{1}\"},{\"operator\":\"Default\",\"representation\":\"Unknown\",\"text\":\"{0}{1}\"}]}},{\"columnMatch\":\"IncidentType\",\"formatter\":18,\"formatOptions\":{\"thresholdsOptions\":\"icons\",\"thresholdsGrid\":[{\"operator\":\"==\",\"thresholdValue\":\"Incident\",\"representation\":\"error\",\"text\":\"{0}{1}\"},{\"operator\":\"==\",\"thresholdValue\":\"Maintenance\",\"representation\":\"Tools\",\"text\":\"{0}{1}\"},{\"operator\":\"==\",\"thresholdValue\":\"ActionRequired\",\"representation\":\"Clock\",\"text\":\"{0}{1}\"},{\"operator\":\"==\",\"thresholdValue\":\"Informational\",\"representation\":\"1\",\"text\":\"{0}{1}\"},{\"operator\":\"Default\",\"representation\":\"more\",\"text\":\"{0}{1}\"}]}},{\"columnMatch\":\"ImpactedSubscriptions\",\"formatter\":5},{\"columnMatch\":\"# Subs.\",\"formatter\":8,\"formatOptions\":{\"min\":-1,\"palette\":\"red\"}},{\"columnMatch\":\"ImpactedRegions\",\"formatter\":5},{\"columnMatch\":\"# Regions\",\"formatter\":8,\"formatOptions\":{\"min\":-1,\"palette\":\"magenta\"}},{\"columnMatch\":\"ImpactMitigationTime\",\"formatter\":5},{\"columnMatch\":\"ResolutionTime (hours)\",\"formatter\":4,\"formatOptions\":{\"min\":-1,\"palette\":\"orange\",\"customColumnWidthSetting\":\"26ch\"}}]},\"tileSettings\":{\"titleContent\":{\"columnMatch\":\"SubscriptionId\",\"formatter\":13,\"formatOptions\":{\"showIcon\":true}},\"showBorder\":false}},\"customWidth\":\"30\",\"name\":\"query - 0 - Copy\",\"styleSettings\":{\"showBorder\":true}},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"AzureActivity\\r\\n| where CategoryValue == \\\"ServiceHealth\\\"\\r\\n| extend TrackingId = tostring(Properties_d.trackingId)\\r\\n| summarize arg_max(TimeGenerated,*) by TrackingId\\r\\n| where TrackingId in ({TrackingID_P:value}) or '{TrackingID_P:label}'=='All'\\r\\n| extend ImpactedRegions = tostring(Properties_d.region)\\r\\n| summarize count() by ImpactedRegions\",\"size\":1,\"title\":\"Impacted Regions\",\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"tiles\",\"tileSettings\":{\"titleContent\":{\"columnMatch\":\"ImpactedRegions\",\"formatter\":1},\"leftContent\":{\"columnMatch\":\"count_\",\"formatter\":12,\"formatOptions\":{\"palette\":\"auto\"},\"numberFormat\":{\"unit\":17,\"options\":{\"maximumSignificantDigits\":3,\"maximumFractionDigits\":2}}},\"showBorder\":false}},\"customWidth\":\"35\",\"name\":\"query - 4\",\"styleSettings\":{\"showBorder\":true}},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"AzureActivity\\r\\n| where CategoryValue == \\\"ServiceHealth\\\"\\r\\n| extend TrackingId = tostring(Properties_d.trackingId)\\r\\n| summarize arg_max(TimeGenerated,*) by TrackingId\\r\\n| where TrackingId in ({TrackingID_P:value}) or '{TrackingID_P:label}'=='All'\\r\\n| extend IncidentType= tostring(Properties_d.incidentType)\\r\\n| summarize count() by IncidentType\",\"size\":1,\"title\":\"Type of Incidents\",\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"piechart\",\"tileSettings\":{\"titleContent\":{\"columnMatch\":\"IncidentType\",\"formatter\":1},\"leftContent\":{\"columnMatch\":\"count_\",\"formatter\":12,\"formatOptions\":{\"palette\":\"auto\"},\"numberFormat\":{\"unit\":17,\"options\":{\"maximumSignificantDigits\":3,\"maximumFractionDigits\":2}}},\"showBorder\":false},\"chartSettings\":{\"seriesLabelSettings\":[{\"seriesName\":\"Maintenance\",\"color\":\"gray\"},{\"seriesName\":\"Incident\",\"color\":\"yellowDark\"},{\"seriesName\":\"ActionRequired\",\"color\":\"redBright\"}]}},\"customWidth\":\"35\",\"name\":\"query - 4 - Copy\",\"styleSettings\":{\"showBorder\":true}},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"AzureActivity\\r\\n| where CategoryValue == \\\"ServiceHealth\\\"\\r\\n| extend TrackingId = tostring(Properties_d.trackingId)\\r\\n| summarize arg_max(TimeGenerated,*) by TrackingId\\r\\n| where TrackingId in ({TrackingID_P:value}) or '{TrackingID_P:label}'=='All'\\r\\n| extend Status = tostring(Properties_d.activityStatusValue)\\r\\n| summarize count() by Status\",\"size\":0,\"title\":\"Service Health on Status\",\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"piechart\",\"tileSettings\":{\"titleContent\":{\"columnMatch\":\"IncidentType\",\"formatter\":1},\"leftContent\":{\"columnMatch\":\"count_\",\"formatter\":12,\"formatOptions\":{\"palette\":\"auto\"},\"numberFormat\":{\"unit\":17,\"options\":{\"maximumSignificantDigits\":3,\"maximumFractionDigits\":2}}},\"showBorder\":false},\"chartSettings\":{\"seriesLabelSettings\":[{\"seriesName\":\"Active\",\"color\":\"red\"},{\"seriesName\":\"Resolved\",\"color\":\"green\"}]}},\"customWidth\":\"45\",\"name\":\"query - 4 - Copy - Copy\",\"styleSettings\":{\"showBorder\":true}},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"AzureActivity\\r\\n| where CategoryValue == \\\"ServiceHealth\\\"\\r\\n| extend TrackingId = tostring(Properties_d.trackingId)\\r\\n| summarize arg_max(TimeGenerated,*) by TrackingId\\r\\n| where TrackingId in ({TrackingID_P:value}) or '{TrackingID_P:label}'=='All'\\r\\n| extend Service = tostring(Properties_d.service)\\r\\n| summarize count() by Service\",\"size\":0,\"title\":\"Service Health Across Services\",\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"categoricalbar\",\"tileSettings\":{\"titleContent\":{\"columnMatch\":\"IncidentType\",\"formatter\":1},\"leftContent\":{\"columnMatch\":\"count_\",\"formatter\":12,\"formatOptions\":{\"palette\":\"auto\"},\"numberFormat\":{\"unit\":17,\"options\":{\"maximumSignificantDigits\":3,\"maximumFractionDigits\":2}}},\"showBorder\":false},\"chartSettings\":{\"seriesLabelSettings\":[{\"seriesName\":\"Active\",\"color\":\"red\"},{\"seriesName\":\"Resolved\",\"color\":\"green\"}]}},\"customWidth\":\"55\",\"name\":\"query - 4 - Copy - Copy - Copy\",\"styleSettings\":{\"showBorder\":true}},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"AzureActivity\\r\\n| where CategoryValue == \\\"ServiceHealth\\\"\\r\\n| extend TrackingId = tostring(Properties_d.trackingId)\\r\\n| summarize arg_max(TimeGenerated,*) by TrackingId\\r\\n| where TrackingId in ({TrackingID_P:value}) or '{TrackingID_P:label}'=='All'\\r\\n| extend Service = tostring(Properties_d.service)\\r\\n| extend ImpactMitigationTime = tostring(Properties_d.impactMitigationTime)\\r\\n| extend ImpactStartTime = tostring(Properties_d.impactStartTime)\\r\\n| extend [\\\"ResolutionTime\\\"]=datetime_diff('hour',todatetime(ImpactMitigationTime),todatetime(ImpactStartTime))\\r\\n| extend ImpactedRegions = todynamic(parse_json(tostring(parse_json(tostring(parse_json(Properties).impactedServices))[0].ImpactedRegions)))\\r\\n| mv-expand ImpactedRegions\\r\\n| project Service,ImpactedRegions.RegionName, [\\\"ResolutionTime\\\"], _ResourceId\",\"size\":0,\"title\":\"Resolution Time\",\"timeContextFromParameter\":\"TimeRange\",\"showExportToExcel\":true,\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"table\",\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"$gen_group\",\"formatter\":13,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"ResolutionTime\",\"formatter\":8,\"formatOptions\":{\"palette\":\"redDark\"},\"numberFormat\":{\"unit\":25,\"options\":{\"style\":\"decimal\",\"useGrouping\":false}}},{\"columnMatch\":\"_ResourceId\",\"formatter\":5}],\"filter\":true,\"hierarchySettings\":{\"treeType\":1,\"groupBy\":[\"_ResourceId\"],\"expandTopLevel\":true}},\"tileSettings\":{\"titleContent\":{\"columnMatch\":\"IncidentType\",\"formatter\":1},\"leftContent\":{\"columnMatch\":\"count_\",\"formatter\":12,\"formatOptions\":{\"palette\":\"auto\"},\"numberFormat\":{\"unit\":17,\"options\":{\"maximumSignificantDigits\":3,\"maximumFractionDigits\":2}}},\"showBorder\":false},\"chartSettings\":{\"seriesLabelSettings\":[{\"seriesName\":\"Active\",\"color\":\"red\"},{\"seriesName\":\"Resolved\",\"color\":\"green\"}]}},\"customWidth\":\"70\",\"name\":\"query - 4 - Copy - Copy - Copy - Copy\",\"styleSettings\":{\"showBorder\":true}},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"AzureActivity\\r\\n| where CategoryValue == \\\"ServiceHealth\\\"\\r\\n| extend TrackingId = tostring(Properties_d.trackingId)\\r\\n| summarize arg_max(TimeGenerated,*) by TrackingId\\r\\n| where TrackingId in ({TrackingID_P:value}) or '{TrackingID_P:label}'=='All'\\r\\n| extend Stage = tostring(parse_json(Properties).stage)\\r\\n| summarize count() by Stage\",\"size\":0,\"title\":\"Current Stage\",\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"tiles\",\"tileSettings\":{\"titleContent\":{\"columnMatch\":\"Stage\",\"formatter\":1},\"leftContent\":{\"columnMatch\":\"count_\",\"formatter\":12,\"formatOptions\":{\"palette\":\"auto\"},\"numberFormat\":{\"unit\":17,\"options\":{\"maximumSignificantDigits\":3,\"maximumFractionDigits\":2}}},\"showBorder\":false},\"chartSettings\":{\"seriesLabelSettings\":[{\"seriesName\":\"Active\",\"color\":\"red\"},{\"seriesName\":\"Resolved\",\"color\":\"green\"}]}},\"customWidth\":\"30\",\"name\":\"query - 4 - Copy - Copy - Copy - Copy - Copy\",\"styleSettings\":{\"showBorder\":true}},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"AzureActivity\\r\\n| where CategoryValue == \\\"ServiceHealth\\\"\\r\\n| extend TrackingId = tostring(Properties_d.trackingId)\\r\\n| summarize arg_max(TimeGenerated,) by TrackingId\\r\\n| where TrackingId in ({TrackingID_P:value}) or '{TrackingID_P:label}'=='All'\\r\\n//| where Level in ('Warning','Error','Information')\\r\\n| extend IncidentType= tostring(Properties_d.incidentType)\\r\\n//| where IncidentType in ('Incident','Maintenance','ActionRequired')\\r\\n| extend ImpactMitigationTime = tostring(Properties_d.impactMitigationTime)\\r\\n| extend ImpactStartTime = tostring(Properties_d.impactStartTime)\\r\\n| extend Status = tostring(Properties_d.activityStatusValue)\\r\\n| extend Service = tostring(Properties_d.service)\\r\\n| extend Title = tostring(Properties_d.defaultLanguageTitle)\\r\\n| extend ImpactedRegions = tostring(parse_json(tostring(parse_json(tostring(parse_json(Properties).impactedServices))[0].ImpactedRegions)))\\r\\n| summarize ImpactedSubscriptions=make_set(SubscriptionId), TimeGenerated=arg_max(TimeGenerated,) by Level, ImpactedRegions, Service, TrackingId, Status\\r\\n| project TimeGenerated\\r\\n , TrackingId\\r\\n , Title\\r\\n , Status\\r\\n , [\\\"Impact Start Time\\\"]=todatetime(ImpactStartTime)\\r\\n , Level\\r\\n , IncidentType\\r\\n , ImpactedSubscriptions\\r\\n , Service\\r\\n , [\\\"# Subs.\\\"]=array_length(ImpactedSubscriptions)\\r\\n , ImpactedRegions\\r\\n , [\\\"# Regions\\\"]=array_length(parse_json(ImpactedRegions))\\r\\n , todatetime(ImpactMitigationTime)\\r\\n , [\\\"ResolutionTime (hours)\\\"]=datetime_diff('hour',todatetime(ImpactMitigationTime),todatetime(ImpactStartTime))\\r\\n| order by TimeGenerated \",\"size\":0,\"showAnalytics\":true,\"title\":\"Analysis of incident\",\"timeContextFromParameter\":\"TimeRange\",\"showExportToExcel\":true,\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"crossComponentResources\":[\"{LAworkspace}\"],\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"TimeGenerated\",\"formatter\":0,\"formatOptions\":{\"customColumnWidthSetting\":\"22ch\"}},{\"columnMatch\":\"TrackingId\",\"formatter\":7,\"formatOptions\":{\"linkTarget\":\"GenericDetails\",\"linkIsContextBlade\":true,\"customColumnWidthSetting\":\"14ch\"}},{\"columnMatch\":\"Status\",\"formatter\":18,\"formatOptions\":{\"thresholdsOptions\":\"icons\",\"thresholdsGrid\":[{\"operator\":\"==\",\"thresholdValue\":\"Active\",\"representation\":\"2\",\"text\":\"{0}{1}\"},{\"operator\":\"==\",\"thresholdValue\":\"Resolved\",\"representation\":\"Resolved\",\"text\":\"{0}{1}\"},{\"operator\":\"Default\",\"representation\":\"more\",\"text\":\"{0}{1}\"}],\"customColumnWidthSetting\":\"12ch\"}},{\"columnMatch\":\"Impact Start Time\",\"formatter\":5},{\"columnMatch\":\"Level\",\"formatter\":18,\"formatOptions\":{\"thresholdsOptions\":\"icons\",\"thresholdsGrid\":[{\"operator\":\"==\",\"thresholdValue\":\"Information\",\"representation\":\"info\",\"text\":\"{0}{1}\"},{\"operator\":\"==\",\"thresholdValue\":\"Warning\",\"representation\":\"warning\",\"text\":\"{0}{1}\"},{\"operator\":\"==\",\"thresholdValue\":\"Error\",\"representation\":\"error\",\"text\":\"{0}{1}\"},{\"operator\":\"Default\",\"representation\":\"Unknown\",\"text\":\"{0}{1}\"}]}},{\"columnMatch\":\"IncidentType\",\"formatter\":18,\"formatOptions\":{\"thresholdsOptions\":\"icons\",\"thresholdsGrid\":[{\"operator\":\"==\",\"thresholdValue\":\"Incident\",\"representation\":\"error\",\"text\":\"{0}{1}\"},{\"operator\":\"==\",\"thresholdValue\":\"Maintenance\",\"representation\":\"Tools\",\"text\":\"{0}{1}\"},{\"operator\":\"==\",\"thresholdValue\":\"ActionRequired\",\"representation\":\"Clock\",\"text\":\"{0}{1}\"},{\"operator\":\"==\",\"thresholdValue\":\"Informational\",\"representation\":\"1\",\"text\":\"{0}{1}\"},{\"operator\":\"Default\",\"representation\":\"more\",\"text\":\"{0}{1}\"}]}},{\"columnMatch\":\"ImpactedSubscriptions\",\"formatter\":5},{\"columnMatch\":\"# Subs.\",\"formatter\":8,\"formatOptions\":{\"min\":-1,\"palette\":\"red\"}},{\"columnMatch\":\"ImpactedRegions\",\"formatter\":5},{\"columnMatch\":\"# Regions\",\"formatter\":8,\"formatOptions\":{\"min\":-1,\"palette\":\"magenta\"}},{\"columnMatch\":\"ImpactMitigationTime\",\"formatter\":5},{\"columnMatch\":\"ResolutionTime (hours)\",\"formatter\":4,\"formatOptions\":{\"min\":-1,\"palette\":\"orange\",\"customColumnWidthSetting\":\"26ch\"}}],\"filter\":true,\"sortBy\":[{\"itemKey\":\"$gen_link_TrackingId_1\",\"sortOrder\":1}]},\"sortBy\":[{\"itemKey\":\"$gen_link_TrackingId_1\",\"sortOrder\":1}]},\"name\":\"query - 0\",\"styleSettings\":{\"showBorder\":true}},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"AzureActivity\\r\\n| where CategoryValue == \\\"ServiceHealth\\\"\\r\\n| extend TrackingId = tostring(Properties_d.trackingId)\\r\\n| where TrackingId in ({TrackingID_P:value}) or '{TrackingID_P:label}'=='All'\\r\\n| summarize ImpactedSubscriptions=make_set(SubscriptionId) by TrackingId\\r\\n| project ImpactedSubscriptions, TrackingId\\r\\n| mv-expand ImpactedSubscriptions\\r\\n| project Subscription=strcat('/subscriptions/',ImpactedSubscriptions), TrackingId\\r\\n| extend Info=strcat('https://app.azure.com/h/',TrackingId)\\r\\n| order by TrackingId asc\",\"size\":0,\"showAnalytics\":true,\"title\":\"Affected subscriptions\",\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"crossComponentResources\":[\"{LAworkspace}\"],\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"TrackingId\",\"formatter\":1,\"formatOptions\":{\"linkColumn\":\"Info\",\"linkTarget\":\"Url\"}},{\"columnMatch\":\"Info\",\"formatter\":5,\"formatOptions\":{\"linkTarget\":\"Url\",\"linkLabel\":\"Shareable link\"}}],\"filter\":true}},\"customWidth\":\"50\",\"name\":\"query - 2\",\"styleSettings\":{\"showBorder\":true}},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"AzureActivity\\r\\n| where CategoryValue == \\\"ServiceHealth\\\"\\r\\n| extend TrackingId = tostring(Properties_d.trackingId)\\r\\n| where TrackingId in ({TrackingID_P:value}) or '{TrackingID_P:label}'=='All'\\r\\n| extend ImpactedRegions = tostring(parse_json(tostring(parse_json(tostring(parse_json(Properties).impactedServices))[0].ImpactedRegions)))\\r\\n| project todynamic(ImpactedRegions), TrackingId\\r\\n| mv-expand ImpactedRegions\\r\\n| project Region=strcat(tostring(ImpactedRegions.RegionName),' (',tostring(ImpactedRegions.RegionId),')'),TrackingId\\r\\n| distinct Region, TrackingId\\r\\n| extend Info=strcat('https://app.azure.com/h/', TrackingId)\\r\\n| order by TrackingId asc\\r\\n\",\"size\":0,\"showAnalytics\":true,\"title\":\"Affected regions\",\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"crossComponentResources\":[\"{LAworkspace}\"],\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"TrackingId\",\"formatter\":1,\"formatOptions\":{\"linkColumn\":\"Info\",\"linkTarget\":\"Url\"}},{\"columnMatch\":\"Info\",\"formatter\":5}],\"filter\":true}},\"customWidth\":\"50\",\"name\":\"query - 1\",\"styleSettings\":{\"showBorder\":true}}]},\"name\":\"GroupActivityLogs01\",\"styleSettings\":{\"showBorder\":true}}],\"fromTemplateId\":\"sentinel-AzureServiceHealthWorkbook\",\"$schema\":\"https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json\"}\r\n",
+ "serializedData": "{\"version\":\"Notebook/1.0\",\"items\":[{\"type\":1,\"content\":{\"json\":\"## Azure Activity Logs for Azure Service Health Analysis Workbook\"},\"name\":\"text - 1\"},{\"type\":9,\"content\":{\"version\":\"KqlParameterItem/1.0\",\"crossComponentResources\":[\"{Subscription}\"],\"parameters\":[{\"id\":\"76e0f423-6828-47f3-aa86-522604bbbc6f\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"Subscription\",\"type\":6,\"description\":\"Azure Subscription where is the Log Analytics with Activity Logs informaiton\",\"isRequired\":true,\"query\":\"summarize by subscriptionId\\r\\n| project value = strcat(\\\"/subscriptions/\\\",subscriptionId), label = subscriptionId\\r\\n| order by value \",\"crossComponentResources\":[\"value::all\"],\"typeSettings\":{\"showDefault\":false},\"timeContext\":{\"durationMs\":86400000},\"queryType\":1,\"resourceType\":\"microsoft.resourcegraph/resources\",\"value\":\"/subscriptions/fcb7d51b-418f-45a9-8418-5c0f17e343c8\"},{\"id\":\"ea100a5b-3c79-4761-8235-6a7989c83da5\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"LAworkspace\",\"label\":\"Log Analytics workspace\",\"type\":5,\"description\":\"Log Analytics workspace where the Activity Logs information is sent\",\"isRequired\":true,\"query\":\"where type == 'microsoft.operationalinsights/workspaces'\\r\\n| project id\\r\\n| order by id asc\",\"crossComponentResources\":[\"{Subscription}\"],\"typeSettings\":{\"showDefault\":false},\"timeContext\":{\"durationMs\":86400000},\"queryType\":1,\"resourceType\":\"microsoft.resourcegraph/resources\",\"value\":\"\"},{\"id\":\"6b112ffe-a3a2-4b9e-a17a-c4ea5af739d7\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"TimeRange\",\"type\":4,\"typeSettings\":{\"selectableValues\":[{\"durationMs\":3600000},{\"durationMs\":86400000},{\"durationMs\":259200000},{\"durationMs\":604800000},{\"durationMs\":1209600000},{\"durationMs\":2592000000}],\"allowCustom\":true},\"timeContext\":{\"durationMs\":86400000},\"value\":{\"durationMs\":2592000000}}],\"style\":\"pills\",\"queryType\":1,\"resourceType\":\"microsoft.resourcegraph/resources\"},\"name\":\"parameters - 0\"},{\"type\":9,\"content\":{\"version\":\"KqlParameterItem/1.0\",\"crossComponentResources\":[\"{LAworkspace}\"],\"parameters\":[{\"id\":\"2fb175cb-a2b6-4dd3-9473-886a8db4cd9c\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"TrackingID_P\",\"label\":\"Tracking ID\",\"type\":2,\"isRequired\":true,\"multiSelect\":true,\"quote\":\"'\",\"delimiter\":\",\",\"query\":\"AzureActivity\\r\\n| where CategoryValue == \\\"ServiceHealth\\\"\\r\\n| extend TrackingId = tostring(Properties_d.trackingId)\\r\\n| distinct TrackingId\\r\\n| order by TrackingId asc\",\"crossComponentResources\":[\"{LAworkspace}\"],\"typeSettings\":{\"additionalResourceOptions\":[\"value::all\"],\"selectAllValue\":\"All\",\"showDefault\":false},\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"value\":[\"value::all\"]}],\"style\":\"pills\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},\"name\":\"parameters - 3\"},{\"type\":12,\"content\":{\"version\":\"NotebookGroup/1.0\",\"groupType\":\"editable\",\"items\":[{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"AzureActivity\\r\\n| where CategoryValue == \\\"ServiceHealth\\\" \\r\\n| summarize TimeGenerated=arg_max(TimeGenerated,*) by SubscriptionId\\r\\n| extend SubscriptionId == strcat('/subscriptions/', SubscriptionId)\",\"size\":1,\"showAnalytics\":true,\"title\":\"Subscriptions Impacted\",\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"crossComponentResources\":[\"{LAworkspace}\"],\"visualization\":\"tiles\",\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"TimeGenerated\",\"formatter\":0,\"formatOptions\":{\"customColumnWidthSetting\":\"22ch\"}},{\"columnMatch\":\"TrackingId\",\"formatter\":7,\"formatOptions\":{\"linkTarget\":\"GenericDetails\",\"linkIsContextBlade\":true,\"customColumnWidthSetting\":\"14ch\"}},{\"columnMatch\":\"Status\",\"formatter\":18,\"formatOptions\":{\"thresholdsOptions\":\"icons\",\"thresholdsGrid\":[{\"operator\":\"==\",\"thresholdValue\":\"Active\",\"representation\":\"2\",\"text\":\"{0}{1}\"},{\"operator\":\"==\",\"thresholdValue\":\"Resolved\",\"representation\":\"Resolved\",\"text\":\"{0}{1}\"},{\"operator\":\"Default\",\"representation\":\"more\",\"text\":\"{0}{1}\"}],\"customColumnWidthSetting\":\"12ch\"}},{\"columnMatch\":\"Impact Start Time\",\"formatter\":5},{\"columnMatch\":\"Level\",\"formatter\":18,\"formatOptions\":{\"thresholdsOptions\":\"icons\",\"thresholdsGrid\":[{\"operator\":\"==\",\"thresholdValue\":\"Information\",\"representation\":\"info\",\"text\":\"{0}{1}\"},{\"operator\":\"==\",\"thresholdValue\":\"Warning\",\"representation\":\"warning\",\"text\":\"{0}{1}\"},{\"operator\":\"==\",\"thresholdValue\":\"Error\",\"representation\":\"error\",\"text\":\"{0}{1}\"},{\"operator\":\"Default\",\"representation\":\"Unknown\",\"text\":\"{0}{1}\"}]}},{\"columnMatch\":\"IncidentType\",\"formatter\":18,\"formatOptions\":{\"thresholdsOptions\":\"icons\",\"thresholdsGrid\":[{\"operator\":\"==\",\"thresholdValue\":\"Incident\",\"representation\":\"error\",\"text\":\"{0}{1}\"},{\"operator\":\"==\",\"thresholdValue\":\"Maintenance\",\"representation\":\"Tools\",\"text\":\"{0}{1}\"},{\"operator\":\"==\",\"thresholdValue\":\"ActionRequired\",\"representation\":\"Clock\",\"text\":\"{0}{1}\"},{\"operator\":\"==\",\"thresholdValue\":\"Informational\",\"representation\":\"1\",\"text\":\"{0}{1}\"},{\"operator\":\"Default\",\"representation\":\"more\",\"text\":\"{0}{1}\"}]}},{\"columnMatch\":\"ImpactedSubscriptions\",\"formatter\":5},{\"columnMatch\":\"# Subs.\",\"formatter\":8,\"formatOptions\":{\"min\":-1,\"palette\":\"red\"}},{\"columnMatch\":\"ImpactedRegions\",\"formatter\":5},{\"columnMatch\":\"# Regions\",\"formatter\":8,\"formatOptions\":{\"min\":-1,\"palette\":\"magenta\"}},{\"columnMatch\":\"ImpactMitigationTime\",\"formatter\":5},{\"columnMatch\":\"ResolutionTime (hours)\",\"formatter\":4,\"formatOptions\":{\"min\":-1,\"palette\":\"orange\",\"customColumnWidthSetting\":\"26ch\"}}]},\"tileSettings\":{\"titleContent\":{\"columnMatch\":\"SubscriptionId\",\"formatter\":13,\"formatOptions\":{\"showIcon\":true}},\"showBorder\":false}},\"customWidth\":\"30\",\"name\":\"query - 0 - Copy\",\"styleSettings\":{\"showBorder\":true}},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"AzureActivity\\r\\n| where CategoryValue == \\\"ServiceHealth\\\"\\r\\n| extend TrackingId = tostring(Properties_d.trackingId)\\r\\n| summarize arg_max(TimeGenerated,*) by TrackingId\\r\\n| where TrackingId in ({TrackingID_P:value}) or '{TrackingID_P:label}'=='All'\\r\\n| extend ImpactedRegions = tostring(Properties_d.region)\\r\\n| summarize count() by ImpactedRegions\",\"size\":1,\"title\":\"Impacted Regions\",\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"tiles\",\"tileSettings\":{\"titleContent\":{\"columnMatch\":\"ImpactedRegions\",\"formatter\":1},\"leftContent\":{\"columnMatch\":\"count_\",\"formatter\":12,\"formatOptions\":{\"palette\":\"auto\"},\"numberFormat\":{\"unit\":17,\"options\":{\"maximumSignificantDigits\":3,\"maximumFractionDigits\":2}}},\"showBorder\":false}},\"customWidth\":\"35\",\"name\":\"query - 4\",\"styleSettings\":{\"showBorder\":true}},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"AzureActivity\\r\\n| where CategoryValue == \\\"ServiceHealth\\\"\\r\\n| extend TrackingId = tostring(Properties_d.trackingId)\\r\\n| summarize arg_max(TimeGenerated,*) by TrackingId\\r\\n| where TrackingId in ({TrackingID_P:value}) or '{TrackingID_P:label}'=='All'\\r\\n| extend IncidentType= tostring(Properties_d.incidentType)\\r\\n| summarize count() by IncidentType\",\"size\":1,\"title\":\"Type of Incidents\",\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"piechart\",\"tileSettings\":{\"titleContent\":{\"columnMatch\":\"IncidentType\",\"formatter\":1},\"leftContent\":{\"columnMatch\":\"count_\",\"formatter\":12,\"formatOptions\":{\"palette\":\"auto\"},\"numberFormat\":{\"unit\":17,\"options\":{\"maximumSignificantDigits\":3,\"maximumFractionDigits\":2}}},\"showBorder\":false},\"chartSettings\":{\"seriesLabelSettings\":[{\"seriesName\":\"Maintenance\",\"color\":\"gray\"},{\"seriesName\":\"Incident\",\"color\":\"yellowDark\"},{\"seriesName\":\"ActionRequired\",\"color\":\"redBright\"}]}},\"customWidth\":\"35\",\"name\":\"query - 4 - Copy\",\"styleSettings\":{\"showBorder\":true}},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"AzureActivity\\r\\n| where CategoryValue == \\\"ServiceHealth\\\"\\r\\n| extend TrackingId = tostring(Properties_d.trackingId)\\r\\n| summarize arg_max(TimeGenerated,*) by TrackingId\\r\\n| where TrackingId in ({TrackingID_P:value}) or '{TrackingID_P:label}'=='All'\\r\\n| extend Status = tostring(Properties_d.activityStatusValue)\\r\\n| summarize count() by Status\",\"size\":0,\"title\":\"Service Health on Status\",\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"piechart\",\"tileSettings\":{\"titleContent\":{\"columnMatch\":\"IncidentType\",\"formatter\":1},\"leftContent\":{\"columnMatch\":\"count_\",\"formatter\":12,\"formatOptions\":{\"palette\":\"auto\"},\"numberFormat\":{\"unit\":17,\"options\":{\"maximumSignificantDigits\":3,\"maximumFractionDigits\":2}}},\"showBorder\":false},\"chartSettings\":{\"seriesLabelSettings\":[{\"seriesName\":\"Active\",\"color\":\"red\"},{\"seriesName\":\"Resolved\",\"color\":\"green\"}]}},\"customWidth\":\"45\",\"name\":\"query - 4 - Copy - Copy\",\"styleSettings\":{\"showBorder\":true}},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"AzureActivity\\r\\n| where CategoryValue == \\\"ServiceHealth\\\"\\r\\n| extend TrackingId = tostring(Properties_d.trackingId)\\r\\n| summarize arg_max(TimeGenerated,*) by TrackingId\\r\\n| where TrackingId in ({TrackingID_P:value}) or '{TrackingID_P:label}'=='All'\\r\\n| extend Service = tostring(Properties_d.service)\\r\\n| summarize count() by Service\",\"size\":0,\"title\":\"Service Health Across Services\",\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"categoricalbar\",\"tileSettings\":{\"titleContent\":{\"columnMatch\":\"IncidentType\",\"formatter\":1},\"leftContent\":{\"columnMatch\":\"count_\",\"formatter\":12,\"formatOptions\":{\"palette\":\"auto\"},\"numberFormat\":{\"unit\":17,\"options\":{\"maximumSignificantDigits\":3,\"maximumFractionDigits\":2}}},\"showBorder\":false},\"chartSettings\":{\"seriesLabelSettings\":[{\"seriesName\":\"Active\",\"color\":\"red\"},{\"seriesName\":\"Resolved\",\"color\":\"green\"}]}},\"customWidth\":\"55\",\"name\":\"query - 4 - Copy - Copy - Copy\",\"styleSettings\":{\"showBorder\":true}},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"AzureActivity\\r\\n| where CategoryValue == \\\"ServiceHealth\\\"\\r\\n| extend TrackingId = tostring(Properties_d.trackingId)\\r\\n| summarize arg_max(TimeGenerated,*) by TrackingId\\r\\n| where TrackingId in ({TrackingID_P:value}) or '{TrackingID_P:label}'=='All'\\r\\n| extend Service = tostring(Properties_d.service)\\r\\n| extend ImpactMitigationTime = tostring(Properties_d.impactMitigationTime)\\r\\n| extend ImpactStartTime = tostring(Properties_d.impactStartTime)\\r\\n| extend [\\\"ResolutionTime\\\"]=datetime_diff('hour',todatetime(ImpactMitigationTime),todatetime(ImpactStartTime))\\r\\n| extend ImpactedRegions = todynamic(parse_json(tostring(parse_json(tostring(parse_json(Properties).impactedServices))[0].ImpactedRegions)))\\r\\n| mv-expand ImpactedRegions\\r\\n| project Service,ImpactedRegions.RegionName, [\\\"ResolutionTime\\\"], _ResourceId\",\"size\":0,\"title\":\"Resolution Time\",\"timeContextFromParameter\":\"TimeRange\",\"showExportToExcel\":true,\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"table\",\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"$gen_group\",\"formatter\":13,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"ResolutionTime\",\"formatter\":8,\"formatOptions\":{\"palette\":\"redDark\"},\"numberFormat\":{\"unit\":25,\"options\":{\"style\":\"decimal\",\"useGrouping\":false}}},{\"columnMatch\":\"_ResourceId\",\"formatter\":5}],\"filter\":true,\"hierarchySettings\":{\"treeType\":1,\"groupBy\":[\"_ResourceId\"],\"expandTopLevel\":true}},\"tileSettings\":{\"titleContent\":{\"columnMatch\":\"IncidentType\",\"formatter\":1},\"leftContent\":{\"columnMatch\":\"count_\",\"formatter\":12,\"formatOptions\":{\"palette\":\"auto\"},\"numberFormat\":{\"unit\":17,\"options\":{\"maximumSignificantDigits\":3,\"maximumFractionDigits\":2}}},\"showBorder\":false},\"chartSettings\":{\"seriesLabelSettings\":[{\"seriesName\":\"Active\",\"color\":\"red\"},{\"seriesName\":\"Resolved\",\"color\":\"green\"}]}},\"customWidth\":\"70\",\"name\":\"query - 4 - Copy - Copy - Copy - Copy\",\"styleSettings\":{\"showBorder\":true}},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"AzureActivity\\r\\n| where CategoryValue == \\\"ServiceHealth\\\"\\r\\n| extend TrackingId = tostring(Properties_d.trackingId)\\r\\n| summarize arg_max(TimeGenerated,*) by TrackingId\\r\\n| where TrackingId in ({TrackingID_P:value}) or '{TrackingID_P:label}'=='All'\\r\\n| extend Stage = tostring(parse_json(Properties).stage)\\r\\n| summarize count() by Stage\",\"size\":0,\"title\":\"Current Stage\",\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"tiles\",\"tileSettings\":{\"titleContent\":{\"columnMatch\":\"Stage\",\"formatter\":1},\"leftContent\":{\"columnMatch\":\"count_\",\"formatter\":12,\"formatOptions\":{\"palette\":\"auto\"},\"numberFormat\":{\"unit\":17,\"options\":{\"maximumSignificantDigits\":3,\"maximumFractionDigits\":2}}},\"showBorder\":false},\"chartSettings\":{\"seriesLabelSettings\":[{\"seriesName\":\"Active\",\"color\":\"red\"},{\"seriesName\":\"Resolved\",\"color\":\"green\"}]}},\"customWidth\":\"30\",\"name\":\"query - 4 - Copy - Copy - Copy - Copy - Copy\",\"styleSettings\":{\"showBorder\":true}},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"AzureActivity\\r\\n| where CategoryValue == \\\"ServiceHealth\\\"\\r\\n| extend TrackingId = tostring(Properties_d.trackingId)\\r\\n| summarize arg_max(TimeGenerated,) by TrackingId\\r\\n| where TrackingId in ({TrackingID_P:value}) or '{TrackingID_P:label}'=='All'\\r\\n//| where Level in ('Warning','Error','Information')\\r\\n| extend IncidentType= tostring(Properties_d.incidentType)\\r\\n//| where IncidentType in ('Incident','Maintenance','ActionRequired')\\r\\n| extend ImpactMitigationTime = tostring(Properties_d.impactMitigationTime)\\r\\n| extend ImpactStartTime = tostring(Properties_d.impactStartTime)\\r\\n| extend Status = tostring(Properties_d.activityStatusValue)\\r\\n| extend Service = tostring(Properties_d.service)\\r\\n| extend Title = tostring(Properties_d.defaultLanguageTitle)\\r\\n| extend ImpactedRegions = tostring(parse_json(tostring(parse_json(tostring(parse_json(Properties).impactedServices))[0].ImpactedRegions)))\\r\\n| summarize ImpactedSubscriptions=make_set(SubscriptionId), TimeGenerated=arg_max(TimeGenerated,) by Level, ImpactedRegions, Service, TrackingId, Status\\r\\n| project TimeGenerated\\r\\n , TrackingId\\r\\n , Title\\r\\n , Status\\r\\n , [\\\"Impact Start Time\\\"]=todatetime(ImpactStartTime)\\r\\n , Level\\r\\n , IncidentType\\r\\n , ImpactedSubscriptions\\r\\n , Service\\r\\n , [\\\"# Subs.\\\"]=array_length(ImpactedSubscriptions)\\r\\n , ImpactedRegions\\r\\n , [\\\"# Regions\\\"]=array_length(parse_json(ImpactedRegions))\\r\\n , todatetime(ImpactMitigationTime)\\r\\n , [\\\"ResolutionTime (hours)\\\"]=datetime_diff('hour',todatetime(ImpactMitigationTime),todatetime(ImpactStartTime))\\r\\n| order by TimeGenerated \",\"size\":0,\"showAnalytics\":true,\"title\":\"Analysis of incident\",\"timeContextFromParameter\":\"TimeRange\",\"showExportToExcel\":true,\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"crossComponentResources\":[\"{LAworkspace}\"],\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"TimeGenerated\",\"formatter\":0,\"formatOptions\":{\"customColumnWidthSetting\":\"22ch\"}},{\"columnMatch\":\"TrackingId\",\"formatter\":7,\"formatOptions\":{\"linkTarget\":\"GenericDetails\",\"linkIsContextBlade\":true,\"customColumnWidthSetting\":\"14ch\"}},{\"columnMatch\":\"Status\",\"formatter\":18,\"formatOptions\":{\"thresholdsOptions\":\"icons\",\"thresholdsGrid\":[{\"operator\":\"==\",\"thresholdValue\":\"Active\",\"representation\":\"2\",\"text\":\"{0}{1}\"},{\"operator\":\"==\",\"thresholdValue\":\"Resolved\",\"representation\":\"Resolved\",\"text\":\"{0}{1}\"},{\"operator\":\"Default\",\"representation\":\"more\",\"text\":\"{0}{1}\"}],\"customColumnWidthSetting\":\"12ch\"}},{\"columnMatch\":\"Impact Start Time\",\"formatter\":5},{\"columnMatch\":\"Level\",\"formatter\":18,\"formatOptions\":{\"thresholdsOptions\":\"icons\",\"thresholdsGrid\":[{\"operator\":\"==\",\"thresholdValue\":\"Information\",\"representation\":\"info\",\"text\":\"{0}{1}\"},{\"operator\":\"==\",\"thresholdValue\":\"Warning\",\"representation\":\"warning\",\"text\":\"{0}{1}\"},{\"operator\":\"==\",\"thresholdValue\":\"Error\",\"representation\":\"error\",\"text\":\"{0}{1}\"},{\"operator\":\"Default\",\"representation\":\"Unknown\",\"text\":\"{0}{1}\"}]}},{\"columnMatch\":\"IncidentType\",\"formatter\":18,\"formatOptions\":{\"thresholdsOptions\":\"icons\",\"thresholdsGrid\":[{\"operator\":\"==\",\"thresholdValue\":\"Incident\",\"representation\":\"error\",\"text\":\"{0}{1}\"},{\"operator\":\"==\",\"thresholdValue\":\"Maintenance\",\"representation\":\"Tools\",\"text\":\"{0}{1}\"},{\"operator\":\"==\",\"thresholdValue\":\"ActionRequired\",\"representation\":\"Clock\",\"text\":\"{0}{1}\"},{\"operator\":\"==\",\"thresholdValue\":\"Informational\",\"representation\":\"1\",\"text\":\"{0}{1}\"},{\"operator\":\"Default\",\"representation\":\"more\",\"text\":\"{0}{1}\"}]}},{\"columnMatch\":\"ImpactedSubscriptions\",\"formatter\":5},{\"columnMatch\":\"# Subs.\",\"formatter\":8,\"formatOptions\":{\"min\":-1,\"palette\":\"red\"}},{\"columnMatch\":\"ImpactedRegions\",\"formatter\":5},{\"columnMatch\":\"# Regions\",\"formatter\":8,\"formatOptions\":{\"min\":-1,\"palette\":\"magenta\"}},{\"columnMatch\":\"ImpactMitigationTime\",\"formatter\":5},{\"columnMatch\":\"ResolutionTime (hours)\",\"formatter\":4,\"formatOptions\":{\"min\":-1,\"palette\":\"orange\",\"customColumnWidthSetting\":\"26ch\"}}],\"filter\":true,\"sortBy\":[{\"itemKey\":\"$gen_link_TrackingId_1\",\"sortOrder\":1}]},\"sortBy\":[{\"itemKey\":\"$gen_link_TrackingId_1\",\"sortOrder\":1}]},\"name\":\"query - 0\",\"styleSettings\":{\"showBorder\":true}},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"AzureActivity\\r\\n| where CategoryValue == \\\"ServiceHealth\\\"\\r\\n| extend TrackingId = tostring(Properties_d.trackingId)\\r\\n| where TrackingId in ({TrackingID_P:value}) or '{TrackingID_P:label}'=='All'\\r\\n| summarize ImpactedSubscriptions=make_set(SubscriptionId) by TrackingId\\r\\n| project ImpactedSubscriptions, TrackingId\\r\\n| mv-expand ImpactedSubscriptions\\r\\n| project Subscription=strcat('/subscriptions/',ImpactedSubscriptions), TrackingId\\r\\n| extend Info=strcat('https://app.azure.com/h/',TrackingId)\\r\\n| order by TrackingId asc\",\"size\":0,\"showAnalytics\":true,\"title\":\"Affected subscriptions\",\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"crossComponentResources\":[\"{LAworkspace}\"],\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"TrackingId\",\"formatter\":1,\"formatOptions\":{\"linkColumn\":\"Info\",\"linkTarget\":\"Url\"}},{\"columnMatch\":\"Info\",\"formatter\":5,\"formatOptions\":{\"linkTarget\":\"Url\",\"linkLabel\":\"Shareable link\"}}],\"filter\":true}},\"customWidth\":\"50\",\"name\":\"query - 2\",\"styleSettings\":{\"showBorder\":true}},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"AzureActivity\\r\\n| where CategoryValue == \\\"ServiceHealth\\\"\\r\\n| extend TrackingId = tostring(Properties_d.trackingId)\\r\\n| where TrackingId in ({TrackingID_P:value}) or '{TrackingID_P:label}'=='All'\\r\\n| extend ImpactedRegions = tostring(parse_json(tostring(parse_json(tostring(parse_json(Properties).impactedServices))[0].ImpactedRegions)))\\r\\n| project todynamic(ImpactedRegions), TrackingId\\r\\n| mv-expand ImpactedRegions\\r\\n| project Region=strcat(tostring(ImpactedRegions.RegionName),' (',tostring(ImpactedRegions.RegionId),')'),TrackingId\\r\\n| distinct Region, TrackingId\\r\\n| extend Info=strcat('https://app.azure.com/h/', TrackingId)\\r\\n| order by TrackingId asc\\r\\n\",\"size\":0,\"showAnalytics\":true,\"title\":\"Affected regions\",\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"crossComponentResources\":[\"{LAworkspace}\"],\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"TrackingId\",\"formatter\":1,\"formatOptions\":{\"linkColumn\":\"Info\",\"linkTarget\":\"Url\"}},{\"columnMatch\":\"Info\",\"formatter\":5}],\"filter\":true}},\"customWidth\":\"50\",\"name\":\"query - 1\",\"styleSettings\":{\"showBorder\":true}}]},\"name\":\"GroupActivityLogs01\",\"styleSettings\":{\"showBorder\":true}}],\"fromTemplateId\":\"sentinel-AzureServiceHealthWorkbook\",\"$schema\":\"https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json\"}\n",
"version": "1.0",
"sourceId": "[variables('workspaceResourceId')]",
"category": "sentinel"
@@ -3614,19 +3682,20 @@
"contentProductId": "[variables('_workbookcontentProductId2')]",
"id": "[variables('_workbookcontentProductId2')]",
"version": "[variables('workbookVersion2')]"
- }
+ },
+ "condition": "[parameters('DeployWorkbook')]"
},
{
"type": "Microsoft.OperationalInsights/workspaces/providers/contentPackages",
"apiVersion": "2023-04-01-preview",
"location": "[parameters('workspace-location')]",
"properties": {
- "version": "3.0.4",
+ "version": "3.1.2",
"kind": "Solution",
"contentSchemaVersion": "3.0.0",
"displayName": "Azure Activity",
"publisherDisplayName": "Microsoft Sentinel, Microsoft Corporation",
- "descriptionHtml": "
Note: Please refer to the following before installing the solution:
\n• Review the solution Release Notes
\n• There may be known issues pertaining to this Solution, please refer to them before installing.
\nThe Azure Activity solution for Microsoft Sentinel enables you to ingest Azure Activity Administrative, Security, Service Health, Alert, Recommendation, Policy, Autoscale and Resource Health logs using Diagnostic Settings into Microsoft Sentinel.
\nData Connectors: 1, Workbooks: 2, Analytic Rules: 14, Hunting Queries: 15
\nLearn more about Microsoft Sentinel | Learn more about Solutions
\n", + "descriptionHtml": "Note: Please refer to the following before installing the solution:
\n• Review the solution Release Notes
\n• There may be known issues pertaining to this Solution, please refer to them before installing.
\nThe Azure Activity solution for Microsoft Sentinel enables you to ingest Azure Activity Administrative, Security, Service Health, Alert, Recommendation, Policy, Autoscale and Resource Health logs using Diagnostic Settings into Microsoft Sentinel.
\nData Connectors: 1, Workbooks: 2, Analytic Rules: 14, XDR Detections: 14, Hunting Queries: 15
\nLearn more about Microsoft Sentinel | Learn more about Solutions
\n", "contentKind": "Solution", "contentProductId": "[variables('_solutioncontentProductId')]", "id": "[variables('_solutioncontentProductId')]", @@ -3810,6 +3879,76 @@ "kind": "Workbook", "contentId": "[variables('_workbookContentId2')]", "version": "[variables('workbookVersion2')]" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-88f453ff-7b9e-45bb-8c12-4058ca5e44ee", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-86a036b2-3686-42eb-b417-909fc0867771", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-d9938c3b-16f9-444d-bc22-ea9a9110e0fd", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-361dd1e3-1c11-491e-82a3-bb2e44ac36ba", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-9736e5f1-7b6e-4bfb-a708-e53ff1d182c3", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-b2c15736-b9eb-4dae-8b02-3016b6a45a32", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-68c89998-8052-4c80-a1f6-9d81060b6d57", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-ec491363-5fe7-4eff-b68e-f42dcb76fcf6", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-56fe0db0-6779-46fa-b3c5-006082a53064", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-6d7214d9-4a28-44df-aafb-0910b9e6ae3e", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-9fb57e58-3ed8-4b89-afcf-c8e786508b1c", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-23de46ea-c425-4a77-b456-511ae4855d69", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-48c026d8-7f36-4a95-9568-6f1420d66e37", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-ed43bdb7-eaab-4ea4-be52-6951fcfa7e3b", + "version": "3.1.0" } ] }, @@ -3824,6 +3963,2433 @@ } }, "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/', variables('_solutionId'))]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "AzureActivity-CD-xdr-88f453ff-7b9e-45bb-8c12-4058ca5e44ee", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "status": "disabled", + "detectionAction": { + "alertTemplate": { + "tactics": [ + { + "tactic": "DefenseEvasion", + "techniques": [ + { + "technique": "T1578" + } + ] + } + ], + "severity": "medium", + "title": "Microsoft Entra ID Hybrid Health AD FS New Server", + "entityMappings": { + "ips": [ + { + "addressColumn": "CallerIpAddress", + "id": "[if(true(), 'ip1', 'ip1')]" + } + ], + "accounts": [ + { + "upnSuffixColumn": "UPNSuffix", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "Name" + } + ] + }, + "description": "'This detection uses AzureActivity logs (Administrative category) to identify the creation or update of a server instance in an Microsoft Entra ID Hybrid Health AD FS service.\nA threat actor can create a new AD Health ADFS service and create a fake server instance to spoof AD FS signing logs. There is no need to compromise an on-premises AD FS server.\nThis can be done programmatically via HTTP requests to Azure. More information in this blog: https://o365blog.com/post/hybridhealthagent/'" + } + }, + "displayName": "Microsoft Entra ID Hybrid Health AD FS New Server", + "queryCondition": { + "queryText": "AzureActivity\n| where CategoryValue =~ 'Administrative'\n| where ResourceProviderValue =~ 'Microsoft.ADHybridHealthService'\n| where _ResourceId has 'AdFederationService'\n| where OperationNameValue =~ 'Microsoft.ADHybridHealthService/services/servicemembers/action'\n| extend claimsJson = parse_json(Claims)\n| extend AppId = tostring(claimsJson.appid), AccountName = tostring(claimsJson.name), Name = tostring(split(Caller,'@',0)[0]), UPNSuffix = tostring(split(Caller,'@',1)[0])\n| project-away claimsJson" + }, + "id": "[if(true(), 'xdr-88f453ff-7b9e-45bb-8c12-4058ca5e44ee', 'xdr-88f453ff-7b9e-45bb-8c12-4058ca5e44ee')]", + "schedule": { + "frequency": "P1D" + } + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-88f453ff-7b9e-45bb-8c12-4058ca5e44ee')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'AzureActivity-CD-xdr-88f453ff-7b9e-45bb-8c12-4058ca5e44ee')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'This detection uses AzureActivity logs (Administrative category) to identify the creation or update of a server instance in an Microsoft Entra ID Hybrid Health AD FS service.\nA threat actor can create a new AD Health ADFS service and create a fake server instance to spoof AD FS signing logs. There is no need to compromise an on-premises AD FS server.\nThis can be done programmatically via HTTP requests to Azure. More information in this blog: https://o365blog.com/post/hybridhealthagent/'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "status": "disabled", + "detectionAction": { + "alertTemplate": { + "tactics": [ + { + "tactic": "DefenseEvasion", + "techniques": [ + { + "technique": "T1578" + } + ] + } + ], + "severity": "medium", + "title": "Microsoft Entra ID Hybrid Health AD FS New Server", + "entityMappings": { + "ips": [ + { + "addressColumn": "CallerIpAddress", + "id": "[if(true(), 'ip1', 'ip1')]" + } + ], + "accounts": [ + { + "upnSuffixColumn": "UPNSuffix", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "Name" + } + ] + }, + "description": "'This detection uses AzureActivity logs (Administrative category) to identify the creation or update of a server instance in an Microsoft Entra ID Hybrid Health AD FS service.\nA threat actor can create a new AD Health ADFS service and create a fake server instance to spoof AD FS signing logs. There is no need to compromise an on-premises AD FS server.\nThis can be done programmatically via HTTP requests to Azure. More information in this blog: https://o365blog.com/post/hybridhealthagent/'" + } + }, + "displayName": "Microsoft Entra ID Hybrid Health AD FS New Server", + "queryCondition": { + "queryText": "AzureActivity\n| where CategoryValue =~ 'Administrative'\n| where ResourceProviderValue =~ 'Microsoft.ADHybridHealthService'\n| where _ResourceId has 'AdFederationService'\n| where OperationNameValue =~ 'Microsoft.ADHybridHealthService/services/servicemembers/action'\n| extend claimsJson = parse_json(Claims)\n| extend AppId = tostring(claimsJson.appid), AccountName = tostring(claimsJson.name), Name = tostring(split(Caller,'@',0)[0]), UPNSuffix = tostring(split(Caller,'@',1)[0])\n| project-away claimsJson" + }, + "id": "[if(true(), 'xdr-88f453ff-7b9e-45bb-8c12-4058ca5e44ee', 'xdr-88f453ff-7b9e-45bb-8c12-4058ca5e44ee')]", + "schedule": { + "frequency": "P1D" + } + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-88f453ff-7b9e-45bb-8c12-4058ca5e44ee", + "contentKind": "CustomDetection", + "displayName": "Microsoft Entra ID Hybrid Health AD FS New Server", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-88f453ff-7b9e-45bb-8c12-4058ca5e44ee','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-88f453ff-7b9e-45bb-8c12-4058ca5e44ee','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "AzureActivity-CD-xdr-86a036b2-3686-42eb-b417-909fc0867771", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "status": "disabled", + "detectionAction": { + "alertTemplate": { + "tactics": [ + { + "tactic": "DefenseEvasion", + "techniques": [ + { + "technique": "T1578", + "subTechniques": [ + "T1578.003" + ] + } + ] + } + ], + "severity": "medium", + "title": "Microsoft Entra ID Hybrid Health AD FS Service Delete", + "entityMappings": { + "ips": [ + { + "addressColumn": "CallerIpAddress", + "id": "[if(true(), 'ip1', 'ip1')]" + } + ], + "accounts": [ + { + "upnSuffixColumn": "UPNSuffix", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "Name" + } + ] + }, + "description": "'This detection uses AzureActivity logs (Administrative category) to identify the deletion of an Microsoft Entra ID Hybrid Health AD FS service instance in a tenant.\nA threat actor can create a new AD Health ADFS service and create a fake server to spoof AD FS signing logs.\nThe health AD FS service can then be deleted after it is no longer needed via HTTP requests to Azure.\nMore information is available in this blog https://o365blog.com/post/hybridhealthagent/'" + } + }, + "displayName": "Microsoft Entra ID Hybrid Health AD FS Service Delete", + "queryCondition": { + "queryText": "AzureActivity\n| where CategoryValue =~ 'Administrative'\n| where ResourceProviderValue =~ 'Microsoft.ADHybridHealthService'\n| where _ResourceId has 'AdFederationService'\n| where OperationNameValue =~ 'Microsoft.ADHybridHealthService/services/delete'\n| extend claimsJson = parse_json(Claims)\n| extend AppId = tostring(claimsJson.appid), AccountName = tostring(claimsJson.name), Name = tostring(split(Caller,'@',0)[0]), UPNSuffix = tostring(split(Caller,'@',1)[0])\n| project-away claimsJson" + }, + "id": "[if(true(), 'xdr-86a036b2-3686-42eb-b417-909fc0867771', 'xdr-86a036b2-3686-42eb-b417-909fc0867771')]", + "schedule": { + "frequency": "P1D" + } + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-86a036b2-3686-42eb-b417-909fc0867771')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'AzureActivity-CD-xdr-86a036b2-3686-42eb-b417-909fc0867771')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'This detection uses AzureActivity logs (Administrative category) to identify the deletion of an Microsoft Entra ID Hybrid Health AD FS service instance in a tenant.\nA threat actor can create a new AD Health ADFS service and create a fake server to spoof AD FS signing logs.\nThe health AD FS service can then be deleted after it is no longer needed via HTTP requests to Azure.\nMore information is available in this blog https://o365blog.com/post/hybridhealthagent/'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "status": "disabled", + "detectionAction": { + "alertTemplate": { + "tactics": [ + { + "tactic": "DefenseEvasion", + "techniques": [ + { + "technique": "T1578", + "subTechniques": [ + "T1578.003" + ] + } + ] + } + ], + "severity": "medium", + "title": "Microsoft Entra ID Hybrid Health AD FS Service Delete", + "entityMappings": { + "ips": [ + { + "addressColumn": "CallerIpAddress", + "id": "[if(true(), 'ip1', 'ip1')]" + } + ], + "accounts": [ + { + "upnSuffixColumn": "UPNSuffix", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "Name" + } + ] + }, + "description": "'This detection uses AzureActivity logs (Administrative category) to identify the deletion of an Microsoft Entra ID Hybrid Health AD FS service instance in a tenant.\nA threat actor can create a new AD Health ADFS service and create a fake server to spoof AD FS signing logs.\nThe health AD FS service can then be deleted after it is no longer needed via HTTP requests to Azure.\nMore information is available in this blog https://o365blog.com/post/hybridhealthagent/'" + } + }, + "displayName": "Microsoft Entra ID Hybrid Health AD FS Service Delete", + "queryCondition": { + "queryText": "AzureActivity\n| where CategoryValue =~ 'Administrative'\n| where ResourceProviderValue =~ 'Microsoft.ADHybridHealthService'\n| where _ResourceId has 'AdFederationService'\n| where OperationNameValue =~ 'Microsoft.ADHybridHealthService/services/delete'\n| extend claimsJson = parse_json(Claims)\n| extend AppId = tostring(claimsJson.appid), AccountName = tostring(claimsJson.name), Name = tostring(split(Caller,'@',0)[0]), UPNSuffix = tostring(split(Caller,'@',1)[0])\n| project-away claimsJson" + }, + "id": "[if(true(), 'xdr-86a036b2-3686-42eb-b417-909fc0867771', 'xdr-86a036b2-3686-42eb-b417-909fc0867771')]", + "schedule": { + "frequency": "P1D" + } + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-86a036b2-3686-42eb-b417-909fc0867771", + "contentKind": "CustomDetection", + "displayName": "Microsoft Entra ID Hybrid Health AD FS Service Delete", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-86a036b2-3686-42eb-b417-909fc0867771','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-86a036b2-3686-42eb-b417-909fc0867771','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "AzureActivity-CD-xdr-d9938c3b-16f9-444d-bc22-ea9a9110e0fd", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "status": "disabled", + "detectionAction": { + "alertTemplate": { + "tactics": [ + { + "tactic": "CredentialAccess", + "techniques": [ + { + "technique": "T1528" + } + ] + } + ], + "severity": "medium", + "title": "Microsoft Entra ID Hybrid Health AD FS Suspicious Application", + "entityMappings": { + "ips": [ + { + "addressColumn": "CallerIpAddress", + "id": "[if(true(), 'ip1', 'ip1')]" + } + ], + "accounts": [ + { + "upnSuffixColumn": "UPNSuffix", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "Name" + } + ] + }, + "description": "'This detection uses AzureActivity logs (Administrative category) to identify a suspicious application adding a server instance to an Microsoft Entra ID Hybrid Health AD FS service or deleting the AD FS service instance.\nUsually the Microsoft Entra ID Connect Health Agent application with ID cf6d7e68-f018-4e0a-a7b3-126e053fb88d and ID cb1056e2-e479-49de-ae31-7812af012ed8 is used to perform those operations.'" + } + }, + "displayName": "Microsoft Entra ID Hybrid Health AD FS Suspicious Application", + "queryCondition": { + "queryText": "// Microsoft Entra ID Connect Health Agent - cf6d7e68-f018-4e0a-a7b3-126e053fb88d\n// Microsoft Entra ID Connect - cb1056e2-e479-49de-ae31-7812af012ed8\nlet appList = dynamic(['cf6d7e68-f018-4e0a-a7b3-126e053fb88d','cb1056e2-e479-49de-ae31-7812af012ed8']);\nlet operationNamesList = dynamic(['Microsoft.ADHybridHealthService/services/servicemembers/action','Microsoft.ADHybridHealthService/services/delete']);\nAzureActivity\n| where CategoryValue =~ 'Administrative'\n| where ResourceProviderValue =~ 'Microsoft.ADHybridHealthService'\n| where _ResourceId has 'AdFederationService'\n| where OperationNameValue in~ (operationNamesList)\n| extend claimsJson = parse_json(Claims)\n| extend AppId = tostring(claimsJson.appid), AccountName = tostring(claimsJson.name), Name = tostring(split(Caller,'@',0)[0]), UPNSuffix = tostring(split(Caller,'@',1)[0])\n| where AppId !in (appList)\n| project-away claimsJson" + }, + "id": "[if(true(), 'xdr-d9938c3b-16f9-444d-bc22-ea9a9110e0fd', 'xdr-d9938c3b-16f9-444d-bc22-ea9a9110e0fd')]", + "schedule": { + "frequency": "P1D" + } + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-d9938c3b-16f9-444d-bc22-ea9a9110e0fd')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'AzureActivity-CD-xdr-d9938c3b-16f9-444d-bc22-ea9a9110e0fd')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'This detection uses AzureActivity logs (Administrative category) to identify a suspicious application adding a server instance to an Microsoft Entra ID Hybrid Health AD FS service or deleting the AD FS service instance.\nUsually the Microsoft Entra ID Connect Health Agent application with ID cf6d7e68-f018-4e0a-a7b3-126e053fb88d and ID cb1056e2-e479-49de-ae31-7812af012ed8 is used to perform those operations.'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "status": "disabled", + "detectionAction": { + "alertTemplate": { + "tactics": [ + { + "tactic": "CredentialAccess", + "techniques": [ + { + "technique": "T1528" + } + ] + } + ], + "severity": "medium", + "title": "Microsoft Entra ID Hybrid Health AD FS Suspicious Application", + "entityMappings": { + "ips": [ + { + "addressColumn": "CallerIpAddress", + "id": "[if(true(), 'ip1', 'ip1')]" + } + ], + "accounts": [ + { + "upnSuffixColumn": "UPNSuffix", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "Name" + } + ] + }, + "description": "'This detection uses AzureActivity logs (Administrative category) to identify a suspicious application adding a server instance to an Microsoft Entra ID Hybrid Health AD FS service or deleting the AD FS service instance.\nUsually the Microsoft Entra ID Connect Health Agent application with ID cf6d7e68-f018-4e0a-a7b3-126e053fb88d and ID cb1056e2-e479-49de-ae31-7812af012ed8 is used to perform those operations.'" + } + }, + "displayName": "Microsoft Entra ID Hybrid Health AD FS Suspicious Application", + "queryCondition": { + "queryText": "// Microsoft Entra ID Connect Health Agent - cf6d7e68-f018-4e0a-a7b3-126e053fb88d\n// Microsoft Entra ID Connect - cb1056e2-e479-49de-ae31-7812af012ed8\nlet appList = dynamic(['cf6d7e68-f018-4e0a-a7b3-126e053fb88d','cb1056e2-e479-49de-ae31-7812af012ed8']);\nlet operationNamesList = dynamic(['Microsoft.ADHybridHealthService/services/servicemembers/action','Microsoft.ADHybridHealthService/services/delete']);\nAzureActivity\n| where CategoryValue =~ 'Administrative'\n| where ResourceProviderValue =~ 'Microsoft.ADHybridHealthService'\n| where _ResourceId has 'AdFederationService'\n| where OperationNameValue in~ (operationNamesList)\n| extend claimsJson = parse_json(Claims)\n| extend AppId = tostring(claimsJson.appid), AccountName = tostring(claimsJson.name), Name = tostring(split(Caller,'@',0)[0]), UPNSuffix = tostring(split(Caller,'@',1)[0])\n| where AppId !in (appList)\n| project-away claimsJson" + }, + "id": "[if(true(), 'xdr-d9938c3b-16f9-444d-bc22-ea9a9110e0fd', 'xdr-d9938c3b-16f9-444d-bc22-ea9a9110e0fd')]", + "schedule": { + "frequency": "P1D" + } + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-d9938c3b-16f9-444d-bc22-ea9a9110e0fd", + "contentKind": "CustomDetection", + "displayName": "Microsoft Entra ID Hybrid Health AD FS Suspicious Application", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-d9938c3b-16f9-444d-bc22-ea9a9110e0fd','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-d9938c3b-16f9-444d-bc22-ea9a9110e0fd','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "AzureActivity-CD-xdr-361dd1e3-1c11-491e-82a3-bb2e44ac36ba", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "status": "disabled", + "detectionAction": { + "alertTemplate": { + "tactics": [ + { + "tactic": "Impact", + "techniques": [ + { + "technique": "T1496" + } + ] + } + ], + "severity": "medium", + "title": "Suspicious number of resource creation or deployment activities", + "entityMappings": { + "ips": [ + { + "addressColumn": "CallerIpAddress", + "id": "[if(true(), 'ip1', 'ip1')]" + } + ], + "accounts": [ + { + "upnSuffixColumn": "UPNSuffix", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "Name" + }, + { + "aadUserIdColumn": "AadUserId", + "id": "[if(true(), 'account2', 'account2')]" + } + ] + }, + "description": "'Indicates when an anomalous number of VM creations or deployment activities occur in Azure via the AzureActivity log. This query generates the baseline pattern of cloud resource creation by an individual and generates an anomaly when any unusual spike is detected. These anomalies from unusual or privileged users could be an indication of a cloud infrastructure takedown by an adversary.'" + } + }, + "displayName": "Suspicious number of resource creation or deployment activities", + "queryCondition": { + "queryText": "let szOperationNames = dynamic([\"microsoft.compute/virtualMachines/write\", \"microsoft.resources/deployments/write\"]);\nlet starttime = 7d;\nlet endtime = 1d;\nlet timeframe = 1d;\nlet TimeSeriesData =\nAzureActivity\n| where TimeGenerated between (startofday(ago(starttime)) .. startofday(now()))\n| where OperationNameValue in~ (szOperationNames)\n| project TimeGenerated, Caller\n| make-series Total = count() on TimeGenerated from startofday(ago(starttime)) to startofday(now()) step timeframe by Caller;\nTimeSeriesData\n| extend (anomalies, score, baseline) = series_decompose_anomalies(Total, 3, -1, 'linefit')\n| mv-expand Total to typeof(double), TimeGenerated to typeof(datetime), anomalies to typeof(double), score to typeof(double), baseline to typeof(long)\n| where TimeGenerated >= startofday(ago(endtime))\n| where anomalies > 0 and baseline > 0\n| project Caller, TimeGenerated, Total, baseline, anomalies, score\n| join (AzureActivity\n| where TimeGenerated > startofday(ago(endtime))\n| where OperationNameValue in~ (szOperationNames)\n| summarize make_set(OperationNameValue,100), make_set(_ResourceId,100), make_set(CallerIpAddress,100) by bin(TimeGenerated, timeframe), Caller\n) on TimeGenerated, Caller\n| mv-expand CallerIpAddress=set_CallerIpAddress\n| project-away Caller1\n| extend Name = iif(Caller has '@',tostring(split(Caller,'@',0)[0]),\"\")\n| extend UPNSuffix = iif(Caller has '@',tostring(split(Caller,'@',1)[0]),\"\")\n| extend AadUserId = iif(Caller !has '@',Caller,\"\")" + }, + "id": "[if(true(), 'xdr-361dd1e3-1c11-491e-82a3-bb2e44ac36ba', 'xdr-361dd1e3-1c11-491e-82a3-bb2e44ac36ba')]", + "schedule": { + "frequency": "P1D" + } + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-361dd1e3-1c11-491e-82a3-bb2e44ac36ba')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'AzureActivity-CD-xdr-361dd1e3-1c11-491e-82a3-bb2e44ac36ba')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'Indicates when an anomalous number of VM creations or deployment activities occur in Azure via the AzureActivity log. This query generates the baseline pattern of cloud resource creation by an individual and generates an anomaly when any unusual spike is detected. These anomalies from unusual or privileged users could be an indication of a cloud infrastructure takedown by an adversary.'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "status": "disabled", + "detectionAction": { + "alertTemplate": { + "tactics": [ + { + "tactic": "Impact", + "techniques": [ + { + "technique": "T1496" + } + ] + } + ], + "severity": "medium", + "title": "Suspicious number of resource creation or deployment activities", + "entityMappings": { + "ips": [ + { + "addressColumn": "CallerIpAddress", + "id": "[if(true(), 'ip1', 'ip1')]" + } + ], + "accounts": [ + { + "upnSuffixColumn": "UPNSuffix", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "Name" + }, + { + "aadUserIdColumn": "AadUserId", + "id": "[if(true(), 'account2', 'account2')]" + } + ] + }, + "description": "'Indicates when an anomalous number of VM creations or deployment activities occur in Azure via the AzureActivity log. This query generates the baseline pattern of cloud resource creation by an individual and generates an anomaly when any unusual spike is detected. These anomalies from unusual or privileged users could be an indication of a cloud infrastructure takedown by an adversary.'" + } + }, + "displayName": "Suspicious number of resource creation or deployment activities", + "queryCondition": { + "queryText": "let szOperationNames = dynamic([\"microsoft.compute/virtualMachines/write\", \"microsoft.resources/deployments/write\"]);\nlet starttime = 7d;\nlet endtime = 1d;\nlet timeframe = 1d;\nlet TimeSeriesData =\nAzureActivity\n| where TimeGenerated between (startofday(ago(starttime)) .. startofday(now()))\n| where OperationNameValue in~ (szOperationNames)\n| project TimeGenerated, Caller\n| make-series Total = count() on TimeGenerated from startofday(ago(starttime)) to startofday(now()) step timeframe by Caller;\nTimeSeriesData\n| extend (anomalies, score, baseline) = series_decompose_anomalies(Total, 3, -1, 'linefit')\n| mv-expand Total to typeof(double), TimeGenerated to typeof(datetime), anomalies to typeof(double), score to typeof(double), baseline to typeof(long)\n| where TimeGenerated >= startofday(ago(endtime))\n| where anomalies > 0 and baseline > 0\n| project Caller, TimeGenerated, Total, baseline, anomalies, score\n| join (AzureActivity\n| where TimeGenerated > startofday(ago(endtime))\n| where OperationNameValue in~ (szOperationNames)\n| summarize make_set(OperationNameValue,100), make_set(_ResourceId,100), make_set(CallerIpAddress,100) by bin(TimeGenerated, timeframe), Caller\n) on TimeGenerated, Caller\n| mv-expand CallerIpAddress=set_CallerIpAddress\n| project-away Caller1\n| extend Name = iif(Caller has '@',tostring(split(Caller,'@',0)[0]),\"\")\n| extend UPNSuffix = iif(Caller has '@',tostring(split(Caller,'@',1)[0]),\"\")\n| extend AadUserId = iif(Caller !has '@',Caller,\"\")" + }, + "id": "[if(true(), 'xdr-361dd1e3-1c11-491e-82a3-bb2e44ac36ba', 'xdr-361dd1e3-1c11-491e-82a3-bb2e44ac36ba')]", + "schedule": { + "frequency": "P1D" + } + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-361dd1e3-1c11-491e-82a3-bb2e44ac36ba", + "contentKind": "CustomDetection", + "displayName": "Suspicious number of resource creation or deployment activities", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-361dd1e3-1c11-491e-82a3-bb2e44ac36ba','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-361dd1e3-1c11-491e-82a3-bb2e44ac36ba','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "AzureActivity-CD-xdr-9736e5f1-7b6e-4bfb-a708-e53ff1d182c3", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "status": "disabled", + "detectionAction": { + "alertTemplate": { + "entityMappings": { + "hosts": [ + { + "nameColumn": "ComputerName", + "id": "[if(true(), 'host1', 'host1')]" + } + ], + "accounts": [ + { + "upnSuffixColumn": "UPNSuffix", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "Name" + } + ], + "ips": [ + { + "addressColumn": "CallerIpAddress", + "id": "[if(true(), 'ip1', 'ip1')]" + } + ] + }, + "customDetails": { + "AccountFullName": "Caller" + }, + "severity": "low", + "title": "Creation of expensive computes in Azure", + "description": "'Identifies the creation of large size or expensive VMs (with GPUs or with a large number of virtual CPUs) in Azure.\nAn adversary may create new or update existing virtual machines to evade defenses or use them for cryptomining purposes.\nFor Windows/Linux Vm Sizes, see https://docs.microsoft.com/azure/virtual-machines/windows/sizes \nAzure VM Naming Conventions, see https://docs.microsoft.com/azure/virtual-machines/vm-naming-conventions'", + "tactics": [ + { + "tactic": "DefenseEvasion", + "techniques": [ + { + "technique": "T1578" + } + ] + } + ] + } + }, + "displayName": "Creation of expensive computes in Azure", + "queryCondition": { + "queryText": "let tokens = dynamic([\"416\",\"208\",\"192\",\"128\",\"120\",\"96\",\"80\",\"72\",\"64\",\"48\",\"44\",\"40\",\"nc12\",\"nc24\",\"nv24\"]);\nlet operationList = dynamic([\"microsoft.compute/virtualmachines/write\", \"microsoft.resources/deployments/write\"]);\nAzureActivity\n| where OperationNameValue in~ (operationList)\n| where ActivityStatusValue startswith \"Accept\"\n| where Properties has 'vmSize'\n| extend parsed_property= parse_json(tostring((parse_json(Properties).responseBody))).properties\n| extend vmSize = tostring((parsed_property.hardwareProfile).vmSize)\n| mv-apply token=tokens to typeof(string) on (where vmSize contains token)\n| extend ComputerName = tostring((parsed_property.osProfile).computerName)\n| project TimeGenerated, OperationNameValue, ActivityStatusValue, Caller, CallerIpAddress, ComputerName, vmSize\n| extend Name = tostring(split(Caller,'@',0)[0]), UPNSuffix = tostring(split(Caller,'@',1)[0])" + }, + "id": "[if(true(), 'xdr-9736e5f1-7b6e-4bfb-a708-e53ff1d182c3', 'xdr-9736e5f1-7b6e-4bfb-a708-e53ff1d182c3')]", + "schedule": { + "frequency": "P1D" + } + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-9736e5f1-7b6e-4bfb-a708-e53ff1d182c3')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'AzureActivity-CD-xdr-9736e5f1-7b6e-4bfb-a708-e53ff1d182c3')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'Identifies the creation of large size or expensive VMs (with GPUs or with a large number of virtual CPUs) in Azure.\nAn adversary may create new or update existing virtual machines to evade defenses or use them for cryptomining purposes.\nFor Windows/Linux Vm Sizes, see https://docs.microsoft.com/azure/virtual-machines/windows/sizes \nAzure VM Naming Conventions, see https://docs.microsoft.com/azure/virtual-machines/vm-naming-conventions'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "status": "disabled", + "detectionAction": { + "alertTemplate": { + "entityMappings": { + "hosts": [ + { + "nameColumn": "ComputerName", + "id": "[if(true(), 'host1', 'host1')]" + } + ], + "accounts": [ + { + "upnSuffixColumn": "UPNSuffix", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "Name" + } + ], + "ips": [ + { + "addressColumn": "CallerIpAddress", + "id": "[if(true(), 'ip1', 'ip1')]" + } + ] + }, + "customDetails": { + "AccountFullName": "Caller" + }, + "severity": "low", + "title": "Creation of expensive computes in Azure", + "description": "'Identifies the creation of large size or expensive VMs (with GPUs or with a large number of virtual CPUs) in Azure.\nAn adversary may create new or update existing virtual machines to evade defenses or use them for cryptomining purposes.\nFor Windows/Linux Vm Sizes, see https://docs.microsoft.com/azure/virtual-machines/windows/sizes \nAzure VM Naming Conventions, see https://docs.microsoft.com/azure/virtual-machines/vm-naming-conventions'", + "tactics": [ + { + "tactic": "DefenseEvasion", + "techniques": [ + { + "technique": "T1578" + } + ] + } + ] + } + }, + "displayName": "Creation of expensive computes in Azure", + "queryCondition": { + "queryText": "let tokens = dynamic([\"416\",\"208\",\"192\",\"128\",\"120\",\"96\",\"80\",\"72\",\"64\",\"48\",\"44\",\"40\",\"nc12\",\"nc24\",\"nv24\"]);\nlet operationList = dynamic([\"microsoft.compute/virtualmachines/write\", \"microsoft.resources/deployments/write\"]);\nAzureActivity\n| where OperationNameValue in~ (operationList)\n| where ActivityStatusValue startswith \"Accept\"\n| where Properties has 'vmSize'\n| extend parsed_property= parse_json(tostring((parse_json(Properties).responseBody))).properties\n| extend vmSize = tostring((parsed_property.hardwareProfile).vmSize)\n| mv-apply token=tokens to typeof(string) on (where vmSize contains token)\n| extend ComputerName = tostring((parsed_property.osProfile).computerName)\n| project TimeGenerated, OperationNameValue, ActivityStatusValue, Caller, CallerIpAddress, ComputerName, vmSize\n| extend Name = tostring(split(Caller,'@',0)[0]), UPNSuffix = tostring(split(Caller,'@',1)[0])" + }, + "id": "[if(true(), 'xdr-9736e5f1-7b6e-4bfb-a708-e53ff1d182c3', 'xdr-9736e5f1-7b6e-4bfb-a708-e53ff1d182c3')]", + "schedule": { + "frequency": "P1D" + } + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-9736e5f1-7b6e-4bfb-a708-e53ff1d182c3", + "contentKind": "CustomDetection", + "displayName": "Creation of expensive computes in Azure", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-9736e5f1-7b6e-4bfb-a708-e53ff1d182c3','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-9736e5f1-7b6e-4bfb-a708-e53ff1d182c3','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "AzureActivity-CD-xdr-b2c15736-b9eb-4dae-8b02-3016b6a45a32", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "status": "disabled", + "detectionAction": { + "alertTemplate": { + "entityMappings": { + "ips": [ + { + "addressColumn": "CallerIpAddress", + "id": "[if(true(), 'ip1', 'ip1')]" + } + ], + "accounts": [ + { + "upnSuffixColumn": "UPNSuffix", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "Name" + } + ] + }, + "customDetails": { + "AccountFullName": "Caller" + }, + "severity": "medium", + "title": "Suspicious granting of permissions to an account", + "description": "'Identifies IPs from which users grant access to other users on Azure resources and alerts when a previously unseen source IP address is used.'", + "tactics": [ + { + "tactic": "Persistence", + "techniques": [ + { + "technique": "T1098" + } + ] + } + ] + } + }, + "displayName": "Suspicious granting of permissions to an account", + "queryCondition": { + "queryText": "let starttime = 14d;\nlet endtime = 1d;\n// The number of operations above which an IP address is considered an unusual source of role assignment operations\nlet alertOperationThreshold = 5;\nlet AzureBuiltInRole = externaldata(Role:string,RoleDescription:string,ID:string) [@\"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Feeds/AzureBuiltInRole.csv\"] with (format=\"csv\", ignoreFirstRecord=True);\nlet createRoleAssignmentActivity = AzureActivity\n| where OperationNameValue =~ \"microsoft.authorization/roleassignments/write\";\nlet RoleAssignedActivity = createRoleAssignmentActivity\n| where TimeGenerated between (ago(starttime) .. ago(endtime))\n| summarize count() by CallerIpAddress, Caller, bin(TimeGenerated, 1d)\n| where count_ >= alertOperationThreshold\n// Returns all the records from the right side that don't have matches from the left.\n| join kind = rightanti (\ncreateRoleAssignmentActivity\n| where TimeGenerated > ago(endtime)\n| extend parsed_property = tostring(parse_json(Properties).requestbody)\n| extend PrincipalId = case(parsed_property has_cs 'PrincipalId',parse_json(parsed_property).Properties.PrincipalId, parsed_property has_cs 'principalId',parse_json(parsed_property).properties.principalId,\"\")\n| extend PrincipalType = case(parsed_property has_cs 'PrincipalType',parse_json(parsed_property).Properties.PrincipalType, parsed_property has_cs 'principalType',parse_json(parsed_property).properties.principalType, \"\")\n| extend Scope = case(parsed_property has_cs 'Scope',parse_json(parsed_property).Properties.Scope, parsed_property has_cs 'scope',parse_json(parsed_property).properties.scope,\"\")\n| extend RoleAddedDetails = case(parsed_property has_cs 'RoleDefinitionId',parse_json(parsed_property).Properties.RoleDefinitionId,parsed_property has_cs 'roleDefinitionId',parse_json(parsed_property).properties.roleDefinitionId,\"\")\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), ActivityTimeStamp = make_set(TimeGenerated), ActivityStatusValue = make_set(ActivityStatusValue), CorrelationId = make_set(CorrelationId), ActivityCountByCallerIPAddress = count()\nby ResourceId, CallerIpAddress, Caller, OperationNameValue, Resource, ResourceGroup, PrincipalId, PrincipalType, Scope, RoleAddedDetails\n) on CallerIpAddress, Caller\n| extend timestamp = StartTimeUtc, AccountCustomEntity = Caller, IPCustomEntity = CallerIpAddress;\nlet RoleAssignedActivitywithRoleDetails = RoleAssignedActivity\n| extend RoleAssignedID = tostring(split(RoleAddedDetails, \"/\")[-1])\n// Returns all matching records from left and right sides.\n| join kind = inner (AzureBuiltInRole\n) on $left.RoleAssignedID == $right.ID;\nlet CallerIPCountSummary = RoleAssignedActivitywithRoleDetails | summarize AssignmentCountbyCaller = count() by Caller, CallerIpAddress;\nlet RoleAssignedActivityWithCount = RoleAssignedActivitywithRoleDetails | join kind = inner (CallerIPCountSummary | project Caller, AssignmentCountbyCaller, CallerIpAddress) on Caller, CallerIpAddress;\nRoleAssignedActivityWithCount\n| summarize arg_max(StartTimeUtc, *) by PrincipalId, RoleAssignedID\n// \tReturns all the records from the left side and only matching records from the right side.\n| join kind = leftouter( IdentityInfo\n| summarize arg_max(TimeGenerated, *) by AccountObjectId\n) on $left.PrincipalId == $right.AccountObjectId\n// Check if assignment count is greater than the threshold.\n| where AssignmentCountbyCaller >= alertOperationThreshold\n| project ActivityTimeStamp, OperationNameValue, Caller, CallerIpAddress, PrincipalId, RoleAssignedID, RoleAddedDetails, Role, RoleDescription, AccountUPN, AccountCreationTime, GroupMembership, UserType, ActivityStatusValue, ResourceGroup, PrincipalType, Scope, CorrelationId, timestamp, AccountCustomEntity, IPCustomEntity, AssignmentCountbyCaller\n| extend Name = tostring(split(Caller,'@',0)[0]), UPNSuffix = tostring(split(Caller,'@',1)[0])" + }, + "id": "[if(true(), 'xdr-b2c15736-b9eb-4dae-8b02-3016b6a45a32', 'xdr-b2c15736-b9eb-4dae-8b02-3016b6a45a32')]", + "schedule": { + "frequency": "P1D" + } + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-b2c15736-b9eb-4dae-8b02-3016b6a45a32')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'AzureActivity-CD-xdr-b2c15736-b9eb-4dae-8b02-3016b6a45a32')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'Identifies IPs from which users grant access to other users on Azure resources and alerts when a previously unseen source IP address is used.'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "status": "disabled", + "detectionAction": { + "alertTemplate": { + "entityMappings": { + "ips": [ + { + "addressColumn": "CallerIpAddress", + "id": "[if(true(), 'ip1', 'ip1')]" + } + ], + "accounts": [ + { + "upnSuffixColumn": "UPNSuffix", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "Name" + } + ] + }, + "customDetails": { + "AccountFullName": "Caller" + }, + "severity": "medium", + "title": "Suspicious granting of permissions to an account", + "description": "'Identifies IPs from which users grant access to other users on Azure resources and alerts when a previously unseen source IP address is used.'", + "tactics": [ + { + "tactic": "Persistence", + "techniques": [ + { + "technique": "T1098" + } + ] + } + ] + } + }, + "displayName": "Suspicious granting of permissions to an account", + "queryCondition": { + "queryText": "let starttime = 14d;\nlet endtime = 1d;\n// The number of operations above which an IP address is considered an unusual source of role assignment operations\nlet alertOperationThreshold = 5;\nlet AzureBuiltInRole = externaldata(Role:string,RoleDescription:string,ID:string) [@\"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Feeds/AzureBuiltInRole.csv\"] with (format=\"csv\", ignoreFirstRecord=True);\nlet createRoleAssignmentActivity = AzureActivity\n| where OperationNameValue =~ \"microsoft.authorization/roleassignments/write\";\nlet RoleAssignedActivity = createRoleAssignmentActivity\n| where TimeGenerated between (ago(starttime) .. ago(endtime))\n| summarize count() by CallerIpAddress, Caller, bin(TimeGenerated, 1d)\n| where count_ >= alertOperationThreshold\n// Returns all the records from the right side that don't have matches from the left.\n| join kind = rightanti (\ncreateRoleAssignmentActivity\n| where TimeGenerated > ago(endtime)\n| extend parsed_property = tostring(parse_json(Properties).requestbody)\n| extend PrincipalId = case(parsed_property has_cs 'PrincipalId',parse_json(parsed_property).Properties.PrincipalId, parsed_property has_cs 'principalId',parse_json(parsed_property).properties.principalId,\"\")\n| extend PrincipalType = case(parsed_property has_cs 'PrincipalType',parse_json(parsed_property).Properties.PrincipalType, parsed_property has_cs 'principalType',parse_json(parsed_property).properties.principalType, \"\")\n| extend Scope = case(parsed_property has_cs 'Scope',parse_json(parsed_property).Properties.Scope, parsed_property has_cs 'scope',parse_json(parsed_property).properties.scope,\"\")\n| extend RoleAddedDetails = case(parsed_property has_cs 'RoleDefinitionId',parse_json(parsed_property).Properties.RoleDefinitionId,parsed_property has_cs 'roleDefinitionId',parse_json(parsed_property).properties.roleDefinitionId,\"\")\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), ActivityTimeStamp = make_set(TimeGenerated), ActivityStatusValue = make_set(ActivityStatusValue), CorrelationId = make_set(CorrelationId), ActivityCountByCallerIPAddress = count()\nby ResourceId, CallerIpAddress, Caller, OperationNameValue, Resource, ResourceGroup, PrincipalId, PrincipalType, Scope, RoleAddedDetails\n) on CallerIpAddress, Caller\n| extend timestamp = StartTimeUtc, AccountCustomEntity = Caller, IPCustomEntity = CallerIpAddress;\nlet RoleAssignedActivitywithRoleDetails = RoleAssignedActivity\n| extend RoleAssignedID = tostring(split(RoleAddedDetails, \"/\")[-1])\n// Returns all matching records from left and right sides.\n| join kind = inner (AzureBuiltInRole\n) on $left.RoleAssignedID == $right.ID;\nlet CallerIPCountSummary = RoleAssignedActivitywithRoleDetails | summarize AssignmentCountbyCaller = count() by Caller, CallerIpAddress;\nlet RoleAssignedActivityWithCount = RoleAssignedActivitywithRoleDetails | join kind = inner (CallerIPCountSummary | project Caller, AssignmentCountbyCaller, CallerIpAddress) on Caller, CallerIpAddress;\nRoleAssignedActivityWithCount\n| summarize arg_max(StartTimeUtc, *) by PrincipalId, RoleAssignedID\n// \tReturns all the records from the left side and only matching records from the right side.\n| join kind = leftouter( IdentityInfo\n| summarize arg_max(TimeGenerated, *) by AccountObjectId\n) on $left.PrincipalId == $right.AccountObjectId\n// Check if assignment count is greater than the threshold.\n| where AssignmentCountbyCaller >= alertOperationThreshold\n| project ActivityTimeStamp, OperationNameValue, Caller, CallerIpAddress, PrincipalId, RoleAssignedID, RoleAddedDetails, Role, RoleDescription, AccountUPN, AccountCreationTime, GroupMembership, UserType, ActivityStatusValue, ResourceGroup, PrincipalType, Scope, CorrelationId, timestamp, AccountCustomEntity, IPCustomEntity, AssignmentCountbyCaller\n| extend Name = tostring(split(Caller,'@',0)[0]), UPNSuffix = tostring(split(Caller,'@',1)[0])" + }, + "id": "[if(true(), 'xdr-b2c15736-b9eb-4dae-8b02-3016b6a45a32', 'xdr-b2c15736-b9eb-4dae-8b02-3016b6a45a32')]", + "schedule": { + "frequency": "P1D" + } + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-b2c15736-b9eb-4dae-8b02-3016b6a45a32", + "contentKind": "CustomDetection", + "displayName": "Suspicious granting of permissions to an account", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-b2c15736-b9eb-4dae-8b02-3016b6a45a32','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-b2c15736-b9eb-4dae-8b02-3016b6a45a32','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "AzureActivity-CD-xdr-68c89998-8052-4c80-a1f6-9d81060b6d57", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "status": "disabled", + "detectionAction": { + "alertTemplate": { + "tactics": [ + { + "tactic": "InitialAccess", + "techniques": [ + { + "technique": "T1078" + } + ] + } + ], + "severity": "low", + "title": "Azure Machine Learning Write Operations", + "entityMappings": { + "accounts": [ + { + "upnColumn": "Caller", + "id": "[if(true(), 'account1', 'account1')]" + } + ], + "azureResources": [ + { + "resourceIdColumn": "_ResourceId", + "id": "[if(true(), 'azureResource1', 'azureResource1')]" + } + ], + "ips": [ + { + "addressColumn": "CallerIpAddress", + "id": "[if(true(), 'ip1', 'ip1')]" + } + ] + }, + "description": "'Shows the most prevalent users who perform write operations on Azure Machine Learning resources. List the common source IP address for each of those accounts. If an operation is not from those IP addresses, it may be worthy of investigation.'" + } + }, + "displayName": "Azure Machine Learning Write Operations", + "queryCondition": { + "queryText": "AzureActivity\n| where ResourceProviderValue == \"MICROSOFT.MACHINELEARNINGSERVICES\" // Filter activities related to Microsoft Machine Learning Services\n| extend SCOPE = tostring(parse_json(Authorization).scope) // Parse Authorization scope as string\n| extend subname = split(Hierarchy, \"/\") // Split Hierarchy to extract Subscription Name and ID\n| extend ['Subscription Name'] = subname[-2], ['Subscription ID'] = subname[-1] // Extract Subscription Name and ID\n| extend Properties = parse_json(Properties) // Parse Properties as JSON\n| extend Properties_entity = tostring(Properties.entity) // Cast Properties.entity to string\n| where isnotempty(Properties_entity) // Filter activities where Properties.entity is not empty\n// | where Properties_entity contains \"deepseek\" // Filter activities where Properties.entity contains \"deepseek\"\n| where OperationNameValue contains \"write\" // Filter activities where OperationNameValue contains \"write\"\n| where OperationNameValue !contains \"MICROSOFT.AUTHORIZATION/ROLEASSIGNMENTS/WRITE\" // Exclude role assignments\n| extend LLM = tostring(split(Properties_entity, \"/\")[-1]) // Extract the last segment of Properties_entity and cast it to string\n| distinct TimeGenerated, tostring(['Subscription Name']), ResourceGroup, tostring(['Subscription ID']), Caller, CallerIpAddress, OperationNameValue, LLM, _ResourceId // Select distinct relevant fields for output" + }, + "id": "[if(true(), 'xdr-68c89998-8052-4c80-a1f6-9d81060b6d57', 'xdr-68c89998-8052-4c80-a1f6-9d81060b6d57')]", + "schedule": { + "frequency": "P1D" + } + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-68c89998-8052-4c80-a1f6-9d81060b6d57')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'AzureActivity-CD-xdr-68c89998-8052-4c80-a1f6-9d81060b6d57')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'Shows the most prevalent users who perform write operations on Azure Machine Learning resources. List the common source IP address for each of those accounts. If an operation is not from those IP addresses, it may be worthy of investigation.'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "status": "disabled", + "detectionAction": { + "alertTemplate": { + "tactics": [ + { + "tactic": "InitialAccess", + "techniques": [ + { + "technique": "T1078" + } + ] + } + ], + "severity": "low", + "title": "Azure Machine Learning Write Operations", + "entityMappings": { + "accounts": [ + { + "upnColumn": "Caller", + "id": "[if(true(), 'account1', 'account1')]" + } + ], + "azureResources": [ + { + "resourceIdColumn": "_ResourceId", + "id": "[if(true(), 'azureResource1', 'azureResource1')]" + } + ], + "ips": [ + { + "addressColumn": "CallerIpAddress", + "id": "[if(true(), 'ip1', 'ip1')]" + } + ] + }, + "description": "'Shows the most prevalent users who perform write operations on Azure Machine Learning resources. List the common source IP address for each of those accounts. If an operation is not from those IP addresses, it may be worthy of investigation.'" + } + }, + "displayName": "Azure Machine Learning Write Operations", + "queryCondition": { + "queryText": "AzureActivity\n| where ResourceProviderValue == \"MICROSOFT.MACHINELEARNINGSERVICES\" // Filter activities related to Microsoft Machine Learning Services\n| extend SCOPE = tostring(parse_json(Authorization).scope) // Parse Authorization scope as string\n| extend subname = split(Hierarchy, \"/\") // Split Hierarchy to extract Subscription Name and ID\n| extend ['Subscription Name'] = subname[-2], ['Subscription ID'] = subname[-1] // Extract Subscription Name and ID\n| extend Properties = parse_json(Properties) // Parse Properties as JSON\n| extend Properties_entity = tostring(Properties.entity) // Cast Properties.entity to string\n| where isnotempty(Properties_entity) // Filter activities where Properties.entity is not empty\n// | where Properties_entity contains \"deepseek\" // Filter activities where Properties.entity contains \"deepseek\"\n| where OperationNameValue contains \"write\" // Filter activities where OperationNameValue contains \"write\"\n| where OperationNameValue !contains \"MICROSOFT.AUTHORIZATION/ROLEASSIGNMENTS/WRITE\" // Exclude role assignments\n| extend LLM = tostring(split(Properties_entity, \"/\")[-1]) // Extract the last segment of Properties_entity and cast it to string\n| distinct TimeGenerated, tostring(['Subscription Name']), ResourceGroup, tostring(['Subscription ID']), Caller, CallerIpAddress, OperationNameValue, LLM, _ResourceId // Select distinct relevant fields for output" + }, + "id": "[if(true(), 'xdr-68c89998-8052-4c80-a1f6-9d81060b6d57', 'xdr-68c89998-8052-4c80-a1f6-9d81060b6d57')]", + "schedule": { + "frequency": "P1D" + } + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-68c89998-8052-4c80-a1f6-9d81060b6d57", + "contentKind": "CustomDetection", + "displayName": "Azure Machine Learning Write Operations", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-68c89998-8052-4c80-a1f6-9d81060b6d57','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-68c89998-8052-4c80-a1f6-9d81060b6d57','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "AzureActivity-CD-xdr-ec491363-5fe7-4eff-b68e-f42dcb76fcf6", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "status": "disabled", + "detectionAction": { + "alertTemplate": { + "tactics": [ + { + "tactic": "DefenseEvasion", + "techniques": [ + { + "technique": "T1578" + } + ] + } + ], + "severity": "medium", + "title": "NRT Microsoft Entra ID Hybrid Health AD FS New Server", + "entityMappings": { + "ips": [ + { + "addressColumn": "CallerIpAddress", + "id": "[if(true(), 'ip1', 'ip1')]" + } + ], + "accounts": [ + { + "upnSuffixColumn": "UPNSuffix", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "Name" + } + ] + }, + "description": "'This detection uses AzureActivity logs (Administrative category) to identify the creation or update of a server instance in an Microsoft Entra ID Hybrid Health AD FS service.\nA threat actor can create a new AD Health ADFS service and create a fake server instance to spoof AD FS signing logs. There is no need to compromise an on-premises AD FS server.\nThis can be done programmatically via HTTP requests to Azure. More information in this blog: https://o365blog.com/post/hybridhealthagent/'" + } + }, + "displayName": "NRT Microsoft Entra ID Hybrid Health AD FS New Server", + "queryCondition": { + "queryText": "AzureActivity\n| where CategoryValue =~ 'Administrative'\n| where ResourceProviderValue =~ 'Microsoft.ADHybridHealthService'\n| where _ResourceId has 'AdFederationService'\n| where OperationNameValue =~ 'Microsoft.ADHybridHealthService/services/servicemembers/action'\n| extend claimsJson = parse_json(Claims)\n| extend AppId = tostring(claimsJson.appid), AccountName = tostring(claimsJson.name), Name = tostring(split(Caller,'@',0)[0]), UPNSuffix = tostring(split(Caller,'@',1)[0])\n| project-away claimsJson" + }, + "id": "[if(true(), 'xdr-ec491363-5fe7-4eff-b68e-f42dcb76fcf6', 'xdr-ec491363-5fe7-4eff-b68e-f42dcb76fcf6')]", + "schedule": { + "frequency": "PT1H" + } + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-ec491363-5fe7-4eff-b68e-f42dcb76fcf6')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'AzureActivity-CD-xdr-ec491363-5fe7-4eff-b68e-f42dcb76fcf6')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'This detection uses AzureActivity logs (Administrative category) to identify the creation or update of a server instance in an Microsoft Entra ID Hybrid Health AD FS service.\nA threat actor can create a new AD Health ADFS service and create a fake server instance to spoof AD FS signing logs. There is no need to compromise an on-premises AD FS server.\nThis can be done programmatically via HTTP requests to Azure. More information in this blog: https://o365blog.com/post/hybridhealthagent/'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "status": "disabled", + "detectionAction": { + "alertTemplate": { + "tactics": [ + { + "tactic": "DefenseEvasion", + "techniques": [ + { + "technique": "T1578" + } + ] + } + ], + "severity": "medium", + "title": "NRT Microsoft Entra ID Hybrid Health AD FS New Server", + "entityMappings": { + "ips": [ + { + "addressColumn": "CallerIpAddress", + "id": "[if(true(), 'ip1', 'ip1')]" + } + ], + "accounts": [ + { + "upnSuffixColumn": "UPNSuffix", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "Name" + } + ] + }, + "description": "'This detection uses AzureActivity logs (Administrative category) to identify the creation or update of a server instance in an Microsoft Entra ID Hybrid Health AD FS service.\nA threat actor can create a new AD Health ADFS service and create a fake server instance to spoof AD FS signing logs. There is no need to compromise an on-premises AD FS server.\nThis can be done programmatically via HTTP requests to Azure. More information in this blog: https://o365blog.com/post/hybridhealthagent/'" + } + }, + "displayName": "NRT Microsoft Entra ID Hybrid Health AD FS New Server", + "queryCondition": { + "queryText": "AzureActivity\n| where CategoryValue =~ 'Administrative'\n| where ResourceProviderValue =~ 'Microsoft.ADHybridHealthService'\n| where _ResourceId has 'AdFederationService'\n| where OperationNameValue =~ 'Microsoft.ADHybridHealthService/services/servicemembers/action'\n| extend claimsJson = parse_json(Claims)\n| extend AppId = tostring(claimsJson.appid), AccountName = tostring(claimsJson.name), Name = tostring(split(Caller,'@',0)[0]), UPNSuffix = tostring(split(Caller,'@',1)[0])\n| project-away claimsJson" + }, + "id": "[if(true(), 'xdr-ec491363-5fe7-4eff-b68e-f42dcb76fcf6', 'xdr-ec491363-5fe7-4eff-b68e-f42dcb76fcf6')]", + "schedule": { + "frequency": "PT1H" + } + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-ec491363-5fe7-4eff-b68e-f42dcb76fcf6", + "contentKind": "CustomDetection", + "displayName": "NRT Microsoft Entra ID Hybrid Health AD FS New Server", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-ec491363-5fe7-4eff-b68e-f42dcb76fcf6','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-ec491363-5fe7-4eff-b68e-f42dcb76fcf6','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "AzureActivity-CD-xdr-56fe0db0-6779-46fa-b3c5-006082a53064", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "status": "disabled", + "detectionAction": { + "alertTemplate": { + "entityMappings": { + "hosts": [ + { + "nameColumn": "ComputerName", + "id": "[if(true(), 'host1', 'host1')]" + } + ], + "accounts": [ + { + "upnSuffixColumn": "UPNSuffix", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "Name" + } + ], + "ips": [ + { + "addressColumn": "CallerIpAddress", + "id": "[if(true(), 'ip1', 'ip1')]" + } + ] + }, + "customDetails": { + "AccountFullName": "Caller" + }, + "severity": "medium", + "title": "NRT Creation of expensive computes in Azure", + "description": "'Identifies the creation of large size or expensive VMs (with GPUs or with a large number of virtual CPUs) in Azure.\nAn adversary may create new or update existing virtual machines to evade defenses or use them for cryptomining purposes.\nFor Windows/Linux Vm Sizes, see https://docs.microsoft.com/azure/virtual-machines/windows/sizes \nAzure VM Naming Conventions, see https://docs.microsoft.com/azure/virtual-machines/vm-naming-conventions'", + "tactics": [ + { + "tactic": "DefenseEvasion", + "techniques": [ + { + "technique": "T1578" + } + ] + } + ] + } + }, + "displayName": "NRT Creation of expensive computes in Azure", + "queryCondition": { + "queryText": "let tokens = dynamic([\"416\",\"208\",\"192\",\"128\",\"120\",\"96\",\"80\",\"72\",\"64\",\"48\",\"44\",\"40\",\"nc12\",\"nc24\",\"nv24\"]);\nlet operationList = dynamic([\"microsoft.compute/virtualmachines/write\", \"microsoft.resources/deployments/write\"]);\nAzureActivity\n| where OperationNameValue in~ (operationList)\n| where ActivityStatusValue startswith \"Accept\"\n| where Properties has 'vmSize'\n| extend parsed_property= parse_json(tostring((parse_json(Properties).responseBody))).properties\n| extend vmSize = tostring((parsed_property.hardwareProfile).vmSize)\n| mv-apply token=tokens to typeof(string) on (where vmSize contains token)\n| extend ComputerName = tostring((parsed_property.osProfile).computerName)\n| project TimeGenerated, OperationNameValue, ActivityStatusValue, Caller, CallerIpAddress, ComputerName, vmSize\n| extend Name = tostring(split(Caller,'@',0)[0]), UPNSuffix = tostring(split(Caller,'@',1)[0])" + }, + "id": "[if(true(), 'xdr-56fe0db0-6779-46fa-b3c5-006082a53064', 'xdr-56fe0db0-6779-46fa-b3c5-006082a53064')]", + "schedule": { + "frequency": "PT1H" + } + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-56fe0db0-6779-46fa-b3c5-006082a53064')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'AzureActivity-CD-xdr-56fe0db0-6779-46fa-b3c5-006082a53064')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'Identifies the creation of large size or expensive VMs (with GPUs or with a large number of virtual CPUs) in Azure.\nAn adversary may create new or update existing virtual machines to evade defenses or use them for cryptomining purposes.\nFor Windows/Linux Vm Sizes, see https://docs.microsoft.com/azure/virtual-machines/windows/sizes \nAzure VM Naming Conventions, see https://docs.microsoft.com/azure/virtual-machines/vm-naming-conventions'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "status": "disabled", + "detectionAction": { + "alertTemplate": { + "entityMappings": { + "hosts": [ + { + "nameColumn": "ComputerName", + "id": "[if(true(), 'host1', 'host1')]" + } + ], + "accounts": [ + { + "upnSuffixColumn": "UPNSuffix", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "Name" + } + ], + "ips": [ + { + "addressColumn": "CallerIpAddress", + "id": "[if(true(), 'ip1', 'ip1')]" + } + ] + }, + "customDetails": { + "AccountFullName": "Caller" + }, + "severity": "medium", + "title": "NRT Creation of expensive computes in Azure", + "description": "'Identifies the creation of large size or expensive VMs (with GPUs or with a large number of virtual CPUs) in Azure.\nAn adversary may create new or update existing virtual machines to evade defenses or use them for cryptomining purposes.\nFor Windows/Linux Vm Sizes, see https://docs.microsoft.com/azure/virtual-machines/windows/sizes \nAzure VM Naming Conventions, see https://docs.microsoft.com/azure/virtual-machines/vm-naming-conventions'", + "tactics": [ + { + "tactic": "DefenseEvasion", + "techniques": [ + { + "technique": "T1578" + } + ] + } + ] + } + }, + "displayName": "NRT Creation of expensive computes in Azure", + "queryCondition": { + "queryText": "let tokens = dynamic([\"416\",\"208\",\"192\",\"128\",\"120\",\"96\",\"80\",\"72\",\"64\",\"48\",\"44\",\"40\",\"nc12\",\"nc24\",\"nv24\"]);\nlet operationList = dynamic([\"microsoft.compute/virtualmachines/write\", \"microsoft.resources/deployments/write\"]);\nAzureActivity\n| where OperationNameValue in~ (operationList)\n| where ActivityStatusValue startswith \"Accept\"\n| where Properties has 'vmSize'\n| extend parsed_property= parse_json(tostring((parse_json(Properties).responseBody))).properties\n| extend vmSize = tostring((parsed_property.hardwareProfile).vmSize)\n| mv-apply token=tokens to typeof(string) on (where vmSize contains token)\n| extend ComputerName = tostring((parsed_property.osProfile).computerName)\n| project TimeGenerated, OperationNameValue, ActivityStatusValue, Caller, CallerIpAddress, ComputerName, vmSize\n| extend Name = tostring(split(Caller,'@',0)[0]), UPNSuffix = tostring(split(Caller,'@',1)[0])" + }, + "id": "[if(true(), 'xdr-56fe0db0-6779-46fa-b3c5-006082a53064', 'xdr-56fe0db0-6779-46fa-b3c5-006082a53064')]", + "schedule": { + "frequency": "PT1H" + } + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-56fe0db0-6779-46fa-b3c5-006082a53064", + "contentKind": "CustomDetection", + "displayName": "NRT Creation of expensive computes in Azure", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-56fe0db0-6779-46fa-b3c5-006082a53064','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-56fe0db0-6779-46fa-b3c5-006082a53064','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "AzureActivity-CD-xdr-6d7214d9-4a28-44df-aafb-0910b9e6ae3e", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "status": "disabled", + "detectionAction": { + "alertTemplate": { + "entityMappings": { + "ips": [ + { + "addressColumn": "UserIP", + "id": "[if(true(), 'ip1', 'ip1')]" + } + ], + "accounts": [ + { + "upnSuffixColumn": "UPNSuffix", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "Name" + } + ] + }, + "customDetails": { + "AccountFullName": "Caller" + }, + "severity": "low", + "title": "New CloudShell User", + "description": "'Identifies when a user creates an Azure CloudShell for the first time.\nMonitor this activity to ensure only the expected users are using CloudShell.'", + "tactics": [ + { + "tactic": "Execution", + "techniques": [ + { + "technique": "T1059" + } + ] + } + ] + } + }, + "displayName": "New CloudShell User", + "queryCondition": { + "queryText": "let match_window = 3m;\nAzureActivity\n| where ResourceGroup has \"cloud-shell\"\n| where (OperationNameValue =~ \"Microsoft.Storage/storageAccounts/listKeys/action\")\n| where ActivityStatusValue =~ \"Success\"\n| extend TimeKey = bin(TimeGenerated, match_window), AzureIP = CallerIpAddress\n| join kind = inner\n(AzureActivity\n| where ResourceGroup has \"cloud-shell\"\n| where (OperationNameValue =~ \"Microsoft.Storage/storageAccounts/write\")\n| extend TimeKey = bin(TimeGenerated, match_window), UserIP = CallerIpAddress\n) on Caller, TimeKey\n| summarize count() by TimeKey, Caller, ResourceGroup, SubscriptionId, TenantId, AzureIP, UserIP, HTTPRequest, Type, Properties, CategoryValue, OperationList = strcat(OperationNameValue, ' , ', OperationNameValue1)\n| extend Name = tostring(split(Caller,'@',0)[0]), UPNSuffix = tostring(split(Caller,'@',1)[0])" + }, + "id": "[if(true(), 'xdr-6d7214d9-4a28-44df-aafb-0910b9e6ae3e', 'xdr-6d7214d9-4a28-44df-aafb-0910b9e6ae3e')]", + "schedule": { + "frequency": "P1D" + } + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-6d7214d9-4a28-44df-aafb-0910b9e6ae3e')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'AzureActivity-CD-xdr-6d7214d9-4a28-44df-aafb-0910b9e6ae3e')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'Identifies when a user creates an Azure CloudShell for the first time.\nMonitor this activity to ensure only the expected users are using CloudShell.'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "status": "disabled", + "detectionAction": { + "alertTemplate": { + "entityMappings": { + "ips": [ + { + "addressColumn": "UserIP", + "id": "[if(true(), 'ip1', 'ip1')]" + } + ], + "accounts": [ + { + "upnSuffixColumn": "UPNSuffix", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "Name" + } + ] + }, + "customDetails": { + "AccountFullName": "Caller" + }, + "severity": "low", + "title": "New CloudShell User", + "description": "'Identifies when a user creates an Azure CloudShell for the first time.\nMonitor this activity to ensure only the expected users are using CloudShell.'", + "tactics": [ + { + "tactic": "Execution", + "techniques": [ + { + "technique": "T1059" + } + ] + } + ] + } + }, + "displayName": "New CloudShell User", + "queryCondition": { + "queryText": "let match_window = 3m;\nAzureActivity\n| where ResourceGroup has \"cloud-shell\"\n| where (OperationNameValue =~ \"Microsoft.Storage/storageAccounts/listKeys/action\")\n| where ActivityStatusValue =~ \"Success\"\n| extend TimeKey = bin(TimeGenerated, match_window), AzureIP = CallerIpAddress\n| join kind = inner\n(AzureActivity\n| where ResourceGroup has \"cloud-shell\"\n| where (OperationNameValue =~ \"Microsoft.Storage/storageAccounts/write\")\n| extend TimeKey = bin(TimeGenerated, match_window), UserIP = CallerIpAddress\n) on Caller, TimeKey\n| summarize count() by TimeKey, Caller, ResourceGroup, SubscriptionId, TenantId, AzureIP, UserIP, HTTPRequest, Type, Properties, CategoryValue, OperationList = strcat(OperationNameValue, ' , ', OperationNameValue1)\n| extend Name = tostring(split(Caller,'@',0)[0]), UPNSuffix = tostring(split(Caller,'@',1)[0])" + }, + "id": "[if(true(), 'xdr-6d7214d9-4a28-44df-aafb-0910b9e6ae3e', 'xdr-6d7214d9-4a28-44df-aafb-0910b9e6ae3e')]", + "schedule": { + "frequency": "P1D" + } + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-6d7214d9-4a28-44df-aafb-0910b9e6ae3e", + "contentKind": "CustomDetection", + "displayName": "New CloudShell User", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-6d7214d9-4a28-44df-aafb-0910b9e6ae3e','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-6d7214d9-4a28-44df-aafb-0910b9e6ae3e','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "AzureActivity-CD-xdr-9fb57e58-3ed8-4b89-afcf-c8e786508b1c", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "status": "disabled", + "detectionAction": { + "alertTemplate": { + "entityMappings": { + "ips": [ + { + "addressColumn": "CallerIpAddress", + "id": "[if(true(), 'ip1', 'ip1')]" + } + ], + "accounts": [ + { + "upnSuffixColumn": "UPNSuffix", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "Name" + }, + { + "aadUserIdColumn": "AadUserId", + "id": "[if(true(), 'account2', 'account2')]" + } + ] + }, + "customDetails": { + "AccountFullName": "Caller" + }, + "severity": "low", + "title": "Suspicious Resource deployment", + "description": "'Identifies when a rare Resource and ResourceGroup deployment occurs by a previously unseen caller.'", + "tactics": [ + { + "tactic": "Impact", + "techniques": [ + { + "technique": "T1496" + } + ] + } + ] + } + }, + "displayName": "Suspicious Resource deployment", + "queryCondition": { + "queryText": "// Add or remove operation names below as per your requirements. For operations lists, please refer to https://learn.microsoft.com/en-us/Azure/role-based-access-control/resource-provider-operations#all\nlet szOperationNames = dynamic([\"Microsoft.Compute/virtualMachines/write\", \"Microsoft.Resources/deployments/write\", \"Microsoft.Resources/subscriptions/resourceGroups/write\"]);\nlet starttime = 14d;\nlet endtime = 1d;\nlet RareCaller = AzureActivity\n| where TimeGenerated between (ago(starttime) .. ago(endtime))\n| where OperationNameValue in~ (szOperationNames)\n| summarize count() by CallerIpAddress, Caller, OperationNameValue, bin(TimeGenerated,1d)\n// Returns all the records from the right side that don't have matches from the left.\n| join kind=rightantisemi (\nAzureActivity\n| where TimeGenerated > ago(endtime)\n| where OperationNameValue in~ (szOperationNames)\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), ActivityTimeStamp = make_set(TimeGenerated,100), ActivityStatusValue = make_set(ActivityStatusValue,100), CorrelationIds = make_set(CorrelationId,100), ResourceGroups = make_set(ResourceGroup,100), ResourceIds = make_set(_ResourceId,100), ActivityCountByCallerIPAddress = count()\nby CallerIpAddress, Caller, OperationNameValue) on CallerIpAddress, Caller, OperationNameValue;\nRareCaller\n| extend Name = iif(Caller has '@',tostring(split(Caller,'@',0)[0]),\"\")\n| extend UPNSuffix = iif(Caller has '@',tostring(split(Caller,'@',1)[0]),\"\")\n| extend AadUserId = iif(Caller !has '@',Caller,\"\")" + }, + "id": "[if(true(), 'xdr-9fb57e58-3ed8-4b89-afcf-c8e786508b1c', 'xdr-9fb57e58-3ed8-4b89-afcf-c8e786508b1c')]", + "schedule": { + "frequency": "P1D" + } + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-9fb57e58-3ed8-4b89-afcf-c8e786508b1c')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'AzureActivity-CD-xdr-9fb57e58-3ed8-4b89-afcf-c8e786508b1c')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'Identifies when a rare Resource and ResourceGroup deployment occurs by a previously unseen caller.'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "status": "disabled", + "detectionAction": { + "alertTemplate": { + "entityMappings": { + "ips": [ + { + "addressColumn": "CallerIpAddress", + "id": "[if(true(), 'ip1', 'ip1')]" + } + ], + "accounts": [ + { + "upnSuffixColumn": "UPNSuffix", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "Name" + }, + { + "aadUserIdColumn": "AadUserId", + "id": "[if(true(), 'account2', 'account2')]" + } + ] + }, + "customDetails": { + "AccountFullName": "Caller" + }, + "severity": "low", + "title": "Suspicious Resource deployment", + "description": "'Identifies when a rare Resource and ResourceGroup deployment occurs by a previously unseen caller.'", + "tactics": [ + { + "tactic": "Impact", + "techniques": [ + { + "technique": "T1496" + } + ] + } + ] + } + }, + "displayName": "Suspicious Resource deployment", + "queryCondition": { + "queryText": "// Add or remove operation names below as per your requirements. For operations lists, please refer to https://learn.microsoft.com/en-us/Azure/role-based-access-control/resource-provider-operations#all\nlet szOperationNames = dynamic([\"Microsoft.Compute/virtualMachines/write\", \"Microsoft.Resources/deployments/write\", \"Microsoft.Resources/subscriptions/resourceGroups/write\"]);\nlet starttime = 14d;\nlet endtime = 1d;\nlet RareCaller = AzureActivity\n| where TimeGenerated between (ago(starttime) .. ago(endtime))\n| where OperationNameValue in~ (szOperationNames)\n| summarize count() by CallerIpAddress, Caller, OperationNameValue, bin(TimeGenerated,1d)\n// Returns all the records from the right side that don't have matches from the left.\n| join kind=rightantisemi (\nAzureActivity\n| where TimeGenerated > ago(endtime)\n| where OperationNameValue in~ (szOperationNames)\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), ActivityTimeStamp = make_set(TimeGenerated,100), ActivityStatusValue = make_set(ActivityStatusValue,100), CorrelationIds = make_set(CorrelationId,100), ResourceGroups = make_set(ResourceGroup,100), ResourceIds = make_set(_ResourceId,100), ActivityCountByCallerIPAddress = count()\nby CallerIpAddress, Caller, OperationNameValue) on CallerIpAddress, Caller, OperationNameValue;\nRareCaller\n| extend Name = iif(Caller has '@',tostring(split(Caller,'@',0)[0]),\"\")\n| extend UPNSuffix = iif(Caller has '@',tostring(split(Caller,'@',1)[0]),\"\")\n| extend AadUserId = iif(Caller !has '@',Caller,\"\")" + }, + "id": "[if(true(), 'xdr-9fb57e58-3ed8-4b89-afcf-c8e786508b1c', 'xdr-9fb57e58-3ed8-4b89-afcf-c8e786508b1c')]", + "schedule": { + "frequency": "P1D" + } + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-9fb57e58-3ed8-4b89-afcf-c8e786508b1c", + "contentKind": "CustomDetection", + "displayName": "Suspicious Resource deployment", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-9fb57e58-3ed8-4b89-afcf-c8e786508b1c','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-9fb57e58-3ed8-4b89-afcf-c8e786508b1c','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "AzureActivity-CD-xdr-23de46ea-c425-4a77-b456-511ae4855d69", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "status": "disabled", + "detectionAction": { + "alertTemplate": { + "entityMappings": { + "ips": [ + { + "addressColumn": "CallerIpAddress", + "id": "[if(true(), 'ip1', 'ip1')]" + } + ], + "accounts": [ + { + "upnSuffixColumn": "UPNSuffix", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "Name" + } + ] + }, + "customDetails": { + "AccountFullName": "Caller" + }, + "severity": "low", + "title": "Rare subscription-level operations in Azure", + "description": "'This query looks for a few sensitive subscription-level events based on Azure Activity Logs. For example, this monitors for the operation name 'Create or Update Snapshot', which is used for creating backups but could be misused by attackers to dump hashes or extract sensitive information from the disk.'", + "tactics": [ + { + "tactic": "CredentialAccess", + "techniques": [ + { + "technique": "T1003" + } + ] + } + ] + } + }, + "displayName": "Rare subscription-level operations in Azure", + "queryCondition": { + "queryText": "let starttime = 14d;\nlet endtime = 1d;\n// The number of operations above which an IP address is considered an unusual source of role assignment operations\nlet alertOperationThreshold = 5;\n// Add or remove operation names below as per your requirements. For operations lists, please refer to https://learn.microsoft.com/en-us/Azure/role-based-access-control/resource-provider-operations#all\nlet SensitiveOperationList = dynamic([\"microsoft.compute/snapshots/write\", \"microsoft.network/networksecuritygroups/write\", \"microsoft.storage/storageaccounts/listkeys/action\"]);\nlet SensitiveActivity = AzureActivity\n| where OperationNameValue in~ (SensitiveOperationList) or OperationNameValue hassuffix \"listkeys/action\"\n| where ActivityStatusValue =~ \"Success\";\nSensitiveActivity\n| where TimeGenerated between (ago(starttime) .. ago(endtime))\n| summarize count() by CallerIpAddress, Caller, OperationNameValue, bin(TimeGenerated,1d)\n| where count_ >= alertOperationThreshold\n// Returns all the records from the right side that don't have matches from the left\n| join kind = rightanti (\nSensitiveActivity\n| where TimeGenerated >= ago(endtime)\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), ActivityTimeStamp = make_list(TimeGenerated), ActivityStatusValue = make_list(ActivityStatusValue), CorrelationIds = make_list(CorrelationId), ResourceGroups = make_list(ResourceGroup), ResourceIds = make_list(_ResourceId), ActivityCountByCallerIPAddress = count()\nby CallerIpAddress, Caller, OperationNameValue\n| where ActivityCountByCallerIPAddress >= alertOperationThreshold\n) on CallerIpAddress, Caller, OperationNameValue\n| extend Name = tostring(split(Caller,'@',0)[0]), UPNSuffix = tostring(split(Caller,'@',1)[0])" + }, + "id": "[if(true(), 'xdr-23de46ea-c425-4a77-b456-511ae4855d69', 'xdr-23de46ea-c425-4a77-b456-511ae4855d69')]", + "schedule": { + "frequency": "P1D" + } + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-23de46ea-c425-4a77-b456-511ae4855d69')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'AzureActivity-CD-xdr-23de46ea-c425-4a77-b456-511ae4855d69')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'This query looks for a few sensitive subscription-level events based on Azure Activity Logs. For example, this monitors for the operation name 'Create or Update Snapshot', which is used for creating backups but could be misused by attackers to dump hashes or extract sensitive information from the disk.'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "status": "disabled", + "detectionAction": { + "alertTemplate": { + "entityMappings": { + "ips": [ + { + "addressColumn": "CallerIpAddress", + "id": "[if(true(), 'ip1', 'ip1')]" + } + ], + "accounts": [ + { + "upnSuffixColumn": "UPNSuffix", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "Name" + } + ] + }, + "customDetails": { + "AccountFullName": "Caller" + }, + "severity": "low", + "title": "Rare subscription-level operations in Azure", + "description": "'This query looks for a few sensitive subscription-level events based on Azure Activity Logs. For example, this monitors for the operation name 'Create or Update Snapshot', which is used for creating backups but could be misused by attackers to dump hashes or extract sensitive information from the disk.'", + "tactics": [ + { + "tactic": "CredentialAccess", + "techniques": [ + { + "technique": "T1003" + } + ] + } + ] + } + }, + "displayName": "Rare subscription-level operations in Azure", + "queryCondition": { + "queryText": "let starttime = 14d;\nlet endtime = 1d;\n// The number of operations above which an IP address is considered an unusual source of role assignment operations\nlet alertOperationThreshold = 5;\n// Add or remove operation names below as per your requirements. For operations lists, please refer to https://learn.microsoft.com/en-us/Azure/role-based-access-control/resource-provider-operations#all\nlet SensitiveOperationList = dynamic([\"microsoft.compute/snapshots/write\", \"microsoft.network/networksecuritygroups/write\", \"microsoft.storage/storageaccounts/listkeys/action\"]);\nlet SensitiveActivity = AzureActivity\n| where OperationNameValue in~ (SensitiveOperationList) or OperationNameValue hassuffix \"listkeys/action\"\n| where ActivityStatusValue =~ \"Success\";\nSensitiveActivity\n| where TimeGenerated between (ago(starttime) .. ago(endtime))\n| summarize count() by CallerIpAddress, Caller, OperationNameValue, bin(TimeGenerated,1d)\n| where count_ >= alertOperationThreshold\n// Returns all the records from the right side that don't have matches from the left\n| join kind = rightanti (\nSensitiveActivity\n| where TimeGenerated >= ago(endtime)\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), ActivityTimeStamp = make_list(TimeGenerated), ActivityStatusValue = make_list(ActivityStatusValue), CorrelationIds = make_list(CorrelationId), ResourceGroups = make_list(ResourceGroup), ResourceIds = make_list(_ResourceId), ActivityCountByCallerIPAddress = count()\nby CallerIpAddress, Caller, OperationNameValue\n| where ActivityCountByCallerIPAddress >= alertOperationThreshold\n) on CallerIpAddress, Caller, OperationNameValue\n| extend Name = tostring(split(Caller,'@',0)[0]), UPNSuffix = tostring(split(Caller,'@',1)[0])" + }, + "id": "[if(true(), 'xdr-23de46ea-c425-4a77-b456-511ae4855d69', 'xdr-23de46ea-c425-4a77-b456-511ae4855d69')]", + "schedule": { + "frequency": "P1D" + } + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-23de46ea-c425-4a77-b456-511ae4855d69", + "contentKind": "CustomDetection", + "displayName": "Rare subscription-level operations in Azure", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-23de46ea-c425-4a77-b456-511ae4855d69','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-23de46ea-c425-4a77-b456-511ae4855d69','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "AzureActivity-CD-xdr-48c026d8-7f36-4a95-9568-6f1420d66e37", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "status": "disabled", + "detectionAction": { + "alertTemplate": { + "entityMappings": { + "azureResources": [ + { + "resourceIdColumn": "_ResourceId", + "id": "[if(true(), 'azureResource1', 'azureResource1')]" + } + ], + "accounts": [ + { + "upnSuffixColumn": "UPNSuffix", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "Name" + } + ] + }, + "customDetails": { + "SourceTenantId": "SourceTenantId", + "AccountFullName": "Caller", + "DestinationTenantId": "DestinationTenantId" + }, + "severity": "low", + "title": "Subscription moved to another tenant", + "description": "'This detection uses AzureActivity logs (Security category) to identify when a subscription is moved to another tenant.\nA threat actor may move a subscription into their own tenant to circumvent local resource deployment and logging policies.\nOnce moved, threat actors may deploy resources and perform malicious activities such as crypto mining.\nThis is a technique known as \"subscription hijacking\". More information can be found here: https://techcommunity.microsoft.com/t5/microsoft-365-defender-blog/hunt-for-compromised-azure-subscriptions-using-microsoft/ba-p/3607121'", + "tactics": [ + { + "tactic": "Impact", + "techniques": [ + { + "technique": "T1496" + } + ] + } + ] + } + }, + "displayName": "Subscription moved to another tenant", + "queryCondition": { + "queryText": "let queryFrequency = 5m;\nlet eventCapture = \"moved from tenant ([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}) to tenant ([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\";\nAzureActivity\n| where ingestion_time() > ago(queryFrequency)\n| where CategoryValue =~ \"Security\"\n| where OperationNameValue =~ \"Microsoft.Subscription/updateTenant/action\"\n| extend Properties_d = coalesce(parse_json(Properties), Properties_d)\n| where isnotempty(Properties_d)\n| extend Summary = tostring(Properties_d.message)\n| extend EventCapture = extract_all(eventCapture, Summary)\n| extend SourceTenantId = iff(isnotempty(EventCapture), EventCapture[0][0], \"\")\n| extend DestinationTenantId = iff(isnotempty(EventCapture), EventCapture[0][1], \"\")\n| extend\n Name = split(Caller, \"@\", 0)[0],\n UPNSuffix = split(Caller, \"@\", 1)[0]" + }, + "id": "[if(true(), 'xdr-48c026d8-7f36-4a95-9568-6f1420d66e37', 'xdr-48c026d8-7f36-4a95-9568-6f1420d66e37')]", + "schedule": { + "frequency": "PT5M" + } + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-48c026d8-7f36-4a95-9568-6f1420d66e37')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'AzureActivity-CD-xdr-48c026d8-7f36-4a95-9568-6f1420d66e37')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'This detection uses AzureActivity logs (Security category) to identify when a subscription is moved to another tenant.\nA threat actor may move a subscription into their own tenant to circumvent local resource deployment and logging policies.\nOnce moved, threat actors may deploy resources and perform malicious activities such as crypto mining.\nThis is a technique known as \"subscription hijacking\". More information can be found here: https://techcommunity.microsoft.com/t5/microsoft-365-defender-blog/hunt-for-compromised-azure-subscriptions-using-microsoft/ba-p/3607121'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "status": "disabled", + "detectionAction": { + "alertTemplate": { + "entityMappings": { + "azureResources": [ + { + "resourceIdColumn": "_ResourceId", + "id": "[if(true(), 'azureResource1', 'azureResource1')]" + } + ], + "accounts": [ + { + "upnSuffixColumn": "UPNSuffix", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "Name" + } + ] + }, + "customDetails": { + "SourceTenantId": "SourceTenantId", + "AccountFullName": "Caller", + "DestinationTenantId": "DestinationTenantId" + }, + "severity": "low", + "title": "Subscription moved to another tenant", + "description": "'This detection uses AzureActivity logs (Security category) to identify when a subscription is moved to another tenant.\nA threat actor may move a subscription into their own tenant to circumvent local resource deployment and logging policies.\nOnce moved, threat actors may deploy resources and perform malicious activities such as crypto mining.\nThis is a technique known as \"subscription hijacking\". More information can be found here: https://techcommunity.microsoft.com/t5/microsoft-365-defender-blog/hunt-for-compromised-azure-subscriptions-using-microsoft/ba-p/3607121'", + "tactics": [ + { + "tactic": "Impact", + "techniques": [ + { + "technique": "T1496" + } + ] + } + ] + } + }, + "displayName": "Subscription moved to another tenant", + "queryCondition": { + "queryText": "let queryFrequency = 5m;\nlet eventCapture = \"moved from tenant ([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}) to tenant ([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\";\nAzureActivity\n| where ingestion_time() > ago(queryFrequency)\n| where CategoryValue =~ \"Security\"\n| where OperationNameValue =~ \"Microsoft.Subscription/updateTenant/action\"\n| extend Properties_d = coalesce(parse_json(Properties), Properties_d)\n| where isnotempty(Properties_d)\n| extend Summary = tostring(Properties_d.message)\n| extend EventCapture = extract_all(eventCapture, Summary)\n| extend SourceTenantId = iff(isnotempty(EventCapture), EventCapture[0][0], \"\")\n| extend DestinationTenantId = iff(isnotempty(EventCapture), EventCapture[0][1], \"\")\n| extend\n Name = split(Caller, \"@\", 0)[0],\n UPNSuffix = split(Caller, \"@\", 1)[0]" + }, + "id": "[if(true(), 'xdr-48c026d8-7f36-4a95-9568-6f1420d66e37', 'xdr-48c026d8-7f36-4a95-9568-6f1420d66e37')]", + "schedule": { + "frequency": "PT5M" + } + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-48c026d8-7f36-4a95-9568-6f1420d66e37", + "contentKind": "CustomDetection", + "displayName": "Subscription moved to another tenant", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-48c026d8-7f36-4a95-9568-6f1420d66e37','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-48c026d8-7f36-4a95-9568-6f1420d66e37','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "AzureActivity-CD-xdr-ed43bdb7-eaab-4ea4-be52-6951fcfa7e3b", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "status": "disabled", + "detectionAction": { + "alertTemplate": { + "entityMappings": { + "accounts": [ + { + "upnSuffixColumn": "UPNSuffix", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "Name" + }, + { + "aadUserIdColumn": "AadUserId", + "id": "[if(true(), 'account2', 'account2')]" + } + ] + }, + "customDetails": { + "AccountFullName": "Caller" + }, + "severity": "medium", + "title": "Mass Cloud resource deletions Time Series Anomaly", + "description": "'This query generates the baseline pattern of cloud resource deletions by an individual and generates an anomaly when any unusual spike is detected. These anomalies from unusual or privileged users could be an indication of a cloud infrastructure takedown by an adversary.'", + "tactics": [ + { + "tactic": "Impact", + "techniques": [ + { + "technique": "T1485" + } + ] + } + ] + } + }, + "displayName": "Mass Cloud resource deletions Time Series Anomaly", + "queryCondition": { + "queryText": "let starttime = 14d;\nlet endtime = 1d;\nlet timeframe = 1d;\nlet TotalEventsThreshold = 25;\nlet TimeSeriesData = AzureActivity\n| where TimeGenerated between (startofday(ago(starttime))..startofday(now()))\n| where OperationNameValue endswith \"delete\"\n| project TimeGenerated, Caller\n| make-series Total = count() on TimeGenerated from startofday(ago(starttime)) to startofday(now()) step timeframe by Caller;\nTimeSeriesData\n| extend (anomalies, score, baseline) = series_decompose_anomalies(Total, 3, -1, 'linefit')\n| mv-expand Total to typeof(double), TimeGenerated to typeof(datetime), anomalies to typeof(double), score to typeof(double), baseline to typeof(long)\n| where TimeGenerated >= startofday(ago(endtime))\n| where anomalies > 0\n| project Caller, TimeGenerated, Total, baseline, anomalies, score\n| where Total > TotalEventsThreshold and baseline > 0\n| join (AzureActivity\n| where TimeGenerated > startofday(ago(endtime))\n| where OperationNameValue endswith \"delete\"\n| summarize count(), make_set(OperationNameValue,100), make_set(_ResourceId,100) by bin(TimeGenerated, timeframe), Caller ) on TimeGenerated, Caller\n| extend Name = iif(Caller has '@',tostring(split(Caller,'@',0)[0]),\"\")\n| extend UPNSuffix = iif(Caller has '@',tostring(split(Caller,'@',1)[0]),\"\")\n| extend AadUserId = iif(Caller !has '@',Caller,\"\")" + }, + "id": "[if(true(), 'xdr-ed43bdb7-eaab-4ea4-be52-6951fcfa7e3b', 'xdr-ed43bdb7-eaab-4ea4-be52-6951fcfa7e3b')]", + "schedule": { + "frequency": "P1D" + } + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-ed43bdb7-eaab-4ea4-be52-6951fcfa7e3b')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'AzureActivity-CD-xdr-ed43bdb7-eaab-4ea4-be52-6951fcfa7e3b')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'This query generates the baseline pattern of cloud resource deletions by an individual and generates an anomaly when any unusual spike is detected. These anomalies from unusual or privileged users could be an indication of a cloud infrastructure takedown by an adversary.'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "status": "disabled", + "detectionAction": { + "alertTemplate": { + "entityMappings": { + "accounts": [ + { + "upnSuffixColumn": "UPNSuffix", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "Name" + }, + { + "aadUserIdColumn": "AadUserId", + "id": "[if(true(), 'account2', 'account2')]" + } + ] + }, + "customDetails": { + "AccountFullName": "Caller" + }, + "severity": "medium", + "title": "Mass Cloud resource deletions Time Series Anomaly", + "description": "'This query generates the baseline pattern of cloud resource deletions by an individual and generates an anomaly when any unusual spike is detected. These anomalies from unusual or privileged users could be an indication of a cloud infrastructure takedown by an adversary.'", + "tactics": [ + { + "tactic": "Impact", + "techniques": [ + { + "technique": "T1485" + } + ] + } + ] + } + }, + "displayName": "Mass Cloud resource deletions Time Series Anomaly", + "queryCondition": { + "queryText": "let starttime = 14d;\nlet endtime = 1d;\nlet timeframe = 1d;\nlet TotalEventsThreshold = 25;\nlet TimeSeriesData = AzureActivity\n| where TimeGenerated between (startofday(ago(starttime))..startofday(now()))\n| where OperationNameValue endswith \"delete\"\n| project TimeGenerated, Caller\n| make-series Total = count() on TimeGenerated from startofday(ago(starttime)) to startofday(now()) step timeframe by Caller;\nTimeSeriesData\n| extend (anomalies, score, baseline) = series_decompose_anomalies(Total, 3, -1, 'linefit')\n| mv-expand Total to typeof(double), TimeGenerated to typeof(datetime), anomalies to typeof(double), score to typeof(double), baseline to typeof(long)\n| where TimeGenerated >= startofday(ago(endtime))\n| where anomalies > 0\n| project Caller, TimeGenerated, Total, baseline, anomalies, score\n| where Total > TotalEventsThreshold and baseline > 0\n| join (AzureActivity\n| where TimeGenerated > startofday(ago(endtime))\n| where OperationNameValue endswith \"delete\"\n| summarize count(), make_set(OperationNameValue,100), make_set(_ResourceId,100) by bin(TimeGenerated, timeframe), Caller ) on TimeGenerated, Caller\n| extend Name = iif(Caller has '@',tostring(split(Caller,'@',0)[0]),\"\")\n| extend UPNSuffix = iif(Caller has '@',tostring(split(Caller,'@',1)[0]),\"\")\n| extend AadUserId = iif(Caller !has '@',Caller,\"\")" + }, + "id": "[if(true(), 'xdr-ed43bdb7-eaab-4ea4-be52-6951fcfa7e3b', 'xdr-ed43bdb7-eaab-4ea4-be52-6951fcfa7e3b')]", + "schedule": { + "frequency": "P1D" + } + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-ed43bdb7-eaab-4ea4-be52-6951fcfa7e3b", + "contentKind": "CustomDetection", + "displayName": "Mass Cloud resource deletions Time Series Anomaly", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-ed43bdb7-eaab-4ea4-be52-6951fcfa7e3b','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-ed43bdb7-eaab-4ea4-be52-6951fcfa7e3b','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "pid-1f6369a4-223e-4c86-808c-1d26a17c4def-partnercenter", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [] + } + } } ], "outputs": {} diff --git a/Solutions/Azure Activity/Package/testParameters.json b/Solutions/Azure Activity/Package/testParameters.json index 67757a2c4d4..2f501d5b987 100644 --- a/Solutions/Azure Activity/Package/testParameters.json +++ b/Solutions/Azure Activity/Package/testParameters.json @@ -36,5 +36,40 @@ "metadata": { "description": "Name for the workbook" } + }, + "DeployAnalyticsRule": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Deploy the Microsoft Sentinel analytic rules carried by this solution (ContentKind AnalyticsRule and its AnalyticsRuleTemplate registration face)." + } + }, + "DeployWorkbook": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Deploy the Microsoft Sentinel workbook content and its Content Hub registration carried by this solution (ContentKind Workbook and WorkbookTemplate)." + } + }, + "DeployDataConnector": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Deploy the data connectors carried by this solution, together with their metadata and catalog entries (ContentKind DataConnector, ResourceDataConnector and DataType)." + } + }, + "DeployCustomDetection": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Deploy the XDR-native custom detection resources and their Content Hub registrations (ContentKind CustomDetection and CustomDetectionTemplate). Independent of DeployAnalyticsRule: both kinds can be selected together. Existing analytic-rule instances are not disabled or removed. CD enabled or disabled status is controlled separately from this deployment switch." + } + }, + "DeployHuntingQuery": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Deploy the Microsoft Sentinel hunting queries carried by this solution." + } } } diff --git a/Solutions/Azure Activity/ReleaseNotes.md b/Solutions/Azure Activity/ReleaseNotes.md index 90585a4891b..fc000604183 100644 --- a/Solutions/Azure Activity/ReleaseNotes.md +++ b/Solutions/Azure Activity/ReleaseNotes.md @@ -1,5 +1,6 @@ | **Version** | **Date Modified (DD-MM-YYYY)** | **Change History** | |-------------|--------------------------------|----------------------------------------------------------------------------| +| 3.1.2 | 12-10-2026 | Added 14 disabled Defender XDR Custom Detections with reviewed migration assumptions and offline structural validation. Runtime and alert parity validation were not performed. | | 3.0.4 | 25-02-2026 | Updated description_detailed for the Rare_Custom_Script_Extension Hunting Query. | | 3.0.3 | 19-02-2025 | Added new **Workbook** Azure Service Health to the Solution and added new **Hunting query** Machine_Learning_Creation.yaml.Note: Please refer to the following before installing the solution:
\n• Review the solution Release Notes
\n• There may be known issues pertaining to this Solution, please refer to them before installing.
\nThe Cisco ASA solution for Microsoft Sentinel enables you to ingest Cisco ASA logs into Microsoft Sentinel.
\nCisco ASA/FTD via AMA - This data connector helps in ingesting Cisco ASA logs into your Log Analytics Workspace using the new Azure Monitor Agent. Learn more about ingesting using the new Azure Monitor Agent here.
\n\nUnderlying Microsoft Technologies used:
\nThis solution takes a dependency on the following technologies, and some of these dependencies either may be in Preview state or might result in additional ingestion or operational costs:
\n\nData Connectors: 1, Workbooks: 1, Analytic Rules: 3, Custom Azure Logic Apps Connectors: 1, Playbooks: 3
\nLearn more about Microsoft Sentinel | Learn more about Solutions
\n", + "descriptionHtml": "Note: Please refer to the following before installing the solution:
\n• Review the solution Release Notes
\n• There may be known issues pertaining to this Solution, please refer to them before installing.
\nThe Cisco ASA solution for Microsoft Sentinel enables you to ingest Cisco ASA logs into Microsoft Sentinel.
\nCisco ASA/FTD via AMA - This data connector helps in ingesting Cisco ASA logs into your Log Analytics Workspace using the new Azure Monitor Agent. Learn more about ingesting using the new Azure Monitor Agent here.
\n\nUnderlying Microsoft Technologies used:
\nThis solution takes a dependency on the following technologies, and some of these dependencies either may be in Preview state or might result in additional ingestion or operational costs:
\n\nData Connectors: 1, Workbooks: 1, Analytic Rules: 3, XDR Detections: 3, Custom Azure Logic Apps Connectors: 1, Playbooks: 3
\nLearn more about Microsoft Sentinel | Learn more about Solutions
\n", "contentKind": "Solution", "contentProductId": "[variables('_solutioncontentProductId')]", "id": "[variables('_solutioncontentProductId')]", @@ -5411,6 +5457,21 @@ "kind": "AnalyticsRule", "contentId": "[variables('analyticRuleObject3')._analyticRulecontentId3]", "version": "[variables('analyticRuleObject3').analyticRuleVersion3]" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-795edf2d-cf3e-45b5-8452-fe6c9e6a582e", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-f3a8c2d0-7b41-4e9a-9f6a-2d8a1c4e5b72", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-79f29feb-6a9d-4cdf-baaa-2daf480a5da1", + "version": "3.1.0" } ] }, @@ -5425,6 +5486,524 @@ } }, "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/', variables('_solutionId'))]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "CiscoASA-CD-xdr-795edf2d-cf3e-45b5-8452-fe6c9e6a582e", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "queryCondition": { + "queryText": "CommonSecurityLog\n| where isempty(CommunicationDirection)\n| where DeviceEventClassID in (\"733101\",\"733102\",\"733103\",\"733104\",\"733105\")\n| extend HostName = tostring(split(DeviceName, \".\")[0]), DomainIndex = toint(indexof(DeviceName, '.'))\n| extend HostNameDomain = iff(DomainIndex != -1, substring(DeviceName, DomainIndex + 1), DeviceName)" + }, + "displayName": "Cisco ASA - threat detection message fired", + "id": "[if(true(), 'xdr-795edf2d-cf3e-45b5-8452-fe6c9e6a582e', 'xdr-795edf2d-cf3e-45b5-8452-fe6c9e6a582e')]", + "schedule": { + "frequency": "PT1H" + }, + "status": "disabled", + "detectionAction": { + "alertTemplate": { + "title": "Cisco ASA - threat detection message fired", + "tactics": [ + { + "techniques": [ + { + "technique": "T1046" + } + ], + "tactic": "Discovery" + } + ], + "description": "'Identifies when the Cisco ASA Threat Detection engine fired an alert based on malicious activity occurring on the network inicated by DeviceEventClassID 733101-733105\nResources: https://www.cisco.com/c/en/us/td/docs/security/asa/syslog/b_syslog/syslogs9.html\nDetails on how to further troubleshoot/investigate: https://www.cisco.com/c/en/us/support/docs/security/asa-5500-x-series-next-generation-firewalls/113685-asa-threat-detection.html'", + "customDetails": { + "HostFullName": "DeviceName" + }, + "severity": "medium", + "entityMappings": { + "ips": [ + { + "addressColumn": "SourceIP", + "id": "[if(true(), 'ip1', 'ip1')]" + } + ], + "hosts": [ + { + "nameColumn": "DeviceName", + "id": "[if(true(), 'host1', 'host1')]" + } + ] + } + } + } + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-795edf2d-cf3e-45b5-8452-fe6c9e6a582e')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'CiscoASA-CD-xdr-795edf2d-cf3e-45b5-8452-fe6c9e6a582e')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'Identifies when the Cisco ASA Threat Detection engine fired an alert based on malicious activity occurring on the network inicated by DeviceEventClassID 733101-733105\nResources: https://www.cisco.com/c/en/us/td/docs/security/asa/syslog/b_syslog/syslogs9.html\nDetails on how to further troubleshoot/investigate: https://www.cisco.com/c/en/us/support/docs/security/asa-5500-x-series-next-generation-firewalls/113685-asa-threat-detection.html'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "queryCondition": { + "queryText": "CommonSecurityLog\n| where isempty(CommunicationDirection)\n| where DeviceEventClassID in (\"733101\",\"733102\",\"733103\",\"733104\",\"733105\")\n| extend HostName = tostring(split(DeviceName, \".\")[0]), DomainIndex = toint(indexof(DeviceName, '.'))\n| extend HostNameDomain = iff(DomainIndex != -1, substring(DeviceName, DomainIndex + 1), DeviceName)" + }, + "displayName": "Cisco ASA - threat detection message fired", + "id": "[if(true(), 'xdr-795edf2d-cf3e-45b5-8452-fe6c9e6a582e', 'xdr-795edf2d-cf3e-45b5-8452-fe6c9e6a582e')]", + "schedule": { + "frequency": "PT1H" + }, + "status": "disabled", + "detectionAction": { + "alertTemplate": { + "title": "Cisco ASA - threat detection message fired", + "tactics": [ + { + "techniques": [ + { + "technique": "T1046" + } + ], + "tactic": "Discovery" + } + ], + "description": "'Identifies when the Cisco ASA Threat Detection engine fired an alert based on malicious activity occurring on the network inicated by DeviceEventClassID 733101-733105\nResources: https://www.cisco.com/c/en/us/td/docs/security/asa/syslog/b_syslog/syslogs9.html\nDetails on how to further troubleshoot/investigate: https://www.cisco.com/c/en/us/support/docs/security/asa-5500-x-series-next-generation-firewalls/113685-asa-threat-detection.html'", + "customDetails": { + "HostFullName": "DeviceName" + }, + "severity": "medium", + "entityMappings": { + "ips": [ + { + "addressColumn": "SourceIP", + "id": "[if(true(), 'ip1', 'ip1')]" + } + ], + "hosts": [ + { + "nameColumn": "DeviceName", + "id": "[if(true(), 'host1', 'host1')]" + } + ] + } + } + } + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-795edf2d-cf3e-45b5-8452-fe6c9e6a582e", + "contentKind": "CustomDetection", + "displayName": "Cisco ASA - threat detection message fired", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-795edf2d-cf3e-45b5-8452-fe6c9e6a582e','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-795edf2d-cf3e-45b5-8452-fe6c9e6a582e','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "CiscoASA-CD-xdr-f3a8c2d0-7b41-4e9a-9f6a-2d8a1c4e5b72", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "queryCondition": { + "queryText": "let Lookback = 1h;\nlet MinUploadBytes = 1073741824;\nlet MinUploadRatio = 95.0;\nCommonSecurityLog\n| where TimeGenerated > ago(Lookback)\n| where DeviceProduct has_any (\"ASA\", \"FTD\")\n| where isnotempty(SourceIP) and isnotempty(DestinationIP)\n| where ipv4_is_private(SourceIP)\n| where not(ipv4_is_private(DestinationIP))\n| where DeviceAction in~ (\"allow\", \"allowed\", \"accept\", \"accepted\", \"permitted\")\n| extend SentBytesLong = tolong(SentBytes)\n| extend ReceivedBytesLong = tolong(ReceivedBytes)\n| where isnotnull(SentBytesLong)\n| summarize\n TotalBytesSent = sum(SentBytesLong),\n TotalBytesReceived = sum(coalesce(ReceivedBytesLong, 0)),\n Connections = count(),\n DestinationPorts = make_set(DestinationPort, 20),\n Applications = make_set(ApplicationProtocol, 20),\n FirstSeen = min(TimeGenerated),\n LastSeen = max(TimeGenerated)\n by SourceIP, DestinationIP\n| where TotalBytesSent >= MinUploadBytes\n| extend TotalGBSent = round(TotalBytesSent / 1024.0 / 1024.0 / 1024.0, 2)\n| extend TotalGBReceived = round(TotalBytesReceived / 1024.0 / 1024.0 / 1024.0, 2)\n| extend UploadRatio = round(todouble(TotalBytesSent) / todouble(TotalBytesSent + TotalBytesReceived) * 100, 2)\n| where UploadRatio >= MinUploadRatio\n| project\n TimeGenerated = LastSeen,\n SourceIP,\n DestinationIP,\n TotalGBSent,\n TotalGBReceived,\n UploadRatio,\n Connections,\n DestinationPorts,\n Applications,\n FirstSeen,\n LastSeen\n| order by TotalGBSent desc" + }, + "displayName": "Cisco ASA - Possible Data Exfiltration Detection", + "id": "[if(true(), 'xdr-f3a8c2d0-7b41-4e9a-9f6a-2d8a1c4e5b72', 'xdr-f3a8c2d0-7b41-4e9a-9f6a-2d8a1c4e5b72')]", + "schedule": { + "frequency": "PT1H" + }, + "status": "disabled", + "detectionAction": { + "alertTemplate": { + "severity": "medium", + "entityMappings": { + "ips": [ + { + "addressColumn": "SourceIP", + "id": "[if(true(), 'ip1', 'ip1')]" + }, + { + "addressColumn": "DestinationIP", + "id": "[if(true(), 'ip2', 'ip2')]" + } + ] + }, + "title": "Cisco ASA - Possible Data Exfiltration Detection", + "tactics": [ + { + "techniques": [ + { + "technique": "T1041" + }, + { + "technique": "T1048" + } + ], + "tactic": "Exfiltration" + } + ], + "description": "'Detects potential data exfiltration when an internal source IP sends a large amount of outbound data to the internet, especially when the volume is significantly higher than its normal behavior.'" + } + } + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-f3a8c2d0-7b41-4e9a-9f6a-2d8a1c4e5b72')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'CiscoASA-CD-xdr-f3a8c2d0-7b41-4e9a-9f6a-2d8a1c4e5b72')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'Detects potential data exfiltration when an internal source IP sends a large amount of outbound data to the internet, especially when the volume is significantly higher than its normal behavior.'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "queryCondition": { + "queryText": "let Lookback = 1h;\nlet MinUploadBytes = 1073741824;\nlet MinUploadRatio = 95.0;\nCommonSecurityLog\n| where TimeGenerated > ago(Lookback)\n| where DeviceProduct has_any (\"ASA\", \"FTD\")\n| where isnotempty(SourceIP) and isnotempty(DestinationIP)\n| where ipv4_is_private(SourceIP)\n| where not(ipv4_is_private(DestinationIP))\n| where DeviceAction in~ (\"allow\", \"allowed\", \"accept\", \"accepted\", \"permitted\")\n| extend SentBytesLong = tolong(SentBytes)\n| extend ReceivedBytesLong = tolong(ReceivedBytes)\n| where isnotnull(SentBytesLong)\n| summarize\n TotalBytesSent = sum(SentBytesLong),\n TotalBytesReceived = sum(coalesce(ReceivedBytesLong, 0)),\n Connections = count(),\n DestinationPorts = make_set(DestinationPort, 20),\n Applications = make_set(ApplicationProtocol, 20),\n FirstSeen = min(TimeGenerated),\n LastSeen = max(TimeGenerated)\n by SourceIP, DestinationIP\n| where TotalBytesSent >= MinUploadBytes\n| extend TotalGBSent = round(TotalBytesSent / 1024.0 / 1024.0 / 1024.0, 2)\n| extend TotalGBReceived = round(TotalBytesReceived / 1024.0 / 1024.0 / 1024.0, 2)\n| extend UploadRatio = round(todouble(TotalBytesSent) / todouble(TotalBytesSent + TotalBytesReceived) * 100, 2)\n| where UploadRatio >= MinUploadRatio\n| project\n TimeGenerated = LastSeen,\n SourceIP,\n DestinationIP,\n TotalGBSent,\n TotalGBReceived,\n UploadRatio,\n Connections,\n DestinationPorts,\n Applications,\n FirstSeen,\n LastSeen\n| order by TotalGBSent desc" + }, + "displayName": "Cisco ASA - Possible Data Exfiltration Detection", + "id": "[if(true(), 'xdr-f3a8c2d0-7b41-4e9a-9f6a-2d8a1c4e5b72', 'xdr-f3a8c2d0-7b41-4e9a-9f6a-2d8a1c4e5b72')]", + "schedule": { + "frequency": "PT1H" + }, + "status": "disabled", + "detectionAction": { + "alertTemplate": { + "severity": "medium", + "entityMappings": { + "ips": [ + { + "addressColumn": "SourceIP", + "id": "[if(true(), 'ip1', 'ip1')]" + }, + { + "addressColumn": "DestinationIP", + "id": "[if(true(), 'ip2', 'ip2')]" + } + ] + }, + "title": "Cisco ASA - Possible Data Exfiltration Detection", + "tactics": [ + { + "techniques": [ + { + "technique": "T1041" + }, + { + "technique": "T1048" + } + ], + "tactic": "Exfiltration" + } + ], + "description": "'Detects potential data exfiltration when an internal source IP sends a large amount of outbound data to the internet, especially when the volume is significantly higher than its normal behavior.'" + } + } + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-f3a8c2d0-7b41-4e9a-9f6a-2d8a1c4e5b72", + "contentKind": "CustomDetection", + "displayName": "Cisco ASA - Possible Data Exfiltration Detection", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-f3a8c2d0-7b41-4e9a-9f6a-2d8a1c4e5b72','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-f3a8c2d0-7b41-4e9a-9f6a-2d8a1c4e5b72','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "CiscoASA-CD-xdr-79f29feb-6a9d-4cdf-baaa-2daf480a5da1", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "queryCondition": { + "queryText": "let timeframe = 1h;\nlet last1h = CommonSecurityLog\n| where TimeGenerated >= ago(timeframe)\n| where isempty(CommunicationDirection)\n| where DeviceEventClassID == \"733100\"\n| extend SourceOfDropRateCount = tostring(split(tostring(split(Message, \"]\")[0]),\"[ \")[1])\n| extend splitMessage = split(Message, \".\")\n| extend DropRate = tostring(split(tostring(splitMessage[0]),\"] \")[1])\n| extend CurrentBurstRate = split(tostring(split(tostring(splitMessage[1]),\" \")[0]),\"is \")\n| extend CurrentBurstRatePerSec = toint(split(tostring(CurrentBurstRate[1]),\" \")[0])\n| extend MaxConfiguredBurstRate = toint(CurrentBurstRate[2])\n| extend CurrentAvgRate = split(tostring(split(tostring(splitMessage[1]),\" \")[1]),\"is \")\n| extend CurrentAvgRatePerSec = toint(split(tostring(CurrentAvgRate[1]),\" \")[0])\n| extend MaxConfiguredAvgRate = toint(CurrentAvgRate[2])\n| extend CumulativeTotal = toint(split(tostring(split(tostring(splitMessage[1]),\" \")[2]),\"is \")[1])\n| summarize last1hCumTotal = sum(CumulativeTotal), last1hAvgRatePerSec = avg(CurrentAvgRatePerSec), last1hAvgBurstRatePerSec = avg(CurrentBurstRatePerSec) by DeviceName, DeviceEventClassID, SourceIP, SourceOfDropRateCount, DropRate;\nlet prev6h = CommonSecurityLog\n| where TimeGenerated between (ago(6h) .. ago(1h))\n| where isempty(CommunicationDirection)\n| where DeviceEventClassID == \"733100\"\n| extend SourceOfDropRateCount = tostring(split(tostring(split(Message, \"]\")[0]),\"[ \")[1])\n| extend splitMessage = split(Message, \".\")\n| extend DropRate = tostring(split(tostring(splitMessage[0]),\"] \")[1])\n| extend CurrentBurstRate = split(tostring(split(tostring(splitMessage[1]),\" \")[0]),\"is \")\n| extend prevCurrentBurstRatePerSec = toint(split(tostring(CurrentBurstRate[1]),\" \")[0])\n| extend prevMaxConfiguredBurstRate = toint(CurrentBurstRate[2])\n| extend CurrentAvgRate = split(tostring(split(tostring(splitMessage[1]),\" \")[1]),\"is \")\n| extend prevCurrentAvgRatePerSec = toint(split(tostring(CurrentAvgRate[1]),\" \")[0])\n| extend prevMaxConfiguredAvgRate = toint(CurrentAvgRate[2])\n| extend prevCumulativeTotal = toint(split(tostring(split(tostring(splitMessage[1]),\" \")[2]),\"is \")[1])\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), prev6hCumTotal = sum(prevCumulativeTotal), prev6hAvgRatePerSec = avg(prevCurrentAvgRatePerSec), prev6hAvgBurstRatePerSec = avg(prevCurrentBurstRatePerSec)\nby DeviceName, DeviceEventClassID, SourceIP, SourceOfDropRateCount, DropRate;\nlast1h | join (\n prev6h\n) on DeviceName, DeviceEventClassID, SourceIP, SourceOfDropRateCount, DropRate\n| project StartTimeUtc, EndTimeUtc, DeviceName, DeviceEventClassID, SourceIP, SourceOfDropRateCount, DropRate, last1hCumTotal, prev6hCumTotal, prev6hAvgCumTotal = prev6hCumTotal/6, last1hAvgRatePerSec, prev6hAvgRatePerSec, last1hAvgBurstRatePerSec, prev6hAvgBurstRatePerSec\n// Select only events that indicate a doubling of the expected rate in the last hour over the previous 6 hours\n| where last1hCumTotal > 2*prev6hAvgCumTotal or last1hAvgRatePerSec > 2*prev6hAvgRatePerSec or last1hAvgBurstRatePerSec > 2*prev6hAvgBurstRatePerSec\n| extend HostName = tostring(split(DeviceName, \".\")[0]), DomainIndex = toint(indexof(DeviceName, '.'))\n| extend HostNameDomain = iff(DomainIndex != -1, substring(DeviceName, DomainIndex + 1), DeviceName)" + }, + "displayName": "Cisco ASA - average attack detection rate increase", + "id": "[if(true(), 'xdr-79f29feb-6a9d-4cdf-baaa-2daf480a5da1', 'xdr-79f29feb-6a9d-4cdf-baaa-2daf480a5da1')]", + "schedule": { + "frequency": "PT1H" + }, + "status": "disabled", + "detectionAction": { + "alertTemplate": { + "title": "Cisco ASA - average attack detection rate increase", + "tactics": [ + { + "techniques": [ + { + "technique": "T1046" + } + ], + "tactic": "Discovery" + } + ], + "description": "'This will help you determine if Cisco ASA devices are under heavier attack than normal over the last hour versus the previous 6 hours based on DeviceEventClassID 733100\nReferences: https://www.cisco.com/c/en/us/td/docs/security/asa/syslog/b_syslog/syslogs9.html\nDetails on how to further troubleshoot/investigate: https://www.cisco.com/c/en/us/support/docs/security/asa-5500-x-series-next-generation-firewalls/113685-asa-threat-detection.html'", + "customDetails": { + "HostFullName": "DeviceName" + }, + "severity": "low", + "entityMappings": { + "ips": [ + { + "addressColumn": "SourceIP", + "id": "[if(true(), 'ip1', 'ip1')]" + } + ], + "hosts": [ + { + "nameColumn": "HostName", + "id": "[if(true(), 'host1', 'host1')]", + "dnsDomainColumn": "HostNameDomain" + } + ] + } + } + } + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-79f29feb-6a9d-4cdf-baaa-2daf480a5da1')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'CiscoASA-CD-xdr-79f29feb-6a9d-4cdf-baaa-2daf480a5da1')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'This will help you determine if Cisco ASA devices are under heavier attack than normal over the last hour versus the previous 6 hours based on DeviceEventClassID 733100\nReferences: https://www.cisco.com/c/en/us/td/docs/security/asa/syslog/b_syslog/syslogs9.html\nDetails on how to further troubleshoot/investigate: https://www.cisco.com/c/en/us/support/docs/security/asa-5500-x-series-next-generation-firewalls/113685-asa-threat-detection.html'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "queryCondition": { + "queryText": "let timeframe = 1h;\nlet last1h = CommonSecurityLog\n| where TimeGenerated >= ago(timeframe)\n| where isempty(CommunicationDirection)\n| where DeviceEventClassID == \"733100\"\n| extend SourceOfDropRateCount = tostring(split(tostring(split(Message, \"]\")[0]),\"[ \")[1])\n| extend splitMessage = split(Message, \".\")\n| extend DropRate = tostring(split(tostring(splitMessage[0]),\"] \")[1])\n| extend CurrentBurstRate = split(tostring(split(tostring(splitMessage[1]),\" \")[0]),\"is \")\n| extend CurrentBurstRatePerSec = toint(split(tostring(CurrentBurstRate[1]),\" \")[0])\n| extend MaxConfiguredBurstRate = toint(CurrentBurstRate[2])\n| extend CurrentAvgRate = split(tostring(split(tostring(splitMessage[1]),\" \")[1]),\"is \")\n| extend CurrentAvgRatePerSec = toint(split(tostring(CurrentAvgRate[1]),\" \")[0])\n| extend MaxConfiguredAvgRate = toint(CurrentAvgRate[2])\n| extend CumulativeTotal = toint(split(tostring(split(tostring(splitMessage[1]),\" \")[2]),\"is \")[1])\n| summarize last1hCumTotal = sum(CumulativeTotal), last1hAvgRatePerSec = avg(CurrentAvgRatePerSec), last1hAvgBurstRatePerSec = avg(CurrentBurstRatePerSec) by DeviceName, DeviceEventClassID, SourceIP, SourceOfDropRateCount, DropRate;\nlet prev6h = CommonSecurityLog\n| where TimeGenerated between (ago(6h) .. ago(1h))\n| where isempty(CommunicationDirection)\n| where DeviceEventClassID == \"733100\"\n| extend SourceOfDropRateCount = tostring(split(tostring(split(Message, \"]\")[0]),\"[ \")[1])\n| extend splitMessage = split(Message, \".\")\n| extend DropRate = tostring(split(tostring(splitMessage[0]),\"] \")[1])\n| extend CurrentBurstRate = split(tostring(split(tostring(splitMessage[1]),\" \")[0]),\"is \")\n| extend prevCurrentBurstRatePerSec = toint(split(tostring(CurrentBurstRate[1]),\" \")[0])\n| extend prevMaxConfiguredBurstRate = toint(CurrentBurstRate[2])\n| extend CurrentAvgRate = split(tostring(split(tostring(splitMessage[1]),\" \")[1]),\"is \")\n| extend prevCurrentAvgRatePerSec = toint(split(tostring(CurrentAvgRate[1]),\" \")[0])\n| extend prevMaxConfiguredAvgRate = toint(CurrentAvgRate[2])\n| extend prevCumulativeTotal = toint(split(tostring(split(tostring(splitMessage[1]),\" \")[2]),\"is \")[1])\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), prev6hCumTotal = sum(prevCumulativeTotal), prev6hAvgRatePerSec = avg(prevCurrentAvgRatePerSec), prev6hAvgBurstRatePerSec = avg(prevCurrentBurstRatePerSec)\nby DeviceName, DeviceEventClassID, SourceIP, SourceOfDropRateCount, DropRate;\nlast1h | join (\n prev6h\n) on DeviceName, DeviceEventClassID, SourceIP, SourceOfDropRateCount, DropRate\n| project StartTimeUtc, EndTimeUtc, DeviceName, DeviceEventClassID, SourceIP, SourceOfDropRateCount, DropRate, last1hCumTotal, prev6hCumTotal, prev6hAvgCumTotal = prev6hCumTotal/6, last1hAvgRatePerSec, prev6hAvgRatePerSec, last1hAvgBurstRatePerSec, prev6hAvgBurstRatePerSec\n// Select only events that indicate a doubling of the expected rate in the last hour over the previous 6 hours\n| where last1hCumTotal > 2*prev6hAvgCumTotal or last1hAvgRatePerSec > 2*prev6hAvgRatePerSec or last1hAvgBurstRatePerSec > 2*prev6hAvgBurstRatePerSec\n| extend HostName = tostring(split(DeviceName, \".\")[0]), DomainIndex = toint(indexof(DeviceName, '.'))\n| extend HostNameDomain = iff(DomainIndex != -1, substring(DeviceName, DomainIndex + 1), DeviceName)" + }, + "displayName": "Cisco ASA - average attack detection rate increase", + "id": "[if(true(), 'xdr-79f29feb-6a9d-4cdf-baaa-2daf480a5da1', 'xdr-79f29feb-6a9d-4cdf-baaa-2daf480a5da1')]", + "schedule": { + "frequency": "PT1H" + }, + "status": "disabled", + "detectionAction": { + "alertTemplate": { + "title": "Cisco ASA - average attack detection rate increase", + "tactics": [ + { + "techniques": [ + { + "technique": "T1046" + } + ], + "tactic": "Discovery" + } + ], + "description": "'This will help you determine if Cisco ASA devices are under heavier attack than normal over the last hour versus the previous 6 hours based on DeviceEventClassID 733100\nReferences: https://www.cisco.com/c/en/us/td/docs/security/asa/syslog/b_syslog/syslogs9.html\nDetails on how to further troubleshoot/investigate: https://www.cisco.com/c/en/us/support/docs/security/asa-5500-x-series-next-generation-firewalls/113685-asa-threat-detection.html'", + "customDetails": { + "HostFullName": "DeviceName" + }, + "severity": "low", + "entityMappings": { + "ips": [ + { + "addressColumn": "SourceIP", + "id": "[if(true(), 'ip1', 'ip1')]" + } + ], + "hosts": [ + { + "nameColumn": "HostName", + "id": "[if(true(), 'host1', 'host1')]", + "dnsDomainColumn": "HostNameDomain" + } + ] + } + } + } + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-79f29feb-6a9d-4cdf-baaa-2daf480a5da1", + "contentKind": "CustomDetection", + "displayName": "Cisco ASA - average attack detection rate increase", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-79f29feb-6a9d-4cdf-baaa-2daf480a5da1','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-79f29feb-6a9d-4cdf-baaa-2daf480a5da1','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "pid-3a2fe349-a98b-4e96-83d2-045415a8ffa9-partnercenter", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [] + } + } } ], "outputs": {} diff --git a/Solutions/CiscoASA/Package/testParameters.json b/Solutions/CiscoASA/Package/testParameters.json index b1cecba0740..2812ef3b7d9 100644 --- a/Solutions/CiscoASA/Package/testParameters.json +++ b/Solutions/CiscoASA/Package/testParameters.json @@ -28,5 +28,40 @@ "metadata": { "description": "Name for the workbook" } + }, + "DeployAnalyticsRule": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Deploy the Microsoft Sentinel analytic rules carried by this solution (ContentKind AnalyticsRule and its AnalyticsRuleTemplate registration face)." + } + }, + "DeployPlaybook": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Deploy the playbooks carried by this solution and the automation assets they depend on (PlaybookTemplate, AzureFunction, LogicAppsCustomConnector). These are never shipped independently of the playbook they serve." + } + }, + "DeployWorkbook": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Deploy the Microsoft Sentinel workbook content and its Content Hub registration carried by this solution (ContentKind Workbook and WorkbookTemplate)." + } + }, + "DeployDataConnector": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Deploy the data connectors carried by this solution, together with their metadata and catalog entries (ContentKind DataConnector, ResourceDataConnector and DataType)." + } + }, + "DeployCustomDetection": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Deploy the XDR-native custom detection resources and their Content Hub registrations (ContentKind CustomDetection and CustomDetectionTemplate). Independent of DeployAnalyticsRule: both kinds can be selected together. Existing analytic-rule instances are not disabled or removed. CD enabled or disabled status is controlled separately from this deployment switch." + } } } diff --git a/Solutions/CiscoASA/ReleaseNotes.md b/Solutions/CiscoASA/ReleaseNotes.md index 1e831a7a5ff..b064208b62b 100644 --- a/Solutions/CiscoASA/ReleaseNotes.md +++ b/Solutions/CiscoASA/ReleaseNotes.md @@ -1,5 +1,8 @@ | **Version** | **Date Modified (DD-MM-YYYY)** | **Change History** | |-------------|--------------------------------|------------------------------------------------------------------------------| +| 3.1.2 | 12-10-2026 | Refreshed the V3.1 hybrid package for three disabled Defender XDR Custom Detections with reviewed Host mappings and source-rule provenance. | +| 3.1.1 | 11-10-2026 | Added a reviewed Host mapping to the threat-message Custom Detection and recorded accepted Host-mapping assumptions while preserving original host values in alert details. | +| 3.1.0 | 11-10-2026 | Added three disabled Defender XDR Custom Detections with source-rule provenance and V3.1 hybrid packaging support. | | 3.0.9 | 15-09-2026 |Updated the CiscoASA workbook and analytic rules to incorporate FTD logs alongside ASA logs. | | 3.0.8 | 22-08-2026 | Added new detection rule for Possible Data Exfilteration | | 3.0.7 | 01-09-2025 | Updates to the `template_CiscoAsaAma.json` file to reflect the general availability of the Cisco ASA/FTD via AMA connector | diff --git a/Solutions/CiscoASA/SolutionMetadata.json b/Solutions/CiscoASA/SolutionMetadata.json index d69f02d0df3..a66f67fb93a 100644 --- a/Solutions/CiscoASA/SolutionMetadata.json +++ b/Solutions/CiscoASA/SolutionMetadata.json @@ -1,16 +1,22 @@ { - "publisherId": "azuresentinel", - "offerId": "azure-sentinel-solution-ciscoasa", - "firstPublishDate": "2022-05-23", - "providers": ["Cisco"], - "categories": { - "domains" : ["Security - Automation (SOAR)"], - "verticals": [] - }, - "support": { - "tier": "Microsoft", - "name": "Microsoft Corporation", - "email": "support@microsoft.com", - "link": "https://support.microsoft.com/" - } -} \ No newline at end of file + "trackingId": "pid-3a2fe349-a98b-4e96-83d2-045415a8ffa9-partnercenter", + "publisherId": "azuresentinel", + "offerId": "azure-sentinel-solution-ciscoasa", + "firstPublishDate": "2022-05-23", + "providers": [ + "Cisco" + ], + "categories": { + "domains": [ + "Security - Automation (SOAR)" + ], + "verticals": [] + }, + "support": { + "tier": "Microsoft", + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "link": "https://support.microsoft.com/" + }, + "version": "3.1.2" +} diff --git a/Solutions/CiscoASA/XDR Detections/CiscoASA-AvgAttackDetectRateIncrease.yaml b/Solutions/CiscoASA/XDR Detections/CiscoASA-AvgAttackDetectRateIncrease.yaml new file mode 100644 index 00000000000..af37a956cba --- /dev/null +++ b/Solutions/CiscoASA/XDR Detections/CiscoASA-AvgAttackDetectRateIncrease.yaml @@ -0,0 +1,145 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: CiscoAsaAma + dataTypes: + - CommonSecurityLog +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: 79f29feb-6a9d-4cdf-baaa-2daf480a5da1 + path: Analytic Rules/CiscoASA-AvgAttackDetectRateIncrease.yaml + version: 1.0.3 + querySha256: 5bb9db1a60eb71e21009f4b1e0d049090642e0c89b8c693d50b3f66219bb1143 + schedule: + queryFrequency: 1h + queryPeriod: 6h + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - 'Schedule assessment: source frequency=1h, lookback=6h; target frequency=PT1H, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - 'Best-effort entity mapping requires review: source Host.FullName column `DeviceName` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - Host.FullName value is retained as customDetails.HostFullName from query column `DeviceName`, but its target output + binding requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.HostFullName column `DeviceName` requires runtime output-schema binding verification + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: + - All source MITRE tactics are preserved in source order in authored YAML. V3.1 ARM packaging carries only the first tactic + and its compatible techniques; this classification loss is not validated parity. Direct Graph deployment requires a + single tactic. + errors: [] + originalTactics: + - Discovery + - Impact + originalTechniques: + - T1046 + - T1498 + reviewScope: + sourceDocumentSha256: 8e3a5cd157088c224cdaf56c1505b3175865e771700c9fc14afac7b2cc042c87 + targetQuerySha256: d97131b413ab064a6fc032c18fadc8fe78c6eaa2ee5973230904cf6528704b8e + reviewDecisions: + - reason: 'Best-effort entity mapping requires review: source Host.FullName column `DeviceName` is provisionally represented + by hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + decision: accepted + sourceDocumentSha256: 8e3a5cd157088c224cdaf56c1505b3175865e771700c9fc14afac7b2cc042c87 + targetQuerySha256: d97131b413ab064a6fc032c18fadc8fe78c6eaa2ee5973230904cf6528704b8e + supplementalEntityDetails: + - entityType: Host + entityIndex: 1 + identifier: FullName + sourceColumn: DeviceName + column: DeviceName + status: runtime-binding-pending + customDetailKey: HostFullName + acceptedReviewReasons: + - 'Best-effort entity mapping requires review: source Host.FullName column `DeviceName` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' +properties: + id: xdr-79f29feb-6a9d-4cdf-baaa-2daf480a5da1 + displayName: Cisco ASA - average attack detection rate increase + status: disabled + queryCondition: + queryText: |- + let timeframe = 1h; + let last1h = CommonSecurityLog + | where TimeGenerated >= ago(timeframe) + | where isempty(CommunicationDirection) + | where DeviceEventClassID == "733100" + | extend SourceOfDropRateCount = tostring(split(tostring(split(Message, "]")[0]),"[ ")[1]) + | extend splitMessage = split(Message, ".") + | extend DropRate = tostring(split(tostring(splitMessage[0]),"] ")[1]) + | extend CurrentBurstRate = split(tostring(split(tostring(splitMessage[1])," ")[0]),"is ") + | extend CurrentBurstRatePerSec = toint(split(tostring(CurrentBurstRate[1])," ")[0]) + | extend MaxConfiguredBurstRate = toint(CurrentBurstRate[2]) + | extend CurrentAvgRate = split(tostring(split(tostring(splitMessage[1])," ")[1]),"is ") + | extend CurrentAvgRatePerSec = toint(split(tostring(CurrentAvgRate[1])," ")[0]) + | extend MaxConfiguredAvgRate = toint(CurrentAvgRate[2]) + | extend CumulativeTotal = toint(split(tostring(split(tostring(splitMessage[1])," ")[2]),"is ")[1]) + | summarize last1hCumTotal = sum(CumulativeTotal), last1hAvgRatePerSec = avg(CurrentAvgRatePerSec), last1hAvgBurstRatePerSec = avg(CurrentBurstRatePerSec) by DeviceName, DeviceEventClassID, SourceIP, SourceOfDropRateCount, DropRate; + let prev6h = CommonSecurityLog + | where TimeGenerated between (ago(6h) .. ago(1h)) + | where isempty(CommunicationDirection) + | where DeviceEventClassID == "733100" + | extend SourceOfDropRateCount = tostring(split(tostring(split(Message, "]")[0]),"[ ")[1]) + | extend splitMessage = split(Message, ".") + | extend DropRate = tostring(split(tostring(splitMessage[0]),"] ")[1]) + | extend CurrentBurstRate = split(tostring(split(tostring(splitMessage[1])," ")[0]),"is ") + | extend prevCurrentBurstRatePerSec = toint(split(tostring(CurrentBurstRate[1])," ")[0]) + | extend prevMaxConfiguredBurstRate = toint(CurrentBurstRate[2]) + | extend CurrentAvgRate = split(tostring(split(tostring(splitMessage[1])," ")[1]),"is ") + | extend prevCurrentAvgRatePerSec = toint(split(tostring(CurrentAvgRate[1])," ")[0]) + | extend prevMaxConfiguredAvgRate = toint(CurrentAvgRate[2]) + | extend prevCumulativeTotal = toint(split(tostring(split(tostring(splitMessage[1])," ")[2]),"is ")[1]) + | summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), prev6hCumTotal = sum(prevCumulativeTotal), prev6hAvgRatePerSec = avg(prevCurrentAvgRatePerSec), prev6hAvgBurstRatePerSec = avg(prevCurrentBurstRatePerSec) + by DeviceName, DeviceEventClassID, SourceIP, SourceOfDropRateCount, DropRate; + last1h | join ( + prev6h + ) on DeviceName, DeviceEventClassID, SourceIP, SourceOfDropRateCount, DropRate + | project StartTimeUtc, EndTimeUtc, DeviceName, DeviceEventClassID, SourceIP, SourceOfDropRateCount, DropRate, last1hCumTotal, prev6hCumTotal, prev6hAvgCumTotal = prev6hCumTotal/6, last1hAvgRatePerSec, prev6hAvgRatePerSec, last1hAvgBurstRatePerSec, prev6hAvgBurstRatePerSec + // Select only events that indicate a doubling of the expected rate in the last hour over the previous 6 hours + | where last1hCumTotal > 2*prev6hAvgCumTotal or last1hAvgRatePerSec > 2*prev6hAvgRatePerSec or last1hAvgBurstRatePerSec > 2*prev6hAvgBurstRatePerSec + | extend HostName = tostring(split(DeviceName, ".")[0]), DomainIndex = toint(indexof(DeviceName, '.')) + | extend HostNameDomain = iff(DomainIndex != -1, substring(DeviceName, DomainIndex + 1), DeviceName) + schedule: + frequency: PT1H + detectionAction: + alertTemplate: + title: Cisco ASA - average attack detection rate increase + description: |- + 'This will help you determine if Cisco ASA devices are under heavier attack than normal over the last hour versus the previous 6 hours based on DeviceEventClassID 733100 + References: https://www.cisco.com/c/en/us/td/docs/security/asa/syslog/b_syslog/syslogs9.html + Details on how to further troubleshoot/investigate: https://www.cisco.com/c/en/us/support/docs/security/asa-5500-x-series-next-generation-firewalls/113685-asa-threat-detection.html' + severity: low + entityMappings: + hosts: + - id: host1 + nameColumn: HostName + dnsDomainColumn: HostNameDomain + ips: + - id: ip1 + addressColumn: SourceIP + tactics: + - tactic: Discovery + techniques: + - technique: T1046 + - tactic: Impact + techniques: + - technique: T1498 + customDetails: + HostFullName: DeviceName diff --git a/Solutions/CiscoASA/XDR Detections/CiscoASA-PossibleDataExfiltration.yaml b/Solutions/CiscoASA/XDR Detections/CiscoASA-PossibleDataExfiltration.yaml new file mode 100644 index 00000000000..33060261bca --- /dev/null +++ b/Solutions/CiscoASA/XDR Detections/CiscoASA-PossibleDataExfiltration.yaml @@ -0,0 +1,106 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: CiscoAsaAma + dataTypes: + - CommonSecurityLog +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: f3a8c2d0-7b41-4e9a-9f6a-2d8a1c4e5b72 + path: Analytic Rules/CiscoASA-PossibleDataExfiltration.yaml + version: 1.0.2 + querySha256: f1d897203ad69c043b0c39637d5d5453043c2a5125da58fb4661ee7cfaf54712 + schedule: + queryFrequency: 1h + queryPeriod: 1h + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - 'Schedule assessment: source frequency=1h, lookback=1h; target frequency=PT1H, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + informational: [] + errors: [] + originalTactics: + - Exfiltration + originalTechniques: + - T1041 + - T1048 + reviewScope: + sourceDocumentSha256: 8c396f191884d39b0116322d96829140ed5bec7fd7de3118579390ebd7129728 + targetQuerySha256: 6a81fb5eae70a7441a378b0a8cf6e5073747c7376befbedf5b36f6bb601dad64 +properties: + id: xdr-f3a8c2d0-7b41-4e9a-9f6a-2d8a1c4e5b72 + displayName: Cisco ASA - Possible Data Exfiltration Detection + status: disabled + queryCondition: + queryText: |- + let Lookback = 1h; + let MinUploadBytes = 1073741824; + let MinUploadRatio = 95.0; + CommonSecurityLog + | where TimeGenerated > ago(Lookback) + | where DeviceProduct has_any ("ASA", "FTD") + | where isnotempty(SourceIP) and isnotempty(DestinationIP) + | where ipv4_is_private(SourceIP) + | where not(ipv4_is_private(DestinationIP)) + | where DeviceAction in~ ("allow", "allowed", "accept", "accepted", "permitted") + | extend SentBytesLong = tolong(SentBytes) + | extend ReceivedBytesLong = tolong(ReceivedBytes) + | where isnotnull(SentBytesLong) + | summarize + TotalBytesSent = sum(SentBytesLong), + TotalBytesReceived = sum(coalesce(ReceivedBytesLong, 0)), + Connections = count(), + DestinationPorts = make_set(DestinationPort, 20), + Applications = make_set(ApplicationProtocol, 20), + FirstSeen = min(TimeGenerated), + LastSeen = max(TimeGenerated) + by SourceIP, DestinationIP + | where TotalBytesSent >= MinUploadBytes + | extend TotalGBSent = round(TotalBytesSent / 1024.0 / 1024.0 / 1024.0, 2) + | extend TotalGBReceived = round(TotalBytesReceived / 1024.0 / 1024.0 / 1024.0, 2) + | extend UploadRatio = round(todouble(TotalBytesSent) / todouble(TotalBytesSent + TotalBytesReceived) * 100, 2) + | where UploadRatio >= MinUploadRatio + | project + TimeGenerated = LastSeen, + SourceIP, + DestinationIP, + TotalGBSent, + TotalGBReceived, + UploadRatio, + Connections, + DestinationPorts, + Applications, + FirstSeen, + LastSeen + | order by TotalGBSent desc + schedule: + frequency: PT1H + detectionAction: + alertTemplate: + title: Cisco ASA - Possible Data Exfiltration Detection + description: '''Detects potential data exfiltration when an internal source IP sends a large amount of outbound data + to the internet, especially when the volume is significantly higher than its normal behavior.''' + severity: medium + entityMappings: + ips: + - id: ip1 + addressColumn: SourceIP + - id: ip2 + addressColumn: DestinationIP + tactics: + - tactic: Exfiltration + techniques: + - technique: T1041 + - technique: T1048 diff --git a/Solutions/CiscoASA/XDR Detections/CiscoASA-ThreatDetectionMessage.yaml b/Solutions/CiscoASA/XDR Detections/CiscoASA-ThreatDetectionMessage.yaml new file mode 100644 index 00000000000..ac725e7c456 --- /dev/null +++ b/Solutions/CiscoASA/XDR Detections/CiscoASA-ThreatDetectionMessage.yaml @@ -0,0 +1,109 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: CiscoAsaAma + dataTypes: + - CommonSecurityLog +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: 795edf2d-cf3e-45b5-8452-fe6c9e6a582e + path: Analytic Rules/CiscoASA-ThreatDetectionMessage.yaml + version: 1.0.3 + querySha256: d2550971e5d78a731b0300f36e424804e569c5832dad6dd99bd27ba5779386ca + schedule: + queryFrequency: 1h + queryPeriod: 1h + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - 'Schedule assessment: source frequency=1h, lookback=1h; target frequency=PT1H, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - 'Best-effort entity mapping requires review: source Host.FullName column `DeviceName` is provisionally represented by + hosts.nameColumn `DeviceName`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + - Host.FullName value is retained as customDetails.HostFullName from query column `DeviceName`, but its target output + binding requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.HostFullName column `DeviceName` requires runtime output-schema binding verification + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: + - All source MITRE tactics are preserved in source order in authored YAML. V3.1 ARM packaging carries only the first tactic + and its compatible techniques; this classification loss is not validated parity. Direct Graph deployment requires a + single tactic. + errors: [] + originalTactics: + - Discovery + - Impact + originalTechniques: + - T1046 + - T1498 + reviewScope: + sourceDocumentSha256: 1950041799fad8925658109382fafd0a6af66a8d6f56feabf7224ddf380881c4 + targetQuerySha256: 7c14061341a40bd433b9ca444954e39693ef716b5b4c70fdeb60b13d0754ac78 + reviewDecisions: + - reason: 'Best-effort entity mapping requires review: source Host.FullName column `DeviceName` is provisionally represented + by hosts.nameColumn `DeviceName`; confirm that this column is the intended host identifier. The original value is + also retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + decision: accepted + sourceDocumentSha256: 1950041799fad8925658109382fafd0a6af66a8d6f56feabf7224ddf380881c4 + targetQuerySha256: 7c14061341a40bd433b9ca444954e39693ef716b5b4c70fdeb60b13d0754ac78 + supplementalEntityDetails: + - entityType: Host + entityIndex: 1 + identifier: FullName + sourceColumn: DeviceName + column: DeviceName + status: runtime-binding-pending + customDetailKey: HostFullName + acceptedReviewReasons: + - 'Best-effort entity mapping requires review: source Host.FullName column `DeviceName` is provisionally represented by + hosts.nameColumn `DeviceName`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' +properties: + id: xdr-795edf2d-cf3e-45b5-8452-fe6c9e6a582e + displayName: Cisco ASA - threat detection message fired + status: disabled + queryCondition: + queryText: |- + CommonSecurityLog + | where isempty(CommunicationDirection) + | where DeviceEventClassID in ("733101","733102","733103","733104","733105") + | extend HostName = tostring(split(DeviceName, ".")[0]), DomainIndex = toint(indexof(DeviceName, '.')) + | extend HostNameDomain = iff(DomainIndex != -1, substring(DeviceName, DomainIndex + 1), DeviceName) + schedule: + frequency: PT1H + detectionAction: + alertTemplate: + title: Cisco ASA - threat detection message fired + description: |- + 'Identifies when the Cisco ASA Threat Detection engine fired an alert based on malicious activity occurring on the network inicated by DeviceEventClassID 733101-733105 + Resources: https://www.cisco.com/c/en/us/td/docs/security/asa/syslog/b_syslog/syslogs9.html + Details on how to further troubleshoot/investigate: https://www.cisco.com/c/en/us/support/docs/security/asa-5500-x-series-next-generation-firewalls/113685-asa-threat-detection.html' + severity: medium + entityMappings: + hosts: + - id: host1 + nameColumn: DeviceName + ips: + - id: ip1 + addressColumn: SourceIP + tactics: + - tactic: Discovery + techniques: + - technique: T1046 + - tactic: Impact + techniques: + - technique: T1498 + customDetails: + HostFullName: DeviceName diff --git a/Solutions/Endpoint Threat Protection Essentials/Analytic Rules/WDigestDowngradeAttack.yaml b/Solutions/Endpoint Threat Protection Essentials/Analytic Rules/WDigestDowngradeAttack.yaml index 7206f0b4207..b05105cb118 100644 --- a/Solutions/Endpoint Threat Protection Essentials/Analytic Rules/WDigestDowngradeAttack.yaml +++ b/Solutions/Endpoint Threat Protection Essentials/Analytic Rules/WDigestDowngradeAttack.yaml @@ -2,7 +2,7 @@ id: f6502545-ae3a-4232-a8b0-79d87e5c98d7 name: WDigest downgrade attack description: | 'When the WDigest Authentication protocol is enabled, plain text passwords are stored in the Local Security Authority Subsystem Service (LSASS) exposing them to theft. This setting will prevent WDigest from storing credentials in memory. - Ref: https://www.stigviewer.com/stig/windows_7/2016-12-19/finding/V-72753' + Ref: https://www.microsoft.com/en-us/security/blog/2022/07/27/untangling-knotweed-european-private-sector-offensive-actor-using-0-day-exploits/' severity: Medium status: Available requiredDataConnectors: @@ -40,5 +40,5 @@ entityMappings: columnName: HostName - identifier: DnsDomain columnName: DnsDomain -version: 1.0.3 +version: 3.1.2 kind: Scheduled diff --git a/Solutions/Endpoint Threat Protection Essentials/Analytic Rules/WindowsBinariesLolbinsRenamed.yaml b/Solutions/Endpoint Threat Protection Essentials/Analytic Rules/WindowsBinariesLolbinsRenamed.yaml index b22ce603ef0..5b12108bfcd 100644 --- a/Solutions/Endpoint Threat Protection Essentials/Analytic Rules/WindowsBinariesLolbinsRenamed.yaml +++ b/Solutions/Endpoint Threat Protection Essentials/Analytic Rules/WindowsBinariesLolbinsRenamed.yaml @@ -2,7 +2,7 @@ id: cbf6ad48-fa5c-4bf7-b205-28dbadb91255 name: Windows Binaries Lolbins Renamed description: | 'This query detects the execution of renamed Windows binaries (Lolbins). This is a common technique used by adversaries to evade detection. - Ref: https://docs.paloaltonetworks.com/cortex/cortex-xdr/cortex-xdr-analytics-alert-reference/cortex-xdr-analytics-alert-reference/execution-of-renamed-lolbin.html' + Ref: https://cortex-docs.paloaltonetworks.com/analytics-alerts/alerts-by-name/execution-of-renamed-lolbin' severity: Medium status: Available requiredDataConnectors: @@ -46,5 +46,5 @@ entityMappings: fieldMappings: - identifier: Name columnName: User -version: 1.0.3 +version: 3.1.2 kind: Scheduled diff --git a/Solutions/Endpoint Threat Protection Essentials/Data/Solution_EndpointThreatProtectionEssentials.json b/Solutions/Endpoint Threat Protection Essentials/Data/Solution_EndpointThreatProtectionEssentials.json index 2cf365bd45d..7e5a163e996 100644 --- a/Solutions/Endpoint Threat Protection Essentials/Data/Solution_EndpointThreatProtectionEssentials.json +++ b/Solutions/Endpoint Threat Protection Essentials/Data/Solution_EndpointThreatProtectionEssentials.json @@ -21,21 +21,21 @@ "Hunting Queries/WindowsFirewallUpdateUsingNetsh.yaml" ], "Analytic Rules": [ - "Analytic Rules/base64_encoded_pefile.yaml", + "Analytic Rules/Certutil-Download-Abuse.yaml", "Analytic Rules/DumpingLSASSProcessIntoaFile.yaml", - "Analytic Rules/execute_base64_decodedpayload.yaml", "Analytic Rules/LateralMovementViaDCOM.yaml", "Analytic Rules/MacroInvokingShellBrowserWindowCOMObjects.yaml", - "Analytic Rules/malware_in_recyclebin.yaml", "Analytic Rules/PotentialRemoteDesktopTunneling.yaml", "Analytic Rules/RegistryPersistenceViaAppCertDLLModification.yaml", "Analytic Rules/RegistryPersistenceViaAppInt_DLLsModification.yaml", "Analytic Rules/SecurityEventLogCleared.yaml", + "Analytic Rules/SuspiciousPowerShellCommandExecuted.yaml", "Analytic Rules/WDigestDowngradeAttack.yaml", "Analytic Rules/WindowsBinariesExecutedfromNon-DefaultDirectory.yaml", "Analytic Rules/WindowsBinariesLolbinsRenamed.yaml", - "Analytic Rules/SuspiciousPowerShellCommandExecuted.yaml", - "Analytic Rules/Certutil-Download-Abuse.yaml" + "Analytic Rules/base64_encoded_pefile.yaml", + "Analytic Rules/execute_base64_decodedpayload.yaml", + "Analytic Rules/malware_in_recyclebin.yaml" ], "dependentDomainSolutionIds": [ "azuresentinel.azure-sentinel-solution-securityevents", @@ -43,7 +43,24 @@ "azuresentinel.azure-sentinel-solution-windowsforwardedevents" ], "BasePath": "C:\\GitHub\\Azure-Sentinel\\Solutions\\Endpoint Threat Protection Essentials", - "Version": "3.0.7", "Metadata": "SolutionMetadata.json", - "TemplateSpec": true + "TemplateSpec": true, + "XDR Detections": [ + "XDR Detections/Certutil-Download-Abuse.yaml", + "XDR Detections/DumpingLSASSProcessIntoaFile.yaml", + "XDR Detections/LateralMovementViaDCOM.yaml", + "XDR Detections/MacroInvokingShellBrowserWindowCOMObjects.yaml", + "XDR Detections/PotentialRemoteDesktopTunneling.yaml", + "XDR Detections/RegistryPersistenceViaAppCertDLLModification.yaml", + "XDR Detections/RegistryPersistenceViaAppInt_DLLsModification.yaml", + "XDR Detections/SecurityEventLogCleared.yaml", + "XDR Detections/SuspiciousPowerShellCommandExecuted.yaml", + "XDR Detections/WDigestDowngradeAttack.yaml", + "XDR Detections/WindowsBinariesExecutedfromNon-DefaultDirectory.yaml", + "XDR Detections/WindowsBinariesLolbinsRenamed.yaml", + "XDR Detections/base64_encoded_pefile.yaml", + "XDR Detections/execute_base64_decodedpayload.yaml", + "XDR Detections/malware_in_recyclebin.yaml" + ], + "Version": "3.1.2" } diff --git a/Solutions/Endpoint Threat Protection Essentials/Hunting Queries/DownloadOfNewFileUsingCurl.yaml b/Solutions/Endpoint Threat Protection Essentials/Hunting Queries/DownloadOfNewFileUsingCurl.yaml index 5f6e61e44c8..5e64a54e9a4 100644 --- a/Solutions/Endpoint Threat Protection Essentials/Hunting Queries/DownloadOfNewFileUsingCurl.yaml +++ b/Solutions/Endpoint Threat Protection Essentials/Hunting Queries/DownloadOfNewFileUsingCurl.yaml @@ -4,7 +4,7 @@ description: | Threat actors may use tools such as Curl to download additional files, communicate with C2 infrastructure, or exfiltrate data. This query looks for new files being downloaded using Curl. description-detailed: | Threat actors may use tools such as Curl to download additional files, communicate with C2 infrastructure, or exfiltrate data. This query looks for new files being downloaded using Curl. Curl also has legitimate uses files and hosts should be reviewed to identify potentially malicious activity. - Ref: https://www.microsoft.com/security/blog/2022/07/27/untangling-knotweed-european-private-sector-offensive-actor-using-0-day-exploits/ + Ref: https://www.microsoft.com/en-us/security/blog/2022/07/27/untangling-knotweed-european-private-sector-offensive-actor-using-0-day-exploits/ requiredDataConnectors: - connectorId: MicrosoftThreatProtection dataTypes: @@ -57,4 +57,4 @@ entityMappings: fieldMappings: - identifier: Name columnName: remote_file -version: 1.0.1 \ No newline at end of file +version: 3.1.2 \ No newline at end of file diff --git a/Solutions/Endpoint Threat Protection Essentials/Hunting Queries/WindowsFirewallUpdateUsingNetsh.yaml b/Solutions/Endpoint Threat Protection Essentials/Hunting Queries/WindowsFirewallUpdateUsingNetsh.yaml index 164b8c2f8b6..2802cc1286a 100644 --- a/Solutions/Endpoint Threat Protection Essentials/Hunting Queries/WindowsFirewallUpdateUsingNetsh.yaml +++ b/Solutions/Endpoint Threat Protection Essentials/Hunting Queries/WindowsFirewallUpdateUsingNetsh.yaml @@ -12,7 +12,7 @@ description-detailed: | In short, "has_all" will only match when the referenced field has all strings in the list. Refer to netsh syntax: https://docs.microsoft.com/windows-server/administration/windows-commands/netsh Refer to our Microsoft Defender XDR blog for details on use during the Solorigate attack: - https://www.microsoft.com/security/blog/2021/01/20/deep-dive-into-the-solorigate-second-stage-activation-from-sunburst-to-teardrop-and-raindrop/ + https://www.microsoft.com/en-us/security/blog/2021/01/20/deep-dive-into-the-solorigate-second-stage-activation-from-sunburst-to-teardrop-and-raindrop/ severity: Low requiredDataConnectors: - connectorId: SecurityEvents @@ -144,4 +144,4 @@ entityMappings: fieldMappings: - identifier: FullName columnName: Computer -version: 1.0.0 \ No newline at end of file +version: 3.1.2 \ No newline at end of file diff --git a/Solutions/Endpoint Threat Protection Essentials/Package/3.1.2.zip b/Solutions/Endpoint Threat Protection Essentials/Package/3.1.2.zip new file mode 100644 index 00000000000..feb42b47b4d Binary files /dev/null and b/Solutions/Endpoint Threat Protection Essentials/Package/3.1.2.zip differ diff --git a/Solutions/Endpoint Threat Protection Essentials/Package/createUiDefinition.json b/Solutions/Endpoint Threat Protection Essentials/Package/createUiDefinition.json index 060272bac59..20c6d19d6d0 100644 --- a/Solutions/Endpoint Threat Protection Essentials/Package/createUiDefinition.json +++ b/Solutions/Endpoint Threat Protection Essentials/Package/createUiDefinition.json @@ -6,7 +6,7 @@ "config": { "isWizard": false, "basics": { - "description": "Note: Please refer to the following before installing the solution:
\n• Review the solution Release Notes
\n• There may be known issues pertaining to this Solution, please refer to them before installing.
\nThe Endpoint Threat Protection Essentials solution provides content to monitor, detect and investigate threats related to windows machines. The solution looks for things like suspicious commandlines, PowerShell based attacks, LOLBins, registry manipulation, scheduled tasks etc. which are some of the most commonly used techniques by attackers when targeting endpoints.
\nPre-requisites:
\nThis is a domain solution and does not include any data connectors. The content in this solution supports the connectors listed below. Install one or more of the listed solutions, to unlock the value provided by this solution.
\nWindows Security Events
\nMicrosoft Defender XDR
\nWindows Forwarded Events
\nKeywords: LOLBins, PowerShell, Registry, Lsass, Commandline, scheduled tasks, Malware.
\nAnalytic Rules: 15, Hunting Queries: 15
\nLearn more about Microsoft Sentinel | Learn more about Solutions
\n", + "descriptionHtml": "Note: Please refer to the following before installing the solution:
\n• Review the solution Release Notes
\n• There may be known issues pertaining to this Solution, please refer to them before installing.
\nThe Endpoint Threat Protection Essentials solution provides content to monitor, detect and investigate threats related to windows machines. The solution looks for things like suspicious commandlines, PowerShell based attacks, LOLBins, registry manipulation, scheduled tasks etc. which are some of the most commonly used techniques by attackers when targeting endpoints.
\nPre-requisites:
\nThis is a domain solution and does not include any data connectors. The content in this solution supports the connectors listed below. Install one or more of the listed solutions, to unlock the value provided by this solution.
\nWindows Security Events
\nMicrosoft Defender XDR
\nWindows Forwarded Events
\nKeywords: LOLBins, PowerShell, Registry, Lsass, Commandline, scheduled tasks, Malware.
\nAnalytic Rules: 15, XDR Detections: 15, Hunting Queries: 15
\nLearn more about Microsoft Sentinel | Learn more about Solutions
\n", "contentKind": "Solution", "contentProductId": "[variables('_solutioncontentProductId')]", "id": "[variables('_solutioncontentProductId')]", @@ -3731,20 +3782,2721 @@ { "kind": "Solution", "contentId": "azuresentinel.azure-sentinel-solution-windowsforwardedevents" - } - ] - }, - "firstPublishDate": "2022-11-16", - "providers": [ - "Microsoft" - ], - "categories": { - "domains": [ - "Security - Threat Protection" - ] - } - }, - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/', variables('_solutionId'))]" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-4a9d3c2e-7f1b-4e58-9a0c-2d5b8e3f1a7c", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-a7b9df32-1367-402d-b385-882daf6e3020", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-50cbf34a-4cdd-45d7-b3f5-8b53a1d0d14f", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-e7470b35-0128-4508-bfc9-e01cfb3c2eb7", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-d2e8fd50-8d66-11ec-b909-0242ac120002", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-c61ad0ac-ad68-4ebb-b41a-74296d3e0044", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-9367dff0-941d-44e2-8875-cb48570c7add", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-80da0a8f-cfe1-4cd0-a895-8bc1771a720e", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-b5153fb3-ada9-4ce4-9131-79c771efb50d", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-f6502545-ae3a-4232-a8b0-79d87e5c98d7", + "version": "3.1.2" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-15049017-527f-4d3b-b011-b0e99e68ef45", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-cbf6ad48-fa5c-4bf7-b205-28dbadb91255", + "version": "3.1.2" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-ca67c83e-7fff-4127-a3e3-1af66d6d4cad", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-d6190dde-8fd2-456a-ac5b-0a32400b0464", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-75bf9902-0789-47c1-a5d8-f57046aa72df", + "version": "3.1.0" + } + ] + }, + "firstPublishDate": "2022-11-16", + "providers": [ + "Microsoft" + ], + "categories": { + "domains": [ + "Security - Threat Protection" + ] + } + }, + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/', variables('_solutionId'))]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "EndpointThreatProtectionEssentials-CD-xdr-4a9d3c2e-7f1b-21fbb732", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "schedule": { + "frequency": "PT1H" + }, + "id": "[if(true(), 'xdr-4a9d3c2e-7f1b-4e58-9a0c-2d5b8e3f1a7c', 'xdr-4a9d3c2e-7f1b-4e58-9a0c-2d5b8e3f1a7c')]", + "displayName": "CertUtil Used for File Download (Living off the Land)", + "queryCondition": { + "queryText": "let Lookback = 1h;\nlet AllowlistedDomains = dynamic([\n \"windowsupdate.microsoft.com\",\n \"download.microsoft.com\",\n \"dl.delivery.mp.microsoft.com\",\n \"ctldl.windowsupdate.com\"\n]);\nlet MDE_Results =\n DeviceProcessEvents\n | where Timestamp >= ago(Lookback)\n | where FileName =~ \"certutil.exe\"\n | where ProcessCommandLine has_any (\"-urlcache\", \"-verifyctl\", \"-decode\", \"-decodehex\")\n | where ProcessCommandLine has_any (\"http://\", \"https://\", \"ftp://\")\n | where not(ProcessCommandLine has_any (AllowlistedDomains))\n | extend\n AccountName = InitiatingProcessAccountName,\n AccountDomain = InitiatingProcessAccountDomain,\n HostName = DeviceName,\n EventTime = Timestamp\n | project EventTime, HostName, AccountName, AccountDomain,\n ProcessCommandLine, InitiatingProcessFileName;\nlet SecEvent_Results =\n SecurityEvent\n | where TimeGenerated >= ago(Lookback)\n | where EventID == 4688\n | where NewProcessName endswith \"\\\\certutil.exe\"\n | where CommandLine has_any (\"-urlcache\", \"-verifyctl\", \"-decode\", \"-decodehex\")\n | where CommandLine has_any (\"http://\", \"https://\", \"ftp://\")\n | where not(CommandLine has_any (AllowlistedDomains))\n | extend\n AccountName = SubjectUserName,\n AccountDomain = SubjectDomainName,\n HostName = Computer,\n EventTime = TimeGenerated,\n ProcessCommandLine = CommandLine,\n InitiatingProcessFileName = ParentProcessName\n | project EventTime, HostName, AccountName, AccountDomain,\n ProcessCommandLine, InitiatingProcessFileName;\nunion MDE_Results, SecEvent_Results\n| sort by EventTime desc" + }, + "detectionAction": { + "alertTemplate": { + "description": "Detects certutil.exe being used to download files from remote URLs via the\n-urlcache or -verifyctl flags. CertUtil is a signed Windows binary (LOLBin)\nthat attackers abuse to download payloads while bypassing application\nwhitelisting and network controls.\nTune AllowlistedDomains to match your PKI/CA infrastructure.", + "title": "CertUtil Used for File Download (Living off the Land)", + "customDetails": { + "HostFullName": "HostName", + "ProcessCommandLine": "ProcessCommandLine" + }, + "tactics": [ + { + "tactic": "CommandAndControl", + "techniques": [ + { + "technique": "T1105" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ], + "accounts": [ + { + "nameColumn": "AccountName", + "ntDomainColumn": "AccountDomain", + "id": "[if(true(), 'account1', 'account1')]" + } + ] + }, + "severity": "high" + } + }, + "status": "disabled" + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-4a9d3c2e-7f1b-4e58-9a0c-2d5b8e3f1a7c')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'EndpointThreatProtectionEssentials-CD-xdr-4a9d3c2e-7f1b-21fbb732')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "Detects certutil.exe being used to download files from remote URLs via the\n-urlcache or -verifyctl flags. CertUtil is a signed Windows binary (LOLBin)\nthat attackers abuse to download payloads while bypassing application\nwhitelisting and network controls.\nTune AllowlistedDomains to match your PKI/CA infrastructure.", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "schedule": { + "frequency": "PT1H" + }, + "id": "[if(true(), 'xdr-4a9d3c2e-7f1b-4e58-9a0c-2d5b8e3f1a7c', 'xdr-4a9d3c2e-7f1b-4e58-9a0c-2d5b8e3f1a7c')]", + "displayName": "CertUtil Used for File Download (Living off the Land)", + "queryCondition": { + "queryText": "let Lookback = 1h;\nlet AllowlistedDomains = dynamic([\n \"windowsupdate.microsoft.com\",\n \"download.microsoft.com\",\n \"dl.delivery.mp.microsoft.com\",\n \"ctldl.windowsupdate.com\"\n]);\nlet MDE_Results =\n DeviceProcessEvents\n | where Timestamp >= ago(Lookback)\n | where FileName =~ \"certutil.exe\"\n | where ProcessCommandLine has_any (\"-urlcache\", \"-verifyctl\", \"-decode\", \"-decodehex\")\n | where ProcessCommandLine has_any (\"http://\", \"https://\", \"ftp://\")\n | where not(ProcessCommandLine has_any (AllowlistedDomains))\n | extend\n AccountName = InitiatingProcessAccountName,\n AccountDomain = InitiatingProcessAccountDomain,\n HostName = DeviceName,\n EventTime = Timestamp\n | project EventTime, HostName, AccountName, AccountDomain,\n ProcessCommandLine, InitiatingProcessFileName;\nlet SecEvent_Results =\n SecurityEvent\n | where TimeGenerated >= ago(Lookback)\n | where EventID == 4688\n | where NewProcessName endswith \"\\\\certutil.exe\"\n | where CommandLine has_any (\"-urlcache\", \"-verifyctl\", \"-decode\", \"-decodehex\")\n | where CommandLine has_any (\"http://\", \"https://\", \"ftp://\")\n | where not(CommandLine has_any (AllowlistedDomains))\n | extend\n AccountName = SubjectUserName,\n AccountDomain = SubjectDomainName,\n HostName = Computer,\n EventTime = TimeGenerated,\n ProcessCommandLine = CommandLine,\n InitiatingProcessFileName = ParentProcessName\n | project EventTime, HostName, AccountName, AccountDomain,\n ProcessCommandLine, InitiatingProcessFileName;\nunion MDE_Results, SecEvent_Results\n| sort by EventTime desc" + }, + "detectionAction": { + "alertTemplate": { + "description": "Detects certutil.exe being used to download files from remote URLs via the\n-urlcache or -verifyctl flags. CertUtil is a signed Windows binary (LOLBin)\nthat attackers abuse to download payloads while bypassing application\nwhitelisting and network controls.\nTune AllowlistedDomains to match your PKI/CA infrastructure.", + "title": "CertUtil Used for File Download (Living off the Land)", + "customDetails": { + "HostFullName": "HostName", + "ProcessCommandLine": "ProcessCommandLine" + }, + "tactics": [ + { + "tactic": "CommandAndControl", + "techniques": [ + { + "technique": "T1105" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ], + "accounts": [ + { + "nameColumn": "AccountName", + "ntDomainColumn": "AccountDomain", + "id": "[if(true(), 'account1', 'account1')]" + } + ] + }, + "severity": "high" + } + }, + "status": "disabled" + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-4a9d3c2e-7f1b-4e58-9a0c-2d5b8e3f1a7c", + "contentKind": "CustomDetection", + "displayName": "CertUtil Used for File Download (Living off the Land)", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-4a9d3c2e-7f1b-4e58-9a0c-2d5b8e3f1a7c','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-4a9d3c2e-7f1b-4e58-9a0c-2d5b8e3f1a7c','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "EndpointThreatProtectionEssentials-CD-xdr-a7b9df32-1367-d7dbf0d9", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "schedule": { + "frequency": "PT1H" + }, + "id": "[if(true(), 'xdr-a7b9df32-1367-402d-b385-882daf6e3020', 'xdr-a7b9df32-1367-402d-b385-882daf6e3020')]", + "displayName": "Dumping LSASS Process Into a File", + "queryCondition": { + "queryText": "Event\n| where EventLog =~ \"Microsoft-Windows-Sysmon/Operational\" and EventID==10\n| parse EventData with * 'TargetImage\">' TargetImage \"<\" * 'GrantedAccess\">' GrantedAccess \"<\" * 'CallTrace\">' CallTrace \"<\" *\n| where GrantedAccess =~ \"0x1FFFFF\" and TargetImage =~ \"C:\\\\Windows\\\\System32\\\\lsass.exe\" and CallTrace has_any (\"dbghelp.dll\",\"dbgcore.dll\")\n| parse EventData with * 'SourceProcessGUID\">' SourceProcessGUID \"<\" * 'SourceImage\">' SourceImage \"<\" *\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by EventID, Computer, SourceProcessGUID, SourceImage, GrantedAccess, TargetImage, CallTrace\n| extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'')" + }, + "detectionAction": { + "alertTemplate": { + "description": "'Adversaries may attempt to access credential material stored in the process memory of the Local Security Authority Subsystem Service (LSASS).\nAfter a user logs on, the system generates and stores a variety of credential materials in LSASS process memory.\nThese credential materials can be harvested by an administrative user or system and used to conduct lateral movement using alternate authentication materials.\nAs well as in-memory techniques, the LSASS process memory can be dumped from the target host and analyzed on a local system.\nRef: https://attack.mitre.org/techniques/T1003/001/'", + "title": "Dumping LSASS Process Into a File", + "customDetails": { + "HostFullName": "Computer", + "ProcessCommandLine": "SourceImage" + }, + "tactics": [ + { + "tactic": "CredentialAccess", + "techniques": [ + { + "subTechniques": [ + "T1003.001" + ], + "technique": "T1003" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "nameColumn": "HostName", + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'host1', 'host1')]" + } + ] + }, + "severity": "high" + } + }, + "status": "disabled" + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-a7b9df32-1367-402d-b385-882daf6e3020')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'EndpointThreatProtectionEssentials-CD-xdr-a7b9df32-1367-d7dbf0d9')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'Adversaries may attempt to access credential material stored in the process memory of the Local Security Authority Subsystem Service (LSASS).\nAfter a user logs on, the system generates and stores a variety of credential materials in LSASS process memory.\nThese credential materials can be harvested by an administrative user or system and used to conduct lateral movement using alternate authentication materials.\nAs well as in-memory techniques, the LSASS process memory can be dumped from the target host and analyzed on a local system.\nRef: https://attack.mitre.org/techniques/T1003/001/'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "schedule": { + "frequency": "PT1H" + }, + "id": "[if(true(), 'xdr-a7b9df32-1367-402d-b385-882daf6e3020', 'xdr-a7b9df32-1367-402d-b385-882daf6e3020')]", + "displayName": "Dumping LSASS Process Into a File", + "queryCondition": { + "queryText": "Event\n| where EventLog =~ \"Microsoft-Windows-Sysmon/Operational\" and EventID==10\n| parse EventData with * 'TargetImage\">' TargetImage \"<\" * 'GrantedAccess\">' GrantedAccess \"<\" * 'CallTrace\">' CallTrace \"<\" *\n| where GrantedAccess =~ \"0x1FFFFF\" and TargetImage =~ \"C:\\\\Windows\\\\System32\\\\lsass.exe\" and CallTrace has_any (\"dbghelp.dll\",\"dbgcore.dll\")\n| parse EventData with * 'SourceProcessGUID\">' SourceProcessGUID \"<\" * 'SourceImage\">' SourceImage \"<\" *\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by EventID, Computer, SourceProcessGUID, SourceImage, GrantedAccess, TargetImage, CallTrace\n| extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'')" + }, + "detectionAction": { + "alertTemplate": { + "description": "'Adversaries may attempt to access credential material stored in the process memory of the Local Security Authority Subsystem Service (LSASS).\nAfter a user logs on, the system generates and stores a variety of credential materials in LSASS process memory.\nThese credential materials can be harvested by an administrative user or system and used to conduct lateral movement using alternate authentication materials.\nAs well as in-memory techniques, the LSASS process memory can be dumped from the target host and analyzed on a local system.\nRef: https://attack.mitre.org/techniques/T1003/001/'", + "title": "Dumping LSASS Process Into a File", + "customDetails": { + "HostFullName": "Computer", + "ProcessCommandLine": "SourceImage" + }, + "tactics": [ + { + "tactic": "CredentialAccess", + "techniques": [ + { + "subTechniques": [ + "T1003.001" + ], + "technique": "T1003" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "nameColumn": "HostName", + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'host1', 'host1')]" + } + ] + }, + "severity": "high" + } + }, + "status": "disabled" + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-a7b9df32-1367-402d-b385-882daf6e3020", + "contentKind": "CustomDetection", + "displayName": "Dumping LSASS Process Into a File", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-a7b9df32-1367-402d-b385-882daf6e3020','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-a7b9df32-1367-402d-b385-882daf6e3020','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "EndpointThreatProtectionEssentials-CD-xdr-50cbf34a-4cdd-e4d8085e", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "schedule": { + "frequency": "PT1H" + }, + "id": "[if(true(), 'xdr-50cbf34a-4cdd-45d7-b3f5-8b53a1d0d14f', 'xdr-50cbf34a-4cdd-45d7-b3f5-8b53a1d0d14f')]", + "displayName": "Lateral Movement via DCOM", + "queryCondition": { + "queryText": "Event\n| where EventLog =~ \"Microsoft-Windows-Sysmon/Operational\" and EventID==1\n| parse EventData with * 'CommandLine\">' CommandLine \"<\" * 'ParentCommandLine\">' ParentCommandLine \"<\" *\n| where ParentCommandLine =~ \"C:\\\\Windows\\\\System32\\\\svchost.exe -k DcomLaunch\" and CommandLine =~ \"C:\\\\Windows\\\\System32\\\\mmc.exe -Embedding\"\n| parse EventData with * 'ProcessGuid\">' ProcessGuid \"<\" * 'Image\">' Image \"<\" * 'Description\">' Description \"<\" * 'CurrentDirectory\">' CurrentDirectory \"<\" * 'User\">' User \"<\" * 'LogonGuid\">' LogonGuid \"<\" * 'ParentProcessGuid\">' ParentProcessGuid \"<\" * 'ParentImage\">' ParentImage \"<\" * 'ParentCommandLine\">' ParentCommandLine \"<\" * 'ParentUser\">' ParentUser \"<\" *\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by EventID, Computer, User, ParentImage, ParentProcessGuid, ParentCommandLine, ParentUser, Image, ProcessGuid, CommandLine, Description\n| extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'')" + }, + "detectionAction": { + "alertTemplate": { + "description": "'This query detects a fairly uncommon attack technique using the Windows Distributed Component Object Model (DCOM) to make a remote execution call to another computer system and gain lateral movement throughout the network.\nRef: http://thenegative.zone/incident%20response/2017/02/04/MMC20.Application-Lateral-Movement-Analysis.html'", + "title": "Lateral Movement via DCOM", + "customDetails": { + "HostFullName": "Computer", + "ProcessCommandLine": "CommandLine" + }, + "tactics": [ + { + "tactic": "LateralMovement", + "techniques": [ + { + "subTechniques": [ + "T1021.003" + ], + "technique": "T1021" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "nameColumn": "HostName", + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'host1', 'host1')]" + } + ], + "accounts": [ + { + "nameColumn": "User", + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'account1', 'account1')]" + } + ] + }, + "severity": "medium" + } + }, + "status": "disabled" + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-50cbf34a-4cdd-45d7-b3f5-8b53a1d0d14f')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'EndpointThreatProtectionEssentials-CD-xdr-50cbf34a-4cdd-e4d8085e')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'This query detects a fairly uncommon attack technique using the Windows Distributed Component Object Model (DCOM) to make a remote execution call to another computer system and gain lateral movement throughout the network.\nRef: http://thenegative.zone/incident%20response/2017/02/04/MMC20.Application-Lateral-Movement-Analysis.html'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "schedule": { + "frequency": "PT1H" + }, + "id": "[if(true(), 'xdr-50cbf34a-4cdd-45d7-b3f5-8b53a1d0d14f', 'xdr-50cbf34a-4cdd-45d7-b3f5-8b53a1d0d14f')]", + "displayName": "Lateral Movement via DCOM", + "queryCondition": { + "queryText": "Event\n| where EventLog =~ \"Microsoft-Windows-Sysmon/Operational\" and EventID==1\n| parse EventData with * 'CommandLine\">' CommandLine \"<\" * 'ParentCommandLine\">' ParentCommandLine \"<\" *\n| where ParentCommandLine =~ \"C:\\\\Windows\\\\System32\\\\svchost.exe -k DcomLaunch\" and CommandLine =~ \"C:\\\\Windows\\\\System32\\\\mmc.exe -Embedding\"\n| parse EventData with * 'ProcessGuid\">' ProcessGuid \"<\" * 'Image\">' Image \"<\" * 'Description\">' Description \"<\" * 'CurrentDirectory\">' CurrentDirectory \"<\" * 'User\">' User \"<\" * 'LogonGuid\">' LogonGuid \"<\" * 'ParentProcessGuid\">' ParentProcessGuid \"<\" * 'ParentImage\">' ParentImage \"<\" * 'ParentCommandLine\">' ParentCommandLine \"<\" * 'ParentUser\">' ParentUser \"<\" *\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by EventID, Computer, User, ParentImage, ParentProcessGuid, ParentCommandLine, ParentUser, Image, ProcessGuid, CommandLine, Description\n| extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'')" + }, + "detectionAction": { + "alertTemplate": { + "description": "'This query detects a fairly uncommon attack technique using the Windows Distributed Component Object Model (DCOM) to make a remote execution call to another computer system and gain lateral movement throughout the network.\nRef: http://thenegative.zone/incident%20response/2017/02/04/MMC20.Application-Lateral-Movement-Analysis.html'", + "title": "Lateral Movement via DCOM", + "customDetails": { + "HostFullName": "Computer", + "ProcessCommandLine": "CommandLine" + }, + "tactics": [ + { + "tactic": "LateralMovement", + "techniques": [ + { + "subTechniques": [ + "T1021.003" + ], + "technique": "T1021" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "nameColumn": "HostName", + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'host1', 'host1')]" + } + ], + "accounts": [ + { + "nameColumn": "User", + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'account1', 'account1')]" + } + ] + }, + "severity": "medium" + } + }, + "status": "disabled" + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-50cbf34a-4cdd-45d7-b3f5-8b53a1d0d14f", + "contentKind": "CustomDetection", + "displayName": "Lateral Movement via DCOM", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-50cbf34a-4cdd-45d7-b3f5-8b53a1d0d14f','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-50cbf34a-4cdd-45d7-b3f5-8b53a1d0d14f','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "EndpointThreatProtectionEssentials-CD-xdr-e7470b35-0128-7a380f4d", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "schedule": { + "frequency": "PT1H" + }, + "id": "[if(true(), 'xdr-e7470b35-0128-4508-bfc9-e01cfb3c2eb7', 'xdr-e7470b35-0128-4508-bfc9-e01cfb3c2eb7')]", + "displayName": "Detecting Macro Invoking ShellBrowserWindow COM Objects", + "queryCondition": { + "queryText": "Event\n | where EventLog =~ \"Microsoft-Windows-Sysmon/Operational\" and EventID==1\n | parse EventData with * 'Image\">' Image \"<\" * 'CommandLine\">' CommandLine \"<\" * 'ParentImage\">' ParentImage \"<\" *\n | where ParentImage has \"svchost.exe\" and Image has \"rundll32.exe\" and CommandLine has \"{c08afd90-f2a1-11d1-8455-00a0c91f3880}\"\n | parse EventData with * 'ProcessGuid\">' ProcessGuid \"<\" * 'Description\">' Description \"<\" * 'CurrentDirectory\">' CurrentDirectory \"<\" * 'User\">' User \"<\" * 'LogonGuid\">' LogonGuid \"<\" * 'ParentProcessGuid\">' ParentProcessGuid \"<\" * 'ParentImage\">' ParentImage \"<\" * 'ParentCommandLine\">' ParentCommandLine \"<\" * 'ParentUser\">' ParentUser \"<\" *\n | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by EventID, Computer, User, ParentImage, ParentProcessGuid, ParentCommandLine, ParentUser, Image, ProcessGuid, CommandLine, Description\n | extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'')" + }, + "detectionAction": { + "alertTemplate": { + "description": "'This query detects a macro invoking ShellBrowserWindow COM Objects evade naive parent/child Office detection rules.'", + "title": "Detecting Macro Invoking ShellBrowserWindow COM Objects", + "customDetails": { + "HostFullName": "Computer", + "ProcessCommandLine": "CommandLine" + }, + "tactics": [ + { + "tactic": "LateralMovement", + "techniques": [ + { + "subTechniques": [ + "T1021.003" + ], + "technique": "T1021" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "nameColumn": "HostName", + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'host1', 'host1')]" + } + ], + "accounts": [ + { + "nameColumn": "User", + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'account1', 'account1')]" + } + ] + }, + "severity": "medium" + } + }, + "status": "disabled" + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-e7470b35-0128-4508-bfc9-e01cfb3c2eb7')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'EndpointThreatProtectionEssentials-CD-xdr-e7470b35-0128-7a380f4d')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'This query detects a macro invoking ShellBrowserWindow COM Objects evade naive parent/child Office detection rules.'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "schedule": { + "frequency": "PT1H" + }, + "id": "[if(true(), 'xdr-e7470b35-0128-4508-bfc9-e01cfb3c2eb7', 'xdr-e7470b35-0128-4508-bfc9-e01cfb3c2eb7')]", + "displayName": "Detecting Macro Invoking ShellBrowserWindow COM Objects", + "queryCondition": { + "queryText": "Event\n | where EventLog =~ \"Microsoft-Windows-Sysmon/Operational\" and EventID==1\n | parse EventData with * 'Image\">' Image \"<\" * 'CommandLine\">' CommandLine \"<\" * 'ParentImage\">' ParentImage \"<\" *\n | where ParentImage has \"svchost.exe\" and Image has \"rundll32.exe\" and CommandLine has \"{c08afd90-f2a1-11d1-8455-00a0c91f3880}\"\n | parse EventData with * 'ProcessGuid\">' ProcessGuid \"<\" * 'Description\">' Description \"<\" * 'CurrentDirectory\">' CurrentDirectory \"<\" * 'User\">' User \"<\" * 'LogonGuid\">' LogonGuid \"<\" * 'ParentProcessGuid\">' ParentProcessGuid \"<\" * 'ParentImage\">' ParentImage \"<\" * 'ParentCommandLine\">' ParentCommandLine \"<\" * 'ParentUser\">' ParentUser \"<\" *\n | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by EventID, Computer, User, ParentImage, ParentProcessGuid, ParentCommandLine, ParentUser, Image, ProcessGuid, CommandLine, Description\n | extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'')" + }, + "detectionAction": { + "alertTemplate": { + "description": "'This query detects a macro invoking ShellBrowserWindow COM Objects evade naive parent/child Office detection rules.'", + "title": "Detecting Macro Invoking ShellBrowserWindow COM Objects", + "customDetails": { + "HostFullName": "Computer", + "ProcessCommandLine": "CommandLine" + }, + "tactics": [ + { + "tactic": "LateralMovement", + "techniques": [ + { + "subTechniques": [ + "T1021.003" + ], + "technique": "T1021" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "nameColumn": "HostName", + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'host1', 'host1')]" + } + ], + "accounts": [ + { + "nameColumn": "User", + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'account1', 'account1')]" + } + ] + }, + "severity": "medium" + } + }, + "status": "disabled" + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-e7470b35-0128-4508-bfc9-e01cfb3c2eb7", + "contentKind": "CustomDetection", + "displayName": "Detecting Macro Invoking ShellBrowserWindow COM Objects", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-e7470b35-0128-4508-bfc9-e01cfb3c2eb7','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-e7470b35-0128-4508-bfc9-e01cfb3c2eb7','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "EndpointThreatProtectionEssentials-CD-xdr-d2e8fd50-8d66-0a5bb20d", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "schedule": { + "frequency": "PT1H" + }, + "id": "[if(true(), 'xdr-d2e8fd50-8d66-11ec-b909-0242ac120002', 'xdr-d2e8fd50-8d66-11ec-b909-0242ac120002')]", + "displayName": "Potential Remote Desktop Tunneling", + "queryCondition": { + "queryText": "SecurityEvent\n | where EventID in (4624,4625) and LogonType in (10) and IpAddress in (\"::1\",\"127.0.0.1\")\n | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by EventID, Computer, TargetUserName, TargetLogonId, LogonType, IpAddress\n | extend Name=tostring(split(TargetUserName, \"@\")[0]), UPNSuffix=tostring(split(TargetUserName, \"@\")[1])\n | extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'')" + }, + "detectionAction": { + "alertTemplate": { + "description": "'This query detects remote desktop authentication attempts with a localhost source address, which can indicate a tunneled login.\nRef: https://www.mandiant.com/resources/bypassing-network-restrictions-through-rdp-tunneling'", + "title": "Potential Remote Desktop Tunneling", + "customDetails": { + "HostFullName": "Computer" + }, + "tactics": [ + { + "tactic": "CommandAndControl", + "techniques": [ + { + "technique": "T1572" + } + ] + } + ], + "entityMappings": { + "ips": [ + { + "addressColumn": "IpAddress", + "id": "[if(true(), 'ip1', 'ip1')]" + } + ], + "accounts": [ + { + "upnSuffixColumn": "UPNSuffix", + "nameColumn": "Name", + "id": "[if(true(), 'account1', 'account1')]" + } + ], + "hosts": [ + { + "nameColumn": "HostName", + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'host1', 'host1')]" + } + ] + }, + "severity": "medium" + } + }, + "status": "disabled" + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-d2e8fd50-8d66-11ec-b909-0242ac120002')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'EndpointThreatProtectionEssentials-CD-xdr-d2e8fd50-8d66-0a5bb20d')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'This query detects remote desktop authentication attempts with a localhost source address, which can indicate a tunneled login.\nRef: https://www.mandiant.com/resources/bypassing-network-restrictions-through-rdp-tunneling'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "schedule": { + "frequency": "PT1H" + }, + "id": "[if(true(), 'xdr-d2e8fd50-8d66-11ec-b909-0242ac120002', 'xdr-d2e8fd50-8d66-11ec-b909-0242ac120002')]", + "displayName": "Potential Remote Desktop Tunneling", + "queryCondition": { + "queryText": "SecurityEvent\n | where EventID in (4624,4625) and LogonType in (10) and IpAddress in (\"::1\",\"127.0.0.1\")\n | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by EventID, Computer, TargetUserName, TargetLogonId, LogonType, IpAddress\n | extend Name=tostring(split(TargetUserName, \"@\")[0]), UPNSuffix=tostring(split(TargetUserName, \"@\")[1])\n | extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'')" + }, + "detectionAction": { + "alertTemplate": { + "description": "'This query detects remote desktop authentication attempts with a localhost source address, which can indicate a tunneled login.\nRef: https://www.mandiant.com/resources/bypassing-network-restrictions-through-rdp-tunneling'", + "title": "Potential Remote Desktop Tunneling", + "customDetails": { + "HostFullName": "Computer" + }, + "tactics": [ + { + "tactic": "CommandAndControl", + "techniques": [ + { + "technique": "T1572" + } + ] + } + ], + "entityMappings": { + "ips": [ + { + "addressColumn": "IpAddress", + "id": "[if(true(), 'ip1', 'ip1')]" + } + ], + "accounts": [ + { + "upnSuffixColumn": "UPNSuffix", + "nameColumn": "Name", + "id": "[if(true(), 'account1', 'account1')]" + } + ], + "hosts": [ + { + "nameColumn": "HostName", + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'host1', 'host1')]" + } + ] + }, + "severity": "medium" + } + }, + "status": "disabled" + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-d2e8fd50-8d66-11ec-b909-0242ac120002", + "contentKind": "CustomDetection", + "displayName": "Potential Remote Desktop Tunneling", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-d2e8fd50-8d66-11ec-b909-0242ac120002','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-d2e8fd50-8d66-11ec-b909-0242ac120002','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "EndpointThreatProtectionEssentials-CD-xdr-c61ad0ac-ad68-63050247", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "schedule": { + "frequency": "PT1H" + }, + "id": "[if(true(), 'xdr-c61ad0ac-ad68-4ebb-b41a-74296d3e0044', 'xdr-c61ad0ac-ad68-4ebb-b41a-74296d3e0044')]", + "displayName": "Registry Persistence via AppCert DLL Modification", + "queryCondition": { + "queryText": "Event\n| where EventLog =~ \"Microsoft-Windows-Sysmon/Operational\" and EventID in (13)\n| parse EventData with * 'TargetObject\">' TargetObject \"<\" * 'Details\">' Details \"<\" *\n| where TargetObject has (\"\\\\Control\\\\Session Manager\\\\AppCertDLLs\\\\\")\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated) by EventID, Computer, TargetObject, Details\n| extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'')" + }, + "detectionAction": { + "alertTemplate": { + "description": "'Adversaries may establish persistence and/or elevate privileges by executing malicious content triggered by AppCert DLLs loaded into processes. \nDynamic-link libraries (DLLs) that are specified in the AppCertDLLs Registry key under HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\ are loaded into every process that calls the ubiquitously used application programming interface (API) functions CreateProcess, CreateProcessAsUser, CreateProcessWithLoginW, CreateProcessWithTokenW, or WinExec.\nRef: https://attack.mitre.org/techniques/T1546/009/'", + "title": "Registry Persistence via AppCert DLL Modification", + "customDetails": { + "HostFullName": "Computer", + "RegistryKeyKey": "TargetObject" + }, + "tactics": [ + { + "tactic": "Persistence", + "techniques": [ + { + "subTechniques": [ + "T1546.009" + ], + "technique": "T1546" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "nameColumn": "HostName", + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'host1', 'host1')]" + } + ] + }, + "severity": "medium" + } + }, + "status": "disabled" + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-c61ad0ac-ad68-4ebb-b41a-74296d3e0044')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'EndpointThreatProtectionEssentials-CD-xdr-c61ad0ac-ad68-63050247')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'Adversaries may establish persistence and/or elevate privileges by executing malicious content triggered by AppCert DLLs loaded into processes. \nDynamic-link libraries (DLLs) that are specified in the AppCertDLLs Registry key under HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\ are loaded into every process that calls the ubiquitously used application programming interface (API) functions CreateProcess, CreateProcessAsUser, CreateProcessWithLoginW, CreateProcessWithTokenW, or WinExec.\nRef: https://attack.mitre.org/techniques/T1546/009/'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "schedule": { + "frequency": "PT1H" + }, + "id": "[if(true(), 'xdr-c61ad0ac-ad68-4ebb-b41a-74296d3e0044', 'xdr-c61ad0ac-ad68-4ebb-b41a-74296d3e0044')]", + "displayName": "Registry Persistence via AppCert DLL Modification", + "queryCondition": { + "queryText": "Event\n| where EventLog =~ \"Microsoft-Windows-Sysmon/Operational\" and EventID in (13)\n| parse EventData with * 'TargetObject\">' TargetObject \"<\" * 'Details\">' Details \"<\" *\n| where TargetObject has (\"\\\\Control\\\\Session Manager\\\\AppCertDLLs\\\\\")\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated) by EventID, Computer, TargetObject, Details\n| extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'')" + }, + "detectionAction": { + "alertTemplate": { + "description": "'Adversaries may establish persistence and/or elevate privileges by executing malicious content triggered by AppCert DLLs loaded into processes. \nDynamic-link libraries (DLLs) that are specified in the AppCertDLLs Registry key under HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\ are loaded into every process that calls the ubiquitously used application programming interface (API) functions CreateProcess, CreateProcessAsUser, CreateProcessWithLoginW, CreateProcessWithTokenW, or WinExec.\nRef: https://attack.mitre.org/techniques/T1546/009/'", + "title": "Registry Persistence via AppCert DLL Modification", + "customDetails": { + "HostFullName": "Computer", + "RegistryKeyKey": "TargetObject" + }, + "tactics": [ + { + "tactic": "Persistence", + "techniques": [ + { + "subTechniques": [ + "T1546.009" + ], + "technique": "T1546" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "nameColumn": "HostName", + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'host1', 'host1')]" + } + ] + }, + "severity": "medium" + } + }, + "status": "disabled" + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-c61ad0ac-ad68-4ebb-b41a-74296d3e0044", + "contentKind": "CustomDetection", + "displayName": "Registry Persistence via AppCert DLL Modification", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-c61ad0ac-ad68-4ebb-b41a-74296d3e0044','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-c61ad0ac-ad68-4ebb-b41a-74296d3e0044','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "EndpointThreatProtectionEssentials-CD-xdr-9367dff0-941d-c0494af8", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "schedule": { + "frequency": "PT1H" + }, + "id": "[if(true(), 'xdr-9367dff0-941d-44e2-8875-cb48570c7add', 'xdr-9367dff0-941d-44e2-8875-cb48570c7add')]", + "displayName": "Registry Persistence via AppInit DLLs Modification", + "queryCondition": { + "queryText": "Event\n| where EventLog =~ \"Microsoft-Windows-Sysmon/Operational\" and EventID in (13)\n| parse EventData with * 'TargetObject\">' TargetObject \"<\" * 'Details\">' Details \"<\" *\n| where TargetObject has \"\\\\Windows NT\\\\CurrentVersion\\\\Windows\\\\AppInit_DLLs\"\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated) by EventID, Computer, TargetObject, Details\n| extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'')" + }, + "detectionAction": { + "alertTemplate": { + "description": "'Adversaries may establish persistence and/or elevate privileges by executing malicious content triggered by AppInit DLLs loaded into processes. \nDynamic-link libraries (DLLs) that are specified in the AppInit_DLLs value in the Registry keys HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows or HKEY_LOCAL_MACHINE\\Software\\Wow6432Node\\Microsoft\\Windows NT\\CurrentVersion\\Windows are loaded by user32.dll into every process that loads user32.dll. In practice this is nearly every program, since user32.dll is a very common library.\nRef: https://attack.mitre.org/techniques/T1546/", + "title": "Registry Persistence via AppInit DLLs Modification", + "customDetails": { + "HostFullName": "Computer", + "RegistryKeyKey": "TargetObject" + }, + "tactics": [ + { + "tactic": "Persistence", + "techniques": [ + { + "subTechniques": [ + "T1546.010" + ], + "technique": "T1546" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "nameColumn": "HostName", + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'host1', 'host1')]" + } + ] + }, + "severity": "medium" + } + }, + "status": "disabled" + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-9367dff0-941d-44e2-8875-cb48570c7add')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'EndpointThreatProtectionEssentials-CD-xdr-9367dff0-941d-c0494af8')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'Adversaries may establish persistence and/or elevate privileges by executing malicious content triggered by AppInit DLLs loaded into processes. \nDynamic-link libraries (DLLs) that are specified in the AppInit_DLLs value in the Registry keys HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows or HKEY_LOCAL_MACHINE\\Software\\Wow6432Node\\Microsoft\\Windows NT\\CurrentVersion\\Windows are loaded by user32.dll into every process that loads user32.dll. In practice this is nearly every program, since user32.dll is a very common library.\nRef: https://attack.mitre.org/techniques/T1546/", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "schedule": { + "frequency": "PT1H" + }, + "id": "[if(true(), 'xdr-9367dff0-941d-44e2-8875-cb48570c7add', 'xdr-9367dff0-941d-44e2-8875-cb48570c7add')]", + "displayName": "Registry Persistence via AppInit DLLs Modification", + "queryCondition": { + "queryText": "Event\n| where EventLog =~ \"Microsoft-Windows-Sysmon/Operational\" and EventID in (13)\n| parse EventData with * 'TargetObject\">' TargetObject \"<\" * 'Details\">' Details \"<\" *\n| where TargetObject has \"\\\\Windows NT\\\\CurrentVersion\\\\Windows\\\\AppInit_DLLs\"\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated) by EventID, Computer, TargetObject, Details\n| extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'')" + }, + "detectionAction": { + "alertTemplate": { + "description": "'Adversaries may establish persistence and/or elevate privileges by executing malicious content triggered by AppInit DLLs loaded into processes. \nDynamic-link libraries (DLLs) that are specified in the AppInit_DLLs value in the Registry keys HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows or HKEY_LOCAL_MACHINE\\Software\\Wow6432Node\\Microsoft\\Windows NT\\CurrentVersion\\Windows are loaded by user32.dll into every process that loads user32.dll. In practice this is nearly every program, since user32.dll is a very common library.\nRef: https://attack.mitre.org/techniques/T1546/", + "title": "Registry Persistence via AppInit DLLs Modification", + "customDetails": { + "HostFullName": "Computer", + "RegistryKeyKey": "TargetObject" + }, + "tactics": [ + { + "tactic": "Persistence", + "techniques": [ + { + "subTechniques": [ + "T1546.010" + ], + "technique": "T1546" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "nameColumn": "HostName", + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'host1', 'host1')]" + } + ] + }, + "severity": "medium" + } + }, + "status": "disabled" + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-9367dff0-941d-44e2-8875-cb48570c7add", + "contentKind": "CustomDetection", + "displayName": "Registry Persistence via AppInit DLLs Modification", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-9367dff0-941d-44e2-8875-cb48570c7add','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-9367dff0-941d-44e2-8875-cb48570c7add','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "EndpointThreatProtectionEssentials-CD-xdr-80da0a8f-cfe1-f3581b3a", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "schedule": { + "frequency": "P1D" + }, + "id": "[if(true(), 'xdr-80da0a8f-cfe1-4cd0-a895-8bc1771a720e', 'xdr-80da0a8f-cfe1-4cd0-a895-8bc1771a720e')]", + "displayName": "Security Event log cleared", + "queryCondition": { + "queryText": "(union isfuzzy=true\n(\nSecurityEvent\n| where EventID == 1102 and EventSourceName =~ \"Microsoft-Windows-Eventlog\"\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), EventCount = count() by Computer, Account, EventID, Activity\n),\n(\nWindowsEvent\n| where EventID == 1102 and Provider =~ \"Microsoft-Windows-Eventlog\"\n| extend Account = strcat(tostring(EventData.SubjectDomainName),\"\\\\\", tostring(EventData.SubjectUserName))\n| extend Activity= \"1102 - The audit log was cleared.\"\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), EventCount = count() by Computer, Account, EventID, Activity\n)\n)\n| extend Name=tostring(split(Account, \"@\")[0]), UPNSuffix=tostring(split(Account, \"@\")[1])\n| extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'')" + }, + "detectionAction": { + "alertTemplate": { + "description": "'Checks for event id 1102 which indicates the security event log was cleared.\nIt uses Event Source Name \"Microsoft-Windows-Eventlog\" to avoid generating false positives from other sources, like AD FS servers for instance.'", + "title": "Security Event log cleared", + "customDetails": { + "HostFullName": "Computer" + }, + "tactics": [ + { + "tactic": "DefenseEvasion", + "techniques": [ + { + "technique": "T1070" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "nameColumn": "HostName", + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'host1', 'host1')]" + } + ], + "accounts": [ + { + "upnSuffixColumn": "UPNSuffix", + "nameColumn": "Name", + "id": "[if(true(), 'account1', 'account1')]" + } + ] + }, + "severity": "medium" + } + }, + "status": "disabled" + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-80da0a8f-cfe1-4cd0-a895-8bc1771a720e')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'EndpointThreatProtectionEssentials-CD-xdr-80da0a8f-cfe1-f3581b3a')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'Checks for event id 1102 which indicates the security event log was cleared.\nIt uses Event Source Name \"Microsoft-Windows-Eventlog\" to avoid generating false positives from other sources, like AD FS servers for instance.'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "schedule": { + "frequency": "P1D" + }, + "id": "[if(true(), 'xdr-80da0a8f-cfe1-4cd0-a895-8bc1771a720e', 'xdr-80da0a8f-cfe1-4cd0-a895-8bc1771a720e')]", + "displayName": "Security Event log cleared", + "queryCondition": { + "queryText": "(union isfuzzy=true\n(\nSecurityEvent\n| where EventID == 1102 and EventSourceName =~ \"Microsoft-Windows-Eventlog\"\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), EventCount = count() by Computer, Account, EventID, Activity\n),\n(\nWindowsEvent\n| where EventID == 1102 and Provider =~ \"Microsoft-Windows-Eventlog\"\n| extend Account = strcat(tostring(EventData.SubjectDomainName),\"\\\\\", tostring(EventData.SubjectUserName))\n| extend Activity= \"1102 - The audit log was cleared.\"\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), EventCount = count() by Computer, Account, EventID, Activity\n)\n)\n| extend Name=tostring(split(Account, \"@\")[0]), UPNSuffix=tostring(split(Account, \"@\")[1])\n| extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'')" + }, + "detectionAction": { + "alertTemplate": { + "description": "'Checks for event id 1102 which indicates the security event log was cleared.\nIt uses Event Source Name \"Microsoft-Windows-Eventlog\" to avoid generating false positives from other sources, like AD FS servers for instance.'", + "title": "Security Event log cleared", + "customDetails": { + "HostFullName": "Computer" + }, + "tactics": [ + { + "tactic": "DefenseEvasion", + "techniques": [ + { + "technique": "T1070" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "nameColumn": "HostName", + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'host1', 'host1')]" + } + ], + "accounts": [ + { + "upnSuffixColumn": "UPNSuffix", + "nameColumn": "Name", + "id": "[if(true(), 'account1', 'account1')]" + } + ] + }, + "severity": "medium" + } + }, + "status": "disabled" + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-80da0a8f-cfe1-4cd0-a895-8bc1771a720e", + "contentKind": "CustomDetection", + "displayName": "Security Event log cleared", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-80da0a8f-cfe1-4cd0-a895-8bc1771a720e','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-80da0a8f-cfe1-4cd0-a895-8bc1771a720e','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "EndpointThreatProtectionEssentials-CD-xdr-b5153fb3-ada9-60829c5a", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "schedule": { + "frequency": "PT1H" + }, + "id": "[if(true(), 'xdr-b5153fb3-ada9-4ce4-9131-79c771efb50d', 'xdr-b5153fb3-ada9-4ce4-9131-79c771efb50d')]", + "displayName": "Suspicious Powershell Commandlet Executed", + "queryCondition": { + "queryText": "// Adjust the list of suspicious commandlets as needed\nlet SuspiciousPowerShellCommandList = dynamic([\"Get-ADUserResultantPasswordPolicy\",\n \"Get-DomainPolicy\",\n \"Get-DomainUser\",\n \"Get-DomainComputer\",\n \"Get-DomainController\",\n \"Get-DomainGroup\",\n \"Get-DomainTrust\",\n \"Get-ADTrust\",\n \"Get-ForestTrust\"\n ]);\nDeviceEvents\n| where ActionType == \"PowerShellCommand\"\n| extend Commandlet = tostring(parse_json(AdditionalFields).Command)\n| where Commandlet has_any (SuspiciousPowerShellCommandList)\n| project TimeGenerated, DeviceName, LocalIP, InitiatingProcessAccountUpn, InitiatingProcessId, InitiatingProcessFileName, InitiatingProcessFolderPath, InitiatingProcessCommandLine\n| extend Username = tostring(split(InitiatingProcessAccountUpn, '@')[0]), UPNSuffix = tostring(split(InitiatingProcessAccountUpn, '@')[1])\n| extend DvcHostname = tostring(split(DeviceName, '.')[0]), DvcDomain = tostring(strcat_array(array_slice(split(DeviceName, '.'), 1, -1), '.'))" + }, + "detectionAction": { + "alertTemplate": { + "description": "This analytic rule detects when a suspicious PowerShell commandlet is executed on a host. Threat actors often use PowerShell to execute commands and scripts to move laterally, escalate privileges, and exfiltrate data.", + "title": "Suspicious Powershell Commandlet Executed", + "customDetails": { + "ProcessProcessId": "InitiatingProcessId", + "HostFullName": "DeviceName", + "ProcessCommandLine": "InitiatingProcessCommandLine" + }, + "tactics": [ + { + "tactic": "Execution", + "techniques": [ + { + "technique": "T1059" + } + ] + } + ], + "entityMappings": { + "ips": [ + { + "addressColumn": "LocalIP", + "id": "[if(true(), 'ip1', 'ip1')]" + } + ], + "accounts": [ + { + "upnSuffixColumn": "UPNSuffix", + "nameColumn": "Username", + "id": "[if(true(), 'account1', 'account1')]" + } + ], + "hosts": [ + { + "nameColumn": "DvcHostname", + "dnsDomainColumn": "DvcDomain", + "id": "[if(true(), 'host1', 'host1')]" + } + ] + }, + "severity": "medium" + } + }, + "status": "disabled" + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-b5153fb3-ada9-4ce4-9131-79c771efb50d')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'EndpointThreatProtectionEssentials-CD-xdr-b5153fb3-ada9-60829c5a')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "This analytic rule detects when a suspicious PowerShell commandlet is executed on a host. Threat actors often use PowerShell to execute commands and scripts to move laterally, escalate privileges, and exfiltrate data.", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "schedule": { + "frequency": "PT1H" + }, + "id": "[if(true(), 'xdr-b5153fb3-ada9-4ce4-9131-79c771efb50d', 'xdr-b5153fb3-ada9-4ce4-9131-79c771efb50d')]", + "displayName": "Suspicious Powershell Commandlet Executed", + "queryCondition": { + "queryText": "// Adjust the list of suspicious commandlets as needed\nlet SuspiciousPowerShellCommandList = dynamic([\"Get-ADUserResultantPasswordPolicy\",\n \"Get-DomainPolicy\",\n \"Get-DomainUser\",\n \"Get-DomainComputer\",\n \"Get-DomainController\",\n \"Get-DomainGroup\",\n \"Get-DomainTrust\",\n \"Get-ADTrust\",\n \"Get-ForestTrust\"\n ]);\nDeviceEvents\n| where ActionType == \"PowerShellCommand\"\n| extend Commandlet = tostring(parse_json(AdditionalFields).Command)\n| where Commandlet has_any (SuspiciousPowerShellCommandList)\n| project TimeGenerated, DeviceName, LocalIP, InitiatingProcessAccountUpn, InitiatingProcessId, InitiatingProcessFileName, InitiatingProcessFolderPath, InitiatingProcessCommandLine\n| extend Username = tostring(split(InitiatingProcessAccountUpn, '@')[0]), UPNSuffix = tostring(split(InitiatingProcessAccountUpn, '@')[1])\n| extend DvcHostname = tostring(split(DeviceName, '.')[0]), DvcDomain = tostring(strcat_array(array_slice(split(DeviceName, '.'), 1, -1), '.'))" + }, + "detectionAction": { + "alertTemplate": { + "description": "This analytic rule detects when a suspicious PowerShell commandlet is executed on a host. Threat actors often use PowerShell to execute commands and scripts to move laterally, escalate privileges, and exfiltrate data.", + "title": "Suspicious Powershell Commandlet Executed", + "customDetails": { + "ProcessProcessId": "InitiatingProcessId", + "HostFullName": "DeviceName", + "ProcessCommandLine": "InitiatingProcessCommandLine" + }, + "tactics": [ + { + "tactic": "Execution", + "techniques": [ + { + "technique": "T1059" + } + ] + } + ], + "entityMappings": { + "ips": [ + { + "addressColumn": "LocalIP", + "id": "[if(true(), 'ip1', 'ip1')]" + } + ], + "accounts": [ + { + "upnSuffixColumn": "UPNSuffix", + "nameColumn": "Username", + "id": "[if(true(), 'account1', 'account1')]" + } + ], + "hosts": [ + { + "nameColumn": "DvcHostname", + "dnsDomainColumn": "DvcDomain", + "id": "[if(true(), 'host1', 'host1')]" + } + ] + }, + "severity": "medium" + } + }, + "status": "disabled" + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-b5153fb3-ada9-4ce4-9131-79c771efb50d", + "contentKind": "CustomDetection", + "displayName": "Suspicious Powershell Commandlet Executed", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-b5153fb3-ada9-4ce4-9131-79c771efb50d','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-b5153fb3-ada9-4ce4-9131-79c771efb50d','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "EndpointThreatProtectionEssentials-CD-xdr-f6502545-ae3a-98cd590a", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "schedule": { + "frequency": "PT1H" + }, + "id": "[if(true(), 'xdr-f6502545-ae3a-4232-a8b0-79d87e5c98d7', 'xdr-f6502545-ae3a-4232-a8b0-79d87e5c98d7')]", + "displayName": "WDigest downgrade attack", + "queryCondition": { + "queryText": "Event\n| where EventLog =~ \"Microsoft-Windows-Sysmon/Operational\" and EventID in (13)\n| parse EventData with * 'TargetObject\">' TargetObject \"<\" * 'Details\">' Details \"<\" *\n| where TargetObject=~\"HKLM\\\\System\\\\CurrentControlSet\\\\Control\\\\SecurityProviders\\\\WDigest\\\\UseLogonCredential\" and Details !=\"DWORD (0x00000000)\"\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated) by EventID, Computer, TargetObject, Details\n| extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'')" + }, + "detectionAction": { + "alertTemplate": { + "description": "'When the WDigest Authentication protocol is enabled, plain text passwords are stored in the Local Security Authority Subsystem Service (LSASS) exposing them to theft. This setting will prevent WDigest from storing credentials in memory.\nRef: https://www.microsoft.com/en-us/security/blog/2022/07/27/untangling-knotweed-european-private-sector-offensive-actor-using-0-day-exploits/'", + "title": "WDigest downgrade attack", + "customDetails": { + "HostFullName": "Computer", + "RegistryKeyKey": "TargetObject" + }, + "tactics": [ + { + "tactic": "CredentialAccess", + "techniques": [ + { + "technique": "T1003" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "nameColumn": "HostName", + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'host1', 'host1')]" + } + ] + }, + "severity": "medium" + } + }, + "status": "disabled" + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-f6502545-ae3a-4232-a8b0-79d87e5c98d7')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'EndpointThreatProtectionEssentials-CD-xdr-f6502545-ae3a-98cd590a')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'When the WDigest Authentication protocol is enabled, plain text passwords are stored in the Local Security Authority Subsystem Service (LSASS) exposing them to theft. This setting will prevent WDigest from storing credentials in memory.\nRef: https://www.microsoft.com/en-us/security/blog/2022/07/27/untangling-knotweed-european-private-sector-offensive-actor-using-0-day-exploits/'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "schedule": { + "frequency": "PT1H" + }, + "id": "[if(true(), 'xdr-f6502545-ae3a-4232-a8b0-79d87e5c98d7', 'xdr-f6502545-ae3a-4232-a8b0-79d87e5c98d7')]", + "displayName": "WDigest downgrade attack", + "queryCondition": { + "queryText": "Event\n| where EventLog =~ \"Microsoft-Windows-Sysmon/Operational\" and EventID in (13)\n| parse EventData with * 'TargetObject\">' TargetObject \"<\" * 'Details\">' Details \"<\" *\n| where TargetObject=~\"HKLM\\\\System\\\\CurrentControlSet\\\\Control\\\\SecurityProviders\\\\WDigest\\\\UseLogonCredential\" and Details !=\"DWORD (0x00000000)\"\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated) by EventID, Computer, TargetObject, Details\n| extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'')" + }, + "detectionAction": { + "alertTemplate": { + "description": "'When the WDigest Authentication protocol is enabled, plain text passwords are stored in the Local Security Authority Subsystem Service (LSASS) exposing them to theft. This setting will prevent WDigest from storing credentials in memory.\nRef: https://www.microsoft.com/en-us/security/blog/2022/07/27/untangling-knotweed-european-private-sector-offensive-actor-using-0-day-exploits/'", + "title": "WDigest downgrade attack", + "customDetails": { + "HostFullName": "Computer", + "RegistryKeyKey": "TargetObject" + }, + "tactics": [ + { + "tactic": "CredentialAccess", + "techniques": [ + { + "technique": "T1003" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "nameColumn": "HostName", + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'host1', 'host1')]" + } + ] + }, + "severity": "medium" + } + }, + "status": "disabled" + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-f6502545-ae3a-4232-a8b0-79d87e5c98d7", + "contentKind": "CustomDetection", + "displayName": "WDigest downgrade attack", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-f6502545-ae3a-4232-a8b0-79d87e5c98d7','-','3.1.2')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-f6502545-ae3a-4232-a8b0-79d87e5c98d7','-','3.1.2')))]", + "version": "3.1.2", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "EndpointThreatProtectionEssentials-CD-xdr-15049017-527f-5297a7d9", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "schedule": { + "frequency": "PT1H" + }, + "id": "[if(true(), 'xdr-15049017-527f-4d3b-b011-b0e99e68ef45', 'xdr-15049017-527f-4d3b-b011-b0e99e68ef45')]", + "displayName": "Windows Binaries Executed from Non-Default Directory", + "queryCondition": { + "queryText": "let procList = externaldata(Process:string) [@\"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Microsoft_Lolbas_Execution_Binaries.csv\"] with (format=\"csv\", ignoreFirstRecord=True);\nSecurityEvent\n| where EventID == 4688 and Process has_any (procList) and not (NewProcessName has (\"C:\\\\Windows\\\\\"))\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by EventID, Computer, SubjectUserName, NewProcessName, Process, CommandLine\n| extend Name=tostring(split(SubjectUserName, \"@\")[0]), UPNSuffix=tostring(split(SubjectUserName, \"@\")[1])\n| extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'')" + }, + "detectionAction": { + "alertTemplate": { + "description": "'The query detects Windows binaries, that can be executed from a non-default directory (e.g. C:\\Windows\\, C:\\Windows\\System32 etc.). \nRef: https://lolbas-project.github.io/'", + "title": "Windows Binaries Executed from Non-Default Directory", + "customDetails": { + "HostFullName": "Computer", + "ProcessCommandLine": "CommandLine" + }, + "tactics": [ + { + "tactic": "Execution", + "techniques": [ + { + "technique": "T1059" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "nameColumn": "HostName", + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'host1', 'host1')]" + } + ], + "accounts": [ + { + "upnSuffixColumn": "UPNSuffix", + "nameColumn": "Name", + "id": "[if(true(), 'account1', 'account1')]" + } + ] + }, + "severity": "medium" + } + }, + "status": "disabled" + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-15049017-527f-4d3b-b011-b0e99e68ef45')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'EndpointThreatProtectionEssentials-CD-xdr-15049017-527f-5297a7d9')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'The query detects Windows binaries, that can be executed from a non-default directory (e.g. C:\\Windows\\, C:\\Windows\\System32 etc.). \nRef: https://lolbas-project.github.io/'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "schedule": { + "frequency": "PT1H" + }, + "id": "[if(true(), 'xdr-15049017-527f-4d3b-b011-b0e99e68ef45', 'xdr-15049017-527f-4d3b-b011-b0e99e68ef45')]", + "displayName": "Windows Binaries Executed from Non-Default Directory", + "queryCondition": { + "queryText": "let procList = externaldata(Process:string) [@\"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Microsoft_Lolbas_Execution_Binaries.csv\"] with (format=\"csv\", ignoreFirstRecord=True);\nSecurityEvent\n| where EventID == 4688 and Process has_any (procList) and not (NewProcessName has (\"C:\\\\Windows\\\\\"))\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by EventID, Computer, SubjectUserName, NewProcessName, Process, CommandLine\n| extend Name=tostring(split(SubjectUserName, \"@\")[0]), UPNSuffix=tostring(split(SubjectUserName, \"@\")[1])\n| extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'')" + }, + "detectionAction": { + "alertTemplate": { + "description": "'The query detects Windows binaries, that can be executed from a non-default directory (e.g. C:\\Windows\\, C:\\Windows\\System32 etc.). \nRef: https://lolbas-project.github.io/'", + "title": "Windows Binaries Executed from Non-Default Directory", + "customDetails": { + "HostFullName": "Computer", + "ProcessCommandLine": "CommandLine" + }, + "tactics": [ + { + "tactic": "Execution", + "techniques": [ + { + "technique": "T1059" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "nameColumn": "HostName", + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'host1', 'host1')]" + } + ], + "accounts": [ + { + "upnSuffixColumn": "UPNSuffix", + "nameColumn": "Name", + "id": "[if(true(), 'account1', 'account1')]" + } + ] + }, + "severity": "medium" + } + }, + "status": "disabled" + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-15049017-527f-4d3b-b011-b0e99e68ef45", + "contentKind": "CustomDetection", + "displayName": "Windows Binaries Executed from Non-Default Directory", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-15049017-527f-4d3b-b011-b0e99e68ef45','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-15049017-527f-4d3b-b011-b0e99e68ef45','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "EndpointThreatProtectionEssentials-CD-xdr-cbf6ad48-fa5c-9f98ab95", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "schedule": { + "frequency": "PT1H" + }, + "id": "[if(true(), 'xdr-cbf6ad48-fa5c-4bf7-b205-28dbadb91255', 'xdr-cbf6ad48-fa5c-4bf7-b205-28dbadb91255')]", + "displayName": "Windows Binaries Lolbins Renamed", + "queryCondition": { + "queryText": "let procList = externaldata(Process:string) [@\"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Microsoft_Lolbas_Execution_Binaries.csv\"] with (format=\"csv\", ignoreFirstRecord=True);\nEvent\n| where EventLog =~ \"Microsoft-Windows-Sysmon/Operational\" and EventID==1\n| parse EventData with * 'Image\">' Image \"<\" * 'OriginalFileName\">' OriginalFileName \"<\" *\n| where OriginalFileName has_any (procList) and not (Image has_any (procList))\n| parse EventData with * 'ProcessGuid\">' ProcessGuid \"<\" * 'Description\">' Description \"<\" * 'CommandLine\">' CommandLine \"<\" * 'CurrentDirectory\">' CurrentDirectory \"<\" * 'User\">' User \"<\" * 'LogonGuid\">' LogonGuid \"<\" * 'Hashes\">' Hashes \"<\" * 'ParentProcessGuid\">' ParentProcessGuid \"<\" * 'ParentImage\">' ParentImage \"<\" * 'ParentCommandLine\">' ParentCommandLine \"<\" * 'ParentUser\">' ParentUser \"<\" *\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by EventID, Computer, User, ParentImage, ParentProcessGuid, ParentCommandLine, ParentUser, Image, ProcessGuid, CommandLine, Description, OriginalFileName, CurrentDirectory, Hashes\n| extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'')" + }, + "detectionAction": { + "alertTemplate": { + "description": "'This query detects the execution of renamed Windows binaries (Lolbins). This is a common technique used by adversaries to evade detection. \nRef: https://cortex-docs.paloaltonetworks.com/analytics-alerts/alerts-by-name/execution-of-renamed-lolbin'", + "title": "Windows Binaries Lolbins Renamed", + "customDetails": { + "HostFullName": "Computer", + "ProcessCommandLine": "CommandLine" + }, + "tactics": [ + { + "tactic": "Execution", + "techniques": [ + { + "technique": "T1059" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "nameColumn": "HostName", + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'host1', 'host1')]" + } + ], + "accounts": [ + { + "nameColumn": "User", + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'account1', 'account1')]" + } + ] + }, + "severity": "medium" + } + }, + "status": "disabled" + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-cbf6ad48-fa5c-4bf7-b205-28dbadb91255')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'EndpointThreatProtectionEssentials-CD-xdr-cbf6ad48-fa5c-9f98ab95')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'This query detects the execution of renamed Windows binaries (Lolbins). This is a common technique used by adversaries to evade detection. \nRef: https://cortex-docs.paloaltonetworks.com/analytics-alerts/alerts-by-name/execution-of-renamed-lolbin'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "schedule": { + "frequency": "PT1H" + }, + "id": "[if(true(), 'xdr-cbf6ad48-fa5c-4bf7-b205-28dbadb91255', 'xdr-cbf6ad48-fa5c-4bf7-b205-28dbadb91255')]", + "displayName": "Windows Binaries Lolbins Renamed", + "queryCondition": { + "queryText": "let procList = externaldata(Process:string) [@\"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Microsoft_Lolbas_Execution_Binaries.csv\"] with (format=\"csv\", ignoreFirstRecord=True);\nEvent\n| where EventLog =~ \"Microsoft-Windows-Sysmon/Operational\" and EventID==1\n| parse EventData with * 'Image\">' Image \"<\" * 'OriginalFileName\">' OriginalFileName \"<\" *\n| where OriginalFileName has_any (procList) and not (Image has_any (procList))\n| parse EventData with * 'ProcessGuid\">' ProcessGuid \"<\" * 'Description\">' Description \"<\" * 'CommandLine\">' CommandLine \"<\" * 'CurrentDirectory\">' CurrentDirectory \"<\" * 'User\">' User \"<\" * 'LogonGuid\">' LogonGuid \"<\" * 'Hashes\">' Hashes \"<\" * 'ParentProcessGuid\">' ParentProcessGuid \"<\" * 'ParentImage\">' ParentImage \"<\" * 'ParentCommandLine\">' ParentCommandLine \"<\" * 'ParentUser\">' ParentUser \"<\" *\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by EventID, Computer, User, ParentImage, ParentProcessGuid, ParentCommandLine, ParentUser, Image, ProcessGuid, CommandLine, Description, OriginalFileName, CurrentDirectory, Hashes\n| extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'')" + }, + "detectionAction": { + "alertTemplate": { + "description": "'This query detects the execution of renamed Windows binaries (Lolbins). This is a common technique used by adversaries to evade detection. \nRef: https://cortex-docs.paloaltonetworks.com/analytics-alerts/alerts-by-name/execution-of-renamed-lolbin'", + "title": "Windows Binaries Lolbins Renamed", + "customDetails": { + "HostFullName": "Computer", + "ProcessCommandLine": "CommandLine" + }, + "tactics": [ + { + "tactic": "Execution", + "techniques": [ + { + "technique": "T1059" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "nameColumn": "HostName", + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'host1', 'host1')]" + } + ], + "accounts": [ + { + "nameColumn": "User", + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'account1', 'account1')]" + } + ] + }, + "severity": "medium" + } + }, + "status": "disabled" + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-cbf6ad48-fa5c-4bf7-b205-28dbadb91255", + "contentKind": "CustomDetection", + "displayName": "Windows Binaries Lolbins Renamed", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-cbf6ad48-fa5c-4bf7-b205-28dbadb91255','-','3.1.2')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-cbf6ad48-fa5c-4bf7-b205-28dbadb91255','-','3.1.2')))]", + "version": "3.1.2", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "EndpointThreatProtectionEssentials-CD-xdr-ca67c83e-7fff-e4486f8f", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "schedule": { + "frequency": "P1D" + }, + "id": "[if(true(), 'xdr-ca67c83e-7fff-4127-a3e3-1af66d6d4cad', 'xdr-ca67c83e-7fff-4127-a3e3-1af66d6d4cad')]", + "displayName": "Base64 encoded Windows process command-lines", + "queryCondition": { + "queryText": "let ProcessCreationEvents=(union isfuzzy=true\n(SecurityEvent\n| where EventID==4688\n| where isnotempty(CommandLine)\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), count() by Computer, Account = SubjectUserName, AccountDomain = SubjectDomainName,\nFileName = Process, CommandLine, ParentProcessName\n),\n(WindowsEvent\n| where EventID==4688\n| where EventData has \"TVqQAAMAAAAEAAA\"\n| extend CommandLine = tostring(EventData.CommandLine)\n| where isnotempty(CommandLine)\n| extend ParentProcessName = tostring(EventData.ParentProcessName)\n| extend NewProcessName = tostring(EventData.NewProcessName)\n| extend Process=tostring(split(NewProcessName, '\\\\')[-1])\n| extend SubjectUserName = tostring(EventData.SubjectUserName)\n| extend SubjectDomainName = tostring(EventData.SubjectDomainName)\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), count() by Computer, Account = SubjectUserName, AccountDomain = SubjectDomainName,\nFileName = Process, CommandLine, ParentProcessName));\nProcessCreationEvents\n| where CommandLine contains \"TVqQAAMAAAAEAAA\"\n| extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'')" + }, + "detectionAction": { + "alertTemplate": { + "description": "'Identifies instances of a base64-encoded PE file header seen in the process command line parameter.'", + "title": "Base64 encoded Windows process command-lines", + "customDetails": { + "HostFullName": "Computer" + }, + "tactics": [ + { + "tactic": "Execution", + "techniques": [ + { + "technique": "T1059" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "nameColumn": "HostName", + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'host1', 'host1')]" + } + ], + "accounts": [ + { + "nameColumn": "Account", + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'account1', 'account1')]" + } + ] + }, + "severity": "medium" + } + }, + "status": "disabled" + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-ca67c83e-7fff-4127-a3e3-1af66d6d4cad')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'EndpointThreatProtectionEssentials-CD-xdr-ca67c83e-7fff-e4486f8f')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'Identifies instances of a base64-encoded PE file header seen in the process command line parameter.'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "schedule": { + "frequency": "P1D" + }, + "id": "[if(true(), 'xdr-ca67c83e-7fff-4127-a3e3-1af66d6d4cad', 'xdr-ca67c83e-7fff-4127-a3e3-1af66d6d4cad')]", + "displayName": "Base64 encoded Windows process command-lines", + "queryCondition": { + "queryText": "let ProcessCreationEvents=(union isfuzzy=true\n(SecurityEvent\n| where EventID==4688\n| where isnotempty(CommandLine)\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), count() by Computer, Account = SubjectUserName, AccountDomain = SubjectDomainName,\nFileName = Process, CommandLine, ParentProcessName\n),\n(WindowsEvent\n| where EventID==4688\n| where EventData has \"TVqQAAMAAAAEAAA\"\n| extend CommandLine = tostring(EventData.CommandLine)\n| where isnotempty(CommandLine)\n| extend ParentProcessName = tostring(EventData.ParentProcessName)\n| extend NewProcessName = tostring(EventData.NewProcessName)\n| extend Process=tostring(split(NewProcessName, '\\\\')[-1])\n| extend SubjectUserName = tostring(EventData.SubjectUserName)\n| extend SubjectDomainName = tostring(EventData.SubjectDomainName)\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), count() by Computer, Account = SubjectUserName, AccountDomain = SubjectDomainName,\nFileName = Process, CommandLine, ParentProcessName));\nProcessCreationEvents\n| where CommandLine contains \"TVqQAAMAAAAEAAA\"\n| extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'')" + }, + "detectionAction": { + "alertTemplate": { + "description": "'Identifies instances of a base64-encoded PE file header seen in the process command line parameter.'", + "title": "Base64 encoded Windows process command-lines", + "customDetails": { + "HostFullName": "Computer" + }, + "tactics": [ + { + "tactic": "Execution", + "techniques": [ + { + "technique": "T1059" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "nameColumn": "HostName", + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'host1', 'host1')]" + } + ], + "accounts": [ + { + "nameColumn": "Account", + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'account1', 'account1')]" + } + ] + }, + "severity": "medium" + } + }, + "status": "disabled" + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-ca67c83e-7fff-4127-a3e3-1af66d6d4cad", + "contentKind": "CustomDetection", + "displayName": "Base64 encoded Windows process command-lines", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-ca67c83e-7fff-4127-a3e3-1af66d6d4cad','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-ca67c83e-7fff-4127-a3e3-1af66d6d4cad','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "EndpointThreatProtectionEssentials-CD-xdr-d6190dde-8fd2-74c17e9d", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "schedule": { + "frequency": "P1D" + }, + "id": "[if(true(), 'xdr-d6190dde-8fd2-456a-ac5b-0a32400b0464', 'xdr-d6190dde-8fd2-456a-ac5b-0a32400b0464')]", + "displayName": "Process executed from binary hidden in Base64 encoded file", + "queryCondition": { + "queryText": "let ProcessCreationEvents=(union isfuzzy=true\n(SecurityEvent\n| where EventID==4688\n| where isnotempty(CommandLine)\n| project TimeGenerated, Computer, Account = SubjectUserName, AccountDomain = SubjectDomainName, FileName = Process, CommandLine, ParentProcessName\n),\n(WindowsEvent\n| where EventID==4688\n| where EventData has_any (\".decode('base64')\", \"base64 --decode\", \".decode64(\" )\n| extend CommandLine = tostring(EventData.CommandLine)\n| where isnotempty(CommandLine)\n| extend SubjectUserName = tostring(EventData.SubjectUserName)\n| extend SubjectDomainName = tostring(EventData.SubjectDomainName)\n| extend NewProcessName = tostring(EventData.NewProcessName)\n| extend FileName=tostring(split(NewProcessName, '\\\\')[-1])\n| extend ParentProcessName = tostring(EventData.ParentProcessName)\n| project TimeGenerated, Computer, Account = SubjectUserName, AccountDomain = SubjectDomainName, CommandLine, ParentProcessName\n));\nProcessCreationEvents\n| where CommandLine contains \".decode('base64')\"\n or CommandLine contains \"base64 --decode\"\n or CommandLine contains \".decode64(\"\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), CountToday = count() by Computer, Account, AccountDomain, FileName, CommandLine, ParentProcessName\n| extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'')" + }, + "detectionAction": { + "alertTemplate": { + "description": "'Encoding malicious software is a technique used to obfuscate files from detection. \nThe first CommandLine component is looking for Python decoding base64. \nThe second CommandLine component is looking for Bash/sh command line base64 decoding.\nThe third one is looking for Ruby decoding base64.'", + "title": "Process executed from binary hidden in Base64 encoded file", + "customDetails": { + "HostFullName": "Computer" + }, + "tactics": [ + { + "tactic": "Execution", + "techniques": [ + { + "technique": "T1059" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "nameColumn": "HostName", + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'host1', 'host1')]" + } + ], + "accounts": [ + { + "nameColumn": "Account", + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'account1', 'account1')]" + } + ] + }, + "severity": "medium" + } + }, + "status": "disabled" + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-d6190dde-8fd2-456a-ac5b-0a32400b0464')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'EndpointThreatProtectionEssentials-CD-xdr-d6190dde-8fd2-74c17e9d')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'Encoding malicious software is a technique used to obfuscate files from detection. \nThe first CommandLine component is looking for Python decoding base64. \nThe second CommandLine component is looking for Bash/sh command line base64 decoding.\nThe third one is looking for Ruby decoding base64.'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "schedule": { + "frequency": "P1D" + }, + "id": "[if(true(), 'xdr-d6190dde-8fd2-456a-ac5b-0a32400b0464', 'xdr-d6190dde-8fd2-456a-ac5b-0a32400b0464')]", + "displayName": "Process executed from binary hidden in Base64 encoded file", + "queryCondition": { + "queryText": "let ProcessCreationEvents=(union isfuzzy=true\n(SecurityEvent\n| where EventID==4688\n| where isnotempty(CommandLine)\n| project TimeGenerated, Computer, Account = SubjectUserName, AccountDomain = SubjectDomainName, FileName = Process, CommandLine, ParentProcessName\n),\n(WindowsEvent\n| where EventID==4688\n| where EventData has_any (\".decode('base64')\", \"base64 --decode\", \".decode64(\" )\n| extend CommandLine = tostring(EventData.CommandLine)\n| where isnotempty(CommandLine)\n| extend SubjectUserName = tostring(EventData.SubjectUserName)\n| extend SubjectDomainName = tostring(EventData.SubjectDomainName)\n| extend NewProcessName = tostring(EventData.NewProcessName)\n| extend FileName=tostring(split(NewProcessName, '\\\\')[-1])\n| extend ParentProcessName = tostring(EventData.ParentProcessName)\n| project TimeGenerated, Computer, Account = SubjectUserName, AccountDomain = SubjectDomainName, CommandLine, ParentProcessName\n));\nProcessCreationEvents\n| where CommandLine contains \".decode('base64')\"\n or CommandLine contains \"base64 --decode\"\n or CommandLine contains \".decode64(\"\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), CountToday = count() by Computer, Account, AccountDomain, FileName, CommandLine, ParentProcessName\n| extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'')" + }, + "detectionAction": { + "alertTemplate": { + "description": "'Encoding malicious software is a technique used to obfuscate files from detection. \nThe first CommandLine component is looking for Python decoding base64. \nThe second CommandLine component is looking for Bash/sh command line base64 decoding.\nThe third one is looking for Ruby decoding base64.'", + "title": "Process executed from binary hidden in Base64 encoded file", + "customDetails": { + "HostFullName": "Computer" + }, + "tactics": [ + { + "tactic": "Execution", + "techniques": [ + { + "technique": "T1059" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "nameColumn": "HostName", + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'host1', 'host1')]" + } + ], + "accounts": [ + { + "nameColumn": "Account", + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'account1', 'account1')]" + } + ] + }, + "severity": "medium" + } + }, + "status": "disabled" + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-d6190dde-8fd2-456a-ac5b-0a32400b0464", + "contentKind": "CustomDetection", + "displayName": "Process executed from binary hidden in Base64 encoded file", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-d6190dde-8fd2-456a-ac5b-0a32400b0464','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-d6190dde-8fd2-456a-ac5b-0a32400b0464','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "EndpointThreatProtectionEssentials-CD-xdr-75bf9902-0789-686e5dfe", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "schedule": { + "frequency": "P1D" + }, + "id": "[if(true(), 'xdr-75bf9902-0789-47c1-a5d8-f57046aa72df', 'xdr-75bf9902-0789-47c1-a5d8-f57046aa72df')]", + "displayName": "Malware in the recycle bin", + "queryCondition": { + "queryText": "let procList = externaldata(Process:string) [@\"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Microsoft_Lolbas_Execution_Binaries.csv\"] with (format=\"csv\", ignoreFirstRecord=True);\nlet recycle_bin_paths = dynamic([@\":\\RECYCLER\", @\":\\$RECYCLE.BIN\"]);\nlet ProcessCreationEvents=(union isfuzzy=true\n(SecurityEvent\n| where EventID==4688\n| where isnotempty(CommandLine)\n| project TimeGenerated, Computer, Account = SubjectUserName, AccountDomain = SubjectDomainName, NewProcessName,\nFileName = Process, CommandLine, ParentProcessName\n),\n(WindowsEvent\n| where EventID==4688 and EventData has_any (procList) and EventData has_any (recycle_bin_paths)\n| extend CommandLine = tostring(EventData.CommandLine)\n| where isnotempty(CommandLine)\n| extend SubjectUserName = tostring(EventData.SubjectUserName)\n| extend SubjectDomainName = tostring(EventData.SubjectDomainName)\n| extend NewProcessName = tostring(EventData.NewProcessName)\n| extend ParentProcessName = tostring(EventData.ParentProcessName)\n| extend Process=tostring(split(NewProcessName, '\\\\')[-1])\n| project TimeGenerated, Computer, Account = SubjectUserName, AccountDomain = SubjectDomainName, NewProcessName,\nFileName = Process, CommandLine, ParentProcessName\n));\nProcessCreationEvents\n| where FileName in~ (procList)\n| where CommandLine has_any (recycle_bin_paths)\n| project StartTimeUtc = TimeGenerated, Computer, Account, NewProcessName, FileName, CommandLine, ParentProcessName\n| extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'')" + }, + "detectionAction": { + "alertTemplate": { + "description": "'The query detects Windows binaries that can be used for executing malware and have been hidden in the recycle bin.\nThe list of these binaries is sourced from https://lolbas-project.github.io/\nReferences: https://azure.microsoft.com/blog/how-azure-security-center-helps-reveal-a-cyberattack/.'", + "title": "Malware in the recycle bin", + "customDetails": { + "HostFullName": "Computer" + }, + "tactics": [ + { + "tactic": "DefenseEvasion", + "techniques": [ + { + "technique": "T1564" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "nameColumn": "HostName", + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'host1', 'host1')]" + } + ], + "accounts": [ + { + "nameColumn": "Account", + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'account1', 'account1')]" + } + ] + }, + "severity": "medium" + } + }, + "status": "disabled" + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-75bf9902-0789-47c1-a5d8-f57046aa72df')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'EndpointThreatProtectionEssentials-CD-xdr-75bf9902-0789-686e5dfe')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'The query detects Windows binaries that can be used for executing malware and have been hidden in the recycle bin.\nThe list of these binaries is sourced from https://lolbas-project.github.io/\nReferences: https://azure.microsoft.com/blog/how-azure-security-center-helps-reveal-a-cyberattack/.'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "schedule": { + "frequency": "P1D" + }, + "id": "[if(true(), 'xdr-75bf9902-0789-47c1-a5d8-f57046aa72df', 'xdr-75bf9902-0789-47c1-a5d8-f57046aa72df')]", + "displayName": "Malware in the recycle bin", + "queryCondition": { + "queryText": "let procList = externaldata(Process:string) [@\"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Microsoft_Lolbas_Execution_Binaries.csv\"] with (format=\"csv\", ignoreFirstRecord=True);\nlet recycle_bin_paths = dynamic([@\":\\RECYCLER\", @\":\\$RECYCLE.BIN\"]);\nlet ProcessCreationEvents=(union isfuzzy=true\n(SecurityEvent\n| where EventID==4688\n| where isnotempty(CommandLine)\n| project TimeGenerated, Computer, Account = SubjectUserName, AccountDomain = SubjectDomainName, NewProcessName,\nFileName = Process, CommandLine, ParentProcessName\n),\n(WindowsEvent\n| where EventID==4688 and EventData has_any (procList) and EventData has_any (recycle_bin_paths)\n| extend CommandLine = tostring(EventData.CommandLine)\n| where isnotempty(CommandLine)\n| extend SubjectUserName = tostring(EventData.SubjectUserName)\n| extend SubjectDomainName = tostring(EventData.SubjectDomainName)\n| extend NewProcessName = tostring(EventData.NewProcessName)\n| extend ParentProcessName = tostring(EventData.ParentProcessName)\n| extend Process=tostring(split(NewProcessName, '\\\\')[-1])\n| project TimeGenerated, Computer, Account = SubjectUserName, AccountDomain = SubjectDomainName, NewProcessName,\nFileName = Process, CommandLine, ParentProcessName\n));\nProcessCreationEvents\n| where FileName in~ (procList)\n| where CommandLine has_any (recycle_bin_paths)\n| project StartTimeUtc = TimeGenerated, Computer, Account, NewProcessName, FileName, CommandLine, ParentProcessName\n| extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'')" + }, + "detectionAction": { + "alertTemplate": { + "description": "'The query detects Windows binaries that can be used for executing malware and have been hidden in the recycle bin.\nThe list of these binaries is sourced from https://lolbas-project.github.io/\nReferences: https://azure.microsoft.com/blog/how-azure-security-center-helps-reveal-a-cyberattack/.'", + "title": "Malware in the recycle bin", + "customDetails": { + "HostFullName": "Computer" + }, + "tactics": [ + { + "tactic": "DefenseEvasion", + "techniques": [ + { + "technique": "T1564" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "nameColumn": "HostName", + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'host1', 'host1')]" + } + ], + "accounts": [ + { + "nameColumn": "Account", + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'account1', 'account1')]" + } + ] + }, + "severity": "medium" + } + }, + "status": "disabled" + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-75bf9902-0789-47c1-a5d8-f57046aa72df", + "contentKind": "CustomDetection", + "displayName": "Malware in the recycle bin", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-75bf9902-0789-47c1-a5d8-f57046aa72df','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-75bf9902-0789-47c1-a5d8-f57046aa72df','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "pid-399fb80b-c914-4257-b61e-91ab73733888-partnercenter", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [] + } + } } ], "outputs": {} diff --git a/Solutions/Endpoint Threat Protection Essentials/Package/testParameters.json b/Solutions/Endpoint Threat Protection Essentials/Package/testParameters.json index e55ec41a9ac..8f5b425d45e 100644 --- a/Solutions/Endpoint Threat Protection Essentials/Package/testParameters.json +++ b/Solutions/Endpoint Threat Protection Essentials/Package/testParameters.json @@ -20,5 +20,26 @@ "metadata": { "description": "Workspace name for Log Analytics where Microsoft Sentinel is setup" } + }, + "DeployAnalyticsRule": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Deploy the Microsoft Sentinel analytic rules carried by this solution (ContentKind AnalyticsRule and its AnalyticsRuleTemplate registration face)." + } + }, + "DeployCustomDetection": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Deploy the XDR-native custom detection resources and their Content Hub registrations (ContentKind CustomDetection and CustomDetectionTemplate). Independent of DeployAnalyticsRule: both kinds can be selected together. Existing analytic-rule instances are not disabled or removed. CD enabled or disabled status is controlled separately from this deployment switch." + } + }, + "DeployHuntingQuery": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Deploy the Microsoft Sentinel hunting queries carried by this solution." + } } } diff --git a/Solutions/Endpoint Threat Protection Essentials/ReleaseNotes.md b/Solutions/Endpoint Threat Protection Essentials/ReleaseNotes.md index 23ff32409ea..487257b0383 100644 --- a/Solutions/Endpoint Threat Protection Essentials/ReleaseNotes.md +++ b/Solutions/Endpoint Threat Protection Essentials/ReleaseNotes.md @@ -1,5 +1,6 @@ | **Version** | **Date Modified (DD-MM-YYYY)** | **Change History** | |-------------|--------------------------------|------------------------------------------------------------------------------| +| 3.1.2 | 12-10-2026 | Added 15 disabled Defender XDR Custom Detections with source-rule provenance and reviewed mappings. Offline authoring validation completed; runtime validation and alert parity not run. | | 3.0.7 | 18-08-2026 | Updated version and mapping of `connectorId` to `dataTypes` for multiple **Analytic Rules** and **Hunting Queries**. | | 3.0.6 | 20-07-2026 | Added **Analytic Rule** CertUtil Used for File Download. | | 3.0.5 | 18-11-2024 | Removed the broken URL in **Analytic Rule** and **Hunting Query** | diff --git a/Solutions/Endpoint Threat Protection Essentials/SolutionMetadata.json b/Solutions/Endpoint Threat Protection Essentials/SolutionMetadata.json index 2958be61e07..960db95fc98 100644 --- a/Solutions/Endpoint Threat Protection Essentials/SolutionMetadata.json +++ b/Solutions/Endpoint Threat Protection Essentials/SolutionMetadata.json @@ -1,15 +1,21 @@ { - "publisherId": "azuresentinel", - "offerId": "azure-sentinel-solution-endpointthreat", - "firstPublishDate": "2022-11-16", - "providers": ["Microsoft"], - "categories": { - "domains" : ["Security - Threat Protection"] - }, - "support": { - "name": "Microsoft Corporation", - "email": "support@microsoft.com", - "tier": "Microsoft", - "link": "https://support.microsoft.com" - } -} \ No newline at end of file + "trackingId": "pid-399fb80b-c914-4257-b61e-91ab73733888-partnercenter", + "publisherId": "azuresentinel", + "offerId": "azure-sentinel-solution-endpointthreat", + "firstPublishDate": "2022-11-16", + "providers": [ + "Microsoft" + ], + "categories": { + "domains": [ + "Security - Threat Protection" + ] + }, + "support": { + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "tier": "Microsoft", + "link": "https://support.microsoft.com" + }, + "version": "3.1.2" +} diff --git a/Solutions/Endpoint Threat Protection Essentials/XDR Detections/Certutil-Download-Abuse.yaml b/Solutions/Endpoint Threat Protection Essentials/XDR Detections/Certutil-Download-Abuse.yaml new file mode 100644 index 00000000000..350adacace0 --- /dev/null +++ b/Solutions/Endpoint Threat Protection Essentials/XDR Detections/Certutil-Download-Abuse.yaml @@ -0,0 +1,176 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: MicrosoftThreatProtection + dataTypes: + - DeviceProcessEvents +- connectorId: SecurityEvents + dataTypes: + - SecurityEvent +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: 4a9d3c2e-7f1b-4e58-9a0c-2d5b8e3f1a7c + path: Analytic Rules/Certutil-Download-Abuse.yaml + version: 1.0.0 + querySha256: 2f456bffe591a084ad3c4409bce544fce261fa043c7d9236623d645a5dc646bc + schedule: + queryFrequency: 1h + queryPeriod: 1h + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - query mixes native Defender and Sentinel workload tables; time columns were preserved and require runtime validation + - 'Schedule assessment: source frequency=1h, lookback=1h; target frequency=PT1H, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - 'Best-effort entity mapping requires review: source Host.FullName column `HostName` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - Host.FullName value is retained as customDetails.HostFullName from query column `HostName`, but its target output binding + requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.HostFullName column `HostName` requires runtime output-schema binding verification + - Process.CommandLine value is retained as customDetails.ProcessCommandLine from query column `ProcessCommandLine`, but + its target output binding requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.ProcessCommandLine column `ProcessCommandLine` requires runtime output-schema binding verification + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: + - All source MITRE tactics are preserved in source order in authored YAML. V3.1 ARM packaging carries only the first tactic + and its compatible techniques; this classification loss is not validated parity. Direct Graph deployment requires a + single tactic. + errors: [] + originalTactics: + - CommandAndControl + - DefenseEvasion + originalTechniques: + - T1105 + - T1218 + - T1140 + reviewScope: + sourceDocumentSha256: e260d599fd7336743433a81e3d8bfebaf266e5045b227673fa4959e96b5617f7 + targetQuerySha256: 133cd5d3e24d02d6bf86df62c17fa9fade6b77eed26a4d961e1110a11bfa0a19 + reviewDecisions: + - reason: query mixes native Defender and Sentinel workload tables; time columns were preserved and require runtime validation + decision: accepted + sourceDocumentSha256: e260d599fd7336743433a81e3d8bfebaf266e5045b227673fa4959e96b5617f7 + targetQuerySha256: 133cd5d3e24d02d6bf86df62c17fa9fade6b77eed26a4d961e1110a11bfa0a19 + - reason: Original Sentinel lookback is shorter than the native XDR service window, but source and target table inputs + cannot be proven equivalent + decision: accepted + sourceDocumentSha256: e260d599fd7336743433a81e3d8bfebaf266e5045b227673fa4959e96b5617f7 + targetQuerySha256: 133cd5d3e24d02d6bf86df62c17fa9fade6b77eed26a4d961e1110a11bfa0a19 + - reason: 'Best-effort entity mapping requires review: source Host.FullName column `HostName` is provisionally represented + by hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + decision: accepted + sourceDocumentSha256: e260d599fd7336743433a81e3d8bfebaf266e5045b227673fa4959e96b5617f7 + targetQuerySha256: 133cd5d3e24d02d6bf86df62c17fa9fade6b77eed26a4d961e1110a11bfa0a19 + supplementalEntityDetails: + - entityType: Host + entityIndex: 1 + identifier: FullName + sourceColumn: HostName + column: HostName + status: runtime-binding-pending + customDetailKey: HostFullName + - entityType: Process + entityIndex: 3 + identifier: CommandLine + sourceColumn: ProcessCommandLine + column: ProcessCommandLine + status: runtime-binding-pending + customDetailKey: ProcessCommandLine + acceptedReviewReasons: + - 'Best-effort entity mapping requires review: source Host.FullName column `HostName` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - Original Sentinel lookback is shorter than the native XDR service window, but source and target table inputs cannot + be proven equivalent + - query mixes native Defender and Sentinel workload tables; time columns were preserved and require runtime validation +properties: + id: xdr-4a9d3c2e-7f1b-4e58-9a0c-2d5b8e3f1a7c + displayName: CertUtil Used for File Download (Living off the Land) + status: disabled + queryCondition: + queryText: |- + let Lookback = 1h; + let AllowlistedDomains = dynamic([ + "windowsupdate.microsoft.com", + "download.microsoft.com", + "dl.delivery.mp.microsoft.com", + "ctldl.windowsupdate.com" + ]); + let MDE_Results = + DeviceProcessEvents + | where Timestamp >= ago(Lookback) + | where FileName =~ "certutil.exe" + | where ProcessCommandLine has_any ("-urlcache", "-verifyctl", "-decode", "-decodehex") + | where ProcessCommandLine has_any ("http://", "https://", "ftp://") + | where not(ProcessCommandLine has_any (AllowlistedDomains)) + | extend + AccountName = InitiatingProcessAccountName, + AccountDomain = InitiatingProcessAccountDomain, + HostName = DeviceName, + EventTime = Timestamp + | project EventTime, HostName, AccountName, AccountDomain, + ProcessCommandLine, InitiatingProcessFileName; + let SecEvent_Results = + SecurityEvent + | where TimeGenerated >= ago(Lookback) + | where EventID == 4688 + | where NewProcessName endswith "\\certutil.exe" + | where CommandLine has_any ("-urlcache", "-verifyctl", "-decode", "-decodehex") + | where CommandLine has_any ("http://", "https://", "ftp://") + | where not(CommandLine has_any (AllowlistedDomains)) + | extend + AccountName = SubjectUserName, + AccountDomain = SubjectDomainName, + HostName = Computer, + EventTime = TimeGenerated, + ProcessCommandLine = CommandLine, + InitiatingProcessFileName = ParentProcessName + | project EventTime, HostName, AccountName, AccountDomain, + ProcessCommandLine, InitiatingProcessFileName; + union MDE_Results, SecEvent_Results + | sort by EventTime desc + schedule: + frequency: PT1H + detectionAction: + alertTemplate: + title: CertUtil Used for File Download (Living off the Land) + description: |- + Detects certutil.exe being used to download files from remote URLs via the + -urlcache or -verifyctl flags. CertUtil is a signed Windows binary (LOLBin) + that attackers abuse to download payloads while bypassing application + whitelisting and network controls. + Tune AllowlistedDomains to match your PKI/CA infrastructure. + severity: high + entityMappings: + hosts: + - id: host1 + nameColumn: HostName + accounts: + - id: account1 + nameColumn: AccountName + ntDomainColumn: AccountDomain + tactics: + - tactic: CommandAndControl + techniques: + - technique: T1105 + - tactic: DefenseEvasion + techniques: + - technique: T1218 + - technique: T1140 + customDetails: + HostFullName: HostName + ProcessCommandLine: ProcessCommandLine diff --git a/Solutions/Endpoint Threat Protection Essentials/XDR Detections/DumpingLSASSProcessIntoaFile.yaml b/Solutions/Endpoint Threat Protection Essentials/XDR Detections/DumpingLSASSProcessIntoaFile.yaml new file mode 100644 index 00000000000..adc6096cf46 --- /dev/null +++ b/Solutions/Endpoint Threat Protection Essentials/XDR Detections/DumpingLSASSProcessIntoaFile.yaml @@ -0,0 +1,119 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: SecurityEvents + dataTypes: + - SecurityEvent +- connectorId: WindowsSecurityEvents + dataTypes: + - SecurityEvent +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: a7b9df32-1367-402d-b385-882daf6e3020 + path: Analytic Rules/DumpingLSASSProcessIntoaFile.yaml + version: 1.0.3 + querySha256: 0de46f393e18390635007b90d927cd482cb4ceb149d74d5aebc158b043c88449 + schedule: + queryFrequency: 1h + queryPeriod: 1h + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - 'Schedule assessment: source frequency=1h, lookback=1h; target frequency=PT1H, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - Host.FullName value is retained as customDetails.HostFullName from query column `Computer`, but its target output binding + requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.HostFullName column `Computer` requires runtime output-schema binding verification + - Process.CommandLine value is retained as customDetails.ProcessCommandLine from query column `SourceImage`, but its target + output binding requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.ProcessCommandLine column `SourceImage` requires runtime output-schema binding verification + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: [] + errors: [] + originalTactics: + - CredentialAccess + originalTechniques: + - T1003.001 + reviewScope: + sourceDocumentSha256: 6428d2cb61c9c0175ada1906f6bd056da37d6498c56cb6bc07edf0efcd4d3b78 + targetQuerySha256: 2ea0ba73127186363713fe7eaefdeb536e321069130b2b6c4801c595e062bb66 + reviewDecisions: + - reason: 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented + by hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + decision: accepted + sourceDocumentSha256: 6428d2cb61c9c0175ada1906f6bd056da37d6498c56cb6bc07edf0efcd4d3b78 + targetQuerySha256: 2ea0ba73127186363713fe7eaefdeb536e321069130b2b6c4801c595e062bb66 + supplementalEntityDetails: + - entityType: Host + entityIndex: 1 + identifier: FullName + sourceColumn: Computer + column: Computer + status: runtime-binding-pending + customDetailKey: HostFullName + - entityType: Process + entityIndex: 2 + identifier: CommandLine + sourceColumn: SourceImage + column: SourceImage + status: runtime-binding-pending + customDetailKey: ProcessCommandLine + acceptedReviewReasons: + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' +properties: + id: xdr-a7b9df32-1367-402d-b385-882daf6e3020 + displayName: Dumping LSASS Process Into a File + status: disabled + queryCondition: + queryText: |- + Event + | where EventLog =~ "Microsoft-Windows-Sysmon/Operational" and EventID==10 + | parse EventData with * 'TargetImage">' TargetImage "<" * 'GrantedAccess">' GrantedAccess "<" * 'CallTrace">' CallTrace "<" * + | where GrantedAccess =~ "0x1FFFFF" and TargetImage =~ "C:\\Windows\\System32\\lsass.exe" and CallTrace has_any ("dbghelp.dll","dbgcore.dll") + | parse EventData with * 'SourceProcessGUID">' SourceProcessGUID "<" * 'SourceImage">' SourceImage "<" * + | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by EventID, Computer, SourceProcessGUID, SourceImage, GrantedAccess, TargetImage, CallTrace + | extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'') + schedule: + frequency: PT1H + detectionAction: + alertTemplate: + title: Dumping LSASS Process Into a File + description: |- + 'Adversaries may attempt to access credential material stored in the process memory of the Local Security Authority Subsystem Service (LSASS). + After a user logs on, the system generates and stores a variety of credential materials in LSASS process memory. + These credential materials can be harvested by an administrative user or system and used to conduct lateral movement using alternate authentication materials. + As well as in-memory techniques, the LSASS process memory can be dumped from the target host and analyzed on a local system. + Ref: https://attack.mitre.org/techniques/T1003/001/' + severity: high + entityMappings: + hosts: + - id: host1 + nameColumn: HostName + dnsDomainColumn: DnsDomain + tactics: + - tactic: CredentialAccess + techniques: + - technique: T1003 + subTechniques: + - T1003.001 + customDetails: + HostFullName: Computer + ProcessCommandLine: SourceImage diff --git a/Solutions/Endpoint Threat Protection Essentials/XDR Detections/LateralMovementViaDCOM.yaml b/Solutions/Endpoint Threat Protection Essentials/XDR Detections/LateralMovementViaDCOM.yaml new file mode 100644 index 00000000000..f0bbdd854ba --- /dev/null +++ b/Solutions/Endpoint Threat Protection Essentials/XDR Detections/LateralMovementViaDCOM.yaml @@ -0,0 +1,121 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: SecurityEvents + dataTypes: + - SecurityEvent +- connectorId: WindowsSecurityEvents + dataTypes: + - SecurityEvent +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: 50cbf34a-4cdd-45d7-b3f5-8b53a1d0d14f + path: Analytic Rules/LateralMovementViaDCOM.yaml + version: 1.0.3 + querySha256: 5d241ebc7138ffe07fd4fbf9d4dc86a2282373960f053c4e8a50a8727c7ee14b + schedule: + queryFrequency: 1h + queryPeriod: 1h + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - 'Schedule assessment: source frequency=1h, lookback=1h; target frequency=PT1H, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - Account mapping was completed with projected column `DnsDomain` + - Process.CommandLine value is retained as customDetails.ProcessCommandLine from query column `CommandLine`, but its target + output binding requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.ProcessCommandLine column `CommandLine` requires runtime output-schema binding verification + - Host.FullName value is retained as customDetails.HostFullName from query column `Computer`, but its target output binding + requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.HostFullName column `Computer` requires runtime output-schema binding verification + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: [] + errors: [] + originalTactics: + - LateralMovement + originalTechniques: + - T1021.003 + reviewScope: + sourceDocumentSha256: 4a6b81332e877fdb915f8060d084e04af6cfce0e4693e21275c8985019fa1a36 + targetQuerySha256: 143938aa8b89f8af527853dd341931da335fb9017e3af0b701d6d6d195b9f451 + reviewDecisions: + - reason: 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented + by hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + decision: accepted + sourceDocumentSha256: 4a6b81332e877fdb915f8060d084e04af6cfce0e4693e21275c8985019fa1a36 + targetQuerySha256: 143938aa8b89f8af527853dd341931da335fb9017e3af0b701d6d6d195b9f451 + supplementalEntityDetails: + - entityType: Process + entityIndex: 1 + identifier: CommandLine + sourceColumn: CommandLine + column: CommandLine + status: runtime-binding-pending + customDetailKey: ProcessCommandLine + - entityType: Host + entityIndex: 2 + identifier: FullName + sourceColumn: Computer + column: Computer + status: runtime-binding-pending + customDetailKey: HostFullName + acceptedReviewReasons: + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' +properties: + id: xdr-50cbf34a-4cdd-45d7-b3f5-8b53a1d0d14f + displayName: Lateral Movement via DCOM + status: disabled + queryCondition: + queryText: |- + Event + | where EventLog =~ "Microsoft-Windows-Sysmon/Operational" and EventID==1 + | parse EventData with * 'CommandLine">' CommandLine "<" * 'ParentCommandLine">' ParentCommandLine "<" * + | where ParentCommandLine =~ "C:\\Windows\\System32\\svchost.exe -k DcomLaunch" and CommandLine =~ "C:\\Windows\\System32\\mmc.exe -Embedding" + | parse EventData with * 'ProcessGuid">' ProcessGuid "<" * 'Image">' Image "<" * 'Description">' Description "<" * 'CurrentDirectory">' CurrentDirectory "<" * 'User">' User "<" * 'LogonGuid">' LogonGuid "<" * 'ParentProcessGuid">' ParentProcessGuid "<" * 'ParentImage">' ParentImage "<" * 'ParentCommandLine">' ParentCommandLine "<" * 'ParentUser">' ParentUser "<" * + | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by EventID, Computer, User, ParentImage, ParentProcessGuid, ParentCommandLine, ParentUser, Image, ProcessGuid, CommandLine, Description + | extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'') + schedule: + frequency: PT1H + detectionAction: + alertTemplate: + title: Lateral Movement via DCOM + description: |- + 'This query detects a fairly uncommon attack technique using the Windows Distributed Component Object Model (DCOM) to make a remote execution call to another computer system and gain lateral movement throughout the network. + Ref: http://thenegative.zone/incident%20response/2017/02/04/MMC20.Application-Lateral-Movement-Analysis.html' + severity: medium + entityMappings: + hosts: + - id: host1 + nameColumn: HostName + dnsDomainColumn: DnsDomain + accounts: + - id: account1 + nameColumn: User + dnsDomainColumn: DnsDomain + tactics: + - tactic: LateralMovement + techniques: + - technique: T1021 + subTechniques: + - T1021.003 + customDetails: + ProcessCommandLine: CommandLine + HostFullName: Computer diff --git a/Solutions/Endpoint Threat Protection Essentials/XDR Detections/MacroInvokingShellBrowserWindowCOMObjects.yaml b/Solutions/Endpoint Threat Protection Essentials/XDR Detections/MacroInvokingShellBrowserWindowCOMObjects.yaml new file mode 100644 index 00000000000..933723bb1e5 --- /dev/null +++ b/Solutions/Endpoint Threat Protection Essentials/XDR Detections/MacroInvokingShellBrowserWindowCOMObjects.yaml @@ -0,0 +1,120 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: SecurityEvents + dataTypes: + - SecurityEvent +- connectorId: WindowsSecurityEvents + dataTypes: + - SecurityEvent +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: e7470b35-0128-4508-bfc9-e01cfb3c2eb7 + path: Analytic Rules/MacroInvokingShellBrowserWindowCOMObjects.yaml + version: 1.0.4 + querySha256: d2032ada6f462b2b6c555bee806cf4ec608e290baffa849197d43e172d53da07 + schedule: + queryFrequency: 1h + queryPeriod: 1h + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - 'Schedule assessment: source frequency=1h, lookback=1h; target frequency=PT1H, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - Account mapping was completed with projected column `DnsDomain` + - Process.CommandLine value is retained as customDetails.ProcessCommandLine from query column `CommandLine`, but its target + output binding requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.ProcessCommandLine column `CommandLine` requires runtime output-schema binding verification + - Host.FullName value is retained as customDetails.HostFullName from query column `Computer`, but its target output binding + requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.HostFullName column `Computer` requires runtime output-schema binding verification + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: [] + errors: [] + originalTactics: + - LateralMovement + originalTechniques: + - T1021.003 + reviewScope: + sourceDocumentSha256: 51f7073d47aa79bc70b40ffdb03abe576d4458582aa6e9f87bcbd859589aa2c5 + targetQuerySha256: e199e737c5ba8bd76790a6f9b936e74cfa5c8d03ce1c116c3f9e97c8484534d4 + reviewDecisions: + - reason: 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented + by hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + decision: accepted + sourceDocumentSha256: 51f7073d47aa79bc70b40ffdb03abe576d4458582aa6e9f87bcbd859589aa2c5 + targetQuerySha256: e199e737c5ba8bd76790a6f9b936e74cfa5c8d03ce1c116c3f9e97c8484534d4 + supplementalEntityDetails: + - entityType: Process + entityIndex: 1 + identifier: CommandLine + sourceColumn: CommandLine + column: CommandLine + status: runtime-binding-pending + customDetailKey: ProcessCommandLine + - entityType: Host + entityIndex: 2 + identifier: FullName + sourceColumn: Computer + column: Computer + status: runtime-binding-pending + customDetailKey: HostFullName + acceptedReviewReasons: + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' +properties: + id: xdr-e7470b35-0128-4508-bfc9-e01cfb3c2eb7 + displayName: Detecting Macro Invoking ShellBrowserWindow COM Objects + status: disabled + queryCondition: + queryText: |- + Event + | where EventLog =~ "Microsoft-Windows-Sysmon/Operational" and EventID==1 + | parse EventData with * 'Image">' Image "<" * 'CommandLine">' CommandLine "<" * 'ParentImage">' ParentImage "<" * + | where ParentImage has "svchost.exe" and Image has "rundll32.exe" and CommandLine has "{c08afd90-f2a1-11d1-8455-00a0c91f3880}" + | parse EventData with * 'ProcessGuid">' ProcessGuid "<" * 'Description">' Description "<" * 'CurrentDirectory">' CurrentDirectory "<" * 'User">' User "<" * 'LogonGuid">' LogonGuid "<" * 'ParentProcessGuid">' ParentProcessGuid "<" * 'ParentImage">' ParentImage "<" * 'ParentCommandLine">' ParentCommandLine "<" * 'ParentUser">' ParentUser "<" * + | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by EventID, Computer, User, ParentImage, ParentProcessGuid, ParentCommandLine, ParentUser, Image, ProcessGuid, CommandLine, Description + | extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'') + schedule: + frequency: PT1H + detectionAction: + alertTemplate: + title: Detecting Macro Invoking ShellBrowserWindow COM Objects + description: '''This query detects a macro invoking ShellBrowserWindow COM Objects evade naive parent/child Office detection + rules.''' + severity: medium + entityMappings: + hosts: + - id: host1 + nameColumn: HostName + dnsDomainColumn: DnsDomain + accounts: + - id: account1 + nameColumn: User + dnsDomainColumn: DnsDomain + tactics: + - tactic: LateralMovement + techniques: + - technique: T1021 + subTechniques: + - T1021.003 + customDetails: + ProcessCommandLine: CommandLine + HostFullName: Computer diff --git a/Solutions/Endpoint Threat Protection Essentials/XDR Detections/PotentialRemoteDesktopTunneling.yaml b/Solutions/Endpoint Threat Protection Essentials/XDR Detections/PotentialRemoteDesktopTunneling.yaml new file mode 100644 index 00000000000..f4d490ca40d --- /dev/null +++ b/Solutions/Endpoint Threat Protection Essentials/XDR Detections/PotentialRemoteDesktopTunneling.yaml @@ -0,0 +1,107 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: SecurityEvents + dataTypes: + - SecurityEvent +- connectorId: WindowsSecurityEvents + dataTypes: + - SecurityEvent +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: d2e8fd50-8d66-11ec-b909-0242ac120002 + path: Analytic Rules/PotentialRemoteDesktopTunneling.yaml + version: 1.0.4 + querySha256: 10ad6b35880a79f841264ced48e18eae1b8c19ccdff67d90a7f53c5eee514ca5 + schedule: + queryFrequency: 1h + queryPeriod: 1h + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - 'Schedule assessment: source frequency=1h, lookback=1h; target frequency=PT1H, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: + - Host.FullName mismatch is informational because its original value is preserved as customDetails.HostFullName from query + column `Computer`; supplemental details do not restore entity identity, correlation, or alert parity + errors: [] + originalTactics: + - CommandAndControl + originalTechniques: + - T1572 + reviewScope: + sourceDocumentSha256: f547ca61da1023eb933b5d273b65e604e05f9212014feafe4820c19e4c999c9d + targetQuerySha256: ea130e4b7690472aa952388e1a60643347d699e17ad82107dec371189a23359f + reviewDecisions: + - reason: 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented + by hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + decision: accepted + sourceDocumentSha256: f547ca61da1023eb933b5d273b65e604e05f9212014feafe4820c19e4c999c9d + targetQuerySha256: ea130e4b7690472aa952388e1a60643347d699e17ad82107dec371189a23359f + supplementalEntityDetails: + - entityType: Host + entityIndex: 2 + identifier: FullName + sourceColumn: Computer + column: Computer + status: available + customDetailKey: HostFullName + acceptedReviewReasons: + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' +properties: + id: xdr-d2e8fd50-8d66-11ec-b909-0242ac120002 + displayName: Potential Remote Desktop Tunneling + status: disabled + queryCondition: + queryText: |- + SecurityEvent + | where EventID in (4624,4625) and LogonType in (10) and IpAddress in ("::1","127.0.0.1") + | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by EventID, Computer, TargetUserName, TargetLogonId, LogonType, IpAddress + | extend Name=tostring(split(TargetUserName, "@")[0]), UPNSuffix=tostring(split(TargetUserName, "@")[1]) + | extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'') + schedule: + frequency: PT1H + detectionAction: + alertTemplate: + title: Potential Remote Desktop Tunneling + description: |- + 'This query detects remote desktop authentication attempts with a localhost source address, which can indicate a tunneled login. + Ref: https://www.mandiant.com/resources/bypassing-network-restrictions-through-rdp-tunneling' + severity: medium + entityMappings: + accounts: + - id: account1 + nameColumn: Name + upnSuffixColumn: UPNSuffix + hosts: + - id: host1 + nameColumn: HostName + dnsDomainColumn: DnsDomain + ips: + - id: ip1 + addressColumn: IpAddress + tactics: + - tactic: CommandAndControl + techniques: + - technique: T1572 + customDetails: + HostFullName: Computer diff --git a/Solutions/Endpoint Threat Protection Essentials/XDR Detections/RegistryPersistenceViaAppCertDLLModification.yaml b/Solutions/Endpoint Threat Protection Essentials/XDR Detections/RegistryPersistenceViaAppCertDLLModification.yaml new file mode 100644 index 00000000000..1a09180cdd7 --- /dev/null +++ b/Solutions/Endpoint Threat Protection Essentials/XDR Detections/RegistryPersistenceViaAppCertDLLModification.yaml @@ -0,0 +1,117 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: SecurityEvents + dataTypes: + - SecurityEvent +- connectorId: WindowsSecurityEvents + dataTypes: + - SecurityEvent +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: c61ad0ac-ad68-4ebb-b41a-74296d3e0044 + path: Analytic Rules/RegistryPersistenceViaAppCertDLLModification.yaml + version: 1.0.3 + querySha256: f573dd39fa955c5882e2c2958b46170bae4e40a9abf83b5535c0ceced44c7ab4 + schedule: + queryFrequency: 1h + queryPeriod: 1h + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - 'Schedule assessment: source frequency=1h, lookback=1h; target frequency=PT1H, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - RegistryKey.Key value is retained as customDetails.RegistryKeyKey from query column `TargetObject`, but its target output + binding requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.RegistryKeyKey column `TargetObject` requires runtime output-schema binding verification + - Host.FullName value is retained as customDetails.HostFullName from query column `Computer`, but its target output binding + requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.HostFullName column `Computer` requires runtime output-schema binding verification + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: [] + errors: [] + originalTactics: + - Persistence + originalTechniques: + - T1546.009 + reviewScope: + sourceDocumentSha256: 223302baded61b819f0a09477d75aebae160016f461589741286bb6a5cb90083 + targetQuerySha256: af3f0a2ee13bb8fdb2dedfc9aa0e405337a7089e4e443fd2ba54a4b7dc7519ab + reviewDecisions: + - reason: 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented + by hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + decision: accepted + sourceDocumentSha256: 223302baded61b819f0a09477d75aebae160016f461589741286bb6a5cb90083 + targetQuerySha256: af3f0a2ee13bb8fdb2dedfc9aa0e405337a7089e4e443fd2ba54a4b7dc7519ab + supplementalEntityDetails: + - entityType: RegistryKey + entityIndex: 1 + identifier: Key + sourceColumn: TargetObject + column: TargetObject + status: runtime-binding-pending + customDetailKey: RegistryKeyKey + - entityType: Host + entityIndex: 2 + identifier: FullName + sourceColumn: Computer + column: Computer + status: runtime-binding-pending + customDetailKey: HostFullName + acceptedReviewReasons: + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' +properties: + id: xdr-c61ad0ac-ad68-4ebb-b41a-74296d3e0044 + displayName: Registry Persistence via AppCert DLL Modification + status: disabled + queryCondition: + queryText: |- + Event + | where EventLog =~ "Microsoft-Windows-Sysmon/Operational" and EventID in (13) + | parse EventData with * 'TargetObject">' TargetObject "<" * 'Details">' Details "<" * + | where TargetObject has ("\\Control\\Session Manager\\AppCertDLLs\\") + | summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated) by EventID, Computer, TargetObject, Details + | extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'') + schedule: + frequency: PT1H + detectionAction: + alertTemplate: + title: Registry Persistence via AppCert DLL Modification + description: "'Adversaries may establish persistence and/or elevate privileges by executing malicious content triggered\ + \ by AppCert DLLs loaded into processes. \nDynamic-link libraries (DLLs) that are specified in the AppCertDLLs Registry\ + \ key under HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\ are loaded into every process\ + \ that calls the ubiquitously used application programming interface (API) functions CreateProcess, CreateProcessAsUser,\ + \ CreateProcessWithLoginW, CreateProcessWithTokenW, or WinExec.\nRef: https://attack.mitre.org/techniques/T1546/009/'" + severity: medium + entityMappings: + hosts: + - id: host1 + nameColumn: HostName + dnsDomainColumn: DnsDomain + tactics: + - tactic: Persistence + techniques: + - technique: T1546 + subTechniques: + - T1546.009 + customDetails: + RegistryKeyKey: TargetObject + HostFullName: Computer diff --git a/Solutions/Endpoint Threat Protection Essentials/XDR Detections/RegistryPersistenceViaAppInt_DLLsModification.yaml b/Solutions/Endpoint Threat Protection Essentials/XDR Detections/RegistryPersistenceViaAppInt_DLLsModification.yaml new file mode 100644 index 00000000000..ff4d9cb13ea --- /dev/null +++ b/Solutions/Endpoint Threat Protection Essentials/XDR Detections/RegistryPersistenceViaAppInt_DLLsModification.yaml @@ -0,0 +1,118 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: SecurityEvents + dataTypes: + - SecurityEvent +- connectorId: WindowsSecurityEvents + dataTypes: + - SecurityEvent +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: 9367dff0-941d-44e2-8875-cb48570c7add + path: Analytic Rules/RegistryPersistenceViaAppInt_DLLsModification.yaml + version: 1.0.3 + querySha256: f01dbb6839f999a51d0cb48ca58dee3f4d63c83498ab8d3ec81cd5ab0ad06e20 + schedule: + queryFrequency: 1h + queryPeriod: 1h + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - 'Schedule assessment: source frequency=1h, lookback=1h; target frequency=PT1H, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - RegistryKey.Key value is retained as customDetails.RegistryKeyKey from query column `TargetObject`, but its target output + binding requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.RegistryKeyKey column `TargetObject` requires runtime output-schema binding verification + - Host.FullName value is retained as customDetails.HostFullName from query column `Computer`, but its target output binding + requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.HostFullName column `Computer` requires runtime output-schema binding verification + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: [] + errors: [] + originalTactics: + - Persistence + originalTechniques: + - T1546.010 + reviewScope: + sourceDocumentSha256: 607545768ad26fb2466eb905ed75cbd7a9b04b63b05dc2a2fe61f4a573da8156 + targetQuerySha256: 7a19f1259798ab059f6d56ce50ef77f801dc3014cc2a95718ac1ccab43acf091 + reviewDecisions: + - reason: 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented + by hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + decision: accepted + sourceDocumentSha256: 607545768ad26fb2466eb905ed75cbd7a9b04b63b05dc2a2fe61f4a573da8156 + targetQuerySha256: 7a19f1259798ab059f6d56ce50ef77f801dc3014cc2a95718ac1ccab43acf091 + supplementalEntityDetails: + - entityType: RegistryKey + entityIndex: 1 + identifier: Key + sourceColumn: TargetObject + column: TargetObject + status: runtime-binding-pending + customDetailKey: RegistryKeyKey + - entityType: Host + entityIndex: 2 + identifier: FullName + sourceColumn: Computer + column: Computer + status: runtime-binding-pending + customDetailKey: HostFullName + acceptedReviewReasons: + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' +properties: + id: xdr-9367dff0-941d-44e2-8875-cb48570c7add + displayName: Registry Persistence via AppInit DLLs Modification + status: disabled + queryCondition: + queryText: |- + Event + | where EventLog =~ "Microsoft-Windows-Sysmon/Operational" and EventID in (13) + | parse EventData with * 'TargetObject">' TargetObject "<" * 'Details">' Details "<" * + | where TargetObject has "\\Windows NT\\CurrentVersion\\Windows\\AppInit_DLLs" + | summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated) by EventID, Computer, TargetObject, Details + | extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'') + schedule: + frequency: PT1H + detectionAction: + alertTemplate: + title: Registry Persistence via AppInit DLLs Modification + description: "'Adversaries may establish persistence and/or elevate privileges by executing malicious content triggered\ + \ by AppInit DLLs loaded into processes. \nDynamic-link libraries (DLLs) that are specified in the AppInit_DLLs value\ + \ in the Registry keys HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows or HKEY_LOCAL_MACHINE\\\ + Software\\Wow6432Node\\Microsoft\\Windows NT\\CurrentVersion\\Windows are loaded by user32.dll into every process\ + \ that loads user32.dll. In practice this is nearly every program, since user32.dll is a very common library.\nRef:\ + \ https://attack.mitre.org/techniques/T1546/" + severity: medium + entityMappings: + hosts: + - id: host1 + nameColumn: HostName + dnsDomainColumn: DnsDomain + tactics: + - tactic: Persistence + techniques: + - technique: T1546 + subTechniques: + - T1546.010 + customDetails: + RegistryKeyKey: TargetObject + HostFullName: Computer diff --git a/Solutions/Endpoint Threat Protection Essentials/XDR Detections/SecurityEventLogCleared.yaml b/Solutions/Endpoint Threat Protection Essentials/XDR Detections/SecurityEventLogCleared.yaml new file mode 100644 index 00000000000..9e82af3189a --- /dev/null +++ b/Solutions/Endpoint Threat Protection Essentials/XDR Detections/SecurityEventLogCleared.yaml @@ -0,0 +1,125 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: SecurityEvents + dataTypes: + - SecurityEvent +- connectorId: WindowsSecurityEvents + dataTypes: + - SecurityEvent +- connectorId: WindowsForwardedEvents + dataTypes: + - WindowsEvent +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: 80da0a8f-cfe1-4cd0-a895-8bc1771a720e + path: Analytic Rules/SecurityEventLogCleared.yaml + version: 1.1.5 + querySha256: a065228957b93a418ba8c93be4f2c1dab5e7909e50bd3e2d206c6c4e12eb1435 + schedule: + queryFrequency: 1d + queryPeriod: 1d + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - isfuzzy unions can still fail semantic binding in Advanced Hunting + - 'Schedule assessment: source frequency=1d, lookback=1d; target frequency=P1D, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - Host.FullName value is retained as customDetails.HostFullName from query column `Computer`, but its target output binding + requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.HostFullName column `Computer` requires runtime output-schema binding verification + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: [] + errors: [] + originalTactics: + - DefenseEvasion + originalTechniques: + - T1070 + reviewScope: + sourceDocumentSha256: 04f8109f07a289752210c71afed8d24077281ca3f47acff8e1b8545c85b712ef + targetQuerySha256: 8f707b8609f79b1d11f1f231d8f2870822182965fe17da3666f967fdbbee3bcc + reviewDecisions: + - reason: isfuzzy unions can still fail semantic binding in Advanced Hunting + decision: accepted + sourceDocumentSha256: 04f8109f07a289752210c71afed8d24077281ca3f47acff8e1b8545c85b712ef + targetQuerySha256: 8f707b8609f79b1d11f1f231d8f2870822182965fe17da3666f967fdbbee3bcc + - reason: 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented + by hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + decision: accepted + sourceDocumentSha256: 04f8109f07a289752210c71afed8d24077281ca3f47acff8e1b8545c85b712ef + targetQuerySha256: 8f707b8609f79b1d11f1f231d8f2870822182965fe17da3666f967fdbbee3bcc + supplementalEntityDetails: + - entityType: Host + entityIndex: 2 + identifier: FullName + sourceColumn: Computer + column: Computer + status: runtime-binding-pending + customDetailKey: HostFullName + acceptedReviewReasons: + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - isfuzzy unions can still fail semantic binding in Advanced Hunting +properties: + id: xdr-80da0a8f-cfe1-4cd0-a895-8bc1771a720e + displayName: Security Event log cleared + status: disabled + queryCondition: + queryText: |- + (union isfuzzy=true + ( + SecurityEvent + | where EventID == 1102 and EventSourceName =~ "Microsoft-Windows-Eventlog" + | summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), EventCount = count() by Computer, Account, EventID, Activity + ), + ( + WindowsEvent + | where EventID == 1102 and Provider =~ "Microsoft-Windows-Eventlog" + | extend Account = strcat(tostring(EventData.SubjectDomainName),"\\", tostring(EventData.SubjectUserName)) + | extend Activity= "1102 - The audit log was cleared." + | summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), EventCount = count() by Computer, Account, EventID, Activity + ) + ) + | extend Name=tostring(split(Account, "@")[0]), UPNSuffix=tostring(split(Account, "@")[1]) + | extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'') + schedule: + frequency: P1D + detectionAction: + alertTemplate: + title: Security Event log cleared + description: |- + 'Checks for event id 1102 which indicates the security event log was cleared. + It uses Event Source Name "Microsoft-Windows-Eventlog" to avoid generating false positives from other sources, like AD FS servers for instance.' + severity: medium + entityMappings: + accounts: + - id: account1 + nameColumn: Name + upnSuffixColumn: UPNSuffix + hosts: + - id: host1 + nameColumn: HostName + dnsDomainColumn: DnsDomain + tactics: + - tactic: DefenseEvasion + techniques: + - technique: T1070 + customDetails: + HostFullName: Computer diff --git a/Solutions/Endpoint Threat Protection Essentials/XDR Detections/SuspiciousPowerShellCommandExecuted.yaml b/Solutions/Endpoint Threat Protection Essentials/XDR Detections/SuspiciousPowerShellCommandExecuted.yaml new file mode 100644 index 00000000000..2f30d622568 --- /dev/null +++ b/Solutions/Endpoint Threat Protection Essentials/XDR Detections/SuspiciousPowerShellCommandExecuted.yaml @@ -0,0 +1,154 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: MicrosoftThreatProtection + dataTypes: + - DeviceEvents +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: b5153fb3-ada9-4ce4-9131-79c771efb50d + path: Analytic Rules/SuspiciousPowerShellCommandExecuted.yaml + version: 1.0.1 + querySha256: 69109f9eaea460120b41e2f961c2abf7b5af4f13d34b4f341b9a197e68585d0c + schedule: + queryFrequency: 1h + queryPeriod: 1h + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - catalog column mappings were not applied because table/alias scope is ambiguous + - 'Schedule assessment: source frequency=1h, lookback=1h; target frequency=PT1H, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - 'Best-effort entity mapping requires review: source Host.FullName column `DeviceName` is provisionally represented by + hosts.nameColumn `DvcHostname`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + - Host.FullName value is retained as customDetails.HostFullName from query column `DeviceName`, but its target output + binding requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.HostFullName column `DeviceName` requires runtime output-schema binding verification + - Process.ProcessId value is retained as customDetails.ProcessProcessId from query column `InitiatingProcessId`, but its + target output binding requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.ProcessProcessId column `InitiatingProcessId` requires runtime output-schema binding verification + - Process.CommandLine value is retained as customDetails.ProcessCommandLine from query column `InitiatingProcessCommandLine`, + but its target output binding requires runtime-schema verification; custom details do not restore entity identity or + correlation + - Supplemental customDetails.ProcessCommandLine column `InitiatingProcessCommandLine` requires runtime output-schema binding + verification + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: [] + errors: [] + originalTactics: + - Execution + originalTechniques: + - T1059 + reviewScope: + sourceDocumentSha256: 2302f8b65d306898fdbe21bac11a19a1b1ddcc4de4d5c1c025fbbe99ab61c035 + targetQuerySha256: 7472ac454cb9e5ca6f42ead73fe209e710472d665f4a2dc7577875d6f9bc0366 + reviewDecisions: + - reason: catalog column mappings were not applied because table/alias scope is ambiguous + decision: accepted + sourceDocumentSha256: 2302f8b65d306898fdbe21bac11a19a1b1ddcc4de4d5c1c025fbbe99ab61c035 + targetQuerySha256: 7472ac454cb9e5ca6f42ead73fe209e710472d665f4a2dc7577875d6f9bc0366 + - reason: Original Sentinel lookback is shorter than the native XDR service window, but source and target table inputs + cannot be proven equivalent + decision: accepted + sourceDocumentSha256: 2302f8b65d306898fdbe21bac11a19a1b1ddcc4de4d5c1c025fbbe99ab61c035 + targetQuerySha256: 7472ac454cb9e5ca6f42ead73fe209e710472d665f4a2dc7577875d6f9bc0366 + - reason: 'Best-effort entity mapping requires review: source Host.FullName column `DeviceName` is provisionally represented + by hosts.nameColumn `DvcHostname`; confirm that this column is the intended host identifier. The original value is + also retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + decision: accepted + sourceDocumentSha256: 2302f8b65d306898fdbe21bac11a19a1b1ddcc4de4d5c1c025fbbe99ab61c035 + targetQuerySha256: 7472ac454cb9e5ca6f42ead73fe209e710472d665f4a2dc7577875d6f9bc0366 + supplementalEntityDetails: + - entityType: Host + entityIndex: 1 + identifier: FullName + sourceColumn: DeviceName + column: DeviceName + status: runtime-binding-pending + customDetailKey: HostFullName + - entityType: Process + entityIndex: 4 + identifier: ProcessId + sourceColumn: InitiatingProcessId + column: InitiatingProcessId + status: runtime-binding-pending + customDetailKey: ProcessProcessId + - entityType: Process + entityIndex: 4 + identifier: CommandLine + sourceColumn: InitiatingProcessCommandLine + column: InitiatingProcessCommandLine + status: runtime-binding-pending + customDetailKey: ProcessCommandLine + acceptedReviewReasons: + - 'Best-effort entity mapping requires review: source Host.FullName column `DeviceName` is provisionally represented by + hosts.nameColumn `DvcHostname`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + - Original Sentinel lookback is shorter than the native XDR service window, but source and target table inputs cannot + be proven equivalent + - catalog column mappings were not applied because table/alias scope is ambiguous +properties: + id: xdr-b5153fb3-ada9-4ce4-9131-79c771efb50d + displayName: Suspicious Powershell Commandlet Executed + status: disabled + queryCondition: + queryText: |- + // Adjust the list of suspicious commandlets as needed + let SuspiciousPowerShellCommandList = dynamic(["Get-ADUserResultantPasswordPolicy", + "Get-DomainPolicy", + "Get-DomainUser", + "Get-DomainComputer", + "Get-DomainController", + "Get-DomainGroup", + "Get-DomainTrust", + "Get-ADTrust", + "Get-ForestTrust" + ]); + DeviceEvents + | where ActionType == "PowerShellCommand" + | extend Commandlet = tostring(parse_json(AdditionalFields).Command) + | where Commandlet has_any (SuspiciousPowerShellCommandList) + | project TimeGenerated, DeviceName, LocalIP, InitiatingProcessAccountUpn, InitiatingProcessId, InitiatingProcessFileName, InitiatingProcessFolderPath, InitiatingProcessCommandLine + | extend Username = tostring(split(InitiatingProcessAccountUpn, '@')[0]), UPNSuffix = tostring(split(InitiatingProcessAccountUpn, '@')[1]) + | extend DvcHostname = tostring(split(DeviceName, '.')[0]), DvcDomain = tostring(strcat_array(array_slice(split(DeviceName, '.'), 1, -1), '.')) + schedule: + frequency: PT1H + detectionAction: + alertTemplate: + title: Suspicious Powershell Commandlet Executed + description: This analytic rule detects when a suspicious PowerShell commandlet is executed on a host. Threat actors + often use PowerShell to execute commands and scripts to move laterally, escalate privileges, and exfiltrate data. + severity: medium + entityMappings: + hosts: + - id: host1 + nameColumn: DvcHostname + dnsDomainColumn: DvcDomain + ips: + - id: ip1 + addressColumn: LocalIP + accounts: + - id: account1 + nameColumn: Username + upnSuffixColumn: UPNSuffix + tactics: + - tactic: Execution + techniques: + - technique: T1059 + customDetails: + HostFullName: DeviceName + ProcessProcessId: InitiatingProcessId + ProcessCommandLine: InitiatingProcessCommandLine diff --git a/Solutions/Endpoint Threat Protection Essentials/XDR Detections/WDigestDowngradeAttack.yaml b/Solutions/Endpoint Threat Protection Essentials/XDR Detections/WDigestDowngradeAttack.yaml new file mode 100644 index 00000000000..5705f7be8a0 --- /dev/null +++ b/Solutions/Endpoint Threat Protection Essentials/XDR Detections/WDigestDowngradeAttack.yaml @@ -0,0 +1,113 @@ +schemaVersion: 1.0.0 +version: 3.1.2 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: SecurityEvents + dataTypes: + - SecurityEvent +- connectorId: WindowsSecurityEvents + dataTypes: + - SecurityEvent +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: f6502545-ae3a-4232-a8b0-79d87e5c98d7 + path: Analytic Rules/WDigestDowngradeAttack.yaml + version: 3.1.2 + querySha256: fa4bce6bcdb1c3184b3619365759d926c5ab29f70adaa501ebd91dda7d0aa6d9 + schedule: + queryFrequency: 1h + queryPeriod: 1h + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - 'Schedule assessment: source frequency=1h, lookback=1h; target frequency=PT1H, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - RegistryKey.Key value is retained as customDetails.RegistryKeyKey from query column `TargetObject`, but its target output + binding requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.RegistryKeyKey column `TargetObject` requires runtime output-schema binding verification + - Host.FullName value is retained as customDetails.HostFullName from query column `Computer`, but its target output binding + requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.HostFullName column `Computer` requires runtime output-schema binding verification + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: [] + errors: [] + originalTactics: + - CredentialAccess + originalTechniques: + - T1003 + reviewScope: + sourceDocumentSha256: 329f719c1896284a71fb31d4e85c1f1d99340dd137f969e8445eb6f843e3d332 + targetQuerySha256: 97d8fa2b5b8d495abe33ae0854276700bba9a4067bedc6d3283eb5d0ca37fb0d + reviewDecisions: + - reason: 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented + by hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + decision: accepted + sourceDocumentSha256: 329f719c1896284a71fb31d4e85c1f1d99340dd137f969e8445eb6f843e3d332 + targetQuerySha256: 97d8fa2b5b8d495abe33ae0854276700bba9a4067bedc6d3283eb5d0ca37fb0d + supplementalEntityDetails: + - entityType: RegistryKey + entityIndex: 1 + identifier: Key + sourceColumn: TargetObject + column: TargetObject + status: runtime-binding-pending + customDetailKey: RegistryKeyKey + - entityType: Host + entityIndex: 2 + identifier: FullName + sourceColumn: Computer + column: Computer + status: runtime-binding-pending + customDetailKey: HostFullName + acceptedReviewReasons: + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' +properties: + id: xdr-f6502545-ae3a-4232-a8b0-79d87e5c98d7 + displayName: WDigest downgrade attack + status: disabled + queryCondition: + queryText: |- + Event + | where EventLog =~ "Microsoft-Windows-Sysmon/Operational" and EventID in (13) + | parse EventData with * 'TargetObject">' TargetObject "<" * 'Details">' Details "<" * + | where TargetObject=~"HKLM\\System\\CurrentControlSet\\Control\\SecurityProviders\\WDigest\\UseLogonCredential" and Details !="DWORD (0x00000000)" + | summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated) by EventID, Computer, TargetObject, Details + | extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'') + schedule: + frequency: PT1H + detectionAction: + alertTemplate: + title: WDigest downgrade attack + description: |- + 'When the WDigest Authentication protocol is enabled, plain text passwords are stored in the Local Security Authority Subsystem Service (LSASS) exposing them to theft. This setting will prevent WDigest from storing credentials in memory. + Ref: https://www.microsoft.com/en-us/security/blog/2022/07/27/untangling-knotweed-european-private-sector-offensive-actor-using-0-day-exploits/' + severity: medium + entityMappings: + hosts: + - id: host1 + nameColumn: HostName + dnsDomainColumn: DnsDomain + tactics: + - tactic: CredentialAccess + techniques: + - technique: T1003 + customDetails: + RegistryKeyKey: TargetObject + HostFullName: Computer diff --git a/Solutions/Endpoint Threat Protection Essentials/XDR Detections/WindowsBinariesExecutedfromNon-DefaultDirectory.yaml b/Solutions/Endpoint Threat Protection Essentials/XDR Detections/WindowsBinariesExecutedfromNon-DefaultDirectory.yaml new file mode 100644 index 00000000000..3dceb44e29b --- /dev/null +++ b/Solutions/Endpoint Threat Protection Essentials/XDR Detections/WindowsBinariesExecutedfromNon-DefaultDirectory.yaml @@ -0,0 +1,122 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: SecurityEvents + dataTypes: + - SecurityEvent +- connectorId: WindowsSecurityEvents + dataTypes: + - SecurityEvent +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: 15049017-527f-4d3b-b011-b0e99e68ef45 + path: Analytic Rules/WindowsBinariesExecutedfromNon-DefaultDirectory.yaml + version: 1.0.4 + querySha256: fda4bf8db4520dfa60a3e61d96130c1e9c5e28f2a4b592ca6f7112a03b3d105b + schedule: + queryFrequency: 1h + queryPeriod: 1h + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - externaldata availability must be verified by runtime validation + - 'Schedule assessment: source frequency=1h, lookback=1h; target frequency=PT1H, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - Host.FullName value is retained as customDetails.HostFullName from query column `Computer`, but its target output binding + requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.HostFullName column `Computer` requires runtime output-schema binding verification + - Process.CommandLine value is retained as customDetails.ProcessCommandLine from query column `CommandLine`, but its target + output binding requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.ProcessCommandLine column `CommandLine` requires runtime output-schema binding verification + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: [] + errors: [] + originalTactics: + - Execution + originalTechniques: + - T1059 + reviewScope: + sourceDocumentSha256: 32cf49a35a7b747e229fb1509afc09283b037c8db058dd86ec0d1aeb26152051 + targetQuerySha256: 6c8530f0f1b2c507916e7dbe6cdec8b85248d05c2ab15e8c6bafc3ced5580f8a + reviewDecisions: + - reason: externaldata availability must be verified by runtime validation + decision: accepted + sourceDocumentSha256: 32cf49a35a7b747e229fb1509afc09283b037c8db058dd86ec0d1aeb26152051 + targetQuerySha256: 6c8530f0f1b2c507916e7dbe6cdec8b85248d05c2ab15e8c6bafc3ced5580f8a + - reason: 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented + by hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + decision: accepted + sourceDocumentSha256: 32cf49a35a7b747e229fb1509afc09283b037c8db058dd86ec0d1aeb26152051 + targetQuerySha256: 6c8530f0f1b2c507916e7dbe6cdec8b85248d05c2ab15e8c6bafc3ced5580f8a + supplementalEntityDetails: + - entityType: Host + entityIndex: 2 + identifier: FullName + sourceColumn: Computer + column: Computer + status: runtime-binding-pending + customDetailKey: HostFullName + - entityType: Process + entityIndex: 3 + identifier: CommandLine + sourceColumn: CommandLine + column: CommandLine + status: runtime-binding-pending + customDetailKey: ProcessCommandLine + acceptedReviewReasons: + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - externaldata availability must be verified by runtime validation +properties: + id: xdr-15049017-527f-4d3b-b011-b0e99e68ef45 + displayName: Windows Binaries Executed from Non-Default Directory + status: disabled + queryCondition: + queryText: |- + let procList = externaldata(Process:string) [@"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Microsoft_Lolbas_Execution_Binaries.csv"] with (format="csv", ignoreFirstRecord=True); + SecurityEvent + | where EventID == 4688 and Process has_any (procList) and not (NewProcessName has ("C:\\Windows\\")) + | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by EventID, Computer, SubjectUserName, NewProcessName, Process, CommandLine + | extend Name=tostring(split(SubjectUserName, "@")[0]), UPNSuffix=tostring(split(SubjectUserName, "@")[1]) + | extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'') + schedule: + frequency: PT1H + detectionAction: + alertTemplate: + title: Windows Binaries Executed from Non-Default Directory + description: "'The query detects Windows binaries, that can be executed from a non-default directory (e.g. C:\\Windows\\\ + , C:\\Windows\\System32 etc.). \nRef: https://lolbas-project.github.io/'" + severity: medium + entityMappings: + accounts: + - id: account1 + nameColumn: Name + upnSuffixColumn: UPNSuffix + hosts: + - id: host1 + nameColumn: HostName + dnsDomainColumn: DnsDomain + tactics: + - tactic: Execution + techniques: + - technique: T1059 + customDetails: + HostFullName: Computer + ProcessCommandLine: CommandLine diff --git a/Solutions/Endpoint Threat Protection Essentials/XDR Detections/WindowsBinariesLolbinsRenamed.yaml b/Solutions/Endpoint Threat Protection Essentials/XDR Detections/WindowsBinariesLolbinsRenamed.yaml new file mode 100644 index 00000000000..4e7a7340fcc --- /dev/null +++ b/Solutions/Endpoint Threat Protection Essentials/XDR Detections/WindowsBinariesLolbinsRenamed.yaml @@ -0,0 +1,125 @@ +schemaVersion: 1.0.0 +version: 3.1.2 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: SecurityEvents + dataTypes: + - SecurityEvent +- connectorId: WindowsSecurityEvents + dataTypes: + - SecurityEvent +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: cbf6ad48-fa5c-4bf7-b205-28dbadb91255 + path: Analytic Rules/WindowsBinariesLolbinsRenamed.yaml + version: 3.1.2 + querySha256: 047b42fc2e2a3e30bb561f092079315dcf2c1327cf84a75e422a678db52e9719 + schedule: + queryFrequency: 1h + queryPeriod: 1h + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - externaldata availability must be verified by runtime validation + - 'Schedule assessment: source frequency=1h, lookback=1h; target frequency=PT1H, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - Account mapping was completed with projected column `DnsDomain` + - Process.CommandLine value is retained as customDetails.ProcessCommandLine from query column `CommandLine`, but its target + output binding requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.ProcessCommandLine column `CommandLine` requires runtime output-schema binding verification + - Host.FullName value is retained as customDetails.HostFullName from query column `Computer`, but its target output binding + requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.HostFullName column `Computer` requires runtime output-schema binding verification + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: [] + errors: [] + originalTactics: + - Execution + originalTechniques: + - T1059 + reviewScope: + sourceDocumentSha256: 96b0a8f74e9e24823e4ea4e9e033ad1bf84781f06e57c3f79349ec0bc7f1f200 + targetQuerySha256: 038a5f9575080798d84bf9f6293f30279428dce88eae261e01d8d2081989440e + reviewDecisions: + - reason: externaldata availability must be verified by runtime validation + decision: accepted + sourceDocumentSha256: 96b0a8f74e9e24823e4ea4e9e033ad1bf84781f06e57c3f79349ec0bc7f1f200 + targetQuerySha256: 038a5f9575080798d84bf9f6293f30279428dce88eae261e01d8d2081989440e + - reason: 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented + by hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + decision: accepted + sourceDocumentSha256: 96b0a8f74e9e24823e4ea4e9e033ad1bf84781f06e57c3f79349ec0bc7f1f200 + targetQuerySha256: 038a5f9575080798d84bf9f6293f30279428dce88eae261e01d8d2081989440e + supplementalEntityDetails: + - entityType: Process + entityIndex: 1 + identifier: CommandLine + sourceColumn: CommandLine + column: CommandLine + status: runtime-binding-pending + customDetailKey: ProcessCommandLine + - entityType: Host + entityIndex: 2 + identifier: FullName + sourceColumn: Computer + column: Computer + status: runtime-binding-pending + customDetailKey: HostFullName + acceptedReviewReasons: + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - externaldata availability must be verified by runtime validation +properties: + id: xdr-cbf6ad48-fa5c-4bf7-b205-28dbadb91255 + displayName: Windows Binaries Lolbins Renamed + status: disabled + queryCondition: + queryText: |- + let procList = externaldata(Process:string) [@"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Microsoft_Lolbas_Execution_Binaries.csv"] with (format="csv", ignoreFirstRecord=True); + Event + | where EventLog =~ "Microsoft-Windows-Sysmon/Operational" and EventID==1 + | parse EventData with * 'Image">' Image "<" * 'OriginalFileName">' OriginalFileName "<" * + | where OriginalFileName has_any (procList) and not (Image has_any (procList)) + | parse EventData with * 'ProcessGuid">' ProcessGuid "<" * 'Description">' Description "<" * 'CommandLine">' CommandLine "<" * 'CurrentDirectory">' CurrentDirectory "<" * 'User">' User "<" * 'LogonGuid">' LogonGuid "<" * 'Hashes">' Hashes "<" * 'ParentProcessGuid">' ParentProcessGuid "<" * 'ParentImage">' ParentImage "<" * 'ParentCommandLine">' ParentCommandLine "<" * 'ParentUser">' ParentUser "<" * + | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by EventID, Computer, User, ParentImage, ParentProcessGuid, ParentCommandLine, ParentUser, Image, ProcessGuid, CommandLine, Description, OriginalFileName, CurrentDirectory, Hashes + | extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'') + schedule: + frequency: PT1H + detectionAction: + alertTemplate: + title: Windows Binaries Lolbins Renamed + description: "'This query detects the execution of renamed Windows binaries (Lolbins). This is a common technique used\ + \ by adversaries to evade detection. \nRef: https://cortex-docs.paloaltonetworks.com/analytics-alerts/alerts-by-name/execution-of-renamed-lolbin'" + severity: medium + entityMappings: + hosts: + - id: host1 + nameColumn: HostName + dnsDomainColumn: DnsDomain + accounts: + - id: account1 + nameColumn: User + dnsDomainColumn: DnsDomain + tactics: + - tactic: Execution + techniques: + - technique: T1059 + customDetails: + ProcessCommandLine: CommandLine + HostFullName: Computer diff --git a/Solutions/Endpoint Threat Protection Essentials/XDR Detections/base64_encoded_pefile.yaml b/Solutions/Endpoint Threat Protection Essentials/XDR Detections/base64_encoded_pefile.yaml new file mode 100644 index 00000000000..166d123c7d5 --- /dev/null +++ b/Solutions/Endpoint Threat Protection Essentials/XDR Detections/base64_encoded_pefile.yaml @@ -0,0 +1,140 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: SecurityEvents + dataTypes: + - SecurityEvent +- connectorId: WindowsSecurityEvents + dataTypes: + - SecurityEvent +- connectorId: WindowsForwardedEvents + dataTypes: + - WindowsEvent +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: ca67c83e-7fff-4127-a3e3-1af66d6d4cad + path: Analytic Rules/base64_encoded_pefile.yaml + version: 1.1.5 + querySha256: 3558b09c136f0999cff742f0526e4e4c5cb86145bec1c73e15d089b7e2a95596 + schedule: + queryFrequency: 1d + queryPeriod: 1d + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - isfuzzy unions can still fail semantic binding in Advanced Hunting + - 'Schedule assessment: source frequency=1d, lookback=1d; target frequency=P1D, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - Account mapping was completed with projected column `DnsDomain` + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - Host.FullName value is retained as customDetails.HostFullName from query column `Computer`, but its target output binding + requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.HostFullName column `Computer` requires runtime output-schema binding verification + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: + - All source MITRE tactics are preserved in source order in authored YAML. V3.1 ARM packaging carries only the first tactic + and its compatible techniques; this classification loss is not validated parity. Direct Graph deployment requires a + single tactic. + errors: [] + originalTactics: + - Execution + - DefenseEvasion + originalTechniques: + - T1059 + - T1027 + - T1140 + reviewScope: + sourceDocumentSha256: 8e4c6207c4d6fe232f3f3e5db4227a16933797982594b98bb38060f1c280c82b + targetQuerySha256: 52cc90884a768e381a7a4d2afad7833b53b6b52e62e07f1d8f9120217552c1a5 + reviewDecisions: + - reason: isfuzzy unions can still fail semantic binding in Advanced Hunting + decision: accepted + sourceDocumentSha256: 8e4c6207c4d6fe232f3f3e5db4227a16933797982594b98bb38060f1c280c82b + targetQuerySha256: 52cc90884a768e381a7a4d2afad7833b53b6b52e62e07f1d8f9120217552c1a5 + - reason: 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented + by hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + decision: accepted + sourceDocumentSha256: 8e4c6207c4d6fe232f3f3e5db4227a16933797982594b98bb38060f1c280c82b + targetQuerySha256: 52cc90884a768e381a7a4d2afad7833b53b6b52e62e07f1d8f9120217552c1a5 + supplementalEntityDetails: + - entityType: Host + entityIndex: 2 + identifier: FullName + sourceColumn: Computer + column: Computer + status: runtime-binding-pending + customDetailKey: HostFullName + acceptedReviewReasons: + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - isfuzzy unions can still fail semantic binding in Advanced Hunting +properties: + id: xdr-ca67c83e-7fff-4127-a3e3-1af66d6d4cad + displayName: Base64 encoded Windows process command-lines + status: disabled + queryCondition: + queryText: |- + let ProcessCreationEvents=(union isfuzzy=true + (SecurityEvent + | where EventID==4688 + | where isnotempty(CommandLine) + | summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), count() by Computer, Account = SubjectUserName, AccountDomain = SubjectDomainName, + FileName = Process, CommandLine, ParentProcessName + ), + (WindowsEvent + | where EventID==4688 + | where EventData has "TVqQAAMAAAAEAAA" + | extend CommandLine = tostring(EventData.CommandLine) + | where isnotempty(CommandLine) + | extend ParentProcessName = tostring(EventData.ParentProcessName) + | extend NewProcessName = tostring(EventData.NewProcessName) + | extend Process=tostring(split(NewProcessName, '\\')[-1]) + | extend SubjectUserName = tostring(EventData.SubjectUserName) + | extend SubjectDomainName = tostring(EventData.SubjectDomainName) + | summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), count() by Computer, Account = SubjectUserName, AccountDomain = SubjectDomainName, + FileName = Process, CommandLine, ParentProcessName)); + ProcessCreationEvents + | where CommandLine contains "TVqQAAMAAAAEAAA" + | extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'') + schedule: + frequency: P1D + detectionAction: + alertTemplate: + title: Base64 encoded Windows process command-lines + description: '''Identifies instances of a base64-encoded PE file header seen in the process command line parameter.''' + severity: medium + entityMappings: + accounts: + - id: account1 + nameColumn: Account + dnsDomainColumn: DnsDomain + hosts: + - id: host1 + nameColumn: HostName + dnsDomainColumn: DnsDomain + tactics: + - tactic: Execution + techniques: + - technique: T1059 + - tactic: DefenseEvasion + techniques: + - technique: T1027 + - technique: T1140 + customDetails: + HostFullName: Computer diff --git a/Solutions/Endpoint Threat Protection Essentials/XDR Detections/execute_base64_decodedpayload.yaml b/Solutions/Endpoint Threat Protection Essentials/XDR Detections/execute_base64_decodedpayload.yaml new file mode 100644 index 00000000000..b5a66f61fb8 --- /dev/null +++ b/Solutions/Endpoint Threat Protection Essentials/XDR Detections/execute_base64_decodedpayload.yaml @@ -0,0 +1,144 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: SecurityEvents + dataTypes: + - SecurityEvent +- connectorId: WindowsSecurityEvents + dataTypes: + - SecurityEvent +- connectorId: WindowsForwardedEvents + dataTypes: + - WindowsEvent +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: d6190dde-8fd2-456a-ac5b-0a32400b0464 + path: Analytic Rules/execute_base64_decodedpayload.yaml + version: 1.1.4 + querySha256: b6a99955528144a5970a8904c92e7569ff9b5c6adcf066b6c858496c5838f7d9 + schedule: + queryFrequency: 1d + queryPeriod: 1d + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - isfuzzy unions can still fail semantic binding in Advanced Hunting + - 'Schedule assessment: source frequency=1d, lookback=1d; target frequency=P1D, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - Account mapping was completed with projected column `DnsDomain` + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - Host.FullName value is retained as customDetails.HostFullName from query column `Computer`, but its target output binding + requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.HostFullName column `Computer` requires runtime output-schema binding verification + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: + - All source MITRE tactics are preserved in source order in authored YAML. V3.1 ARM packaging carries only the first tactic + and its compatible techniques; this classification loss is not validated parity. Direct Graph deployment requires a + single tactic. + errors: [] + originalTactics: + - Execution + - DefenseEvasion + originalTechniques: + - T1059 + - T1027 + - T1140 + reviewScope: + sourceDocumentSha256: e8c4ba6039b55522c2067f775803f79b1a35de2dc6221c2a086da7ef59557d65 + targetQuerySha256: c85c3f30029baa14ff54e2dc4ce14c8f323754a7e801f875fe024697cdd31e28 + reviewDecisions: + - reason: isfuzzy unions can still fail semantic binding in Advanced Hunting + decision: accepted + sourceDocumentSha256: e8c4ba6039b55522c2067f775803f79b1a35de2dc6221c2a086da7ef59557d65 + targetQuerySha256: c85c3f30029baa14ff54e2dc4ce14c8f323754a7e801f875fe024697cdd31e28 + - reason: 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented + by hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + decision: accepted + sourceDocumentSha256: e8c4ba6039b55522c2067f775803f79b1a35de2dc6221c2a086da7ef59557d65 + targetQuerySha256: c85c3f30029baa14ff54e2dc4ce14c8f323754a7e801f875fe024697cdd31e28 + supplementalEntityDetails: + - entityType: Host + entityIndex: 2 + identifier: FullName + sourceColumn: Computer + column: Computer + status: runtime-binding-pending + customDetailKey: HostFullName + acceptedReviewReasons: + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - isfuzzy unions can still fail semantic binding in Advanced Hunting +properties: + id: xdr-d6190dde-8fd2-456a-ac5b-0a32400b0464 + displayName: Process executed from binary hidden in Base64 encoded file + status: disabled + queryCondition: + queryText: |- + let ProcessCreationEvents=(union isfuzzy=true + (SecurityEvent + | where EventID==4688 + | where isnotempty(CommandLine) + | project TimeGenerated, Computer, Account = SubjectUserName, AccountDomain = SubjectDomainName, FileName = Process, CommandLine, ParentProcessName + ), + (WindowsEvent + | where EventID==4688 + | where EventData has_any (".decode('base64')", "base64 --decode", ".decode64(" ) + | extend CommandLine = tostring(EventData.CommandLine) + | where isnotempty(CommandLine) + | extend SubjectUserName = tostring(EventData.SubjectUserName) + | extend SubjectDomainName = tostring(EventData.SubjectDomainName) + | extend NewProcessName = tostring(EventData.NewProcessName) + | extend FileName=tostring(split(NewProcessName, '\\')[-1]) + | extend ParentProcessName = tostring(EventData.ParentProcessName) + | project TimeGenerated, Computer, Account = SubjectUserName, AccountDomain = SubjectDomainName, CommandLine, ParentProcessName + )); + ProcessCreationEvents + | where CommandLine contains ".decode('base64')" + or CommandLine contains "base64 --decode" + or CommandLine contains ".decode64(" + | summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), CountToday = count() by Computer, Account, AccountDomain, FileName, CommandLine, ParentProcessName + | extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'') + schedule: + frequency: P1D + detectionAction: + alertTemplate: + title: Process executed from binary hidden in Base64 encoded file + description: "'Encoding malicious software is a technique used to obfuscate files from detection. \nThe first CommandLine\ + \ component is looking for Python decoding base64. \nThe second CommandLine component is looking for Bash/sh command\ + \ line base64 decoding.\nThe third one is looking for Ruby decoding base64.'" + severity: medium + entityMappings: + accounts: + - id: account1 + nameColumn: Account + dnsDomainColumn: DnsDomain + hosts: + - id: host1 + nameColumn: HostName + dnsDomainColumn: DnsDomain + tactics: + - tactic: Execution + techniques: + - technique: T1059 + - tactic: DefenseEvasion + techniques: + - technique: T1027 + - technique: T1140 + customDetails: + HostFullName: Computer diff --git a/Solutions/Endpoint Threat Protection Essentials/XDR Detections/malware_in_recyclebin.yaml b/Solutions/Endpoint Threat Protection Essentials/XDR Detections/malware_in_recyclebin.yaml new file mode 100644 index 00000000000..dfb6cb9236d --- /dev/null +++ b/Solutions/Endpoint Threat Protection Essentials/XDR Detections/malware_in_recyclebin.yaml @@ -0,0 +1,143 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: SecurityEvents + dataTypes: + - SecurityEvent +- connectorId: WindowsSecurityEvents + dataTypes: + - SecurityEvent +- connectorId: WindowsForwardedEvents + dataTypes: + - WindowsEvent +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: 75bf9902-0789-47c1-a5d8-f57046aa72df + path: Analytic Rules/malware_in_recyclebin.yaml + version: 1.1.6 + querySha256: 2be13d2cf69456b016acb63be1e58a5b0880a7cd0f74760b4a97d7d05790ad8a + schedule: + queryFrequency: 1d + queryPeriod: 1d + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - externaldata availability must be verified by runtime validation + - isfuzzy unions can still fail semantic binding in Advanced Hunting + - 'Schedule assessment: source frequency=1d, lookback=1d; target frequency=P1D, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - Account mapping was completed with projected column `DnsDomain` + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - Host.FullName value is retained as customDetails.HostFullName from query column `Computer`, but its target output binding + requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.HostFullName column `Computer` requires runtime output-schema binding verification + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: [] + errors: [] + originalTactics: + - DefenseEvasion + originalTechniques: + - T1564 + reviewScope: + sourceDocumentSha256: 58b0f4a0817b98bb26893c43ba29b5ba103021f8a646a03ecfaf0ea97babf948 + targetQuerySha256: 06a22d445a627a8f3001125d23d77133519d71ae4dc09ca4bada73b5b494737f + reviewDecisions: + - reason: externaldata availability must be verified by runtime validation + decision: accepted + sourceDocumentSha256: 58b0f4a0817b98bb26893c43ba29b5ba103021f8a646a03ecfaf0ea97babf948 + targetQuerySha256: 06a22d445a627a8f3001125d23d77133519d71ae4dc09ca4bada73b5b494737f + - reason: isfuzzy unions can still fail semantic binding in Advanced Hunting + decision: accepted + sourceDocumentSha256: 58b0f4a0817b98bb26893c43ba29b5ba103021f8a646a03ecfaf0ea97babf948 + targetQuerySha256: 06a22d445a627a8f3001125d23d77133519d71ae4dc09ca4bada73b5b494737f + - reason: 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented + by hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + decision: accepted + sourceDocumentSha256: 58b0f4a0817b98bb26893c43ba29b5ba103021f8a646a03ecfaf0ea97babf948 + targetQuerySha256: 06a22d445a627a8f3001125d23d77133519d71ae4dc09ca4bada73b5b494737f + supplementalEntityDetails: + - entityType: Host + entityIndex: 2 + identifier: FullName + sourceColumn: Computer + column: Computer + status: runtime-binding-pending + customDetailKey: HostFullName + acceptedReviewReasons: + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - externaldata availability must be verified by runtime validation + - isfuzzy unions can still fail semantic binding in Advanced Hunting +properties: + id: xdr-75bf9902-0789-47c1-a5d8-f57046aa72df + displayName: Malware in the recycle bin + status: disabled + queryCondition: + queryText: |- + let procList = externaldata(Process:string) [@"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Microsoft_Lolbas_Execution_Binaries.csv"] with (format="csv", ignoreFirstRecord=True); + let recycle_bin_paths = dynamic([@":\RECYCLER", @":\$RECYCLE.BIN"]); + let ProcessCreationEvents=(union isfuzzy=true + (SecurityEvent + | where EventID==4688 + | where isnotempty(CommandLine) + | project TimeGenerated, Computer, Account = SubjectUserName, AccountDomain = SubjectDomainName, NewProcessName, + FileName = Process, CommandLine, ParentProcessName + ), + (WindowsEvent + | where EventID==4688 and EventData has_any (procList) and EventData has_any (recycle_bin_paths) + | extend CommandLine = tostring(EventData.CommandLine) + | where isnotempty(CommandLine) + | extend SubjectUserName = tostring(EventData.SubjectUserName) + | extend SubjectDomainName = tostring(EventData.SubjectDomainName) + | extend NewProcessName = tostring(EventData.NewProcessName) + | extend ParentProcessName = tostring(EventData.ParentProcessName) + | extend Process=tostring(split(NewProcessName, '\\')[-1]) + | project TimeGenerated, Computer, Account = SubjectUserName, AccountDomain = SubjectDomainName, NewProcessName, + FileName = Process, CommandLine, ParentProcessName + )); + ProcessCreationEvents + | where FileName in~ (procList) + | where CommandLine has_any (recycle_bin_paths) + | project StartTimeUtc = TimeGenerated, Computer, Account, NewProcessName, FileName, CommandLine, ParentProcessName + | extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'') + schedule: + frequency: P1D + detectionAction: + alertTemplate: + title: Malware in the recycle bin + description: |- + 'The query detects Windows binaries that can be used for executing malware and have been hidden in the recycle bin. + The list of these binaries is sourced from https://lolbas-project.github.io/ + References: https://azure.microsoft.com/blog/how-azure-security-center-helps-reveal-a-cyberattack/.' + severity: medium + entityMappings: + accounts: + - id: account1 + nameColumn: Account + dnsDomainColumn: DnsDomain + hosts: + - id: host1 + nameColumn: HostName + dnsDomainColumn: DnsDomain + tactics: + - tactic: DefenseEvasion + techniques: + - technique: T1564 + customDetails: + HostFullName: Computer diff --git a/Solutions/Syslog/Analytic Rules/FailedLogonAttempts_UnknownUser.yaml b/Solutions/Syslog/Analytic Rules/FailedLogonAttempts_UnknownUser.yaml index c4dad5258b5..7673a4fd740 100644 --- a/Solutions/Syslog/Analytic Rules/FailedLogonAttempts_UnknownUser.yaml +++ b/Solutions/Syslog/Analytic Rules/FailedLogonAttempts_UnknownUser.yaml @@ -5,6 +5,7 @@ description: | If there are many of hits, especially from outside your network, it could indicate a brute force attack. Default threshold for logon attempts is 15.' severity: Medium +status: Available requiredDataConnectors: - connectorId: Syslog dataTypes: diff --git a/Solutions/Syslog/Analytic Rules/NRT_squid_events_for_mining_pools.yaml b/Solutions/Syslog/Analytic Rules/NRT_squid_events_for_mining_pools.yaml index 0447c81d697..5afbd778e7f 100644 --- a/Solutions/Syslog/Analytic Rules/NRT_squid_events_for_mining_pools.yaml +++ b/Solutions/Syslog/Analytic Rules/NRT_squid_events_for_mining_pools.yaml @@ -4,6 +4,7 @@ description: | 'Checks for Squid proxy events in Syslog associated with common mining pools .This query presumes the default Squid log format is being used. http://www.squid-cache.org/Doc/config/access_log/' severity: Low +status: Available requiredDataConnectors: - connectorId: Syslog dataTypes: diff --git a/Solutions/Syslog/Analytic Rules/sftp_file_transfer_above_threshold.yaml b/Solutions/Syslog/Analytic Rules/sftp_file_transfer_above_threshold.yaml index 25fcb39d20d..468300301f9 100644 --- a/Solutions/Syslog/Analytic Rules/sftp_file_transfer_above_threshold.yaml +++ b/Solutions/Syslog/Analytic Rules/sftp_file_transfer_above_threshold.yaml @@ -4,6 +4,7 @@ description: | 'Identifies SFTP File Transfers above certain threshold in a 15min time period. It requires SFTP VERBOSE loglevel to be enabled. Please note that entity mapping for arrays is not supported, so when there is a single value in an array, we will pull that value from the array as a single string to populate the entity to support entity mapping features within Sentinel. Additionally, if the array is multivalued, we will input a string to indicate this with a unique hash so that matching will not occur.' severity: Medium +status: Available requiredDataConnectors: - connectorId: Syslog dataTypes: diff --git a/Solutions/Syslog/Analytic Rules/sftp_file_transfer_folders_above_threshold.yaml b/Solutions/Syslog/Analytic Rules/sftp_file_transfer_folders_above_threshold.yaml index 705c00e238d..0e8fa236291 100644 --- a/Solutions/Syslog/Analytic Rules/sftp_file_transfer_folders_above_threshold.yaml +++ b/Solutions/Syslog/Analytic Rules/sftp_file_transfer_folders_above_threshold.yaml @@ -5,6 +5,7 @@ description: | It requires SFTP VERBOSE loglevel to be enabled. Please note that entity mapping for arrays is not supported, so when there is a single value in an array, we will pull that value from the array as a single string to populate the entity to support entity mapping features within Sentinel. Additionally, if the array is multivalued, we will input a string to indicate this with a unique hash so that matching will not occur.' severity: Medium +status: Available requiredDataConnectors: - connectorId: Syslog dataTypes: diff --git a/Solutions/Syslog/Analytic Rules/squid_cryptomining_pools.yaml b/Solutions/Syslog/Analytic Rules/squid_cryptomining_pools.yaml index 4d00f42c18b..f0ec5a2d0ab 100644 --- a/Solutions/Syslog/Analytic Rules/squid_cryptomining_pools.yaml +++ b/Solutions/Syslog/Analytic Rules/squid_cryptomining_pools.yaml @@ -4,6 +4,7 @@ description: | 'Checks for Squid proxy events in Syslog associated with common mining pools. This query presumes the default Squid log format is being used. http://www.squid-cache.org/Doc/config/access_log/' severity: Low +status: Available requiredDataConnectors: - connectorId: Syslog dataTypes: diff --git a/Solutions/Syslog/Analytic Rules/squid_tor_proxies.yaml b/Solutions/Syslog/Analytic Rules/squid_tor_proxies.yaml index 683493d0b17..f83a73f554f 100644 --- a/Solutions/Syslog/Analytic Rules/squid_tor_proxies.yaml +++ b/Solutions/Syslog/Analytic Rules/squid_tor_proxies.yaml @@ -4,6 +4,7 @@ description: | 'Check for Squid proxy events associated with common ToR proxies. This query presumes the default squid log format is being used. http://www.squid-cache.org/Doc/config/access_log/' severity: Low +status: Available requiredDataConnectors: - connectorId: Syslog dataTypes: diff --git a/Solutions/Syslog/Analytic Rules/ssh_potentialBruteForce.yaml b/Solutions/Syslog/Analytic Rules/ssh_potentialBruteForce.yaml index 3b0145cf96f..4eea5f0d499 100644 --- a/Solutions/Syslog/Analytic Rules/ssh_potentialBruteForce.yaml +++ b/Solutions/Syslog/Analytic Rules/ssh_potentialBruteForce.yaml @@ -5,6 +5,7 @@ description: | Please note that entity mapping for arrays is not supported, so when there is a single value in an array, we will pull that value from the array as a single string to populate the entity to support entity mapping features within Sentinel. Additionally, if the array is multivalued, we will input a string to indicate this with a unique hash so that matching will not occur. As an example - ComputerList is an array that we check for a single value and write that into the HostName field for use in the entity mapping within Sentinel.' severity: Low +status: Available requiredDataConnectors: - connectorId: Syslog dataTypes: diff --git a/Solutions/Syslog/Data/Solution_syslog.json b/Solutions/Syslog/Data/Solution_syslog.json index 15f4a08fc63..3b26479b1b3 100644 --- a/Solutions/Syslog/Data/Solution_syslog.json +++ b/Solutions/Syslog/Data/Solution_syslog.json @@ -20,6 +20,15 @@ "Analytic Rules/sftp_file_transfer_above_threshold.yaml", "Analytic Rules/sftp_file_transfer_folders_above_threshold.yaml" ], + "XDR Detections": [ + "XDR Detections/FailedLogonAttempts_UnknownUser.yaml", + "XDR Detections/NRT_squid_events_for_mining_pools.yaml", + "XDR Detections/squid_cryptomining_pools.yaml", + "XDR Detections/squid_tor_proxies.yaml", + "XDR Detections/ssh_potentialBruteForce.yaml", + "XDR Detections/sftp_file_transfer_above_threshold.yaml", + "XDR Detections/sftp_file_transfer_folders_above_threshold.yaml" + ], "Hunting Queries": [ "Hunting Queries/CryptoCurrencyMiners.yaml", "Hunting Queries/SCXExecuteRunAsProviders.yaml", @@ -31,16 +40,16 @@ "Hunting Queries/squid_malformed_requests.yaml", "Hunting Queries/squid_volume_anomalies.yaml" ], - "Parsers":[ + "Parsers": [ "Workspace Functions/SyslogConnectorsOverallStatus.yaml", - "Workspace Functions/SyslogConnectorsEventVolumebyDeviceProduct.yaml" + "Workspace Functions/SyslogConnectorsEventVolumebyDeviceProduct.yaml" ], "BasePath": "C:\\GitHub\\Azure-Sentinel\\Solutions\\Syslog", - "Version": "3.0.7", "Metadata": "SolutionMetadata.json", "TemplateSpec": true, "StaticDataConnectorIds": [ "Syslog", "SyslogAma" - ] -} \ No newline at end of file + ], + "Version": "3.1.2" +} diff --git a/Solutions/Syslog/Package/3.1.2.zip b/Solutions/Syslog/Package/3.1.2.zip new file mode 100644 index 00000000000..4a66c17ed68 Binary files /dev/null and b/Solutions/Syslog/Package/3.1.2.zip differ diff --git a/Solutions/Syslog/Package/createUiDefinition.json b/Solutions/Syslog/Package/createUiDefinition.json index 7ae19e09540..e9ce323a802 100644 --- a/Solutions/Syslog/Package/createUiDefinition.json +++ b/Solutions/Syslog/Package/createUiDefinition.json @@ -6,7 +6,7 @@ "config": { "isWizard": false, "basics": { - "description": "**NOTE**: After the solution is installed, Microsoft recommends configuring and leveraging the Syslog via AMA connector for log ingestion. Legacy connector uses the Log Analytics agent, which is about to be deprecated by **Aug 31, 2024,** and thus should only be installed where AMA is not supported.
\n\n**Data Connectors:** 2, **Parsers:** 2, **Workbooks:** 2, **Analytic Rules:** 7, **Hunting Queries:** 9\n\n[Learn more about Microsoft Sentinel](https://aka.ms/azuresentinel) | [Learn more about Solutions](https://aka.ms/azuresentinelsolutionsdoc)", + "description": "**NOTE**: After the solution is installed, Microsoft recommends configuring and leveraging the Syslog via AMA connector for log ingestion. Legacy connector uses the Log Analytics agent, which is about to be deprecated by **Aug 31, 2024,** and thus should only be installed where AMA is not supported.
\n\n**Data Connectors:** 2, **Parsers:** 2, **Workbooks:** 2, **Analytic Rules:** 7, **XDR Detections:** 7, **Hunting Queries:** 9\n\n[Learn more about Microsoft Sentinel](https://aka.ms/azuresentinel) | [Learn more about Solutions](https://aka.ms/azuresentinelsolutionsdoc)", "subscription": { "resourceProviders": [ "Microsoft.OperationsManagement/solutions", @@ -51,6 +51,54 @@ } ], "steps": [ + { + "name": "contentSelection", + "label": "Content selection", + "elements": [ + { + "name": "DeployAnalyticsRule", + "type": "Microsoft.Common.CheckBox", + "label": "DeployAnalyticsRule", + "defaultValue": true, + "toolTip": "Deploy the Microsoft Sentinel analytic rules carried by this solution (ContentKind AnalyticsRule and its AnalyticsRuleTemplate registration face)." + }, + { + "name": "DeployWorkbook", + "type": "Microsoft.Common.CheckBox", + "label": "DeployWorkbook", + "defaultValue": true, + "toolTip": "Deploy the Microsoft Sentinel workbook content and its Content Hub registration carried by this solution (ContentKind Workbook and WorkbookTemplate)." + }, + { + "name": "DeployDataConnector", + "type": "Microsoft.Common.CheckBox", + "label": "DeployDataConnector", + "defaultValue": true, + "toolTip": "Deploy the data connectors carried by this solution, together with their metadata and catalog entries (ContentKind DataConnector, ResourceDataConnector and DataType)." + }, + { + "name": "DeployCustomDetection", + "type": "Microsoft.Common.CheckBox", + "label": "DeployCustomDetection", + "defaultValue": false, + "toolTip": "Deploy the XDR-native custom detection resources and their Content Hub registrations (ContentKind CustomDetection and CustomDetectionTemplate). Independent of DeployAnalyticsRule: both kinds can be selected together. Existing analytic-rule instances are not disabled or removed. CD enabled or disabled status is controlled separately from this deployment switch." + }, + { + "name": "DeployHuntingQuery", + "type": "Microsoft.Common.CheckBox", + "label": "DeployHuntingQuery", + "defaultValue": true, + "toolTip": "Deploy the Microsoft Sentinel hunting queries carried by this solution." + }, + { + "name": "DeployParser", + "type": "Microsoft.Common.CheckBox", + "label": "DeployParser", + "defaultValue": true, + "toolTip": "Deploy the parsers and their registrations carried by this solution." + } + ] + }, { "name": "dataconnectors", "label": "Data Connectors", @@ -63,6 +111,13 @@ "text": "This Solution installs the data connector for Syslog. You can get Syslog Syslog data in your Microsoft Sentinel workspace. After installing the solution, configure and enable this data connector by following guidance in Manage solution view." } }, + { + "name": "dataconnectors2-text", + "type": "Microsoft.Common.TextBlock", + "options": { + "text": "This Solution installs the data connector for Syslog. You can get Syslog Syslog data in your Microsoft Sentinel workspace. After installing the solution, configure and enable this data connector by following guidance in Manage solution view." + } + }, { "name": "dataconnectors-parser-text", "type": "Microsoft.Common.TextBlock", @@ -418,7 +473,13 @@ "outputs": { "workspace-location": "[first(map(filter(basics('getLAWorkspace').value, (filter) => and(contains(toLower(filter.id), toLower(resourceGroup().name)),equals(filter.name,basics('workspace')))), (item) => item.location))]", "location": "[location()]", - "workspace": "[basics('workspace')]" + "workspace": "[basics('workspace')]", + "DeployAnalyticsRule": "[steps('contentSelection').DeployAnalyticsRule]", + "DeployWorkbook": "[steps('contentSelection').DeployWorkbook]", + "DeployDataConnector": "[steps('contentSelection').DeployDataConnector]", + "DeployCustomDetection": "[steps('contentSelection').DeployCustomDetection]", + "DeployHuntingQuery": "[steps('contentSelection').DeployHuntingQuery]", + "DeployParser": "[steps('contentSelection').DeployParser]" } } } diff --git a/Solutions/Syslog/Package/mainTemplate.json b/Solutions/Syslog/Package/mainTemplate.json index 261c15d9624..9984ff294c1 100644 --- a/Solutions/Syslog/Package/mainTemplate.json +++ b/Solutions/Syslog/Package/mainTemplate.json @@ -43,13 +43,55 @@ "metadata": { "description": "Name for the workbook" } + }, + "DeployAnalyticsRule": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Deploy the Microsoft Sentinel analytic rules carried by this solution (ContentKind AnalyticsRule and its AnalyticsRuleTemplate registration face)." + } + }, + "DeployWorkbook": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Deploy the Microsoft Sentinel workbook content and its Content Hub registration carried by this solution (ContentKind Workbook and WorkbookTemplate)." + } + }, + "DeployDataConnector": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Deploy the data connectors carried by this solution, together with their metadata and catalog entries (ContentKind DataConnector, ResourceDataConnector and DataType)." + } + }, + "DeployCustomDetection": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Deploy the XDR-native custom detection resources and their Content Hub registrations (ContentKind CustomDetection and CustomDetectionTemplate). Independent of DeployAnalyticsRule: both kinds can be selected together. Existing analytic-rule instances are not disabled or removed. CD enabled or disabled status is controlled separately from this deployment switch." + } + }, + "DeployHuntingQuery": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Deploy the Microsoft Sentinel hunting queries carried by this solution." + } + }, + "DeployParser": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Deploy the parsers and their registrations carried by this solution." + } } }, "variables": { "email": "support@microsoft.com", "_email": "[variables('email')]", "_solutionName": "Syslog", - "_solutionVersion": "3.0.7", + "_solutionVersion": "3.1.2", "solutionId": "azuresentinel.azure-sentinel-solution-syslog", "_solutionId": "[variables('solutionId')]", "uiConfigId1": "Syslog", @@ -203,7 +245,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "Syslog data connector with template version 3.0.7", + "description": "Syslog data connector with template version 3.1.2", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('dataConnectorVersion1')]", @@ -285,7 +327,8 @@ "contentProductId": "[variables('_dataConnectorcontentProductId1')]", "id": "[variables('_dataConnectorcontentProductId1')]", "version": "[variables('dataConnectorVersion1')]" - } + }, + "condition": "[parameters('DeployDataConnector')]" }, { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", @@ -315,7 +358,8 @@ "tier": "Microsoft", "link": "https://support.microsoft.com" } - } + }, + "condition": "[parameters('DeployDataConnector')]" }, { "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',variables('_dataConnectorContentId1'))]", @@ -351,7 +395,8 @@ ], "id": "[variables('_uiConfigId1')]" } - } + }, + "condition": "[parameters('DeployParser')]" }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", @@ -362,7 +407,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "Syslog data connector with template version 3.0.7", + "description": "Syslog data connector with template version 3.1.2", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('dataConnectorVersion2')]", @@ -444,7 +489,8 @@ "contentProductId": "[variables('_dataConnectorcontentProductId2')]", "id": "[variables('_dataConnectorcontentProductId2')]", "version": "[variables('dataConnectorVersion2')]" - } + }, + "condition": "[parameters('DeployDataConnector')]" }, { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", @@ -474,7 +520,8 @@ "tier": "Microsoft", "link": "https://support.microsoft.com" } - } + }, + "condition": "[parameters('DeployDataConnector')]" }, { "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',variables('_dataConnectorContentId2'))]", @@ -510,7 +557,8 @@ ], "id": "[variables('_uiConfigId2')]" } - } + }, + "condition": "[parameters('DeployParser')]" }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", @@ -521,7 +569,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "LinuxMachines Workbook with template version 3.0.7", + "description": "LinuxMachines Workbook with template version 3.1.2", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('workbookVersion1')]", @@ -539,7 +587,7 @@ }, "properties": { "displayName": "[parameters('workbook1-name')]", - "serializedData": "{\"version\":\"Notebook/1.0\",\"items\":[{\"type\":1,\"content\":{\"json\":\"## Linux Machines\"},\"name\":\"text - 0\"},{\"type\":9,\"content\":{\"version\":\"KqlParameterItem/1.0\",\"query\":\"\",\"parameters\":[{\"id\":\"1025a43d-241c-4e40-95dc-c9eb9c789bc5\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"TimeRange\",\"type\":4,\"isRequired\":true,\"value\":{\"durationMs\":1209600000},\"typeSettings\":{\"selectableValues\":[{\"durationMs\":300000},{\"durationMs\":900000},{\"durationMs\":1800000},{\"durationMs\":3600000},{\"durationMs\":14400000},{\"durationMs\":43200000},{\"durationMs\":86400000},{\"durationMs\":172800000},{\"durationMs\":259200000},{\"durationMs\":604800000},{\"durationMs\":1209600000},{\"durationMs\":2419200000},{\"durationMs\":2592000000},{\"durationMs\":5184000000},{\"durationMs\":7776000000}],\"allowCustom\":true}},{\"id\":\"bc241870-7874-4927-8c74-d17e747522b1\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"Computer\",\"type\":5,\"isRequired\":true,\"multiSelect\":true,\"quote\":\"'\",\"delimiter\":\",\",\"query\":\"Syslog\\r\\n| summarize syslogEventsCount = count() by Computer\\r\\n| sort by syslogEventsCount desc\\r\\n| project Computer\\r\\n\",\"value\":[\"value::all\"],\"typeSettings\":{\"additionalResourceOptions\":[\"value::all\"],\"selectAllValue\":\"All\"},\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},{\"id\":\"e073f36e-2fb5-421d-9099-217205b247f5\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"Severity\",\"type\":2,\"isRequired\":true,\"multiSelect\":true,\"quote\":\"'\",\"delimiter\":\",\",\"value\":[\"value::all\"],\"typeSettings\":{\"additionalResourceOptions\":[\"value::all\"],\"selectAllValue\":\"*\"},\"jsonData\":\"[\\\"Emergency\\\", \\\"Alert\\\", \\\"Critical\\\", \\\"Error\\\", \\\"Warning\\\", \\\"Notice\\\", \\\"Informational\\\", \\\"Debug\\\"]\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\"}],\"style\":\"pills\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},\"name\":\"parameters - 1\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"Syslog\\r\\n| summarize count() by SeverityLevel\\r\\n| extend severityNumber = iif(SeverityLevel == 'emerg' or SeverityLevel == 'panic', 0, iif(SeverityLevel == 'alert', 1, iif(SeverityLevel == 'crit', 2, iif(SeverityLevel == 'err' or SeverityLevel == 'error', 3, iif(SeverityLevel == 'warning' or SeverityLevel == 'warn', 4, iif(SeverityLevel == 'notice', 5, iif(SeverityLevel == 'info', 6, iif(SeverityLevel == 'debug', 7, 8))))))))\\r\\n| sort by severityNumber asc\\r\\n| extend Severity = iif(SeverityLevel == 'emerg' or SeverityLevel == 'panic', 'Emergency', iif(SeverityLevel == 'alert', 'Alert', iif(SeverityLevel == 'crit', 'Critical', iif(SeverityLevel == 'err' or SeverityLevel == 'error', 'Error', iif(SeverityLevel == 'warning' or SeverityLevel == 'warn', 'Warning', iif(SeverityLevel == 'notice', 'Notice', iif(SeverityLevel == 'info', 'Informational', iif(SeverityLevel == 'debug', 'Debug', 'Unknown'))))))))\\r\\n| project-away severityNumber\\r\\n| where \\\"*\\\" in ({Severity}) or Severity in ({Severity})\\r\\n\",\"size\":4,\"exportToExcelOptions\":\"visible\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"tiles\",\"tileSettings\":{\"titleContent\":{\"columnMatch\":\"SeverityLevel\",\"formatter\":1,\"formatOptions\":{\"showIcon\":true}},\"leftContent\":{\"columnMatch\":\"count_\",\"formatter\":12,\"formatOptions\":{\"palette\":\"hotCold\",\"showIcon\":true},\"numberFormat\":{\"unit\":17,\"options\":{\"style\":\"decimal\",\"maximumFractionDigits\":2,\"maximumSignificantDigits\":3}}},\"showBorder\":false,\"sortOrderField\":2}},\"name\":\"query - 2\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"Syslog\\r\\n| where \\\"{Computer:lable}\\\" == \\\"All\\\" or Computer in ({Computer})\\r\\n| extend Severity = iif(SeverityLevel == 'emerg' or SeverityLevel == 'panic', 'Emergency', iif(SeverityLevel == 'alert', 'Alert', iif(SeverityLevel == 'crit', 'Critical', iif(SeverityLevel == 'err' or SeverityLevel == 'error', 'Error', iif(SeverityLevel == 'warning' or SeverityLevel == 'warn', 'Warning', iif(SeverityLevel == 'notice', 'Notice', iif(SeverityLevel == 'info', 'Informational', iif(SeverityLevel == 'debug', 'Debug', 'Unknown'))))))))\\r\\n| where \\\"*\\\" in ({Severity}) or Severity in ({Severity})\\r\\n| where SeverityLevel in (\\\"emerg\\\")\\r\\n| summarize count() by Computer, TimeGenerated\\r\\n\",\"size\":1,\"exportToExcelOptions\":\"visible\",\"title\":\"\\\"Emergency\\\" level events, by computer\",\"noDataMessage\":\"No emergency events within the defined scope\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"timechart\"},\"customWidth\":\"33\",\"name\":\"query - 2 - Copy\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"Syslog\\r\\n| where \\\"{Computer:lable}\\\" == \\\"All\\\" or Computer in ({Computer})\\r\\n| extend Severity = iif(SeverityLevel == 'emerg' or SeverityLevel == 'panic', 'Emergency', iif(SeverityLevel == 'alert', 'Alert', iif(SeverityLevel == 'crit', 'Critical', iif(SeverityLevel == 'err' or SeverityLevel == 'error', 'Error', iif(SeverityLevel == 'warning' or SeverityLevel == 'warn', 'Warning', iif(SeverityLevel == 'notice', 'Notice', iif(SeverityLevel == 'info', 'Informational', iif(SeverityLevel == 'debug', 'Debug', 'Unknown'))))))))\\r\\n| where \\\"*\\\" in ({Severity}) or Severity in ({Severity})\\r\\n| where SeverityLevel in (\\\"crit\\\")\\r\\n| summarize count() by Computer, TimeGenerated\\r\\n\",\"size\":1,\"exportToExcelOptions\":\"visible\",\"title\":\"\\\"Critical\\\" level events, by computer\",\"noDataMessage\":\"No critical events within the defined scope\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"timechart\"},\"customWidth\":\"33\",\"name\":\"query - 2 - Copy\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"Syslog\\r\\n| where \\\"{Computer:lable}\\\" == \\\"All\\\" or Computer in ({Computer})\\r\\n| extend Severity = iif(SeverityLevel == 'emerg' or SeverityLevel == 'panic', 'Emergency', iif(SeverityLevel == 'alert', 'Alert', iif(SeverityLevel == 'crit', 'Critical', iif(SeverityLevel == 'err' or SeverityLevel == 'error', 'Error', iif(SeverityLevel == 'warning' or SeverityLevel == 'warn', 'Warning', iif(SeverityLevel == 'notice', 'Notice', iif(SeverityLevel == 'info', 'Informational', iif(SeverityLevel == 'debug', 'Debug', 'Unknown'))))))))\\r\\n| where \\\"*\\\" in ({Severity}) or Severity in ({Severity})\\r\\n| where SeverityLevel in (\\\"alert\\\")\\r\\n| summarize count() by Computer, TimeGenerated\\r\\n\",\"size\":1,\"exportToExcelOptions\":\"visible\",\"title\":\"\\\"Alert\\\" level events, by computer\",\"noDataMessage\":\"No alert events within the defined scope\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"timechart\"},\"customWidth\":\"33\",\"name\":\"query - 2 - Copy - Copy\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"Syslog\\r\\n| where Computer in ({Computer})\\r\\n| extend Severity = iif(SeverityLevel == 'emerg' or SeverityLevel == 'panic', 'Emergency', iif(SeverityLevel == 'alert', 'Alert', iif(SeverityLevel == 'crit', 'Critical', iif(SeverityLevel == 'err' or SeverityLevel == 'error', 'Error', iif(SeverityLevel == 'warning' or SeverityLevel == 'warn', 'Warning', iif(SeverityLevel == 'notice', 'Notice', iif(SeverityLevel == 'info', 'Informational', iif(SeverityLevel == 'debug', 'Debug', 'Unknown'))))))))\\r\\n| extend SeverityNumber = iif(SeverityLevel == 'emerg' or SeverityLevel == 'panic', 0, iif(SeverityLevel == 'alert', 1, iif(SeverityLevel == 'crit', 2, iif(SeverityLevel == 'err' or SeverityLevel == 'error', 3, iif(SeverityLevel == 'warning' or SeverityLevel == 'warn', 4, iif(SeverityLevel == 'notice', 5, iif(SeverityLevel == 'info', 6, iif(SeverityLevel == 'debug', 7, 8))))))))\\r\\n| where Severity in ({Severity})\\r\\n|extend Computer = iif(isempty(_ResourceId), Computer, _ResourceId)\\r\\n| project TimeGenerated, Computer, SeverityLevel, SeverityNumber, Facility, HostIP, ProcessNameAndID = strcat(ProcessName, ' (', iff(isempty(ProcessID), \\\"-\\\", tostring(ProcessID)), ')') \\r\\n\",\"size\":0,\"exportToExcelOptions\":\"visible\",\"title\":\"Events\",\"noDataMessage\":\"No events\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"TimeGenerated\",\"formatter\":0,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Computer\",\"formatter\":0,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"SeverityLevel\",\"formatter\":0,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"SeverityNumber\",\"formatter\":8,\"formatOptions\":{\"min\":7,\"max\":0,\"palette\":\"redDark\",\"showIcon\":true}},{\"columnMatch\":\"Facility\",\"formatter\":0,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"HostIP\",\"formatter\":0,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"ProcessNameAndID\",\"formatter\":0,\"formatOptions\":{\"showIcon\":true}}]}},\"name\":\"query - 2 - Copy - Copy - Copy\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"Syslog\\r\\n| where \\\"{Computer:lable}\\\" == \\\"All\\\" or Computer in ({Computer})\\r\\n| extend Severity = iif(SeverityLevel == 'emerg' or SeverityLevel == 'panic', 'Emergency', iif(SeverityLevel == 'alert', 'Alert', iif(SeverityLevel == 'crit', 'Critical', iif(SeverityLevel == 'err' or SeverityLevel == 'error', 'Error', iif(SeverityLevel == 'warning' or SeverityLevel == 'warn', 'Warning', iif(SeverityLevel == 'notice', 'Notice', iif(SeverityLevel == 'info', 'Informational', iif(SeverityLevel == 'debug', 'Debug', 'Unknown'))))))))\\r\\n| where \\\"*\\\" in ({Severity}) or Severity in ({Severity})\\r\\n| summarize count() by SyslogMessage\\r\\n\",\"size\":0,\"exportToExcelOptions\":\"visible\",\"title\":\"Syslog messages of events\",\"noDataMessage\":\"No messages\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"piechart\"},\"customWidth\":\"50\",\"name\":\"query - 7\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"Syslog\\r\\n| where \\\"{Computer:lable}\\\" == \\\"All\\\" or Computer in ({Computer})\\r\\n| extend Severity = iif(SeverityLevel == 'emerg' or SeverityLevel == 'panic', 'Emergency', iif(SeverityLevel == 'alert', 'Alert', iif(SeverityLevel == 'crit', 'Critical', iif(SeverityLevel == 'err' or SeverityLevel == 'error', 'Error', iif(SeverityLevel == 'warning' or SeverityLevel == 'warn', 'Warning', iif(SeverityLevel == 'notice', 'Notice', iif(SeverityLevel == 'info', 'Informational', iif(SeverityLevel == 'debug', 'Debug', 'Unknown'))))))))\\r\\n| where \\\"*\\\" in ({Severity}) or Severity in ({Severity})\\r\\n| summarize count() by Facility, ProcessName\\r\\n| project Process = strcat(ProcessName, ' (', Facility, ')'), Count = count_ \\r\\n\",\"size\":0,\"exportToExcelOptions\":\"visible\",\"title\":\"Process names of events\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"piechart\"},\"customWidth\":\"50\",\"name\":\"query - 11\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"Syslog\\r\\n| where \\\"{Computer:lable}\\\" == \\\"All\\\" or Computer in ({Computer})\\r\\n| extend Severity = iif(SeverityLevel == 'emerg' or SeverityLevel == 'panic', 'Emergency', iif(SeverityLevel == 'alert', 'Alert', iif(SeverityLevel == 'crit', 'Critical', iif(SeverityLevel == 'err' or SeverityLevel == 'error', 'Error', iif(SeverityLevel == 'warning' or SeverityLevel == 'warn', 'Warning', iif(SeverityLevel == 'notice', 'Notice', iif(SeverityLevel == 'info', 'Informational', iif(SeverityLevel == 'debug', 'Debug', 'Unknown'))))))))\\r\\n| where \\\"*\\\" in ({Severity}) or Severity in ({Severity})\\r\\n| summarize count() by Facility, SeverityLevel\\r\\n\",\"size\":0,\"exportToExcelOptions\":\"visible\",\"title\":\"Event distribution, by facility\",\"noDataMessage\":\"No events\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"piechart\"},\"customWidth\":\"50\",\"name\":\"query - 7 - Copy - Copy - Copy\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"Syslog\\r\\n| where \\\"{Computer:lable}\\\" == \\\"All\\\" or Computer in ({Computer})\\r\\n| extend Severity = iif(SeverityLevel == 'emerg' or SeverityLevel == 'panic', 'Emergency', iif(SeverityLevel == 'alert', 'Alert', iif(SeverityLevel == 'crit', 'Critical', iif(SeverityLevel == 'err' or SeverityLevel == 'error', 'Error', iif(SeverityLevel == 'warning' or SeverityLevel == 'warn', 'Warning', iif(SeverityLevel == 'notice', 'Notice', iif(SeverityLevel == 'info', 'Informational', iif(SeverityLevel == 'debug', 'Debug', 'Unknown'))))))))\\r\\n| where \\\"*\\\" in ({Severity}) or Severity in ({Severity})\\r\\n| summarize count() by Facility, SeverityLevel\",\"size\":0,\"exportToExcelOptions\":\"visible\",\"title\":\"Severity levels, by facility\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"categoricalbar\"},\"customWidth\":\"50\",\"name\":\"query - 11 - Copy\"}],\"fromTemplateId\":\"sentinel-LinuxMachines\",\"$schema\":\"https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json\"}\r\n", + "serializedData": "{\"version\":\"Notebook/1.0\",\"items\":[{\"type\":1,\"content\":{\"json\":\"## Linux Machines\"},\"name\":\"text - 0\"},{\"type\":9,\"content\":{\"version\":\"KqlParameterItem/1.0\",\"query\":\"\",\"parameters\":[{\"id\":\"1025a43d-241c-4e40-95dc-c9eb9c789bc5\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"TimeRange\",\"type\":4,\"isRequired\":true,\"value\":{\"durationMs\":1209600000},\"typeSettings\":{\"selectableValues\":[{\"durationMs\":300000},{\"durationMs\":900000},{\"durationMs\":1800000},{\"durationMs\":3600000},{\"durationMs\":14400000},{\"durationMs\":43200000},{\"durationMs\":86400000},{\"durationMs\":172800000},{\"durationMs\":259200000},{\"durationMs\":604800000},{\"durationMs\":1209600000},{\"durationMs\":2419200000},{\"durationMs\":2592000000},{\"durationMs\":5184000000},{\"durationMs\":7776000000}],\"allowCustom\":true}},{\"id\":\"bc241870-7874-4927-8c74-d17e747522b1\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"Computer\",\"type\":5,\"isRequired\":true,\"multiSelect\":true,\"quote\":\"'\",\"delimiter\":\",\",\"query\":\"Syslog\\r\\n| summarize syslogEventsCount = count() by Computer\\r\\n| sort by syslogEventsCount desc\\r\\n| project Computer\\r\\n\",\"value\":[\"value::all\"],\"typeSettings\":{\"additionalResourceOptions\":[\"value::all\"],\"selectAllValue\":\"All\"},\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},{\"id\":\"e073f36e-2fb5-421d-9099-217205b247f5\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"Severity\",\"type\":2,\"isRequired\":true,\"multiSelect\":true,\"quote\":\"'\",\"delimiter\":\",\",\"value\":[\"value::all\"],\"typeSettings\":{\"additionalResourceOptions\":[\"value::all\"],\"selectAllValue\":\"*\"},\"jsonData\":\"[\\\"Emergency\\\", \\\"Alert\\\", \\\"Critical\\\", \\\"Error\\\", \\\"Warning\\\", \\\"Notice\\\", \\\"Informational\\\", \\\"Debug\\\"]\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\"}],\"style\":\"pills\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},\"name\":\"parameters - 1\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"Syslog\\r\\n| summarize count() by SeverityLevel\\r\\n| extend severityNumber = iif(SeverityLevel == 'emerg' or SeverityLevel == 'panic', 0, iif(SeverityLevel == 'alert', 1, iif(SeverityLevel == 'crit', 2, iif(SeverityLevel == 'err' or SeverityLevel == 'error', 3, iif(SeverityLevel == 'warning' or SeverityLevel == 'warn', 4, iif(SeverityLevel == 'notice', 5, iif(SeverityLevel == 'info', 6, iif(SeverityLevel == 'debug', 7, 8))))))))\\r\\n| sort by severityNumber asc\\r\\n| extend Severity = iif(SeverityLevel == 'emerg' or SeverityLevel == 'panic', 'Emergency', iif(SeverityLevel == 'alert', 'Alert', iif(SeverityLevel == 'crit', 'Critical', iif(SeverityLevel == 'err' or SeverityLevel == 'error', 'Error', iif(SeverityLevel == 'warning' or SeverityLevel == 'warn', 'Warning', iif(SeverityLevel == 'notice', 'Notice', iif(SeverityLevel == 'info', 'Informational', iif(SeverityLevel == 'debug', 'Debug', 'Unknown'))))))))\\r\\n| project-away severityNumber\\r\\n| where \\\"*\\\" in ({Severity}) or Severity in ({Severity})\\r\\n\",\"size\":4,\"exportToExcelOptions\":\"visible\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"tiles\",\"tileSettings\":{\"titleContent\":{\"columnMatch\":\"SeverityLevel\",\"formatter\":1,\"formatOptions\":{\"showIcon\":true}},\"leftContent\":{\"columnMatch\":\"count_\",\"formatter\":12,\"formatOptions\":{\"palette\":\"hotCold\",\"showIcon\":true},\"numberFormat\":{\"unit\":17,\"options\":{\"style\":\"decimal\",\"maximumFractionDigits\":2,\"maximumSignificantDigits\":3}}},\"showBorder\":false,\"sortOrderField\":2}},\"name\":\"query - 2\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"Syslog\\r\\n| where \\\"{Computer:lable}\\\" == \\\"All\\\" or Computer in ({Computer})\\r\\n| extend Severity = iif(SeverityLevel == 'emerg' or SeverityLevel == 'panic', 'Emergency', iif(SeverityLevel == 'alert', 'Alert', iif(SeverityLevel == 'crit', 'Critical', iif(SeverityLevel == 'err' or SeverityLevel == 'error', 'Error', iif(SeverityLevel == 'warning' or SeverityLevel == 'warn', 'Warning', iif(SeverityLevel == 'notice', 'Notice', iif(SeverityLevel == 'info', 'Informational', iif(SeverityLevel == 'debug', 'Debug', 'Unknown'))))))))\\r\\n| where \\\"*\\\" in ({Severity}) or Severity in ({Severity})\\r\\n| where SeverityLevel in (\\\"emerg\\\")\\r\\n| summarize count() by Computer, TimeGenerated\\r\\n\",\"size\":1,\"exportToExcelOptions\":\"visible\",\"title\":\"\\\"Emergency\\\" level events, by computer\",\"noDataMessage\":\"No emergency events within the defined scope\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"timechart\"},\"customWidth\":\"33\",\"name\":\"query - 2 - Copy\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"Syslog\\r\\n| where \\\"{Computer:lable}\\\" == \\\"All\\\" or Computer in ({Computer})\\r\\n| extend Severity = iif(SeverityLevel == 'emerg' or SeverityLevel == 'panic', 'Emergency', iif(SeverityLevel == 'alert', 'Alert', iif(SeverityLevel == 'crit', 'Critical', iif(SeverityLevel == 'err' or SeverityLevel == 'error', 'Error', iif(SeverityLevel == 'warning' or SeverityLevel == 'warn', 'Warning', iif(SeverityLevel == 'notice', 'Notice', iif(SeverityLevel == 'info', 'Informational', iif(SeverityLevel == 'debug', 'Debug', 'Unknown'))))))))\\r\\n| where \\\"*\\\" in ({Severity}) or Severity in ({Severity})\\r\\n| where SeverityLevel in (\\\"crit\\\")\\r\\n| summarize count() by Computer, TimeGenerated\\r\\n\",\"size\":1,\"exportToExcelOptions\":\"visible\",\"title\":\"\\\"Critical\\\" level events, by computer\",\"noDataMessage\":\"No critical events within the defined scope\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"timechart\"},\"customWidth\":\"33\",\"name\":\"query - 2 - Copy\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"Syslog\\r\\n| where \\\"{Computer:lable}\\\" == \\\"All\\\" or Computer in ({Computer})\\r\\n| extend Severity = iif(SeverityLevel == 'emerg' or SeverityLevel == 'panic', 'Emergency', iif(SeverityLevel == 'alert', 'Alert', iif(SeverityLevel == 'crit', 'Critical', iif(SeverityLevel == 'err' or SeverityLevel == 'error', 'Error', iif(SeverityLevel == 'warning' or SeverityLevel == 'warn', 'Warning', iif(SeverityLevel == 'notice', 'Notice', iif(SeverityLevel == 'info', 'Informational', iif(SeverityLevel == 'debug', 'Debug', 'Unknown'))))))))\\r\\n| where \\\"*\\\" in ({Severity}) or Severity in ({Severity})\\r\\n| where SeverityLevel in (\\\"alert\\\")\\r\\n| summarize count() by Computer, TimeGenerated\\r\\n\",\"size\":1,\"exportToExcelOptions\":\"visible\",\"title\":\"\\\"Alert\\\" level events, by computer\",\"noDataMessage\":\"No alert events within the defined scope\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"timechart\"},\"customWidth\":\"33\",\"name\":\"query - 2 - Copy - Copy\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"Syslog\\r\\n| where Computer in ({Computer})\\r\\n| extend Severity = iif(SeverityLevel == 'emerg' or SeverityLevel == 'panic', 'Emergency', iif(SeverityLevel == 'alert', 'Alert', iif(SeverityLevel == 'crit', 'Critical', iif(SeverityLevel == 'err' or SeverityLevel == 'error', 'Error', iif(SeverityLevel == 'warning' or SeverityLevel == 'warn', 'Warning', iif(SeverityLevel == 'notice', 'Notice', iif(SeverityLevel == 'info', 'Informational', iif(SeverityLevel == 'debug', 'Debug', 'Unknown'))))))))\\r\\n| extend SeverityNumber = iif(SeverityLevel == 'emerg' or SeverityLevel == 'panic', 0, iif(SeverityLevel == 'alert', 1, iif(SeverityLevel == 'crit', 2, iif(SeverityLevel == 'err' or SeverityLevel == 'error', 3, iif(SeverityLevel == 'warning' or SeverityLevel == 'warn', 4, iif(SeverityLevel == 'notice', 5, iif(SeverityLevel == 'info', 6, iif(SeverityLevel == 'debug', 7, 8))))))))\\r\\n| where Severity in ({Severity})\\r\\n|extend Computer = iif(isempty(_ResourceId), Computer, _ResourceId)\\r\\n| project TimeGenerated, Computer, SeverityLevel, SeverityNumber, Facility, HostIP, ProcessNameAndID = strcat(ProcessName, ' (', iff(isempty(ProcessID), \\\"-\\\", tostring(ProcessID)), ')') \\r\\n\",\"size\":0,\"exportToExcelOptions\":\"visible\",\"title\":\"Events\",\"noDataMessage\":\"No events\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"TimeGenerated\",\"formatter\":0,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Computer\",\"formatter\":0,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"SeverityLevel\",\"formatter\":0,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"SeverityNumber\",\"formatter\":8,\"formatOptions\":{\"min\":7,\"max\":0,\"palette\":\"redDark\",\"showIcon\":true}},{\"columnMatch\":\"Facility\",\"formatter\":0,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"HostIP\",\"formatter\":0,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"ProcessNameAndID\",\"formatter\":0,\"formatOptions\":{\"showIcon\":true}}]}},\"name\":\"query - 2 - Copy - Copy - Copy\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"Syslog\\r\\n| where \\\"{Computer:lable}\\\" == \\\"All\\\" or Computer in ({Computer})\\r\\n| extend Severity = iif(SeverityLevel == 'emerg' or SeverityLevel == 'panic', 'Emergency', iif(SeverityLevel == 'alert', 'Alert', iif(SeverityLevel == 'crit', 'Critical', iif(SeverityLevel == 'err' or SeverityLevel == 'error', 'Error', iif(SeverityLevel == 'warning' or SeverityLevel == 'warn', 'Warning', iif(SeverityLevel == 'notice', 'Notice', iif(SeverityLevel == 'info', 'Informational', iif(SeverityLevel == 'debug', 'Debug', 'Unknown'))))))))\\r\\n| where \\\"*\\\" in ({Severity}) or Severity in ({Severity})\\r\\n| summarize count() by SyslogMessage\\r\\n\",\"size\":0,\"exportToExcelOptions\":\"visible\",\"title\":\"Syslog messages of events\",\"noDataMessage\":\"No messages\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"piechart\"},\"customWidth\":\"50\",\"name\":\"query - 7\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"Syslog\\r\\n| where \\\"{Computer:lable}\\\" == \\\"All\\\" or Computer in ({Computer})\\r\\n| extend Severity = iif(SeverityLevel == 'emerg' or SeverityLevel == 'panic', 'Emergency', iif(SeverityLevel == 'alert', 'Alert', iif(SeverityLevel == 'crit', 'Critical', iif(SeverityLevel == 'err' or SeverityLevel == 'error', 'Error', iif(SeverityLevel == 'warning' or SeverityLevel == 'warn', 'Warning', iif(SeverityLevel == 'notice', 'Notice', iif(SeverityLevel == 'info', 'Informational', iif(SeverityLevel == 'debug', 'Debug', 'Unknown'))))))))\\r\\n| where \\\"*\\\" in ({Severity}) or Severity in ({Severity})\\r\\n| summarize count() by Facility, ProcessName\\r\\n| project Process = strcat(ProcessName, ' (', Facility, ')'), Count = count_ \\r\\n\",\"size\":0,\"exportToExcelOptions\":\"visible\",\"title\":\"Process names of events\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"piechart\"},\"customWidth\":\"50\",\"name\":\"query - 11\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"Syslog\\r\\n| where \\\"{Computer:lable}\\\" == \\\"All\\\" or Computer in ({Computer})\\r\\n| extend Severity = iif(SeverityLevel == 'emerg' or SeverityLevel == 'panic', 'Emergency', iif(SeverityLevel == 'alert', 'Alert', iif(SeverityLevel == 'crit', 'Critical', iif(SeverityLevel == 'err' or SeverityLevel == 'error', 'Error', iif(SeverityLevel == 'warning' or SeverityLevel == 'warn', 'Warning', iif(SeverityLevel == 'notice', 'Notice', iif(SeverityLevel == 'info', 'Informational', iif(SeverityLevel == 'debug', 'Debug', 'Unknown'))))))))\\r\\n| where \\\"*\\\" in ({Severity}) or Severity in ({Severity})\\r\\n| summarize count() by Facility, SeverityLevel\\r\\n\",\"size\":0,\"exportToExcelOptions\":\"visible\",\"title\":\"Event distribution, by facility\",\"noDataMessage\":\"No events\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"piechart\"},\"customWidth\":\"50\",\"name\":\"query - 7 - Copy - Copy - Copy\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"Syslog\\r\\n| where \\\"{Computer:lable}\\\" == \\\"All\\\" or Computer in ({Computer})\\r\\n| extend Severity = iif(SeverityLevel == 'emerg' or SeverityLevel == 'panic', 'Emergency', iif(SeverityLevel == 'alert', 'Alert', iif(SeverityLevel == 'crit', 'Critical', iif(SeverityLevel == 'err' or SeverityLevel == 'error', 'Error', iif(SeverityLevel == 'warning' or SeverityLevel == 'warn', 'Warning', iif(SeverityLevel == 'notice', 'Notice', iif(SeverityLevel == 'info', 'Informational', iif(SeverityLevel == 'debug', 'Debug', 'Unknown'))))))))\\r\\n| where \\\"*\\\" in ({Severity}) or Severity in ({Severity})\\r\\n| summarize count() by Facility, SeverityLevel\",\"size\":0,\"exportToExcelOptions\":\"visible\",\"title\":\"Severity levels, by facility\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"categoricalbar\"},\"customWidth\":\"50\",\"name\":\"query - 11 - Copy\"}],\"fromTemplateId\":\"sentinel-LinuxMachines\",\"$schema\":\"https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json\"}\n", "version": "1.0", "sourceId": "[variables('workspaceResourceId')]", "category": "sentinel" @@ -598,7 +646,8 @@ "contentProductId": "[variables('_workbookcontentProductId1')]", "id": "[variables('_workbookcontentProductId1')]", "version": "[variables('workbookVersion1')]" - } + }, + "condition": "[parameters('DeployWorkbook')]" }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", @@ -609,7 +658,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "SyslogConnectorsOverviewWorkbook Workbook with template version 3.0.7", + "description": "SyslogConnectorsOverviewWorkbook Workbook with template version 3.1.2", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('workbookVersion2')]", @@ -627,7 +676,7 @@ }, "properties": { "displayName": "[parameters('workbook2-name')]", - "serializedData": "{\"version\":\"Notebook/1.0\",\"items\":[{\"type\":1,\"content\":{\"json\":\"# Syslog Ingestion Overview\\n---\\n\\nThis Workbook gives an overview of ingestion of logs in the Syslog table\"},\"name\":\"text - 2\"},{\"type\":9,\"content\":{\"version\":\"KqlParameterItem/1.0\",\"crossComponentResources\":[\"{Workspace}\"],\"parameters\":[{\"id\":\"37fd3af4-5d65-41e2-81ae-0720f281eb04\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"Subscription\",\"type\":6,\"isRequired\":true,\"isGlobal\":true,\"multiSelect\":true,\"quote\":\"'\",\"delimiter\":\",\",\"typeSettings\":{\"additionalResourceOptions\":[\"value::all\"],\"includeAll\":true,\"showDefault\":false},\"timeContext\":{\"durationMs\":86400000}},{\"id\":\"0407e413-4562-4a87-b660-72facb921954\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"TimeRange\",\"type\":4,\"isRequired\":true,\"isGlobal\":true,\"typeSettings\":{\"selectableValues\":[{\"durationMs\":300000},{\"durationMs\":900000},{\"durationMs\":1800000},{\"durationMs\":3600000},{\"durationMs\":14400000},{\"durationMs\":43200000},{\"durationMs\":86400000},{\"durationMs\":172800000},{\"durationMs\":259200000},{\"durationMs\":604800000},{\"durationMs\":1209600000},{\"durationMs\":2419200000},{\"durationMs\":2592000000},{\"durationMs\":5184000000},{\"durationMs\":7776000000}]},\"timeContext\":{\"durationMs\":86400000},\"value\":{\"durationMs\":7776000000}},{\"id\":\"f0722820-a155-4a53-a8e3-1483213a5d67\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"Workspace\",\"label\":\"Sentinel Workspace\",\"type\":5,\"isRequired\":true,\"isGlobal\":true,\"multiSelect\":true,\"quote\":\"'\",\"delimiter\":\",\",\"query\":\"where type =~ 'microsoft.operationalinsights/workspaces'\\r\\n| project id\",\"crossComponentResources\":[\"{Subscription}\"],\"typeSettings\":{\"resourceTypeFilter\":{\"microsoft.operationalinsights/workspaces\":true},\"showDefault\":false},\"timeContext\":{\"durationMs\":2592000000},\"queryType\":1,\"resourceType\":\"microsoft.resourcegraph/resources\"}],\"style\":\"pills\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},\"name\":\"parameters - 0\"},{\"type\":1,\"content\":{\"json\":\"## Log Ingestion Overview\\r\\n##### Select the Device Product to render the time chart\\r\\n---\"},\"name\":\"text - 3\"},{\"type\":12,\"content\":{\"version\":\"NotebookGroup/1.0\",\"groupType\":\"editable\",\"items\":[{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"SyslogConnectorsOverallStatus({TimeRange:start}, {TimeRange:end})\",\"size\":0,\"timeContextFromParameter\":\"TimeRange\",\"exportFieldName\":\"DeviceProduct\",\"exportParameterName\":\"DeviceProduct\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"crossComponentResources\":[\"{Workspace}\"],\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"ConnectionStatus\",\"formatter\":18,\"formatOptions\":{\"thresholdsOptions\":\"icons\",\"thresholdsGrid\":[{\"operator\":\"==\",\"thresholdValue\":\"Connected\",\"representation\":\"success\",\"text\":\"{0}{1}\"},{\"operator\":\"!=\",\"thresholdValue\":\"Connected\",\"representation\":\"error\",\"text\":\"{0}{1}\"},{\"operator\":\"Default\",\"representation\":\"success\",\"text\":\"{0}{1}\"}]},\"numberFormat\":{\"unit\":0,\"options\":{\"style\":\"decimal\"}}},{\"columnMatch\":\"OutofBox\",\"formatter\":18,\"formatOptions\":{\"thresholdsOptions\":\"icons\",\"thresholdsGrid\":[{\"operator\":\"==\",\"thresholdValue\":\"Available\",\"representation\":\"Available\",\"text\":\"{0}{1}\"},{\"operator\":\"!=\",\"thresholdValue\":\"Yes\",\"representation\":\"Unavailable\",\"text\":\"{0}{1}\"},{\"operator\":\"Default\",\"representation\":\"success\",\"text\":\"{0}{1}\"}]}}],\"labelSettings\":[{\"columnId\":\"DeviceProduct\",\"label\":\"Device Product\"}]}},\"customWidth\":\"50\",\"name\":\"query - 1 - Copy\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"SyslogConnectorsEventVolumebyDeviceProduct({TimeRange:start},{TimeRange:end},\\\"{DeviceProduct}\\\")\\r\\n| render timechart \",\"size\":0,\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"crossComponentResources\":[\"{Workspace}\"],\"visualization\":\"timechart\",\"chartSettings\":{\"showMetrics\":false}},\"customWidth\":\"50\",\"name\":\"query - 2\"}]},\"name\":\"IngestedLogs\"}],\"fromTemplateId\":\"sentinel-SyslogOverview\",\"$schema\":\"https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json\"}\r\n", + "serializedData": "{\"version\":\"Notebook/1.0\",\"items\":[{\"type\":1,\"content\":{\"json\":\"# Syslog Ingestion Overview\\n---\\n\\nThis Workbook gives an overview of ingestion of logs in the Syslog table\"},\"name\":\"text - 2\"},{\"type\":9,\"content\":{\"version\":\"KqlParameterItem/1.0\",\"crossComponentResources\":[\"{Workspace}\"],\"parameters\":[{\"id\":\"37fd3af4-5d65-41e2-81ae-0720f281eb04\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"Subscription\",\"type\":6,\"isRequired\":true,\"isGlobal\":true,\"multiSelect\":true,\"quote\":\"'\",\"delimiter\":\",\",\"typeSettings\":{\"additionalResourceOptions\":[\"value::all\"],\"includeAll\":true,\"showDefault\":false},\"timeContext\":{\"durationMs\":86400000}},{\"id\":\"0407e413-4562-4a87-b660-72facb921954\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"TimeRange\",\"type\":4,\"isRequired\":true,\"isGlobal\":true,\"typeSettings\":{\"selectableValues\":[{\"durationMs\":300000},{\"durationMs\":900000},{\"durationMs\":1800000},{\"durationMs\":3600000},{\"durationMs\":14400000},{\"durationMs\":43200000},{\"durationMs\":86400000},{\"durationMs\":172800000},{\"durationMs\":259200000},{\"durationMs\":604800000},{\"durationMs\":1209600000},{\"durationMs\":2419200000},{\"durationMs\":2592000000},{\"durationMs\":5184000000},{\"durationMs\":7776000000}]},\"timeContext\":{\"durationMs\":86400000},\"value\":{\"durationMs\":7776000000}},{\"id\":\"f0722820-a155-4a53-a8e3-1483213a5d67\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"Workspace\",\"label\":\"Sentinel Workspace\",\"type\":5,\"isRequired\":true,\"isGlobal\":true,\"multiSelect\":true,\"quote\":\"'\",\"delimiter\":\",\",\"query\":\"where type =~ 'microsoft.operationalinsights/workspaces'\\r\\n| project id\",\"crossComponentResources\":[\"{Subscription}\"],\"typeSettings\":{\"resourceTypeFilter\":{\"microsoft.operationalinsights/workspaces\":true},\"showDefault\":false},\"timeContext\":{\"durationMs\":2592000000},\"queryType\":1,\"resourceType\":\"microsoft.resourcegraph/resources\"}],\"style\":\"pills\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},\"name\":\"parameters - 0\"},{\"type\":1,\"content\":{\"json\":\"## Log Ingestion Overview\\r\\n##### Select the Device Product to render the time chart\\r\\n---\"},\"name\":\"text - 3\"},{\"type\":12,\"content\":{\"version\":\"NotebookGroup/1.0\",\"groupType\":\"editable\",\"items\":[{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"SyslogConnectorsOverallStatus({TimeRange:start}, {TimeRange:end})\",\"size\":0,\"timeContextFromParameter\":\"TimeRange\",\"exportFieldName\":\"DeviceProduct\",\"exportParameterName\":\"DeviceProduct\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"crossComponentResources\":[\"{Workspace}\"],\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"ConnectionStatus\",\"formatter\":18,\"formatOptions\":{\"thresholdsOptions\":\"icons\",\"thresholdsGrid\":[{\"operator\":\"==\",\"thresholdValue\":\"Connected\",\"representation\":\"success\",\"text\":\"{0}{1}\"},{\"operator\":\"!=\",\"thresholdValue\":\"Connected\",\"representation\":\"error\",\"text\":\"{0}{1}\"},{\"operator\":\"Default\",\"representation\":\"success\",\"text\":\"{0}{1}\"}]},\"numberFormat\":{\"unit\":0,\"options\":{\"style\":\"decimal\"}}},{\"columnMatch\":\"OutofBox\",\"formatter\":18,\"formatOptions\":{\"thresholdsOptions\":\"icons\",\"thresholdsGrid\":[{\"operator\":\"==\",\"thresholdValue\":\"Available\",\"representation\":\"Available\",\"text\":\"{0}{1}\"},{\"operator\":\"!=\",\"thresholdValue\":\"Yes\",\"representation\":\"Unavailable\",\"text\":\"{0}{1}\"},{\"operator\":\"Default\",\"representation\":\"success\",\"text\":\"{0}{1}\"}]}}],\"labelSettings\":[{\"columnId\":\"DeviceProduct\",\"label\":\"Device Product\"}]}},\"customWidth\":\"50\",\"name\":\"query - 1 - Copy\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"SyslogConnectorsEventVolumebyDeviceProduct({TimeRange:start},{TimeRange:end},\\\"{DeviceProduct}\\\")\\r\\n| render timechart \",\"size\":0,\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"crossComponentResources\":[\"{Workspace}\"],\"visualization\":\"timechart\",\"chartSettings\":{\"showMetrics\":false}},\"customWidth\":\"50\",\"name\":\"query - 2\"}]},\"name\":\"IngestedLogs\"}],\"fromTemplateId\":\"sentinel-SyslogOverview\",\"$schema\":\"https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json\"}\n", "version": "1.0", "sourceId": "[variables('workspaceResourceId')]", "category": "sentinel" @@ -690,7 +739,8 @@ "contentProductId": "[variables('_workbookcontentProductId2')]", "id": "[variables('_workbookcontentProductId2')]", "version": "[variables('workbookVersion2')]" - } + }, + "condition": "[parameters('DeployWorkbook')]" }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", @@ -701,7 +751,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "FailedLogonAttempts_UnknownUser_AnalyticalRules Analytics Rule with template version 3.0.7", + "description": "FailedLogonAttempts_UnknownUser_AnalyticalRules Analytics Rule with template version 3.1.2", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('analyticRuleObject1').analyticRuleVersion1]", @@ -752,8 +802,8 @@ "entityType": "Host", "fieldMappings": [ { - "columnName": "Computer", - "identifier": "FullName" + "identifier": "FullName", + "columnName": "Computer" } ] }, @@ -761,8 +811,8 @@ "entityType": "IP", "fieldMappings": [ { - "columnName": "HostIP", - "identifier": "Address" + "identifier": "Address", + "columnName": "HostIP" } ] } @@ -809,7 +859,8 @@ "contentProductId": "[variables('analyticRuleObject1')._analyticRulecontentProductId1]", "id": "[variables('analyticRuleObject1')._analyticRulecontentProductId1]", "version": "[variables('analyticRuleObject1').analyticRuleVersion1]" - } + }, + "condition": "[parameters('DeployAnalyticsRule')]" }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", @@ -820,7 +871,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "NRT_squid_events_for_mining_pools_AnalyticalRules Analytics Rule with template version 3.0.7", + "description": "NRT_squid_events_for_mining_pools_AnalyticalRules Analytics Rule with template version 3.1.2", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('analyticRuleObject2').analyticRuleVersion2]", @@ -867,8 +918,8 @@ "entityType": "Account", "fieldMappings": [ { - "columnName": "User", - "identifier": "FullName" + "identifier": "FullName", + "columnName": "User" } ] }, @@ -876,8 +927,8 @@ "entityType": "IP", "fieldMappings": [ { - "columnName": "SourceIP", - "identifier": "Address" + "identifier": "Address", + "columnName": "SourceIP" } ] }, @@ -885,8 +936,8 @@ "entityType": "URL", "fieldMappings": [ { - "columnName": "URL", - "identifier": "Url" + "identifier": "Url", + "columnName": "URL" } ] } @@ -933,7 +984,8 @@ "contentProductId": "[variables('analyticRuleObject2')._analyticRulecontentProductId2]", "id": "[variables('analyticRuleObject2')._analyticRulecontentProductId2]", "version": "[variables('analyticRuleObject2').analyticRuleVersion2]" - } + }, + "condition": "[parameters('DeployAnalyticsRule')]" }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", @@ -944,7 +996,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "squid_cryptomining_pools_AnalyticalRules Analytics Rule with template version 3.0.7", + "description": "squid_cryptomining_pools_AnalyticalRules Analytics Rule with template version 3.1.2", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('analyticRuleObject3').analyticRuleVersion3]", @@ -995,16 +1047,16 @@ "entityType": "Account", "fieldMappings": [ { - "columnName": "User", - "identifier": "FullName" + "identifier": "FullName", + "columnName": "User" }, { - "columnName": "AccountName", - "identifier": "Name" + "identifier": "Name", + "columnName": "AccountName" }, { - "columnName": "AccountUPNSuffix", - "identifier": "UPNSuffix" + "identifier": "UPNSuffix", + "columnName": "AccountUPNSuffix" } ] }, @@ -1012,8 +1064,8 @@ "entityType": "IP", "fieldMappings": [ { - "columnName": "SourceIP", - "identifier": "Address" + "identifier": "Address", + "columnName": "SourceIP" } ] }, @@ -1021,8 +1073,8 @@ "entityType": "URL", "fieldMappings": [ { - "columnName": "URL", - "identifier": "Url" + "identifier": "Url", + "columnName": "URL" } ] } @@ -1069,7 +1121,8 @@ "contentProductId": "[variables('analyticRuleObject3')._analyticRulecontentProductId3]", "id": "[variables('analyticRuleObject3')._analyticRulecontentProductId3]", "version": "[variables('analyticRuleObject3').analyticRuleVersion3]" - } + }, + "condition": "[parameters('DeployAnalyticsRule')]" }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", @@ -1080,7 +1133,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "squid_tor_proxies_AnalyticalRules Analytics Rule with template version 3.0.7", + "description": "squid_tor_proxies_AnalyticalRules Analytics Rule with template version 3.1.2", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('analyticRuleObject4').analyticRuleVersion4]", @@ -1132,16 +1185,16 @@ "entityType": "Account", "fieldMappings": [ { - "columnName": "User", - "identifier": "FullName" + "identifier": "FullName", + "columnName": "User" }, { - "columnName": "AccountName", - "identifier": "Name" + "identifier": "Name", + "columnName": "AccountName" }, { - "columnName": "AccountUPNSuffix", - "identifier": "UPNSuffix" + "identifier": "UPNSuffix", + "columnName": "AccountUPNSuffix" } ] }, @@ -1149,8 +1202,8 @@ "entityType": "IP", "fieldMappings": [ { - "columnName": "SourceIP", - "identifier": "Address" + "identifier": "Address", + "columnName": "SourceIP" } ] }, @@ -1158,8 +1211,8 @@ "entityType": "URL", "fieldMappings": [ { - "columnName": "URL", - "identifier": "Url" + "identifier": "Url", + "columnName": "URL" } ] } @@ -1206,7 +1259,8 @@ "contentProductId": "[variables('analyticRuleObject4')._analyticRulecontentProductId4]", "id": "[variables('analyticRuleObject4')._analyticRulecontentProductId4]", "version": "[variables('analyticRuleObject4').analyticRuleVersion4]" - } + }, + "condition": "[parameters('DeployAnalyticsRule')]" }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", @@ -1217,7 +1271,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "ssh_potentialBruteForce_AnalyticalRules Analytics Rule with template version 3.0.7", + "description": "ssh_potentialBruteForce_AnalyticalRules Analytics Rule with template version 3.1.2", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('analyticRuleObject5').analyticRuleVersion5]", @@ -1268,8 +1322,8 @@ "entityType": "Account", "fieldMappings": [ { - "columnName": "Account", - "identifier": "Name" + "identifier": "Name", + "columnName": "Account" } ] }, @@ -1277,8 +1331,8 @@ "entityType": "IP", "fieldMappings": [ { - "columnName": "IPAddress", - "identifier": "Address" + "identifier": "Address", + "columnName": "IPAddress" } ] }, @@ -1286,8 +1340,8 @@ "entityType": "Host", "fieldMappings": [ { - "columnName": "HostName", - "identifier": "HostName" + "identifier": "HostName", + "columnName": "HostName" } ] }, @@ -1295,8 +1349,8 @@ "entityType": "AzureResource", "fieldMappings": [ { - "columnName": "ResourceId", - "identifier": "ResourceId" + "identifier": "ResourceId", + "columnName": "ResourceId" } ] } @@ -1343,7 +1397,8 @@ "contentProductId": "[variables('analyticRuleObject5')._analyticRulecontentProductId5]", "id": "[variables('analyticRuleObject5')._analyticRulecontentProductId5]", "version": "[variables('analyticRuleObject5').analyticRuleVersion5]" - } + }, + "condition": "[parameters('DeployAnalyticsRule')]" }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", @@ -1354,7 +1409,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "sftp_file_transfer_above_threshold_AnalyticalRules Analytics Rule with template version 3.0.7", + "description": "sftp_file_transfer_above_threshold_AnalyticalRules Analytics Rule with template version 3.1.2", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('analyticRuleObject6').analyticRuleVersion6]", @@ -1405,8 +1460,8 @@ "entityType": "Account", "fieldMappings": [ { - "columnName": "username", - "identifier": "Name" + "identifier": "Name", + "columnName": "username" } ] }, @@ -1414,8 +1469,8 @@ "entityType": "IP", "fieldMappings": [ { - "columnName": "src_ip", - "identifier": "Address" + "identifier": "Address", + "columnName": "src_ip" } ] }, @@ -1423,8 +1478,8 @@ "entityType": "Host", "fieldMappings": [ { - "columnName": "Computer", - "identifier": "HostName" + "identifier": "HostName", + "columnName": "Computer" } ] }, @@ -1432,8 +1487,8 @@ "entityType": "File", "fieldMappings": [ { - "columnName": "FileSample", - "identifier": "Name" + "identifier": "Name", + "columnName": "FileSample" } ] } @@ -1443,17 +1498,19 @@ "FilesList": "fileslist" }, "incidentConfiguration": { + "createIncident": true, "groupingConfiguration": { - "enabled": true, - "lookbackDuration": "5h", + "matchingMethod": "Selected", "groupByEntities": [ "Account", "Host" ], "enabled": true, - "reopenClosedIncident": false - }, - "createIncident": true + "groupByCustomDetails": [], + "reopenClosedIncident": false, + "lookbackDuration": "5h", + "groupByAlertDetails": [] + } } } }, @@ -1497,7 +1554,8 @@ "contentProductId": "[variables('analyticRuleObject6')._analyticRulecontentProductId6]", "id": "[variables('analyticRuleObject6')._analyticRulecontentProductId6]", "version": "[variables('analyticRuleObject6').analyticRuleVersion6]" - } + }, + "condition": "[parameters('DeployAnalyticsRule')]" }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", @@ -1508,7 +1566,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "sftp_file_transfer_folders_above_threshold_AnalyticalRules Analytics Rule with template version 3.0.7", + "description": "sftp_file_transfer_folders_above_threshold_AnalyticalRules Analytics Rule with template version 3.1.2", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('analyticRuleObject7').analyticRuleVersion7]", @@ -1559,8 +1617,8 @@ "entityType": "Account", "fieldMappings": [ { - "columnName": "username", - "identifier": "Name" + "identifier": "Name", + "columnName": "username" } ] }, @@ -1568,8 +1626,8 @@ "entityType": "IP", "fieldMappings": [ { - "columnName": "src_ip", - "identifier": "Address" + "identifier": "Address", + "columnName": "src_ip" } ] }, @@ -1577,8 +1635,8 @@ "entityType": "Host", "fieldMappings": [ { - "columnName": "Computer", - "identifier": "HostName" + "identifier": "HostName", + "columnName": "Computer" } ] }, @@ -1586,8 +1644,8 @@ "entityType": "File", "fieldMappings": [ { - "columnName": "DirSample", - "identifier": "Name" + "identifier": "Name", + "columnName": "DirSample" } ] } @@ -1597,17 +1655,19 @@ "FilesList": "dirlist" }, "incidentConfiguration": { + "createIncident": true, "groupingConfiguration": { - "enabled": true, - "lookbackDuration": "5h", + "matchingMethod": "Selected", "groupByEntities": [ "Account", "Host" ], "enabled": true, - "reopenClosedIncident": false - }, - "createIncident": true + "groupByCustomDetails": [], + "reopenClosedIncident": false, + "lookbackDuration": "5h", + "groupByAlertDetails": [] + } } } }, @@ -1651,7 +1711,8 @@ "contentProductId": "[variables('analyticRuleObject7')._analyticRulecontentProductId7]", "id": "[variables('analyticRuleObject7')._analyticRulecontentProductId7]", "version": "[variables('analyticRuleObject7').analyticRuleVersion7]" - } + }, + "condition": "[parameters('DeployAnalyticsRule')]" }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", @@ -1662,7 +1723,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "CryptoCurrencyMiners_HuntingQueries Hunting Query with template version 3.0.7", + "description": "CryptoCurrencyMiners_HuntingQueries Hunting Query with template version 3.1.2", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('huntingQueryObject1').huntingQueryVersion1]", @@ -1671,7 +1732,7 @@ "resources": [ { "type": "Microsoft.OperationalInsights/savedSearches", - "apiVersion": "2022-10-01", + "apiVersion": "2025-07-01", "name": "Syslog_Hunting_Query_1", "location": "[parameters('workspace-location')]", "properties": { @@ -1736,7 +1797,8 @@ "contentProductId": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject1')._huntingQuerycontentId1,'-', '1.0.1')))]", "id": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject1')._huntingQuerycontentId1,'-', '1.0.1')))]", "version": "1.0.1" - } + }, + "condition": "[parameters('DeployHuntingQuery')]" }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", @@ -1747,7 +1809,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "SCXExecuteRunAsProviders_HuntingQueries Hunting Query with template version 3.0.7", + "description": "SCXExecuteRunAsProviders_HuntingQueries Hunting Query with template version 3.1.2", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('huntingQueryObject2').huntingQueryVersion2]", @@ -1756,7 +1818,7 @@ "resources": [ { "type": "Microsoft.OperationalInsights/savedSearches", - "apiVersion": "2022-10-01", + "apiVersion": "2025-07-01", "name": "Syslog_Hunting_Query_2", "location": "[parameters('workspace-location')]", "properties": { @@ -1821,7 +1883,8 @@ "contentProductId": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject2')._huntingQuerycontentId2,'-', '1.0.2')))]", "id": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject2')._huntingQuerycontentId2,'-', '1.0.2')))]", "version": "1.0.2" - } + }, + "condition": "[parameters('DeployHuntingQuery')]" }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", @@ -1832,7 +1895,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "CryptoThreatActivity_HuntingQueries Hunting Query with template version 3.0.7", + "description": "CryptoThreatActivity_HuntingQueries Hunting Query with template version 3.1.2", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('huntingQueryObject3').huntingQueryVersion3]", @@ -1841,7 +1904,7 @@ "resources": [ { "type": "Microsoft.OperationalInsights/savedSearches", - "apiVersion": "2022-10-01", + "apiVersion": "2025-07-01", "name": "Syslog_Hunting_Query_3", "location": "[parameters('workspace-location')]", "properties": { @@ -1906,7 +1969,8 @@ "contentProductId": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject3')._huntingQuerycontentId3,'-', '1.0.1')))]", "id": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject3')._huntingQuerycontentId3,'-', '1.0.1')))]", "version": "1.0.1" - } + }, + "condition": "[parameters('DeployHuntingQuery')]" }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", @@ -1917,7 +1981,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "RareProcess_ForLxHost_HuntingQueries Hunting Query with template version 3.0.7", + "description": "RareProcess_ForLxHost_HuntingQueries Hunting Query with template version 3.1.2", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('huntingQueryObject4').huntingQueryVersion4]", @@ -1926,7 +1990,7 @@ "resources": [ { "type": "Microsoft.OperationalInsights/savedSearches", - "apiVersion": "2022-10-01", + "apiVersion": "2025-07-01", "name": "Syslog_Hunting_Query_4", "location": "[parameters('workspace-location')]", "properties": { @@ -1991,7 +2055,8 @@ "contentProductId": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject4')._huntingQuerycontentId4,'-', '1.0.0')))]", "id": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject4')._huntingQuerycontentId4,'-', '1.0.0')))]", "version": "1.0.0" - } + }, + "condition": "[parameters('DeployHuntingQuery')]" }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", @@ -2002,7 +2067,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "SchedTaskAggregation_HuntingQueries Hunting Query with template version 3.0.7", + "description": "SchedTaskAggregation_HuntingQueries Hunting Query with template version 3.1.2", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('huntingQueryObject5').huntingQueryVersion5]", @@ -2011,7 +2076,7 @@ "resources": [ { "type": "Microsoft.OperationalInsights/savedSearches", - "apiVersion": "2022-10-01", + "apiVersion": "2025-07-01", "name": "Syslog_Hunting_Query_5", "location": "[parameters('workspace-location')]", "properties": { @@ -2076,7 +2141,8 @@ "contentProductId": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject5')._huntingQuerycontentId5,'-', '1.0.0')))]", "id": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject5')._huntingQuerycontentId5,'-', '1.0.0')))]", "version": "1.0.0" - } + }, + "condition": "[parameters('DeployHuntingQuery')]" }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", @@ -2087,7 +2153,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "SchedTaskEditViaCrontab_HuntingQueries Hunting Query with template version 3.0.7", + "description": "SchedTaskEditViaCrontab_HuntingQueries Hunting Query with template version 3.1.2", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('huntingQueryObject6').huntingQueryVersion6]", @@ -2096,7 +2162,7 @@ "resources": [ { "type": "Microsoft.OperationalInsights/savedSearches", - "apiVersion": "2022-10-01", + "apiVersion": "2025-07-01", "name": "Syslog_Hunting_Query_6", "location": "[parameters('workspace-location')]", "properties": { @@ -2161,7 +2227,8 @@ "contentProductId": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject6')._huntingQuerycontentId6,'-', '1.0.1')))]", "id": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject6')._huntingQuerycontentId6,'-', '1.0.1')))]", "version": "1.0.1" - } + }, + "condition": "[parameters('DeployHuntingQuery')]" }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", @@ -2172,7 +2239,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "squid_abused_tlds_HuntingQueries Hunting Query with template version 3.0.7", + "description": "squid_abused_tlds_HuntingQueries Hunting Query with template version 3.1.2", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('huntingQueryObject7').huntingQueryVersion7]", @@ -2181,7 +2248,7 @@ "resources": [ { "type": "Microsoft.OperationalInsights/savedSearches", - "apiVersion": "2022-10-01", + "apiVersion": "2025-07-01", "name": "Syslog_Hunting_Query_7", "location": "[parameters('workspace-location')]", "properties": { @@ -2246,7 +2313,8 @@ "contentProductId": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject7')._huntingQuerycontentId7,'-', '1.0.1')))]", "id": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject7')._huntingQuerycontentId7,'-', '1.0.1')))]", "version": "1.0.1" - } + }, + "condition": "[parameters('DeployHuntingQuery')]" }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", @@ -2257,7 +2325,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "squid_malformed_requests_HuntingQueries Hunting Query with template version 3.0.7", + "description": "squid_malformed_requests_HuntingQueries Hunting Query with template version 3.1.2", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('huntingQueryObject8').huntingQueryVersion8]", @@ -2266,7 +2334,7 @@ "resources": [ { "type": "Microsoft.OperationalInsights/savedSearches", - "apiVersion": "2022-10-01", + "apiVersion": "2025-07-01", "name": "Syslog_Hunting_Query_8", "location": "[parameters('workspace-location')]", "properties": { @@ -2331,7 +2399,8 @@ "contentProductId": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject8')._huntingQuerycontentId8,'-', '1.0.1')))]", "id": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject8')._huntingQuerycontentId8,'-', '1.0.1')))]", "version": "1.0.1" - } + }, + "condition": "[parameters('DeployHuntingQuery')]" }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", @@ -2342,7 +2411,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "squid_volume_anomalies_HuntingQueries Hunting Query with template version 3.0.7", + "description": "squid_volume_anomalies_HuntingQueries Hunting Query with template version 3.1.2", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('huntingQueryObject9').huntingQueryVersion9]", @@ -2351,7 +2420,7 @@ "resources": [ { "type": "Microsoft.OperationalInsights/savedSearches", - "apiVersion": "2022-10-01", + "apiVersion": "2025-07-01", "name": "Syslog_Hunting_Query_9", "location": "[parameters('workspace-location')]", "properties": { @@ -2416,7 +2485,8 @@ "contentProductId": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject9')._huntingQuerycontentId9,'-', '1.0.1')))]", "id": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject9')._huntingQuerycontentId9,'-', '1.0.1')))]", "version": "1.0.1" - } + }, + "condition": "[parameters('DeployHuntingQuery')]" }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", @@ -2427,7 +2497,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "SyslogConnectorsOverallStatus Data Parser with template version 3.0.7", + "description": "SyslogConnectorsOverallStatus Data Parser with template version 3.1.2", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('parserObject1').parserVersion1]", @@ -2436,7 +2506,7 @@ "resources": [ { "name": "[variables('parserObject1')._parserName1]", - "apiVersion": "2022-10-01", + "apiVersion": "2025-07-01", "type": "Microsoft.OperationalInsights/workspaces/savedSearches", "location": "[parameters('workspace-location')]", "properties": { @@ -2497,11 +2567,12 @@ "contentProductId": "[concat(take(variables('_solutionId'),50),'-','pr','-', uniqueString(concat(variables('_solutionId'),'-','Parser','-',variables('parserObject1').parserContentId1,'-', '1.0.0')))]", "id": "[concat(take(variables('_solutionId'),50),'-','pr','-', uniqueString(concat(variables('_solutionId'),'-','Parser','-',variables('parserObject1').parserContentId1,'-', '1.0.0')))]", "version": "[variables('parserObject1').parserVersion1]" - } + }, + "condition": "[parameters('DeployParser')]" }, { "type": "Microsoft.OperationalInsights/workspaces/savedSearches", - "apiVersion": "2022-10-01", + "apiVersion": "2025-07-01", "name": "[variables('parserObject1')._parserName1]", "location": "[parameters('workspace-location')]", "properties": { @@ -2518,7 +2589,8 @@ "value": "" } ] - } + }, + "condition": "[parameters('DeployParser')]" }, { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", @@ -2548,7 +2620,8 @@ "tier": "Microsoft", "link": "https://support.microsoft.com" } - } + }, + "condition": "[parameters('DeployParser')]" }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", @@ -2559,7 +2632,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "SyslogConnectorsEventVolumebyDeviceProduct Data Parser with template version 3.0.7", + "description": "SyslogConnectorsEventVolumebyDeviceProduct Data Parser with template version 3.1.2", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('parserObject2').parserVersion2]", @@ -2568,7 +2641,7 @@ "resources": [ { "name": "[variables('parserObject2')._parserName2]", - "apiVersion": "2022-10-01", + "apiVersion": "2025-07-01", "type": "Microsoft.OperationalInsights/workspaces/savedSearches", "location": "[parameters('workspace-location')]", "properties": { @@ -2629,11 +2702,12 @@ "contentProductId": "[concat(take(variables('_solutionId'),50),'-','pr','-', uniqueString(concat(variables('_solutionId'),'-','Parser','-',variables('parserObject2').parserContentId2,'-', '1.0.0')))]", "id": "[concat(take(variables('_solutionId'),50),'-','pr','-', uniqueString(concat(variables('_solutionId'),'-','Parser','-',variables('parserObject2').parserContentId2,'-', '1.0.0')))]", "version": "[variables('parserObject2').parserVersion2]" - } + }, + "condition": "[parameters('DeployParser')]" }, { "type": "Microsoft.OperationalInsights/workspaces/savedSearches", - "apiVersion": "2022-10-01", + "apiVersion": "2025-07-01", "name": "[variables('parserObject2')._parserName2]", "location": "[parameters('workspace-location')]", "properties": { @@ -2650,7 +2724,8 @@ "value": "" } ] - } + }, + "condition": "[parameters('DeployParser')]" }, { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", @@ -2680,19 +2755,20 @@ "tier": "Microsoft", "link": "https://support.microsoft.com" } - } + }, + "condition": "[parameters('DeployParser')]" }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentPackages", "apiVersion": "2023-04-01-preview", "location": "[parameters('workspace-location')]", "properties": { - "version": "3.0.7", + "version": "3.1.2", "kind": "Solution", "contentSchemaVersion": "3.0.0", "displayName": "Syslog", "publisherDisplayName": "Microsoft Sentinel, Microsoft Corporation", - "descriptionHtml": "Note: Please refer to the following before installing the solution:
\n• Review the solution Release Notes
\n• There may be known issues pertaining to this Solution, please refer to them before installing.
\nThe Syslog solution allows you to ingest events from applications or appliances that generate and can forward logs in the Syslog format to a Syslog Forwarder. The Agent for Linux is then able to forward these logs to the Log Analytics/Microsoft Sentinel workspace.
\nInstalling this solution will deploy two data connectors,
\nSyslog via AMA - This data connector helps in ingesting syslog messages into your Log Analytics Workspace using the new Azure Monitor Agent. Learn more about ingesting using the new Azure Monitor Agent here. Microsoft recommends using this Data Connector.
\nSyslog via Legacy Agent - This data connector helps in ingesting syslog messages into your Log Analytics Workspace using the legacy Log Analytics agent.
\n**NOTE**: After the solution is installed, Microsoft recommends configuring and leveraging the Syslog via AMA connector for log ingestion. Legacy connector uses the Log Analytics agent, which is about to be deprecated by **Aug 31, 2024,** and thus should only be installed where AMA is not supported.
\nData Connectors: 2, Parsers: 2, Workbooks: 2, Analytic Rules: 7, Hunting Queries: 9
\nLearn more about Microsoft Sentinel | Learn more about Solutions
\n", + "descriptionHtml": "Note: Please refer to the following before installing the solution:
\n• Review the solution Release Notes
\n• There may be known issues pertaining to this Solution, please refer to them before installing.
\nThe Syslog solution allows you to ingest events from applications or appliances that generate and can forward logs in the Syslog format to a Syslog Forwarder. The Agent for Linux is then able to forward these logs to the Log Analytics/Microsoft Sentinel workspace.
\nInstalling this solution will deploy two data connectors,
\nSyslog via AMA - This data connector helps in ingesting syslog messages into your Log Analytics Workspace using the new Azure Monitor Agent. Learn more about ingesting using the new Azure Monitor Agent here. Microsoft recommends using this Data Connector.
\nSyslog via Legacy Agent - This data connector helps in ingesting syslog messages into your Log Analytics Workspace using the legacy Log Analytics agent.
\n**NOTE**: After the solution is installed, Microsoft recommends configuring and leveraging the Syslog via AMA connector for log ingestion. Legacy connector uses the Log Analytics agent, which is about to be deprecated by **Aug 31, 2024,** and thus should only be installed where AMA is not supported.
\nData Connectors: 2, Parsers: 2, Workbooks: 2, Analytic Rules: 7, XDR Detections: 7, Hunting Queries: 9
\nLearn more about Microsoft Sentinel | Learn more about Solutions
\n", "contentKind": "Solution", "contentProductId": "[variables('_solutioncontentProductId')]", "id": "[variables('_solutioncontentProductId')]", @@ -2826,6 +2902,41 @@ "kind": "Parser", "contentId": "[variables('parserObject2').parserContentId2]", "version": "[variables('parserObject2').parserVersion2]" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-e7ec9fa6-e7f7-41ed-a34b-b956837a3ee6", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-dd03057e-4347-4853-bf1e-2b2d21eb4e59", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-80733eb7-35b2-45b6-b2b8-3c51df258206", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-90d3f6ec-80fb-48e0-9937-2c70c9df9bad", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-e1ce0eab-10d1-4aae-863f-9a383345ba88", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-bb6a74c8-889d-4c6e-8412-7d5efe33f4ed", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-7355434e-09d5-4401-b56d-e03e9379dfb1", + "version": "3.1.0" } ] }, @@ -2840,6 +2951,1256 @@ } }, "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/', variables('_solutionId'))]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "Syslog-CD-xdr-e7ec9fa6-e7f7-41ed-a34b-b956837a3ee6", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-e7ec9fa6-e7f7-41ed-a34b-b956837a3ee6', 'xdr-e7ec9fa6-e7f7-41ed-a34b-b956837a3ee6')]", + "status": "disabled", + "displayName": "Failed logon attempts in authpriv", + "detectionAction": { + "alertTemplate": { + "description": "'Identifies failed logon attempts from unknown users in Syslog authpriv logs. The unknown user means the account that tried to log in isn't provisioned on the machine. A few hits could indicate someone attempting to access a machine they aren't authorized to access. \nIf there are many of hits, especially from outside your network, it could indicate a brute force attack. \nDefault threshold for logon attempts is 15.'", + "customDetails": { + "HostFullName": "Computer" + }, + "severity": "medium", + "tactics": [ + { + "techniques": [ + { + "technique": "T1110" + } + ], + "tactic": "CredentialAccess" + } + ], + "title": "Failed logon attempts in authpriv", + "entityMappings": { + "hosts": [ + { + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "Computer" + } + ], + "ips": [ + { + "id": "[if(true(), 'ip1', 'ip1')]", + "addressColumn": "HostIP" + } + ] + } + } + }, + "queryCondition": { + "queryText": "let threshold = 15;\n// Below pulls messages from syslog-authpriv logs where there was an authentication failure with an unknown user.\n// IP address of system attempting logon is also extracted from the SyslogMessage field. Some of these messages\n// are aggregated.\nSyslog\n| where Facility =~ \"authpriv\"\n| where SyslogMessage has \"authentication failure\" and SyslogMessage has \" uid=0\"\n| extend RemoteIP = extract(@\".*?rhost=([\\d.]+).*?\", 1,SyslogMessage)\n| project TimeGenerated, Computer, ProcessName, HostIP, RemoteIP, ProcessID\n| join kind=innerunique (\n // Below pulls messages from syslog-authpriv logs that show each instance an unknown user tried to logon.\n Syslog\n | where Facility =~ \"authpriv\"\n | where SyslogMessage has \"user unknown\"\n | project Computer, HostIP, ProcessID\n ) on Computer, HostIP, ProcessID\n// Count the number of failed logon attempts by External IP and internal machine\n| summarize FirstLogonAttempt = min(TimeGenerated), LatestLogonAttempt = max(TimeGenerated), TotalLogonAttempts = count() by Computer, HostIP, RemoteIP\n// Calculate the time between first and last logon attempt (AttemptPeriodLength)\n| extend TimeBetweenLogonAttempts = LatestLogonAttempt - FirstLogonAttempt\n| where TotalLogonAttempts >= threshold\n| project FirstLogonAttempt, LatestLogonAttempt, TimeBetweenLogonAttempts, TotalLogonAttempts, SourceAddress = RemoteIP, Computer, HostIP\n| sort by Computer asc nulls last" + }, + "schedule": { + "frequency": "P1D" + } + } + } + } + } + }, + "condition": "[and(parameters('DeployParser'), parameters('DeployCustomDetection'))]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-e7ec9fa6-e7f7-41ed-a34b-b956837a3ee6')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'Syslog-CD-xdr-e7ec9fa6-e7f7-41ed-a34b-b956837a3ee6')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'Identifies failed logon attempts from unknown users in Syslog authpriv logs. The unknown user means the account that tried to log in isn't provisioned on the machine. A few hits could indicate someone attempting to access a machine they aren't authorized to access. \nIf there are many of hits, especially from outside your network, it could indicate a brute force attack. \nDefault threshold for logon attempts is 15.'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-e7ec9fa6-e7f7-41ed-a34b-b956837a3ee6', 'xdr-e7ec9fa6-e7f7-41ed-a34b-b956837a3ee6')]", + "status": "disabled", + "displayName": "Failed logon attempts in authpriv", + "detectionAction": { + "alertTemplate": { + "description": "'Identifies failed logon attempts from unknown users in Syslog authpriv logs. The unknown user means the account that tried to log in isn't provisioned on the machine. A few hits could indicate someone attempting to access a machine they aren't authorized to access. \nIf there are many of hits, especially from outside your network, it could indicate a brute force attack. \nDefault threshold for logon attempts is 15.'", + "customDetails": { + "HostFullName": "Computer" + }, + "severity": "medium", + "tactics": [ + { + "techniques": [ + { + "technique": "T1110" + } + ], + "tactic": "CredentialAccess" + } + ], + "title": "Failed logon attempts in authpriv", + "entityMappings": { + "hosts": [ + { + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "Computer" + } + ], + "ips": [ + { + "id": "[if(true(), 'ip1', 'ip1')]", + "addressColumn": "HostIP" + } + ] + } + } + }, + "queryCondition": { + "queryText": "let threshold = 15;\n// Below pulls messages from syslog-authpriv logs where there was an authentication failure with an unknown user.\n// IP address of system attempting logon is also extracted from the SyslogMessage field. Some of these messages\n// are aggregated.\nSyslog\n| where Facility =~ \"authpriv\"\n| where SyslogMessage has \"authentication failure\" and SyslogMessage has \" uid=0\"\n| extend RemoteIP = extract(@\".*?rhost=([\\d.]+).*?\", 1,SyslogMessage)\n| project TimeGenerated, Computer, ProcessName, HostIP, RemoteIP, ProcessID\n| join kind=innerunique (\n // Below pulls messages from syslog-authpriv logs that show each instance an unknown user tried to logon.\n Syslog\n | where Facility =~ \"authpriv\"\n | where SyslogMessage has \"user unknown\"\n | project Computer, HostIP, ProcessID\n ) on Computer, HostIP, ProcessID\n// Count the number of failed logon attempts by External IP and internal machine\n| summarize FirstLogonAttempt = min(TimeGenerated), LatestLogonAttempt = max(TimeGenerated), TotalLogonAttempts = count() by Computer, HostIP, RemoteIP\n// Calculate the time between first and last logon attempt (AttemptPeriodLength)\n| extend TimeBetweenLogonAttempts = LatestLogonAttempt - FirstLogonAttempt\n| where TotalLogonAttempts >= threshold\n| project FirstLogonAttempt, LatestLogonAttempt, TimeBetweenLogonAttempts, TotalLogonAttempts, SourceAddress = RemoteIP, Computer, HostIP\n| sort by Computer asc nulls last" + }, + "schedule": { + "frequency": "P1D" + } + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-e7ec9fa6-e7f7-41ed-a34b-b956837a3ee6", + "contentKind": "CustomDetection", + "displayName": "Failed logon attempts in authpriv", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-e7ec9fa6-e7f7-41ed-a34b-b956837a3ee6','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-e7ec9fa6-e7f7-41ed-a34b-b956837a3ee6','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "Syslog-CD-xdr-dd03057e-4347-4853-bf1e-2b2d21eb4e59", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-dd03057e-4347-4853-bf1e-2b2d21eb4e59', 'xdr-dd03057e-4347-4853-bf1e-2b2d21eb4e59')]", + "status": "disabled", + "displayName": "NRT Squid proxy events related to mining pools", + "detectionAction": { + "alertTemplate": { + "description": "'Checks for Squid proxy events in Syslog associated with common mining pools .This query presumes the default Squid log format is being used.\n http://www.squid-cache.org/Doc/config/access_log/'", + "customDetails": { + "AccountFullName": "User" + }, + "severity": "low", + "tactics": [ + { + "techniques": [ + { + "technique": "T1102" + } + ], + "tactic": "CommandAndControl" + } + ], + "title": "NRT Squid proxy events related to mining pools", + "entityMappings": { + "urls": [ + { + "id": "[if(true(), 'url1', 'url1')]", + "addressColumn": "URL" + } + ], + "ips": [ + { + "id": "[if(true(), 'ip1', 'ip1')]", + "addressColumn": "SourceIP" + } + ] + } + } + }, + "queryCondition": { + "queryText": "let DomainList = dynamic([\"monerohash.com\", \"do-dear.com\", \"xmrminerpro.com\", \"secumine.net\", \"xmrpool.com\", \"minexmr.org\", \"hashanywhere.com\", \"xmrget.com\",\n\"mininglottery.eu\", \"minergate.com\", \"moriaxmr.com\", \"multipooler.com\", \"moneropools.com\", \"xmrpool.eu\", \"coolmining.club\", \"supportxmr.com\",\n\"minexmr.com\", \"hashvault.pro\", \"xmrpool.net\", \"crypto-pool.fr\", \"xmr.pt\", \"miner.rocks\", \"walpool.com\", \"herominers.com\", \"gntl.co.uk\", \"semipool.com\",\n\"coinfoundry.org\", \"cryptoknight.cc\", \"fairhash.org\", \"baikalmine.com\", \"tubepool.xyz\", \"fairpool.xyz\", \"asiapool.io\", \"coinpoolit.webhop.me\", \"nanopool.org\",\n\"moneropool.com\", \"miner.center\", \"prohash.net\", \"poolto.be\", \"cryptoescrow.eu\", \"monerominers.net\", \"cryptonotepool.org\", \"extrmepool.org\", \"webcoin.me\",\n\"kippo.eu\", \"hashinvest.ws\", \"monero.farm\", \"supportxmr.com\", \"xmrpool.eu\", \"linux-repository-updates.com\", \"1gh.com\", \"dwarfpool.com\", \"hash-to-coins.com\",\n\"hashvault.pro\", \"pool-proxy.com\", \"hashfor.cash\", \"fairpool.cloud\", \"litecoinpool.org\", \"mineshaft.ml\", \"abcxyz.stream\", \"moneropool.ru\", \"cryptonotepool.org.uk\",\n\"extremepool.org\", \"extremehash.com\", \"hashinvest.net\", \"unipool.pro\", \"crypto-pools.org\", \"monero.net\", \"backup-pool.com\", \"mooo.com\", \"freeyy.me\", \"cryptonight.net\",\n\"shscrypto.net\"]);\nSyslog\n| where ProcessName contains \"squid\"\n| extend URL = extract(\"(([A-Z]+ [a-z]{4,5}:\\\\/\\\\/)|[A-Z]+ )([^ :]*)\",3,SyslogMessage),\n SourceIP = extract(\"([0-9]+ )(([0-9]{1,3})\\\\.([0-9]{1,3})\\\\.([0-9]{1,3})\\\\.([0-9]{1,3}))\",2,SyslogMessage),\n Status = extract(\"(TCP_(([A-Z]+)(_[A-Z]+)*)|UDP_(([A-Z]+)(_[A-Z]+)*))\",1,SyslogMessage),\n HTTP_Status_Code = extract(\"(TCP_(([A-Z]+)(_[A-Z]+)*)|UDP_(([A-Z]+)(_[A-Z]+)*))/([0-9]{3})\",8,SyslogMessage),\n User = extract(\"(CONNECT |GET )([^ ]* )([^ ]+)\",3,SyslogMessage),\n RemotePort = extract(\"(CONNECT |GET )([^ ]*)(:)([0-9]*)\",4,SyslogMessage),\n Domain = extract(\"(([A-Z]+ [a-z]{4,5}:\\\\/\\\\/)|[A-Z]+ )([^ :\\\\/]*)\",3,SyslogMessage),\n Bytes = toint(extract(\"([A-Z]+\\\\/[0-9]{3} )([0-9]+)\",2,SyslogMessage)),\n contentType = extract(\"([a-z/]+$)\",1,SyslogMessage)\n| extend TLD = extract(\"\\\\.[a-z]*$\",0,Domain)\n| where HTTP_Status_Code == '200'\n| where Domain contains \".\"\n| where Domain has_any (DomainList)" + }, + "schedule": { + "frequency": "PT1H" + } + } + } + } + } + }, + "condition": "[and(parameters('DeployParser'), parameters('DeployCustomDetection'))]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-dd03057e-4347-4853-bf1e-2b2d21eb4e59')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'Syslog-CD-xdr-dd03057e-4347-4853-bf1e-2b2d21eb4e59')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'Checks for Squid proxy events in Syslog associated with common mining pools .This query presumes the default Squid log format is being used.\n http://www.squid-cache.org/Doc/config/access_log/'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-dd03057e-4347-4853-bf1e-2b2d21eb4e59', 'xdr-dd03057e-4347-4853-bf1e-2b2d21eb4e59')]", + "status": "disabled", + "displayName": "NRT Squid proxy events related to mining pools", + "detectionAction": { + "alertTemplate": { + "description": "'Checks for Squid proxy events in Syslog associated with common mining pools .This query presumes the default Squid log format is being used.\n http://www.squid-cache.org/Doc/config/access_log/'", + "customDetails": { + "AccountFullName": "User" + }, + "severity": "low", + "tactics": [ + { + "techniques": [ + { + "technique": "T1102" + } + ], + "tactic": "CommandAndControl" + } + ], + "title": "NRT Squid proxy events related to mining pools", + "entityMappings": { + "urls": [ + { + "id": "[if(true(), 'url1', 'url1')]", + "addressColumn": "URL" + } + ], + "ips": [ + { + "id": "[if(true(), 'ip1', 'ip1')]", + "addressColumn": "SourceIP" + } + ] + } + } + }, + "queryCondition": { + "queryText": "let DomainList = dynamic([\"monerohash.com\", \"do-dear.com\", \"xmrminerpro.com\", \"secumine.net\", \"xmrpool.com\", \"minexmr.org\", \"hashanywhere.com\", \"xmrget.com\",\n\"mininglottery.eu\", \"minergate.com\", \"moriaxmr.com\", \"multipooler.com\", \"moneropools.com\", \"xmrpool.eu\", \"coolmining.club\", \"supportxmr.com\",\n\"minexmr.com\", \"hashvault.pro\", \"xmrpool.net\", \"crypto-pool.fr\", \"xmr.pt\", \"miner.rocks\", \"walpool.com\", \"herominers.com\", \"gntl.co.uk\", \"semipool.com\",\n\"coinfoundry.org\", \"cryptoknight.cc\", \"fairhash.org\", \"baikalmine.com\", \"tubepool.xyz\", \"fairpool.xyz\", \"asiapool.io\", \"coinpoolit.webhop.me\", \"nanopool.org\",\n\"moneropool.com\", \"miner.center\", \"prohash.net\", \"poolto.be\", \"cryptoescrow.eu\", \"monerominers.net\", \"cryptonotepool.org\", \"extrmepool.org\", \"webcoin.me\",\n\"kippo.eu\", \"hashinvest.ws\", \"monero.farm\", \"supportxmr.com\", \"xmrpool.eu\", \"linux-repository-updates.com\", \"1gh.com\", \"dwarfpool.com\", \"hash-to-coins.com\",\n\"hashvault.pro\", \"pool-proxy.com\", \"hashfor.cash\", \"fairpool.cloud\", \"litecoinpool.org\", \"mineshaft.ml\", \"abcxyz.stream\", \"moneropool.ru\", \"cryptonotepool.org.uk\",\n\"extremepool.org\", \"extremehash.com\", \"hashinvest.net\", \"unipool.pro\", \"crypto-pools.org\", \"monero.net\", \"backup-pool.com\", \"mooo.com\", \"freeyy.me\", \"cryptonight.net\",\n\"shscrypto.net\"]);\nSyslog\n| where ProcessName contains \"squid\"\n| extend URL = extract(\"(([A-Z]+ [a-z]{4,5}:\\\\/\\\\/)|[A-Z]+ )([^ :]*)\",3,SyslogMessage),\n SourceIP = extract(\"([0-9]+ )(([0-9]{1,3})\\\\.([0-9]{1,3})\\\\.([0-9]{1,3})\\\\.([0-9]{1,3}))\",2,SyslogMessage),\n Status = extract(\"(TCP_(([A-Z]+)(_[A-Z]+)*)|UDP_(([A-Z]+)(_[A-Z]+)*))\",1,SyslogMessage),\n HTTP_Status_Code = extract(\"(TCP_(([A-Z]+)(_[A-Z]+)*)|UDP_(([A-Z]+)(_[A-Z]+)*))/([0-9]{3})\",8,SyslogMessage),\n User = extract(\"(CONNECT |GET )([^ ]* )([^ ]+)\",3,SyslogMessage),\n RemotePort = extract(\"(CONNECT |GET )([^ ]*)(:)([0-9]*)\",4,SyslogMessage),\n Domain = extract(\"(([A-Z]+ [a-z]{4,5}:\\\\/\\\\/)|[A-Z]+ )([^ :\\\\/]*)\",3,SyslogMessage),\n Bytes = toint(extract(\"([A-Z]+\\\\/[0-9]{3} )([0-9]+)\",2,SyslogMessage)),\n contentType = extract(\"([a-z/]+$)\",1,SyslogMessage)\n| extend TLD = extract(\"\\\\.[a-z]*$\",0,Domain)\n| where HTTP_Status_Code == '200'\n| where Domain contains \".\"\n| where Domain has_any (DomainList)" + }, + "schedule": { + "frequency": "PT1H" + } + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-dd03057e-4347-4853-bf1e-2b2d21eb4e59", + "contentKind": "CustomDetection", + "displayName": "NRT Squid proxy events related to mining pools", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-dd03057e-4347-4853-bf1e-2b2d21eb4e59','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-dd03057e-4347-4853-bf1e-2b2d21eb4e59','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "Syslog-CD-xdr-80733eb7-35b2-45b6-b2b8-3c51df258206", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-80733eb7-35b2-45b6-b2b8-3c51df258206', 'xdr-80733eb7-35b2-45b6-b2b8-3c51df258206')]", + "status": "disabled", + "displayName": "Squid proxy events related to mining pools", + "detectionAction": { + "alertTemplate": { + "description": "'Checks for Squid proxy events in Syslog associated with common mining pools. This query presumes the default Squid log format is being used.\n http://www.squid-cache.org/Doc/config/access_log/'", + "customDetails": { + "AccountFullName": "User" + }, + "severity": "low", + "tactics": [ + { + "techniques": [ + { + "technique": "T1102" + } + ], + "tactic": "CommandAndControl" + } + ], + "title": "Squid proxy events related to mining pools", + "entityMappings": { + "accounts": [ + { + "upnSuffixColumn": "AccountUPNSuffix", + "nameColumn": "AccountName", + "id": "[if(true(), 'account1', 'account1')]" + } + ], + "urls": [ + { + "id": "[if(true(), 'url1', 'url1')]", + "addressColumn": "URL" + } + ], + "ips": [ + { + "id": "[if(true(), 'ip1', 'ip1')]", + "addressColumn": "SourceIP" + } + ] + } + } + }, + "queryCondition": { + "queryText": "let DomainList = dynamic([\"monerohash.com\", \"do-dear.com\", \"xmrminerpro.com\", \"secumine.net\", \"xmrpool.com\", \"minexmr.org\", \"hashanywhere.com\", \"xmrget.com\",\n\"mininglottery.eu\", \"minergate.com\", \"moriaxmr.com\", \"multipooler.com\", \"moneropools.com\", \"xmrpool.eu\", \"coolmining.club\", \"supportxmr.com\",\n\"minexmr.com\", \"hashvault.pro\", \"xmrpool.net\", \"crypto-pool.fr\", \"xmr.pt\", \"miner.rocks\", \"walpool.com\", \"herominers.com\", \"gntl.co.uk\", \"semipool.com\",\n\"coinfoundry.org\", \"cryptoknight.cc\", \"fairhash.org\", \"baikalmine.com\", \"tubepool.xyz\", \"fairpool.xyz\", \"asiapool.io\", \"coinpoolit.webhop.me\", \"nanopool.org\",\n\"moneropool.com\", \"miner.center\", \"prohash.net\", \"poolto.be\", \"cryptoescrow.eu\", \"monerominers.net\", \"cryptonotepool.org\", \"extrmepool.org\", \"webcoin.me\",\n\"kippo.eu\", \"hashinvest.ws\", \"monero.farm\", \"supportxmr.com\", \"xmrpool.eu\", \"linux-repository-updates.com\", \"1gh.com\", \"dwarfpool.com\", \"hash-to-coins.com\",\n\"hashvault.pro\", \"pool-proxy.com\", \"hashfor.cash\", \"fairpool.cloud\", \"litecoinpool.org\", \"mineshaft.ml\", \"abcxyz.stream\", \"moneropool.ru\", \"cryptonotepool.org.uk\",\n\"extremepool.org\", \"extremehash.com\", \"hashinvest.net\", \"unipool.pro\", \"crypto-pools.org\", \"monero.net\", \"backup-pool.com\", \"mooo.com\", \"freeyy.me\", \"cryptonight.net\",\n\"shscrypto.net\"]);\nSyslog\n| where ProcessName contains \"squid\"\n| extend URL = extract(\"(([A-Z]+ [a-z]{4,5}:\\\\/\\\\/)|[A-Z]+ )([^ :]*)\",3,SyslogMessage),\n SourceIP = extract(\"([0-9]+ )(([0-9]{1,3})\\\\.([0-9]{1,3})\\\\.([0-9]{1,3})\\\\.([0-9]{1,3}))\",2,SyslogMessage),\n Status = extract(\"(TCP_(([A-Z]+)(_[A-Z]+)*)|UDP_(([A-Z]+)(_[A-Z]+)*))\",1,SyslogMessage),\n HTTP_Status_Code = extract(\"(TCP_(([A-Z]+)(_[A-Z]+)*)|UDP_(([A-Z]+)(_[A-Z]+)*))/([0-9]{3})\",8,SyslogMessage),\n User = extract(\"(CONNECT |GET )([^ ]* )([^ ]+)\",3,SyslogMessage),\n RemotePort = extract(\"(CONNECT |GET )([^ ]*)(:)([0-9]*)\",4,SyslogMessage),\n Domain = extract(\"(([A-Z]+ [a-z]{4,5}:\\\\/\\\\/)|[A-Z]+ )([^ :\\\\/]*)\",3,SyslogMessage),\n Bytes = toint(extract(\"([A-Z]+\\\\/[0-9]{3} )([0-9]+)\",2,SyslogMessage)),\n contentType = extract(\"([a-z/]+$)\",1,SyslogMessage)\n| extend TLD = extract(\"\\\\.[a-z]*$\",0,Domain)\n| where HTTP_Status_Code == '200'\n| where Domain contains \".\"\n| where Domain has_any (DomainList)\n| extend AccountName = tostring(split(User, \"@\")[0]), AccountUPNSuffix = tostring(split(User, \"@\")[1])" + }, + "schedule": { + "frequency": "P1D" + } + } + } + } + } + }, + "condition": "[and(parameters('DeployParser'), parameters('DeployCustomDetection'))]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-80733eb7-35b2-45b6-b2b8-3c51df258206')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'Syslog-CD-xdr-80733eb7-35b2-45b6-b2b8-3c51df258206')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'Checks for Squid proxy events in Syslog associated with common mining pools. This query presumes the default Squid log format is being used.\n http://www.squid-cache.org/Doc/config/access_log/'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-80733eb7-35b2-45b6-b2b8-3c51df258206', 'xdr-80733eb7-35b2-45b6-b2b8-3c51df258206')]", + "status": "disabled", + "displayName": "Squid proxy events related to mining pools", + "detectionAction": { + "alertTemplate": { + "description": "'Checks for Squid proxy events in Syslog associated with common mining pools. This query presumes the default Squid log format is being used.\n http://www.squid-cache.org/Doc/config/access_log/'", + "customDetails": { + "AccountFullName": "User" + }, + "severity": "low", + "tactics": [ + { + "techniques": [ + { + "technique": "T1102" + } + ], + "tactic": "CommandAndControl" + } + ], + "title": "Squid proxy events related to mining pools", + "entityMappings": { + "accounts": [ + { + "upnSuffixColumn": "AccountUPNSuffix", + "nameColumn": "AccountName", + "id": "[if(true(), 'account1', 'account1')]" + } + ], + "urls": [ + { + "id": "[if(true(), 'url1', 'url1')]", + "addressColumn": "URL" + } + ], + "ips": [ + { + "id": "[if(true(), 'ip1', 'ip1')]", + "addressColumn": "SourceIP" + } + ] + } + } + }, + "queryCondition": { + "queryText": "let DomainList = dynamic([\"monerohash.com\", \"do-dear.com\", \"xmrminerpro.com\", \"secumine.net\", \"xmrpool.com\", \"minexmr.org\", \"hashanywhere.com\", \"xmrget.com\",\n\"mininglottery.eu\", \"minergate.com\", \"moriaxmr.com\", \"multipooler.com\", \"moneropools.com\", \"xmrpool.eu\", \"coolmining.club\", \"supportxmr.com\",\n\"minexmr.com\", \"hashvault.pro\", \"xmrpool.net\", \"crypto-pool.fr\", \"xmr.pt\", \"miner.rocks\", \"walpool.com\", \"herominers.com\", \"gntl.co.uk\", \"semipool.com\",\n\"coinfoundry.org\", \"cryptoknight.cc\", \"fairhash.org\", \"baikalmine.com\", \"tubepool.xyz\", \"fairpool.xyz\", \"asiapool.io\", \"coinpoolit.webhop.me\", \"nanopool.org\",\n\"moneropool.com\", \"miner.center\", \"prohash.net\", \"poolto.be\", \"cryptoescrow.eu\", \"monerominers.net\", \"cryptonotepool.org\", \"extrmepool.org\", \"webcoin.me\",\n\"kippo.eu\", \"hashinvest.ws\", \"monero.farm\", \"supportxmr.com\", \"xmrpool.eu\", \"linux-repository-updates.com\", \"1gh.com\", \"dwarfpool.com\", \"hash-to-coins.com\",\n\"hashvault.pro\", \"pool-proxy.com\", \"hashfor.cash\", \"fairpool.cloud\", \"litecoinpool.org\", \"mineshaft.ml\", \"abcxyz.stream\", \"moneropool.ru\", \"cryptonotepool.org.uk\",\n\"extremepool.org\", \"extremehash.com\", \"hashinvest.net\", \"unipool.pro\", \"crypto-pools.org\", \"monero.net\", \"backup-pool.com\", \"mooo.com\", \"freeyy.me\", \"cryptonight.net\",\n\"shscrypto.net\"]);\nSyslog\n| where ProcessName contains \"squid\"\n| extend URL = extract(\"(([A-Z]+ [a-z]{4,5}:\\\\/\\\\/)|[A-Z]+ )([^ :]*)\",3,SyslogMessage),\n SourceIP = extract(\"([0-9]+ )(([0-9]{1,3})\\\\.([0-9]{1,3})\\\\.([0-9]{1,3})\\\\.([0-9]{1,3}))\",2,SyslogMessage),\n Status = extract(\"(TCP_(([A-Z]+)(_[A-Z]+)*)|UDP_(([A-Z]+)(_[A-Z]+)*))\",1,SyslogMessage),\n HTTP_Status_Code = extract(\"(TCP_(([A-Z]+)(_[A-Z]+)*)|UDP_(([A-Z]+)(_[A-Z]+)*))/([0-9]{3})\",8,SyslogMessage),\n User = extract(\"(CONNECT |GET )([^ ]* )([^ ]+)\",3,SyslogMessage),\n RemotePort = extract(\"(CONNECT |GET )([^ ]*)(:)([0-9]*)\",4,SyslogMessage),\n Domain = extract(\"(([A-Z]+ [a-z]{4,5}:\\\\/\\\\/)|[A-Z]+ )([^ :\\\\/]*)\",3,SyslogMessage),\n Bytes = toint(extract(\"([A-Z]+\\\\/[0-9]{3} )([0-9]+)\",2,SyslogMessage)),\n contentType = extract(\"([a-z/]+$)\",1,SyslogMessage)\n| extend TLD = extract(\"\\\\.[a-z]*$\",0,Domain)\n| where HTTP_Status_Code == '200'\n| where Domain contains \".\"\n| where Domain has_any (DomainList)\n| extend AccountName = tostring(split(User, \"@\")[0]), AccountUPNSuffix = tostring(split(User, \"@\")[1])" + }, + "schedule": { + "frequency": "P1D" + } + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-80733eb7-35b2-45b6-b2b8-3c51df258206", + "contentKind": "CustomDetection", + "displayName": "Squid proxy events related to mining pools", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-80733eb7-35b2-45b6-b2b8-3c51df258206','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-80733eb7-35b2-45b6-b2b8-3c51df258206','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "Syslog-CD-xdr-90d3f6ec-80fb-48e0-9937-2c70c9df9bad", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-90d3f6ec-80fb-48e0-9937-2c70c9df9bad', 'xdr-90d3f6ec-80fb-48e0-9937-2c70c9df9bad')]", + "status": "disabled", + "displayName": "Squid proxy events for ToR proxies", + "detectionAction": { + "alertTemplate": { + "description": "'Check for Squid proxy events associated with common ToR proxies. This query presumes the default squid log format is being used.\nhttp://www.squid-cache.org/Doc/config/access_log/'", + "customDetails": { + "AccountFullName": "User" + }, + "severity": "low", + "tactics": [ + { + "techniques": [ + { + "technique": "T1090" + }, + { + "technique": "T1008" + } + ], + "tactic": "CommandAndControl" + } + ], + "title": "Squid proxy events for ToR proxies", + "entityMappings": { + "accounts": [ + { + "upnSuffixColumn": "AccountUPNSuffix", + "nameColumn": "AccountName", + "id": "[if(true(), 'account1', 'account1')]" + } + ], + "urls": [ + { + "id": "[if(true(), 'url1', 'url1')]", + "addressColumn": "URL" + } + ], + "ips": [ + { + "id": "[if(true(), 'ip1', 'ip1')]", + "addressColumn": "SourceIP" + } + ] + } + } + }, + "queryCondition": { + "queryText": "let DomainList = dynamic([\"tor2web.org\", \"tor2web.com\", \"torlink.co\", \"onion.to\", \"onion.ink\", \"onion.cab\", \"onion.nu\", \"onion.link\",\n\"onion.it\", \"onion.city\", \"onion.direct\", \"onion.top\", \"onion.casa\", \"onion.plus\", \"onion.rip\", \"onion.dog\", \"tor2web.fi\",\n\"tor2web.blutmagie.de\", \"onion.sh\", \"onion.lu\", \"onion.pet\", \"t2w.pw\", \"tor2web.ae.org\", \"tor2web.io\", \"tor2web.xyz\", \"onion.lt\",\n\"s1.tor-gateways.de\", \"s2.tor-gateways.de\", \"s3.tor-gateways.de\", \"s4.tor-gateways.de\", \"s5.tor-gateways.de\", \"hiddenservice.net\"]);\nSyslog\n| where ProcessName contains \"squid\"\n| extend URL = extract(\"(([A-Z]+ [a-z]{4,5}:\\\\/\\\\/)|[A-Z]+ )([^ :]*)\",3,SyslogMessage),\n SourceIP = extract(\"([0-9]+ )(([0-9]{1,3})\\\\.([0-9]{1,3})\\\\.([0-9]{1,3})\\\\.([0-9]{1,3}))\",2,SyslogMessage),\n Status = extract(\"(TCP_(([A-Z]+)(_[A-Z]+)*)|UDP_(([A-Z]+)(_[A-Z]+)*))\",1,SyslogMessage),\n HTTP_Status_Code = extract(\"(TCP_(([A-Z]+)(_[A-Z]+)*)|UDP_(([A-Z]+)(_[A-Z]+)*))/([0-9]{3})\",8,SyslogMessage),\n User = extract(\"(CONNECT |GET )([^ ]* )([^ ]+)\",3,SyslogMessage),\n RemotePort = extract(\"(CONNECT |GET )([^ ]*)(:)([0-9]*)\",4,SyslogMessage),\n Domain = extract(\"(([A-Z]+ [a-z]{4,5}:\\\\/\\\\/)|[A-Z]+ )([^ :\\\\/]*)\",3,SyslogMessage),\n Bytes = toint(extract(\"([A-Z]+\\\\/[0-9]{3} )([0-9]+)\",2,SyslogMessage)),\n contentType = extract(\"([a-z/]+$)\",1,SyslogMessage)\n| extend TLD = extract(\"\\\\.[a-z]*$\",0,Domain)\n| where HTTP_Status_Code == \"200\"\n| where Domain contains \".\"\n| where Domain has_any (DomainList)\n| extend AccountName = tostring(split(User, \"@\")[0]), AccountUPNSuffix = tostring(split(User, \"@\")[1])" + }, + "schedule": { + "frequency": "P1D" + } + } + } + } + } + }, + "condition": "[and(parameters('DeployParser'), parameters('DeployCustomDetection'))]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-90d3f6ec-80fb-48e0-9937-2c70c9df9bad')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'Syslog-CD-xdr-90d3f6ec-80fb-48e0-9937-2c70c9df9bad')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'Check for Squid proxy events associated with common ToR proxies. This query presumes the default squid log format is being used.\nhttp://www.squid-cache.org/Doc/config/access_log/'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-90d3f6ec-80fb-48e0-9937-2c70c9df9bad', 'xdr-90d3f6ec-80fb-48e0-9937-2c70c9df9bad')]", + "status": "disabled", + "displayName": "Squid proxy events for ToR proxies", + "detectionAction": { + "alertTemplate": { + "description": "'Check for Squid proxy events associated with common ToR proxies. This query presumes the default squid log format is being used.\nhttp://www.squid-cache.org/Doc/config/access_log/'", + "customDetails": { + "AccountFullName": "User" + }, + "severity": "low", + "tactics": [ + { + "techniques": [ + { + "technique": "T1090" + }, + { + "technique": "T1008" + } + ], + "tactic": "CommandAndControl" + } + ], + "title": "Squid proxy events for ToR proxies", + "entityMappings": { + "accounts": [ + { + "upnSuffixColumn": "AccountUPNSuffix", + "nameColumn": "AccountName", + "id": "[if(true(), 'account1', 'account1')]" + } + ], + "urls": [ + { + "id": "[if(true(), 'url1', 'url1')]", + "addressColumn": "URL" + } + ], + "ips": [ + { + "id": "[if(true(), 'ip1', 'ip1')]", + "addressColumn": "SourceIP" + } + ] + } + } + }, + "queryCondition": { + "queryText": "let DomainList = dynamic([\"tor2web.org\", \"tor2web.com\", \"torlink.co\", \"onion.to\", \"onion.ink\", \"onion.cab\", \"onion.nu\", \"onion.link\",\n\"onion.it\", \"onion.city\", \"onion.direct\", \"onion.top\", \"onion.casa\", \"onion.plus\", \"onion.rip\", \"onion.dog\", \"tor2web.fi\",\n\"tor2web.blutmagie.de\", \"onion.sh\", \"onion.lu\", \"onion.pet\", \"t2w.pw\", \"tor2web.ae.org\", \"tor2web.io\", \"tor2web.xyz\", \"onion.lt\",\n\"s1.tor-gateways.de\", \"s2.tor-gateways.de\", \"s3.tor-gateways.de\", \"s4.tor-gateways.de\", \"s5.tor-gateways.de\", \"hiddenservice.net\"]);\nSyslog\n| where ProcessName contains \"squid\"\n| extend URL = extract(\"(([A-Z]+ [a-z]{4,5}:\\\\/\\\\/)|[A-Z]+ )([^ :]*)\",3,SyslogMessage),\n SourceIP = extract(\"([0-9]+ )(([0-9]{1,3})\\\\.([0-9]{1,3})\\\\.([0-9]{1,3})\\\\.([0-9]{1,3}))\",2,SyslogMessage),\n Status = extract(\"(TCP_(([A-Z]+)(_[A-Z]+)*)|UDP_(([A-Z]+)(_[A-Z]+)*))\",1,SyslogMessage),\n HTTP_Status_Code = extract(\"(TCP_(([A-Z]+)(_[A-Z]+)*)|UDP_(([A-Z]+)(_[A-Z]+)*))/([0-9]{3})\",8,SyslogMessage),\n User = extract(\"(CONNECT |GET )([^ ]* )([^ ]+)\",3,SyslogMessage),\n RemotePort = extract(\"(CONNECT |GET )([^ ]*)(:)([0-9]*)\",4,SyslogMessage),\n Domain = extract(\"(([A-Z]+ [a-z]{4,5}:\\\\/\\\\/)|[A-Z]+ )([^ :\\\\/]*)\",3,SyslogMessage),\n Bytes = toint(extract(\"([A-Z]+\\\\/[0-9]{3} )([0-9]+)\",2,SyslogMessage)),\n contentType = extract(\"([a-z/]+$)\",1,SyslogMessage)\n| extend TLD = extract(\"\\\\.[a-z]*$\",0,Domain)\n| where HTTP_Status_Code == \"200\"\n| where Domain contains \".\"\n| where Domain has_any (DomainList)\n| extend AccountName = tostring(split(User, \"@\")[0]), AccountUPNSuffix = tostring(split(User, \"@\")[1])" + }, + "schedule": { + "frequency": "P1D" + } + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-90d3f6ec-80fb-48e0-9937-2c70c9df9bad", + "contentKind": "CustomDetection", + "displayName": "Squid proxy events for ToR proxies", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-90d3f6ec-80fb-48e0-9937-2c70c9df9bad','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-90d3f6ec-80fb-48e0-9937-2c70c9df9bad','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "Syslog-CD-xdr-e1ce0eab-10d1-4aae-863f-9a383345ba88", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-e1ce0eab-10d1-4aae-863f-9a383345ba88', 'xdr-e1ce0eab-10d1-4aae-863f-9a383345ba88')]", + "status": "disabled", + "displayName": "SSH - Potential Brute Force", + "detectionAction": { + "alertTemplate": { + "description": "'Identifies an IP address that had 15 failed attempts to sign in via SSH in a 4 hour block during a 24 hour time period.\n Please note that entity mapping for arrays is not supported, so when there is a single value in an array, we will pull that value from the array as a single string to populate the entity to support entity mapping features within Sentinel. Additionally, if the array is multivalued, we will input a string to indicate this with a unique hash so that matching will not occur.\n As an example - ComputerList is an array that we check for a single value and write that into the HostN", + "customDetails": { + "AccountName": "Account" + }, + "severity": "low", + "tactics": [ + { + "techniques": [ + { + "technique": "T1110" + } + ], + "tactic": "CredentialAccess" + } + ], + "title": "SSH - Potential Brute Force", + "entityMappings": { + "hosts": [ + { + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ], + "ips": [ + { + "id": "[if(true(), 'ip1', 'ip1')]", + "addressColumn": "IPAddress" + } + ], + "azureResources": [ + { + "id": "[if(true(), 'azureResource1', 'azureResource1')]", + "resourceIdColumn": "ResourceId" + } + ] + } + } + }, + "queryCondition": { + "queryText": "let threshold = 15;\nSyslog\n| where ProcessName =~ \"sshd\"\n| where SyslogMessage contains \"Failed password for invalid user\"\n| parse kind=relaxed SyslogMessage with * \"invalid user \" user \" from \" ip \" port\" port \" ssh2\" *\n// using distinct below as it has been seen that Syslog can duplicate entries depending on implementation\n| distinct TimeGenerated, Computer, user, ip, port, SyslogMessage, _ResourceId\n| summarize EventTimes = make_list(TimeGenerated), PerHourCount = count() by bin(TimeGenerated,4h), ip, Computer, user, _ResourceId\n| where PerHourCount > threshold\n| mvexpand EventTimes\n| extend EventTimes = tostring(EventTimes)\n| summarize StartTime = min(EventTimes), EndTime = max(EventTimes), UserList = make_set(user), ComputerList = make_set(Computer), ResourceIdList = make_set(_ResourceId), sum(PerHourCount) by IPAddress = ip\n// bringing through single computer and user if array only has 1, otherwise, referencing the column and hashing the ComputerList or UserList so we don't get accidental entity matches when reviewing alerts\n| extend HostName = iff(array_length(ComputerList) == 1, tostring(ComputerList[0]), strcat(\"SeeComputerListField\",\"_\", tostring(hash(tostring(ComputerList)))))\n| extend Account = iff(array_length(ComputerList) == 1, tostring(UserList[0]), strcat(\"SeeUserListField\",\"_\", tostring(hash(tostring(UserList)))))\n| extend ResourceId = iff(array_length(ResourceIdList) == 1, tostring(ResourceIdList[0]), strcat(\"SeeResourceIdListField\",\"_\", tostring(hash(tostring(ResourceIdList)))))" + }, + "schedule": { + "frequency": "P1D" + } + } + } + } + } + }, + "condition": "[and(parameters('DeployParser'), parameters('DeployCustomDetection'))]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-e1ce0eab-10d1-4aae-863f-9a383345ba88')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'Syslog-CD-xdr-e1ce0eab-10d1-4aae-863f-9a383345ba88')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'Identifies an IP address that had 15 failed attempts to sign in via SSH in a 4 hour block during a 24 hour time period.\n Please note that entity mapping for arrays is not supported, so when there is a single value in an array, we will pull that value from the array as a single string to populate the entity to support entity mapping features within Sentinel. Additionally, if the array is multivalued, we will input a string to indicate this with a unique hash so that matching will not occur.\n As an example - ComputerList is an array that we check for a single value and write that into the HostN", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-e1ce0eab-10d1-4aae-863f-9a383345ba88', 'xdr-e1ce0eab-10d1-4aae-863f-9a383345ba88')]", + "status": "disabled", + "displayName": "SSH - Potential Brute Force", + "detectionAction": { + "alertTemplate": { + "description": "'Identifies an IP address that had 15 failed attempts to sign in via SSH in a 4 hour block during a 24 hour time period.\n Please note that entity mapping for arrays is not supported, so when there is a single value in an array, we will pull that value from the array as a single string to populate the entity to support entity mapping features within Sentinel. Additionally, if the array is multivalued, we will input a string to indicate this with a unique hash so that matching will not occur.\n As an example - ComputerList is an array that we check for a single value and write that into the HostN", + "customDetails": { + "AccountName": "Account" + }, + "severity": "low", + "tactics": [ + { + "techniques": [ + { + "technique": "T1110" + } + ], + "tactic": "CredentialAccess" + } + ], + "title": "SSH - Potential Brute Force", + "entityMappings": { + "hosts": [ + { + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ], + "ips": [ + { + "id": "[if(true(), 'ip1', 'ip1')]", + "addressColumn": "IPAddress" + } + ], + "azureResources": [ + { + "id": "[if(true(), 'azureResource1', 'azureResource1')]", + "resourceIdColumn": "ResourceId" + } + ] + } + } + }, + "queryCondition": { + "queryText": "let threshold = 15;\nSyslog\n| where ProcessName =~ \"sshd\"\n| where SyslogMessage contains \"Failed password for invalid user\"\n| parse kind=relaxed SyslogMessage with * \"invalid user \" user \" from \" ip \" port\" port \" ssh2\" *\n// using distinct below as it has been seen that Syslog can duplicate entries depending on implementation\n| distinct TimeGenerated, Computer, user, ip, port, SyslogMessage, _ResourceId\n| summarize EventTimes = make_list(TimeGenerated), PerHourCount = count() by bin(TimeGenerated,4h), ip, Computer, user, _ResourceId\n| where PerHourCount > threshold\n| mvexpand EventTimes\n| extend EventTimes = tostring(EventTimes)\n| summarize StartTime = min(EventTimes), EndTime = max(EventTimes), UserList = make_set(user), ComputerList = make_set(Computer), ResourceIdList = make_set(_ResourceId), sum(PerHourCount) by IPAddress = ip\n// bringing through single computer and user if array only has 1, otherwise, referencing the column and hashing the ComputerList or UserList so we don't get accidental entity matches when reviewing alerts\n| extend HostName = iff(array_length(ComputerList) == 1, tostring(ComputerList[0]), strcat(\"SeeComputerListField\",\"_\", tostring(hash(tostring(ComputerList)))))\n| extend Account = iff(array_length(ComputerList) == 1, tostring(UserList[0]), strcat(\"SeeUserListField\",\"_\", tostring(hash(tostring(UserList)))))\n| extend ResourceId = iff(array_length(ResourceIdList) == 1, tostring(ResourceIdList[0]), strcat(\"SeeResourceIdListField\",\"_\", tostring(hash(tostring(ResourceIdList)))))" + }, + "schedule": { + "frequency": "P1D" + } + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-e1ce0eab-10d1-4aae-863f-9a383345ba88", + "contentKind": "CustomDetection", + "displayName": "SSH - Potential Brute Force", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-e1ce0eab-10d1-4aae-863f-9a383345ba88','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-e1ce0eab-10d1-4aae-863f-9a383345ba88','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "Syslog-CD-xdr-bb6a74c8-889d-4c6e-8412-7d5efe33f4ed", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-bb6a74c8-889d-4c6e-8412-7d5efe33f4ed', 'xdr-bb6a74c8-889d-4c6e-8412-7d5efe33f4ed')]", + "status": "disabled", + "displayName": "SFTP File transfer above threshold", + "detectionAction": { + "alertTemplate": { + "description": "'Identifies SFTP File Transfers above certain threshold in a 15min time period. It requires SFTP VERBOSE loglevel to be enabled.\n Please note that entity mapping for arrays is not supported, so when there is a single value in an array, we will pull that value from the array as a single string to populate the entity to support entity mapping features within Sentinel. Additionally, if the array is multivalued, we will input a string to indicate this with a unique hash so that matching will not occur.'", + "customDetails": { + "FilesList": "fileslist", + "FileSample": "FileSample", + "TransferCount": "count_distinct_filepath" + }, + "severity": "medium", + "tactics": [ + { + "techniques": [ + { + "technique": "T1020" + } + ], + "tactic": "Exfiltration" + } + ], + "title": "SFTP File transfer above threshold", + "entityMappings": { + "hosts": [ + { + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "Computer" + } + ], + "ips": [ + { + "id": "[if(true(), 'ip1', 'ip1')]", + "addressColumn": "src_ip" + } + ] + } + } + }, + "queryCondition": { + "queryText": "let threshold = 50;\nSyslog\n| where ProcessName has \"sftp\"\n and SyslogMessage has \"close \"\n and SyslogMessage has \" bytes read \"\n| parse SyslogMessage with \"close \\\"\" filepath \"\\\" bytes read \" readbytes: int \" written \" writtenbytes: int\n| join kind=leftouter (\n Syslog\n | where ProcessName has \"sftp\" and SyslogMessage has \"session opened for\"\n | parse SyslogMessage with \"session opened for local user \" username: string \" from [\" src_ip \"]\"\n | project username, src_ip, ProcessID\n )\n on ProcessID\n| project-away ProcessID1\n| summarize count_distinct_filepath=dcount(filepath), fileslist=make_set(filepath) by Computer, username, src_ip, bin(TimeGenerated, 15m)\n| where count_distinct_filepath >= threshold\n| extend FileSample = iff(array_length(fileslist) == 1, tostring(fileslist[0]), strcat(\"SeeFilesListField\",\"_\", tostring(hash(tostring(fileslist)))))" + }, + "schedule": { + "frequency": "PT15M" + } + } + } + } + } + }, + "condition": "[and(parameters('DeployParser'), parameters('DeployCustomDetection'))]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-bb6a74c8-889d-4c6e-8412-7d5efe33f4ed')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'Syslog-CD-xdr-bb6a74c8-889d-4c6e-8412-7d5efe33f4ed')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'Identifies SFTP File Transfers above certain threshold in a 15min time period. It requires SFTP VERBOSE loglevel to be enabled.\n Please note that entity mapping for arrays is not supported, so when there is a single value in an array, we will pull that value from the array as a single string to populate the entity to support entity mapping features within Sentinel. Additionally, if the array is multivalued, we will input a string to indicate this with a unique hash so that matching will not occur.'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-bb6a74c8-889d-4c6e-8412-7d5efe33f4ed', 'xdr-bb6a74c8-889d-4c6e-8412-7d5efe33f4ed')]", + "status": "disabled", + "displayName": "SFTP File transfer above threshold", + "detectionAction": { + "alertTemplate": { + "description": "'Identifies SFTP File Transfers above certain threshold in a 15min time period. It requires SFTP VERBOSE loglevel to be enabled.\n Please note that entity mapping for arrays is not supported, so when there is a single value in an array, we will pull that value from the array as a single string to populate the entity to support entity mapping features within Sentinel. Additionally, if the array is multivalued, we will input a string to indicate this with a unique hash so that matching will not occur.'", + "customDetails": { + "FilesList": "fileslist", + "FileSample": "FileSample", + "TransferCount": "count_distinct_filepath" + }, + "severity": "medium", + "tactics": [ + { + "techniques": [ + { + "technique": "T1020" + } + ], + "tactic": "Exfiltration" + } + ], + "title": "SFTP File transfer above threshold", + "entityMappings": { + "hosts": [ + { + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "Computer" + } + ], + "ips": [ + { + "id": "[if(true(), 'ip1', 'ip1')]", + "addressColumn": "src_ip" + } + ] + } + } + }, + "queryCondition": { + "queryText": "let threshold = 50;\nSyslog\n| where ProcessName has \"sftp\"\n and SyslogMessage has \"close \"\n and SyslogMessage has \" bytes read \"\n| parse SyslogMessage with \"close \\\"\" filepath \"\\\" bytes read \" readbytes: int \" written \" writtenbytes: int\n| join kind=leftouter (\n Syslog\n | where ProcessName has \"sftp\" and SyslogMessage has \"session opened for\"\n | parse SyslogMessage with \"session opened for local user \" username: string \" from [\" src_ip \"]\"\n | project username, src_ip, ProcessID\n )\n on ProcessID\n| project-away ProcessID1\n| summarize count_distinct_filepath=dcount(filepath), fileslist=make_set(filepath) by Computer, username, src_ip, bin(TimeGenerated, 15m)\n| where count_distinct_filepath >= threshold\n| extend FileSample = iff(array_length(fileslist) == 1, tostring(fileslist[0]), strcat(\"SeeFilesListField\",\"_\", tostring(hash(tostring(fileslist)))))" + }, + "schedule": { + "frequency": "PT15M" + } + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-bb6a74c8-889d-4c6e-8412-7d5efe33f4ed", + "contentKind": "CustomDetection", + "displayName": "SFTP File transfer above threshold", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-bb6a74c8-889d-4c6e-8412-7d5efe33f4ed','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-bb6a74c8-889d-4c6e-8412-7d5efe33f4ed','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "Syslog-CD-xdr-7355434e-09d5-4401-b56d-e03e9379dfb1", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-7355434e-09d5-4401-b56d-e03e9379dfb1', 'xdr-7355434e-09d5-4401-b56d-e03e9379dfb1')]", + "status": "disabled", + "displayName": "SFTP File transfer folder count above threshold", + "detectionAction": { + "alertTemplate": { + "description": "'Identifies SFTP File Transfers with distinct folder count above certain threshold in a 15min time period.\n It requires SFTP VERBOSE loglevel to be enabled.\n Please note that entity mapping for arrays is not supported, so when there is a single value in an array, we will pull that value from the array as a single string to populate the entity to support entity mapping features within Sentinel. Additionally, if the array is multivalued, we will input a string to indicate this with a unique hash so that matching will not occur.'", + "customDetails": { + "FilesList": "dirlist", + "DirSample": "DirSample", + "TransferCount": "count_distinct_dirpath" + }, + "severity": "medium", + "tactics": [ + { + "techniques": [ + { + "technique": "T1020" + } + ], + "tactic": "Exfiltration" + } + ], + "title": "SFTP File transfer folder count above threshold", + "entityMappings": { + "hosts": [ + { + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "Computer" + } + ], + "ips": [ + { + "id": "[if(true(), 'ip1', 'ip1')]", + "addressColumn": "src_ip" + } + ] + } + } + }, + "queryCondition": { + "queryText": "let threshold = 10;\nSyslog\n| where ProcessName has \"sftp\"\n and SyslogMessage has \"close \"\n and SyslogMessage has \" bytes read \"\n| parse SyslogMessage with \"close \\\"\" filepath \"\\\" bytes read \" readbytes: int \" written \" writtenbytes: int\n| parse kind=regex filepath with dirpath:string \"/\" filename:string\n| join kind=leftouter (\n Syslog\n | where ProcessName has \"sftp\" and SyslogMessage has \"session opened for\"\n | parse SyslogMessage with \"session opened for local user \" username: string \" from [\" src_ip \"]\"\n | project username, src_ip, ProcessID\n )\n on ProcessID\n| project-away ProcessID1\n| summarize count_distinct_dirpath=dcount(dirpath), dirlist=make_set(dirpath) by Computer, username, src_ip, bin(TimeGenerated, 15m)\n| where count_distinct_dirpath >= threshold\n| extend DirSample = iff(array_length(dirlist) == 1, tostring(dirlist[0]), strcat(\"SeeDirListField\",\"_\", tostring(hash(tostring(dirlist)))))" + }, + "schedule": { + "frequency": "PT15M" + } + } + } + } + } + }, + "condition": "[and(parameters('DeployParser'), parameters('DeployCustomDetection'))]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-7355434e-09d5-4401-b56d-e03e9379dfb1')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'Syslog-CD-xdr-7355434e-09d5-4401-b56d-e03e9379dfb1')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'Identifies SFTP File Transfers with distinct folder count above certain threshold in a 15min time period.\n It requires SFTP VERBOSE loglevel to be enabled.\n Please note that entity mapping for arrays is not supported, so when there is a single value in an array, we will pull that value from the array as a single string to populate the entity to support entity mapping features within Sentinel. Additionally, if the array is multivalued, we will input a string to indicate this with a unique hash so that matching will not occur.'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-7355434e-09d5-4401-b56d-e03e9379dfb1', 'xdr-7355434e-09d5-4401-b56d-e03e9379dfb1')]", + "status": "disabled", + "displayName": "SFTP File transfer folder count above threshold", + "detectionAction": { + "alertTemplate": { + "description": "'Identifies SFTP File Transfers with distinct folder count above certain threshold in a 15min time period.\n It requires SFTP VERBOSE loglevel to be enabled.\n Please note that entity mapping for arrays is not supported, so when there is a single value in an array, we will pull that value from the array as a single string to populate the entity to support entity mapping features within Sentinel. Additionally, if the array is multivalued, we will input a string to indicate this with a unique hash so that matching will not occur.'", + "customDetails": { + "FilesList": "dirlist", + "DirSample": "DirSample", + "TransferCount": "count_distinct_dirpath" + }, + "severity": "medium", + "tactics": [ + { + "techniques": [ + { + "technique": "T1020" + } + ], + "tactic": "Exfiltration" + } + ], + "title": "SFTP File transfer folder count above threshold", + "entityMappings": { + "hosts": [ + { + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "Computer" + } + ], + "ips": [ + { + "id": "[if(true(), 'ip1', 'ip1')]", + "addressColumn": "src_ip" + } + ] + } + } + }, + "queryCondition": { + "queryText": "let threshold = 10;\nSyslog\n| where ProcessName has \"sftp\"\n and SyslogMessage has \"close \"\n and SyslogMessage has \" bytes read \"\n| parse SyslogMessage with \"close \\\"\" filepath \"\\\" bytes read \" readbytes: int \" written \" writtenbytes: int\n| parse kind=regex filepath with dirpath:string \"/\" filename:string\n| join kind=leftouter (\n Syslog\n | where ProcessName has \"sftp\" and SyslogMessage has \"session opened for\"\n | parse SyslogMessage with \"session opened for local user \" username: string \" from [\" src_ip \"]\"\n | project username, src_ip, ProcessID\n )\n on ProcessID\n| project-away ProcessID1\n| summarize count_distinct_dirpath=dcount(dirpath), dirlist=make_set(dirpath) by Computer, username, src_ip, bin(TimeGenerated, 15m)\n| where count_distinct_dirpath >= threshold\n| extend DirSample = iff(array_length(dirlist) == 1, tostring(dirlist[0]), strcat(\"SeeDirListField\",\"_\", tostring(hash(tostring(dirlist)))))" + }, + "schedule": { + "frequency": "PT15M" + } + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-7355434e-09d5-4401-b56d-e03e9379dfb1", + "contentKind": "CustomDetection", + "displayName": "SFTP File transfer folder count above threshold", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-7355434e-09d5-4401-b56d-e03e9379dfb1','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-7355434e-09d5-4401-b56d-e03e9379dfb1','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "pid-1cf1db80-d519-4f89-b498-e97385a7cbb6-partnercenter", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [] + } + } } ], "outputs": {} diff --git a/Solutions/Syslog/Package/testParameters.json b/Solutions/Syslog/Package/testParameters.json index aef42689bbf..2b257e10a20 100644 --- a/Solutions/Syslog/Package/testParameters.json +++ b/Solutions/Syslog/Package/testParameters.json @@ -36,5 +36,47 @@ "metadata": { "description": "Name for the workbook" } + }, + "DeployAnalyticsRule": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Deploy the Microsoft Sentinel analytic rules carried by this solution (ContentKind AnalyticsRule and its AnalyticsRuleTemplate registration face)." + } + }, + "DeployWorkbook": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Deploy the Microsoft Sentinel workbook content and its Content Hub registration carried by this solution (ContentKind Workbook and WorkbookTemplate)." + } + }, + "DeployDataConnector": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Deploy the data connectors carried by this solution, together with their metadata and catalog entries (ContentKind DataConnector, ResourceDataConnector and DataType)." + } + }, + "DeployCustomDetection": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Deploy the XDR-native custom detection resources and their Content Hub registrations (ContentKind CustomDetection and CustomDetectionTemplate). Independent of DeployAnalyticsRule: both kinds can be selected together. Existing analytic-rule instances are not disabled or removed. CD enabled or disabled status is controlled separately from this deployment switch." + } + }, + "DeployHuntingQuery": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Deploy the Microsoft Sentinel hunting queries carried by this solution." + } + }, + "DeployParser": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Deploy the parsers and their registrations carried by this solution." + } } } diff --git a/Solutions/Syslog/ReleaseNotes.md b/Solutions/Syslog/ReleaseNotes.md index 1137f4b7e77..367261bfe07 100644 --- a/Solutions/Syslog/ReleaseNotes.md +++ b/Solutions/Syslog/ReleaseNotes.md @@ -1,5 +1,6 @@ | **Version** | **Date Modified (DD-MM-YYYY)** | **Change History** | |-------------|--------------------------------|--------------------------------------------------------------------| +| 3.1.2 | 12-10-2026 | Added seven disabled **Defender XDR Custom Detections** converted from Syslog **Analytic Rules**, with source provenance. Offline structural validation passed; runtime validation was not performed. | | 3.0.7 | 04-11-2024 | Updated the Syslog **Data Connector** template to latest version | | 3.0.6 | 01-08-2024 | Updated **Analytic rules** for entity mappings and parameter for parser function | | 3.0.5 | 16-07-2024 | Added 2 new Workspace Function **Parsers** and a new **Workbook** | diff --git a/Solutions/Syslog/SolutionMetadata.json b/Solutions/Syslog/SolutionMetadata.json index 04f586b2d32..00e9ddb1c35 100644 --- a/Solutions/Syslog/SolutionMetadata.json +++ b/Solutions/Syslog/SolutionMetadata.json @@ -1,16 +1,22 @@ { - "publisherId": "azuresentinel", - "offerId": "azure-sentinel-solution-syslog", - "firstPublishDate": "2022-05-23", - "providers": ["Microsoft"], - "categories": { - "domains" : ["IT Operations"], - "verticals": [] - }, - "support": { - "name": "Microsoft Corporation", - "email": "support@microsoft.com", - "tier": "Microsoft", - "link": "https://support.microsoft.com" - } -} \ No newline at end of file + "trackingId": "pid-1cf1db80-d519-4f89-b498-e97385a7cbb6-partnercenter", + "publisherId": "azuresentinel", + "offerId": "azure-sentinel-solution-syslog", + "firstPublishDate": "2022-05-23", + "providers": [ + "Microsoft" + ], + "categories": { + "domains": [ + "IT Operations" + ], + "verticals": [] + }, + "support": { + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "tier": "Microsoft", + "link": "https://support.microsoft.com" + }, + "version": "3.1.2" +} diff --git a/Solutions/Syslog/XDR Detections/FailedLogonAttempts_UnknownUser.yaml b/Solutions/Syslog/XDR Detections/FailedLogonAttempts_UnknownUser.yaml new file mode 100644 index 00000000000..11eade36fed --- /dev/null +++ b/Solutions/Syslog/XDR Detections/FailedLogonAttempts_UnknownUser.yaml @@ -0,0 +1,122 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: Syslog + dataTypes: + - Syslog +- connectorId: SyslogAma + dataTypes: + - Syslog +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: e7ec9fa6-e7f7-41ed-a34b-b956837a3ee6 + path: Analytic Rules/FailedLogonAttempts_UnknownUser.yaml + version: 1.0.5 + querySha256: f05d75464d053f17049485947f0c87326885c6790cd9072e2cfd7e313491f9ce + schedule: + queryFrequency: 1d + queryPeriod: 1d + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - 'Schedule assessment: source frequency=1d, lookback=1d; target frequency=P1D, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `Computer`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - Host.FullName value is retained as customDetails.HostFullName from query column `Computer`, but its target output binding + requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.HostFullName column `Computer` requires runtime output-schema binding verification + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: [] + errors: [] + originalTactics: + - CredentialAccess + originalTechniques: + - T1110 + reviewScope: + sourceDocumentSha256: 94e174abb303b6b039c02a9b18d693002ea846aebed1136e5c13c3098c4b96b4 + targetQuerySha256: 4121065aed1cd830a0ee9c6af2c1a2e2142cb0d6ab7451c0a55722f22295898d + reviewDecisions: + - reason: 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented + by hosts.nameColumn `Computer`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + decision: accepted + sourceDocumentSha256: 94e174abb303b6b039c02a9b18d693002ea846aebed1136e5c13c3098c4b96b4 + targetQuerySha256: 4121065aed1cd830a0ee9c6af2c1a2e2142cb0d6ab7451c0a55722f22295898d + supplementalEntityDetails: + - entityType: Host + entityIndex: 1 + identifier: FullName + sourceColumn: Computer + column: Computer + status: runtime-binding-pending + customDetailKey: HostFullName + acceptedReviewReasons: + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `Computer`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' +properties: + id: xdr-e7ec9fa6-e7f7-41ed-a34b-b956837a3ee6 + displayName: Failed logon attempts in authpriv + status: disabled + queryCondition: + queryText: |- + let threshold = 15; + // Below pulls messages from syslog-authpriv logs where there was an authentication failure with an unknown user. + // IP address of system attempting logon is also extracted from the SyslogMessage field. Some of these messages + // are aggregated. + Syslog + | where Facility =~ "authpriv" + | where SyslogMessage has "authentication failure" and SyslogMessage has " uid=0" + | extend RemoteIP = extract(@".*?rhost=([\d.]+).*?", 1,SyslogMessage) + | project TimeGenerated, Computer, ProcessName, HostIP, RemoteIP, ProcessID + | join kind=innerunique ( + // Below pulls messages from syslog-authpriv logs that show each instance an unknown user tried to logon. + Syslog + | where Facility =~ "authpriv" + | where SyslogMessage has "user unknown" + | project Computer, HostIP, ProcessID + ) on Computer, HostIP, ProcessID + // Count the number of failed logon attempts by External IP and internal machine + | summarize FirstLogonAttempt = min(TimeGenerated), LatestLogonAttempt = max(TimeGenerated), TotalLogonAttempts = count() by Computer, HostIP, RemoteIP + // Calculate the time between first and last logon attempt (AttemptPeriodLength) + | extend TimeBetweenLogonAttempts = LatestLogonAttempt - FirstLogonAttempt + | where TotalLogonAttempts >= threshold + | project FirstLogonAttempt, LatestLogonAttempt, TimeBetweenLogonAttempts, TotalLogonAttempts, SourceAddress = RemoteIP, Computer, HostIP + | sort by Computer asc nulls last + schedule: + frequency: P1D + detectionAction: + alertTemplate: + title: Failed logon attempts in authpriv + description: "'Identifies failed logon attempts from unknown users in Syslog authpriv logs. The unknown user means the\ + \ account that tried to log in isn't provisioned on the machine. A few hits could indicate someone attempting to access\ + \ a machine they aren't authorized to access. \nIf there are many of hits, especially from outside your network, it\ + \ could indicate a brute force attack. \nDefault threshold for logon attempts is 15.'" + severity: medium + entityMappings: + hosts: + - id: host1 + nameColumn: Computer + ips: + - id: ip1 + addressColumn: HostIP + tactics: + - tactic: CredentialAccess + techniques: + - technique: T1110 + customDetails: + HostFullName: Computer diff --git a/Solutions/Syslog/XDR Detections/NRT_squid_events_for_mining_pools.yaml b/Solutions/Syslog/XDR Detections/NRT_squid_events_for_mining_pools.yaml new file mode 100644 index 00000000000..64e69ec6312 --- /dev/null +++ b/Solutions/Syslog/XDR Detections/NRT_squid_events_for_mining_pools.yaml @@ -0,0 +1,109 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: Syslog + dataTypes: + - Syslog +- connectorId: SyslogAma + dataTypes: + - Syslog +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: dd03057e-4347-4853-bf1e-2b2d21eb4e59 + path: Analytic Rules/NRT_squid_events_for_mining_pools.yaml + version: 1.0.1 + querySha256: b2bd678529381e36c8792c1fa3ac15ab7b8d2e72eaff67c0b2378f61f4d11751 + schedule: + queryFrequency: '' + queryPeriod: '' + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - 'Schedule assessment: source frequency=unknown, lookback=unknown; target frequency=PT1H, native lookback=unknown/unconfigured; + source NRT timing is not preserved by the emitted scheduled frequency. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - Account mapping is incomplete and was removed + - Account.FullName value is retained as customDetails.AccountFullName from query column `User`, but its target output + binding requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.AccountFullName column `User` requires runtime output-schema binding verification + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: [] + errors: [] + originalTactics: + - CommandAndControl + originalTechniques: + - T1102 + reviewScope: + sourceDocumentSha256: 7664b8ff18fc9fdf46b026b73772fb01c76d5dfda26b6047abf0a06e5f6160b1 + targetQuerySha256: bacee1cc34481202d0db3998b53c46ed974a562d50dbb172833e3a0fef1e6322 + supplementalEntityDetails: + - entityType: Account + entityIndex: 1 + identifier: FullName + sourceColumn: User + column: User + status: runtime-binding-pending + customDetailKey: AccountFullName +properties: + id: xdr-dd03057e-4347-4853-bf1e-2b2d21eb4e59 + displayName: NRT Squid proxy events related to mining pools + status: disabled + queryCondition: + queryText: |- + let DomainList = dynamic(["monerohash.com", "do-dear.com", "xmrminerpro.com", "secumine.net", "xmrpool.com", "minexmr.org", "hashanywhere.com", "xmrget.com", + "mininglottery.eu", "minergate.com", "moriaxmr.com", "multipooler.com", "moneropools.com", "xmrpool.eu", "coolmining.club", "supportxmr.com", + "minexmr.com", "hashvault.pro", "xmrpool.net", "crypto-pool.fr", "xmr.pt", "miner.rocks", "walpool.com", "herominers.com", "gntl.co.uk", "semipool.com", + "coinfoundry.org", "cryptoknight.cc", "fairhash.org", "baikalmine.com", "tubepool.xyz", "fairpool.xyz", "asiapool.io", "coinpoolit.webhop.me", "nanopool.org", + "moneropool.com", "miner.center", "prohash.net", "poolto.be", "cryptoescrow.eu", "monerominers.net", "cryptonotepool.org", "extrmepool.org", "webcoin.me", + "kippo.eu", "hashinvest.ws", "monero.farm", "supportxmr.com", "xmrpool.eu", "linux-repository-updates.com", "1gh.com", "dwarfpool.com", "hash-to-coins.com", + "hashvault.pro", "pool-proxy.com", "hashfor.cash", "fairpool.cloud", "litecoinpool.org", "mineshaft.ml", "abcxyz.stream", "moneropool.ru", "cryptonotepool.org.uk", + "extremepool.org", "extremehash.com", "hashinvest.net", "unipool.pro", "crypto-pools.org", "monero.net", "backup-pool.com", "mooo.com", "freeyy.me", "cryptonight.net", + "shscrypto.net"]); + Syslog + | 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), + Status = extract("(TCP_(([A-Z]+)(_[A-Z]+)*)|UDP_(([A-Z]+)(_[A-Z]+)*))",1,SyslogMessage), + HTTP_Status_Code = extract("(TCP_(([A-Z]+)(_[A-Z]+)*)|UDP_(([A-Z]+)(_[A-Z]+)*))/([0-9]{3})",8,SyslogMessage), + User = extract("(CONNECT |GET )([^ ]* )([^ ]+)",3,SyslogMessage), + RemotePort = extract("(CONNECT |GET )([^ ]*)(:)([0-9]*)",4,SyslogMessage), + Domain = extract("(([A-Z]+ [a-z]{4,5}:\\/\\/)|[A-Z]+ )([^ :\\/]*)",3,SyslogMessage), + Bytes = toint(extract("([A-Z]+\\/[0-9]{3} )([0-9]+)",2,SyslogMessage)), + contentType = extract("([a-z/]+$)",1,SyslogMessage) + | extend TLD = extract("\\.[a-z]*$",0,Domain) + | where HTTP_Status_Code == '200' + | where Domain contains "." + | where Domain has_any (DomainList) + schedule: + frequency: PT1H + detectionAction: + alertTemplate: + title: NRT Squid proxy events related to mining pools + description: |- + 'Checks for Squid proxy events in Syslog associated with common mining pools .This query presumes the default Squid log format is being used. + http://www.squid-cache.org/Doc/config/access_log/' + severity: low + entityMappings: + ips: + - id: ip1 + addressColumn: SourceIP + urls: + - id: url1 + addressColumn: URL + tactics: + - tactic: CommandAndControl + techniques: + - technique: T1102 + customDetails: + AccountFullName: User diff --git a/Solutions/Syslog/XDR Detections/sftp_file_transfer_above_threshold.yaml b/Solutions/Syslog/XDR Detections/sftp_file_transfer_above_threshold.yaml new file mode 100644 index 00000000000..422addf5882 --- /dev/null +++ b/Solutions/Syslog/XDR Detections/sftp_file_transfer_above_threshold.yaml @@ -0,0 +1,120 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: Syslog + dataTypes: + - Syslog +- connectorId: SyslogAma + dataTypes: + - Syslog +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: bb6a74c8-889d-4c6e-8412-7d5efe33f4ed + path: Analytic Rules/sftp_file_transfer_above_threshold.yaml + version: 1.0.2 + querySha256: 229e6a2a0d68cb93844c47305c44c893315f0ea38992d247a65131c3179a3bef + schedule: + queryFrequency: 15m + queryPeriod: 15m + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - 'Schedule assessment: source frequency=15m, lookback=15m; target frequency=PT15M, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - entity mappings were resolved by the configured per-rule override + - Unconfirmed generic Account.Name mapping was omitted because another required Host, Mailbox, or IP asset is available + - customDetails 'TransferCount' column `count_distinct_filepath` has an unproven output binding after a destructive projection; + the explicit binding is retained, but static analysis cannot establish its output and runtime output-schema verification + is required + - customDetails 'FilesList' column `fileslist` has an unproven output binding after a destructive projection; the explicit + binding is retained, but static analysis cannot establish its output and runtime output-schema verification is required + - customDetails 'FileSample' column `FileSample` has an unproven output binding after a destructive projection; the explicit + binding is retained, but static analysis cannot establish its output and runtime output-schema verification is required + - Account.Name output column `username` cannot be proven after a destructive projection; no supplemental customDetails + binding was added and KQL was not rewritten. Runtime output-schema verification is required + - File.Name output column `FileSample` cannot be proven after a destructive projection; no supplemental customDetails + binding was added and KQL was not rewritten. Runtime output-schema verification is required + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: [] + errors: [] + originalTactics: + - Exfiltration + originalTechniques: + - T1020 + reviewScope: + sourceDocumentSha256: 5d34e02aa59b8055179bd394d2839b4ecd047f2ae298ac4b7ab9d789177246e1 + targetQuerySha256: c97c66cb95887fc9121a9ba5e3a9340558efe04bb948ff548b345dc2c1cf7b5a + supplementalEntityDetails: + - entityType: Account + entityIndex: 1 + identifier: Name + sourceColumn: username + column: username + status: unproven-destructive-projection + reason: unproven-destructive-projection + - entityType: File + entityIndex: 4 + identifier: Name + sourceColumn: FileSample + column: FileSample + status: unproven-destructive-projection + reason: unproven-destructive-projection +properties: + id: xdr-bb6a74c8-889d-4c6e-8412-7d5efe33f4ed + displayName: SFTP File transfer above threshold + status: disabled + queryCondition: + queryText: |- + let threshold = 50; + Syslog + | where ProcessName has "sftp" + and SyslogMessage has "close " + and SyslogMessage has " bytes read " + | parse SyslogMessage with "close \"" filepath "\" bytes read " readbytes: int " written " writtenbytes: int + | join kind=leftouter ( + Syslog + | where ProcessName has "sftp" and SyslogMessage has "session opened for" + | parse SyslogMessage with "session opened for local user " username: string " from [" src_ip "]" + | project username, src_ip, ProcessID + ) + on ProcessID + | project-away ProcessID1 + | summarize count_distinct_filepath=dcount(filepath), fileslist=make_set(filepath) by Computer, username, src_ip, bin(TimeGenerated, 15m) + | where count_distinct_filepath >= threshold + | extend FileSample = iff(array_length(fileslist) == 1, tostring(fileslist[0]), strcat("SeeFilesListField","_", tostring(hash(tostring(fileslist))))) + schedule: + frequency: PT15M + detectionAction: + alertTemplate: + title: SFTP File transfer above threshold + description: |- + 'Identifies SFTP File Transfers above certain threshold in a 15min time period. It requires SFTP VERBOSE loglevel to be enabled. + Please note that entity mapping for arrays is not supported, so when there is a single value in an array, we will pull that value from the array as a single string to populate the entity to support entity mapping features within Sentinel. Additionally, if the array is multivalued, we will input a string to indicate this with a unique hash so that matching will not occur.' + severity: medium + entityMappings: + ips: + - id: ip1 + addressColumn: src_ip + hosts: + - id: host1 + nameColumn: Computer + tactics: + - tactic: Exfiltration + techniques: + - technique: T1020 + customDetails: + TransferCount: count_distinct_filepath + FilesList: fileslist + FileSample: FileSample diff --git a/Solutions/Syslog/XDR Detections/sftp_file_transfer_folders_above_threshold.yaml b/Solutions/Syslog/XDR Detections/sftp_file_transfer_folders_above_threshold.yaml new file mode 100644 index 00000000000..6d3f148092c --- /dev/null +++ b/Solutions/Syslog/XDR Detections/sftp_file_transfer_folders_above_threshold.yaml @@ -0,0 +1,122 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: Syslog + dataTypes: + - Syslog +- connectorId: SyslogAma + dataTypes: + - Syslog +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: 7355434e-09d5-4401-b56d-e03e9379dfb1 + path: Analytic Rules/sftp_file_transfer_folders_above_threshold.yaml + version: 1.0.2 + querySha256: 8daccb633fccaa9d478b094eb88b2f48eb8f55378a903c7a7b1633bbf36dea5c + schedule: + queryFrequency: 15m + queryPeriod: 15m + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - 'Schedule assessment: source frequency=15m, lookback=15m; target frequency=PT15M, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - entity mappings were resolved by the configured per-rule override + - Unconfirmed generic Account.Name mapping was omitted because another required Host, Mailbox, or IP asset is available + - customDetails 'TransferCount' column `count_distinct_dirpath` has an unproven output binding after a destructive projection; + the explicit binding is retained, but static analysis cannot establish its output and runtime output-schema verification + is required + - customDetails 'FilesList' column `dirlist` has an unproven output binding after a destructive projection; the explicit + binding is retained, but static analysis cannot establish its output and runtime output-schema verification is required + - customDetails 'DirSample' column `DirSample` has an unproven output binding after a destructive projection; the explicit + binding is retained, but static analysis cannot establish its output and runtime output-schema verification is required + - Account.Name output column `username` cannot be proven after a destructive projection; no supplemental customDetails + binding was added and KQL was not rewritten. Runtime output-schema verification is required + - File.Name output column `DirSample` cannot be proven after a destructive projection; no supplemental customDetails binding + was added and KQL was not rewritten. Runtime output-schema verification is required + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: [] + errors: [] + originalTactics: + - Exfiltration + originalTechniques: + - T1020 + reviewScope: + sourceDocumentSha256: 5ff1c7403c00b955d1a3f533cbd2d6917ae65ed0c582466b0382c40e9063f06b + targetQuerySha256: 78f79a95695ace45b69c1f4abd358b1c837d9460cf61167ba0341249381a1324 + supplementalEntityDetails: + - entityType: Account + entityIndex: 1 + identifier: Name + sourceColumn: username + column: username + status: unproven-destructive-projection + reason: unproven-destructive-projection + - entityType: File + entityIndex: 4 + identifier: Name + sourceColumn: DirSample + column: DirSample + status: unproven-destructive-projection + reason: unproven-destructive-projection +properties: + id: xdr-7355434e-09d5-4401-b56d-e03e9379dfb1 + displayName: SFTP File transfer folder count above threshold + status: disabled + queryCondition: + queryText: |- + let threshold = 10; + Syslog + | where ProcessName has "sftp" + and SyslogMessage has "close " + and SyslogMessage has " bytes read " + | parse SyslogMessage with "close \"" filepath "\" bytes read " readbytes: int " written " writtenbytes: int + | parse kind=regex filepath with dirpath:string "/" filename:string + | join kind=leftouter ( + Syslog + | where ProcessName has "sftp" and SyslogMessage has "session opened for" + | parse SyslogMessage with "session opened for local user " username: string " from [" src_ip "]" + | project username, src_ip, ProcessID + ) + on ProcessID + | project-away ProcessID1 + | summarize count_distinct_dirpath=dcount(dirpath), dirlist=make_set(dirpath) by Computer, username, src_ip, bin(TimeGenerated, 15m) + | where count_distinct_dirpath >= threshold + | extend DirSample = iff(array_length(dirlist) == 1, tostring(dirlist[0]), strcat("SeeDirListField","_", tostring(hash(tostring(dirlist))))) + schedule: + frequency: PT15M + detectionAction: + alertTemplate: + title: SFTP File transfer folder count above threshold + description: |- + 'Identifies SFTP File Transfers with distinct folder count above certain threshold in a 15min time period. + It requires SFTP VERBOSE loglevel to be enabled. + Please note that entity mapping for arrays is not supported, so when there is a single value in an array, we will pull that value from the array as a single string to populate the entity to support entity mapping features within Sentinel. Additionally, if the array is multivalued, we will input a string to indicate this with a unique hash so that matching will not occur.' + severity: medium + entityMappings: + ips: + - id: ip1 + addressColumn: src_ip + hosts: + - id: host1 + nameColumn: Computer + tactics: + - tactic: Exfiltration + techniques: + - technique: T1020 + customDetails: + TransferCount: count_distinct_dirpath + FilesList: dirlist + DirSample: DirSample diff --git a/Solutions/Syslog/XDR Detections/squid_cryptomining_pools.yaml b/Solutions/Syslog/XDR Detections/squid_cryptomining_pools.yaml new file mode 100644 index 00000000000..f4300f3ed9a --- /dev/null +++ b/Solutions/Syslog/XDR Detections/squid_cryptomining_pools.yaml @@ -0,0 +1,113 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: Syslog + dataTypes: + - Syslog +- connectorId: SyslogAma + dataTypes: + - Syslog +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: 80733eb7-35b2-45b6-b2b8-3c51df258206 + path: Analytic Rules/squid_cryptomining_pools.yaml + version: 1.0.4 + querySha256: 1b51dd89594816d34352297cad67b94c78fd97072ede888f754bc6fb9adf4620 + schedule: + queryFrequency: 1d + queryPeriod: 1d + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - 'Schedule assessment: source frequency=1d, lookback=1d; target frequency=P1D, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - Account.FullName value is retained as customDetails.AccountFullName from query column `User`, but its target output + binding requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.AccountFullName column `User` requires runtime output-schema binding verification + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: [] + errors: [] + originalTactics: + - CommandAndControl + originalTechniques: + - T1102 + reviewScope: + sourceDocumentSha256: 156d7b5e8983896b704219eda2ffd436e40a5bf509a4fbd62e8c04533ff4cd38 + targetQuerySha256: 4b985fa9aaae408f77f3d0219fb0d8183a142ff46ebf5bbc48eb565a33aff55b + supplementalEntityDetails: + - entityType: Account + entityIndex: 1 + identifier: FullName + sourceColumn: User + column: User + status: runtime-binding-pending + customDetailKey: AccountFullName +properties: + id: xdr-80733eb7-35b2-45b6-b2b8-3c51df258206 + displayName: Squid proxy events related to mining pools + status: disabled + queryCondition: + queryText: |- + let DomainList = dynamic(["monerohash.com", "do-dear.com", "xmrminerpro.com", "secumine.net", "xmrpool.com", "minexmr.org", "hashanywhere.com", "xmrget.com", + "mininglottery.eu", "minergate.com", "moriaxmr.com", "multipooler.com", "moneropools.com", "xmrpool.eu", "coolmining.club", "supportxmr.com", + "minexmr.com", "hashvault.pro", "xmrpool.net", "crypto-pool.fr", "xmr.pt", "miner.rocks", "walpool.com", "herominers.com", "gntl.co.uk", "semipool.com", + "coinfoundry.org", "cryptoknight.cc", "fairhash.org", "baikalmine.com", "tubepool.xyz", "fairpool.xyz", "asiapool.io", "coinpoolit.webhop.me", "nanopool.org", + "moneropool.com", "miner.center", "prohash.net", "poolto.be", "cryptoescrow.eu", "monerominers.net", "cryptonotepool.org", "extrmepool.org", "webcoin.me", + "kippo.eu", "hashinvest.ws", "monero.farm", "supportxmr.com", "xmrpool.eu", "linux-repository-updates.com", "1gh.com", "dwarfpool.com", "hash-to-coins.com", + "hashvault.pro", "pool-proxy.com", "hashfor.cash", "fairpool.cloud", "litecoinpool.org", "mineshaft.ml", "abcxyz.stream", "moneropool.ru", "cryptonotepool.org.uk", + "extremepool.org", "extremehash.com", "hashinvest.net", "unipool.pro", "crypto-pools.org", "monero.net", "backup-pool.com", "mooo.com", "freeyy.me", "cryptonight.net", + "shscrypto.net"]); + Syslog + | 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), + Status = extract("(TCP_(([A-Z]+)(_[A-Z]+)*)|UDP_(([A-Z]+)(_[A-Z]+)*))",1,SyslogMessage), + HTTP_Status_Code = extract("(TCP_(([A-Z]+)(_[A-Z]+)*)|UDP_(([A-Z]+)(_[A-Z]+)*))/([0-9]{3})",8,SyslogMessage), + User = extract("(CONNECT |GET )([^ ]* )([^ ]+)",3,SyslogMessage), + RemotePort = extract("(CONNECT |GET )([^ ]*)(:)([0-9]*)",4,SyslogMessage), + Domain = extract("(([A-Z]+ [a-z]{4,5}:\\/\\/)|[A-Z]+ )([^ :\\/]*)",3,SyslogMessage), + Bytes = toint(extract("([A-Z]+\\/[0-9]{3} )([0-9]+)",2,SyslogMessage)), + contentType = extract("([a-z/]+$)",1,SyslogMessage) + | extend TLD = extract("\\.[a-z]*$",0,Domain) + | where HTTP_Status_Code == '200' + | where Domain contains "." + | where Domain has_any (DomainList) + | extend AccountName = tostring(split(User, "@")[0]), AccountUPNSuffix = tostring(split(User, "@")[1]) + schedule: + frequency: P1D + detectionAction: + alertTemplate: + title: Squid proxy events related to mining pools + description: |- + 'Checks for Squid proxy events in Syslog associated with common mining pools. This query presumes the default Squid log format is being used. + http://www.squid-cache.org/Doc/config/access_log/' + severity: low + entityMappings: + accounts: + - id: account1 + nameColumn: AccountName + upnSuffixColumn: AccountUPNSuffix + ips: + - id: ip1 + addressColumn: SourceIP + urls: + - id: url1 + addressColumn: URL + tactics: + - tactic: CommandAndControl + techniques: + - technique: T1102 + customDetails: + AccountFullName: User diff --git a/Solutions/Syslog/XDR Detections/squid_tor_proxies.yaml b/Solutions/Syslog/XDR Detections/squid_tor_proxies.yaml new file mode 100644 index 00000000000..b59ef8bf6d0 --- /dev/null +++ b/Solutions/Syslog/XDR Detections/squid_tor_proxies.yaml @@ -0,0 +1,110 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: Syslog + dataTypes: + - Syslog +- connectorId: SyslogAma + dataTypes: + - Syslog +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: 90d3f6ec-80fb-48e0-9937-2c70c9df9bad + path: Analytic Rules/squid_tor_proxies.yaml + version: 1.0.3 + querySha256: 04dc098452e9ed7461dd1a09f8716e535716b4d540b225675bec6b8679ab1037 + schedule: + queryFrequency: 1d + queryPeriod: 1d + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - 'Schedule assessment: source frequency=1d, lookback=1d; target frequency=P1D, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - Account.FullName value is retained as customDetails.AccountFullName from query column `User`, but its target output + binding requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.AccountFullName column `User` requires runtime output-schema binding verification + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: [] + errors: [] + originalTactics: + - CommandAndControl + originalTechniques: + - T1090 + - T1008 + reviewScope: + sourceDocumentSha256: 389dac28d4d5b0010403538999ed1f29d3220876094bf8ca1296b2c68c666a13 + targetQuerySha256: 18abb2bca0f1e27a99b7ac0f002b321bc78ffcd17189d837b636a1801e50f90a + supplementalEntityDetails: + - entityType: Account + entityIndex: 1 + identifier: FullName + sourceColumn: User + column: User + status: runtime-binding-pending + customDetailKey: AccountFullName +properties: + id: xdr-90d3f6ec-80fb-48e0-9937-2c70c9df9bad + displayName: Squid proxy events for ToR proxies + status: disabled + queryCondition: + queryText: |- + let DomainList = dynamic(["tor2web.org", "tor2web.com", "torlink.co", "onion.to", "onion.ink", "onion.cab", "onion.nu", "onion.link", + "onion.it", "onion.city", "onion.direct", "onion.top", "onion.casa", "onion.plus", "onion.rip", "onion.dog", "tor2web.fi", + "tor2web.blutmagie.de", "onion.sh", "onion.lu", "onion.pet", "t2w.pw", "tor2web.ae.org", "tor2web.io", "tor2web.xyz", "onion.lt", + "s1.tor-gateways.de", "s2.tor-gateways.de", "s3.tor-gateways.de", "s4.tor-gateways.de", "s5.tor-gateways.de", "hiddenservice.net"]); + Syslog + | 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), + Status = extract("(TCP_(([A-Z]+)(_[A-Z]+)*)|UDP_(([A-Z]+)(_[A-Z]+)*))",1,SyslogMessage), + HTTP_Status_Code = extract("(TCP_(([A-Z]+)(_[A-Z]+)*)|UDP_(([A-Z]+)(_[A-Z]+)*))/([0-9]{3})",8,SyslogMessage), + User = extract("(CONNECT |GET )([^ ]* )([^ ]+)",3,SyslogMessage), + RemotePort = extract("(CONNECT |GET )([^ ]*)(:)([0-9]*)",4,SyslogMessage), + Domain = extract("(([A-Z]+ [a-z]{4,5}:\\/\\/)|[A-Z]+ )([^ :\\/]*)",3,SyslogMessage), + Bytes = toint(extract("([A-Z]+\\/[0-9]{3} )([0-9]+)",2,SyslogMessage)), + contentType = extract("([a-z/]+$)",1,SyslogMessage) + | extend TLD = extract("\\.[a-z]*$",0,Domain) + | where HTTP_Status_Code == "200" + | where Domain contains "." + | where Domain has_any (DomainList) + | extend AccountName = tostring(split(User, "@")[0]), AccountUPNSuffix = tostring(split(User, "@")[1]) + schedule: + frequency: P1D + detectionAction: + alertTemplate: + title: Squid proxy events for ToR proxies + description: |- + 'Check for Squid proxy events associated with common ToR proxies. This query presumes the default squid log format is being used. + http://www.squid-cache.org/Doc/config/access_log/' + severity: low + entityMappings: + accounts: + - id: account1 + nameColumn: AccountName + upnSuffixColumn: AccountUPNSuffix + ips: + - id: ip1 + addressColumn: SourceIP + urls: + - id: url1 + addressColumn: URL + tactics: + - tactic: CommandAndControl + techniques: + - technique: T1090 + - technique: T1008 + customDetails: + AccountFullName: User diff --git a/Solutions/Syslog/XDR Detections/ssh_potentialBruteForce.yaml b/Solutions/Syslog/XDR Detections/ssh_potentialBruteForce.yaml new file mode 100644 index 00000000000..8f067757139 --- /dev/null +++ b/Solutions/Syslog/XDR Detections/ssh_potentialBruteForce.yaml @@ -0,0 +1,105 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: Syslog + dataTypes: + - Syslog +- connectorId: SyslogAma + dataTypes: + - Syslog +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: e1ce0eab-10d1-4aae-863f-9a383345ba88 + path: Analytic Rules/ssh_potentialBruteForce.yaml + version: 1.1.5 + querySha256: ac7da7d8c114e0094deb9fa76da84e129777348e9acdeac514c516bf2a4d3ad0 + schedule: + queryFrequency: 1d + queryPeriod: 1d + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - 'Schedule assessment: source frequency=1d, lookback=1d; target frequency=P1D, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - Unconfirmed generic Account.Name mapping was omitted because another required Host, Mailbox, or IP asset is available + - Account.Name value is retained as customDetails.AccountName from query column `Account`, but its target output binding + requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.AccountName column `Account` requires runtime output-schema binding verification + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: [] + errors: [] + originalTactics: + - CredentialAccess + originalTechniques: + - T1110 + reviewScope: + sourceDocumentSha256: c15d907e9006c0fc23260a54abf1ef6e097f493dbd5f243f77226881cc7c503e + targetQuerySha256: 376a1e17496299ba43c0bb3f925b6f842df52251273cdd956d163904a278d9ff + supplementalEntityDetails: + - entityType: Account + entityIndex: 1 + identifier: Name + sourceColumn: Account + column: Account + status: runtime-binding-pending + customDetailKey: AccountName +properties: + id: xdr-e1ce0eab-10d1-4aae-863f-9a383345ba88 + displayName: SSH - Potential Brute Force + status: disabled + queryCondition: + queryText: |- + let threshold = 15; + Syslog + | where ProcessName =~ "sshd" + | where SyslogMessage contains "Failed password for invalid user" + | parse kind=relaxed SyslogMessage with * "invalid user " user " from " ip " port" port " ssh2" * + // using distinct below as it has been seen that Syslog can duplicate entries depending on implementation + | distinct TimeGenerated, Computer, user, ip, port, SyslogMessage, _ResourceId + | summarize EventTimes = make_list(TimeGenerated), PerHourCount = count() by bin(TimeGenerated,4h), ip, Computer, user, _ResourceId + | where PerHourCount > threshold + | mvexpand EventTimes + | extend EventTimes = tostring(EventTimes) + | summarize StartTime = min(EventTimes), EndTime = max(EventTimes), UserList = make_set(user), ComputerList = make_set(Computer), ResourceIdList = make_set(_ResourceId), sum(PerHourCount) by IPAddress = ip + // bringing through single computer and user if array only has 1, otherwise, referencing the column and hashing the ComputerList or UserList so we don't get accidental entity matches when reviewing alerts + | extend HostName = iff(array_length(ComputerList) == 1, tostring(ComputerList[0]), strcat("SeeComputerListField","_", tostring(hash(tostring(ComputerList))))) + | extend Account = iff(array_length(ComputerList) == 1, tostring(UserList[0]), strcat("SeeUserListField","_", tostring(hash(tostring(UserList))))) + | extend ResourceId = iff(array_length(ResourceIdList) == 1, tostring(ResourceIdList[0]), strcat("SeeResourceIdListField","_", tostring(hash(tostring(ResourceIdList))))) + schedule: + frequency: P1D + detectionAction: + alertTemplate: + title: SSH - Potential Brute Force + description: |- + 'Identifies an IP address that had 15 failed attempts to sign in via SSH in a 4 hour block during a 24 hour time period. + Please note that entity mapping for arrays is not supported, so when there is a single value in an array, we will pull that value from the array as a single string to populate the entity to support entity mapping features within Sentinel. Additionally, if the array is multivalued, we will input a string to indicate this with a unique hash so that matching will not occur. + As an example - ComputerList is an array that we check for a single value and write that into the HostN + severity: low + entityMappings: + ips: + - id: ip1 + addressColumn: IPAddress + hosts: + - id: host1 + nameColumn: HostName + azureResources: + - id: azureResource1 + resourceIdColumn: ResourceId + tactics: + - tactic: CredentialAccess + techniques: + - technique: T1110 + customDetails: + AccountName: Account diff --git a/Solutions/Windows Security Events/Analytic Rules/ADFSRemoteAuthSyncConnection.yaml b/Solutions/Windows Security Events/Analytic Rules/ADFSRemoteAuthSyncConnection.yaml index 8aea6b00119..db67984a85b 100644 --- a/Solutions/Windows Security Events/Analytic Rules/ADFSRemoteAuthSyncConnection.yaml +++ b/Solutions/Windows Security Events/Analytic Rules/ADFSRemoteAuthSyncConnection.yaml @@ -1,10 +1,10 @@ id: 2f4165a6-c4fb-4e94-861e-37f1b4d6c0e6 name: AD FS Remote Auth Sync Connection description: | - 'This detection uses Security events from the "AD FS Auditing" provider to detect suspicious authentication events on an AD FS server. The results then get correlated with events from the Windows Filtering Platform (WFP) to detect suspicious incoming network traffic on port 80 on the AD FS server. - This could be a sign of a threat actor trying to use replication services on the AD FS server to get its configuration settings and extract sensitive information such as AD FS certificates. In order to use this query you need to enable AD FS auditing on the AD FS Server. + 'Identifies suspicious AD FS authentication by correlating Security events from "AD FS Auditing" with Windows Filtering Platform (WFP) events for incoming port 80 traffic. + This may indicate a threat actor abusing AD FS replication services to obtain configuration settings and sensitive information such as AD FS certificates. Enable AD FS auditing on the AD FS server before using this query. References: - https://docs.microsoft.com/windows-server/identity/ad-fs/troubleshooting/ad-fs-tshoot-logging + https://learn.microsoft.com/en-us/windows-server/identity/ad-fs/troubleshooting/ad-fs-tshoot-logging https://twitter.com/OTR_Community/status/1387038995016732672' severity: Medium requiredDataConnectors: @@ -108,5 +108,5 @@ entityMappings: fieldMappings: - identifier: Address columnName: SourceAddress -version: 1.0.4 +version: 3.1.2 kind: Scheduled \ No newline at end of file diff --git a/Solutions/Windows Security Events/Analytic Rules/ScheduleTaskHide.yaml b/Solutions/Windows Security Events/Analytic Rules/ScheduleTaskHide.yaml index 704279a975e..ec18307d74a 100644 --- a/Solutions/Windows Security Events/Analytic Rules/ScheduleTaskHide.yaml +++ b/Solutions/Windows Security Events/Analytic Rules/ScheduleTaskHide.yaml @@ -1,10 +1,10 @@ id: 6dd2629c-534b-4275-8201-d7968b4fa77e name: Scheduled Task Hide description: | - 'This query detects attempts by malware to hide the scheduled task by deleting the SD (Security Descriptor) value. Removal of SD value results in the scheduled task disappearing from schtasks /query and Task Scheduler. - The query requires auditing to be turned on for HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree registry hive as well as audit policy for registry auditing to be turned on. - Reference: https://www.microsoft.com/security/blog/2022/04/12/tarrask-malware-uses-scheduled-tasks-for-defense-evasion/ - Reference: https://4sysops.com/archives/audit-changes-in-the-windows-registry/' + 'Identifies malware hiding scheduled tasks by deleting the SD (Security Descriptor) value, making tasks disappear from schtasks /query and Task Scheduler. + Enable registry auditing policy and auditing on HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree. + Reference: https://www.microsoft.com/en-us/security/blog/2022/04/12/tarrask-malware-uses-scheduled-tasks-for-defense-evasion/ + Reference: https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/auditing/audit-registry' severity: High requiredDataConnectors: - connectorId: SecurityEvents @@ -55,5 +55,5 @@ entityMappings: columnName: HostName - identifier: DnsDomain columnName: HostNameDomain -version: 1.0.1 +version: 3.1.2 kind: Scheduled diff --git a/Solutions/Windows Security Events/Data/Solution_Windows Security Events.json b/Solutions/Windows Security Events/Data/Solution_Windows Security Events.json index c685b07ee35..655ee753560 100644 --- a/Solutions/Windows Security Events/Data/Solution_Windows Security Events.json +++ b/Solutions/Windows Security Events/Data/Solution_Windows Security Events.json @@ -16,19 +16,19 @@ "Analytic Rules/GainCodeExecutionADFSViaSMB.yaml", "Analytic Rules/LocalDeviceJoinInfoAndTransportKeyRegKeysAccess.yaml", "Analytic Rules/MultipleFailedFollowedBySuccess.yaml", - "Analytic Rules/NewEXEdeployedviaDefaultDomainorDefaultDomainControllerPolicies.yaml", - "Analytic Rules/NonDCActiveDirectoryReplication.yaml", + "Analytic Rules/NRT_SecurityEventLogCleared.yaml", "Analytic Rules/NRT_base64_encoded_pefile.yaml", "Analytic Rules/NRT_execute_base64_decodedpayload.yaml", - "Analytic Rules/NRT_SecurityEventLogCleared.yaml", - "Analytic Rules/password_not_set.yaml", + "Analytic Rules/NewEXEdeployedviaDefaultDomainorDefaultDomainControllerPolicies.yaml", + "Analytic Rules/NonDCActiveDirectoryReplication.yaml", "Analytic Rules/PotentialFodhelperUACBypass.yaml", "Analytic Rules/Potentialre-namedsdeleteusage.yaml", "Analytic Rules/ScheduleTaskHide.yaml", "Analytic Rules/SdeletedeployedviaGPOandrunrecursively.yaml", "Analytic Rules/StartStopHealthService.yaml", "Analytic Rules/TimeSeriesAnomaly-ProcessExecutions.yaml", - "Analytic Rules/WMI-Abuse.yaml" + "Analytic Rules/WMI-Abuse.yaml", + "Analytic Rules/password_not_set.yaml" ], "Workbooks": [ "Workbooks/EventAnalyzer.json", @@ -87,8 +87,31 @@ "Hunting Queries/WindowsSystemShutdownReboot.yaml" ], "BasePath": "C:\\GitHub\\Azure-Sentinel\\Solutions\\Windows Security Events\\", - "Version": "3.0.13", "TemplateSpec": true, "StaticDataConnector": true, - "Metadata": "SolutionMetadata.json" + "Metadata": "SolutionMetadata.json", + "XDR Detections": [ + "XDR Detections/ADFSDBNamedPipeConnection.yaml", + "XDR Detections/ADFSRemoteAuthSyncConnection.yaml", + "XDR Detections/ADFSRemoteHTTPNetworkConnection.yaml", + "XDR Detections/ExcessiveLogonFailures.yaml", + "XDR Detections/ExchangeOABVirtualDirectoryAttributeContainingPotentialWebshell.yaml", + "XDR Detections/GainCodeExecutionADFSViaSMB.yaml", + "XDR Detections/LocalDeviceJoinInfoAndTransportKeyRegKeysAccess.yaml", + "XDR Detections/MultipleFailedFollowedBySuccess.yaml", + "XDR Detections/NRT_SecurityEventLogCleared.yaml", + "XDR Detections/NRT_base64_encoded_pefile.yaml", + "XDR Detections/NRT_execute_base64_decodedpayload.yaml", + "XDR Detections/NewEXEdeployedviaDefaultDomainorDefaultDomainControllerPolicies.yaml", + "XDR Detections/NonDCActiveDirectoryReplication.yaml", + "XDR Detections/PotentialFodhelperUACBypass.yaml", + "XDR Detections/Potentialre-namedsdeleteusage.yaml", + "XDR Detections/ScheduleTaskHide.yaml", + "XDR Detections/SdeletedeployedviaGPOandrunrecursively.yaml", + "XDR Detections/StartStopHealthService.yaml", + "XDR Detections/TimeSeriesAnomaly-ProcessExecutions.yaml", + "XDR Detections/WMI-Abuse.yaml", + "XDR Detections/password_not_set.yaml" + ], + "Version": "3.1.2" } diff --git a/Solutions/Windows Security Events/Hunting Queries/NewChildProcessOfW3WP.yaml b/Solutions/Windows Security Events/Hunting Queries/NewChildProcessOfW3WP.yaml index ece35e7776c..920bc366f82 100644 --- a/Solutions/Windows Security Events/Hunting Queries/NewChildProcessOfW3WP.yaml +++ b/Solutions/Windows Security Events/Hunting Queries/NewChildProcessOfW3WP.yaml @@ -5,7 +5,7 @@ description: | description-detailed: | 'This Hunting Query looks for child processes of w3wp.exe that have not been seen as a child process on that host within the last 14 days. w3wp.exe running suspicious processes such as 'cmd.exe /c echo', 'certutil.exe', or 'powershell.exe' that result in the creation of script files in web -accessible folders is a rare event and is, thus, typically a strong sign of web server compromise and web shell installation. - Ref: https://www.microsoft.com/security/blog/2021/02/11/web-shell-attacks-continue-to-rise/' + Ref: https://www.microsoft.com/en-us/security/blog/2021/02/11/web-shell-attacks-continue-to-rise/' requiredDataConnectors: - connectorId: SecurityEvents dataTypes: @@ -45,4 +45,4 @@ entityMappings: fieldMappings: - identifier: FullName columnName: HostCustomEntity -version: 1.0.0 \ No newline at end of file +version: 3.1.2 \ No newline at end of file diff --git a/Solutions/Windows Security Events/Hunting Queries/Suspicious_enumeration_using_adfind.yaml b/Solutions/Windows Security Events/Hunting Queries/Suspicious_enumeration_using_adfind.yaml index 538899515c2..6a6bccd937a 100644 --- a/Solutions/Windows Security Events/Hunting Queries/Suspicious_enumeration_using_adfind.yaml +++ b/Solutions/Windows Security Events/Hunting Queries/Suspicious_enumeration_using_adfind.yaml @@ -8,7 +8,7 @@ description-detailed: | Below references talk about suspicious use of Adfind by adversaries. - https://thedfirreport.com/2020/05/08/adfind-recon/ - https://www.fireeye.com/blog/threat-research/2020/05/tactics-techniques-procedures-associated-with-maze-ransomware-incidents.html - - https://www.microsoft.com/security/blog/2020/12/18/analyzing-solorigate-the-compromised-dll-file-that-started-a-sophisticated-cyberattack-and-how-microsoft-defender-helps-protect/ + - https://www.microsoft.com/en-us/security/blog/2020/12/18/analyzing-solorigate-the-compromised-dll-file-that-started-a-sophisticated-cyberattack-and-how-microsoft-defender-helps-protect/ requiredDataConnectors: - connectorId: SecurityEvents dataTypes: @@ -62,4 +62,4 @@ entityMappings: columnName: HostName - identifier: DnsDomain columnName: DnsDomain -version: 1.0.2 +version: 3.1.2 diff --git a/Solutions/Windows Security Events/Package/3.1.2.zip b/Solutions/Windows Security Events/Package/3.1.2.zip new file mode 100644 index 00000000000..2f3e5abacbf Binary files /dev/null and b/Solutions/Windows Security Events/Package/3.1.2.zip differ diff --git a/Solutions/Windows Security Events/Package/createUiDefinition.json b/Solutions/Windows Security Events/Package/createUiDefinition.json index 87b11a16bf7..b659c652806 100644 --- a/Solutions/Windows Security Events/Package/createUiDefinition.json +++ b/Solutions/Windows Security Events/Package/createUiDefinition.json @@ -6,7 +6,7 @@ "config": { "isWizard": false, "basics": { - "description": "Note: Please refer to the following before installing the solution:
\n• Review the solution Release Notes
\n• There may be known issues pertaining to this Solution, please refer to them before installing.
\nThe Windows Security Events solution for Microsoft Sentinel allows you to ingest Security events from your Windows machines using the Windows Agent into Microsoft Sentinel. This solution includes two (2) data connectors to help ingest the logs.
\nWindows Security Events via AMA - This data connector helps in ingesting Security Events logs into your Log Analytics Workspace using the new Azure Monitor Agent. Learn more about ingesting using the new Azure Monitor Agent here. Microsoft recommends using this Data Connector.
\nSecurity Events via Legacy Agent - This data connector helps in ingesting Security Events logs into your Log Analytics Workspace using the legacy Log Analytics agent.
\nData Connectors: 2, Workbooks: 2, Analytic Rules: 21, Hunting Queries: 50
\nLearn more about Microsoft Sentinel | Learn more about Solutions
\n", + "descriptionHtml": "Note: Please refer to the following before installing the solution:
\n• Review the solution Release Notes
\n• There may be known issues pertaining to this Solution, please refer to them before installing.
\nThe Windows Security Events solution for Microsoft Sentinel allows you to ingest Security events from your Windows machines using the Windows Agent into Microsoft Sentinel. This solution includes two (2) data connectors to help ingest the logs.
\nWindows Security Events via AMA - This data connector helps in ingesting Security Events logs into your Log Analytics Workspace using the new Azure Monitor Agent. Learn more about ingesting using the new Azure Monitor Agent here. Microsoft recommends using this Data Connector.
\nSecurity Events via Legacy Agent - This data connector helps in ingesting Security Events logs into your Log Analytics Workspace using the legacy Log Analytics agent.
\nData Connectors: 2, Workbooks: 2, Analytic Rules: 21, XDR Detections: 21, Hunting Queries: 50
\nLearn more about Microsoft Sentinel | Learn more about Solutions
\n", "contentKind": "Solution", "contentProductId": "[variables('_solutioncontentProductId')]", "id": "[variables('_solutioncontentProductId')]", @@ -8763,20 +8877,3767 @@ "kind": "HuntingQuery", "contentId": "[variables('huntingQueryObject50')._huntingQuerycontentId50]", "version": "[variables('huntingQueryObject50').huntingQueryVersion50]" - } - ] - }, - "firstPublishDate": "2022-05-23", - "providers": [ - "Microsoft" - ], - "categories": { - "domains": [ - "Security - Threat Protection" - ] - } - }, - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/', variables('_solutionId'))]" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-dcdf9bfc-c239-4764-a9f9-3612e6dff49c", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-2f4165a6-c4fb-4e94-861e-37f1b4d6c0e6", + "version": "3.1.2" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-d57c33a9-76b9-40e0-9dfa-ff0404546410", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-2391ce61-8c8d-41ac-9723-d945b2e90720", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-faf1a6ff-53b5-4f92-8c55-4b20e9957594", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-12dcea64-bec2-41c9-9df2-9f28461b1295", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-a356c8bd-c81d-428b-aa36-83be706be034", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-cf3ede88-a429-493b-9108-3e46d3c741f7", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-508cef41-2cd8-4d40-a519-b04826a9085f", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-c3e5dbaa-a540-408c-8b36-68bdfb3df088", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-7ad4c32b-d0d2-411c-a0e8-b557afa12fce", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-05b4bccd-dd12-423d-8de4-5a6fb526bb4f", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-b9d2eebc-5dcb-4888-8165-900db44443ab", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-56f3f35c-3aca-4437-a1fb-b7a84dc4af00", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-720d12c6-a08c-44c4-b18f-2236412d59b0", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-6dd2629c-534b-4275-8201-d7968b4fa77e", + "version": "3.1.2" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-d9f28fdf-abc8-4f1a-a7e7-1aaec87a2fc5", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-2bc7b4ae-eeaa-4538-ba15-ef298ec1ffae", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-2c55fe7a-b06f-4029-a5b9-c54a2320d7b8", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-3c8e5f0b-1d4a-4b69-9c2e-7f0d3a5e8b1f", + "version": "3.1.0" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-62085097-d113-459f-9ea7-30216f2ee6af", + "version": "3.1.0" + } + ] + }, + "firstPublishDate": "2022-05-23", + "providers": [ + "Microsoft" + ], + "categories": { + "domains": [ + "Security - Threat Protection" + ] + } + }, + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/', variables('_solutionId'))]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "WindowsSecurityEvents-CD-xdr-dcdf9bfc-c239-4764-a9f9-36-e0cabe0e", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-dcdf9bfc-c239-4764-a9f9-3612e6dff49c', 'xdr-dcdf9bfc-c239-4764-a9f9-3612e6dff49c')]", + "queryCondition": { + "queryText": "// Adjust this to use a longer timeframe to identify ADFS servers\n//let lookback = 6d;\n// Adjust this to adjust the key export detection timeframe\n//let timeframe = 1d;\n// Start be identifying ADFS servers to reduce FP chance\nlet ADFS_Servers = (\nEvent\n//| where TimeGenerated > ago(timeframe+lookback)\n| where Source == \"Microsoft-Windows-Sysmon\"\n| where EventID == 18\n| extend EventData = parse_xml(EventData).DataItem.EventData.Data\n| mv-expand bagexpansion=array EventData\n| evaluate bag_unpack(EventData)\n| extend Key = tostring(column_ifexists('@Name', \"\")), Value = column_ifexists('#text', \"\")\n| evaluate pivot(Key, any(Value), TimeGenerated, Source, EventLog, Computer, EventLevel, EventLevelName, EventID, UserName, MG, ManagementGroupName, _ResourceId)\n| extend Image = column_ifexists(\"Image\", \"\")\n| extend process = split(Image, '\\\\', -1)[-1]\n| where process =~ \"Microsoft.IdentityServer.ServiceHost.exe\"\n| summarize by Computer);\n// Look for ADFS servers where Named Pipes event are present\nEvent\n//| where TimeGenerated > ago(timeframe)\n| where Source == \"Microsoft-Windows-Sysmon\"\n| where EventID == 18\n| where Computer in~ (ADFS_Servers)\n| extend RenderedDescription = tostring(split(RenderedDescription, \":\")[0])\n| extend EventData = parse_xml(EventData).DataItem.EventData.Data\n| mv-expand bagexpansion=array EventData\n| evaluate bag_unpack(EventData)\n| extend Key = tostring(column_ifexists('@Name', \"\")), Value = column_ifexists('#text', \"\")\n| evaluate pivot(Key, any(Value), TimeGenerated, Source, EventLog, Computer, EventLevel, EventLevelName, EventID, UserName, RenderedDescription, MG, ManagementGroupName, Type, _ResourceId)\n| extend RuleName = column_ifexists(\"RuleName\", \"\"),\n TechniqueId = column_ifexists(\"TechniqueId\", \"\"),\n TechniqueName = column_ifexists(\"TechniqueName\", \"\"),\n Image = column_ifexists(\"Image\", \"\"),\n PipeName = column_ifexists(\"PipeName\", \"\"),\n EventType = column_ifexists(\"EventType\", \"\")\n| parse RuleName with * 'technique_id=' TechniqueId ',' * 'technique_name=' TechniqueName\n// Look for Pipe related to querying the WID\n| where PipeName == \"\\\\MICROSOFT##WID\\\\tsql\\\\query\"\n| extend process = split(Image, '\\\\', -1)[-1]\n// Exclude expected processes\n| where process !in (\"Microsoft.IdentityServer.ServiceHost.exe\", \"Microsoft.Identity.Health.Adfs.PshSurrogate.exe\", \"AzureADConnect.exe\", \"Microsoft.Tri.Sensor.exe\", \"wsmprovhost.exe\",\"mmc.exe\", \"sqlservr.exe\")\n| extend Operation = RenderedDescription\n| project-reorder TimeGenerated, EventType, Operation, process, Image, Computer, UserName\n| extend HostName = tostring(split(Computer, \".\")[0]), DomainIndex = toint(indexof(Computer, '.'))\n| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)\n| extend AccountName = tostring(split(UserName, @'\\')[1]), AccountNTDomain = tostring(split(UserName, @'\\')[0])" + }, + "schedule": { + "frequency": "P1D" + }, + "detectionAction": { + "alertTemplate": { + "title": "ADFS Database Named Pipe Connection", + "description": "'This detection uses Sysmon telemetry to detect suspicious local connections via a named pipe to the AD FS configuration database (Windows Internal Database).\nIn order to use this query you need to be collecting Sysmon EventIdD 18 (Pipe Connected).\nIf you do not have Sysmon data in your workspace this query will raise an error stating:\nFailed to resolve scalar expression named \"[@Name]\"'", + "tactics": [ + { + "tactic": "Collection", + "techniques": [ + { + "technique": "T1005" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "dnsDomainColumn": "HostNameDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ] + }, + "severity": "medium", + "customDetails": { + "AccountName": "AccountName", + "AccountNTDomain": "AccountNTDomain", + "HostFullName": "Computer", + "AccountFullName": "UserName" + } + } + }, + "status": "disabled", + "displayName": "ADFS Database Named Pipe Connection" + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-dcdf9bfc-c239-4764-a9f9-3612e6dff49c')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'WindowsSecurityEvents-CD-xdr-dcdf9bfc-c239-4764-a9f9-36-e0cabe0e')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'This detection uses Sysmon telemetry to detect suspicious local connections via a named pipe to the AD FS configuration database (Windows Internal Database).\nIn order to use this query you need to be collecting Sysmon EventIdD 18 (Pipe Connected).\nIf you do not have Sysmon data in your workspace this query will raise an error stating:\nFailed to resolve scalar expression named \"[@Name]\"'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-dcdf9bfc-c239-4764-a9f9-3612e6dff49c', 'xdr-dcdf9bfc-c239-4764-a9f9-3612e6dff49c')]", + "queryCondition": { + "queryText": "// Adjust this to use a longer timeframe to identify ADFS servers\n//let lookback = 6d;\n// Adjust this to adjust the key export detection timeframe\n//let timeframe = 1d;\n// Start be identifying ADFS servers to reduce FP chance\nlet ADFS_Servers = (\nEvent\n//| where TimeGenerated > ago(timeframe+lookback)\n| where Source == \"Microsoft-Windows-Sysmon\"\n| where EventID == 18\n| extend EventData = parse_xml(EventData).DataItem.EventData.Data\n| mv-expand bagexpansion=array EventData\n| evaluate bag_unpack(EventData)\n| extend Key = tostring(column_ifexists('@Name', \"\")), Value = column_ifexists('#text', \"\")\n| evaluate pivot(Key, any(Value), TimeGenerated, Source, EventLog, Computer, EventLevel, EventLevelName, EventID, UserName, MG, ManagementGroupName, _ResourceId)\n| extend Image = column_ifexists(\"Image\", \"\")\n| extend process = split(Image, '\\\\', -1)[-1]\n| where process =~ \"Microsoft.IdentityServer.ServiceHost.exe\"\n| summarize by Computer);\n// Look for ADFS servers where Named Pipes event are present\nEvent\n//| where TimeGenerated > ago(timeframe)\n| where Source == \"Microsoft-Windows-Sysmon\"\n| where EventID == 18\n| where Computer in~ (ADFS_Servers)\n| extend RenderedDescription = tostring(split(RenderedDescription, \":\")[0])\n| extend EventData = parse_xml(EventData).DataItem.EventData.Data\n| mv-expand bagexpansion=array EventData\n| evaluate bag_unpack(EventData)\n| extend Key = tostring(column_ifexists('@Name', \"\")), Value = column_ifexists('#text', \"\")\n| evaluate pivot(Key, any(Value), TimeGenerated, Source, EventLog, Computer, EventLevel, EventLevelName, EventID, UserName, RenderedDescription, MG, ManagementGroupName, Type, _ResourceId)\n| extend RuleName = column_ifexists(\"RuleName\", \"\"),\n TechniqueId = column_ifexists(\"TechniqueId\", \"\"),\n TechniqueName = column_ifexists(\"TechniqueName\", \"\"),\n Image = column_ifexists(\"Image\", \"\"),\n PipeName = column_ifexists(\"PipeName\", \"\"),\n EventType = column_ifexists(\"EventType\", \"\")\n| parse RuleName with * 'technique_id=' TechniqueId ',' * 'technique_name=' TechniqueName\n// Look for Pipe related to querying the WID\n| where PipeName == \"\\\\MICROSOFT##WID\\\\tsql\\\\query\"\n| extend process = split(Image, '\\\\', -1)[-1]\n// Exclude expected processes\n| where process !in (\"Microsoft.IdentityServer.ServiceHost.exe\", \"Microsoft.Identity.Health.Adfs.PshSurrogate.exe\", \"AzureADConnect.exe\", \"Microsoft.Tri.Sensor.exe\", \"wsmprovhost.exe\",\"mmc.exe\", \"sqlservr.exe\")\n| extend Operation = RenderedDescription\n| project-reorder TimeGenerated, EventType, Operation, process, Image, Computer, UserName\n| extend HostName = tostring(split(Computer, \".\")[0]), DomainIndex = toint(indexof(Computer, '.'))\n| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)\n| extend AccountName = tostring(split(UserName, @'\\')[1]), AccountNTDomain = tostring(split(UserName, @'\\')[0])" + }, + "schedule": { + "frequency": "P1D" + }, + "detectionAction": { + "alertTemplate": { + "title": "ADFS Database Named Pipe Connection", + "description": "'This detection uses Sysmon telemetry to detect suspicious local connections via a named pipe to the AD FS configuration database (Windows Internal Database).\nIn order to use this query you need to be collecting Sysmon EventIdD 18 (Pipe Connected).\nIf you do not have Sysmon data in your workspace this query will raise an error stating:\nFailed to resolve scalar expression named \"[@Name]\"'", + "tactics": [ + { + "tactic": "Collection", + "techniques": [ + { + "technique": "T1005" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "dnsDomainColumn": "HostNameDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ] + }, + "severity": "medium", + "customDetails": { + "AccountName": "AccountName", + "AccountNTDomain": "AccountNTDomain", + "HostFullName": "Computer", + "AccountFullName": "UserName" + } + } + }, + "status": "disabled", + "displayName": "ADFS Database Named Pipe Connection" + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-dcdf9bfc-c239-4764-a9f9-3612e6dff49c", + "contentKind": "CustomDetection", + "displayName": "ADFS Database Named Pipe Connection", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-dcdf9bfc-c239-4764-a9f9-3612e6dff49c','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-dcdf9bfc-c239-4764-a9f9-3612e6dff49c','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "WindowsSecurityEvents-CD-xdr-2f4165a6-c4fb-4e94-861e-37-0911b0ff", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-2f4165a6-c4fb-4e94-861e-37f1b4d6c0e6', 'xdr-2f4165a6-c4fb-4e94-861e-37f1b4d6c0e6')]", + "queryCondition": { + "queryText": "// Adjust this to use a longer timeframe to identify ADFS servers\n//let lookback = 0d;\n// Adjust this to adjust detection timeframe\n//let timeframe = 1d;\n// SamAccountName of AD FS Service Account. Filter on the use of a specific AD FS user account\n//let adfsuser = 'adfsadmin';\n// Identify ADFS Servers\nlet ADFS_Servers = (\n SecurityEvent\n //| where TimeGenerated > ago(timeframe+lookback)\n | where EventSourceName == 'AD FS Auditing'\n | distinct Computer\n);\nSecurityEvent\n //| where TimeGenerated > ago(timeframe)\n | where Computer in~ (ADFS_Servers)\n // A token of type 'http://schemas.microsoft.com/ws/2006/05/servicemodel/tokens/SecureConversation'\n // for relying party '-' was successfully authenticated.\n | where EventID == 412\n | extend EventData = parse_xml(EventData).EventData.Data\n | extend InstanceId = tostring(EventData[0])\n| join kind=inner\n(\n SecurityEvent\n //| where TimeGenerated > ago(timeframe)\n | where Computer in~ (ADFS_Servers)\n // Events to identify caller identity from event 412\n | where EventID == 501\n | extend EventData = parse_xml(EventData).EventData.Data\n | where tostring(EventData[1]) contains 'identity/claims/name'\n | extend InstanceId = tostring(EventData[0])\n | extend ClaimsName = tostring(EventData[2])\n // Filter on the use of a specific AD FS user account\n //| where ClaimsName contains adfsuser\n)\non $left.InstanceId == $right.InstanceId\n| join kind=inner\n(\n SecurityEvent\n | where EventID == 5156\n | where Computer in~ (ADFS_Servers)\n | extend EventData = parse_xml(EventData).EventData.Data\n | mv-expand bagexpansion=array EventData\n | evaluate bag_unpack(EventData)\n | extend Key = tostring(column_ifexists('@Name', \"\")), Value = column_ifexists('#text', \"\")\n | evaluate pivot(Key, any(Value), TimeGenerated, Computer, EventID)\n | extend DestPort = column_ifexists(\"DestPort\", \"\"),\n Direction = column_ifexists(\"Direction\", \"\"),\n Application = column_ifexists(\"Application\", \"\"),\n DestAddress = column_ifexists(\"DestAddress\", \"\"),\n SourceAddress = column_ifexists(\"SourceAddress\", \"\"),\n SourcePort = column_ifexists(\"SourcePort\", \"\")\n // Look for inbound connections from endpoints on port 80\n | where DestPort == 80 and Direction == '%%14592' and Application == 'System'\n | where DestAddress !in ('::1','0:0:0:0:0:0:0:1')\n)\non $left.Computer == $right.Computer\n| project TimeGenerated, Computer, ClaimsName, SourceAddress, SourcePort\n| extend HostName = tostring(split(Computer, \".\")[0]), DomainIndex = toint(indexof(Computer, '.'))\n| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)\n| extend AccountName = tostring(split(ClaimsName, @'\\')[1]), AccountNTDomain = tostring(split(ClaimsName, @'\\')[0])" + }, + "schedule": { + "frequency": "P1D" + }, + "detectionAction": { + "alertTemplate": { + "title": "AD FS Remote Auth Sync Connection", + "description": "'Identifies suspicious AD FS authentication by correlating Security events from \"AD FS Auditing\" with Windows Filtering Platform (WFP) events for incoming port 80 traffic.\nThis may indicate a threat actor abusing AD FS replication services to obtain configuration settings and sensitive information such as AD FS certificates. Enable AD FS auditing on the AD FS server before using this query.\nReferences:\nhttps://learn.microsoft.com/en-us/windows-server/identity/ad-fs/troubleshooting/ad-fs-tshoot-logging\nhttps://twitter.com/OTR_Community/status/1387038995016732672'", + "tactics": [ + { + "tactic": "Collection", + "techniques": [ + { + "technique": "T1005" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "dnsDomainColumn": "HostNameDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ], + "ips": [ + { + "id": "[if(true(), 'ip1', 'ip1')]", + "addressColumn": "SourceAddress" + } + ] + }, + "severity": "medium", + "customDetails": { + "AccountName": "AccountName", + "HostFullName": "Computer", + "AccountFullName": "ClaimsName" + } + } + }, + "status": "disabled", + "displayName": "AD FS Remote Auth Sync Connection" + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-2f4165a6-c4fb-4e94-861e-37f1b4d6c0e6')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'WindowsSecurityEvents-CD-xdr-2f4165a6-c4fb-4e94-861e-37-0911b0ff')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'Identifies suspicious AD FS authentication by correlating Security events from \"AD FS Auditing\" with Windows Filtering Platform (WFP) events for incoming port 80 traffic.\nThis may indicate a threat actor abusing AD FS replication services to obtain configuration settings and sensitive information such as AD FS certificates. Enable AD FS auditing on the AD FS server before using this query.\nReferences:\nhttps://learn.microsoft.com/en-us/windows-server/identity/ad-fs/troubleshooting/ad-fs-tshoot-logging\nhttps://twitter.com/OTR_Community/status/1387038995016732672'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-2f4165a6-c4fb-4e94-861e-37f1b4d6c0e6', 'xdr-2f4165a6-c4fb-4e94-861e-37f1b4d6c0e6')]", + "queryCondition": { + "queryText": "// Adjust this to use a longer timeframe to identify ADFS servers\n//let lookback = 0d;\n// Adjust this to adjust detection timeframe\n//let timeframe = 1d;\n// SamAccountName of AD FS Service Account. Filter on the use of a specific AD FS user account\n//let adfsuser = 'adfsadmin';\n// Identify ADFS Servers\nlet ADFS_Servers = (\n SecurityEvent\n //| where TimeGenerated > ago(timeframe+lookback)\n | where EventSourceName == 'AD FS Auditing'\n | distinct Computer\n);\nSecurityEvent\n //| where TimeGenerated > ago(timeframe)\n | where Computer in~ (ADFS_Servers)\n // A token of type 'http://schemas.microsoft.com/ws/2006/05/servicemodel/tokens/SecureConversation'\n // for relying party '-' was successfully authenticated.\n | where EventID == 412\n | extend EventData = parse_xml(EventData).EventData.Data\n | extend InstanceId = tostring(EventData[0])\n| join kind=inner\n(\n SecurityEvent\n //| where TimeGenerated > ago(timeframe)\n | where Computer in~ (ADFS_Servers)\n // Events to identify caller identity from event 412\n | where EventID == 501\n | extend EventData = parse_xml(EventData).EventData.Data\n | where tostring(EventData[1]) contains 'identity/claims/name'\n | extend InstanceId = tostring(EventData[0])\n | extend ClaimsName = tostring(EventData[2])\n // Filter on the use of a specific AD FS user account\n //| where ClaimsName contains adfsuser\n)\non $left.InstanceId == $right.InstanceId\n| join kind=inner\n(\n SecurityEvent\n | where EventID == 5156\n | where Computer in~ (ADFS_Servers)\n | extend EventData = parse_xml(EventData).EventData.Data\n | mv-expand bagexpansion=array EventData\n | evaluate bag_unpack(EventData)\n | extend Key = tostring(column_ifexists('@Name', \"\")), Value = column_ifexists('#text', \"\")\n | evaluate pivot(Key, any(Value), TimeGenerated, Computer, EventID)\n | extend DestPort = column_ifexists(\"DestPort\", \"\"),\n Direction = column_ifexists(\"Direction\", \"\"),\n Application = column_ifexists(\"Application\", \"\"),\n DestAddress = column_ifexists(\"DestAddress\", \"\"),\n SourceAddress = column_ifexists(\"SourceAddress\", \"\"),\n SourcePort = column_ifexists(\"SourcePort\", \"\")\n // Look for inbound connections from endpoints on port 80\n | where DestPort == 80 and Direction == '%%14592' and Application == 'System'\n | where DestAddress !in ('::1','0:0:0:0:0:0:0:1')\n)\non $left.Computer == $right.Computer\n| project TimeGenerated, Computer, ClaimsName, SourceAddress, SourcePort\n| extend HostName = tostring(split(Computer, \".\")[0]), DomainIndex = toint(indexof(Computer, '.'))\n| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)\n| extend AccountName = tostring(split(ClaimsName, @'\\')[1]), AccountNTDomain = tostring(split(ClaimsName, @'\\')[0])" + }, + "schedule": { + "frequency": "P1D" + }, + "detectionAction": { + "alertTemplate": { + "title": "AD FS Remote Auth Sync Connection", + "description": "'Identifies suspicious AD FS authentication by correlating Security events from \"AD FS Auditing\" with Windows Filtering Platform (WFP) events for incoming port 80 traffic.\nThis may indicate a threat actor abusing AD FS replication services to obtain configuration settings and sensitive information such as AD FS certificates. Enable AD FS auditing on the AD FS server before using this query.\nReferences:\nhttps://learn.microsoft.com/en-us/windows-server/identity/ad-fs/troubleshooting/ad-fs-tshoot-logging\nhttps://twitter.com/OTR_Community/status/1387038995016732672'", + "tactics": [ + { + "tactic": "Collection", + "techniques": [ + { + "technique": "T1005" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "dnsDomainColumn": "HostNameDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ], + "ips": [ + { + "id": "[if(true(), 'ip1', 'ip1')]", + "addressColumn": "SourceAddress" + } + ] + }, + "severity": "medium", + "customDetails": { + "AccountName": "AccountName", + "HostFullName": "Computer", + "AccountFullName": "ClaimsName" + } + } + }, + "status": "disabled", + "displayName": "AD FS Remote Auth Sync Connection" + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-2f4165a6-c4fb-4e94-861e-37f1b4d6c0e6", + "contentKind": "CustomDetection", + "displayName": "AD FS Remote Auth Sync Connection", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-2f4165a6-c4fb-4e94-861e-37f1b4d6c0e6','-','3.1.2')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-2f4165a6-c4fb-4e94-861e-37f1b4d6c0e6','-','3.1.2')))]", + "version": "3.1.2", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "WindowsSecurityEvents-CD-xdr-d57c33a9-76b9-40e0-9dfa-ff-53033e0a", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-d57c33a9-76b9-40e0-9dfa-ff0404546410', 'xdr-d57c33a9-76b9-40e0-9dfa-ff0404546410')]", + "queryCondition": { + "queryText": "// Adjust this to use a longer timeframe to identify ADFS servers\n//let lookback = 0d;\n// Adjust this to adjust detection timeframe\n//let timeframe = 1d;\n// Filter out other servers in the AD FS farm\nlet ADFSServersList = dynamic([\"ADFS02.domain.com\",\"ADFS03.domain.com\"]);\n// Start by identifying ADFS servers to reduce FP chance\nlet ADFS_Servers = (\nEvent\n//| where TimeGenerated > ago(timeframe+lookback)\n| where Source == \"Microsoft-Windows-Sysmon\"\n| where EventID == 18\n| where Computer !in (ADFSServersList)\n| extend EventData = parse_xml(EventData).DataItem.EventData.Data\n| mv-expand bagexpansion=array EventData\n| evaluate bag_unpack(EventData)\n| extend Key = tostring(column_ifexists('@Name', \"\")), Value = column_ifexists('#text', \"\")\n| evaluate pivot(Key, any(Value), TimeGenerated, Source, EventLog, Computer, EventLevel, EventLevelName, EventID, UserName, MG, ManagementGroupName, _ResourceId)\n| extend Image = column_ifexists(\"Image\", \"\")\n| extend process = split(Image, '\\\\', -1)[-1]\n| where process =~ \"Microsoft.IdentityServer.ServiceHost.exe\"\n| summarize by Computer\n);\n// Look for ADFS servers receiving connections over port 80\nEvent\n//| where TimeGenerated > ago(timeframe)\n| where Source == \"Microsoft-Windows-Sysmon\"\n| where Computer in~ (ADFS_Servers)\n| extend RenderedDescription = tostring(split(RenderedDescription, \":\")[0])\n| extend EventData = parse_xml(EventData).DataItem.EventData.Data\n| mv-expand bagexpansion=array EventData\n| evaluate bag_unpack(EventData)\n| extend Key = tostring(column_ifexists('@Name', \"\")), Value = column_ifexists('#text', \"\")\n| evaluate pivot(Key, any(Value), TimeGenerated, Source, EventLog, Computer, EventLevel, EventLevelName, EventID, UserName, RenderedDescription, MG, ManagementGroupName, _ResourceId)\n| extend RuleName = column_ifexists(\"RuleName\", \"\"), TechniqueId = column_ifexists(\"TechniqueId\", \"\"), TechniqueName = column_ifexists(\"TechniqueName\", \"\")\n| parse RuleName with * 'technique_id=' TechniqueId ',' * 'technique_name=' TechniqueName\n| where EventID == 3\n// Look for endpoints connecting to the AD FS server over port 80\n| extend DestinationPort = column_ifexists(\"DestinationPort\", \"\"), Image = column_ifexists(\"Image\", \"\"), Initiated = column_ifexists(\"Initiated\", \"\"), SourceIp = column_ifexists(\"DestinationIp\", \"\"), DestinationIp = column_ifexists(\"DestinationIp\", \"\")\n| where DestinationPort == 80\n| extend process = split(Image, '\\\\', -1)[-1]\n// Look for the System process receiving connections\n| where process == 'System' and Initiated == 'false'\n| where DestinationIp !in ('::1','0:0:0:0:0:0:0:1')\n| extend Operation = RenderedDescription\n| project-reorder TimeGenerated, Operation, Image, Computer, UserName\n| extend HostName = tostring(split(Computer, \".\")[0]), DomainIndex = toint(indexof(Computer, '.'))\n| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)\n| extend AccountName = tostring(split(UserName, @'\\')[1]), AccountNTDomain = tostring(split(UserName, @'\\')[0])" + }, + "schedule": { + "frequency": "P1D" + }, + "detectionAction": { + "alertTemplate": { + "title": "AD FS Remote HTTP Network Connection", + "description": "'This detection uses Sysmon events (NetworkConnect events) to detect incoming network traffic on port 80 on AD FS servers. This could be a sign of a threat actor trying to use replication services on the AD FS server to get its configuration settings and extract sensitive information such as AD FS certificates.\nIn order to use this query you need to enable Sysmon telemetry on the AD FS Server.\nReference: https://twitter.com/OTR_Community/status/1387038995016732672\n'", + "tactics": [ + { + "tactic": "Collection", + "techniques": [ + { + "technique": "T1005" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "dnsDomainColumn": "HostNameDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ], + "ips": [ + { + "id": "[if(true(), 'ip1', 'ip1')]", + "addressColumn": "SourceIp" + } + ] + }, + "severity": "medium", + "customDetails": { + "AccountName": "AccountName", + "AccountNTDomain": "AccountNTDomain", + "HostFullName": "Computer", + "AccountFullName": "UserName" + } + } + }, + "status": "disabled", + "displayName": "AD FS Remote HTTP Network Connection" + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-d57c33a9-76b9-40e0-9dfa-ff0404546410')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'WindowsSecurityEvents-CD-xdr-d57c33a9-76b9-40e0-9dfa-ff-53033e0a')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'This detection uses Sysmon events (NetworkConnect events) to detect incoming network traffic on port 80 on AD FS servers. This could be a sign of a threat actor trying to use replication services on the AD FS server to get its configuration settings and extract sensitive information such as AD FS certificates.\nIn order to use this query you need to enable Sysmon telemetry on the AD FS Server.\nReference: https://twitter.com/OTR_Community/status/1387038995016732672\n'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-d57c33a9-76b9-40e0-9dfa-ff0404546410', 'xdr-d57c33a9-76b9-40e0-9dfa-ff0404546410')]", + "queryCondition": { + "queryText": "// Adjust this to use a longer timeframe to identify ADFS servers\n//let lookback = 0d;\n// Adjust this to adjust detection timeframe\n//let timeframe = 1d;\n// Filter out other servers in the AD FS farm\nlet ADFSServersList = dynamic([\"ADFS02.domain.com\",\"ADFS03.domain.com\"]);\n// Start by identifying ADFS servers to reduce FP chance\nlet ADFS_Servers = (\nEvent\n//| where TimeGenerated > ago(timeframe+lookback)\n| where Source == \"Microsoft-Windows-Sysmon\"\n| where EventID == 18\n| where Computer !in (ADFSServersList)\n| extend EventData = parse_xml(EventData).DataItem.EventData.Data\n| mv-expand bagexpansion=array EventData\n| evaluate bag_unpack(EventData)\n| extend Key = tostring(column_ifexists('@Name', \"\")), Value = column_ifexists('#text', \"\")\n| evaluate pivot(Key, any(Value), TimeGenerated, Source, EventLog, Computer, EventLevel, EventLevelName, EventID, UserName, MG, ManagementGroupName, _ResourceId)\n| extend Image = column_ifexists(\"Image\", \"\")\n| extend process = split(Image, '\\\\', -1)[-1]\n| where process =~ \"Microsoft.IdentityServer.ServiceHost.exe\"\n| summarize by Computer\n);\n// Look for ADFS servers receiving connections over port 80\nEvent\n//| where TimeGenerated > ago(timeframe)\n| where Source == \"Microsoft-Windows-Sysmon\"\n| where Computer in~ (ADFS_Servers)\n| extend RenderedDescription = tostring(split(RenderedDescription, \":\")[0])\n| extend EventData = parse_xml(EventData).DataItem.EventData.Data\n| mv-expand bagexpansion=array EventData\n| evaluate bag_unpack(EventData)\n| extend Key = tostring(column_ifexists('@Name', \"\")), Value = column_ifexists('#text', \"\")\n| evaluate pivot(Key, any(Value), TimeGenerated, Source, EventLog, Computer, EventLevel, EventLevelName, EventID, UserName, RenderedDescription, MG, ManagementGroupName, _ResourceId)\n| extend RuleName = column_ifexists(\"RuleName\", \"\"), TechniqueId = column_ifexists(\"TechniqueId\", \"\"), TechniqueName = column_ifexists(\"TechniqueName\", \"\")\n| parse RuleName with * 'technique_id=' TechniqueId ',' * 'technique_name=' TechniqueName\n| where EventID == 3\n// Look for endpoints connecting to the AD FS server over port 80\n| extend DestinationPort = column_ifexists(\"DestinationPort\", \"\"), Image = column_ifexists(\"Image\", \"\"), Initiated = column_ifexists(\"Initiated\", \"\"), SourceIp = column_ifexists(\"DestinationIp\", \"\"), DestinationIp = column_ifexists(\"DestinationIp\", \"\")\n| where DestinationPort == 80\n| extend process = split(Image, '\\\\', -1)[-1]\n// Look for the System process receiving connections\n| where process == 'System' and Initiated == 'false'\n| where DestinationIp !in ('::1','0:0:0:0:0:0:0:1')\n| extend Operation = RenderedDescription\n| project-reorder TimeGenerated, Operation, Image, Computer, UserName\n| extend HostName = tostring(split(Computer, \".\")[0]), DomainIndex = toint(indexof(Computer, '.'))\n| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)\n| extend AccountName = tostring(split(UserName, @'\\')[1]), AccountNTDomain = tostring(split(UserName, @'\\')[0])" + }, + "schedule": { + "frequency": "P1D" + }, + "detectionAction": { + "alertTemplate": { + "title": "AD FS Remote HTTP Network Connection", + "description": "'This detection uses Sysmon events (NetworkConnect events) to detect incoming network traffic on port 80 on AD FS servers. This could be a sign of a threat actor trying to use replication services on the AD FS server to get its configuration settings and extract sensitive information such as AD FS certificates.\nIn order to use this query you need to enable Sysmon telemetry on the AD FS Server.\nReference: https://twitter.com/OTR_Community/status/1387038995016732672\n'", + "tactics": [ + { + "tactic": "Collection", + "techniques": [ + { + "technique": "T1005" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "dnsDomainColumn": "HostNameDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ], + "ips": [ + { + "id": "[if(true(), 'ip1', 'ip1')]", + "addressColumn": "SourceIp" + } + ] + }, + "severity": "medium", + "customDetails": { + "AccountName": "AccountName", + "AccountNTDomain": "AccountNTDomain", + "HostFullName": "Computer", + "AccountFullName": "UserName" + } + } + }, + "status": "disabled", + "displayName": "AD FS Remote HTTP Network Connection" + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-d57c33a9-76b9-40e0-9dfa-ff0404546410", + "contentKind": "CustomDetection", + "displayName": "AD FS Remote HTTP Network Connection", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-d57c33a9-76b9-40e0-9dfa-ff0404546410','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-d57c33a9-76b9-40e0-9dfa-ff0404546410','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "WindowsSecurityEvents-CD-xdr-2391ce61-8c8d-41ac-9723-d9-3433927b", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-2391ce61-8c8d-41ac-9723-d945b2e90720', 'xdr-2391ce61-8c8d-41ac-9723-d945b2e90720')]", + "queryCondition": { + "queryText": "let starttime = 8d;\nlet endtime = 1d;\nlet threshold = 0.333;\nlet countlimit = 50;\nSecurityEvent\n| where TimeGenerated >= ago(endtime)\n| where EventID == 4625 and AccountType =~ \"User\"\n| where IpAddress !in (\"127.0.0.1\", \"::1\")\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), CountToday = count() by EventID, Account, LogonTypeName, SubStatus, AccountType, Computer, WorkstationName, IpAddress, Process\n| join kind=leftouter (\n SecurityEvent\n | where TimeGenerated between (ago(starttime) .. ago(endtime))\n | where EventID == 4625 and AccountType =~ \"User\"\n | where IpAddress !in (\"127.0.0.1\", \"::1\")\n | summarize CountPrev7day = count() by EventID, Account, LogonTypeName, SubStatus, AccountType, Computer, WorkstationName, IpAddress\n) on EventID, Account, LogonTypeName, SubStatus, AccountType, Computer, WorkstationName, IpAddress\n| where CountToday >= coalesce(CountPrev7day,0)*threshold and CountToday >= countlimit\n//SubStatus Codes are detailed here - https://docs.microsoft.com/windows/security/threat-protection/auditing/event-4625\n| extend Reason = case(\nSubStatus =~ '0xC000005E', 'There are currently no logon servers available to service the logon request.',\nSubStatus =~ '0xC0000064', 'User logon with misspelled or bad user account',\nSubStatus =~ '0xC000006A', 'User logon with misspelled or bad password',\nSubStatus =~ '0xC000006D', 'Bad user name or password',\nSubStatus =~ '0xC000006E', 'Unknown user name or bad password',\nSubStatus =~ '0xC000006F', 'User logon outside authorized hours',\nSubStatus =~ '0xC0000070', 'User logon from unauthorized workstation',\nSubStatus =~ '0xC0000071', 'User logon with expired password',\nSubStatus =~ '0xC0000072', 'User logon to account disabled by administrator',\nSubStatus =~ '0xC00000DC', 'Indicates the Sam Server was in the wrong state to perform the desired operation',\nSubStatus =~ '0xC0000133', 'Clocks between DC and other computer too far out of sync',\nSubStatus =~ '0xC000015B', 'The user has not been granted the requested logon type (aka logon right) at this machine',\nSubStatus =~ '0xC000018C', 'The logon request failed because the trust relationship between the primary domain and the trusted domain failed',\nSubStatus =~ '0xC0000192', 'An attempt was made to logon, but the Netlogon service was not started',\nSubStatus =~ '0xC0000193', 'User logon with expired account',\nSubStatus =~ '0xC0000224', 'User is required to change password at next logon',\nSubStatus =~ '0xC0000225', 'Evidently a bug in Windows and not a risk',\nSubStatus =~ '0xC0000234', 'User logon with account locked',\nSubStatus =~ '0xC00002EE', 'Failure Reason: An Error occurred during Logon',\nSubStatus =~ '0xC0000413', 'Logon Failure: The machine you are logging onto is protected by an authentication firewall. The specified account is not allowed to authenticate to the machine',\nstrcat('Unknown reason substatus: ', SubStatus))\n| extend WorkstationName = iff(WorkstationName == \"-\" or isempty(WorkstationName), Computer , WorkstationName)\n| project StartTime, EndTime, EventID, Account, LogonTypeName, SubStatus, Reason, AccountType, Computer, WorkstationName, IpAddress, CountToday, CountPrev7day, Avg7Day = round(CountPrev7day*1.00/7,2), Process\n| summarize StartTime = min(StartTime), EndTime = max(EndTime), Computer = make_set(Computer,128), IpAddressList = make_set(IpAddress,128), sum(CountToday), sum(CountPrev7day), avg(Avg7Day)\nby EventID, Account, LogonTypeName, SubStatus, Reason, AccountType, WorkstationName, Process\n| order by sum_CountToday desc nulls last\n| extend timestamp = StartTime, NTDomain = tostring(split(Account, '\\\\', 0)[0]), Name = tostring(split(Account, '\\\\', 1)[0]), HostName = tostring(split(WorkstationName, '.', 0)[0]), DnsDomain = tostring(strcat_array(array_slice(split(WorkstationName, '.'), 1, -1), '.'))" + }, + "schedule": { + "frequency": "P1D" + }, + "detectionAction": { + "alertTemplate": { + "title": "Excessive Windows Logon Failures", + "description": "'This query identifies user accounts which has over 50 Windows logon failures today and at least 33% of the count of logon failures over the previous 7 days.'", + "tactics": [ + { + "tactic": "CredentialAccess", + "techniques": [ + { + "technique": "T1110" + } + ] + } + ], + "entityMappings": { + "accounts": [ + { + "ntDomainColumn": "NTDomain", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "Name" + } + ], + "hosts": [ + { + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ] + }, + "severity": "low", + "customDetails": { + "ProcessCommandLine": "Process", + "HostFullName": "WorkstationName", + "AccountFullName": "Account" + } + } + }, + "status": "disabled", + "displayName": "Excessive Windows Logon Failures" + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-2391ce61-8c8d-41ac-9723-d945b2e90720')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'WindowsSecurityEvents-CD-xdr-2391ce61-8c8d-41ac-9723-d9-3433927b')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'This query identifies user accounts which has over 50 Windows logon failures today and at least 33% of the count of logon failures over the previous 7 days.'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-2391ce61-8c8d-41ac-9723-d945b2e90720', 'xdr-2391ce61-8c8d-41ac-9723-d945b2e90720')]", + "queryCondition": { + "queryText": "let starttime = 8d;\nlet endtime = 1d;\nlet threshold = 0.333;\nlet countlimit = 50;\nSecurityEvent\n| where TimeGenerated >= ago(endtime)\n| where EventID == 4625 and AccountType =~ \"User\"\n| where IpAddress !in (\"127.0.0.1\", \"::1\")\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), CountToday = count() by EventID, Account, LogonTypeName, SubStatus, AccountType, Computer, WorkstationName, IpAddress, Process\n| join kind=leftouter (\n SecurityEvent\n | where TimeGenerated between (ago(starttime) .. ago(endtime))\n | where EventID == 4625 and AccountType =~ \"User\"\n | where IpAddress !in (\"127.0.0.1\", \"::1\")\n | summarize CountPrev7day = count() by EventID, Account, LogonTypeName, SubStatus, AccountType, Computer, WorkstationName, IpAddress\n) on EventID, Account, LogonTypeName, SubStatus, AccountType, Computer, WorkstationName, IpAddress\n| where CountToday >= coalesce(CountPrev7day,0)*threshold and CountToday >= countlimit\n//SubStatus Codes are detailed here - https://docs.microsoft.com/windows/security/threat-protection/auditing/event-4625\n| extend Reason = case(\nSubStatus =~ '0xC000005E', 'There are currently no logon servers available to service the logon request.',\nSubStatus =~ '0xC0000064', 'User logon with misspelled or bad user account',\nSubStatus =~ '0xC000006A', 'User logon with misspelled or bad password',\nSubStatus =~ '0xC000006D', 'Bad user name or password',\nSubStatus =~ '0xC000006E', 'Unknown user name or bad password',\nSubStatus =~ '0xC000006F', 'User logon outside authorized hours',\nSubStatus =~ '0xC0000070', 'User logon from unauthorized workstation',\nSubStatus =~ '0xC0000071', 'User logon with expired password',\nSubStatus =~ '0xC0000072', 'User logon to account disabled by administrator',\nSubStatus =~ '0xC00000DC', 'Indicates the Sam Server was in the wrong state to perform the desired operation',\nSubStatus =~ '0xC0000133', 'Clocks between DC and other computer too far out of sync',\nSubStatus =~ '0xC000015B', 'The user has not been granted the requested logon type (aka logon right) at this machine',\nSubStatus =~ '0xC000018C', 'The logon request failed because the trust relationship between the primary domain and the trusted domain failed',\nSubStatus =~ '0xC0000192', 'An attempt was made to logon, but the Netlogon service was not started',\nSubStatus =~ '0xC0000193', 'User logon with expired account',\nSubStatus =~ '0xC0000224', 'User is required to change password at next logon',\nSubStatus =~ '0xC0000225', 'Evidently a bug in Windows and not a risk',\nSubStatus =~ '0xC0000234', 'User logon with account locked',\nSubStatus =~ '0xC00002EE', 'Failure Reason: An Error occurred during Logon',\nSubStatus =~ '0xC0000413', 'Logon Failure: The machine you are logging onto is protected by an authentication firewall. The specified account is not allowed to authenticate to the machine',\nstrcat('Unknown reason substatus: ', SubStatus))\n| extend WorkstationName = iff(WorkstationName == \"-\" or isempty(WorkstationName), Computer , WorkstationName)\n| project StartTime, EndTime, EventID, Account, LogonTypeName, SubStatus, Reason, AccountType, Computer, WorkstationName, IpAddress, CountToday, CountPrev7day, Avg7Day = round(CountPrev7day*1.00/7,2), Process\n| summarize StartTime = min(StartTime), EndTime = max(EndTime), Computer = make_set(Computer,128), IpAddressList = make_set(IpAddress,128), sum(CountToday), sum(CountPrev7day), avg(Avg7Day)\nby EventID, Account, LogonTypeName, SubStatus, Reason, AccountType, WorkstationName, Process\n| order by sum_CountToday desc nulls last\n| extend timestamp = StartTime, NTDomain = tostring(split(Account, '\\\\', 0)[0]), Name = tostring(split(Account, '\\\\', 1)[0]), HostName = tostring(split(WorkstationName, '.', 0)[0]), DnsDomain = tostring(strcat_array(array_slice(split(WorkstationName, '.'), 1, -1), '.'))" + }, + "schedule": { + "frequency": "P1D" + }, + "detectionAction": { + "alertTemplate": { + "title": "Excessive Windows Logon Failures", + "description": "'This query identifies user accounts which has over 50 Windows logon failures today and at least 33% of the count of logon failures over the previous 7 days.'", + "tactics": [ + { + "tactic": "CredentialAccess", + "techniques": [ + { + "technique": "T1110" + } + ] + } + ], + "entityMappings": { + "accounts": [ + { + "ntDomainColumn": "NTDomain", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "Name" + } + ], + "hosts": [ + { + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ] + }, + "severity": "low", + "customDetails": { + "ProcessCommandLine": "Process", + "HostFullName": "WorkstationName", + "AccountFullName": "Account" + } + } + }, + "status": "disabled", + "displayName": "Excessive Windows Logon Failures" + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-2391ce61-8c8d-41ac-9723-d945b2e90720", + "contentKind": "CustomDetection", + "displayName": "Excessive Windows Logon Failures", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-2391ce61-8c8d-41ac-9723-d945b2e90720','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-2391ce61-8c8d-41ac-9723-d945b2e90720','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "WindowsSecurityEvents-CD-xdr-faf1a6ff-53b5-4f92-8c55-4b-96364f28", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-faf1a6ff-53b5-4f92-8c55-4b20e9957594', 'xdr-faf1a6ff-53b5-4f92-8c55-4b20e9957594')]", + "queryCondition": { + "queryText": "SecurityEvent\n// Look for specific Directory Service Changes and parse data\n| where EventID == 5136\n| extend EventData = parse_xml(EventData).EventData.Data\n| mv-expand bagexpansion = array EventData\n| evaluate bag_unpack(EventData)\n| extend Key = tostring(column_ifexists('@Name', \"\")), Value = column_ifexists('#text', \"\")\n| evaluate pivot(Key, any(Value),TimeGenerated, EventID, Computer, Account, AccountType, EventSourceName, Activity, SubjectAccount)\n// Where changes relate to Exchange OAB\n| extend ObjectClass = column_ifexists(\"ObjectClass\", \"\")\n| where ObjectClass =~ \"msExchOABVirtualDirectory\"\n// Look for InternalHostName or ExternalHostName properties being changed\n| extend AttributeLDAPDisplayName = column_ifexists(\"AttributeLDAPDisplayName\", \"\")\n| where AttributeLDAPDisplayName in~ (\"msExchExternalHostName\", \"msExchInternalHostName\")\n// Look for suspected webshell activity\n| extend AttributeValue = column_ifexists(\"AttributeValue\", \"\")\n| where AttributeValue has \"script\"\n| project-rename LastSeen = TimeGenerated\n| extend ObjectDN = column_ifexists(\"ObjectDN\", \"\")\n| project-reorder LastSeen, Computer, Account, ObjectDN, AttributeLDAPDisplayName, AttributeValue\n| extend timestamp = LastSeen\n| extend HostName = tostring(split(Computer, \".\")[0]), DomainIndex = toint(indexof(Computer, '.'))\n| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)\n| extend AccountName = tostring(split(Account, @'\\')[1]), AccountNTDomain = tostring(split(Account, @'\\')[0])" + }, + "schedule": { + "frequency": "PT1H" + }, + "detectionAction": { + "alertTemplate": { + "severity": "high", + "entityMappings": { + "hosts": [ + { + "dnsDomainColumn": "HostNameDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ] + }, + "title": "Exchange OAB Virtual Directory Attribute Containing Potential Webshell", + "description": "'This query uses Windows Event ID 5136 in order to detect potential webshell deployment by exploitation of CVE-2021-27065.\nThis query looks for changes to the InternalHostName or ExternalHostName properties of Exchange OAB Virtual Directory objects in AD Directory Services where the new objects contain potential webshell objects.'", + "tactics": [ + { + "tactic": "InitialAccess", + "techniques": [ + { + "technique": "T1190" + } + ] + } + ] + } + }, + "status": "disabled", + "displayName": "Exchange OAB Virtual Directory Attribute Containing Potential Webshell" + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-faf1a6ff-53b5-4f92-8c55-4b20e9957594')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'WindowsSecurityEvents-CD-xdr-faf1a6ff-53b5-4f92-8c55-4b-96364f28')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'This query uses Windows Event ID 5136 in order to detect potential webshell deployment by exploitation of CVE-2021-27065.\nThis query looks for changes to the InternalHostName or ExternalHostName properties of Exchange OAB Virtual Directory objects in AD Directory Services where the new objects contain potential webshell objects.'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-faf1a6ff-53b5-4f92-8c55-4b20e9957594', 'xdr-faf1a6ff-53b5-4f92-8c55-4b20e9957594')]", + "queryCondition": { + "queryText": "SecurityEvent\n// Look for specific Directory Service Changes and parse data\n| where EventID == 5136\n| extend EventData = parse_xml(EventData).EventData.Data\n| mv-expand bagexpansion = array EventData\n| evaluate bag_unpack(EventData)\n| extend Key = tostring(column_ifexists('@Name', \"\")), Value = column_ifexists('#text', \"\")\n| evaluate pivot(Key, any(Value),TimeGenerated, EventID, Computer, Account, AccountType, EventSourceName, Activity, SubjectAccount)\n// Where changes relate to Exchange OAB\n| extend ObjectClass = column_ifexists(\"ObjectClass\", \"\")\n| where ObjectClass =~ \"msExchOABVirtualDirectory\"\n// Look for InternalHostName or ExternalHostName properties being changed\n| extend AttributeLDAPDisplayName = column_ifexists(\"AttributeLDAPDisplayName\", \"\")\n| where AttributeLDAPDisplayName in~ (\"msExchExternalHostName\", \"msExchInternalHostName\")\n// Look for suspected webshell activity\n| extend AttributeValue = column_ifexists(\"AttributeValue\", \"\")\n| where AttributeValue has \"script\"\n| project-rename LastSeen = TimeGenerated\n| extend ObjectDN = column_ifexists(\"ObjectDN\", \"\")\n| project-reorder LastSeen, Computer, Account, ObjectDN, AttributeLDAPDisplayName, AttributeValue\n| extend timestamp = LastSeen\n| extend HostName = tostring(split(Computer, \".\")[0]), DomainIndex = toint(indexof(Computer, '.'))\n| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)\n| extend AccountName = tostring(split(Account, @'\\')[1]), AccountNTDomain = tostring(split(Account, @'\\')[0])" + }, + "schedule": { + "frequency": "PT1H" + }, + "detectionAction": { + "alertTemplate": { + "severity": "high", + "entityMappings": { + "hosts": [ + { + "dnsDomainColumn": "HostNameDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ] + }, + "title": "Exchange OAB Virtual Directory Attribute Containing Potential Webshell", + "description": "'This query uses Windows Event ID 5136 in order to detect potential webshell deployment by exploitation of CVE-2021-27065.\nThis query looks for changes to the InternalHostName or ExternalHostName properties of Exchange OAB Virtual Directory objects in AD Directory Services where the new objects contain potential webshell objects.'", + "tactics": [ + { + "tactic": "InitialAccess", + "techniques": [ + { + "technique": "T1190" + } + ] + } + ] + } + }, + "status": "disabled", + "displayName": "Exchange OAB Virtual Directory Attribute Containing Potential Webshell" + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-faf1a6ff-53b5-4f92-8c55-4b20e9957594", + "contentKind": "CustomDetection", + "displayName": "Exchange OAB Virtual Directory Attribute Containing Potential Webshell", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-faf1a6ff-53b5-4f92-8c55-4b20e9957594','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-faf1a6ff-53b5-4f92-8c55-4b20e9957594','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "WindowsSecurityEvents-CD-xdr-12dcea64-bec2-41c9-9df2-9f-810a41a7", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-12dcea64-bec2-41c9-9df2-9f28461b1295', 'xdr-12dcea64-bec2-41c9-9df2-9f28461b1295')]", + "queryCondition": { + "queryText": "let timeframe = 1d;\n// Adjust for a longer timeframe for identifying ADFS Servers\nlet lookback = 6d;\n// Identify ADFS Servers\nlet ADFS_Servers = (\nSecurityEvent\n| where TimeGenerated > ago(timeframe+lookback)\n| where EventID == 4688 and SubjectLogonId != \"0x3e4\"\n| where NewProcessName has \"Microsoft.IdentityServer.ServiceHost.exe\"\n| distinct Computer\n);\nSecurityEvent\n| where TimeGenerated > ago(timeframe)\n| where Computer in~ (ADFS_Servers)\n| where Account !endswith \"$\"\n// Check for scheduled task events\n| where EventID in (4697, 4698, 4699, 4700, 4701, 4702)\n| extend EventDataParsed = parse_xml(EventData)\n| extend SubjectLogonId = tostring(EventDataParsed.EventData.Data[3][\"#text\"])\n// Check specifically for access to IPC$ share and PIPE\\svcctl and PIPE\\atsvc for Service Control Services and Schedule Control Services\n| union (\n SecurityEvent\n | where TimeGenerated > ago(timeframe)\n | where Computer in~ (ADFS_Servers)\n | where Account !endswith \"$\"\n | where EventID == 5145\n | where RelativeTargetName =~ \"svcctl\" or RelativeTargetName =~ \"atsvc\"\n)\n// Check for lateral movement\n| join kind=inner\n(SecurityEvent\n| where TimeGenerated > ago(timeframe)\n| where Account !endswith \"$\"\n| where EventID == 4624 and LogonType == 3\n) on $left.SubjectLogonId == $right.TargetLogonId\n| project TimeGenerated, Account, Computer, EventID, RelativeTargetName\n| extend timestamp = TimeGenerated\n| extend HostName = tostring(split(Computer, \".\")[0]), DomainIndex = toint(indexof(Computer, '.'))\n| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)\n| extend AccountName = tostring(split(Account, @'\\')[1]), AccountNTDomain = tostring(split(Account, @'\\')[0])" + }, + "schedule": { + "frequency": "P1D" + }, + "detectionAction": { + "alertTemplate": { + "title": "Gain Code Execution on ADFS Server via SMB + Remote Service or Scheduled Task", + "description": "'This query detects instances where an attacker has gained the ability to execute code on an ADFS Server through SMB and Remote Service or Scheduled Task.'", + "tactics": [ + { + "tactic": "LateralMovement", + "techniques": [ + { + "technique": "T1210" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "dnsDomainColumn": "HostNameDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ] + }, + "severity": "medium", + "customDetails": { + "AccountName": "AccountName", + "HostFullName": "Computer", + "AccountFullName": "Account" + } + } + }, + "status": "disabled", + "displayName": "Gain Code Execution on ADFS Server via SMB + Remote Service or Scheduled Task" + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-12dcea64-bec2-41c9-9df2-9f28461b1295')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'WindowsSecurityEvents-CD-xdr-12dcea64-bec2-41c9-9df2-9f-810a41a7')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'This query detects instances where an attacker has gained the ability to execute code on an ADFS Server through SMB and Remote Service or Scheduled Task.'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-12dcea64-bec2-41c9-9df2-9f28461b1295', 'xdr-12dcea64-bec2-41c9-9df2-9f28461b1295')]", + "queryCondition": { + "queryText": "let timeframe = 1d;\n// Adjust for a longer timeframe for identifying ADFS Servers\nlet lookback = 6d;\n// Identify ADFS Servers\nlet ADFS_Servers = (\nSecurityEvent\n| where TimeGenerated > ago(timeframe+lookback)\n| where EventID == 4688 and SubjectLogonId != \"0x3e4\"\n| where NewProcessName has \"Microsoft.IdentityServer.ServiceHost.exe\"\n| distinct Computer\n);\nSecurityEvent\n| where TimeGenerated > ago(timeframe)\n| where Computer in~ (ADFS_Servers)\n| where Account !endswith \"$\"\n// Check for scheduled task events\n| where EventID in (4697, 4698, 4699, 4700, 4701, 4702)\n| extend EventDataParsed = parse_xml(EventData)\n| extend SubjectLogonId = tostring(EventDataParsed.EventData.Data[3][\"#text\"])\n// Check specifically for access to IPC$ share and PIPE\\svcctl and PIPE\\atsvc for Service Control Services and Schedule Control Services\n| union (\n SecurityEvent\n | where TimeGenerated > ago(timeframe)\n | where Computer in~ (ADFS_Servers)\n | where Account !endswith \"$\"\n | where EventID == 5145\n | where RelativeTargetName =~ \"svcctl\" or RelativeTargetName =~ \"atsvc\"\n)\n// Check for lateral movement\n| join kind=inner\n(SecurityEvent\n| where TimeGenerated > ago(timeframe)\n| where Account !endswith \"$\"\n| where EventID == 4624 and LogonType == 3\n) on $left.SubjectLogonId == $right.TargetLogonId\n| project TimeGenerated, Account, Computer, EventID, RelativeTargetName\n| extend timestamp = TimeGenerated\n| extend HostName = tostring(split(Computer, \".\")[0]), DomainIndex = toint(indexof(Computer, '.'))\n| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)\n| extend AccountName = tostring(split(Account, @'\\')[1]), AccountNTDomain = tostring(split(Account, @'\\')[0])" + }, + "schedule": { + "frequency": "P1D" + }, + "detectionAction": { + "alertTemplate": { + "title": "Gain Code Execution on ADFS Server via SMB + Remote Service or Scheduled Task", + "description": "'This query detects instances where an attacker has gained the ability to execute code on an ADFS Server through SMB and Remote Service or Scheduled Task.'", + "tactics": [ + { + "tactic": "LateralMovement", + "techniques": [ + { + "technique": "T1210" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "dnsDomainColumn": "HostNameDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ] + }, + "severity": "medium", + "customDetails": { + "AccountName": "AccountName", + "HostFullName": "Computer", + "AccountFullName": "Account" + } + } + }, + "status": "disabled", + "displayName": "Gain Code Execution on ADFS Server via SMB + Remote Service or Scheduled Task" + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-12dcea64-bec2-41c9-9df2-9f28461b1295", + "contentKind": "CustomDetection", + "displayName": "Gain Code Execution on ADFS Server via SMB + Remote Service or Scheduled Task", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-12dcea64-bec2-41c9-9df2-9f28461b1295','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-12dcea64-bec2-41c9-9df2-9f28461b1295','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "WindowsSecurityEvents-CD-xdr-a356c8bd-c81d-428b-aa36-83-836d372e", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-a356c8bd-c81d-428b-aa36-83be706be034', 'xdr-a356c8bd-c81d-428b-aa36-83be706be034')]", + "queryCondition": { + "queryText": "// AADJoined or Register Device Registry Keys\nlet aadJoinRoot = \"\\\\REGISTRY\\\\MACHINE\\\\SYSTEM\\\\ControlSet001\\\\Control\\\\CloudDomainJoin\\\\JoinInfo\\\\\";\nlet aadRegisteredRoot = \"\\\\SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\WorkplaceJoin\";\n// Transport Key Registry Key\nlet keyTransportKey = \"\\\\REGISTRY\\\\MACHINE\\\\SYSTEM\\\\ControlSet001\\\\Control\\\\Cryptography\\\\Ngc\\\\KeyTransportKey\\\\\";\n(union isfuzzy=true\n(\n// Access to Object Requested\nSecurityEvent\n| where EventID == '4656'\n| where EventData has aadJoinRoot or EventData has aadRegisteredRoot\n| extend EventData = parse_xml(EventData).EventData.Data\n| mv-expand bagexpansion=array EventData\n| evaluate bag_unpack(EventData)\n| extend Key = tostring(column_ifexists('@Name', \"\")), Value = column_ifexists('#text', \"\")\n| evaluate pivot(Key, any(Value), TimeGenerated, Computer, EventID)\n| where ObjectType == 'Key'\n| where ObjectName startswith aadJoinRoot and SubjectLogonId != '0x3e7' //Local System\n| extend ProcessId = column_ifexists(\"ProcessId\", \"\"), Process = split(ProcessName, '\\\\', -1)[-1],Account = strcat(SubjectDomainName, \"\\\\\", SubjectUserName)\n| join kind=innerunique (\n SecurityEvent\n | where EventID == '4656'\n | where EventData has keyTransportKey\n | extend EventData = parse_xml(EventData).EventData.Data\n | mv-expand bagexpansion=array EventData\n | evaluate bag_unpack(EventData)\n | extend Key = tostring(column_ifexists('@Name', \"\")), Value = column_ifexists('#text', \"\")\n | evaluate pivot(Key, any(Value), TimeGenerated, Computer, EventID)\n | extend ObjectName = column_ifexists(\"ObjectName\", \"\"),ObjectType = column_ifexists(\"ObjectType\", \"\")\n | where ObjectType == 'Key'\n | where ObjectName startswith keyTransportKey and SubjectLogonId != '0x3e7' //Local System\n | extend ProcessId = column_ifexists(\"ProcessId\", \"\"), Process = split(ProcessName, '\\\\', -1)[-1],Account = strcat(SubjectDomainName, \"\\\\\", SubjectUserName)\n) on $left.Computer == $right.Computer and $left.SubjectLogonId == $right.SubjectLogonId and $left.ProcessId == $right.ProcessId\n| project TimeGenerated, Computer, Account, SubjectDomainName, SubjectUserName, SubjectLogonId, ObjectName, tostring(Process), ProcessName, ProcessId, EventID\n),\n// Accessing Object\n(\nSecurityEvent\n| where EventID == '4663'\n| where ObjectType == 'Key'\n| where (ObjectName startswith aadJoinRoot or ObjectName contains aadRegisteredRoot) and SubjectLogonId != '0x3e7' //Local System\n| extend Account = SubjectAccount\n| join kind=innerunique (\n SecurityEvent\n | where EventID == '4663'\n | where ObjectType == 'Key'\n | where ObjectName has keyTransportKey and SubjectLogonId != '0x3e7' //Local System\n | extend Account = SubjectAccount\n) on $left.Computer == $right.Computer and $left.SubjectLogonId == $right.SubjectLogonId and $left.ProcessId == $right.ProcessId\n| project TimeGenerated, Computer, Account, SubjectDomainName, SubjectUserName, SubjectLogonId, ObjectName, Process, ProcessName, ProcessId, EventID\n| extend HostName = tostring(split(Computer, '.', 0)[0]), DnsDomain = tostring(strcat_array(array_slice(split(Computer, '.'), 1, -1), '.'))\n)\n)" + }, + "schedule": { + "frequency": "P1D" + }, + "detectionAction": { + "alertTemplate": { + "title": "Microsoft Entra ID Local Device Join Information and Transport Key Registry Keys Access", + "description": "'This detection uses Windows security events to detect suspicious access attempts by the same process to registry keys that provide information about an Microsoft Entra ID joined or registered devices and Transport keys (tkpub / tkpriv).\n This information can be used to export the Device Certificate (dkpub / dkpriv) and Transport key (tkpub/tkpriv).\n These set of keys can be used to impersonate existing Microsoft Entra ID joined devices.\n This detection requires an access control entry (ACE) on the system access control list (SACL) of the following securable objects:\n HKLM:\\SYSTEM\\CurrentContr", + "tactics": [ + { + "tactic": "Discovery", + "techniques": [ + { + "technique": "T1012" + } + ] + } + ], + "entityMappings": { + "accounts": [ + { + "ntDomainColumn": "SubjectDomainName", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "SubjectUserName" + } + ], + "hosts": [ + { + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ] + }, + "severity": "medium", + "customDetails": { + "HostFullName": "Computer", + "AccountFullName": "Account" + } + } + }, + "status": "disabled", + "displayName": "Microsoft Entra ID Local Device Join Information and Transport Key Registry Keys Access" + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-a356c8bd-c81d-428b-aa36-83be706be034')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'WindowsSecurityEvents-CD-xdr-a356c8bd-c81d-428b-aa36-83-836d372e')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'This detection uses Windows security events to detect suspicious access attempts by the same process to registry keys that provide information about an Microsoft Entra ID joined or registered devices and Transport keys (tkpub / tkpriv).\n This information can be used to export the Device Certificate (dkpub / dkpriv) and Transport key (tkpub/tkpriv).\n These set of keys can be used to impersonate existing Microsoft Entra ID joined devices.\n This detection requires an access control entry (ACE) on the system access control list (SACL) of the following securable objects:\n HKLM:\\SYSTEM\\CurrentContr", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-a356c8bd-c81d-428b-aa36-83be706be034', 'xdr-a356c8bd-c81d-428b-aa36-83be706be034')]", + "queryCondition": { + "queryText": "// AADJoined or Register Device Registry Keys\nlet aadJoinRoot = \"\\\\REGISTRY\\\\MACHINE\\\\SYSTEM\\\\ControlSet001\\\\Control\\\\CloudDomainJoin\\\\JoinInfo\\\\\";\nlet aadRegisteredRoot = \"\\\\SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\WorkplaceJoin\";\n// Transport Key Registry Key\nlet keyTransportKey = \"\\\\REGISTRY\\\\MACHINE\\\\SYSTEM\\\\ControlSet001\\\\Control\\\\Cryptography\\\\Ngc\\\\KeyTransportKey\\\\\";\n(union isfuzzy=true\n(\n// Access to Object Requested\nSecurityEvent\n| where EventID == '4656'\n| where EventData has aadJoinRoot or EventData has aadRegisteredRoot\n| extend EventData = parse_xml(EventData).EventData.Data\n| mv-expand bagexpansion=array EventData\n| evaluate bag_unpack(EventData)\n| extend Key = tostring(column_ifexists('@Name', \"\")), Value = column_ifexists('#text', \"\")\n| evaluate pivot(Key, any(Value), TimeGenerated, Computer, EventID)\n| where ObjectType == 'Key'\n| where ObjectName startswith aadJoinRoot and SubjectLogonId != '0x3e7' //Local System\n| extend ProcessId = column_ifexists(\"ProcessId\", \"\"), Process = split(ProcessName, '\\\\', -1)[-1],Account = strcat(SubjectDomainName, \"\\\\\", SubjectUserName)\n| join kind=innerunique (\n SecurityEvent\n | where EventID == '4656'\n | where EventData has keyTransportKey\n | extend EventData = parse_xml(EventData).EventData.Data\n | mv-expand bagexpansion=array EventData\n | evaluate bag_unpack(EventData)\n | extend Key = tostring(column_ifexists('@Name', \"\")), Value = column_ifexists('#text', \"\")\n | evaluate pivot(Key, any(Value), TimeGenerated, Computer, EventID)\n | extend ObjectName = column_ifexists(\"ObjectName\", \"\"),ObjectType = column_ifexists(\"ObjectType\", \"\")\n | where ObjectType == 'Key'\n | where ObjectName startswith keyTransportKey and SubjectLogonId != '0x3e7' //Local System\n | extend ProcessId = column_ifexists(\"ProcessId\", \"\"), Process = split(ProcessName, '\\\\', -1)[-1],Account = strcat(SubjectDomainName, \"\\\\\", SubjectUserName)\n) on $left.Computer == $right.Computer and $left.SubjectLogonId == $right.SubjectLogonId and $left.ProcessId == $right.ProcessId\n| project TimeGenerated, Computer, Account, SubjectDomainName, SubjectUserName, SubjectLogonId, ObjectName, tostring(Process), ProcessName, ProcessId, EventID\n),\n// Accessing Object\n(\nSecurityEvent\n| where EventID == '4663'\n| where ObjectType == 'Key'\n| where (ObjectName startswith aadJoinRoot or ObjectName contains aadRegisteredRoot) and SubjectLogonId != '0x3e7' //Local System\n| extend Account = SubjectAccount\n| join kind=innerunique (\n SecurityEvent\n | where EventID == '4663'\n | where ObjectType == 'Key'\n | where ObjectName has keyTransportKey and SubjectLogonId != '0x3e7' //Local System\n | extend Account = SubjectAccount\n) on $left.Computer == $right.Computer and $left.SubjectLogonId == $right.SubjectLogonId and $left.ProcessId == $right.ProcessId\n| project TimeGenerated, Computer, Account, SubjectDomainName, SubjectUserName, SubjectLogonId, ObjectName, Process, ProcessName, ProcessId, EventID\n| extend HostName = tostring(split(Computer, '.', 0)[0]), DnsDomain = tostring(strcat_array(array_slice(split(Computer, '.'), 1, -1), '.'))\n)\n)" + }, + "schedule": { + "frequency": "P1D" + }, + "detectionAction": { + "alertTemplate": { + "title": "Microsoft Entra ID Local Device Join Information and Transport Key Registry Keys Access", + "description": "'This detection uses Windows security events to detect suspicious access attempts by the same process to registry keys that provide information about an Microsoft Entra ID joined or registered devices and Transport keys (tkpub / tkpriv).\n This information can be used to export the Device Certificate (dkpub / dkpriv) and Transport key (tkpub/tkpriv).\n These set of keys can be used to impersonate existing Microsoft Entra ID joined devices.\n This detection requires an access control entry (ACE) on the system access control list (SACL) of the following securable objects:\n HKLM:\\SYSTEM\\CurrentContr", + "tactics": [ + { + "tactic": "Discovery", + "techniques": [ + { + "technique": "T1012" + } + ] + } + ], + "entityMappings": { + "accounts": [ + { + "ntDomainColumn": "SubjectDomainName", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "SubjectUserName" + } + ], + "hosts": [ + { + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ] + }, + "severity": "medium", + "customDetails": { + "HostFullName": "Computer", + "AccountFullName": "Account" + } + } + }, + "status": "disabled", + "displayName": "Microsoft Entra ID Local Device Join Information and Transport Key Registry Keys Access" + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-a356c8bd-c81d-428b-aa36-83be706be034", + "contentKind": "CustomDetection", + "displayName": "Microsoft Entra ID Local Device Join Information and Transport Key Registry Keys Access", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-a356c8bd-c81d-428b-aa36-83be706be034','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-a356c8bd-c81d-428b-aa36-83be706be034','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "WindowsSecurityEvents-CD-xdr-cf3ede88-a429-493b-9108-3e-64b668ea", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-cf3ede88-a429-493b-9108-3e46d3c741f7', 'xdr-cf3ede88-a429-493b-9108-3e46d3c741f7')]", + "queryCondition": { + "queryText": "let timeRange = 2h;\nlet authenticationWindow = 1h;\nlet authenticationThreshold = 5;\nSecurityEvent\n| where TimeGenerated > ago(timeRange)\n| where EventID in (4624, 4625)\n| where IpAddress != \"-\" and isnotempty(Account)\n| extend Outcome = iff(EventID == 4624, \"Success\", \"Failure\")\n// bin outcomes into 10 minute windows to reduce the volume of data\n| summarize OutcomeCount=count() by bin(TimeGenerated, 10m), Account, IpAddress, Computer, Outcome\n| project TimeGenerated, Account, IpAddress, Computer, Outcome, OutcomeCount\n// sort ready for sessionizing - by account and time of the authentication outcome\n| sort by TimeGenerated asc, Account, IpAddress, Computer, Outcome, OutcomeCount\n| serialize\n// sessionize into failure groupings until either the account changes or there is a success\n| extend SessionStartedUtc = row_window_session(TimeGenerated, timeRange, authenticationWindow, Account != prev(Account) or prev(Outcome) == \"Success\")\n// count the failures in each session\n| summarize FailureCountBeforeSuccess=sumif(OutcomeCount, Outcome == \"Failure\"), StartTime=min(TimeGenerated), EndTime=max(TimeGenerated), make_list(Outcome, 128), make_set(Computer, 128), make_set(IpAddress, 128) by SessionStartedUtc, Account\n// the session must not start with a success, and must end with one\n| where array_index_of(list_Outcome, \"Success\") != 0\n| where array_index_of(list_Outcome, \"Success\") == array_length(list_Outcome) - 1\n| project-away SessionStartedUtc, list_Outcome\n// where the number of failures before the success is above the threshold\n| where FailureCountBeforeSuccess >= authenticationThreshold\n// expand out ip and computer for customer entity assignment\n| mv-expand set_IpAddress, set_Computer\n| extend IpAddress = tostring(set_IpAddress), Computer = tostring(set_Computer)\n| extend timestamp=StartTime, NTDomain = split(Account, '\\\\', 0)[0], Name = split(Account, '\\\\', 1)[0], HostName = tostring(split(Computer, '.', 0)[0]), DnsDomain = tostring(strcat_array(array_slice(split(Computer, '.'), 1, -1), '.'))" + }, + "schedule": { + "frequency": "PT2H" + }, + "detectionAction": { + "alertTemplate": { + "severity": "low", + "entityMappings": { + "accounts": [ + { + "ntDomainColumn": "NTDomain", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "Name" + } + ], + "hosts": [ + { + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ], + "ips": [ + { + "id": "[if(true(), 'ip1', 'ip1')]", + "addressColumn": "IpAddress" + } + ] + }, + "title": "SecurityEvent - Multiple authentication failures followed by a success", + "description": "'Identifies accounts who have failed to logon to the domain multiple times in a row, followed by a successful authentication within a short time frame. Multiple failed attempts followed by a success can be an indication of a brute force attempt or possible mis-configuration of a service account within an environment.\nThe lookback is set to 2h and the authentication window and threshold are set to 1h and 5, meaning we need to see a minimum of 5 failures followed by a success for an account within 1 hour to surface an alert.'", + "tactics": [ + { + "tactic": "CredentialAccess", + "techniques": [ + { + "technique": "T1110" + } + ] + } + ] + } + }, + "status": "disabled", + "displayName": "SecurityEvent - Multiple authentication failures followed by a success" + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-cf3ede88-a429-493b-9108-3e46d3c741f7')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'WindowsSecurityEvents-CD-xdr-cf3ede88-a429-493b-9108-3e-64b668ea')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'Identifies accounts who have failed to logon to the domain multiple times in a row, followed by a successful authentication within a short time frame. Multiple failed attempts followed by a success can be an indication of a brute force attempt or possible mis-configuration of a service account within an environment.\nThe lookback is set to 2h and the authentication window and threshold are set to 1h and 5, meaning we need to see a minimum of 5 failures followed by a success for an account within 1 hour to surface an alert.'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-cf3ede88-a429-493b-9108-3e46d3c741f7', 'xdr-cf3ede88-a429-493b-9108-3e46d3c741f7')]", + "queryCondition": { + "queryText": "let timeRange = 2h;\nlet authenticationWindow = 1h;\nlet authenticationThreshold = 5;\nSecurityEvent\n| where TimeGenerated > ago(timeRange)\n| where EventID in (4624, 4625)\n| where IpAddress != \"-\" and isnotempty(Account)\n| extend Outcome = iff(EventID == 4624, \"Success\", \"Failure\")\n// bin outcomes into 10 minute windows to reduce the volume of data\n| summarize OutcomeCount=count() by bin(TimeGenerated, 10m), Account, IpAddress, Computer, Outcome\n| project TimeGenerated, Account, IpAddress, Computer, Outcome, OutcomeCount\n// sort ready for sessionizing - by account and time of the authentication outcome\n| sort by TimeGenerated asc, Account, IpAddress, Computer, Outcome, OutcomeCount\n| serialize\n// sessionize into failure groupings until either the account changes or there is a success\n| extend SessionStartedUtc = row_window_session(TimeGenerated, timeRange, authenticationWindow, Account != prev(Account) or prev(Outcome) == \"Success\")\n// count the failures in each session\n| summarize FailureCountBeforeSuccess=sumif(OutcomeCount, Outcome == \"Failure\"), StartTime=min(TimeGenerated), EndTime=max(TimeGenerated), make_list(Outcome, 128), make_set(Computer, 128), make_set(IpAddress, 128) by SessionStartedUtc, Account\n// the session must not start with a success, and must end with one\n| where array_index_of(list_Outcome, \"Success\") != 0\n| where array_index_of(list_Outcome, \"Success\") == array_length(list_Outcome) - 1\n| project-away SessionStartedUtc, list_Outcome\n// where the number of failures before the success is above the threshold\n| where FailureCountBeforeSuccess >= authenticationThreshold\n// expand out ip and computer for customer entity assignment\n| mv-expand set_IpAddress, set_Computer\n| extend IpAddress = tostring(set_IpAddress), Computer = tostring(set_Computer)\n| extend timestamp=StartTime, NTDomain = split(Account, '\\\\', 0)[0], Name = split(Account, '\\\\', 1)[0], HostName = tostring(split(Computer, '.', 0)[0]), DnsDomain = tostring(strcat_array(array_slice(split(Computer, '.'), 1, -1), '.'))" + }, + "schedule": { + "frequency": "PT2H" + }, + "detectionAction": { + "alertTemplate": { + "severity": "low", + "entityMappings": { + "accounts": [ + { + "ntDomainColumn": "NTDomain", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "Name" + } + ], + "hosts": [ + { + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ], + "ips": [ + { + "id": "[if(true(), 'ip1', 'ip1')]", + "addressColumn": "IpAddress" + } + ] + }, + "title": "SecurityEvent - Multiple authentication failures followed by a success", + "description": "'Identifies accounts who have failed to logon to the domain multiple times in a row, followed by a successful authentication within a short time frame. Multiple failed attempts followed by a success can be an indication of a brute force attempt or possible mis-configuration of a service account within an environment.\nThe lookback is set to 2h and the authentication window and threshold are set to 1h and 5, meaning we need to see a minimum of 5 failures followed by a success for an account within 1 hour to surface an alert.'", + "tactics": [ + { + "tactic": "CredentialAccess", + "techniques": [ + { + "technique": "T1110" + } + ] + } + ] + } + }, + "status": "disabled", + "displayName": "SecurityEvent - Multiple authentication failures followed by a success" + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-cf3ede88-a429-493b-9108-3e46d3c741f7", + "contentKind": "CustomDetection", + "displayName": "SecurityEvent - Multiple authentication failures followed by a success", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-cf3ede88-a429-493b-9108-3e46d3c741f7','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-cf3ede88-a429-493b-9108-3e46d3c741f7','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "WindowsSecurityEvents-CD-xdr-508cef41-2cd8-4d40-a519-b0-4ff9dff1", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-508cef41-2cd8-4d40-a519-b04826a9085f', 'xdr-508cef41-2cd8-4d40-a519-b04826a9085f')]", + "queryCondition": { + "queryText": "SecurityEvent\n| where EventID == 1102 and EventSourceName == \"Microsoft-Windows-Eventlog\"\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), EventCount = count() by Computer, Account, EventID, Activity\n| extend HostName = tostring(split(Computer, \".\")[0]), DomainIndex = toint(indexof(Computer, '.'))\n| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)\n| extend AccountName = tostring(split(Account, @'\\')[1]), AccountNTDomain = tostring(split(Account, @'\\')[0])" + }, + "schedule": { + "frequency": "PT1H" + }, + "detectionAction": { + "alertTemplate": { + "title": "NRT Security Event log cleared", + "description": "'Checks for event id 1102 which indicates the security event log was cleared.\nIt uses Event Source Name \"Microsoft-Windows-Eventlog\" to avoid generating false positives from other sources, like AD FS servers for instance.'", + "tactics": [ + { + "tactic": "DefenseEvasion", + "techniques": [ + { + "technique": "T1070" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "dnsDomainColumn": "HostNameDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ] + }, + "severity": "medium", + "customDetails": { + "AccountName": "AccountName", + "AccountNTDomain": "AccountNTDomain", + "HostFullName": "Computer", + "AccountFullName": "Account" + } + } + }, + "status": "disabled", + "displayName": "NRT Security Event log cleared" + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-508cef41-2cd8-4d40-a519-b04826a9085f')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'WindowsSecurityEvents-CD-xdr-508cef41-2cd8-4d40-a519-b0-4ff9dff1')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'Checks for event id 1102 which indicates the security event log was cleared.\nIt uses Event Source Name \"Microsoft-Windows-Eventlog\" to avoid generating false positives from other sources, like AD FS servers for instance.'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-508cef41-2cd8-4d40-a519-b04826a9085f', 'xdr-508cef41-2cd8-4d40-a519-b04826a9085f')]", + "queryCondition": { + "queryText": "SecurityEvent\n| where EventID == 1102 and EventSourceName == \"Microsoft-Windows-Eventlog\"\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), EventCount = count() by Computer, Account, EventID, Activity\n| extend HostName = tostring(split(Computer, \".\")[0]), DomainIndex = toint(indexof(Computer, '.'))\n| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)\n| extend AccountName = tostring(split(Account, @'\\')[1]), AccountNTDomain = tostring(split(Account, @'\\')[0])" + }, + "schedule": { + "frequency": "PT1H" + }, + "detectionAction": { + "alertTemplate": { + "title": "NRT Security Event log cleared", + "description": "'Checks for event id 1102 which indicates the security event log was cleared.\nIt uses Event Source Name \"Microsoft-Windows-Eventlog\" to avoid generating false positives from other sources, like AD FS servers for instance.'", + "tactics": [ + { + "tactic": "DefenseEvasion", + "techniques": [ + { + "technique": "T1070" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "dnsDomainColumn": "HostNameDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ] + }, + "severity": "medium", + "customDetails": { + "AccountName": "AccountName", + "AccountNTDomain": "AccountNTDomain", + "HostFullName": "Computer", + "AccountFullName": "Account" + } + } + }, + "status": "disabled", + "displayName": "NRT Security Event log cleared" + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-508cef41-2cd8-4d40-a519-b04826a9085f", + "contentKind": "CustomDetection", + "displayName": "NRT Security Event log cleared", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-508cef41-2cd8-4d40-a519-b04826a9085f','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-508cef41-2cd8-4d40-a519-b04826a9085f','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "WindowsSecurityEvents-CD-xdr-c3e5dbaa-a540-408c-8b36-68-3001d591", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-c3e5dbaa-a540-408c-8b36-68bdfb3df088', 'xdr-c3e5dbaa-a540-408c-8b36-68bdfb3df088')]", + "queryCondition": { + "queryText": "SecurityEvent\n | where EventID == 4688\n | where isnotempty(CommandLine)\n | where CommandLine contains \"TVqQAAMAAAAEAAA\"\n | extend HostName = tostring(split(Computer, '.', 0)[0]), DnsDomain = tostring(strcat_array(array_slice(split(Computer, '.'), 1, -1), '.'))" + }, + "schedule": { + "frequency": "PT1H" + }, + "detectionAction": { + "alertTemplate": { + "title": "NRT Base64 Encoded Windows Process Command-lines", + "description": "'This detection identifies instances of a base64 encoded PE file header seen in the process command line parameter.'", + "tactics": [ + { + "tactic": "Execution", + "techniques": [ + { + "technique": "T1059" + } + ] + } + ], + "entityMappings": { + "accounts": [ + { + "ntDomainColumn": "SubjectDomainName", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "SubjectUserName" + } + ], + "hosts": [ + { + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ] + }, + "severity": "medium", + "customDetails": { + "HostFullName": "Computer", + "AccountFullName": "SubjectAccount" + } + } + }, + "status": "disabled", + "displayName": "NRT Base64 Encoded Windows Process Command-lines" + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-c3e5dbaa-a540-408c-8b36-68bdfb3df088')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'WindowsSecurityEvents-CD-xdr-c3e5dbaa-a540-408c-8b36-68-3001d591')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'This detection identifies instances of a base64 encoded PE file header seen in the process command line parameter.'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-c3e5dbaa-a540-408c-8b36-68bdfb3df088', 'xdr-c3e5dbaa-a540-408c-8b36-68bdfb3df088')]", + "queryCondition": { + "queryText": "SecurityEvent\n | where EventID == 4688\n | where isnotempty(CommandLine)\n | where CommandLine contains \"TVqQAAMAAAAEAAA\"\n | extend HostName = tostring(split(Computer, '.', 0)[0]), DnsDomain = tostring(strcat_array(array_slice(split(Computer, '.'), 1, -1), '.'))" + }, + "schedule": { + "frequency": "PT1H" + }, + "detectionAction": { + "alertTemplate": { + "title": "NRT Base64 Encoded Windows Process Command-lines", + "description": "'This detection identifies instances of a base64 encoded PE file header seen in the process command line parameter.'", + "tactics": [ + { + "tactic": "Execution", + "techniques": [ + { + "technique": "T1059" + } + ] + } + ], + "entityMappings": { + "accounts": [ + { + "ntDomainColumn": "SubjectDomainName", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "SubjectUserName" + } + ], + "hosts": [ + { + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ] + }, + "severity": "medium", + "customDetails": { + "HostFullName": "Computer", + "AccountFullName": "SubjectAccount" + } + } + }, + "status": "disabled", + "displayName": "NRT Base64 Encoded Windows Process Command-lines" + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-c3e5dbaa-a540-408c-8b36-68bdfb3df088", + "contentKind": "CustomDetection", + "displayName": "NRT Base64 Encoded Windows Process Command-lines", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-c3e5dbaa-a540-408c-8b36-68bdfb3df088','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-c3e5dbaa-a540-408c-8b36-68bdfb3df088','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "WindowsSecurityEvents-CD-xdr-7ad4c32b-d0d2-411c-a0e8-b5-3105beaa", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-7ad4c32b-d0d2-411c-a0e8-b557afa12fce', 'xdr-7ad4c32b-d0d2-411c-a0e8-b557afa12fce')]", + "queryCondition": { + "queryText": "SecurityEvent\n| where EventID==4688\n| where isnotempty(CommandLine)\n| project TimeGenerated, Computer, AccountName = SubjectUserName, AccountNTDomain = SubjectDomainName, FileName = Process, CommandLine, ParentProcessName, SubjectAccount\n| extend HostName = tostring(split(Computer, \".\")[0]), DomainIndex = toint(indexof(Computer, '.'))\n| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)\n| where CommandLine contains \".decode('base64')\"\n or CommandLine contains \"base64 --decode\"\n or CommandLine contains \".decode64(\"" + }, + "schedule": { + "frequency": "PT1H" + }, + "detectionAction": { + "alertTemplate": { + "title": "NRT Process executed from binary hidden in Base64 encoded file", + "description": "'Encoding malicious software is a technique used to obfuscate files from detection.\nThe first CommandLine component is looking for Python decoding base64.\nThe second CommandLine component is looking for Bash/sh command line base64 decoding.\nThe third one is looking for Ruby decoding base64.'", + "tactics": [ + { + "tactic": "Execution", + "techniques": [ + { + "technique": "T1059" + } + ] + } + ], + "entityMappings": { + "accounts": [ + { + "ntDomainColumn": "AccountNTDomain", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "AccountName" + } + ], + "hosts": [ + { + "dnsDomainColumn": "HostNameDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ] + }, + "severity": "medium", + "customDetails": { + "HostFullName": "Computer", + "AccountFullName": "SubjectAccount" + } + } + }, + "status": "disabled", + "displayName": "NRT Process executed from binary hidden in Base64 encoded file" + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-7ad4c32b-d0d2-411c-a0e8-b557afa12fce')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'WindowsSecurityEvents-CD-xdr-7ad4c32b-d0d2-411c-a0e8-b5-3105beaa')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'Encoding malicious software is a technique used to obfuscate files from detection.\nThe first CommandLine component is looking for Python decoding base64.\nThe second CommandLine component is looking for Bash/sh command line base64 decoding.\nThe third one is looking for Ruby decoding base64.'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-7ad4c32b-d0d2-411c-a0e8-b557afa12fce', 'xdr-7ad4c32b-d0d2-411c-a0e8-b557afa12fce')]", + "queryCondition": { + "queryText": "SecurityEvent\n| where EventID==4688\n| where isnotempty(CommandLine)\n| project TimeGenerated, Computer, AccountName = SubjectUserName, AccountNTDomain = SubjectDomainName, FileName = Process, CommandLine, ParentProcessName, SubjectAccount\n| extend HostName = tostring(split(Computer, \".\")[0]), DomainIndex = toint(indexof(Computer, '.'))\n| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)\n| where CommandLine contains \".decode('base64')\"\n or CommandLine contains \"base64 --decode\"\n or CommandLine contains \".decode64(\"" + }, + "schedule": { + "frequency": "PT1H" + }, + "detectionAction": { + "alertTemplate": { + "title": "NRT Process executed from binary hidden in Base64 encoded file", + "description": "'Encoding malicious software is a technique used to obfuscate files from detection.\nThe first CommandLine component is looking for Python decoding base64.\nThe second CommandLine component is looking for Bash/sh command line base64 decoding.\nThe third one is looking for Ruby decoding base64.'", + "tactics": [ + { + "tactic": "Execution", + "techniques": [ + { + "technique": "T1059" + } + ] + } + ], + "entityMappings": { + "accounts": [ + { + "ntDomainColumn": "AccountNTDomain", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "AccountName" + } + ], + "hosts": [ + { + "dnsDomainColumn": "HostNameDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ] + }, + "severity": "medium", + "customDetails": { + "HostFullName": "Computer", + "AccountFullName": "SubjectAccount" + } + } + }, + "status": "disabled", + "displayName": "NRT Process executed from binary hidden in Base64 encoded file" + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-7ad4c32b-d0d2-411c-a0e8-b557afa12fce", + "contentKind": "CustomDetection", + "displayName": "NRT Process executed from binary hidden in Base64 encoded file", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-7ad4c32b-d0d2-411c-a0e8-b557afa12fce','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-7ad4c32b-d0d2-411c-a0e8-b557afa12fce','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "WindowsSecurityEvents-CD-xdr-05b4bccd-dd12-423d-8de4-5a-2b60668c", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-05b4bccd-dd12-423d-8de4-5a6fb526bb4f', 'xdr-05b4bccd-dd12-423d-8de4-5a6fb526bb4f')]", + "queryCondition": { + "queryText": "let known_processes = (\n SecurityEvent\n // If adjusting Query Period or Frequency update these\n | where TimeGenerated between(ago(14d)..ago(1d))\n | where EventID == 4688\n | where NewProcessName has_any (\"Policies\\\\{6AC1786C-016F-11D2-945F-00C04fB984F9}\", \"Policies\\\\{31B2F340-016D-11D2-945F-00C04FB984F9}\")\n | summarize by Process);\n SecurityEvent\n // If adjusting Query Period or Frequency update these\n | where TimeGenerated > ago(1d)\n | where EventID == 4688\n | where NewProcessName has_any (\"Policies\\\\{6AC1786C-016F-11D2-945F-00C04fB984F9}\", \"Policies\\\\{31B2F340-016D-11D2-945F-00C04FB984F9}\")\n | where Process !in (known_processes)\n // This will likely apply to multiple hosts so summarize these data\n | summarize FirstSeen=min(TimeGenerated), LastSeen=max(TimeGenerated) by Process, NewProcessName, CommandLine, Computer\n | extend HostName = tostring(split(Computer, \".\")[0]), DomainIndex = toint(indexof(Computer, '.'))\n | extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)" + }, + "schedule": { + "frequency": "P1D" + }, + "detectionAction": { + "alertTemplate": { + "title": "New EXE deployed via Default Domain or Default Domain Controller Policies", + "description": "'This detection highlights executables deployed to hosts via either the Default Domain or Default Domain Controller Policies. These policies apply to all hosts or Domain Controllers and best practice is that these policies should not be used for deployment of files.\nA threat actor may use these policies to deploy files or scripts to all hosts in a domain.'", + "tactics": [ + { + "tactic": "Execution", + "techniques": [ + { + "technique": "T1072" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "dnsDomainColumn": "HostNameDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ] + }, + "severity": "high", + "customDetails": { + "HostFullName": "Computer" + } + } + }, + "status": "disabled", + "displayName": "New EXE deployed via Default Domain or Default Domain Controller Policies" + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-05b4bccd-dd12-423d-8de4-5a6fb526bb4f')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'WindowsSecurityEvents-CD-xdr-05b4bccd-dd12-423d-8de4-5a-2b60668c')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'This detection highlights executables deployed to hosts via either the Default Domain or Default Domain Controller Policies. These policies apply to all hosts or Domain Controllers and best practice is that these policies should not be used for deployment of files.\nA threat actor may use these policies to deploy files or scripts to all hosts in a domain.'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-05b4bccd-dd12-423d-8de4-5a6fb526bb4f', 'xdr-05b4bccd-dd12-423d-8de4-5a6fb526bb4f')]", + "queryCondition": { + "queryText": "let known_processes = (\n SecurityEvent\n // If adjusting Query Period or Frequency update these\n | where TimeGenerated between(ago(14d)..ago(1d))\n | where EventID == 4688\n | where NewProcessName has_any (\"Policies\\\\{6AC1786C-016F-11D2-945F-00C04fB984F9}\", \"Policies\\\\{31B2F340-016D-11D2-945F-00C04FB984F9}\")\n | summarize by Process);\n SecurityEvent\n // If adjusting Query Period or Frequency update these\n | where TimeGenerated > ago(1d)\n | where EventID == 4688\n | where NewProcessName has_any (\"Policies\\\\{6AC1786C-016F-11D2-945F-00C04fB984F9}\", \"Policies\\\\{31B2F340-016D-11D2-945F-00C04FB984F9}\")\n | where Process !in (known_processes)\n // This will likely apply to multiple hosts so summarize these data\n | summarize FirstSeen=min(TimeGenerated), LastSeen=max(TimeGenerated) by Process, NewProcessName, CommandLine, Computer\n | extend HostName = tostring(split(Computer, \".\")[0]), DomainIndex = toint(indexof(Computer, '.'))\n | extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)" + }, + "schedule": { + "frequency": "P1D" + }, + "detectionAction": { + "alertTemplate": { + "title": "New EXE deployed via Default Domain or Default Domain Controller Policies", + "description": "'This detection highlights executables deployed to hosts via either the Default Domain or Default Domain Controller Policies. These policies apply to all hosts or Domain Controllers and best practice is that these policies should not be used for deployment of files.\nA threat actor may use these policies to deploy files or scripts to all hosts in a domain.'", + "tactics": [ + { + "tactic": "Execution", + "techniques": [ + { + "technique": "T1072" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "dnsDomainColumn": "HostNameDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ] + }, + "severity": "high", + "customDetails": { + "HostFullName": "Computer" + } + } + }, + "status": "disabled", + "displayName": "New EXE deployed via Default Domain or Default Domain Controller Policies" + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-05b4bccd-dd12-423d-8de4-5a6fb526bb4f", + "contentKind": "CustomDetection", + "displayName": "New EXE deployed via Default Domain or Default Domain Controller Policies", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-05b4bccd-dd12-423d-8de4-5a6fb526bb4f','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-05b4bccd-dd12-423d-8de4-5a6fb526bb4f','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "WindowsSecurityEvents-CD-xdr-b9d2eebc-5dcb-4888-8165-90-5aeafc5c", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-b9d2eebc-5dcb-4888-8165-900db44443ab', 'xdr-b9d2eebc-5dcb-4888-8165-900db44443ab')]", + "queryCondition": { + "queryText": "// Enter a reference list of hostnames for your DC servers\n//let DCServersList = dynamic ([\"DC01.simulandlabs.com\",\"DC02.simulandlabs.com\"]);\nSecurityEvent\n//| where Computer in (DCServersList)\n| where EventID == 4662 and ObjectServer == 'DS'\n| where AccountType != 'Machine'\n| where Properties has '1131f6aa-9c07-11d1-f79f-00c04fc2dcd2' //DS-Replication-Get-Changes\n or Properties has '1131f6ad-9c07-11d1-f79f-00c04fc2dcd2' //DS-Replication-Get-Changes-All\n or Properties has '89e95b76-444d-4c62-991a-0facbeda640c' //DS-Replication-Get-Changes-In-Filtered-Set\n| project TimeGenerated, Account, Activity, Properties, SubjectLogonId, Computer\n| join kind=leftouter\n(\n SecurityEvent\n //| where Computer in (DCServersList)\n | where EventID == 4624 and LogonType == 3\n | where AccountType != 'Machine'\n | project TargetLogonId, IpAddress, Computer\n)\non $left.SubjectLogonId == $right.TargetLogonId and $left.Computer == $right.Computer\n| project-reorder TimeGenerated, Computer, Account, IpAddress\n| extend HostName = tostring(split(Computer, \".\")[0]), DomainIndex = toint(indexof(Computer, '.'))\n| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)\n| extend AccountNTDomain = tostring(split(Account, \"\\\\\")[0]), AccountName = tostring(split(Account, \"\\\\\")[1])" + }, + "schedule": { + "frequency": "P1D" + }, + "detectionAction": { + "alertTemplate": { + "title": "Non Domain Controller Active Directory Replication", + "description": "'This query detects potential attempts by non-computer accounts (non domain controllers) to retrieve/synchronize an active directory object leveraging directory replication services (DRS).\nA Domain Controller (computer account) would usually be performing these actions in a domain environment. Another detection rule can be created to cover domain controllers accounts doing at rare times.\nA domain user with privileged permissions to use directory replication services is rare.'", + "tactics": [ + { + "tactic": "CredentialAccess", + "techniques": [ + { + "subTechniques": [ + "T1003.006" + ], + "technique": "T1003" + } + ] + } + ], + "entityMappings": { + "accounts": [ + { + "ntDomainColumn": "AccountNTDomain", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "AccountName" + } + ], + "hosts": [ + { + "ntDomainColumn": "HostNameDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ], + "ips": [ + { + "id": "[if(true(), 'ip1', 'ip1')]", + "addressColumn": "IpAddress" + } + ] + }, + "severity": "high", + "customDetails": { + "HostFullName": "Computer", + "AccountFullName": "Account" + } + } + }, + "status": "disabled", + "displayName": "Non Domain Controller Active Directory Replication" + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-b9d2eebc-5dcb-4888-8165-900db44443ab')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'WindowsSecurityEvents-CD-xdr-b9d2eebc-5dcb-4888-8165-90-5aeafc5c')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'This query detects potential attempts by non-computer accounts (non domain controllers) to retrieve/synchronize an active directory object leveraging directory replication services (DRS).\nA Domain Controller (computer account) would usually be performing these actions in a domain environment. Another detection rule can be created to cover domain controllers accounts doing at rare times.\nA domain user with privileged permissions to use directory replication services is rare.'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-b9d2eebc-5dcb-4888-8165-900db44443ab', 'xdr-b9d2eebc-5dcb-4888-8165-900db44443ab')]", + "queryCondition": { + "queryText": "// Enter a reference list of hostnames for your DC servers\n//let DCServersList = dynamic ([\"DC01.simulandlabs.com\",\"DC02.simulandlabs.com\"]);\nSecurityEvent\n//| where Computer in (DCServersList)\n| where EventID == 4662 and ObjectServer == 'DS'\n| where AccountType != 'Machine'\n| where Properties has '1131f6aa-9c07-11d1-f79f-00c04fc2dcd2' //DS-Replication-Get-Changes\n or Properties has '1131f6ad-9c07-11d1-f79f-00c04fc2dcd2' //DS-Replication-Get-Changes-All\n or Properties has '89e95b76-444d-4c62-991a-0facbeda640c' //DS-Replication-Get-Changes-In-Filtered-Set\n| project TimeGenerated, Account, Activity, Properties, SubjectLogonId, Computer\n| join kind=leftouter\n(\n SecurityEvent\n //| where Computer in (DCServersList)\n | where EventID == 4624 and LogonType == 3\n | where AccountType != 'Machine'\n | project TargetLogonId, IpAddress, Computer\n)\non $left.SubjectLogonId == $right.TargetLogonId and $left.Computer == $right.Computer\n| project-reorder TimeGenerated, Computer, Account, IpAddress\n| extend HostName = tostring(split(Computer, \".\")[0]), DomainIndex = toint(indexof(Computer, '.'))\n| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)\n| extend AccountNTDomain = tostring(split(Account, \"\\\\\")[0]), AccountName = tostring(split(Account, \"\\\\\")[1])" + }, + "schedule": { + "frequency": "P1D" + }, + "detectionAction": { + "alertTemplate": { + "title": "Non Domain Controller Active Directory Replication", + "description": "'This query detects potential attempts by non-computer accounts (non domain controllers) to retrieve/synchronize an active directory object leveraging directory replication services (DRS).\nA Domain Controller (computer account) would usually be performing these actions in a domain environment. Another detection rule can be created to cover domain controllers accounts doing at rare times.\nA domain user with privileged permissions to use directory replication services is rare.'", + "tactics": [ + { + "tactic": "CredentialAccess", + "techniques": [ + { + "subTechniques": [ + "T1003.006" + ], + "technique": "T1003" + } + ] + } + ], + "entityMappings": { + "accounts": [ + { + "ntDomainColumn": "AccountNTDomain", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "AccountName" + } + ], + "hosts": [ + { + "ntDomainColumn": "HostNameDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ], + "ips": [ + { + "id": "[if(true(), 'ip1', 'ip1')]", + "addressColumn": "IpAddress" + } + ] + }, + "severity": "high", + "customDetails": { + "HostFullName": "Computer", + "AccountFullName": "Account" + } + } + }, + "status": "disabled", + "displayName": "Non Domain Controller Active Directory Replication" + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-b9d2eebc-5dcb-4888-8165-900db44443ab", + "contentKind": "CustomDetection", + "displayName": "Non Domain Controller Active Directory Replication", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-b9d2eebc-5dcb-4888-8165-900db44443ab','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-b9d2eebc-5dcb-4888-8165-900db44443ab','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "WindowsSecurityEvents-CD-xdr-56f3f35c-3aca-4437-a1fb-b7-77f2fa99", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-56f3f35c-3aca-4437-a1fb-b7a84dc4af00', 'xdr-56f3f35c-3aca-4437-a1fb-b7a84dc4af00')]", + "queryCondition": { + "queryText": "SecurityEvent\n | where EventID == 4657\n | parse ObjectName with \"\\\\REGISTRY\\\\\" KeyPrefix \"\\\\\" RegistryKey\n | project-reorder RegistryKey\n | where RegistryKey has \"Software\\\\Classes\\\\ms-settings\\\\shell\\\\open\\\\command\"\n | extend TimeKey = bin(TimeGenerated, 1h)\n | join (\n SecurityEvent\n | where EventID == 4688\n | where Process =~ \"fodhelper.exe\"\n | where ParentProcessName endswith \"cmd.exe\" or ParentProcessName endswith \"powershell.exe\" or ParentProcessName endswith \"powershell_ise.exe\"\n | extend TimeKey = bin(TimeGenerated, 1h)) on TimeKey, Computer\n | extend HostName = tostring(split(Computer, \".\")[0]), DomainIndex = toint(indexof(Computer, '.'))\n | extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)\n | extend AccountName = tostring(split(TargetAccount, @'\\')[1]), AccountNTDomain = tostring(split(TargetAccount, @'\\')[0])" + }, + "schedule": { + "frequency": "PT2H" + }, + "detectionAction": { + "alertTemplate": { + "title": "Potential Fodhelper UAC Bypass", + "description": "'This detection looks for the steps required to conduct a UAC bypass using Fodhelper.exe. By default this detection looks for the setting of the required registry keys and the invoking of the process within 1 hour - this can be tweaked as required.'", + "tactics": [ + { + "tactic": "PrivilegeEscalation", + "techniques": [ + { + "subTechniques": [ + "T1548.002" + ], + "technique": "T1548" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "dnsDomainColumn": "HostNameDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ] + }, + "severity": "medium", + "customDetails": { + "AccountName": "AccountName", + "HostFullName": "Computer" + } + } + }, + "status": "disabled", + "displayName": "Potential Fodhelper UAC Bypass" + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-56f3f35c-3aca-4437-a1fb-b7a84dc4af00')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'WindowsSecurityEvents-CD-xdr-56f3f35c-3aca-4437-a1fb-b7-77f2fa99')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'This detection looks for the steps required to conduct a UAC bypass using Fodhelper.exe. By default this detection looks for the setting of the required registry keys and the invoking of the process within 1 hour - this can be tweaked as required.'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-56f3f35c-3aca-4437-a1fb-b7a84dc4af00', 'xdr-56f3f35c-3aca-4437-a1fb-b7a84dc4af00')]", + "queryCondition": { + "queryText": "SecurityEvent\n | where EventID == 4657\n | parse ObjectName with \"\\\\REGISTRY\\\\\" KeyPrefix \"\\\\\" RegistryKey\n | project-reorder RegistryKey\n | where RegistryKey has \"Software\\\\Classes\\\\ms-settings\\\\shell\\\\open\\\\command\"\n | extend TimeKey = bin(TimeGenerated, 1h)\n | join (\n SecurityEvent\n | where EventID == 4688\n | where Process =~ \"fodhelper.exe\"\n | where ParentProcessName endswith \"cmd.exe\" or ParentProcessName endswith \"powershell.exe\" or ParentProcessName endswith \"powershell_ise.exe\"\n | extend TimeKey = bin(TimeGenerated, 1h)) on TimeKey, Computer\n | extend HostName = tostring(split(Computer, \".\")[0]), DomainIndex = toint(indexof(Computer, '.'))\n | extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)\n | extend AccountName = tostring(split(TargetAccount, @'\\')[1]), AccountNTDomain = tostring(split(TargetAccount, @'\\')[0])" + }, + "schedule": { + "frequency": "PT2H" + }, + "detectionAction": { + "alertTemplate": { + "title": "Potential Fodhelper UAC Bypass", + "description": "'This detection looks for the steps required to conduct a UAC bypass using Fodhelper.exe. By default this detection looks for the setting of the required registry keys and the invoking of the process within 1 hour - this can be tweaked as required.'", + "tactics": [ + { + "tactic": "PrivilegeEscalation", + "techniques": [ + { + "subTechniques": [ + "T1548.002" + ], + "technique": "T1548" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "dnsDomainColumn": "HostNameDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ] + }, + "severity": "medium", + "customDetails": { + "AccountName": "AccountName", + "HostFullName": "Computer" + } + } + }, + "status": "disabled", + "displayName": "Potential Fodhelper UAC Bypass" + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-56f3f35c-3aca-4437-a1fb-b7a84dc4af00", + "contentKind": "CustomDetection", + "displayName": "Potential Fodhelper UAC Bypass", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-56f3f35c-3aca-4437-a1fb-b7a84dc4af00','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-56f3f35c-3aca-4437-a1fb-b7a84dc4af00','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "WindowsSecurityEvents-CD-xdr-720d12c6-a08c-44c4-b18f-22-6dc59b12", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-720d12c6-a08c-44c4-b18f-2236412d59b0', 'xdr-720d12c6-a08c-44c4-b18f-2236412d59b0')]", + "queryCondition": { + "queryText": "SecurityEvent\n | where EventID == 4688\n | where Process !~ \"sdelete.exe\"\n | where CommandLine has_all (\"accepteula\", \"-r\", \"-s\", \"-q\", \"c:/\")\n | where CommandLine !has (\"sdelete\")\n | extend HostName = tostring(split(Computer, \".\")[0]), DomainIndex = toint(indexof(Computer, '.'))\n | extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)\n | extend AccountName = tostring(split(TargetAccount, @'\\')[1]), AccountNTDomain = tostring(split(TargetAccount, @'\\')[0])" + }, + "schedule": { + "frequency": "PT1H" + }, + "detectionAction": { + "alertTemplate": { + "title": "Potential re-named sdelete usage", + "description": "'This detection looks for command line parameters associated with the use of Sysinternals sdelete (https://docs.microsoft.com/sysinternals/downloads/sdelete) to delete multiple files on a host's C drive.\nA threat actor may re-name the tool to avoid detection and then use it for destructive attacks on a host.'", + "tactics": [ + { + "tactic": "DefenseEvasion", + "techniques": [ + { + "technique": "T1036" + } + ] + } + ], + "entityMappings": { + "accounts": [ + { + "ntDomainColumn": "AccountNTDomain", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "AccountName" + } + ], + "hosts": [ + { + "dnsDomainColumn": "HostNameDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ] + }, + "severity": "low", + "customDetails": { + "HostFullName": "Computer", + "AccountFullName": "TargetAccount" + } + } + }, + "status": "disabled", + "displayName": "Potential re-named sdelete usage" + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-720d12c6-a08c-44c4-b18f-2236412d59b0')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'WindowsSecurityEvents-CD-xdr-720d12c6-a08c-44c4-b18f-22-6dc59b12')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'This detection looks for command line parameters associated with the use of Sysinternals sdelete (https://docs.microsoft.com/sysinternals/downloads/sdelete) to delete multiple files on a host's C drive.\nA threat actor may re-name the tool to avoid detection and then use it for destructive attacks on a host.'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-720d12c6-a08c-44c4-b18f-2236412d59b0', 'xdr-720d12c6-a08c-44c4-b18f-2236412d59b0')]", + "queryCondition": { + "queryText": "SecurityEvent\n | where EventID == 4688\n | where Process !~ \"sdelete.exe\"\n | where CommandLine has_all (\"accepteula\", \"-r\", \"-s\", \"-q\", \"c:/\")\n | where CommandLine !has (\"sdelete\")\n | extend HostName = tostring(split(Computer, \".\")[0]), DomainIndex = toint(indexof(Computer, '.'))\n | extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)\n | extend AccountName = tostring(split(TargetAccount, @'\\')[1]), AccountNTDomain = tostring(split(TargetAccount, @'\\')[0])" + }, + "schedule": { + "frequency": "PT1H" + }, + "detectionAction": { + "alertTemplate": { + "title": "Potential re-named sdelete usage", + "description": "'This detection looks for command line parameters associated with the use of Sysinternals sdelete (https://docs.microsoft.com/sysinternals/downloads/sdelete) to delete multiple files on a host's C drive.\nA threat actor may re-name the tool to avoid detection and then use it for destructive attacks on a host.'", + "tactics": [ + { + "tactic": "DefenseEvasion", + "techniques": [ + { + "technique": "T1036" + } + ] + } + ], + "entityMappings": { + "accounts": [ + { + "ntDomainColumn": "AccountNTDomain", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "AccountName" + } + ], + "hosts": [ + { + "dnsDomainColumn": "HostNameDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ] + }, + "severity": "low", + "customDetails": { + "HostFullName": "Computer", + "AccountFullName": "TargetAccount" + } + } + }, + "status": "disabled", + "displayName": "Potential re-named sdelete usage" + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-720d12c6-a08c-44c4-b18f-2236412d59b0", + "contentKind": "CustomDetection", + "displayName": "Potential re-named sdelete usage", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-720d12c6-a08c-44c4-b18f-2236412d59b0','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-720d12c6-a08c-44c4-b18f-2236412d59b0','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "WindowsSecurityEvents-CD-xdr-6dd2629c-534b-4275-8201-d7-82fb7252", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-6dd2629c-534b-4275-8201-d7968b4fa77e', 'xdr-6dd2629c-534b-4275-8201-d7968b4fa77e')]", + "queryCondition": { + "queryText": "SecurityEvent\n| where EventID == 4657\n| extend EventData = parse_xml(EventData).EventData.Data\n| mv-expand bagexpansion=array EventData\n| evaluate bag_unpack(EventData)\n| extend Key = tostring(column_ifexists('@Name', \"\")), Value = column_ifexists('#text', \"\")\n| evaluate pivot(Key, any(Value), TimeGenerated, TargetAccount, Computer, EventSourceName, Channel, Task, Level, EventID, Activity, TargetLogonId, SourceComputerId, EventOriginId, Type, _ResourceId, TenantId, SourceSystem, ManagementGroupName, IpAddress, Account)\n| extend ObjectName = column_ifexists('ObjectName', \"\"), OperationType = column_ifexists('OperationType', \"\"), ObjectValueName = column_ifexists('ObjectValueName', \"\")\n| where ObjectName has 'Schedule\\\\TaskCache\\\\Tree' and ObjectValueName == \"SD\" and OperationType == \"%%1906\" // %%1906 - Registry value deleted\n| extend HostName = tostring(split(Computer, \".\")[0]), DomainIndex = toint(indexof(Computer, '.'))\n| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)\n| extend AccountName = tostring(split(TargetAccount, @'\\')[1]), AccountNTDomain = tostring(split(TargetAccount, @'\\')[0])\n| extend timestamp = TimeGenerated" + }, + "schedule": { + "frequency": "P1D" + }, + "detectionAction": { + "alertTemplate": { + "title": "Scheduled Task Hide", + "description": "'Identifies malware hiding scheduled tasks by deleting the SD (Security Descriptor) value, making tasks disappear from schtasks /query and Task Scheduler.\n Enable registry auditing policy and auditing on HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Schedule\\TaskCache\\Tree.\n Reference: https://www.microsoft.com/en-us/security/blog/2022/04/12/tarrask-malware-uses-scheduled-tasks-for-defense-evasion/\n Reference: https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/auditing/audit-registry'", + "tactics": [ + { + "tactic": "DefenseEvasion", + "techniques": [ + { + "technique": "T1562" + } + ] + } + ], + "entityMappings": { + "accounts": [ + { + "ntDomainColumn": "AccountNTDomain", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "AccountName" + } + ], + "hosts": [ + { + "dnsDomainColumn": "HostNameDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ] + }, + "severity": "high", + "customDetails": { + "HostFullName": "Computer", + "AccountFullName": "TargetAccount" + } + } + }, + "status": "disabled", + "displayName": "Scheduled Task Hide" + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-6dd2629c-534b-4275-8201-d7968b4fa77e')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'WindowsSecurityEvents-CD-xdr-6dd2629c-534b-4275-8201-d7-82fb7252')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'Identifies malware hiding scheduled tasks by deleting the SD (Security Descriptor) value, making tasks disappear from schtasks /query and Task Scheduler.\n Enable registry auditing policy and auditing on HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Schedule\\TaskCache\\Tree.\n Reference: https://www.microsoft.com/en-us/security/blog/2022/04/12/tarrask-malware-uses-scheduled-tasks-for-defense-evasion/\n Reference: https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/auditing/audit-registry'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-6dd2629c-534b-4275-8201-d7968b4fa77e', 'xdr-6dd2629c-534b-4275-8201-d7968b4fa77e')]", + "queryCondition": { + "queryText": "SecurityEvent\n| where EventID == 4657\n| extend EventData = parse_xml(EventData).EventData.Data\n| mv-expand bagexpansion=array EventData\n| evaluate bag_unpack(EventData)\n| extend Key = tostring(column_ifexists('@Name', \"\")), Value = column_ifexists('#text', \"\")\n| evaluate pivot(Key, any(Value), TimeGenerated, TargetAccount, Computer, EventSourceName, Channel, Task, Level, EventID, Activity, TargetLogonId, SourceComputerId, EventOriginId, Type, _ResourceId, TenantId, SourceSystem, ManagementGroupName, IpAddress, Account)\n| extend ObjectName = column_ifexists('ObjectName', \"\"), OperationType = column_ifexists('OperationType', \"\"), ObjectValueName = column_ifexists('ObjectValueName', \"\")\n| where ObjectName has 'Schedule\\\\TaskCache\\\\Tree' and ObjectValueName == \"SD\" and OperationType == \"%%1906\" // %%1906 - Registry value deleted\n| extend HostName = tostring(split(Computer, \".\")[0]), DomainIndex = toint(indexof(Computer, '.'))\n| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)\n| extend AccountName = tostring(split(TargetAccount, @'\\')[1]), AccountNTDomain = tostring(split(TargetAccount, @'\\')[0])\n| extend timestamp = TimeGenerated" + }, + "schedule": { + "frequency": "P1D" + }, + "detectionAction": { + "alertTemplate": { + "title": "Scheduled Task Hide", + "description": "'Identifies malware hiding scheduled tasks by deleting the SD (Security Descriptor) value, making tasks disappear from schtasks /query and Task Scheduler.\n Enable registry auditing policy and auditing on HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Schedule\\TaskCache\\Tree.\n Reference: https://www.microsoft.com/en-us/security/blog/2022/04/12/tarrask-malware-uses-scheduled-tasks-for-defense-evasion/\n Reference: https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/auditing/audit-registry'", + "tactics": [ + { + "tactic": "DefenseEvasion", + "techniques": [ + { + "technique": "T1562" + } + ] + } + ], + "entityMappings": { + "accounts": [ + { + "ntDomainColumn": "AccountNTDomain", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "AccountName" + } + ], + "hosts": [ + { + "dnsDomainColumn": "HostNameDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ] + }, + "severity": "high", + "customDetails": { + "HostFullName": "Computer", + "AccountFullName": "TargetAccount" + } + } + }, + "status": "disabled", + "displayName": "Scheduled Task Hide" + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-6dd2629c-534b-4275-8201-d7968b4fa77e", + "contentKind": "CustomDetection", + "displayName": "Scheduled Task Hide", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-6dd2629c-534b-4275-8201-d7968b4fa77e','-','3.1.2')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-6dd2629c-534b-4275-8201-d7968b4fa77e','-','3.1.2')))]", + "version": "3.1.2", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "WindowsSecurityEvents-CD-xdr-d9f28fdf-abc8-4f1a-a7e7-1a-e6db60ac", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-d9f28fdf-abc8-4f1a-a7e7-1aaec87a2fc5', 'xdr-d9f28fdf-abc8-4f1a-a7e7-1aaec87a2fc5')]", + "queryCondition": { + "queryText": "SecurityEvent\n | where EventID == 4688\n | where Process =~ \"svchost.exe\"\n | where CommandLine has \"-k GPSvcGroup\" or CommandLine has \"-s gpsvc\"\n | extend timekey = bin(TimeGenerated, 1m)\n | project timekey, NewProcessId, Computer\n | join kind=inner (SecurityEvent\n | where EventID == 4688\n | where Process =~ \"sdelete.exe\" or CommandLine has \"sdelete\"\n | where ParentProcessName endswith \"svchost.exe\"\n | where CommandLine has_all (\"-s\", \"-r\")\n | extend newProcess = Process\n | extend timekey = bin(TimeGenerated, 1m)\n ) on $left.NewProcessId == $right.ProcessId, timekey, Computer\n | extend HostName = tostring(split(Computer, \".\")[0]), DomainIndex = toint(indexof(Computer, '.'))\n | extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)\n | extend AccountName = tostring(split(TargetAccount, @'\\')[1]), AccountNTDomain = tostring(split(TargetAccount, @'\\')[0])" + }, + "schedule": { + "frequency": "P1D" + }, + "detectionAction": { + "alertTemplate": { + "title": "Sdelete deployed via GPO and run recursively", + "description": "'This query looks for the Sdelete process being run recursively after being deployed to a host via GPO. Attackers could use this technique to deploy Sdelete to multiple host and delete data on them.'", + "tactics": [ + { + "tactic": "Impact", + "techniques": [ + { + "technique": "T1485" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "dnsDomainColumn": "HostNameDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ] + }, + "severity": "medium", + "customDetails": { + "AccountName": "AccountName", + "HostFullName": "Computer" + } + } + }, + "status": "disabled", + "displayName": "Sdelete deployed via GPO and run recursively" + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-d9f28fdf-abc8-4f1a-a7e7-1aaec87a2fc5')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'WindowsSecurityEvents-CD-xdr-d9f28fdf-abc8-4f1a-a7e7-1a-e6db60ac')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'This query looks for the Sdelete process being run recursively after being deployed to a host via GPO. Attackers could use this technique to deploy Sdelete to multiple host and delete data on them.'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-d9f28fdf-abc8-4f1a-a7e7-1aaec87a2fc5', 'xdr-d9f28fdf-abc8-4f1a-a7e7-1aaec87a2fc5')]", + "queryCondition": { + "queryText": "SecurityEvent\n | where EventID == 4688\n | where Process =~ \"svchost.exe\"\n | where CommandLine has \"-k GPSvcGroup\" or CommandLine has \"-s gpsvc\"\n | extend timekey = bin(TimeGenerated, 1m)\n | project timekey, NewProcessId, Computer\n | join kind=inner (SecurityEvent\n | where EventID == 4688\n | where Process =~ \"sdelete.exe\" or CommandLine has \"sdelete\"\n | where ParentProcessName endswith \"svchost.exe\"\n | where CommandLine has_all (\"-s\", \"-r\")\n | extend newProcess = Process\n | extend timekey = bin(TimeGenerated, 1m)\n ) on $left.NewProcessId == $right.ProcessId, timekey, Computer\n | extend HostName = tostring(split(Computer, \".\")[0]), DomainIndex = toint(indexof(Computer, '.'))\n | extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)\n | extend AccountName = tostring(split(TargetAccount, @'\\')[1]), AccountNTDomain = tostring(split(TargetAccount, @'\\')[0])" + }, + "schedule": { + "frequency": "P1D" + }, + "detectionAction": { + "alertTemplate": { + "title": "Sdelete deployed via GPO and run recursively", + "description": "'This query looks for the Sdelete process being run recursively after being deployed to a host via GPO. Attackers could use this technique to deploy Sdelete to multiple host and delete data on them.'", + "tactics": [ + { + "tactic": "Impact", + "techniques": [ + { + "technique": "T1485" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "dnsDomainColumn": "HostNameDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ] + }, + "severity": "medium", + "customDetails": { + "AccountName": "AccountName", + "HostFullName": "Computer" + } + } + }, + "status": "disabled", + "displayName": "Sdelete deployed via GPO and run recursively" + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-d9f28fdf-abc8-4f1a-a7e7-1aaec87a2fc5", + "contentKind": "CustomDetection", + "displayName": "Sdelete deployed via GPO and run recursively", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-d9f28fdf-abc8-4f1a-a7e7-1aaec87a2fc5','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-d9f28fdf-abc8-4f1a-a7e7-1aaec87a2fc5','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "WindowsSecurityEvents-CD-xdr-2bc7b4ae-eeaa-4538-ba15-ef-73d2ee80", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-2bc7b4ae-eeaa-4538-ba15-ef298ec1ffae', 'xdr-2bc7b4ae-eeaa-4538-ba15-ef298ec1ffae')]", + "queryCondition": { + "queryText": "SecurityEvent\n| where EventID == 4656\n| extend EventData = parse_xml(EventData).EventData.Data\n| mv-expand bagexpansion=array EventData\n| evaluate bag_unpack(EventData)\n| extend Key = tostring(column_ifexists('@Name', \"\")), Value = column_ifexists('#text', \"\")\n| evaluate pivot(Key, any(Value), TimeGenerated, TargetAccount, Computer, EventSourceName, Channel, Task, Level, EventID, Activity, TargetLogonId, SourceComputerId, EventOriginId, Type, _ResourceId, TenantId, SourceSystem, ManagementGroupName, IpAddress, Account)\n| extend ObjectServer = column_ifexists('ObjectServer', \"\"), ObjectType = column_ifexists('ObjectType', \"\"), ObjectName = column_ifexists('ObjectName', \"\")\n| where isnotempty(ObjectServer) and isnotempty(ObjectType) and isnotempty(ObjectName)\n| where ObjectServer =~ \"SC Manager\" and ObjectType =~ \"SERVICE OBJECT\" and ObjectName =~ \"HealthService\"\n// Comment out the join below if the SACL only audits users that are part of the Network logon users, i.e. with user/group target pointing to \"NU.\"\n| join kind=leftouter (\n SecurityEvent\n | where EventID == 4624\n) on TargetLogonId\n| project TimeGenerated, Computer, Account, TargetAccount, IpAddress,TargetLogonId, ObjectServer, ObjectType, ObjectName\n| extend HostName = tostring(split(Computer, \".\")[0]), DomainIndex = toint(indexof(Computer, '.'))\n| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)\n| extend AccountName = tostring(split(TargetAccount, @'\\')[1]), AccountNTDomain = tostring(split(TargetAccount, @'\\')[0])\n| extend timestamp = TimeGenerated" + }, + "schedule": { + "frequency": "P1D" + }, + "detectionAction": { + "alertTemplate": { + "title": "Starting or Stopping HealthService to Avoid Detection", + "description": "'This query detects events where an actor is stopping or starting HealthService to disable telemetry collection/detection from the agent.\n The query requires a SACL to audit for access request to the service.'", + "tactics": [ + { + "tactic": "DefenseEvasion", + "techniques": [ + { + "subTechniques": [ + "T1562.001" + ], + "technique": "T1562" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "dnsDomainColumn": "HostNameDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ], + "ips": [ + { + "id": "[if(true(), 'ip1', 'ip1')]", + "addressColumn": "IpAddress" + } + ] + }, + "severity": "medium", + "customDetails": { + "AccountName": "AccountName", + "HostFullName": "Computer", + "AccountFullName": "TargetAccount" + } + } + }, + "status": "disabled", + "displayName": "Starting or Stopping HealthService to Avoid Detection" + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-2bc7b4ae-eeaa-4538-ba15-ef298ec1ffae')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'WindowsSecurityEvents-CD-xdr-2bc7b4ae-eeaa-4538-ba15-ef-73d2ee80')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'This query detects events where an actor is stopping or starting HealthService to disable telemetry collection/detection from the agent.\n The query requires a SACL to audit for access request to the service.'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-2bc7b4ae-eeaa-4538-ba15-ef298ec1ffae', 'xdr-2bc7b4ae-eeaa-4538-ba15-ef298ec1ffae')]", + "queryCondition": { + "queryText": "SecurityEvent\n| where EventID == 4656\n| extend EventData = parse_xml(EventData).EventData.Data\n| mv-expand bagexpansion=array EventData\n| evaluate bag_unpack(EventData)\n| extend Key = tostring(column_ifexists('@Name', \"\")), Value = column_ifexists('#text', \"\")\n| evaluate pivot(Key, any(Value), TimeGenerated, TargetAccount, Computer, EventSourceName, Channel, Task, Level, EventID, Activity, TargetLogonId, SourceComputerId, EventOriginId, Type, _ResourceId, TenantId, SourceSystem, ManagementGroupName, IpAddress, Account)\n| extend ObjectServer = column_ifexists('ObjectServer', \"\"), ObjectType = column_ifexists('ObjectType', \"\"), ObjectName = column_ifexists('ObjectName', \"\")\n| where isnotempty(ObjectServer) and isnotempty(ObjectType) and isnotempty(ObjectName)\n| where ObjectServer =~ \"SC Manager\" and ObjectType =~ \"SERVICE OBJECT\" and ObjectName =~ \"HealthService\"\n// Comment out the join below if the SACL only audits users that are part of the Network logon users, i.e. with user/group target pointing to \"NU.\"\n| join kind=leftouter (\n SecurityEvent\n | where EventID == 4624\n) on TargetLogonId\n| project TimeGenerated, Computer, Account, TargetAccount, IpAddress,TargetLogonId, ObjectServer, ObjectType, ObjectName\n| extend HostName = tostring(split(Computer, \".\")[0]), DomainIndex = toint(indexof(Computer, '.'))\n| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)\n| extend AccountName = tostring(split(TargetAccount, @'\\')[1]), AccountNTDomain = tostring(split(TargetAccount, @'\\')[0])\n| extend timestamp = TimeGenerated" + }, + "schedule": { + "frequency": "P1D" + }, + "detectionAction": { + "alertTemplate": { + "title": "Starting or Stopping HealthService to Avoid Detection", + "description": "'This query detects events where an actor is stopping or starting HealthService to disable telemetry collection/detection from the agent.\n The query requires a SACL to audit for access request to the service.'", + "tactics": [ + { + "tactic": "DefenseEvasion", + "techniques": [ + { + "subTechniques": [ + "T1562.001" + ], + "technique": "T1562" + } + ] + } + ], + "entityMappings": { + "hosts": [ + { + "dnsDomainColumn": "HostNameDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ], + "ips": [ + { + "id": "[if(true(), 'ip1', 'ip1')]", + "addressColumn": "IpAddress" + } + ] + }, + "severity": "medium", + "customDetails": { + "AccountName": "AccountName", + "HostFullName": "Computer", + "AccountFullName": "TargetAccount" + } + } + }, + "status": "disabled", + "displayName": "Starting or Stopping HealthService to Avoid Detection" + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-2bc7b4ae-eeaa-4538-ba15-ef298ec1ffae", + "contentKind": "CustomDetection", + "displayName": "Starting or Stopping HealthService to Avoid Detection", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-2bc7b4ae-eeaa-4538-ba15-ef298ec1ffae','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-2bc7b4ae-eeaa-4538-ba15-ef298ec1ffae','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "WindowsSecurityEvents-CD-xdr-2c55fe7a-b06f-4029-a5b9-c5-2a4784bd", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-2c55fe7a-b06f-4029-a5b9-c54a2320d7b8', 'xdr-2c55fe7a-b06f-4029-a5b9-c54a2320d7b8')]", + "queryCondition": { + "queryText": "let starttime = 14d;\nlet endtime = 1d;\nlet timeframe = 1h;\nlet TotalEventsThreshold = 5;\n// Configure the list with sensitive process names\nlet ExeList = dynamic([\"powershell.exe\",\"cmd.exe\",\"wmic.exe\",\"psexec.exe\",\"cacls.exe\",\"rundll32.exe\"]);\nlet TimeSeriesData =\nSecurityEvent\n| where EventID == 4688 | extend Process = tolower(Process)\n| where TimeGenerated between (startofday(ago(starttime))..startofday(ago(endtime)))\n| where Process in~ (ExeList)\n| project TimeGenerated, Computer, AccountType, Account, Process\n| make-series Total=count() on TimeGenerated from startofday(ago(starttime)) to startofday(ago(endtime)) step timeframe by Process;\nlet TimeSeriesAlerts = materialize(TimeSeriesData\n| extend (anomalies, score, baseline) = series_decompose_anomalies(Total, 1.5, -1, 'linefit')\n| mv-expand Total to typeof(double), TimeGenerated to typeof(datetime), anomalies to typeof(double), score to typeof(double), baseline to typeof(long)\n| where anomalies > 0\n| project Process, TimeGenerated, Total, baseline, anomalies, score\n| where Total > TotalEventsThreshold);\nlet AnomalyHours = materialize(TimeSeriesAlerts | where TimeGenerated > ago(2d) | project TimeGenerated);\nTimeSeriesAlerts\n| where TimeGenerated > ago(2d)\n| join (\nSecurityEvent\n| where TimeGenerated between (startofday(ago(starttime))..startofday(ago(endtime)))\n| extend DateHour = bin(TimeGenerated, 1h) // create a new column and round to hour\n| where DateHour in ((AnomalyHours)) //filter the dataset to only selected anomaly hours\n| where EventID == 4688 | extend Process = tolower(Process)\n| summarize CommandlineCount = count() by bin(TimeGenerated, 1h), Process, CommandLine, Computer, Account\n) on Process, TimeGenerated\n| project AnomalyHour = TimeGenerated, Computer, Account, Process, CommandLine, CommandlineCount, Total, baseline, anomalies, score\n| extend timestamp = AnomalyHour, NTDomain = split(Account, '\\\\', 0)[0], Name = split(Account, '\\\\', 1)[0], HostName = tostring(split(Computer, '.', 0)[0]), DnsDomain = tostring(strcat_array(array_slice(split(Computer, '.'), 1, -1), '.'))" + }, + "schedule": { + "frequency": "P1D" + }, + "detectionAction": { + "alertTemplate": { + "title": "Process Execution Frequency Anomaly", + "description": "'This detection identifies anomalous spike in frequency of executions of sensitive processes which are often leveraged as attack vectors.\nThe query leverages KQL's built-in anomaly detection algorithms to find large deviations from baseline patterns.\nSudden increases in execution frequency of sensitive processes should be further investigated for malicious activity.\nTune the values from 1.5 to 3 in series_decompose_anomalies for further outliers or based on custom threshold values for score.'", + "tactics": [ + { + "tactic": "Execution", + "techniques": [ + { + "technique": "T1059" + } + ] + } + ], + "entityMappings": { + "accounts": [ + { + "ntDomainColumn": "NTDomain", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "Name" + } + ], + "hosts": [ + { + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ] + }, + "severity": "medium", + "customDetails": { + "HostFullName": "Computer", + "AccountFullName": "Account" + } + } + }, + "status": "disabled", + "displayName": "Process Execution Frequency Anomaly" + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-2c55fe7a-b06f-4029-a5b9-c54a2320d7b8')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'WindowsSecurityEvents-CD-xdr-2c55fe7a-b06f-4029-a5b9-c5-2a4784bd')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'This detection identifies anomalous spike in frequency of executions of sensitive processes which are often leveraged as attack vectors.\nThe query leverages KQL's built-in anomaly detection algorithms to find large deviations from baseline patterns.\nSudden increases in execution frequency of sensitive processes should be further investigated for malicious activity.\nTune the values from 1.5 to 3 in series_decompose_anomalies for further outliers or based on custom threshold values for score.'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-2c55fe7a-b06f-4029-a5b9-c54a2320d7b8', 'xdr-2c55fe7a-b06f-4029-a5b9-c54a2320d7b8')]", + "queryCondition": { + "queryText": "let starttime = 14d;\nlet endtime = 1d;\nlet timeframe = 1h;\nlet TotalEventsThreshold = 5;\n// Configure the list with sensitive process names\nlet ExeList = dynamic([\"powershell.exe\",\"cmd.exe\",\"wmic.exe\",\"psexec.exe\",\"cacls.exe\",\"rundll32.exe\"]);\nlet TimeSeriesData =\nSecurityEvent\n| where EventID == 4688 | extend Process = tolower(Process)\n| where TimeGenerated between (startofday(ago(starttime))..startofday(ago(endtime)))\n| where Process in~ (ExeList)\n| project TimeGenerated, Computer, AccountType, Account, Process\n| make-series Total=count() on TimeGenerated from startofday(ago(starttime)) to startofday(ago(endtime)) step timeframe by Process;\nlet TimeSeriesAlerts = materialize(TimeSeriesData\n| extend (anomalies, score, baseline) = series_decompose_anomalies(Total, 1.5, -1, 'linefit')\n| mv-expand Total to typeof(double), TimeGenerated to typeof(datetime), anomalies to typeof(double), score to typeof(double), baseline to typeof(long)\n| where anomalies > 0\n| project Process, TimeGenerated, Total, baseline, anomalies, score\n| where Total > TotalEventsThreshold);\nlet AnomalyHours = materialize(TimeSeriesAlerts | where TimeGenerated > ago(2d) | project TimeGenerated);\nTimeSeriesAlerts\n| where TimeGenerated > ago(2d)\n| join (\nSecurityEvent\n| where TimeGenerated between (startofday(ago(starttime))..startofday(ago(endtime)))\n| extend DateHour = bin(TimeGenerated, 1h) // create a new column and round to hour\n| where DateHour in ((AnomalyHours)) //filter the dataset to only selected anomaly hours\n| where EventID == 4688 | extend Process = tolower(Process)\n| summarize CommandlineCount = count() by bin(TimeGenerated, 1h), Process, CommandLine, Computer, Account\n) on Process, TimeGenerated\n| project AnomalyHour = TimeGenerated, Computer, Account, Process, CommandLine, CommandlineCount, Total, baseline, anomalies, score\n| extend timestamp = AnomalyHour, NTDomain = split(Account, '\\\\', 0)[0], Name = split(Account, '\\\\', 1)[0], HostName = tostring(split(Computer, '.', 0)[0]), DnsDomain = tostring(strcat_array(array_slice(split(Computer, '.'), 1, -1), '.'))" + }, + "schedule": { + "frequency": "P1D" + }, + "detectionAction": { + "alertTemplate": { + "title": "Process Execution Frequency Anomaly", + "description": "'This detection identifies anomalous spike in frequency of executions of sensitive processes which are often leveraged as attack vectors.\nThe query leverages KQL's built-in anomaly detection algorithms to find large deviations from baseline patterns.\nSudden increases in execution frequency of sensitive processes should be further investigated for malicious activity.\nTune the values from 1.5 to 3 in series_decompose_anomalies for further outliers or based on custom threshold values for score.'", + "tactics": [ + { + "tactic": "Execution", + "techniques": [ + { + "technique": "T1059" + } + ] + } + ], + "entityMappings": { + "accounts": [ + { + "ntDomainColumn": "NTDomain", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "Name" + } + ], + "hosts": [ + { + "dnsDomainColumn": "DnsDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ] + }, + "severity": "medium", + "customDetails": { + "HostFullName": "Computer", + "AccountFullName": "Account" + } + } + }, + "status": "disabled", + "displayName": "Process Execution Frequency Anomaly" + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-2c55fe7a-b06f-4029-a5b9-c54a2320d7b8", + "contentKind": "CustomDetection", + "displayName": "Process Execution Frequency Anomaly", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-2c55fe7a-b06f-4029-a5b9-c54a2320d7b8','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-2c55fe7a-b06f-4029-a5b9-c54a2320d7b8','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "WindowsSecurityEvents-CD-xdr-3c8e5f0b-1d4a-4b69-9c2e-7f-843a00c9", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-3c8e5f0b-1d4a-4b69-9c2e-7f0d3a5e8b1f', 'xdr-3c8e5f0b-1d4a-4b69-9c2e-7f0d3a5e8b1f')]", + "queryCondition": { + "queryText": "let Lookback = 1h;\nlet SuspiciousChildProcesses = dynamic([\n \"powershell.exe\", \"pwsh.exe\", \"cmd.exe\", \"cscript.exe\", \"wscript.exe\",\n \"mshta.exe\", \"certutil.exe\", \"bitsadmin.exe\", \"regsvr32.exe\",\n \"rundll32.exe\", \"msiexec.exe\", \"installutil.exe\", \"cmstp.exe\",\n \"msbuild.exe\", \"wmic.exe\", \"net.exe\", \"net1.exe\", \"nltest.exe\",\n \"whoami.exe\", \"ipconfig.exe\", \"tasklist.exe\", \"schtasks.exe\",\n \"at.exe\", \"sc.exe\", \"reg.exe\"\n]);\nlet AllowlistedCmdPatterns = dynamic([\n \"ccmexec\", \"SMSAgent\", \"MOMAgent\", \"nessus\", \"qualys\"\n]);\nlet NetworkIndicators = dynamic([\n \"http://\", \"https://\", \"ftp://\", \"Net.WebClient\",\n \"DownloadString\", \"IEX\", \"Invoke-Expression\", \"/transfer\", \"-urlcache\"\n]);\nlet CredentialIndicators = dynamic([\n \"lsass\", \"mimikatz\", \"sekurlsa\", \"dump\", \"sam\", \"ntds\"\n]);\nlet MDE_Results =\n DeviceProcessEvents\n | where Timestamp >= ago(Lookback)\n | where InitiatingProcessFileName =~ \"WmiPrvSE.exe\"\n | where FileName in~ (SuspiciousChildProcesses)\n | where not(ProcessCommandLine has_any (AllowlistedCmdPatterns))\n | extend\n ChildProcess = FileName,\n ChildCmdLine = ProcessCommandLine,\n AccountName = InitiatingProcessAccountName,\n AccountDomain = InitiatingProcessAccountDomain,\n HostName = DeviceName,\n EventTime = Timestamp,\n NetworkActivity = ProcessCommandLine has_any (NetworkIndicators),\n CredentialActivity = ProcessCommandLine has_any (CredentialIndicators)\n | project EventTime, HostName, AccountName, AccountDomain, ChildProcess,\n ChildCmdLine, NetworkActivity, CredentialActivity;\nlet SecEvent_Results =\n SecurityEvent\n | where TimeGenerated >= ago(Lookback)\n | where EventID == 4688\n | where ParentProcessName endswith \"\\\\WmiPrvSE.exe\"\n | extend ChildProcess = tostring(split(NewProcessName, \"\\\\\")[-1])\n | where ChildProcess in~ (SuspiciousChildProcesses)\n | where not(CommandLine has_any (AllowlistedCmdPatterns))\n | extend\n ChildCmdLine = CommandLine,\n AccountName = SubjectUserName,\n AccountDomain = SubjectDomainName,\n HostName = Computer,\n EventTime = TimeGenerated,\n NetworkActivity = CommandLine has_any (NetworkIndicators),\n CredentialActivity = CommandLine has_any (CredentialIndicators)\n | project EventTime, HostName, AccountName, AccountDomain, ChildProcess,\n ChildCmdLine, NetworkActivity, CredentialActivity;\nunion MDE_Results, SecEvent_Results\n| extend RiskScore = iif(CredentialActivity == true, 3, iif(NetworkActivity == true, 2, 1))\n| sort by RiskScore desc, EventTime desc" + }, + "schedule": { + "frequency": "PT1H" + }, + "detectionAction": { + "alertTemplate": { + "title": "WMI Spawning Suspicious Child Process (Living off the Land)", + "description": "Detects WmiPrvSE.exe (the WMI Provider Host) spawning high-risk processes\nsuch as PowerShell, cmd.exe, cscript, or other LOLBins.\nWMI requires no external tools, generates minimal disk artifacts, and can\nexecute code on remote systems over DCOM/RPC while bypassing many controls.\nTune AllowlistedCmdPatterns for known-safe management tools such as SCCM.", + "tactics": [ + { + "tactic": "Execution", + "techniques": [ + { + "technique": "T1047" + }, + { + "subTechniques": [ + "T1059.001", + "T1059.003", + "T1059.005" + ], + "technique": "T1059" + } + ] + } + ], + "entityMappings": { + "accounts": [ + { + "ntDomainColumn": "AccountDomain", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "AccountName" + } + ], + "hosts": [ + { + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ] + }, + "severity": "high", + "customDetails": { + "ProcessCommandLine": "ChildCmdLine", + "HostFullName": "HostName" + } + } + }, + "status": "disabled", + "displayName": "WMI Spawning Suspicious Child Process (Living off the Land)" + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-3c8e5f0b-1d4a-4b69-9c2e-7f0d3a5e8b1f')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'WindowsSecurityEvents-CD-xdr-3c8e5f0b-1d4a-4b69-9c2e-7f-843a00c9')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "Detects WmiPrvSE.exe (the WMI Provider Host) spawning high-risk processes\nsuch as PowerShell, cmd.exe, cscript, or other LOLBins.\nWMI requires no external tools, generates minimal disk artifacts, and can\nexecute code on remote systems over DCOM/RPC while bypassing many controls.\nTune AllowlistedCmdPatterns for known-safe management tools such as SCCM.", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-3c8e5f0b-1d4a-4b69-9c2e-7f0d3a5e8b1f', 'xdr-3c8e5f0b-1d4a-4b69-9c2e-7f0d3a5e8b1f')]", + "queryCondition": { + "queryText": "let Lookback = 1h;\nlet SuspiciousChildProcesses = dynamic([\n \"powershell.exe\", \"pwsh.exe\", \"cmd.exe\", \"cscript.exe\", \"wscript.exe\",\n \"mshta.exe\", \"certutil.exe\", \"bitsadmin.exe\", \"regsvr32.exe\",\n \"rundll32.exe\", \"msiexec.exe\", \"installutil.exe\", \"cmstp.exe\",\n \"msbuild.exe\", \"wmic.exe\", \"net.exe\", \"net1.exe\", \"nltest.exe\",\n \"whoami.exe\", \"ipconfig.exe\", \"tasklist.exe\", \"schtasks.exe\",\n \"at.exe\", \"sc.exe\", \"reg.exe\"\n]);\nlet AllowlistedCmdPatterns = dynamic([\n \"ccmexec\", \"SMSAgent\", \"MOMAgent\", \"nessus\", \"qualys\"\n]);\nlet NetworkIndicators = dynamic([\n \"http://\", \"https://\", \"ftp://\", \"Net.WebClient\",\n \"DownloadString\", \"IEX\", \"Invoke-Expression\", \"/transfer\", \"-urlcache\"\n]);\nlet CredentialIndicators = dynamic([\n \"lsass\", \"mimikatz\", \"sekurlsa\", \"dump\", \"sam\", \"ntds\"\n]);\nlet MDE_Results =\n DeviceProcessEvents\n | where Timestamp >= ago(Lookback)\n | where InitiatingProcessFileName =~ \"WmiPrvSE.exe\"\n | where FileName in~ (SuspiciousChildProcesses)\n | where not(ProcessCommandLine has_any (AllowlistedCmdPatterns))\n | extend\n ChildProcess = FileName,\n ChildCmdLine = ProcessCommandLine,\n AccountName = InitiatingProcessAccountName,\n AccountDomain = InitiatingProcessAccountDomain,\n HostName = DeviceName,\n EventTime = Timestamp,\n NetworkActivity = ProcessCommandLine has_any (NetworkIndicators),\n CredentialActivity = ProcessCommandLine has_any (CredentialIndicators)\n | project EventTime, HostName, AccountName, AccountDomain, ChildProcess,\n ChildCmdLine, NetworkActivity, CredentialActivity;\nlet SecEvent_Results =\n SecurityEvent\n | where TimeGenerated >= ago(Lookback)\n | where EventID == 4688\n | where ParentProcessName endswith \"\\\\WmiPrvSE.exe\"\n | extend ChildProcess = tostring(split(NewProcessName, \"\\\\\")[-1])\n | where ChildProcess in~ (SuspiciousChildProcesses)\n | where not(CommandLine has_any (AllowlistedCmdPatterns))\n | extend\n ChildCmdLine = CommandLine,\n AccountName = SubjectUserName,\n AccountDomain = SubjectDomainName,\n HostName = Computer,\n EventTime = TimeGenerated,\n NetworkActivity = CommandLine has_any (NetworkIndicators),\n CredentialActivity = CommandLine has_any (CredentialIndicators)\n | project EventTime, HostName, AccountName, AccountDomain, ChildProcess,\n ChildCmdLine, NetworkActivity, CredentialActivity;\nunion MDE_Results, SecEvent_Results\n| extend RiskScore = iif(CredentialActivity == true, 3, iif(NetworkActivity == true, 2, 1))\n| sort by RiskScore desc, EventTime desc" + }, + "schedule": { + "frequency": "PT1H" + }, + "detectionAction": { + "alertTemplate": { + "title": "WMI Spawning Suspicious Child Process (Living off the Land)", + "description": "Detects WmiPrvSE.exe (the WMI Provider Host) spawning high-risk processes\nsuch as PowerShell, cmd.exe, cscript, or other LOLBins.\nWMI requires no external tools, generates minimal disk artifacts, and can\nexecute code on remote systems over DCOM/RPC while bypassing many controls.\nTune AllowlistedCmdPatterns for known-safe management tools such as SCCM.", + "tactics": [ + { + "tactic": "Execution", + "techniques": [ + { + "technique": "T1047" + }, + { + "subTechniques": [ + "T1059.001", + "T1059.003", + "T1059.005" + ], + "technique": "T1059" + } + ] + } + ], + "entityMappings": { + "accounts": [ + { + "ntDomainColumn": "AccountDomain", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "AccountName" + } + ], + "hosts": [ + { + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ] + }, + "severity": "high", + "customDetails": { + "ProcessCommandLine": "ChildCmdLine", + "HostFullName": "HostName" + } + } + }, + "status": "disabled", + "displayName": "WMI Spawning Suspicious Child Process (Living off the Land)" + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-3c8e5f0b-1d4a-4b69-9c2e-7f0d3a5e8b1f", + "contentKind": "CustomDetection", + "displayName": "WMI Spawning Suspicious Child Process (Living off the Land)", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-3c8e5f0b-1d4a-4b69-9c2e-7f0d3a5e8b1f','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-3c8e5f0b-1d4a-4b69-9c2e-7f0d3a5e8b1f','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "WindowsSecurityEvents-CD-xdr-62085097-d113-459f-9ea7-30-c613f889", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-62085097-d113-459f-9ea7-30216f2ee6af', 'xdr-62085097-d113-459f-9ea7-30216f2ee6af')]", + "queryCondition": { + "queryText": "let starttime = 3d;\nlet SecEvents = materialize ( SecurityEvent | where TimeGenerated >= ago(starttime)\n| where EventID in (4722,4723) | where TargetUserName !endswith \"$\"\n| project TimeGenerated, EventID, Activity, Computer, TargetAccount, TargetSid, SubjectAccount, SubjectUserSid);\nlet userEnable = SecEvents\n| extend EventID4722Time = TimeGenerated\n// 4722: User Account Enabled\n| where EventID == 4722\n| project Time_Event4722 = TimeGenerated, TargetAccount, TargetSid, SubjectAccount_Event4722 = SubjectAccount, SubjectUserSid_Event4722 = SubjectUserSid, Activity_4722 = Activity, Computer_4722 = Computer;\nlet userPwdSet = SecEvents\n// 4723: Attempt made by user to set password\n| where EventID == 4723\n| project Time_Event4723 = TimeGenerated, TargetAccount, TargetSid, SubjectAccount_Event4723 = SubjectAccount, SubjectUserSid_Event4723 = SubjectUserSid, Activity_4723 = Activity, Computer_4723 = Computer;\nuserEnable | join kind=leftouter userPwdSet on TargetAccount, TargetSid\n| extend PasswordSetAttemptDelta_Min = datetime_diff('minute', Time_Event4723, Time_Event4722)\n| where PasswordSetAttemptDelta_Min > 2880 or isempty(PasswordSetAttemptDelta_Min)\n| project-away TargetAccount1, TargetSid1\n| extend Reason = @\"User either has not yet attempted to set the initial password after account was enabled or it occurred after 48 hours\"\n| order by Time_Event4722 asc\n| project-reorder Time_Event4722, Time_Event4723, PasswordSetAttemptDelta_Min, TargetAccount, TargetSid\n| extend Computer = coalesce(Computer_4723, Computer_4722)\n| extend HostName = tostring(split(Computer, \".\")[0]), DomainIndex = toint(indexof(Computer, '.'))\n| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)\n| extend AccountName = tostring(split(TargetAccount, \"\\\\\")[1]), AccountNTDomain = tostring(split(TargetAccount, \"\\\\\")[0])\n| project-away DomainIndex" + }, + "schedule": { + "frequency": "P1D" + }, + "detectionAction": { + "alertTemplate": { + "severity": "low", + "entityMappings": { + "accounts": [ + { + "ntDomainColumn": "AccountNTDomain", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "AccountName" + }, + { + "id": "[if(true(), 'account2', 'account2')]", + "sidColumn": "TargetSid" + } + ], + "hosts": [ + { + "dnsDomainColumn": "HostNameDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ] + }, + "title": "AD user enabled and password not set within 48 hours", + "description": "'Identifies when an account is enabled with a default password and the password is not set by the user within 48 hours.\nEffectively, there is an event 4722 indicating an account was enabled and within 48 hours, no event 4723 occurs which\nindicates there was no attempt by the user to set the password. This will show any attempts (success or fail) that occur\nafter 48 hours, which can indicate too long of a time period in setting the password to something that only the user knows.\nIt is recommended that this time period is adjusted per your internal company policy.'", + "tactics": [ + { + "tactic": "Persistence", + "techniques": [ + { + "technique": "T1098" + } + ] + } + ] + } + }, + "status": "disabled", + "displayName": "AD user enabled and password not set within 48 hours" + } + } + } + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-cd-',uniquestring('xdr-62085097-d113-459f-9ea7-30216f2ee6af')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'WindowsSecurityEvents-CD-xdr-62085097-d113-459f-9ea7-30-c613f889')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'Identifies when an account is enabled with a default password and the password is not set by the user within 48 hours.\nEffectively, there is an event 4722 indicating an account was enabled and within 48 hours, no event 4723 occurs which\nindicates there was no attempt by the user to set the password. This will show any attempts (success or fail) that occur\nafter 48 hours, which can indicate too long of a time period in setting the password to something that only the user knows.\nIt is recommended that this time period is adjusted per your internal company policy.'", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0", + "imports": { + "MicrosoftSecurity": { + "provider": "MicrosoftSecurity", + "version": "1.0.0" + } + }, + "resources": { + "detectionRule": { + "import": "MicrosoftSecurity", + "type": "Microsoft.Security/detectionRules@2026-06-01-preview", + "properties": { + "id": "[if(true(), 'xdr-62085097-d113-459f-9ea7-30216f2ee6af', 'xdr-62085097-d113-459f-9ea7-30216f2ee6af')]", + "queryCondition": { + "queryText": "let starttime = 3d;\nlet SecEvents = materialize ( SecurityEvent | where TimeGenerated >= ago(starttime)\n| where EventID in (4722,4723) | where TargetUserName !endswith \"$\"\n| project TimeGenerated, EventID, Activity, Computer, TargetAccount, TargetSid, SubjectAccount, SubjectUserSid);\nlet userEnable = SecEvents\n| extend EventID4722Time = TimeGenerated\n// 4722: User Account Enabled\n| where EventID == 4722\n| project Time_Event4722 = TimeGenerated, TargetAccount, TargetSid, SubjectAccount_Event4722 = SubjectAccount, SubjectUserSid_Event4722 = SubjectUserSid, Activity_4722 = Activity, Computer_4722 = Computer;\nlet userPwdSet = SecEvents\n// 4723: Attempt made by user to set password\n| where EventID == 4723\n| project Time_Event4723 = TimeGenerated, TargetAccount, TargetSid, SubjectAccount_Event4723 = SubjectAccount, SubjectUserSid_Event4723 = SubjectUserSid, Activity_4723 = Activity, Computer_4723 = Computer;\nuserEnable | join kind=leftouter userPwdSet on TargetAccount, TargetSid\n| extend PasswordSetAttemptDelta_Min = datetime_diff('minute', Time_Event4723, Time_Event4722)\n| where PasswordSetAttemptDelta_Min > 2880 or isempty(PasswordSetAttemptDelta_Min)\n| project-away TargetAccount1, TargetSid1\n| extend Reason = @\"User either has not yet attempted to set the initial password after account was enabled or it occurred after 48 hours\"\n| order by Time_Event4722 asc\n| project-reorder Time_Event4722, Time_Event4723, PasswordSetAttemptDelta_Min, TargetAccount, TargetSid\n| extend Computer = coalesce(Computer_4723, Computer_4722)\n| extend HostName = tostring(split(Computer, \".\")[0]), DomainIndex = toint(indexof(Computer, '.'))\n| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)\n| extend AccountName = tostring(split(TargetAccount, \"\\\\\")[1]), AccountNTDomain = tostring(split(TargetAccount, \"\\\\\")[0])\n| project-away DomainIndex" + }, + "schedule": { + "frequency": "P1D" + }, + "detectionAction": { + "alertTemplate": { + "severity": "low", + "entityMappings": { + "accounts": [ + { + "ntDomainColumn": "AccountNTDomain", + "id": "[if(true(), 'account1', 'account1')]", + "nameColumn": "AccountName" + }, + { + "id": "[if(true(), 'account2', 'account2')]", + "sidColumn": "TargetSid" + } + ], + "hosts": [ + { + "dnsDomainColumn": "HostNameDomain", + "id": "[if(true(), 'host1', 'host1')]", + "nameColumn": "HostName" + } + ] + }, + "title": "AD user enabled and password not set within 48 hours", + "description": "'Identifies when an account is enabled with a default password and the password is not set by the user within 48 hours.\nEffectively, there is an event 4722 indicating an account was enabled and within 48 hours, no event 4723 occurs which\nindicates there was no attempt by the user to set the password. This will show any attempts (success or fail) that occur\nafter 48 hours, which can indicate too long of a time period in setting the password to something that only the user knows.\nIt is recommended that this time period is adjusted per your internal company policy.'", + "tactics": [ + { + "tactic": "Persistence", + "techniques": [ + { + "technique": "T1098" + } + ] + } + ] + } + }, + "status": "disabled", + "displayName": "AD user enabled and password not set within 48 hours" + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-62085097-d113-459f-9ea7-30216f2ee6af", + "contentKind": "CustomDetection", + "displayName": "AD user enabled and password not set within 48 hours", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-62085097-d113-459f-9ea7-30216f2ee6af','-','3.1.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-62085097-d113-459f-9ea7-30216f2ee6af','-','3.1.0')))]", + "version": "3.1.0", + "dependency": { + "requiredWorkloads": [ + "sentinel" + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "pid-cfc82dab-62e7-4f61-a971-259213533680-partnercenter", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [] + } + } } ], "outputs": {} diff --git a/Solutions/Windows Security Events/Package/testParameters.json b/Solutions/Windows Security Events/Package/testParameters.json index efaf6d5e957..4843d8131bb 100644 --- a/Solutions/Windows Security Events/Package/testParameters.json +++ b/Solutions/Windows Security Events/Package/testParameters.json @@ -36,5 +36,40 @@ "metadata": { "description": "Name for the workbook" } + }, + "DeployAnalyticsRule": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Deploy the Microsoft Sentinel analytic rules carried by this solution (ContentKind AnalyticsRule and its AnalyticsRuleTemplate registration face)." + } + }, + "DeployWorkbook": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Deploy the Microsoft Sentinel workbook content and its Content Hub registration carried by this solution (ContentKind Workbook and WorkbookTemplate)." + } + }, + "DeployDataConnector": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Deploy the data connectors carried by this solution, together with their metadata and catalog entries (ContentKind DataConnector, ResourceDataConnector and DataType)." + } + }, + "DeployCustomDetection": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Deploy the XDR-native custom detection resources and their Content Hub registrations (ContentKind CustomDetection and CustomDetectionTemplate). Independent of DeployAnalyticsRule: both kinds can be selected together. Existing analytic-rule instances are not disabled or removed. CD enabled or disabled status is controlled separately from this deployment switch." + } + }, + "DeployHuntingQuery": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Deploy the Microsoft Sentinel hunting queries carried by this solution." + } } } diff --git a/Solutions/Windows Security Events/ReleaseNotes.md b/Solutions/Windows Security Events/ReleaseNotes.md index c27fbd1c01b..1fadb2c9c17 100644 --- a/Solutions/Windows Security Events/ReleaseNotes.md +++ b/Solutions/Windows Security Events/ReleaseNotes.md @@ -1,5 +1,6 @@ | **Version** | **Date Modified (DD-MM-YYYY)** | **Change History** | |-------------|--------------------------------|--------------------------------------------------------------------------------------------| +| 3.1.2 | 12-10-2026 | Added 21 disabled **Defender XDR Custom Detections** with reviewed entity mappings and hybrid V3.1 packaging alongside existing Microsoft Sentinel content. Validation was offline; runtime execution and alert parity were not run. | | 3.0.13 | 20-07-2026 | Added **Analytic Rule** WMI Spawning Suspicious Child Process | | 3.0.12 | 18-02-2026 | Removed external blog reference text from "Remote Scheduled Task Creation or Update using ATSVC Named Pipe" and " Scheduled Task Creation or Update from User Writable Directory" **hunting query** description | | 3.0.11 | 28-01-2026 | Updated **Analytic Rule** to fix the link from the description & Update **Analytic Rule** NonDCActiveDirectoryReplication - to reduce false positive results | diff --git a/Solutions/Windows Security Events/SolutionMetadata.json b/Solutions/Windows Security Events/SolutionMetadata.json index 38d22929568..d47989b47fe 100644 --- a/Solutions/Windows Security Events/SolutionMetadata.json +++ b/Solutions/Windows Security Events/SolutionMetadata.json @@ -1,15 +1,21 @@ { - "publisherId": "azuresentinel", - "offerId": "azure-sentinel-solution-securityevents", - "firstPublishDate": "2022-05-23", - "providers": ["Microsoft"], - "categories": { - "domains" : ["Security - Threat Protection"] - }, - "support": { - "name": "Microsoft Corporation", - "email": "support@microsoft.com", - "tier": "Microsoft", - "link": "https://support.microsoft.com" - } -} \ No newline at end of file + "trackingId": "pid-cfc82dab-62e7-4f61-a971-259213533680-partnercenter", + "publisherId": "azuresentinel", + "offerId": "azure-sentinel-solution-securityevents", + "firstPublishDate": "2022-05-23", + "providers": [ + "Microsoft" + ], + "categories": { + "domains": [ + "Security - Threat Protection" + ] + }, + "support": { + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "tier": "Microsoft", + "link": "https://support.microsoft.com" + }, + "version": "3.1.2" +} diff --git a/Solutions/Windows Security Events/XDR Detections/ADFSDBNamedPipeConnection.yaml b/Solutions/Windows Security Events/XDR Detections/ADFSDBNamedPipeConnection.yaml new file mode 100644 index 00000000000..b0585020674 --- /dev/null +++ b/Solutions/Windows Security Events/XDR Detections/ADFSDBNamedPipeConnection.yaml @@ -0,0 +1,181 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: SecurityEvents + dataTypes: + - SecurityEvent +- connectorId: WindowsSecurityEvents + dataTypes: + - SecurityEvent +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: dcdf9bfc-c239-4764-a9f9-3612e6dff49c + path: Analytic Rules/ADFSDBNamedPipeConnection.yaml + version: 1.0.2 + querySha256: 1daf1828fbd72115e5015ca11b9c1d34bc0f6a8af264e85eabe11214211ba01a + schedule: + queryFrequency: 1d + queryPeriod: 1d + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - 'Schedule assessment: source frequency=1d, lookback=1d; target frequency=P1D, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - Account.NTDomain column `AccountNTDomain` is not produced by the query + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - Unconfirmed generic Account.Name mapping was omitted because another required Host, Mailbox, or IP asset is available + - Account.FullName value is retained as customDetails.AccountFullName from query column `UserName`, but its target output + binding requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.AccountFullName column `UserName` requires runtime output-schema binding verification + - Account.Name value is retained as customDetails.AccountName from query column `AccountName`, but its target output binding + requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.AccountName column `AccountName` requires runtime output-schema binding verification + - Account.NTDomain value is retained as customDetails.AccountNTDomain from query column `AccountNTDomain`, but its target + output binding requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.AccountNTDomain column `AccountNTDomain` requires runtime output-schema binding verification + - Host.FullName value is retained as customDetails.HostFullName from query column `Computer`, but its target output binding + requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.HostFullName column `Computer` requires runtime output-schema binding verification + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: [] + errors: [] + originalTactics: + - Collection + originalTechniques: + - T1005 + reviewScope: + sourceDocumentSha256: d983d3d01a637ba211a5bf42cf3cc3ac554a782010d923a7d5265ecad97584d0 + targetQuerySha256: 9e2c84c717790b8ca2bbc9856d11bcd812af572e690fd41f3842f6174a23a21c + reviewDecisions: + - reason: 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented + by hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + decision: accepted + sourceDocumentSha256: d983d3d01a637ba211a5bf42cf3cc3ac554a782010d923a7d5265ecad97584d0 + targetQuerySha256: 9e2c84c717790b8ca2bbc9856d11bcd812af572e690fd41f3842f6174a23a21c + supplementalEntityDetails: + - entityType: Account + entityIndex: 1 + identifier: FullName + sourceColumn: UserName + column: UserName + status: runtime-binding-pending + customDetailKey: AccountFullName + - entityType: Account + entityIndex: 1 + identifier: Name + sourceColumn: AccountName + column: AccountName + status: runtime-binding-pending + customDetailKey: AccountName + - entityType: Account + entityIndex: 1 + identifier: NTDomain + sourceColumn: AccountNTDomain + column: AccountNTDomain + status: runtime-binding-pending + customDetailKey: AccountNTDomain + - entityType: Host + entityIndex: 2 + identifier: FullName + sourceColumn: Computer + column: Computer + status: runtime-binding-pending + customDetailKey: HostFullName + acceptedReviewReasons: + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' +properties: + id: xdr-dcdf9bfc-c239-4764-a9f9-3612e6dff49c + displayName: ADFS Database Named Pipe Connection + status: disabled + queryCondition: + queryText: |- + // Adjust this to use a longer timeframe to identify ADFS servers + //let lookback = 6d; + // Adjust this to adjust the key export detection timeframe + //let timeframe = 1d; + // Start be identifying ADFS servers to reduce FP chance + let ADFS_Servers = ( + Event + //| where TimeGenerated > ago(timeframe+lookback) + | where Source == "Microsoft-Windows-Sysmon" + | where EventID == 18 + | extend EventData = parse_xml(EventData).DataItem.EventData.Data + | mv-expand bagexpansion=array EventData + | evaluate bag_unpack(EventData) + | extend Key = tostring(column_ifexists('@Name', "")), Value = column_ifexists('#text', "") + | evaluate pivot(Key, any(Value), TimeGenerated, Source, EventLog, Computer, EventLevel, EventLevelName, EventID, UserName, MG, ManagementGroupName, _ResourceId) + | extend Image = column_ifexists("Image", "") + | extend process = split(Image, '\\', -1)[-1] + | where process =~ "Microsoft.IdentityServer.ServiceHost.exe" + | summarize by Computer); + // Look for ADFS servers where Named Pipes event are present + Event + //| where TimeGenerated > ago(timeframe) + | where Source == "Microsoft-Windows-Sysmon" + | where EventID == 18 + | where Computer in~ (ADFS_Servers) + | extend RenderedDescription = tostring(split(RenderedDescription, ":")[0]) + | extend EventData = parse_xml(EventData).DataItem.EventData.Data + | mv-expand bagexpansion=array EventData + | evaluate bag_unpack(EventData) + | extend Key = tostring(column_ifexists('@Name', "")), Value = column_ifexists('#text', "") + | evaluate pivot(Key, any(Value), TimeGenerated, Source, EventLog, Computer, EventLevel, EventLevelName, EventID, UserName, RenderedDescription, MG, ManagementGroupName, Type, _ResourceId) + | extend RuleName = column_ifexists("RuleName", ""), + TechniqueId = column_ifexists("TechniqueId", ""), + TechniqueName = column_ifexists("TechniqueName", ""), + Image = column_ifexists("Image", ""), + PipeName = column_ifexists("PipeName", ""), + EventType = column_ifexists("EventType", "") + | parse RuleName with * 'technique_id=' TechniqueId ',' * 'technique_name=' TechniqueName + // Look for Pipe related to querying the WID + | where PipeName == "\\MICROSOFT##WID\\tsql\\query" + | extend process = split(Image, '\\', -1)[-1] + // Exclude expected processes + | where process !in ("Microsoft.IdentityServer.ServiceHost.exe", "Microsoft.Identity.Health.Adfs.PshSurrogate.exe", "AzureADConnect.exe", "Microsoft.Tri.Sensor.exe", "wsmprovhost.exe","mmc.exe", "sqlservr.exe") + | extend Operation = RenderedDescription + | project-reorder TimeGenerated, EventType, Operation, process, Image, Computer, UserName + | extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.')) + | extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer) + | extend AccountName = tostring(split(UserName, @'\')[1]), AccountNTDomain = tostring(split(UserName, @'\')[0]) + schedule: + frequency: P1D + detectionAction: + alertTemplate: + title: ADFS Database Named Pipe Connection + description: |- + 'This detection uses Sysmon telemetry to detect suspicious local connections via a named pipe to the AD FS configuration database (Windows Internal Database). + In order to use this query you need to be collecting Sysmon EventIdD 18 (Pipe Connected). + If you do not have Sysmon data in your workspace this query will raise an error stating: + Failed to resolve scalar expression named "[@Name]"' + severity: medium + entityMappings: + hosts: + - id: host1 + nameColumn: HostName + dnsDomainColumn: HostNameDomain + tactics: + - tactic: Collection + techniques: + - technique: T1005 + customDetails: + AccountFullName: UserName + AccountName: AccountName + AccountNTDomain: AccountNTDomain + HostFullName: Computer diff --git a/Solutions/Windows Security Events/XDR Detections/ADFSRemoteAuthSyncConnection.yaml b/Solutions/Windows Security Events/XDR Detections/ADFSRemoteAuthSyncConnection.yaml new file mode 100644 index 00000000000..4727fd6f0f2 --- /dev/null +++ b/Solutions/Windows Security Events/XDR Detections/ADFSRemoteAuthSyncConnection.yaml @@ -0,0 +1,196 @@ +schemaVersion: 1.0.0 +version: 3.1.2 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: SecurityEvents + dataTypes: + - SecurityEvent +- connectorId: WindowsSecurityEvents + dataTypes: + - SecurityEvent +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: 2f4165a6-c4fb-4e94-861e-37f1b4d6c0e6 + path: Analytic Rules/ADFSRemoteAuthSyncConnection.yaml + version: 3.1.2 + querySha256: e4eb22822d708ef675cb0d8ff3ca9c01562e4fc43906858a267fb0539420766f + schedule: + queryFrequency: 1d + queryPeriod: 1d + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - 'Schedule assessment: source frequency=1d, lookback=1d; target frequency=P1D, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - Account.NTDomain column `AccountNTDomain` is not produced by the query + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - Unconfirmed generic Account.Name mapping was omitted because another required Host, Mailbox, or IP asset is available + - Account.FullName value is retained as customDetails.AccountFullName from query column `ClaimsName`, but its target output + binding requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.AccountFullName column `ClaimsName` requires runtime output-schema binding verification + - Account.Name value is retained as customDetails.AccountName from query column `AccountName`, but its target output binding + requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.AccountName column `AccountName` requires runtime output-schema binding verification + - 'Account.NTDomain value is not preserved: column `AccountNTDomain` is missing from the final query output. No invalid + customDetails binding was added and KQL was not rewritten' + - Host.FullName value is retained as customDetails.HostFullName from query column `Computer`, but its target output binding + requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.HostFullName column `Computer` requires runtime output-schema binding verification + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: [] + errors: [] + originalTactics: + - Collection + originalTechniques: + - T1005 + reviewScope: + sourceDocumentSha256: a41e3e0489ccd5fe399dc0d13467eb3fc455b2222d396cd22fd5f20f504f892c + targetQuerySha256: 9da0b769f15932192ef39a3cfaeda3f3a9ea0b962ca4d12ed02583190a4c375b + reviewDecisions: + - reason: 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented + by hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + decision: accepted + sourceDocumentSha256: a41e3e0489ccd5fe399dc0d13467eb3fc455b2222d396cd22fd5f20f504f892c + targetQuerySha256: 9da0b769f15932192ef39a3cfaeda3f3a9ea0b962ca4d12ed02583190a4c375b + supplementalEntityDetails: + - entityType: Account + entityIndex: 1 + identifier: FullName + sourceColumn: ClaimsName + column: ClaimsName + status: runtime-binding-pending + customDetailKey: AccountFullName + - entityType: Account + entityIndex: 1 + identifier: Name + sourceColumn: AccountName + column: AccountName + status: runtime-binding-pending + customDetailKey: AccountName + - entityType: Account + entityIndex: 1 + identifier: NTDomain + sourceColumn: AccountNTDomain + column: AccountNTDomain + status: not-preserved + reason: missing + - entityType: Host + entityIndex: 2 + identifier: FullName + sourceColumn: Computer + column: Computer + status: runtime-binding-pending + customDetailKey: HostFullName + acceptedReviewReasons: + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' +properties: + id: xdr-2f4165a6-c4fb-4e94-861e-37f1b4d6c0e6 + displayName: AD FS Remote Auth Sync Connection + status: disabled + queryCondition: + queryText: |- + // Adjust this to use a longer timeframe to identify ADFS servers + //let lookback = 0d; + // Adjust this to adjust detection timeframe + //let timeframe = 1d; + // SamAccountName of AD FS Service Account. Filter on the use of a specific AD FS user account + //let adfsuser = 'adfsadmin'; + // Identify ADFS Servers + let ADFS_Servers = ( + SecurityEvent + //| where TimeGenerated > ago(timeframe+lookback) + | where EventSourceName == 'AD FS Auditing' + | distinct Computer + ); + SecurityEvent + //| where TimeGenerated > ago(timeframe) + | where Computer in~ (ADFS_Servers) + // A token of type 'http://schemas.microsoft.com/ws/2006/05/servicemodel/tokens/SecureConversation' + // for relying party '-' was successfully authenticated. + | where EventID == 412 + | extend EventData = parse_xml(EventData).EventData.Data + | extend InstanceId = tostring(EventData[0]) + | join kind=inner + ( + SecurityEvent + //| where TimeGenerated > ago(timeframe) + | where Computer in~ (ADFS_Servers) + // Events to identify caller identity from event 412 + | where EventID == 501 + | extend EventData = parse_xml(EventData).EventData.Data + | where tostring(EventData[1]) contains 'identity/claims/name' + | extend InstanceId = tostring(EventData[0]) + | extend ClaimsName = tostring(EventData[2]) + // Filter on the use of a specific AD FS user account + //| where ClaimsName contains adfsuser + ) + on $left.InstanceId == $right.InstanceId + | join kind=inner + ( + SecurityEvent + | where EventID == 5156 + | where Computer in~ (ADFS_Servers) + | extend EventData = parse_xml(EventData).EventData.Data + | mv-expand bagexpansion=array EventData + | evaluate bag_unpack(EventData) + | extend Key = tostring(column_ifexists('@Name', "")), Value = column_ifexists('#text', "") + | evaluate pivot(Key, any(Value), TimeGenerated, Computer, EventID) + | extend DestPort = column_ifexists("DestPort", ""), + Direction = column_ifexists("Direction", ""), + Application = column_ifexists("Application", ""), + DestAddress = column_ifexists("DestAddress", ""), + SourceAddress = column_ifexists("SourceAddress", ""), + SourcePort = column_ifexists("SourcePort", "") + // Look for inbound connections from endpoints on port 80 + | where DestPort == 80 and Direction == '%%14592' and Application == 'System' + | where DestAddress !in ('::1','0:0:0:0:0:0:0:1') + ) + on $left.Computer == $right.Computer + | project TimeGenerated, Computer, ClaimsName, SourceAddress, SourcePort + | extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.')) + | extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer) + | extend AccountName = tostring(split(ClaimsName, @'\')[1]), AccountNTDomain = tostring(split(ClaimsName, @'\')[0]) + schedule: + frequency: P1D + detectionAction: + alertTemplate: + title: AD FS Remote Auth Sync Connection + description: |- + 'Identifies suspicious AD FS authentication by correlating Security events from "AD FS Auditing" with Windows Filtering Platform (WFP) events for incoming port 80 traffic. + This may indicate a threat actor abusing AD FS replication services to obtain configuration settings and sensitive information such as AD FS certificates. Enable AD FS auditing on the AD FS server before using this query. + References: + https://learn.microsoft.com/en-us/windows-server/identity/ad-fs/troubleshooting/ad-fs-tshoot-logging + https://twitter.com/OTR_Community/status/1387038995016732672' + severity: medium + entityMappings: + hosts: + - id: host1 + nameColumn: HostName + dnsDomainColumn: HostNameDomain + ips: + - id: ip1 + addressColumn: SourceAddress + tactics: + - tactic: Collection + techniques: + - technique: T1005 + customDetails: + AccountFullName: ClaimsName + AccountName: AccountName + HostFullName: Computer diff --git a/Solutions/Windows Security Events/XDR Detections/ADFSRemoteHTTPNetworkConnection.yaml b/Solutions/Windows Security Events/XDR Detections/ADFSRemoteHTTPNetworkConnection.yaml new file mode 100644 index 00000000000..74529621800 --- /dev/null +++ b/Solutions/Windows Security Events/XDR Detections/ADFSRemoteHTTPNetworkConnection.yaml @@ -0,0 +1,185 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: SecurityEvents + dataTypes: + - SecurityEvent +- connectorId: WindowsSecurityEvents + dataTypes: + - SecurityEvent +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: d57c33a9-76b9-40e0-9dfa-ff0404546410 + path: Analytic Rules/ADFSRemoteHTTPNetworkConnection.yaml + version: 1.0.2 + querySha256: 793d1a3387b468d63b336f62f1b39c0f23c1c171967866097b2aea3a87c3e647 + schedule: + queryFrequency: 1d + queryPeriod: 1d + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - 'Schedule assessment: source frequency=1d, lookback=1d; target frequency=P1D, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - Account.NTDomain column `AccountNTDomain` is not produced by the query + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - Unconfirmed generic Account.Name mapping was omitted because another required Host, Mailbox, or IP asset is available + - Account.FullName value is retained as customDetails.AccountFullName from query column `UserName`, but its target output + binding requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.AccountFullName column `UserName` requires runtime output-schema binding verification + - Account.Name value is retained as customDetails.AccountName from query column `AccountName`, but its target output binding + requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.AccountName column `AccountName` requires runtime output-schema binding verification + - Account.NTDomain value is retained as customDetails.AccountNTDomain from query column `AccountNTDomain`, but its target + output binding requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.AccountNTDomain column `AccountNTDomain` requires runtime output-schema binding verification + - Host.FullName value is retained as customDetails.HostFullName from query column `Computer`, but its target output binding + requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.HostFullName column `Computer` requires runtime output-schema binding verification + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: [] + errors: [] + originalTactics: + - Collection + originalTechniques: + - T1005 + reviewScope: + sourceDocumentSha256: e055cee0e64521551a12843c955f362f1cea553c92858f52cdfe47e96a37c588 + targetQuerySha256: a0a52a7d5d0e8cb728f06d7be5eaa328ff84b439b00085229995092997c14bb0 + reviewDecisions: + - reason: 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented + by hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + decision: accepted + sourceDocumentSha256: e055cee0e64521551a12843c955f362f1cea553c92858f52cdfe47e96a37c588 + targetQuerySha256: a0a52a7d5d0e8cb728f06d7be5eaa328ff84b439b00085229995092997c14bb0 + supplementalEntityDetails: + - entityType: Account + entityIndex: 1 + identifier: FullName + sourceColumn: UserName + column: UserName + status: runtime-binding-pending + customDetailKey: AccountFullName + - entityType: Account + entityIndex: 1 + identifier: Name + sourceColumn: AccountName + column: AccountName + status: runtime-binding-pending + customDetailKey: AccountName + - entityType: Account + entityIndex: 1 + identifier: NTDomain + sourceColumn: AccountNTDomain + column: AccountNTDomain + status: runtime-binding-pending + customDetailKey: AccountNTDomain + - entityType: Host + entityIndex: 2 + identifier: FullName + sourceColumn: Computer + column: Computer + status: runtime-binding-pending + customDetailKey: HostFullName + acceptedReviewReasons: + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' +properties: + id: xdr-d57c33a9-76b9-40e0-9dfa-ff0404546410 + displayName: AD FS Remote HTTP Network Connection + status: disabled + queryCondition: + queryText: |- + // Adjust this to use a longer timeframe to identify ADFS servers + //let lookback = 0d; + // Adjust this to adjust detection timeframe + //let timeframe = 1d; + // Filter out other servers in the AD FS farm + let ADFSServersList = dynamic(["ADFS02.domain.com","ADFS03.domain.com"]); + // Start by identifying ADFS servers to reduce FP chance + let ADFS_Servers = ( + Event + //| where TimeGenerated > ago(timeframe+lookback) + | where Source == "Microsoft-Windows-Sysmon" + | where EventID == 18 + | where Computer !in (ADFSServersList) + | extend EventData = parse_xml(EventData).DataItem.EventData.Data + | mv-expand bagexpansion=array EventData + | evaluate bag_unpack(EventData) + | extend Key = tostring(column_ifexists('@Name', "")), Value = column_ifexists('#text', "") + | evaluate pivot(Key, any(Value), TimeGenerated, Source, EventLog, Computer, EventLevel, EventLevelName, EventID, UserName, MG, ManagementGroupName, _ResourceId) + | extend Image = column_ifexists("Image", "") + | extend process = split(Image, '\\', -1)[-1] + | where process =~ "Microsoft.IdentityServer.ServiceHost.exe" + | summarize by Computer + ); + // Look for ADFS servers receiving connections over port 80 + Event + //| where TimeGenerated > ago(timeframe) + | where Source == "Microsoft-Windows-Sysmon" + | where Computer in~ (ADFS_Servers) + | extend RenderedDescription = tostring(split(RenderedDescription, ":")[0]) + | extend EventData = parse_xml(EventData).DataItem.EventData.Data + | mv-expand bagexpansion=array EventData + | evaluate bag_unpack(EventData) + | extend Key = tostring(column_ifexists('@Name', "")), Value = column_ifexists('#text', "") + | evaluate pivot(Key, any(Value), TimeGenerated, Source, EventLog, Computer, EventLevel, EventLevelName, EventID, UserName, RenderedDescription, MG, ManagementGroupName, _ResourceId) + | extend RuleName = column_ifexists("RuleName", ""), TechniqueId = column_ifexists("TechniqueId", ""), TechniqueName = column_ifexists("TechniqueName", "") + | parse RuleName with * 'technique_id=' TechniqueId ',' * 'technique_name=' TechniqueName + | where EventID == 3 + // Look for endpoints connecting to the AD FS server over port 80 + | extend DestinationPort = column_ifexists("DestinationPort", ""), Image = column_ifexists("Image", ""), Initiated = column_ifexists("Initiated", ""), SourceIp = column_ifexists("DestinationIp", ""), DestinationIp = column_ifexists("DestinationIp", "") + | where DestinationPort == 80 + | extend process = split(Image, '\\', -1)[-1] + // Look for the System process receiving connections + | where process == 'System' and Initiated == 'false' + | where DestinationIp !in ('::1','0:0:0:0:0:0:0:1') + | extend Operation = RenderedDescription + | project-reorder TimeGenerated, Operation, Image, Computer, UserName + | extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.')) + | extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer) + | extend AccountName = tostring(split(UserName, @'\')[1]), AccountNTDomain = tostring(split(UserName, @'\')[0]) + schedule: + frequency: P1D + detectionAction: + alertTemplate: + title: AD FS Remote HTTP Network Connection + description: |- + 'This detection uses Sysmon events (NetworkConnect events) to detect incoming network traffic on port 80 on AD FS servers. This could be a sign of a threat actor trying to use replication services on the AD FS server to get its configuration settings and extract sensitive information such as AD FS certificates. + In order to use this query you need to enable Sysmon telemetry on the AD FS Server. + Reference: https://twitter.com/OTR_Community/status/1387038995016732672 + ' + severity: medium + entityMappings: + hosts: + - id: host1 + nameColumn: HostName + dnsDomainColumn: HostNameDomain + ips: + - id: ip1 + addressColumn: SourceIp + tactics: + - tactic: Collection + techniques: + - technique: T1005 + customDetails: + AccountFullName: UserName + AccountName: AccountName + AccountNTDomain: AccountNTDomain + HostFullName: Computer diff --git a/Solutions/Windows Security Events/XDR Detections/ExcessiveLogonFailures.yaml b/Solutions/Windows Security Events/XDR Detections/ExcessiveLogonFailures.yaml new file mode 100644 index 00000000000..3ae8cf9acc8 --- /dev/null +++ b/Solutions/Windows Security Events/XDR Detections/ExcessiveLogonFailures.yaml @@ -0,0 +1,168 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: SecurityEvents + dataTypes: + - SecurityEvent +- connectorId: WindowsSecurityEvents + dataTypes: + - SecurityEvent +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: 2391ce61-8c8d-41ac-9723-d945b2e90720 + path: Analytic Rules/ExcessiveLogonFailures.yaml + version: 2.0.3 + querySha256: d3de60eb9afaf4e0aab45ef6e77f3e0daad74b4f24f9044885f935d286e8c57e + schedule: + queryFrequency: 1d + queryPeriod: 8d + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - 'Schedule assessment: source frequency=1d, lookback=8d; target frequency=P1D, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - 'Best-effort entity mapping requires review: source Host.FullName column `WorkstationName` is provisionally represented + by hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + - Account.FullName value is retained as customDetails.AccountFullName from query column `Account`, but its target output + binding requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.AccountFullName column `Account` requires runtime output-schema binding verification + - Host.FullName value is retained as customDetails.HostFullName from query column `WorkstationName`, but its target output + binding requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.HostFullName column `WorkstationName` requires runtime output-schema binding verification + - Process.CommandLine value is retained as customDetails.ProcessCommandLine from query column `Process`, but its target + output binding requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.ProcessCommandLine column `Process` requires runtime output-schema binding verification + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: [] + errors: [] + originalTactics: + - CredentialAccess + originalTechniques: + - T1110 + reviewScope: + sourceDocumentSha256: d188ab5428e4c7cdb109d068383d71cea77af065b33a1e13bf810781a13ac56a + targetQuerySha256: ef31d6ab2070116b67c2bc9a8a554a72d545aaab62a48e6cf24cb4904e08889c + reviewDecisions: + - reason: 'Best-effort entity mapping requires review: source Host.FullName column `WorkstationName` is provisionally + represented by hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original + value is also retained in customDetails when the query output binding is available; this assumption does not prove + entity parity' + decision: accepted + sourceDocumentSha256: d188ab5428e4c7cdb109d068383d71cea77af065b33a1e13bf810781a13ac56a + targetQuerySha256: ef31d6ab2070116b67c2bc9a8a554a72d545aaab62a48e6cf24cb4904e08889c + supplementalEntityDetails: + - entityType: Account + entityIndex: 1 + identifier: FullName + sourceColumn: Account + column: Account + status: runtime-binding-pending + customDetailKey: AccountFullName + - entityType: Host + entityIndex: 2 + identifier: FullName + sourceColumn: WorkstationName + column: WorkstationName + status: runtime-binding-pending + customDetailKey: HostFullName + - entityType: Process + entityIndex: 3 + identifier: CommandLine + sourceColumn: Process + column: Process + status: runtime-binding-pending + customDetailKey: ProcessCommandLine + acceptedReviewReasons: + - 'Best-effort entity mapping requires review: source Host.FullName column `WorkstationName` is provisionally represented + by hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' +properties: + id: xdr-2391ce61-8c8d-41ac-9723-d945b2e90720 + displayName: Excessive Windows Logon Failures + status: disabled + queryCondition: + queryText: |- + let starttime = 8d; + let endtime = 1d; + let threshold = 0.333; + let countlimit = 50; + SecurityEvent + | where TimeGenerated >= ago(endtime) + | where EventID == 4625 and AccountType =~ "User" + | where IpAddress !in ("127.0.0.1", "::1") + | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), CountToday = count() by EventID, Account, LogonTypeName, SubStatus, AccountType, Computer, WorkstationName, IpAddress, Process + | join kind=leftouter ( + SecurityEvent + | where TimeGenerated between (ago(starttime) .. ago(endtime)) + | where EventID == 4625 and AccountType =~ "User" + | where IpAddress !in ("127.0.0.1", "::1") + | summarize CountPrev7day = count() by EventID, Account, LogonTypeName, SubStatus, AccountType, Computer, WorkstationName, IpAddress + ) on EventID, Account, LogonTypeName, SubStatus, AccountType, Computer, WorkstationName, IpAddress + | where CountToday >= coalesce(CountPrev7day,0)*threshold and CountToday >= countlimit + //SubStatus Codes are detailed here - https://docs.microsoft.com/windows/security/threat-protection/auditing/event-4625 + | extend Reason = case( + SubStatus =~ '0xC000005E', 'There are currently no logon servers available to service the logon request.', + SubStatus =~ '0xC0000064', 'User logon with misspelled or bad user account', + SubStatus =~ '0xC000006A', 'User logon with misspelled or bad password', + SubStatus =~ '0xC000006D', 'Bad user name or password', + SubStatus =~ '0xC000006E', 'Unknown user name or bad password', + SubStatus =~ '0xC000006F', 'User logon outside authorized hours', + SubStatus =~ '0xC0000070', 'User logon from unauthorized workstation', + SubStatus =~ '0xC0000071', 'User logon with expired password', + SubStatus =~ '0xC0000072', 'User logon to account disabled by administrator', + SubStatus =~ '0xC00000DC', 'Indicates the Sam Server was in the wrong state to perform the desired operation', + SubStatus =~ '0xC0000133', 'Clocks between DC and other computer too far out of sync', + SubStatus =~ '0xC000015B', 'The user has not been granted the requested logon type (aka logon right) at this machine', + SubStatus =~ '0xC000018C', 'The logon request failed because the trust relationship between the primary domain and the trusted domain failed', + SubStatus =~ '0xC0000192', 'An attempt was made to logon, but the Netlogon service was not started', + SubStatus =~ '0xC0000193', 'User logon with expired account', + SubStatus =~ '0xC0000224', 'User is required to change password at next logon', + SubStatus =~ '0xC0000225', 'Evidently a bug in Windows and not a risk', + SubStatus =~ '0xC0000234', 'User logon with account locked', + SubStatus =~ '0xC00002EE', 'Failure Reason: An Error occurred during Logon', + SubStatus =~ '0xC0000413', 'Logon Failure: The machine you are logging onto is protected by an authentication firewall. The specified account is not allowed to authenticate to the machine', + strcat('Unknown reason substatus: ', SubStatus)) + | extend WorkstationName = iff(WorkstationName == "-" or isempty(WorkstationName), Computer , WorkstationName) + | project StartTime, EndTime, EventID, Account, LogonTypeName, SubStatus, Reason, AccountType, Computer, WorkstationName, IpAddress, CountToday, CountPrev7day, Avg7Day = round(CountPrev7day*1.00/7,2), Process + | summarize StartTime = min(StartTime), EndTime = max(EndTime), Computer = make_set(Computer,128), IpAddressList = make_set(IpAddress,128), sum(CountToday), sum(CountPrev7day), avg(Avg7Day) + by EventID, Account, LogonTypeName, SubStatus, Reason, AccountType, WorkstationName, Process + | order by sum_CountToday desc nulls last + | extend timestamp = StartTime, NTDomain = tostring(split(Account, '\\', 0)[0]), Name = tostring(split(Account, '\\', 1)[0]), HostName = tostring(split(WorkstationName, '.', 0)[0]), DnsDomain = tostring(strcat_array(array_slice(split(WorkstationName, '.'), 1, -1), '.')) + schedule: + frequency: P1D + detectionAction: + alertTemplate: + title: Excessive Windows Logon Failures + description: '''This query identifies user accounts which has over 50 Windows logon failures today and at least 33% + of the count of logon failures over the previous 7 days.''' + severity: low + entityMappings: + accounts: + - id: account1 + nameColumn: Name + ntDomainColumn: NTDomain + hosts: + - id: host1 + nameColumn: HostName + dnsDomainColumn: DnsDomain + tactics: + - tactic: CredentialAccess + techniques: + - technique: T1110 + customDetails: + AccountFullName: Account + HostFullName: WorkstationName + ProcessCommandLine: Process diff --git a/Solutions/Windows Security Events/XDR Detections/ExchangeOABVirtualDirectoryAttributeContainingPotentialWebshell.yaml b/Solutions/Windows Security Events/XDR Detections/ExchangeOABVirtualDirectoryAttributeContainingPotentialWebshell.yaml new file mode 100644 index 00000000000..2f85e5d85b3 --- /dev/null +++ b/Solutions/Windows Security Events/XDR Detections/ExchangeOABVirtualDirectoryAttributeContainingPotentialWebshell.yaml @@ -0,0 +1,144 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: SecurityEvents + dataTypes: + - SecurityEvent +- connectorId: WindowsSecurityEvents + dataTypes: + - SecurityEvent +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: faf1a6ff-53b5-4f92-8c55-4b20e9957594 + path: Analytic Rules/ExchangeOABVirtualDirectoryAttributeContainingPotentialWebshell.yaml + version: 1.0.4 + querySha256: 2edcb22fb48e794c4a77d868b44e80d3594f14d8f9805a8289dd834cc4d90886 + schedule: + queryFrequency: 1h + queryPeriod: 1h + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - 'Schedule assessment: source frequency=1h, lookback=1h; target frequency=PT1H, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - Account.NTDomain column `AccountNTDomain` is not produced by the query + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - Unconfirmed generic Account.Name mapping was omitted because another required Host, Mailbox, or IP asset is available + - Account.FullName output column `Account` cannot be proven after a destructive projection; no supplemental customDetails + binding was added and KQL was not rewritten. Runtime output-schema verification is required + - Account.Name output column `AccountName` cannot be proven after a destructive projection; no supplemental customDetails + binding was added and KQL was not rewritten. Runtime output-schema verification is required + - Account.NTDomain output column `AccountNTDomain` cannot be proven after a destructive projection; no supplemental customDetails + binding was added and KQL was not rewritten. Runtime output-schema verification is required + - Host.FullName output column `Computer` cannot be proven after a destructive projection; no supplemental customDetails + binding was added and KQL was not rewritten. Runtime output-schema verification is required + informational: [] + errors: [] + originalTactics: + - InitialAccess + originalTechniques: + - T1190 + reviewScope: + sourceDocumentSha256: 512e0287eb25973682a90eb2bb9bdcaa0c158fd5c872145498ea3d667e97a9ce + targetQuerySha256: f9e353b5587b5264d09b105e66ae45ef1bebb2194f01224026b6222ac2aadab9 + reviewDecisions: + - reason: 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented + by hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + decision: accepted + sourceDocumentSha256: 512e0287eb25973682a90eb2bb9bdcaa0c158fd5c872145498ea3d667e97a9ce + targetQuerySha256: f9e353b5587b5264d09b105e66ae45ef1bebb2194f01224026b6222ac2aadab9 + supplementalEntityDetails: + - entityType: Account + entityIndex: 1 + identifier: FullName + sourceColumn: Account + column: Account + status: unproven-destructive-projection + reason: unproven-destructive-projection + - entityType: Account + entityIndex: 1 + identifier: Name + sourceColumn: AccountName + column: AccountName + status: unproven-destructive-projection + reason: unproven-destructive-projection + - entityType: Account + entityIndex: 1 + identifier: NTDomain + sourceColumn: AccountNTDomain + column: AccountNTDomain + status: unproven-destructive-projection + reason: unproven-destructive-projection + - entityType: Host + entityIndex: 2 + identifier: FullName + sourceColumn: Computer + column: Computer + status: unproven-destructive-projection + reason: unproven-destructive-projection + acceptedReviewReasons: + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' +properties: + id: xdr-faf1a6ff-53b5-4f92-8c55-4b20e9957594 + displayName: Exchange OAB Virtual Directory Attribute Containing Potential Webshell + status: disabled + queryCondition: + queryText: |- + SecurityEvent + // Look for specific Directory Service Changes and parse data + | where EventID == 5136 + | extend EventData = parse_xml(EventData).EventData.Data + | mv-expand bagexpansion = array EventData + | evaluate bag_unpack(EventData) + | extend Key = tostring(column_ifexists('@Name', "")), Value = column_ifexists('#text', "") + | evaluate pivot(Key, any(Value),TimeGenerated, EventID, Computer, Account, AccountType, EventSourceName, Activity, SubjectAccount) + // Where changes relate to Exchange OAB + | extend ObjectClass = column_ifexists("ObjectClass", "") + | where ObjectClass =~ "msExchOABVirtualDirectory" + // Look for InternalHostName or ExternalHostName properties being changed + | extend AttributeLDAPDisplayName = column_ifexists("AttributeLDAPDisplayName", "") + | where AttributeLDAPDisplayName in~ ("msExchExternalHostName", "msExchInternalHostName") + // Look for suspected webshell activity + | extend AttributeValue = column_ifexists("AttributeValue", "") + | where AttributeValue has "script" + | project-rename LastSeen = TimeGenerated + | extend ObjectDN = column_ifexists("ObjectDN", "") + | project-reorder LastSeen, Computer, Account, ObjectDN, AttributeLDAPDisplayName, AttributeValue + | extend timestamp = LastSeen + | extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.')) + | extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer) + | extend AccountName = tostring(split(Account, @'\')[1]), AccountNTDomain = tostring(split(Account, @'\')[0]) + schedule: + frequency: PT1H + detectionAction: + alertTemplate: + title: Exchange OAB Virtual Directory Attribute Containing Potential Webshell + description: |- + 'This query uses Windows Event ID 5136 in order to detect potential webshell deployment by exploitation of CVE-2021-27065. + This query looks for changes to the InternalHostName or ExternalHostName properties of Exchange OAB Virtual Directory objects in AD Directory Services where the new objects contain potential webshell objects.' + severity: high + entityMappings: + hosts: + - id: host1 + nameColumn: HostName + dnsDomainColumn: HostNameDomain + tactics: + - tactic: InitialAccess + techniques: + - technique: T1190 diff --git a/Solutions/Windows Security Events/XDR Detections/GainCodeExecutionADFSViaSMB.yaml b/Solutions/Windows Security Events/XDR Detections/GainCodeExecutionADFSViaSMB.yaml new file mode 100644 index 00000000000..bc9845bb081 --- /dev/null +++ b/Solutions/Windows Security Events/XDR Detections/GainCodeExecutionADFSViaSMB.yaml @@ -0,0 +1,168 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: SecurityEvents + dataTypes: + - SecurityEvent +- connectorId: WindowsSecurityEvents + dataTypes: + - SecurityEvent +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: 12dcea64-bec2-41c9-9df2-9f28461b1295 + path: Analytic Rules/GainCodeExecutionADFSViaSMB.yaml + version: 1.2.1 + querySha256: db343782486018684a450f42ca5c1ce5ee9982b05f2d96fc9d2d003986e034f1 + schedule: + queryFrequency: 1d + queryPeriod: 7d + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - 'Schedule assessment: source frequency=1d, lookback=7d; target frequency=P1D, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - Account.NTDomain column `AccountNTDomain` is not produced by the query + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - Unconfirmed generic Account.Name mapping was omitted because another required Host, Mailbox, or IP asset is available + - Account.FullName value is retained as customDetails.AccountFullName from query column `Account`, but its target output + binding requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.AccountFullName column `Account` requires runtime output-schema binding verification + - Account.Name value is retained as customDetails.AccountName from query column `AccountName`, but its target output binding + requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.AccountName column `AccountName` requires runtime output-schema binding verification + - 'Account.NTDomain value is not preserved: column `AccountNTDomain` is missing from the final query output. No invalid + customDetails binding was added and KQL was not rewritten' + - Host.FullName value is retained as customDetails.HostFullName from query column `Computer`, but its target output binding + requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.HostFullName column `Computer` requires runtime output-schema binding verification + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: [] + errors: [] + originalTactics: + - LateralMovement + originalTechniques: + - T1210 + reviewScope: + sourceDocumentSha256: c434a44b52bb2def3be096c09e26e41f84f6afe86431dd554176bbcd433f7b9d + targetQuerySha256: 650effc65c59b8b2e61370f3746dba2703425ceff415458cc850c2bbccf02a09 + reviewDecisions: + - reason: 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented + by hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + decision: accepted + sourceDocumentSha256: c434a44b52bb2def3be096c09e26e41f84f6afe86431dd554176bbcd433f7b9d + targetQuerySha256: 650effc65c59b8b2e61370f3746dba2703425ceff415458cc850c2bbccf02a09 + supplementalEntityDetails: + - entityType: Account + entityIndex: 1 + identifier: FullName + sourceColumn: Account + column: Account + status: runtime-binding-pending + customDetailKey: AccountFullName + - entityType: Account + entityIndex: 1 + identifier: Name + sourceColumn: AccountName + column: AccountName + status: runtime-binding-pending + customDetailKey: AccountName + - entityType: Account + entityIndex: 1 + identifier: NTDomain + sourceColumn: AccountNTDomain + column: AccountNTDomain + status: not-preserved + reason: missing + - entityType: Host + entityIndex: 2 + identifier: FullName + sourceColumn: Computer + column: Computer + status: runtime-binding-pending + customDetailKey: HostFullName + acceptedReviewReasons: + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' +properties: + id: xdr-12dcea64-bec2-41c9-9df2-9f28461b1295 + displayName: Gain Code Execution on ADFS Server via SMB + Remote Service or Scheduled Task + status: disabled + queryCondition: + queryText: |- + let timeframe = 1d; + // Adjust for a longer timeframe for identifying ADFS Servers + let lookback = 6d; + // Identify ADFS Servers + let ADFS_Servers = ( + SecurityEvent + | where TimeGenerated > ago(timeframe+lookback) + | where EventID == 4688 and SubjectLogonId != "0x3e4" + | where NewProcessName has "Microsoft.IdentityServer.ServiceHost.exe" + | distinct Computer + ); + SecurityEvent + | where TimeGenerated > ago(timeframe) + | where Computer in~ (ADFS_Servers) + | where Account !endswith "$" + // Check for scheduled task events + | where EventID in (4697, 4698, 4699, 4700, 4701, 4702) + | extend EventDataParsed = parse_xml(EventData) + | extend SubjectLogonId = tostring(EventDataParsed.EventData.Data[3]["#text"]) + // Check specifically for access to IPC$ share and PIPE\svcctl and PIPE\atsvc for Service Control Services and Schedule Control Services + | union ( + SecurityEvent + | where TimeGenerated > ago(timeframe) + | where Computer in~ (ADFS_Servers) + | where Account !endswith "$" + | where EventID == 5145 + | where RelativeTargetName =~ "svcctl" or RelativeTargetName =~ "atsvc" + ) + // Check for lateral movement + | join kind=inner + (SecurityEvent + | where TimeGenerated > ago(timeframe) + | where Account !endswith "$" + | where EventID == 4624 and LogonType == 3 + ) on $left.SubjectLogonId == $right.TargetLogonId + | project TimeGenerated, Account, Computer, EventID, RelativeTargetName + | extend timestamp = TimeGenerated + | extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.')) + | extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer) + | extend AccountName = tostring(split(Account, @'\')[1]), AccountNTDomain = tostring(split(Account, @'\')[0]) + schedule: + frequency: P1D + detectionAction: + alertTemplate: + title: Gain Code Execution on ADFS Server via SMB + Remote Service or Scheduled Task + description: '''This query detects instances where an attacker has gained the ability to execute code on an ADFS Server + through SMB and Remote Service or Scheduled Task.''' + severity: medium + entityMappings: + hosts: + - id: host1 + nameColumn: HostName + dnsDomainColumn: HostNameDomain + tactics: + - tactic: LateralMovement + techniques: + - technique: T1210 + customDetails: + AccountFullName: Account + AccountName: AccountName + HostFullName: Computer diff --git a/Solutions/Windows Security Events/XDR Detections/LocalDeviceJoinInfoAndTransportKeyRegKeysAccess.yaml b/Solutions/Windows Security Events/XDR Detections/LocalDeviceJoinInfoAndTransportKeyRegKeysAccess.yaml new file mode 100644 index 00000000000..600f6a10eea --- /dev/null +++ b/Solutions/Windows Security Events/XDR Detections/LocalDeviceJoinInfoAndTransportKeyRegKeysAccess.yaml @@ -0,0 +1,173 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: SecurityEvents + dataTypes: + - SecurityEvent +- connectorId: WindowsSecurityEvents + dataTypes: + - SecurityEvent +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: a356c8bd-c81d-428b-aa36-83be706be034 + path: Analytic Rules/LocalDeviceJoinInfoAndTransportKeyRegKeysAccess.yaml + version: 1.0.6 + querySha256: 1435d0a01e5761c6cca7444a3b94c851e3f2f5c8134bec6c02d6ce11a0a0f34f + schedule: + queryFrequency: 1d + queryPeriod: 1d + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - isfuzzy unions can still fail semantic binding in Advanced Hunting + - 'Schedule assessment: source frequency=1d, lookback=1d; target frequency=P1D, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - Account.FullName value is retained as customDetails.AccountFullName from query column `Account`, but its target output + binding requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.AccountFullName column `Account` requires runtime output-schema binding verification + - Host.FullName value is retained as customDetails.HostFullName from query column `Computer`, but its target output binding + requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.HostFullName column `Computer` requires runtime output-schema binding verification + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: [] + errors: [] + originalTactics: + - Discovery + originalTechniques: + - T1012 + reviewScope: + sourceDocumentSha256: 7db5647289c00ce1cbb3c412b2c4e59cfb67325dbe4f369fa6e17f74af105bf3 + targetQuerySha256: a3b8d391128a7d13b2ab5498301470eb08bbe0795e0626e7da836b24c724beab + reviewDecisions: + - reason: isfuzzy unions can still fail semantic binding in Advanced Hunting + decision: accepted + sourceDocumentSha256: 7db5647289c00ce1cbb3c412b2c4e59cfb67325dbe4f369fa6e17f74af105bf3 + targetQuerySha256: a3b8d391128a7d13b2ab5498301470eb08bbe0795e0626e7da836b24c724beab + - reason: 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented + by hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + decision: accepted + sourceDocumentSha256: 7db5647289c00ce1cbb3c412b2c4e59cfb67325dbe4f369fa6e17f74af105bf3 + targetQuerySha256: a3b8d391128a7d13b2ab5498301470eb08bbe0795e0626e7da836b24c724beab + supplementalEntityDetails: + - entityType: Account + entityIndex: 1 + identifier: FullName + sourceColumn: Account + column: Account + status: runtime-binding-pending + customDetailKey: AccountFullName + - entityType: Host + entityIndex: 2 + identifier: FullName + sourceColumn: Computer + column: Computer + status: runtime-binding-pending + customDetailKey: HostFullName + acceptedReviewReasons: + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - isfuzzy unions can still fail semantic binding in Advanced Hunting +properties: + id: xdr-a356c8bd-c81d-428b-aa36-83be706be034 + displayName: Microsoft Entra ID Local Device Join Information and Transport Key Registry Keys Access + status: disabled + queryCondition: + queryText: |- + // AADJoined or Register Device Registry Keys + let aadJoinRoot = "\\REGISTRY\\MACHINE\\SYSTEM\\ControlSet001\\Control\\CloudDomainJoin\\JoinInfo\\"; + let aadRegisteredRoot = "\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\WorkplaceJoin"; + // Transport Key Registry Key + let keyTransportKey = "\\REGISTRY\\MACHINE\\SYSTEM\\ControlSet001\\Control\\Cryptography\\Ngc\\KeyTransportKey\\"; + (union isfuzzy=true + ( + // Access to Object Requested + SecurityEvent + | where EventID == '4656' + | where EventData has aadJoinRoot or EventData has aadRegisteredRoot + | extend EventData = parse_xml(EventData).EventData.Data + | mv-expand bagexpansion=array EventData + | evaluate bag_unpack(EventData) + | extend Key = tostring(column_ifexists('@Name', "")), Value = column_ifexists('#text', "") + | evaluate pivot(Key, any(Value), TimeGenerated, Computer, EventID) + | where ObjectType == 'Key' + | where ObjectName startswith aadJoinRoot and SubjectLogonId != '0x3e7' //Local System + | extend ProcessId = column_ifexists("ProcessId", ""), Process = split(ProcessName, '\\', -1)[-1],Account = strcat(SubjectDomainName, "\\", SubjectUserName) + | join kind=innerunique ( + SecurityEvent + | where EventID == '4656' + | where EventData has keyTransportKey + | extend EventData = parse_xml(EventData).EventData.Data + | mv-expand bagexpansion=array EventData + | evaluate bag_unpack(EventData) + | extend Key = tostring(column_ifexists('@Name', "")), Value = column_ifexists('#text', "") + | evaluate pivot(Key, any(Value), TimeGenerated, Computer, EventID) + | extend ObjectName = column_ifexists("ObjectName", ""),ObjectType = column_ifexists("ObjectType", "") + | where ObjectType == 'Key' + | where ObjectName startswith keyTransportKey and SubjectLogonId != '0x3e7' //Local System + | extend ProcessId = column_ifexists("ProcessId", ""), Process = split(ProcessName, '\\', -1)[-1],Account = strcat(SubjectDomainName, "\\", SubjectUserName) + ) on $left.Computer == $right.Computer and $left.SubjectLogonId == $right.SubjectLogonId and $left.ProcessId == $right.ProcessId + | project TimeGenerated, Computer, Account, SubjectDomainName, SubjectUserName, SubjectLogonId, ObjectName, tostring(Process), ProcessName, ProcessId, EventID + ), + // Accessing Object + ( + SecurityEvent + | where EventID == '4663' + | where ObjectType == 'Key' + | where (ObjectName startswith aadJoinRoot or ObjectName contains aadRegisteredRoot) and SubjectLogonId != '0x3e7' //Local System + | extend Account = SubjectAccount + | join kind=innerunique ( + SecurityEvent + | where EventID == '4663' + | where ObjectType == 'Key' + | where ObjectName has keyTransportKey and SubjectLogonId != '0x3e7' //Local System + | extend Account = SubjectAccount + ) on $left.Computer == $right.Computer and $left.SubjectLogonId == $right.SubjectLogonId and $left.ProcessId == $right.ProcessId + | project TimeGenerated, Computer, Account, SubjectDomainName, SubjectUserName, SubjectLogonId, ObjectName, Process, ProcessName, ProcessId, EventID + | extend HostName = tostring(split(Computer, '.', 0)[0]), DnsDomain = tostring(strcat_array(array_slice(split(Computer, '.'), 1, -1), '.')) + ) + ) + schedule: + frequency: P1D + detectionAction: + alertTemplate: + title: Microsoft Entra ID Local Device Join Information and Transport Key Registry Keys Access + description: |- + 'This detection uses Windows security events to detect suspicious access attempts by the same process to registry keys that provide information about an Microsoft Entra ID joined or registered devices and Transport keys (tkpub / tkpriv). + This information can be used to export the Device Certificate (dkpub / dkpriv) and Transport key (tkpub/tkpriv). + These set of keys can be used to impersonate existing Microsoft Entra ID joined devices. + This detection requires an access control entry (ACE) on the system access control list (SACL) of the following securable objects: + HKLM:\SYSTEM\CurrentContr + severity: medium + entityMappings: + accounts: + - id: account1 + nameColumn: SubjectUserName + ntDomainColumn: SubjectDomainName + hosts: + - id: host1 + nameColumn: HostName + dnsDomainColumn: DnsDomain + tactics: + - tactic: Discovery + techniques: + - technique: T1012 + customDetails: + AccountFullName: Account + HostFullName: Computer diff --git a/Solutions/Windows Security Events/XDR Detections/MultipleFailedFollowedBySuccess.yaml b/Solutions/Windows Security Events/XDR Detections/MultipleFailedFollowedBySuccess.yaml new file mode 100644 index 00000000000..199cff63b9e --- /dev/null +++ b/Solutions/Windows Security Events/XDR Detections/MultipleFailedFollowedBySuccess.yaml @@ -0,0 +1,135 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: SecurityEvents + dataTypes: + - SecurityEvent +- connectorId: WindowsSecurityEvents + dataTypes: + - SecurityEvent +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: cf3ede88-a429-493b-9108-3e46d3c741f7 + path: Analytic Rules/MultipleFailedFollowedBySuccess.yaml + version: 1.0.7 + querySha256: fe83b35b4940aa9a57174583b3ea2ba60b363ea843fa2a3a90e9c15398c46aac + schedule: + queryFrequency: 2h + queryPeriod: 2h + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - 'Schedule assessment: source frequency=2h, lookback=2h; target frequency=PT2H, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - Account.FullName output column `Account` cannot be proven after a destructive projection; no supplemental customDetails + binding was added and KQL was not rewritten. Runtime output-schema verification is required + - Host.FullName output column `Computer` cannot be proven after a destructive projection; no supplemental customDetails + binding was added and KQL was not rewritten. Runtime output-schema verification is required + informational: [] + errors: [] + originalTactics: + - CredentialAccess + originalTechniques: + - T1110 + reviewScope: + sourceDocumentSha256: 2e81e24d348a47f062c840df829d220405217d3bd86a93a6de1aba91ce67dedd + targetQuerySha256: c9092718caf4439a7060d6d65f7148e7ca821777d103ea523a461bb976665236 + reviewDecisions: + - reason: 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented + by hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + decision: accepted + sourceDocumentSha256: 2e81e24d348a47f062c840df829d220405217d3bd86a93a6de1aba91ce67dedd + targetQuerySha256: c9092718caf4439a7060d6d65f7148e7ca821777d103ea523a461bb976665236 + supplementalEntityDetails: + - entityType: Account + entityIndex: 1 + identifier: FullName + sourceColumn: Account + column: Account + status: unproven-destructive-projection + reason: unproven-destructive-projection + - entityType: Host + entityIndex: 2 + identifier: FullName + sourceColumn: Computer + column: Computer + status: unproven-destructive-projection + reason: unproven-destructive-projection + acceptedReviewReasons: + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' +properties: + id: xdr-cf3ede88-a429-493b-9108-3e46d3c741f7 + displayName: SecurityEvent - Multiple authentication failures followed by a success + status: disabled + queryCondition: + queryText: |- + let timeRange = 2h; + let authenticationWindow = 1h; + let authenticationThreshold = 5; + SecurityEvent + | where TimeGenerated > ago(timeRange) + | where EventID in (4624, 4625) + | where IpAddress != "-" and isnotempty(Account) + | extend Outcome = iff(EventID == 4624, "Success", "Failure") + // bin outcomes into 10 minute windows to reduce the volume of data + | summarize OutcomeCount=count() by bin(TimeGenerated, 10m), Account, IpAddress, Computer, Outcome + | project TimeGenerated, Account, IpAddress, Computer, Outcome, OutcomeCount + // sort ready for sessionizing - by account and time of the authentication outcome + | sort by TimeGenerated asc, Account, IpAddress, Computer, Outcome, OutcomeCount + | serialize + // sessionize into failure groupings until either the account changes or there is a success + | extend SessionStartedUtc = row_window_session(TimeGenerated, timeRange, authenticationWindow, Account != prev(Account) or prev(Outcome) == "Success") + // count the failures in each session + | summarize FailureCountBeforeSuccess=sumif(OutcomeCount, Outcome == "Failure"), StartTime=min(TimeGenerated), EndTime=max(TimeGenerated), make_list(Outcome, 128), make_set(Computer, 128), make_set(IpAddress, 128) by SessionStartedUtc, Account + // the session must not start with a success, and must end with one + | where array_index_of(list_Outcome, "Success") != 0 + | where array_index_of(list_Outcome, "Success") == array_length(list_Outcome) - 1 + | project-away SessionStartedUtc, list_Outcome + // where the number of failures before the success is above the threshold + | where FailureCountBeforeSuccess >= authenticationThreshold + // expand out ip and computer for customer entity assignment + | mv-expand set_IpAddress, set_Computer + | extend IpAddress = tostring(set_IpAddress), Computer = tostring(set_Computer) + | extend timestamp=StartTime, NTDomain = split(Account, '\\', 0)[0], Name = split(Account, '\\', 1)[0], HostName = tostring(split(Computer, '.', 0)[0]), DnsDomain = tostring(strcat_array(array_slice(split(Computer, '.'), 1, -1), '.')) + schedule: + frequency: PT2H + detectionAction: + alertTemplate: + title: SecurityEvent - Multiple authentication failures followed by a success + description: |- + 'Identifies accounts who have failed to logon to the domain multiple times in a row, followed by a successful authentication within a short time frame. Multiple failed attempts followed by a success can be an indication of a brute force attempt or possible mis-configuration of a service account within an environment. + The lookback is set to 2h and the authentication window and threshold are set to 1h and 5, meaning we need to see a minimum of 5 failures followed by a success for an account within 1 hour to surface an alert.' + severity: low + entityMappings: + accounts: + - id: account1 + nameColumn: Name + ntDomainColumn: NTDomain + hosts: + - id: host1 + nameColumn: HostName + dnsDomainColumn: DnsDomain + ips: + - id: ip1 + addressColumn: IpAddress + tactics: + - tactic: CredentialAccess + techniques: + - technique: T1110 diff --git a/Solutions/Windows Security Events/XDR Detections/NRT_SecurityEventLogCleared.yaml b/Solutions/Windows Security Events/XDR Detections/NRT_SecurityEventLogCleared.yaml new file mode 100644 index 00000000000..b47afe282f1 --- /dev/null +++ b/Solutions/Windows Security Events/XDR Detections/NRT_SecurityEventLogCleared.yaml @@ -0,0 +1,133 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: SecurityEvents + dataTypes: + - SecurityEvent +- connectorId: WindowsSecurityEvents + dataTypes: + - SecurityEvent +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: 508cef41-2cd8-4d40-a519-b04826a9085f + path: Analytic Rules/NRT_SecurityEventLogCleared.yaml + version: 1.0.1 + querySha256: ec40f4d8c3a9c6d43056458d5848e2cef5bbfc0d2eb14f33c09438e9ceeb4eef + schedule: + queryFrequency: '' + queryPeriod: '' + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - 'Schedule assessment: source frequency=unknown, lookback=unknown; target frequency=PT1H, native lookback=unknown/unconfigured; + source NRT timing is not preserved by the emitted scheduled frequency. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - Account.NTDomain column `AccountNTDomain` is not produced by the query + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - Unconfirmed generic Account.Name mapping was omitted because another required Host, Mailbox, or IP asset is available + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: + - Account.FullName mismatch is informational because its original value is preserved as customDetails.AccountFullName + from query column `Account`; supplemental details do not restore entity identity, correlation, or alert parity + - Account.Name mismatch is informational because its original value is preserved as customDetails.AccountName from query + column `AccountName`; supplemental details do not restore entity identity, correlation, or alert parity + - Account.NTDomain mismatch is informational because its original value is preserved as customDetails.AccountNTDomain + from query column `AccountNTDomain`; supplemental details do not restore entity identity, correlation, or alert parity + - Host.FullName mismatch is informational because its original value is preserved as customDetails.HostFullName from query + column `Computer`; supplemental details do not restore entity identity, correlation, or alert parity + errors: [] + originalTactics: + - DefenseEvasion + originalTechniques: + - T1070 + reviewScope: + sourceDocumentSha256: ff28d441ec165d2bbde06fa3bb2b36309883762951595a6257c11b415727c586 + targetQuerySha256: 5f1b140ed6c46d00534ef391656c0b1b34cd6aca8ed49d2f83ce473d903a9311 + reviewDecisions: + - reason: 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented + by hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + decision: accepted + sourceDocumentSha256: ff28d441ec165d2bbde06fa3bb2b36309883762951595a6257c11b415727c586 + targetQuerySha256: 5f1b140ed6c46d00534ef391656c0b1b34cd6aca8ed49d2f83ce473d903a9311 + supplementalEntityDetails: + - entityType: Account + entityIndex: 1 + identifier: FullName + sourceColumn: Account + column: Account + status: available + customDetailKey: AccountFullName + - entityType: Account + entityIndex: 1 + identifier: Name + sourceColumn: AccountName + column: AccountName + status: available + customDetailKey: AccountName + - entityType: Account + entityIndex: 1 + identifier: NTDomain + sourceColumn: AccountNTDomain + column: AccountNTDomain + status: available + customDetailKey: AccountNTDomain + - entityType: Host + entityIndex: 2 + identifier: FullName + sourceColumn: Computer + column: Computer + status: available + customDetailKey: HostFullName + acceptedReviewReasons: + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' +properties: + id: xdr-508cef41-2cd8-4d40-a519-b04826a9085f + displayName: NRT Security Event log cleared + status: disabled + queryCondition: + queryText: |- + SecurityEvent + | where EventID == 1102 and EventSourceName == "Microsoft-Windows-Eventlog" + | summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), EventCount = count() by Computer, Account, EventID, Activity + | extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.')) + | extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer) + | extend AccountName = tostring(split(Account, @'\')[1]), AccountNTDomain = tostring(split(Account, @'\')[0]) + schedule: + frequency: PT1H + detectionAction: + alertTemplate: + title: NRT Security Event log cleared + description: |- + 'Checks for event id 1102 which indicates the security event log was cleared. + It uses Event Source Name "Microsoft-Windows-Eventlog" to avoid generating false positives from other sources, like AD FS servers for instance.' + severity: medium + entityMappings: + hosts: + - id: host1 + nameColumn: HostName + dnsDomainColumn: HostNameDomain + tactics: + - tactic: DefenseEvasion + techniques: + - technique: T1070 + customDetails: + AccountFullName: Account + AccountName: AccountName + AccountNTDomain: AccountNTDomain + HostFullName: Computer diff --git a/Solutions/Windows Security Events/XDR Detections/NRT_base64_encoded_pefile.yaml b/Solutions/Windows Security Events/XDR Detections/NRT_base64_encoded_pefile.yaml new file mode 100644 index 00000000000..1bbab1f848b --- /dev/null +++ b/Solutions/Windows Security Events/XDR Detections/NRT_base64_encoded_pefile.yaml @@ -0,0 +1,125 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: SecurityEvents + dataTypes: + - SecurityEvent +- connectorId: WindowsSecurityEvents + dataTypes: + - SecurityEvent +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: c3e5dbaa-a540-408c-8b36-68bdfb3df088 + path: Analytic Rules/NRT_base64_encoded_pefile.yaml + version: 1.0.2 + querySha256: 5837ccc5a17276478625b87130e7ec4f8dc695caffd47e096d32aa839fabdb7d + schedule: + queryFrequency: '' + queryPeriod: '' + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - 'Schedule assessment: source frequency=unknown, lookback=unknown; target frequency=PT1H, native lookback=unknown/unconfigured; + source NRT timing is not preserved by the emitted scheduled frequency. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - Account.FullName value is retained as customDetails.AccountFullName from query column `SubjectAccount`, but its target + output binding requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.AccountFullName column `SubjectAccount` requires runtime output-schema binding verification + - Host.FullName value is retained as customDetails.HostFullName from query column `Computer`, but its target output binding + requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.HostFullName column `Computer` requires runtime output-schema binding verification + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: + - All source MITRE tactics are preserved in source order in authored YAML. V3.1 ARM packaging carries only the first tactic + and its compatible techniques; this classification loss is not validated parity. Direct Graph deployment requires a + single tactic. + errors: [] + originalTactics: + - Execution + - DefenseEvasion + originalTechniques: + - T1059 + - T1027 + - T1140 + reviewScope: + sourceDocumentSha256: 7c4d62933e44e97582ace18c8b9675e542356dd65784902ece13f5c750f5e8a6 + targetQuerySha256: 8c32ee73b40df208dc034291841b1bda04a653207e25d482c95a1b60e5ff2985 + reviewDecisions: + - reason: 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented + by hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + decision: accepted + sourceDocumentSha256: 7c4d62933e44e97582ace18c8b9675e542356dd65784902ece13f5c750f5e8a6 + targetQuerySha256: 8c32ee73b40df208dc034291841b1bda04a653207e25d482c95a1b60e5ff2985 + supplementalEntityDetails: + - entityType: Account + entityIndex: 1 + identifier: FullName + sourceColumn: SubjectAccount + column: SubjectAccount + status: runtime-binding-pending + customDetailKey: AccountFullName + - entityType: Host + entityIndex: 2 + identifier: FullName + sourceColumn: Computer + column: Computer + status: runtime-binding-pending + customDetailKey: HostFullName + acceptedReviewReasons: + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' +properties: + id: xdr-c3e5dbaa-a540-408c-8b36-68bdfb3df088 + displayName: NRT Base64 Encoded Windows Process Command-lines + status: disabled + queryCondition: + queryText: |- + SecurityEvent + | where EventID == 4688 + | where isnotempty(CommandLine) + | where CommandLine contains "TVqQAAMAAAAEAAA" + | extend HostName = tostring(split(Computer, '.', 0)[0]), DnsDomain = tostring(strcat_array(array_slice(split(Computer, '.'), 1, -1), '.')) + schedule: + frequency: PT1H + detectionAction: + alertTemplate: + title: NRT Base64 Encoded Windows Process Command-lines + description: '''This detection identifies instances of a base64 encoded PE file header seen in the process command line + parameter.''' + severity: medium + entityMappings: + accounts: + - id: account1 + nameColumn: SubjectUserName + ntDomainColumn: SubjectDomainName + hosts: + - id: host1 + nameColumn: HostName + dnsDomainColumn: DnsDomain + tactics: + - tactic: Execution + techniques: + - technique: T1059 + - tactic: DefenseEvasion + techniques: + - technique: T1027 + - technique: T1140 + customDetails: + AccountFullName: SubjectAccount + HostFullName: Computer diff --git a/Solutions/Windows Security Events/XDR Detections/NRT_execute_base64_decodedpayload.yaml b/Solutions/Windows Security Events/XDR Detections/NRT_execute_base64_decodedpayload.yaml new file mode 100644 index 00000000000..1928721e73a --- /dev/null +++ b/Solutions/Windows Security Events/XDR Detections/NRT_execute_base64_decodedpayload.yaml @@ -0,0 +1,130 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: SecurityEvents + dataTypes: + - SecurityEvent +- connectorId: WindowsSecurityEvents + dataTypes: + - SecurityEvent +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: 7ad4c32b-d0d2-411c-a0e8-b557afa12fce + path: Analytic Rules/NRT_execute_base64_decodedpayload.yaml + version: 1.0.2 + querySha256: d1cd1e119ecfed278dcdb052dcf81289b74ee5c3b11010119795857a12bfc01b + schedule: + queryFrequency: '' + queryPeriod: '' + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - 'Schedule assessment: source frequency=unknown, lookback=unknown; target frequency=PT1H, native lookback=unknown/unconfigured; + source NRT timing is not preserved by the emitted scheduled frequency. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: + - Account.FullName mismatch is informational because its original value is preserved as customDetails.AccountFullName + from query column `SubjectAccount`; supplemental details do not restore entity identity, correlation, or alert parity + - Host.FullName mismatch is informational because its original value is preserved as customDetails.HostFullName from query + column `Computer`; supplemental details do not restore entity identity, correlation, or alert parity + - All source MITRE tactics are preserved in source order in authored YAML. V3.1 ARM packaging carries only the first tactic + and its compatible techniques; this classification loss is not validated parity. Direct Graph deployment requires a + single tactic. + errors: [] + originalTactics: + - Execution + - DefenseEvasion + originalTechniques: + - T1059 + - T1027 + - T1140 + reviewScope: + sourceDocumentSha256: 19901ada40994e29c83e4261fb31e95e83516963e30469e81ce24cccb9cbf260 + targetQuerySha256: bc581124618c39fe03d5c8238e28e883e6e0a95c3ac2e9be55161f4295f368e1 + reviewDecisions: + - reason: 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented + by hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + decision: accepted + sourceDocumentSha256: 19901ada40994e29c83e4261fb31e95e83516963e30469e81ce24cccb9cbf260 + targetQuerySha256: bc581124618c39fe03d5c8238e28e883e6e0a95c3ac2e9be55161f4295f368e1 + supplementalEntityDetails: + - entityType: Account + entityIndex: 1 + identifier: FullName + sourceColumn: SubjectAccount + column: SubjectAccount + status: available + customDetailKey: AccountFullName + - entityType: Host + entityIndex: 2 + identifier: FullName + sourceColumn: Computer + column: Computer + status: available + customDetailKey: HostFullName + acceptedReviewReasons: + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' +properties: + id: xdr-7ad4c32b-d0d2-411c-a0e8-b557afa12fce + displayName: NRT Process executed from binary hidden in Base64 encoded file + status: disabled + queryCondition: + queryText: |- + SecurityEvent + | where EventID==4688 + | where isnotempty(CommandLine) + | project TimeGenerated, Computer, AccountName = SubjectUserName, AccountNTDomain = SubjectDomainName, FileName = Process, CommandLine, ParentProcessName, SubjectAccount + | extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.')) + | extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer) + | where CommandLine contains ".decode('base64')" + or CommandLine contains "base64 --decode" + or CommandLine contains ".decode64(" + schedule: + frequency: PT1H + detectionAction: + alertTemplate: + title: NRT Process executed from binary hidden in Base64 encoded file + description: |- + 'Encoding malicious software is a technique used to obfuscate files from detection. + The first CommandLine component is looking for Python decoding base64. + The second CommandLine component is looking for Bash/sh command line base64 decoding. + The third one is looking for Ruby decoding base64.' + severity: medium + entityMappings: + accounts: + - id: account1 + nameColumn: AccountName + ntDomainColumn: AccountNTDomain + hosts: + - id: host1 + nameColumn: HostName + dnsDomainColumn: HostNameDomain + tactics: + - tactic: Execution + techniques: + - technique: T1059 + - tactic: DefenseEvasion + techniques: + - technique: T1027 + - technique: T1140 + customDetails: + AccountFullName: SubjectAccount + HostFullName: Computer diff --git a/Solutions/Windows Security Events/XDR Detections/NewEXEdeployedviaDefaultDomainorDefaultDomainControllerPolicies.yaml b/Solutions/Windows Security Events/XDR Detections/NewEXEdeployedviaDefaultDomainorDefaultDomainControllerPolicies.yaml new file mode 100644 index 00000000000..66941ca49ca --- /dev/null +++ b/Solutions/Windows Security Events/XDR Detections/NewEXEdeployedviaDefaultDomainorDefaultDomainControllerPolicies.yaml @@ -0,0 +1,122 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: SecurityEvents + dataTypes: + - SecurityEvent +- connectorId: WindowsSecurityEvents + dataTypes: + - SecurityEvent +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: 05b4bccd-dd12-423d-8de4-5a6fb526bb4f + path: Analytic Rules/NewEXEdeployedviaDefaultDomainorDefaultDomainControllerPolicies.yaml + version: 1.0.2 + querySha256: d7636b33d4a545b02c3bf662b4d8e4df8ca08aced50e6ef136f02fc7798a7153 + schedule: + queryFrequency: 1d + queryPeriod: 14d + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - 'Schedule assessment: source frequency=1d, lookback=14d; target frequency=P1D, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - Host.FullName value is retained as customDetails.HostFullName from query column `Computer`, but its target output binding + requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.HostFullName column `Computer` requires runtime output-schema binding verification + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: + - All source MITRE tactics are preserved in source order in authored YAML. V3.1 ARM packaging carries only the first tactic + and its compatible techniques; this classification loss is not validated parity. Direct Graph deployment requires a + single tactic. + errors: [] + originalTactics: + - Execution + - LateralMovement + originalTechniques: + - T1072 + - T1570 + reviewScope: + sourceDocumentSha256: 290318ce4d5d282e05c8b3ed091664efcf2543a76b0e682b13588eb373be862d + targetQuerySha256: 5b2526f4077aff4631f290370b646e34cecb7cf065d441f355da224c4d264f18 + reviewDecisions: + - reason: 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented + by hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + decision: accepted + sourceDocumentSha256: 290318ce4d5d282e05c8b3ed091664efcf2543a76b0e682b13588eb373be862d + targetQuerySha256: 5b2526f4077aff4631f290370b646e34cecb7cf065d441f355da224c4d264f18 + supplementalEntityDetails: + - entityType: Host + entityIndex: 1 + identifier: FullName + sourceColumn: Computer + column: Computer + status: runtime-binding-pending + customDetailKey: HostFullName + acceptedReviewReasons: + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' +properties: + id: xdr-05b4bccd-dd12-423d-8de4-5a6fb526bb4f + displayName: New EXE deployed via Default Domain or Default Domain Controller Policies + status: disabled + queryCondition: + queryText: |- + let known_processes = ( + SecurityEvent + // If adjusting Query Period or Frequency update these + | where TimeGenerated between(ago(14d)..ago(1d)) + | where EventID == 4688 + | where NewProcessName has_any ("Policies\\{6AC1786C-016F-11D2-945F-00C04fB984F9}", "Policies\\{31B2F340-016D-11D2-945F-00C04FB984F9}") + | summarize by Process); + SecurityEvent + // If adjusting Query Period or Frequency update these + | where TimeGenerated > ago(1d) + | where EventID == 4688 + | where NewProcessName has_any ("Policies\\{6AC1786C-016F-11D2-945F-00C04fB984F9}", "Policies\\{31B2F340-016D-11D2-945F-00C04FB984F9}") + | where Process !in (known_processes) + // This will likely apply to multiple hosts so summarize these data + | summarize FirstSeen=min(TimeGenerated), LastSeen=max(TimeGenerated) by Process, NewProcessName, CommandLine, Computer + | extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.')) + | extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer) + schedule: + frequency: P1D + detectionAction: + alertTemplate: + title: New EXE deployed via Default Domain or Default Domain Controller Policies + description: |- + 'This detection highlights executables deployed to hosts via either the Default Domain or Default Domain Controller Policies. These policies apply to all hosts or Domain Controllers and best practice is that these policies should not be used for deployment of files. + A threat actor may use these policies to deploy files or scripts to all hosts in a domain.' + severity: high + entityMappings: + hosts: + - id: host1 + nameColumn: HostName + dnsDomainColumn: HostNameDomain + tactics: + - tactic: Execution + techniques: + - technique: T1072 + - tactic: LateralMovement + techniques: + - technique: T1072 + - technique: T1570 + customDetails: + HostFullName: Computer diff --git a/Solutions/Windows Security Events/XDR Detections/NonDCActiveDirectoryReplication.yaml b/Solutions/Windows Security Events/XDR Detections/NonDCActiveDirectoryReplication.yaml new file mode 100644 index 00000000000..2549d745834 --- /dev/null +++ b/Solutions/Windows Security Events/XDR Detections/NonDCActiveDirectoryReplication.yaml @@ -0,0 +1,140 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: SecurityEvents + dataTypes: + - SecurityEvent +- connectorId: WindowsSecurityEvents + dataTypes: + - SecurityEvent +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: b9d2eebc-5dcb-4888-8165-900db44443ab + path: Analytic Rules/NonDCActiveDirectoryReplication.yaml + version: 1.0.6 + querySha256: a12e933e83b0e3f09d50d20110bce85fa3fbee5d103ea3fd5f08e73bee760bd1 + schedule: + queryFrequency: 1d + queryPeriod: 7d + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - 'Schedule assessment: source frequency=1d, lookback=7d; target frequency=P1D, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - Account.FullName value is retained as customDetails.AccountFullName from query column `Account`, but its target output + binding requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.AccountFullName column `Account` requires runtime output-schema binding verification + - Host.FullName value is retained as customDetails.HostFullName from query column `Computer`, but its target output binding + requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.HostFullName column `Computer` requires runtime output-schema binding verification + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: [] + errors: [] + originalTactics: + - CredentialAccess + originalTechniques: + - T1003.006 + reviewScope: + sourceDocumentSha256: 137e49172055c6d15a6a67a6b4b5f10a099e547dd645e355764e1eb21a3219a6 + targetQuerySha256: 38f353977f48343053ad3b08d6d1eac454a5571b51a4725e0e92740bb4baef1f + reviewDecisions: + - reason: 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented + by hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + decision: accepted + sourceDocumentSha256: 137e49172055c6d15a6a67a6b4b5f10a099e547dd645e355764e1eb21a3219a6 + targetQuerySha256: 38f353977f48343053ad3b08d6d1eac454a5571b51a4725e0e92740bb4baef1f + supplementalEntityDetails: + - entityType: Account + entityIndex: 1 + identifier: FullName + sourceColumn: Account + column: Account + status: runtime-binding-pending + customDetailKey: AccountFullName + - entityType: Host + entityIndex: 2 + identifier: FullName + sourceColumn: Computer + column: Computer + status: runtime-binding-pending + customDetailKey: HostFullName + acceptedReviewReasons: + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' +properties: + id: xdr-b9d2eebc-5dcb-4888-8165-900db44443ab + displayName: Non Domain Controller Active Directory Replication + status: disabled + queryCondition: + queryText: |- + // Enter a reference list of hostnames for your DC servers + //let DCServersList = dynamic (["DC01.simulandlabs.com","DC02.simulandlabs.com"]); + SecurityEvent + //| where Computer in (DCServersList) + | where EventID == 4662 and ObjectServer == 'DS' + | where AccountType != 'Machine' + | where Properties has '1131f6aa-9c07-11d1-f79f-00c04fc2dcd2' //DS-Replication-Get-Changes + or Properties has '1131f6ad-9c07-11d1-f79f-00c04fc2dcd2' //DS-Replication-Get-Changes-All + or Properties has '89e95b76-444d-4c62-991a-0facbeda640c' //DS-Replication-Get-Changes-In-Filtered-Set + | project TimeGenerated, Account, Activity, Properties, SubjectLogonId, Computer + | join kind=leftouter + ( + SecurityEvent + //| where Computer in (DCServersList) + | where EventID == 4624 and LogonType == 3 + | where AccountType != 'Machine' + | project TargetLogonId, IpAddress, Computer + ) + on $left.SubjectLogonId == $right.TargetLogonId and $left.Computer == $right.Computer + | project-reorder TimeGenerated, Computer, Account, IpAddress + | extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.')) + | extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer) + | extend AccountNTDomain = tostring(split(Account, "\\")[0]), AccountName = tostring(split(Account, "\\")[1]) + schedule: + frequency: P1D + detectionAction: + alertTemplate: + title: Non Domain Controller Active Directory Replication + description: |- + 'This query detects potential attempts by non-computer accounts (non domain controllers) to retrieve/synchronize an active directory object leveraging directory replication services (DRS). + A Domain Controller (computer account) would usually be performing these actions in a domain environment. Another detection rule can be created to cover domain controllers accounts doing at rare times. + A domain user with privileged permissions to use directory replication services is rare.' + severity: high + entityMappings: + accounts: + - id: account1 + nameColumn: AccountName + ntDomainColumn: AccountNTDomain + hosts: + - id: host1 + nameColumn: HostName + ntDomainColumn: HostNameDomain + ips: + - id: ip1 + addressColumn: IpAddress + tactics: + - tactic: CredentialAccess + techniques: + - technique: T1003 + subTechniques: + - T1003.006 + customDetails: + AccountFullName: Account + HostFullName: Computer diff --git a/Solutions/Windows Security Events/XDR Detections/PotentialFodhelperUACBypass.yaml b/Solutions/Windows Security Events/XDR Detections/PotentialFodhelperUACBypass.yaml new file mode 100644 index 00000000000..60338b8c2d4 --- /dev/null +++ b/Solutions/Windows Security Events/XDR Detections/PotentialFodhelperUACBypass.yaml @@ -0,0 +1,144 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: SecurityEvents + dataTypes: + - SecurityEvent +- connectorId: WindowsSecurityEvents + dataTypes: + - SecurityEvent +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: 56f3f35c-3aca-4437-a1fb-b7a84dc4af00 + path: Analytic Rules/PotentialFodhelperUACBypass.yaml + version: 1.0.2 + querySha256: cbd7996eadc691e4bbf8a5dc74acb30a05e49c5540804f248b34376b03549fc0 + schedule: + queryFrequency: 2h + queryPeriod: 2h + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - 'Schedule assessment: source frequency=2h, lookback=2h; target frequency=PT2H, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - Account.NTDomain column `AccountNTDomain` is not produced by the query + - Unconfirmed generic Account.Name mapping was omitted because another required Host, Mailbox, or IP asset is available + - Host.FullName value is retained as customDetails.HostFullName from query column `Computer`, but its target output binding + requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.HostFullName column `Computer` requires runtime output-schema binding verification + - 'Account.FullName value is not preserved: column `TargetAccount` is missing from the final query output. No invalid + customDetails binding was added and KQL was not rewritten' + - Account.Name value is retained as customDetails.AccountName from query column `AccountName`, but its target output binding + requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.AccountName column `AccountName` requires runtime output-schema binding verification + - 'Account.NTDomain value is not preserved: column `AccountNTDomain` is missing from the final query output. No invalid + customDetails binding was added and KQL was not rewritten' + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: [] + errors: [] + originalTactics: + - PrivilegeEscalation + originalTechniques: + - T1548.002 + reviewScope: + sourceDocumentSha256: ef033d20729200bd74f7df56bc28e4c5ce04f7439bc94c39b72b89501c5510cb + targetQuerySha256: 1fc003ba0f24939ec9713dc3d0b6319ddf7ec895a24fa2fee6af928ad0279f4e + reviewDecisions: + - reason: 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented + by hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + decision: accepted + sourceDocumentSha256: ef033d20729200bd74f7df56bc28e4c5ce04f7439bc94c39b72b89501c5510cb + targetQuerySha256: 1fc003ba0f24939ec9713dc3d0b6319ddf7ec895a24fa2fee6af928ad0279f4e + supplementalEntityDetails: + - entityType: Host + entityIndex: 1 + identifier: FullName + sourceColumn: Computer + column: Computer + status: runtime-binding-pending + customDetailKey: HostFullName + - entityType: Account + entityIndex: 2 + identifier: FullName + sourceColumn: TargetAccount + column: TargetAccount + status: not-preserved + reason: missing + - entityType: Account + entityIndex: 2 + identifier: Name + sourceColumn: AccountName + column: AccountName + status: runtime-binding-pending + customDetailKey: AccountName + - entityType: Account + entityIndex: 2 + identifier: NTDomain + sourceColumn: AccountNTDomain + column: AccountNTDomain + status: not-preserved + reason: missing + acceptedReviewReasons: + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' +properties: + id: xdr-56f3f35c-3aca-4437-a1fb-b7a84dc4af00 + displayName: Potential Fodhelper UAC Bypass + status: disabled + queryCondition: + queryText: |- + SecurityEvent + | where EventID == 4657 + | parse ObjectName with "\\REGISTRY\\" KeyPrefix "\\" RegistryKey + | project-reorder RegistryKey + | where RegistryKey has "Software\\Classes\\ms-settings\\shell\\open\\command" + | extend TimeKey = bin(TimeGenerated, 1h) + | join ( + SecurityEvent + | where EventID == 4688 + | where Process =~ "fodhelper.exe" + | where ParentProcessName endswith "cmd.exe" or ParentProcessName endswith "powershell.exe" or ParentProcessName endswith "powershell_ise.exe" + | extend TimeKey = bin(TimeGenerated, 1h)) on TimeKey, Computer + | extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.')) + | extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer) + | extend AccountName = tostring(split(TargetAccount, @'\')[1]), AccountNTDomain = tostring(split(TargetAccount, @'\')[0]) + schedule: + frequency: PT2H + detectionAction: + alertTemplate: + title: Potential Fodhelper UAC Bypass + description: '''This detection looks for the steps required to conduct a UAC bypass using Fodhelper.exe. By default + this detection looks for the setting of the required registry keys and the invoking of the process within 1 hour - + this can be tweaked as required.''' + severity: medium + entityMappings: + hosts: + - id: host1 + nameColumn: HostName + dnsDomainColumn: HostNameDomain + tactics: + - tactic: PrivilegeEscalation + techniques: + - technique: T1548 + subTechniques: + - T1548.002 + customDetails: + HostFullName: Computer + AccountName: AccountName diff --git a/Solutions/Windows Security Events/XDR Detections/Potentialre-namedsdeleteusage.yaml b/Solutions/Windows Security Events/XDR Detections/Potentialre-namedsdeleteusage.yaml new file mode 100644 index 00000000000..a101dd1f08d --- /dev/null +++ b/Solutions/Windows Security Events/XDR Detections/Potentialre-namedsdeleteusage.yaml @@ -0,0 +1,127 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: SecurityEvents + dataTypes: + - SecurityEvent +- connectorId: WindowsSecurityEvents + dataTypes: + - SecurityEvent +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: 720d12c6-a08c-44c4-b18f-2236412d59b0 + path: Analytic Rules/Potentialre-namedsdeleteusage.yaml + version: 1.0.3 + querySha256: c8c8104b92e8fe3c52ea64fb546b73e24ec3c11442ffd8a34df4e8b177daa193 + schedule: + queryFrequency: 1h + queryPeriod: 1h + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - 'Schedule assessment: source frequency=1h, lookback=1h; target frequency=PT1H, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - Account.FullName value is retained as customDetails.AccountFullName from query column `TargetAccount`, but its target + output binding requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.AccountFullName column `TargetAccount` requires runtime output-schema binding verification + - Host.FullName value is retained as customDetails.HostFullName from query column `Computer`, but its target output binding + requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.HostFullName column `Computer` requires runtime output-schema binding verification + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: + - All source MITRE tactics are preserved in source order in authored YAML. V3.1 ARM packaging carries only the first tactic + and its compatible techniques; this classification loss is not validated parity. Direct Graph deployment requires a + single tactic. + errors: [] + originalTactics: + - DefenseEvasion + - Impact + originalTechniques: + - T1485 + - T1036 + reviewScope: + sourceDocumentSha256: bff5913271b36dbf5a0eb427bbbd925f797f70775af22434217297de2a7a1ff3 + targetQuerySha256: a98789165f837a0dafc513ebe04079311aeb9bfe40f243fffcc15c3d105792d7 + reviewDecisions: + - reason: 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented + by hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + decision: accepted + sourceDocumentSha256: bff5913271b36dbf5a0eb427bbbd925f797f70775af22434217297de2a7a1ff3 + targetQuerySha256: a98789165f837a0dafc513ebe04079311aeb9bfe40f243fffcc15c3d105792d7 + supplementalEntityDetails: + - entityType: Account + entityIndex: 1 + identifier: FullName + sourceColumn: TargetAccount + column: TargetAccount + status: runtime-binding-pending + customDetailKey: AccountFullName + - entityType: Host + entityIndex: 2 + identifier: FullName + sourceColumn: Computer + column: Computer + status: runtime-binding-pending + customDetailKey: HostFullName + acceptedReviewReasons: + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' +properties: + id: xdr-720d12c6-a08c-44c4-b18f-2236412d59b0 + displayName: Potential re-named sdelete usage + status: disabled + queryCondition: + queryText: |- + SecurityEvent + | where EventID == 4688 + | where Process !~ "sdelete.exe" + | where CommandLine has_all ("accepteula", "-r", "-s", "-q", "c:/") + | where CommandLine !has ("sdelete") + | extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.')) + | extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer) + | extend AccountName = tostring(split(TargetAccount, @'\')[1]), AccountNTDomain = tostring(split(TargetAccount, @'\')[0]) + schedule: + frequency: PT1H + detectionAction: + alertTemplate: + title: Potential re-named sdelete usage + description: |- + 'This detection looks for command line parameters associated with the use of Sysinternals sdelete (https://docs.microsoft.com/sysinternals/downloads/sdelete) to delete multiple files on a host's C drive. + A threat actor may re-name the tool to avoid detection and then use it for destructive attacks on a host.' + severity: low + entityMappings: + accounts: + - id: account1 + nameColumn: AccountName + ntDomainColumn: AccountNTDomain + hosts: + - id: host1 + nameColumn: HostName + dnsDomainColumn: HostNameDomain + tactics: + - tactic: DefenseEvasion + techniques: + - technique: T1036 + - tactic: Impact + techniques: + - technique: T1485 + customDetails: + AccountFullName: TargetAccount + HostFullName: Computer diff --git a/Solutions/Windows Security Events/XDR Detections/ScheduleTaskHide.yaml b/Solutions/Windows Security Events/XDR Detections/ScheduleTaskHide.yaml new file mode 100644 index 00000000000..1ab5cef1177 --- /dev/null +++ b/Solutions/Windows Security Events/XDR Detections/ScheduleTaskHide.yaml @@ -0,0 +1,126 @@ +schemaVersion: 1.0.0 +version: 3.1.2 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: SecurityEvents + dataTypes: + - SecurityEvent +- connectorId: WindowsSecurityEvents + dataTypes: + - SecurityEvent +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: 6dd2629c-534b-4275-8201-d7968b4fa77e + path: Analytic Rules/ScheduleTaskHide.yaml + version: 3.1.2 + querySha256: 538f8550cc1c1938f1969380b008486687ca2bf313a26cc7c5ff91f86f19c5d2 + schedule: + queryFrequency: 1d + queryPeriod: 1d + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - 'Schedule assessment: source frequency=1d, lookback=1d; target frequency=P1D, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - Account.FullName value is retained as customDetails.AccountFullName from query column `TargetAccount`, but its target + output binding requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.AccountFullName column `TargetAccount` requires runtime output-schema binding verification + - Host.FullName value is retained as customDetails.HostFullName from query column `Computer`, but its target output binding + requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.HostFullName column `Computer` requires runtime output-schema binding verification + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: [] + errors: [] + originalTactics: + - DefenseEvasion + originalTechniques: + - T1562 + reviewScope: + sourceDocumentSha256: 718b4dac9799e5e0661af82ea383df0af8c33fc5fb79edb3e3609bf251b6c46b + targetQuerySha256: fd034a8da92c00737b0edb8874ca883720de2ce4e177f9be1a50ec9c9691ef88 + reviewDecisions: + - reason: 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented + by hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + decision: accepted + sourceDocumentSha256: 718b4dac9799e5e0661af82ea383df0af8c33fc5fb79edb3e3609bf251b6c46b + targetQuerySha256: fd034a8da92c00737b0edb8874ca883720de2ce4e177f9be1a50ec9c9691ef88 + supplementalEntityDetails: + - entityType: Account + entityIndex: 1 + identifier: FullName + sourceColumn: TargetAccount + column: TargetAccount + status: runtime-binding-pending + customDetailKey: AccountFullName + - entityType: Host + entityIndex: 2 + identifier: FullName + sourceColumn: Computer + column: Computer + status: runtime-binding-pending + customDetailKey: HostFullName + acceptedReviewReasons: + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' +properties: + id: xdr-6dd2629c-534b-4275-8201-d7968b4fa77e + displayName: Scheduled Task Hide + status: disabled + queryCondition: + queryText: |- + SecurityEvent + | where EventID == 4657 + | extend EventData = parse_xml(EventData).EventData.Data + | mv-expand bagexpansion=array EventData + | evaluate bag_unpack(EventData) + | extend Key = tostring(column_ifexists('@Name', "")), Value = column_ifexists('#text', "") + | evaluate pivot(Key, any(Value), TimeGenerated, TargetAccount, Computer, EventSourceName, Channel, Task, Level, EventID, Activity, TargetLogonId, SourceComputerId, EventOriginId, Type, _ResourceId, TenantId, SourceSystem, ManagementGroupName, IpAddress, Account) + | extend ObjectName = column_ifexists('ObjectName', ""), OperationType = column_ifexists('OperationType', ""), ObjectValueName = column_ifexists('ObjectValueName', "") + | where ObjectName has 'Schedule\\TaskCache\\Tree' and ObjectValueName == "SD" and OperationType == "%%1906" // %%1906 - Registry value deleted + | extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.')) + | extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer) + | extend AccountName = tostring(split(TargetAccount, @'\')[1]), AccountNTDomain = tostring(split(TargetAccount, @'\')[0]) + | extend timestamp = TimeGenerated + schedule: + frequency: P1D + detectionAction: + alertTemplate: + title: Scheduled Task Hide + description: |- + 'Identifies malware hiding scheduled tasks by deleting the SD (Security Descriptor) value, making tasks disappear from schtasks /query and Task Scheduler. + Enable registry auditing policy and auditing on HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree. + Reference: https://www.microsoft.com/en-us/security/blog/2022/04/12/tarrask-malware-uses-scheduled-tasks-for-defense-evasion/ + Reference: https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/auditing/audit-registry' + severity: high + entityMappings: + accounts: + - id: account1 + nameColumn: AccountName + ntDomainColumn: AccountNTDomain + hosts: + - id: host1 + nameColumn: HostName + dnsDomainColumn: HostNameDomain + tactics: + - tactic: DefenseEvasion + techniques: + - technique: T1562 + customDetails: + AccountFullName: TargetAccount + HostFullName: Computer diff --git a/Solutions/Windows Security Events/XDR Detections/SdeletedeployedviaGPOandrunrecursively.yaml b/Solutions/Windows Security Events/XDR Detections/SdeletedeployedviaGPOandrunrecursively.yaml new file mode 100644 index 00000000000..471a5aaf186 --- /dev/null +++ b/Solutions/Windows Security Events/XDR Detections/SdeletedeployedviaGPOandrunrecursively.yaml @@ -0,0 +1,143 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: SecurityEvents + dataTypes: + - SecurityEvent +- connectorId: WindowsSecurityEvents + dataTypes: + - SecurityEvent +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: d9f28fdf-abc8-4f1a-a7e7-1aaec87a2fc5 + path: Analytic Rules/SdeletedeployedviaGPOandrunrecursively.yaml + version: 1.0.2 + querySha256: 8002598ba3d8277ad09f5a08c0ae2d03c09bc02fa49253518cf330e0e82348ea + schedule: + queryFrequency: 1d + queryPeriod: 1d + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - 'Schedule assessment: source frequency=1d, lookback=1d; target frequency=P1D, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - Account.NTDomain column `AccountNTDomain` is not produced by the query + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - Unconfirmed generic Account.Name mapping was omitted because another required Host, Mailbox, or IP asset is available + - 'Account.FullName value is not preserved: column `TargetAccount` is missing from the final query output. No invalid + customDetails binding was added and KQL was not rewritten' + - Account.Name value is retained as customDetails.AccountName from query column `AccountName`, but its target output binding + requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.AccountName column `AccountName` requires runtime output-schema binding verification + - 'Account.NTDomain value is not preserved: column `AccountNTDomain` is missing from the final query output. No invalid + customDetails binding was added and KQL was not rewritten' + - Host.FullName value is retained as customDetails.HostFullName from query column `Computer`, but its target output binding + requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.HostFullName column `Computer` requires runtime output-schema binding verification + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: [] + errors: [] + originalTactics: + - Impact + originalTechniques: + - T1485 + reviewScope: + sourceDocumentSha256: 7a3f88263546dab2ec03e210fb54bae2a6f4e9b60d74c08cfb7a776ebbf20b6e + targetQuerySha256: e15f156cdcd33df0f39708ca52c925c96bc5e1fd422b5ee162e314ce870320b1 + reviewDecisions: + - reason: 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented + by hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + decision: accepted + sourceDocumentSha256: 7a3f88263546dab2ec03e210fb54bae2a6f4e9b60d74c08cfb7a776ebbf20b6e + targetQuerySha256: e15f156cdcd33df0f39708ca52c925c96bc5e1fd422b5ee162e314ce870320b1 + supplementalEntityDetails: + - entityType: Account + entityIndex: 1 + identifier: FullName + sourceColumn: TargetAccount + column: TargetAccount + status: not-preserved + reason: missing + - entityType: Account + entityIndex: 1 + identifier: Name + sourceColumn: AccountName + column: AccountName + status: runtime-binding-pending + customDetailKey: AccountName + - entityType: Account + entityIndex: 1 + identifier: NTDomain + sourceColumn: AccountNTDomain + column: AccountNTDomain + status: not-preserved + reason: missing + - entityType: Host + entityIndex: 2 + identifier: FullName + sourceColumn: Computer + column: Computer + status: runtime-binding-pending + customDetailKey: HostFullName + acceptedReviewReasons: + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' +properties: + id: xdr-d9f28fdf-abc8-4f1a-a7e7-1aaec87a2fc5 + displayName: Sdelete deployed via GPO and run recursively + status: disabled + queryCondition: + queryText: |- + SecurityEvent + | where EventID == 4688 + | where Process =~ "svchost.exe" + | where CommandLine has "-k GPSvcGroup" or CommandLine has "-s gpsvc" + | extend timekey = bin(TimeGenerated, 1m) + | project timekey, NewProcessId, Computer + | join kind=inner (SecurityEvent + | where EventID == 4688 + | where Process =~ "sdelete.exe" or CommandLine has "sdelete" + | where ParentProcessName endswith "svchost.exe" + | where CommandLine has_all ("-s", "-r") + | extend newProcess = Process + | extend timekey = bin(TimeGenerated, 1m) + ) on $left.NewProcessId == $right.ProcessId, timekey, Computer + | extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.')) + | extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer) + | extend AccountName = tostring(split(TargetAccount, @'\')[1]), AccountNTDomain = tostring(split(TargetAccount, @'\')[0]) + schedule: + frequency: P1D + detectionAction: + alertTemplate: + title: Sdelete deployed via GPO and run recursively + description: '''This query looks for the Sdelete process being run recursively after being deployed to a host via GPO. + Attackers could use this technique to deploy Sdelete to multiple host and delete data on them.''' + severity: medium + entityMappings: + hosts: + - id: host1 + nameColumn: HostName + dnsDomainColumn: HostNameDomain + tactics: + - tactic: Impact + techniques: + - technique: T1485 + customDetails: + AccountName: AccountName + HostFullName: Computer diff --git a/Solutions/Windows Security Events/XDR Detections/StartStopHealthService.yaml b/Solutions/Windows Security Events/XDR Detections/StartStopHealthService.yaml new file mode 100644 index 00000000000..5364c87c5f7 --- /dev/null +++ b/Solutions/Windows Security Events/XDR Detections/StartStopHealthService.yaml @@ -0,0 +1,154 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: SecurityEvents + dataTypes: + - SecurityEvent +- connectorId: WindowsSecurityEvents + dataTypes: + - SecurityEvent +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: 2bc7b4ae-eeaa-4538-ba15-ef298ec1ffae + path: Analytic Rules/StartStopHealthService.yaml + version: 1.0.2 + querySha256: 6c2275312bd7c7f2c883241459d97d17979c6a4c083bb8a0b6172e3045ae81b4 + schedule: + queryFrequency: 1d + queryPeriod: 1d + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - 'Schedule assessment: source frequency=1d, lookback=1d; target frequency=P1D, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - Account.NTDomain column `AccountNTDomain` is not produced by the query + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - Unconfirmed generic Account.Name mapping was omitted because another required Host, Mailbox, or IP asset is available + - Account.FullName value is retained as customDetails.AccountFullName from query column `TargetAccount`, but its target + output binding requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.AccountFullName column `TargetAccount` requires runtime output-schema binding verification + - Account.Name value is retained as customDetails.AccountName from query column `AccountName`, but its target output binding + requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.AccountName column `AccountName` requires runtime output-schema binding verification + - 'Account.NTDomain value is not preserved: column `AccountNTDomain` is missing from the final query output. No invalid + customDetails binding was added and KQL was not rewritten' + - Host.FullName value is retained as customDetails.HostFullName from query column `Computer`, but its target output binding + requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.HostFullName column `Computer` requires runtime output-schema binding verification + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: [] + errors: [] + originalTactics: + - DefenseEvasion + originalTechniques: + - T1562.001 + reviewScope: + sourceDocumentSha256: 32953c754d9a633d7488694c2d42beda60bc074752a3f4f809916782e93b9606 + targetQuerySha256: 2648ce525362f67937df1213e01ffe93bcc9c768785b63c5470630d8b97673c2 + reviewDecisions: + - reason: 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented + by hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + decision: accepted + sourceDocumentSha256: 32953c754d9a633d7488694c2d42beda60bc074752a3f4f809916782e93b9606 + targetQuerySha256: 2648ce525362f67937df1213e01ffe93bcc9c768785b63c5470630d8b97673c2 + supplementalEntityDetails: + - entityType: Account + entityIndex: 1 + identifier: FullName + sourceColumn: TargetAccount + column: TargetAccount + status: runtime-binding-pending + customDetailKey: AccountFullName + - entityType: Account + entityIndex: 1 + identifier: Name + sourceColumn: AccountName + column: AccountName + status: runtime-binding-pending + customDetailKey: AccountName + - entityType: Account + entityIndex: 1 + identifier: NTDomain + sourceColumn: AccountNTDomain + column: AccountNTDomain + status: not-preserved + reason: missing + - entityType: Host + entityIndex: 2 + identifier: FullName + sourceColumn: Computer + column: Computer + status: runtime-binding-pending + customDetailKey: HostFullName + acceptedReviewReasons: + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' +properties: + id: xdr-2bc7b4ae-eeaa-4538-ba15-ef298ec1ffae + displayName: Starting or Stopping HealthService to Avoid Detection + status: disabled + queryCondition: + queryText: |- + SecurityEvent + | where EventID == 4656 + | extend EventData = parse_xml(EventData).EventData.Data + | mv-expand bagexpansion=array EventData + | evaluate bag_unpack(EventData) + | extend Key = tostring(column_ifexists('@Name', "")), Value = column_ifexists('#text', "") + | evaluate pivot(Key, any(Value), TimeGenerated, TargetAccount, Computer, EventSourceName, Channel, Task, Level, EventID, Activity, TargetLogonId, SourceComputerId, EventOriginId, Type, _ResourceId, TenantId, SourceSystem, ManagementGroupName, IpAddress, Account) + | extend ObjectServer = column_ifexists('ObjectServer', ""), ObjectType = column_ifexists('ObjectType', ""), ObjectName = column_ifexists('ObjectName', "") + | where isnotempty(ObjectServer) and isnotempty(ObjectType) and isnotempty(ObjectName) + | where ObjectServer =~ "SC Manager" and ObjectType =~ "SERVICE OBJECT" and ObjectName =~ "HealthService" + // Comment out the join below if the SACL only audits users that are part of the Network logon users, i.e. with user/group target pointing to "NU." + | join kind=leftouter ( + SecurityEvent + | where EventID == 4624 + ) on TargetLogonId + | project TimeGenerated, Computer, Account, TargetAccount, IpAddress,TargetLogonId, ObjectServer, ObjectType, ObjectName + | extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.')) + | extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer) + | extend AccountName = tostring(split(TargetAccount, @'\')[1]), AccountNTDomain = tostring(split(TargetAccount, @'\')[0]) + | extend timestamp = TimeGenerated + schedule: + frequency: P1D + detectionAction: + alertTemplate: + title: Starting or Stopping HealthService to Avoid Detection + description: |- + 'This query detects events where an actor is stopping or starting HealthService to disable telemetry collection/detection from the agent. + The query requires a SACL to audit for access request to the service.' + severity: medium + entityMappings: + hosts: + - id: host1 + nameColumn: HostName + dnsDomainColumn: HostNameDomain + ips: + - id: ip1 + addressColumn: IpAddress + tactics: + - tactic: DefenseEvasion + techniques: + - technique: T1562 + subTechniques: + - T1562.001 + customDetails: + AccountFullName: TargetAccount + AccountName: AccountName + HostFullName: Computer diff --git a/Solutions/Windows Security Events/XDR Detections/TimeSeriesAnomaly-ProcessExecutions.yaml b/Solutions/Windows Security Events/XDR Detections/TimeSeriesAnomaly-ProcessExecutions.yaml new file mode 100644 index 00000000000..28d88769bef --- /dev/null +++ b/Solutions/Windows Security Events/XDR Detections/TimeSeriesAnomaly-ProcessExecutions.yaml @@ -0,0 +1,145 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: SecurityEvents + dataTypes: + - SecurityEvent +- connectorId: WindowsSecurityEvents + dataTypes: + - SecurityEvent +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: 2c55fe7a-b06f-4029-a5b9-c54a2320d7b8 + path: Analytic Rules/TimeSeriesAnomaly-ProcessExecutions.yaml + version: 1.0.6 + querySha256: 95f38cf051193e54415451342cbe7ca9c3ccaba85316271c1480a29ff049ca3a + schedule: + queryFrequency: 1d + queryPeriod: 14d + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - 'Schedule assessment: source frequency=1d, lookback=14d; target frequency=P1D, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - Account.FullName value is retained as customDetails.AccountFullName from query column `Account`, but its target output + binding requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.AccountFullName column `Account` requires runtime output-schema binding verification + - Host.FullName value is retained as customDetails.HostFullName from query column `Computer`, but its target output binding + requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.HostFullName column `Computer` requires runtime output-schema binding verification + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: [] + errors: [] + originalTactics: + - Execution + originalTechniques: + - T1059 + reviewScope: + sourceDocumentSha256: a8b96af40ebf026f9d3f0b1d7853de036309c4688ee3a0da2b64426665b2d87d + targetQuerySha256: d6d5ca79cc1c4c9f6d978f92c405e7899e955fb5d08c54a7c1a283a53d67a2ad + reviewDecisions: + - reason: 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented + by hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + decision: accepted + sourceDocumentSha256: a8b96af40ebf026f9d3f0b1d7853de036309c4688ee3a0da2b64426665b2d87d + targetQuerySha256: d6d5ca79cc1c4c9f6d978f92c405e7899e955fb5d08c54a7c1a283a53d67a2ad + supplementalEntityDetails: + - entityType: Account + entityIndex: 1 + identifier: FullName + sourceColumn: Account + column: Account + status: runtime-binding-pending + customDetailKey: AccountFullName + - entityType: Host + entityIndex: 2 + identifier: FullName + sourceColumn: Computer + column: Computer + status: runtime-binding-pending + customDetailKey: HostFullName + acceptedReviewReasons: + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' +properties: + id: xdr-2c55fe7a-b06f-4029-a5b9-c54a2320d7b8 + displayName: Process Execution Frequency Anomaly + status: disabled + queryCondition: + queryText: |- + let starttime = 14d; + let endtime = 1d; + let timeframe = 1h; + let TotalEventsThreshold = 5; + // Configure the list with sensitive process names + let ExeList = dynamic(["powershell.exe","cmd.exe","wmic.exe","psexec.exe","cacls.exe","rundll32.exe"]); + let TimeSeriesData = + SecurityEvent + | where EventID == 4688 | extend Process = tolower(Process) + | where TimeGenerated between (startofday(ago(starttime))..startofday(ago(endtime))) + | where Process in~ (ExeList) + | project TimeGenerated, Computer, AccountType, Account, Process + | make-series Total=count() on TimeGenerated from startofday(ago(starttime)) to startofday(ago(endtime)) step timeframe by Process; + let TimeSeriesAlerts = materialize(TimeSeriesData + | extend (anomalies, score, baseline) = series_decompose_anomalies(Total, 1.5, -1, 'linefit') + | mv-expand Total to typeof(double), TimeGenerated to typeof(datetime), anomalies to typeof(double), score to typeof(double), baseline to typeof(long) + | where anomalies > 0 + | project Process, TimeGenerated, Total, baseline, anomalies, score + | where Total > TotalEventsThreshold); + let AnomalyHours = materialize(TimeSeriesAlerts | where TimeGenerated > ago(2d) | project TimeGenerated); + TimeSeriesAlerts + | where TimeGenerated > ago(2d) + | join ( + SecurityEvent + | where TimeGenerated between (startofday(ago(starttime))..startofday(ago(endtime))) + | extend DateHour = bin(TimeGenerated, 1h) // create a new column and round to hour + | where DateHour in ((AnomalyHours)) //filter the dataset to only selected anomaly hours + | where EventID == 4688 | extend Process = tolower(Process) + | summarize CommandlineCount = count() by bin(TimeGenerated, 1h), Process, CommandLine, Computer, Account + ) on Process, TimeGenerated + | project AnomalyHour = TimeGenerated, Computer, Account, Process, CommandLine, CommandlineCount, Total, baseline, anomalies, score + | extend timestamp = AnomalyHour, NTDomain = split(Account, '\\', 0)[0], Name = split(Account, '\\', 1)[0], HostName = tostring(split(Computer, '.', 0)[0]), DnsDomain = tostring(strcat_array(array_slice(split(Computer, '.'), 1, -1), '.')) + schedule: + frequency: P1D + detectionAction: + alertTemplate: + title: Process Execution Frequency Anomaly + description: |- + 'This detection identifies anomalous spike in frequency of executions of sensitive processes which are often leveraged as attack vectors. + The query leverages KQL's built-in anomaly detection algorithms to find large deviations from baseline patterns. + Sudden increases in execution frequency of sensitive processes should be further investigated for malicious activity. + Tune the values from 1.5 to 3 in series_decompose_anomalies for further outliers or based on custom threshold values for score.' + severity: medium + entityMappings: + accounts: + - id: account1 + nameColumn: Name + ntDomainColumn: NTDomain + hosts: + - id: host1 + nameColumn: HostName + dnsDomainColumn: DnsDomain + tactics: + - tactic: Execution + techniques: + - technique: T1059 + customDetails: + AccountFullName: Account + HostFullName: Computer diff --git a/Solutions/Windows Security Events/XDR Detections/WMI-Abuse.yaml b/Solutions/Windows Security Events/XDR Detections/WMI-Abuse.yaml new file mode 100644 index 00000000000..78d89ce6e19 --- /dev/null +++ b/Solutions/Windows Security Events/XDR Detections/WMI-Abuse.yaml @@ -0,0 +1,203 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: MicrosoftThreatProtection + dataTypes: + - DeviceProcessEvents +- connectorId: SecurityEvents + dataTypes: + - SecurityEvent +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: 3c8e5f0b-1d4a-4b69-9c2e-7f0d3a5e8b1f + path: Analytic Rules/WMI-Abuse.yaml + version: 1.0.5 + querySha256: 4700d6b785004488a21e368c61a745c0b1d398753522b7867a0c9772daad0cf8 + schedule: + queryFrequency: 1h + queryPeriod: 1h + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - query mixes native Defender and Sentinel workload tables; time columns were preserved and require runtime validation + - 'Schedule assessment: source frequency=1h, lookback=1h; target frequency=PT1H, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - 'Best-effort entity mapping requires review: source Host.FullName column `HostName` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - Host.FullName value is retained as customDetails.HostFullName from query column `HostName`, but its target output binding + requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.HostFullName column `HostName` requires runtime output-schema binding verification + - Process.CommandLine value is retained as customDetails.ProcessCommandLine from query column `ChildCmdLine`, but its + target output binding requires runtime-schema verification; custom details do not restore entity identity or correlation + - Supplemental customDetails.ProcessCommandLine column `ChildCmdLine` requires runtime output-schema binding verification + - Custom-detail values must remain within the documented combined 4 KB per-alert limit; runtime values are unverified + and the service drops all custom details if exceeded + informational: + - All source MITRE tactics are preserved in source order in authored YAML. V3.1 ARM packaging carries only the first tactic + and its compatible techniques; this classification loss is not validated parity. Direct Graph deployment requires a + single tactic. + errors: [] + originalTactics: + - Execution + - LateralMovement + - Persistence + originalTechniques: + - T1047 + - T1021.006 + - T1059.001 + - T1059.003 + - T1059.005 + reviewScope: + sourceDocumentSha256: e7ad3f9fd6bb88db5b9ead6eaaa9b7c5d9a75c77b12564aa54753fd599319b8d + targetQuerySha256: b55592536bd8d4bc7adb8a824059bba6514c1328652dea07d625e93d239b1f0f + reviewDecisions: + - reason: query mixes native Defender and Sentinel workload tables; time columns were preserved and require runtime validation + decision: accepted + sourceDocumentSha256: e7ad3f9fd6bb88db5b9ead6eaaa9b7c5d9a75c77b12564aa54753fd599319b8d + targetQuerySha256: b55592536bd8d4bc7adb8a824059bba6514c1328652dea07d625e93d239b1f0f + - reason: Original Sentinel lookback is shorter than the native XDR service window, but source and target table inputs + cannot be proven equivalent + decision: accepted + sourceDocumentSha256: e7ad3f9fd6bb88db5b9ead6eaaa9b7c5d9a75c77b12564aa54753fd599319b8d + targetQuerySha256: b55592536bd8d4bc7adb8a824059bba6514c1328652dea07d625e93d239b1f0f + - reason: 'Best-effort entity mapping requires review: source Host.FullName column `HostName` is provisionally represented + by hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + decision: accepted + sourceDocumentSha256: e7ad3f9fd6bb88db5b9ead6eaaa9b7c5d9a75c77b12564aa54753fd599319b8d + targetQuerySha256: b55592536bd8d4bc7adb8a824059bba6514c1328652dea07d625e93d239b1f0f + supplementalEntityDetails: + - entityType: Host + entityIndex: 1 + identifier: FullName + sourceColumn: HostName + column: HostName + status: runtime-binding-pending + customDetailKey: HostFullName + - entityType: Process + entityIndex: 3 + identifier: CommandLine + sourceColumn: ChildCmdLine + column: ChildCmdLine + status: runtime-binding-pending + customDetailKey: ProcessCommandLine + acceptedReviewReasons: + - 'Best-effort entity mapping requires review: source Host.FullName column `HostName` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - Original Sentinel lookback is shorter than the native XDR service window, but source and target table inputs cannot + be proven equivalent + - query mixes native Defender and Sentinel workload tables; time columns were preserved and require runtime validation +properties: + id: xdr-3c8e5f0b-1d4a-4b69-9c2e-7f0d3a5e8b1f + displayName: WMI Spawning Suspicious Child Process (Living off the Land) + status: disabled + queryCondition: + queryText: |- + let Lookback = 1h; + let SuspiciousChildProcesses = dynamic([ + "powershell.exe", "pwsh.exe", "cmd.exe", "cscript.exe", "wscript.exe", + "mshta.exe", "certutil.exe", "bitsadmin.exe", "regsvr32.exe", + "rundll32.exe", "msiexec.exe", "installutil.exe", "cmstp.exe", + "msbuild.exe", "wmic.exe", "net.exe", "net1.exe", "nltest.exe", + "whoami.exe", "ipconfig.exe", "tasklist.exe", "schtasks.exe", + "at.exe", "sc.exe", "reg.exe" + ]); + let AllowlistedCmdPatterns = dynamic([ + "ccmexec", "SMSAgent", "MOMAgent", "nessus", "qualys" + ]); + let NetworkIndicators = dynamic([ + "http://", "https://", "ftp://", "Net.WebClient", + "DownloadString", "IEX", "Invoke-Expression", "/transfer", "-urlcache" + ]); + let CredentialIndicators = dynamic([ + "lsass", "mimikatz", "sekurlsa", "dump", "sam", "ntds" + ]); + let MDE_Results = + DeviceProcessEvents + | where Timestamp >= ago(Lookback) + | where InitiatingProcessFileName =~ "WmiPrvSE.exe" + | where FileName in~ (SuspiciousChildProcesses) + | where not(ProcessCommandLine has_any (AllowlistedCmdPatterns)) + | extend + ChildProcess = FileName, + ChildCmdLine = ProcessCommandLine, + AccountName = InitiatingProcessAccountName, + AccountDomain = InitiatingProcessAccountDomain, + HostName = DeviceName, + EventTime = Timestamp, + NetworkActivity = ProcessCommandLine has_any (NetworkIndicators), + CredentialActivity = ProcessCommandLine has_any (CredentialIndicators) + | project EventTime, HostName, AccountName, AccountDomain, ChildProcess, + ChildCmdLine, NetworkActivity, CredentialActivity; + let SecEvent_Results = + SecurityEvent + | where TimeGenerated >= ago(Lookback) + | where EventID == 4688 + | where ParentProcessName endswith "\\WmiPrvSE.exe" + | extend ChildProcess = tostring(split(NewProcessName, "\\")[-1]) + | where ChildProcess in~ (SuspiciousChildProcesses) + | where not(CommandLine has_any (AllowlistedCmdPatterns)) + | extend + ChildCmdLine = CommandLine, + AccountName = SubjectUserName, + AccountDomain = SubjectDomainName, + HostName = Computer, + EventTime = TimeGenerated, + NetworkActivity = CommandLine has_any (NetworkIndicators), + CredentialActivity = CommandLine has_any (CredentialIndicators) + | project EventTime, HostName, AccountName, AccountDomain, ChildProcess, + ChildCmdLine, NetworkActivity, CredentialActivity; + union MDE_Results, SecEvent_Results + | extend RiskScore = iif(CredentialActivity == true, 3, iif(NetworkActivity == true, 2, 1)) + | sort by RiskScore desc, EventTime desc + schedule: + frequency: PT1H + detectionAction: + alertTemplate: + title: WMI Spawning Suspicious Child Process (Living off the Land) + description: |- + Detects WmiPrvSE.exe (the WMI Provider Host) spawning high-risk processes + such as PowerShell, cmd.exe, cscript, or other LOLBins. + WMI requires no external tools, generates minimal disk artifacts, and can + execute code on remote systems over DCOM/RPC while bypassing many controls. + Tune AllowlistedCmdPatterns for known-safe management tools such as SCCM. + severity: high + entityMappings: + hosts: + - id: host1 + nameColumn: HostName + accounts: + - id: account1 + nameColumn: AccountName + ntDomainColumn: AccountDomain + tactics: + - tactic: Execution + techniques: + - technique: T1047 + - technique: T1059 + subTechniques: + - T1059.001 + - T1059.003 + - T1059.005 + - tactic: LateralMovement + techniques: + - technique: T1021 + subTechniques: + - T1021.006 + - tactic: Persistence + customDetails: + HostFullName: HostName + ProcessCommandLine: ChildCmdLine diff --git a/Solutions/Windows Security Events/XDR Detections/password_not_set.yaml b/Solutions/Windows Security Events/XDR Detections/password_not_set.yaml new file mode 100644 index 00000000000..e0447cfb993 --- /dev/null +++ b/Solutions/Windows Security Events/XDR Detections/password_not_set.yaml @@ -0,0 +1,134 @@ +schemaVersion: 1.0.0 +version: 3.1.0 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: SecurityEvents + dataTypes: + - SecurityEvent +- connectorId: WindowsSecurityEvents + dataTypes: + - SecurityEvent +contentProvenance: + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: 62085097-d113-459f-9ea7-30216f2ee6af + path: Analytic Rules/password_not_set.yaml + version: 1.0.4 + querySha256: 225febe2e822e6a35ab6ad2d77b2387e7a2beecd26b256c1b2736687a07e4899 + schedule: + queryFrequency: 1d + queryPeriod: 3d + conversion: + tool: sentinel-to-xdr-migration + version: 0.1.0 + status: converted + reviewRequired: false + reviewReasons: [] + requiredWorkloads: + - sentinel + warnings: + - 'Schedule assessment: source frequency=1d, lookback=3d; target frequency=P1D, native lookback=unknown/unconfigured; + mixed, Sentinel-only, or unknown query surface; no custom lookback is configured in the payload. See https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules#lookback' + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' + - Account.FullName output column `TargetAccount` cannot be proven after a destructive projection; no supplemental customDetails + binding was added and KQL was not rewritten. Runtime output-schema verification is required + - Host.FullName output column `Computer` cannot be proven after a destructive projection; no supplemental customDetails + binding was added and KQL was not rewritten. Runtime output-schema verification is required + informational: [] + errors: [] + originalTactics: + - Persistence + originalTechniques: + - T1098 + reviewScope: + sourceDocumentSha256: dc854c4da793a9c02c7eefb45b9f9c0a041d5c658b141c155ae9c6aceec64ce7 + targetQuerySha256: 96546114a6a06fd7b591c371a9ce0aee497d65615c6d74ef3befbe790448c5a4 + reviewDecisions: + - reason: 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented + by hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also + retained in customDetails when the query output binding is available; this assumption does not prove entity parity' + decision: accepted + sourceDocumentSha256: dc854c4da793a9c02c7eefb45b9f9c0a041d5c658b141c155ae9c6aceec64ce7 + targetQuerySha256: 96546114a6a06fd7b591c371a9ce0aee497d65615c6d74ef3befbe790448c5a4 + supplementalEntityDetails: + - entityType: Account + entityIndex: 1 + identifier: FullName + sourceColumn: TargetAccount + column: TargetAccount + status: unproven-destructive-projection + reason: unproven-destructive-projection + - entityType: Host + entityIndex: 3 + identifier: FullName + sourceColumn: Computer + column: Computer + status: unproven-destructive-projection + reason: unproven-destructive-projection + acceptedReviewReasons: + - 'Best-effort entity mapping requires review: source Host.FullName column `Computer` is provisionally represented by + hosts.nameColumn `HostName`; confirm that this column is the intended host identifier. The original value is also retained + in customDetails when the query output binding is available; this assumption does not prove entity parity' +properties: + id: xdr-62085097-d113-459f-9ea7-30216f2ee6af + displayName: AD user enabled and password not set within 48 hours + status: disabled + queryCondition: + queryText: |- + let starttime = 3d; + let SecEvents = materialize ( SecurityEvent | where TimeGenerated >= ago(starttime) + | where EventID in (4722,4723) | where TargetUserName !endswith "$" + | project TimeGenerated, EventID, Activity, Computer, TargetAccount, TargetSid, SubjectAccount, SubjectUserSid); + let userEnable = SecEvents + | extend EventID4722Time = TimeGenerated + // 4722: User Account Enabled + | where EventID == 4722 + | project Time_Event4722 = TimeGenerated, TargetAccount, TargetSid, SubjectAccount_Event4722 = SubjectAccount, SubjectUserSid_Event4722 = SubjectUserSid, Activity_4722 = Activity, Computer_4722 = Computer; + let userPwdSet = SecEvents + // 4723: Attempt made by user to set password + | where EventID == 4723 + | project Time_Event4723 = TimeGenerated, TargetAccount, TargetSid, SubjectAccount_Event4723 = SubjectAccount, SubjectUserSid_Event4723 = SubjectUserSid, Activity_4723 = Activity, Computer_4723 = Computer; + userEnable | join kind=leftouter userPwdSet on TargetAccount, TargetSid + | extend PasswordSetAttemptDelta_Min = datetime_diff('minute', Time_Event4723, Time_Event4722) + | where PasswordSetAttemptDelta_Min > 2880 or isempty(PasswordSetAttemptDelta_Min) + | project-away TargetAccount1, TargetSid1 + | extend Reason = @"User either has not yet attempted to set the initial password after account was enabled or it occurred after 48 hours" + | order by Time_Event4722 asc + | project-reorder Time_Event4722, Time_Event4723, PasswordSetAttemptDelta_Min, TargetAccount, TargetSid + | extend Computer = coalesce(Computer_4723, Computer_4722) + | extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.')) + | extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer) + | extend AccountName = tostring(split(TargetAccount, "\\")[1]), AccountNTDomain = tostring(split(TargetAccount, "\\")[0]) + | project-away DomainIndex + schedule: + frequency: P1D + detectionAction: + alertTemplate: + title: AD user enabled and password not set within 48 hours + description: |- + 'Identifies when an account is enabled with a default password and the password is not set by the user within 48 hours. + Effectively, there is an event 4722 indicating an account was enabled and within 48 hours, no event 4723 occurs which + indicates there was no attempt by the user to set the password. This will show any attempts (success or fail) that occur + after 48 hours, which can indicate too long of a time period in setting the password to something that only the user knows. + It is recommended that this time period is adjusted per your internal company policy.' + severity: low + entityMappings: + accounts: + - id: account1 + nameColumn: AccountName + ntDomainColumn: AccountNTDomain + - id: account2 + sidColumn: TargetSid + hosts: + - id: host1 + nameColumn: HostName + dnsDomainColumn: HostNameDomain + tactics: + - tactic: Persistence + techniques: + - technique: T1098