diff --git a/Solutions/QualysVM/Analytic Rules/HighNumberofVulnDetectedV2.yaml b/Solutions/QualysVM/Analytic Rules/HighNumberofVulnDetectedV2.yaml index 5f90c15a779..5c873929f32 100644 --- a/Solutions/QualysVM/Analytic Rules/HighNumberofVulnDetectedV2.yaml +++ b/Solutions/QualysVM/Analytic Rules/HighNumberofVulnDetectedV2.yaml @@ -17,6 +17,189 @@ tactics: relevantTechniques: - T1190 query: | + let QualysHostDetection = view () { + let QualysHostDetection_view = view () { + QualysHostDetection_CL + | mv-expand todynamic(Detections_s) + | extend + Severity_s = tostring(Detections_s.Severity), + Status_s = tostring(Detections_s.Status), + QID_s = tostring(Detections_s.Results) + | extend + TenantId = column_ifexists('TenantId', ''), + SourceSystem = column_ifexists('SourceSystem', ''), + MG = column_ifexists('MG', ''), + ManagementGroupName = column_ifexists('ManagementGroupName', ''), + TimeGenerated = column_ifexists('TimeGenerated', ''), + Computer = column_ifexists('Computer', ''), + RawData = column_ifexists('RawData', ''), + Id = column_ifexists('Id_s', ''), + HostId = column_ifexists('HostId_s', ''), + HostTags = column_ifexists('HostTags_s', ''), + IPAddress = column_ifexists('IPAddress', ''), + TrackingMethod = column_ifexists('TrackingMethod_s', ''), + OperatingSystem = column_ifexists('OperatingSystem_s', ''), + DnsName = column_ifexists('DnsName_s', ''), + NetBios = column_ifexists('NetBios_s', ''), + QGHostId = column_ifexists('QGHostId_g', ''), + LastScanDateTime = column_ifexists('LastScanDateTime_t', ''), + LastVMScannedDateTime = column_ifexists('LastVMScannedDateTime_t', ''), + LastVMAuthScannedDateTime = column_ifexists('LastVMAuthScannedDateTime_t', ''), + QID = column_ifexists('QID_s', ''), + SSL = column_ifexists('SSL_s', ''), + Status = column_ifexists('Status_s', ''), + Ignored = column_ifexists('Ignored_s', ''), + Severity = column_ifexists('Severity_s', ''), + Disabled = column_ifexists('Disabled_s', ''), + LastFixed = column_ifexists('LastFixed_t', ''), + LastFound = column_ifexists('LastFound_t', ''), + TimesFound = column_ifexists('TimesFound_s', ''), + FirstFound = column_ifexists('FirstFound_t', ''), + LastUpdate = column_ifexists('LastUpdate_t', datetime(null)), + LastProcessedDateTime = column_ifexists('LastProcessed_t', datetime(null)), + Result_column_count = tostring(column_ifexists('Result_column_count_d', '')), + Results_0 = column_ifexists('Results_0_s', ''), + Type = column_ifexists('Type', ''), + _ResourceId = column_ifexists('_ResourceId', '') + }; + let QualysHostDetectionV2_view = view () { + QualysHostDetectionV2_CL + | extend + TenantId = column_ifexists('TenantId', ''), + SourceSystem = column_ifexists('SourceSystem', ''), + MG = column_ifexists('MG', ''), + ManagementGroupName = column_ifexists('ManagementGroupName', ''), + TimeGenerated = column_ifexists('TimeGenerated', ''), + Computer = column_ifexists('Computer', ''), + RawData = column_ifexists('RawData', ''), + Id = column_ifexists('Id_s', ''), + HostId = column_ifexists('HostId_s', ''), + IPAddress = column_ifexists('IPAddress', ''), + TrackingMethod = column_ifexists('TrackingMethod_s', ''), + OperatingSystem = column_ifexists('OperatingSystem_s', ''), + DnsName = column_ifexists('DnsName_s', ''), + NetBios = column_ifexists('NetBios_s', ''), + QGHostId = column_ifexists('QGHostId_g', ''), + LastScanDateTime = column_ifexists('LastScanDateTime_t', ''), + LastVMScannedDateTime = column_ifexists('LastVMScannedDateTime_t', ''), + LastVMAuthScannedDateTime = column_ifexists('LastVMAuthScannedDateTime_t', ''), + QID = column_ifexists('QID_s', ''), + SSL = column_ifexists('SSL_s', ''), + Status = column_ifexists('Status_s', ''), + Ignored = column_ifexists('Ignored_s', ''), + Severity = column_ifexists('Severity_s', ''), + Disabled = column_ifexists('Disabled_s', ''), + LastFixed = column_ifexists('LastFixed_t', ''), + LastFound = column_ifexists('LastFound_t', ''), + TimesFound = column_ifexists('TimesFound_s', ''), + FirstFound = column_ifexists('FirstFound_t', ''), + LastUpdate = column_ifexists('LastUpdate_t', datetime(null)), + LastProcessedDateTime = column_ifexists('LastProcessed_t', datetime(null)), + Result_column_count = tostring(column_ifexists('Result_column_count_d', '')), + Results_0 = column_ifexists('Results_0_s', ''), + Type = column_ifexists('Type', ''), + _ResourceId = column_ifexists('_ResourceId', '') + }; + let QualysHostDetectionV3_view = view () { + QualysHostDetectionV3_CL + | extend DetectionList = todynamic(DetectionList) + | extend DetectionItems = iff( + gettype(DetectionList.DETECTION) == "array", + DetectionList.DETECTION, + pack_array(DetectionList.DETECTION) + ) + | mv-expand Detections = DetectionItems to typeof(dynamic) + | extend + TenantId = column_ifexists('TenantId', ''), + SourceSystem = column_ifexists('SourceSystem', ''), + MG = column_ifexists('MG', ''), + ManagementGroupName = column_ifexists('ManagementGroupName', ''), + TimeGenerated = column_ifexists('TimeGenerated', ''), + Computer = column_ifexists('Computer', ''), + RawData = column_ifexists('RawData', ''), + Id = column_ifexists('Id', ''), + HostId = column_ifexists('HostId', ''), + HostTags = column_ifexists('HostTags', ''), + IPAddress = column_ifexists('IPAddress', ''), + TrackingMethod = column_ifexists('TrackingMethod', ''), + OperatingSystem = column_ifexists('OperatingSystem', ''), + DnsName = column_ifexists('DnsName', ''), + NetBios = column_ifexists('NetBios', ''), + QGHostId = column_ifexists('QGHostId', ''), + LastScanDateTime = column_ifexists('LastScanDateTime', ''), + LastVMScannedDateTime = column_ifexists('LastVMScannedDateTime', ''), + LastVMAuthScannedDateTime = column_ifexists('LastVMAuthScannedDateTime', ''), + QID = tostring(Detections.QID), + SSL = tostring(Detections.SSL), + Status = tostring(Detections.STATUS), + Ignored = tostring(Detections.IS_IGNORED), + Severity = tostring(Detections.SEVERITY), + Disabled = tostring(Detections.IS_DISABLED), + LastFixed = todatetime(Detections.LAST_FIXED_DATETIME), + LastFound = todatetime(Detections.LAST_FOUND_DATETIME), + TimesFound = tostring(Detections.TIMES_FOUND), + FirstFound = todatetime(Detections.FIRST_FOUND_DATETIME), + LastUpdate = todatetime(Detections.LAST_UPDATE_DATETIME), + LastProcessedDateTime = coalesce( + todatetime(Detections.LAST_PROCESSED_DATETIME), + todatetime(Detections.LAST_PROCESSED_DATE)), + Results_0 = tostring(coalesce(Detections.RESULTS['#cdata-section'], Detections.RESULTS)), + Result_column_count = "1", + Type = tostring(Detections.TYPE), + _ResourceId = column_ifexists('_ResourceId', '') + | extend _IngestionTime = todatetime(TimeGenerated) + | summarize arg_max(_IngestionTime, *) by HostId, QID, Status, SSL, Ignored, Severity, Disabled, LastFixed, LastFound, TimesFound, FirstFound, Result_column_count, Results_0, Type + | project-away _IngestionTime + }; + union isfuzzy=true + (QualysHostDetection_view), + (QualysHostDetectionV2_view), + (QualysHostDetectionV3_view) + | project + TenantId, + SourceSystem, + MG, + ManagementGroupName, + TimeGenerated, + Computer, + RawData, + Id, + HostId, + HostTags, + IPAddress, + TrackingMethod, + OperatingSystem, + DnsName, + NetBios, + QGHostId, + LastScanDateTime, + LastVMScannedDateTime, + LastVMAuthScannedDateTime, + QID, + SSL, + Type, + Status, + Ignored, + Severity, + Disabled, + LastFixed, + LastFound, + TimesFound, + FirstFound, + LastUpdate, + LastProcessedDateTime, + Result_column_count, + Results_0, + _ResourceId + | extend + HostId = tostring(HostId), + QID = tostring(QID), + Status = tostring(Status), + LastProcessedDateTime = todatetime(LastProcessedDateTime), + LastUpdate = todatetime(LastUpdate), + LastFound = todatetime(LastFound) + | extend DetectionTime = coalesce(LastProcessedDateTime, LastUpdate, LastFound, todatetime(TimeGenerated)) + }; let threshold = 10; QualysHostDetection | where Severity == "5" @@ -25,11 +208,11 @@ query: | entityMappings: - entityType: Host fieldMappings: - - identifier: FullName + - identifier: NetBiosName columnName: NetBios - entityType: IP fieldMappings: - identifier: Address columnName: IPAddress -version: 1.0.4 +version: 3.2.1 kind: Scheduled diff --git a/Solutions/QualysVM/Analytic Rules/NewHighSeverityVulnDetectedAcrossMulitpleHostsV2.yaml b/Solutions/QualysVM/Analytic Rules/NewHighSeverityVulnDetectedAcrossMulitpleHostsV2.yaml index 68d9f762d3e..aef21ba7b42 100644 --- a/Solutions/QualysVM/Analytic Rules/NewHighSeverityVulnDetectedAcrossMulitpleHostsV2.yaml +++ b/Solutions/QualysVM/Analytic Rules/NewHighSeverityVulnDetectedAcrossMulitpleHostsV2.yaml @@ -17,12 +17,200 @@ tactics: relevantTechniques: - T1190 query: | + let QualysHostDetection = view () { + let QualysHostDetection_view = view () { + QualysHostDetection_CL + | mv-expand todynamic(Detections_s) + | extend + Severity_s = tostring(Detections_s.Severity), + Status_s = tostring(Detections_s.Status), + QID_s = tostring(Detections_s.Results) + | extend + TenantId = column_ifexists('TenantId', ''), + SourceSystem = column_ifexists('SourceSystem', ''), + MG = column_ifexists('MG', ''), + ManagementGroupName = column_ifexists('ManagementGroupName', ''), + TimeGenerated = column_ifexists('TimeGenerated', ''), + Computer = column_ifexists('Computer', ''), + RawData = column_ifexists('RawData', ''), + Id = column_ifexists('Id_s', ''), + HostId = column_ifexists('HostId_s', ''), + HostTags = column_ifexists('HostTags_s', ''), + IPAddress = column_ifexists('IPAddress', ''), + TrackingMethod = column_ifexists('TrackingMethod_s', ''), + OperatingSystem = column_ifexists('OperatingSystem_s', ''), + DnsName = column_ifexists('DnsName_s', ''), + NetBios = column_ifexists('NetBios_s', ''), + QGHostId = column_ifexists('QGHostId_g', ''), + LastScanDateTime = column_ifexists('LastScanDateTime_t', ''), + LastVMScannedDateTime = column_ifexists('LastVMScannedDateTime_t', ''), + LastVMAuthScannedDateTime = column_ifexists('LastVMAuthScannedDateTime_t', ''), + QID = column_ifexists('QID_s', ''), + SSL = column_ifexists('SSL_s', ''), + Status = column_ifexists('Status_s', ''), + Ignored = column_ifexists('Ignored_s', ''), + Severity = column_ifexists('Severity_s', ''), + Disabled = column_ifexists('Disabled_s', ''), + LastFixed = column_ifexists('LastFixed_t', ''), + LastFound = column_ifexists('LastFound_t', ''), + TimesFound = column_ifexists('TimesFound_s', ''), + FirstFound = column_ifexists('FirstFound_t', ''), + LastUpdate = column_ifexists('LastUpdate_t', datetime(null)), + LastProcessedDateTime = column_ifexists('LastProcessed_t', datetime(null)), + Result_column_count = tostring(column_ifexists('Result_column_count_d', '')), + Results_0 = column_ifexists('Results_0_s', ''), + Type = column_ifexists('Type', ''), + _ResourceId = column_ifexists('_ResourceId', '') + }; + let QualysHostDetectionV2_view = view () { + QualysHostDetectionV2_CL + | extend + TenantId = column_ifexists('TenantId', ''), + SourceSystem = column_ifexists('SourceSystem', ''), + MG = column_ifexists('MG', ''), + ManagementGroupName = column_ifexists('ManagementGroupName', ''), + TimeGenerated = column_ifexists('TimeGenerated', ''), + Computer = column_ifexists('Computer', ''), + RawData = column_ifexists('RawData', ''), + Id = column_ifexists('Id_s', ''), + HostId = column_ifexists('HostId_s', ''), + IPAddress = column_ifexists('IPAddress', ''), + TrackingMethod = column_ifexists('TrackingMethod_s', ''), + OperatingSystem = column_ifexists('OperatingSystem_s', ''), + DnsName = column_ifexists('DnsName_s', ''), + NetBios = column_ifexists('NetBios_s', ''), + QGHostId = column_ifexists('QGHostId_g', ''), + LastScanDateTime = column_ifexists('LastScanDateTime_t', ''), + LastVMScannedDateTime = column_ifexists('LastVMScannedDateTime_t', ''), + LastVMAuthScannedDateTime = column_ifexists('LastVMAuthScannedDateTime_t', ''), + QID = column_ifexists('QID_s', ''), + SSL = column_ifexists('SSL_s', ''), + Status = column_ifexists('Status_s', ''), + Ignored = column_ifexists('Ignored_s', ''), + Severity = column_ifexists('Severity_s', ''), + Disabled = column_ifexists('Disabled_s', ''), + LastFixed = column_ifexists('LastFixed_t', ''), + LastFound = column_ifexists('LastFound_t', ''), + TimesFound = column_ifexists('TimesFound_s', ''), + FirstFound = column_ifexists('FirstFound_t', ''), + LastUpdate = column_ifexists('LastUpdate_t', datetime(null)), + LastProcessedDateTime = column_ifexists('LastProcessed_t', datetime(null)), + Result_column_count = tostring(column_ifexists('Result_column_count_d', '')), + Results_0 = column_ifexists('Results_0_s', ''), + Type = column_ifexists('Type', ''), + _ResourceId = column_ifexists('_ResourceId', '') + }; + let QualysHostDetectionV3_view = view () { + QualysHostDetectionV3_CL + | extend DetectionList = todynamic(DetectionList) + | extend DetectionItems = iff( + gettype(DetectionList.DETECTION) == "array", + DetectionList.DETECTION, + pack_array(DetectionList.DETECTION) + ) + | mv-expand Detections = DetectionItems to typeof(dynamic) + | extend + TenantId = column_ifexists('TenantId', ''), + SourceSystem = column_ifexists('SourceSystem', ''), + MG = column_ifexists('MG', ''), + ManagementGroupName = column_ifexists('ManagementGroupName', ''), + TimeGenerated = column_ifexists('TimeGenerated', ''), + Computer = column_ifexists('Computer', ''), + RawData = column_ifexists('RawData', ''), + Id = column_ifexists('Id', ''), + HostId = column_ifexists('HostId', ''), + HostTags = column_ifexists('HostTags', ''), + IPAddress = column_ifexists('IPAddress', ''), + TrackingMethod = column_ifexists('TrackingMethod', ''), + OperatingSystem = column_ifexists('OperatingSystem', ''), + DnsName = column_ifexists('DnsName', ''), + NetBios = column_ifexists('NetBios', ''), + QGHostId = column_ifexists('QGHostId', ''), + LastScanDateTime = column_ifexists('LastScanDateTime', ''), + LastVMScannedDateTime = column_ifexists('LastVMScannedDateTime', ''), + LastVMAuthScannedDateTime = column_ifexists('LastVMAuthScannedDateTime', ''), + QID = tostring(Detections.QID), + SSL = tostring(Detections.SSL), + Status = tostring(Detections.STATUS), + Ignored = tostring(Detections.IS_IGNORED), + Severity = tostring(Detections.SEVERITY), + Disabled = tostring(Detections.IS_DISABLED), + LastFixed = todatetime(Detections.LAST_FIXED_DATETIME), + LastFound = todatetime(Detections.LAST_FOUND_DATETIME), + TimesFound = tostring(Detections.TIMES_FOUND), + FirstFound = todatetime(Detections.FIRST_FOUND_DATETIME), + LastUpdate = todatetime(Detections.LAST_UPDATE_DATETIME), + LastProcessedDateTime = coalesce( + todatetime(Detections.LAST_PROCESSED_DATETIME), + todatetime(Detections.LAST_PROCESSED_DATE)), + Results_0 = tostring(coalesce(Detections.RESULTS['#cdata-section'], Detections.RESULTS)), + Result_column_count = "1", + Type = tostring(Detections.TYPE), + _ResourceId = column_ifexists('_ResourceId', '') + | extend _IngestionTime = todatetime(TimeGenerated) + | summarize arg_max(_IngestionTime, *) by HostId, QID, Status, SSL, Ignored, Severity, Disabled, LastFixed, LastFound, TimesFound, FirstFound, Result_column_count, Results_0, Type + | project-away _IngestionTime + }; + union isfuzzy=true + (QualysHostDetection_view), + (QualysHostDetectionV2_view), + (QualysHostDetectionV3_view) + | project + TenantId, + SourceSystem, + MG, + ManagementGroupName, + TimeGenerated, + Computer, + RawData, + Id, + HostId, + HostTags, + IPAddress, + TrackingMethod, + OperatingSystem, + DnsName, + NetBios, + QGHostId, + LastScanDateTime, + LastVMScannedDateTime, + LastVMAuthScannedDateTime, + QID, + SSL, + Type, + Status, + Ignored, + Severity, + Disabled, + LastFixed, + LastFound, + TimesFound, + FirstFound, + LastUpdate, + LastProcessedDateTime, + Result_column_count, + Results_0, + _ResourceId + | extend + HostId = tostring(HostId), + QID = tostring(QID), + Status = tostring(Status), + LastProcessedDateTime = todatetime(LastProcessedDateTime), + LastUpdate = todatetime(LastUpdate), + LastFound = todatetime(LastFound) + | extend DetectionTime = coalesce(LastProcessedDateTime, LastUpdate, LastFound, todatetime(TimeGenerated)) + }; let threshold = 10; QualysHostDetection | extend Status = tostring(Status), Vulnerability = tostring(QID), Severity = tostring(Severity) | where Status =~ "New" and Severity == "5" - | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), dcount(NetBios) by tostring(QID) + | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), dcount(NetBios), RepresentativeHost = take_anyif(NetBios, isnotempty(NetBios)) by tostring(QID) | where dcount_NetBios >= threshold | extend timestamp = StartTime -version: 1.0.2 +entityMappings: + - entityType: Host + fieldMappings: + - identifier: NetBiosName + columnName: RepresentativeHost +version: 3.2.1 kind: Scheduled diff --git a/Solutions/QualysVM/Package/3.2.2.zip b/Solutions/QualysVM/Package/3.2.2.zip new file mode 100644 index 00000000000..e0958d0c48e Binary files /dev/null and b/Solutions/QualysVM/Package/3.2.2.zip differ diff --git a/Solutions/QualysVM/Package/createUiDefinition.json b/Solutions/QualysVM/Package/createUiDefinition.json index 1b1a8c434da..9545e5356f1 100644 --- a/Solutions/QualysVM/Package/createUiDefinition.json +++ b/Solutions/QualysVM/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/QualysVM/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 [Qualys Vulnerability Management](https://www.qualys.com/apps/vulnerability-management-detection-response/) solution for Microsoft Sentinel enables you to ingest host vulnerability detection data into Microsoft Sentinel.\n\n **Underlying Microsoft Technologies used:** \n\n This solution takes a dependency on the following technologies, and some of these dependencies either may be in [Preview](https://azure.microsoft.com/support/legal/preview-supplemental-terms/) state or might result in additional ingestion or operational costs:\n\n• [Microsoft Sentinel Codeless Connector Framework](https://aka.ms/Sentinel-CCP_Platform)\n\n**Data Connectors:** 1, **Parsers:** 1, **Workbooks:** 1, **Analytic Rules:** 2, **Custom Azure Logic Apps Connectors:** 1, **Playbooks:** 4\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/QualysVM/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 [Qualys Vulnerability Management](https://www.qualys.com/apps/vulnerability-management-detection-response/) solution for Microsoft Sentinel enables you to ingest host vulnerability detection data into Microsoft Sentinel.\n\n **Underlying Microsoft Technologies used:** \n\n This solution takes a dependency on the following technologies, and some of these dependencies either may be in [Preview](https://azure.microsoft.com/support/legal/preview-supplemental-terms/) state or might result in additional ingestion or operational costs:\n\n• [Microsoft Sentinel Codeless Connector Framework](https://aka.ms/Sentinel-CCP_Platform)\n\n**Data Connectors:** 1, **Parsers:** 1, **Workbooks:** 1, **Analytic Rules:** 2, **XDR Detections:** 2, **Custom Azure Logic Apps Connectors:** 1, **Playbooks:** 4\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": "DeployPlaybook", + "type": "Microsoft.Common.CheckBox", + "label": "DeployPlaybook", + "defaultValue": true, + "toolTip": "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." + }, + { + "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": "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", @@ -205,7 +253,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]", + "DeployPlaybook": "[steps('contentSelection').DeployPlaybook]", + "DeployWorkbook": "[steps('contentSelection').DeployWorkbook]", + "DeployDataConnector": "[steps('contentSelection').DeployDataConnector]", + "DeployCustomDetection": "[steps('contentSelection').DeployCustomDetection]", + "DeployParser": "[steps('contentSelection').DeployParser]" } } } diff --git a/Solutions/QualysVM/Package/mainTemplate.json b/Solutions/QualysVM/Package/mainTemplate.json index bc37c8efacf..9d6e5f3ec2e 100644 --- a/Solutions/QualysVM/Package/mainTemplate.json +++ b/Solutions/QualysVM/Package/mainTemplate.json @@ -49,17 +49,59 @@ "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." + } + }, + "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": "QualysVM", - "_solutionVersion": "3.1.1", + "_solutionVersion": "3.2.2", "solutionId": "azuresentinel.azure-sentinel-qualysvm", "_solutionId": "[variables('solutionId')]", "workspaceResourceId": "[resourceId('microsoft.OperationalInsights/Workspaces', parameters('workspace'))]", - "dataConnectorCCPVersion": "3.1.1", + "dataConnectorCCPVersion": "3.2.2", "_dataConnectorContentIdConnectorDefinition1": "QualysVMLogsCCPDefinition", "dataConnectorTemplateNameConnectorDefinition1": "[concat(parameters('workspace'),'-dc-',uniquestring(variables('_dataConnectorContentIdConnectorDefinition1')))]", "_dataConnectorContentIdConnections1": "QualysVMLogsCCPDefinitionConnections", @@ -80,18 +122,18 @@ "_workbookContentId1": "[variables('workbookContentId1')]", "_workbookcontentProductId1": "[concat(take(variables('_solutionId'),50),'-','wb','-', uniqueString(concat(variables('_solutionId'),'-','Workbook','-',variables('_workbookContentId1'),'-', variables('workbookVersion1'))))]", "analyticRuleObject1": { - "analyticRuleVersion1": "1.0.4", + "analyticRuleVersion1": "3.2.1", "_analyticRulecontentId1": "3edb7215-250b-40c0-8b46-79093949242d", "analyticRuleId1": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', '3edb7215-250b-40c0-8b46-79093949242d')]", "analyticRuleTemplateSpecName1": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring('3edb7215-250b-40c0-8b46-79093949242d')))]", - "_analyticRulecontentProductId1": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','3edb7215-250b-40c0-8b46-79093949242d','-', '1.0.4')))]" + "_analyticRulecontentProductId1": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','3edb7215-250b-40c0-8b46-79093949242d','-', '3.2.1')))]" }, "analyticRuleObject2": { - "analyticRuleVersion2": "1.0.2", + "analyticRuleVersion2": "3.2.1", "_analyticRulecontentId2": "6116dc19-475a-4148-84b2-efe89c073e27", "analyticRuleId2": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', '6116dc19-475a-4148-84b2-efe89c073e27')]", "analyticRuleTemplateSpecName2": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring('6116dc19-475a-4148-84b2-efe89c073e27')))]", - "_analyticRulecontentProductId2": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','6116dc19-475a-4148-84b2-efe89c073e27','-', '1.0.2')))]" + "_analyticRulecontentProductId2": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','6116dc19-475a-4148-84b2-efe89c073e27','-', '3.2.1')))]" }, "QualysCustomConnector": "QualysCustomConnector", "_QualysCustomConnector": "[variables('QualysCustomConnector')]", @@ -360,7 +402,8 @@ } ] } - } + }, + "condition": "[parameters('DeployDataConnector')]" }, { "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('DataConnector-', variables('_dataConnectorContentIdConnectorDefinition1')))]", @@ -559,7 +602,8 @@ "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", "version": "[variables('dataConnectorCCPVersion')]" - } + }, + "condition": "[parameters('DeployDataConnector')]" }, { "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',variables('_dataConnectorContentIdConnectorDefinition1'))]", @@ -767,7 +811,8 @@ } ] } - } + }, + "condition": "[parameters('DeployDataConnector')]" }, { "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('DataConnector-', variables('_dataConnectorContentIdConnectorDefinition1')))]", @@ -802,7 +847,8 @@ } ] } - } + }, + "condition": "[parameters('DeployDataConnector')]" }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", @@ -970,7 +1016,8 @@ "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", "version": "[variables('dataConnectorCCPVersion')]" - } + }, + "condition": "[parameters('DeployDataConnector')]" }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", @@ -981,7 +1028,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "QualysHostDetection Data Parser with template version 3.1.1", + "description": "QualysHostDetection Data Parser with template version 3.2.2", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('parserObject1').parserVersion1]", @@ -1051,7 +1098,8 @@ "contentProductId": "[concat(take(variables('_solutionId'),50),'-','pr','-', uniqueString(concat(variables('_solutionId'),'-','Parser','-',variables('parserObject1').parserContentId1,'-', '1.1.0')))]", "id": "[concat(take(variables('_solutionId'),50),'-','pr','-', uniqueString(concat(variables('_solutionId'),'-','Parser','-',variables('parserObject1').parserContentId1,'-', '1.1.0')))]", "version": "[variables('parserObject1').parserVersion1]" - } + }, + "condition": "[parameters('DeployParser')]" }, { "type": "Microsoft.OperationalInsights/workspaces/savedSearches", @@ -1072,7 +1120,8 @@ "value": "" } ] - } + }, + "condition": "[parameters('DeployParser')]" }, { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", @@ -1102,7 +1151,8 @@ "tier": "Microsoft", "link": "https://support.microsoft.com" } - } + }, + "condition": "[parameters('DeployParser')]" }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", @@ -1113,7 +1163,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "QualysVMv2 Workbook with template version 3.1.1", + "description": "QualysVMv2 Workbook with template version 3.2.2", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('workbookVersion1')]", @@ -1190,7 +1240,8 @@ "contentProductId": "[variables('_workbookcontentProductId1')]", "id": "[variables('_workbookcontentProductId1')]", "version": "[variables('workbookVersion1')]" - } + }, + "condition": "[parameters('DeployWorkbook')]" }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", @@ -1201,7 +1252,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "HighNumberofVulnDetectedV2_AnalyticalRules Analytics Rule with template version 3.1.1", + "description": "HighNumberofVulnDetectedV2_AnalyticalRules Analytics Rule with template version 3.2.2", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('analyticRuleObject1').analyticRuleVersion1]", @@ -1218,7 +1269,7 @@ "description": "This creates an incident when a host has a high number of urgent, severity 5, vulnerabilities detected.", "displayName": "High Number of Urgent Vulnerabilities Detected", "enabled": false, - "query": "let threshold = 10;\nQualysHostDetection\n| where Severity == \"5\"\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), count() by NetBios, IPAddress\n| where count_ >= threshold\n", + "query": "let QualysHostDetection = view () {\nlet QualysHostDetection_view = view () {\n QualysHostDetection_CL\n | mv-expand todynamic(Detections_s)\n | extend\n Severity_s = tostring(Detections_s.Severity),\n Status_s = tostring(Detections_s.Status),\n QID_s = tostring(Detections_s.Results)\n | extend\n TenantId = column_ifexists('TenantId', ''),\n SourceSystem = column_ifexists('SourceSystem', ''),\n MG = column_ifexists('MG', ''),\n ManagementGroupName = column_ifexists('ManagementGroupName', ''),\n TimeGenerated = column_ifexists('TimeGenerated', ''),\n Computer = column_ifexists('Computer', ''),\n RawData = column_ifexists('RawData', ''),\n Id = column_ifexists('Id_s', ''),\n HostId = column_ifexists('HostId_s', ''),\n HostTags = column_ifexists('HostTags_s', ''),\n IPAddress = column_ifexists('IPAddress', ''),\n TrackingMethod = column_ifexists('TrackingMethod_s', ''),\n OperatingSystem = column_ifexists('OperatingSystem_s', ''),\n DnsName = column_ifexists('DnsName_s', ''),\n NetBios = column_ifexists('NetBios_s', ''),\n QGHostId = column_ifexists('QGHostId_g', ''),\n LastScanDateTime = column_ifexists('LastScanDateTime_t', ''),\n LastVMScannedDateTime = column_ifexists('LastVMScannedDateTime_t', ''),\n LastVMAuthScannedDateTime = column_ifexists('LastVMAuthScannedDateTime_t', ''),\n QID = column_ifexists('QID_s', ''),\n SSL = column_ifexists('SSL_s', ''),\n Status = column_ifexists('Status_s', ''),\n Ignored = column_ifexists('Ignored_s', ''),\n Severity = column_ifexists('Severity_s', ''),\n Disabled = column_ifexists('Disabled_s', ''),\n LastFixed = column_ifexists('LastFixed_t', ''),\n LastFound = column_ifexists('LastFound_t', ''),\n TimesFound = column_ifexists('TimesFound_s', ''),\n FirstFound = column_ifexists('FirstFound_t', ''),\n LastUpdate = column_ifexists('LastUpdate_t', datetime(null)),\n LastProcessedDateTime = column_ifexists('LastProcessed_t', datetime(null)),\n Result_column_count = tostring(column_ifexists('Result_column_count_d', '')),\n Results_0 = column_ifexists('Results_0_s', ''),\n Type = column_ifexists('Type', ''),\n _ResourceId = column_ifexists('_ResourceId', '')\n };\n let QualysHostDetectionV2_view = view () {\n QualysHostDetectionV2_CL\n | extend\n TenantId = column_ifexists('TenantId', ''),\n SourceSystem = column_ifexists('SourceSystem', ''),\n MG = column_ifexists('MG', ''),\n ManagementGroupName = column_ifexists('ManagementGroupName', ''),\n TimeGenerated = column_ifexists('TimeGenerated', ''),\n Computer = column_ifexists('Computer', ''),\n RawData = column_ifexists('RawData', ''),\n Id = column_ifexists('Id_s', ''),\n HostId = column_ifexists('HostId_s', ''),\n IPAddress = column_ifexists('IPAddress', ''),\n TrackingMethod = column_ifexists('TrackingMethod_s', ''),\n OperatingSystem = column_ifexists('OperatingSystem_s', ''),\n DnsName = column_ifexists('DnsName_s', ''),\n NetBios = column_ifexists('NetBios_s', ''),\n QGHostId = column_ifexists('QGHostId_g', ''),\n LastScanDateTime = column_ifexists('LastScanDateTime_t', ''),\n LastVMScannedDateTime = column_ifexists('LastVMScannedDateTime_t', ''),\n LastVMAuthScannedDateTime = column_ifexists('LastVMAuthScannedDateTime_t', ''),\n QID = column_ifexists('QID_s', ''),\n SSL = column_ifexists('SSL_s', ''),\n Status = column_ifexists('Status_s', ''),\n Ignored = column_ifexists('Ignored_s', ''),\n Severity = column_ifexists('Severity_s', ''),\n Disabled = column_ifexists('Disabled_s', ''),\n LastFixed = column_ifexists('LastFixed_t', ''),\n LastFound = column_ifexists('LastFound_t', ''),\n TimesFound = column_ifexists('TimesFound_s', ''),\n FirstFound = column_ifexists('FirstFound_t', ''),\n LastUpdate = column_ifexists('LastUpdate_t', datetime(null)),\n LastProcessedDateTime = column_ifexists('LastProcessed_t', datetime(null)),\n Result_column_count = tostring(column_ifexists('Result_column_count_d', '')),\n Results_0 = column_ifexists('Results_0_s', ''),\n Type = column_ifexists('Type', ''),\n _ResourceId = column_ifexists('_ResourceId', '')\n };\n let QualysHostDetectionV3_view = view () {\n QualysHostDetectionV3_CL\n | extend DetectionList = todynamic(DetectionList)\n | extend DetectionItems = iff(\n gettype(DetectionList.DETECTION) == \"array\",\n DetectionList.DETECTION,\n pack_array(DetectionList.DETECTION)\n )\n | mv-expand Detections = DetectionItems to typeof(dynamic)\n | extend\n TenantId = column_ifexists('TenantId', ''),\n SourceSystem = column_ifexists('SourceSystem', ''),\n MG = column_ifexists('MG', ''),\n ManagementGroupName = column_ifexists('ManagementGroupName', ''),\n TimeGenerated = column_ifexists('TimeGenerated', ''),\n Computer = column_ifexists('Computer', ''),\n RawData = column_ifexists('RawData', ''),\n Id = column_ifexists('Id', ''),\n HostId = column_ifexists('HostId', ''),\n HostTags = column_ifexists('HostTags', ''),\n IPAddress = column_ifexists('IPAddress', ''),\n TrackingMethod = column_ifexists('TrackingMethod', ''),\n OperatingSystem = column_ifexists('OperatingSystem', ''),\n DnsName = column_ifexists('DnsName', ''),\n NetBios = column_ifexists('NetBios', ''),\n QGHostId = column_ifexists('QGHostId', ''),\n LastScanDateTime = column_ifexists('LastScanDateTime', ''),\n LastVMScannedDateTime = column_ifexists('LastVMScannedDateTime', ''),\n LastVMAuthScannedDateTime = column_ifexists('LastVMAuthScannedDateTime', ''),\n QID = tostring(Detections.QID),\n SSL = tostring(Detections.SSL),\n Status = tostring(Detections.STATUS),\n Ignored = tostring(Detections.IS_IGNORED),\n Severity = tostring(Detections.SEVERITY),\n Disabled = tostring(Detections.IS_DISABLED),\n LastFixed = todatetime(Detections.LAST_FIXED_DATETIME),\n LastFound = todatetime(Detections.LAST_FOUND_DATETIME),\n TimesFound = tostring(Detections.TIMES_FOUND),\n FirstFound = todatetime(Detections.FIRST_FOUND_DATETIME),\n LastUpdate = todatetime(Detections.LAST_UPDATE_DATETIME),\n LastProcessedDateTime = coalesce(\n todatetime(Detections.LAST_PROCESSED_DATETIME),\n todatetime(Detections.LAST_PROCESSED_DATE)),\n Results_0 = tostring(coalesce(Detections.RESULTS['#cdata-section'], Detections.RESULTS)),\n Result_column_count = \"1\",\n Type = tostring(Detections.TYPE),\n _ResourceId = column_ifexists('_ResourceId', '')\n | extend _IngestionTime = todatetime(TimeGenerated)\n | summarize arg_max(_IngestionTime, *) by HostId, QID, Status, SSL, Ignored, Severity, Disabled, LastFixed, LastFound, TimesFound, FirstFound, Result_column_count, Results_0, Type\n | project-away _IngestionTime\n };\n union isfuzzy=true\n (QualysHostDetection_view),\n (QualysHostDetectionV2_view),\n (QualysHostDetectionV3_view)\n | project\n TenantId,\n SourceSystem,\n MG,\n ManagementGroupName,\n TimeGenerated,\n Computer,\n RawData,\n Id,\n HostId,\n HostTags,\n IPAddress,\n TrackingMethod,\n OperatingSystem,\n DnsName,\n NetBios,\n QGHostId,\n LastScanDateTime,\n LastVMScannedDateTime,\n LastVMAuthScannedDateTime,\n QID,\n SSL,\n Type,\n Status,\n Ignored,\n Severity,\n Disabled,\n LastFixed,\n LastFound,\n TimesFound,\n FirstFound,\n LastUpdate,\n LastProcessedDateTime,\n Result_column_count,\n Results_0,\n _ResourceId\n | extend\n HostId = tostring(HostId),\n QID = tostring(QID),\n Status = tostring(Status),\n LastProcessedDateTime = todatetime(LastProcessedDateTime),\n LastUpdate = todatetime(LastUpdate),\n LastFound = todatetime(LastFound)\n | extend DetectionTime = coalesce(LastProcessedDateTime, LastUpdate, LastFound, todatetime(TimeGenerated))\n};\nlet threshold = 10;\nQualysHostDetection\n| where Severity == \"5\"\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), count() by NetBios, IPAddress\n| where count_ >= threshold\n", "queryFrequency": "PT1H", "queryPeriod": "PT1H", "severity": "Medium", @@ -1229,10 +1280,10 @@ "status": "Available", "requiredDataConnectors": [ { - "connectorId": "QualysVMLogsCCPDefinition", "dataTypes": [ "QualysHostDetection" - ] + ], + "connectorId": "QualysVMLogsCCPDefinition" } ], "tactics": [ @@ -1243,22 +1294,22 @@ ], "entityMappings": [ { - "entityType": "Host", "fieldMappings": [ { - "identifier": "FullName", + "identifier": "NetBiosName", "columnName": "NetBios" } - ] + ], + "entityType": "Host" }, { - "entityType": "IP", "fieldMappings": [ { "identifier": "Address", "columnName": "IPAddress" } - ] + ], + "entityType": "IP" } ] } @@ -1303,7 +1354,8 @@ "contentProductId": "[variables('analyticRuleObject1')._analyticRulecontentProductId1]", "id": "[variables('analyticRuleObject1')._analyticRulecontentProductId1]", "version": "[variables('analyticRuleObject1').analyticRuleVersion1]" - } + }, + "condition": "[parameters('DeployAnalyticsRule')]" }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", @@ -1314,7 +1366,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "NewHighSeverityVulnDetectedAcrossMulitpleHostsV2_AnalyticalRules Analytics Rule with template version 3.1.1", + "description": "NewHighSeverityVulnDetectedAcrossMulitpleHostsV2_AnalyticalRules Analytics Rule with template version 3.2.2", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('analyticRuleObject2').analyticRuleVersion2]", @@ -1331,7 +1383,7 @@ "description": "This creates an incident when a new high severity vulnerability is detected across multilple hosts", "displayName": "New High Severity Vulnerability Detected Across Multiple Hosts", "enabled": false, - "query": "let threshold = 10;\nQualysHostDetection\n| extend Status = tostring(Status), Vulnerability = tostring(QID), Severity = tostring(Severity)\n| where Status =~ \"New\" and Severity == \"5\"\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), dcount(NetBios) by tostring(QID)\n| where dcount_NetBios >= threshold\n| extend timestamp = StartTime\n", + "query": "let QualysHostDetection = view () {\nlet QualysHostDetection_view = view () {\n QualysHostDetection_CL\n | mv-expand todynamic(Detections_s)\n | extend\n Severity_s = tostring(Detections_s.Severity),\n Status_s = tostring(Detections_s.Status),\n QID_s = tostring(Detections_s.Results)\n | extend\n TenantId = column_ifexists('TenantId', ''),\n SourceSystem = column_ifexists('SourceSystem', ''),\n MG = column_ifexists('MG', ''),\n ManagementGroupName = column_ifexists('ManagementGroupName', ''),\n TimeGenerated = column_ifexists('TimeGenerated', ''),\n Computer = column_ifexists('Computer', ''),\n RawData = column_ifexists('RawData', ''),\n Id = column_ifexists('Id_s', ''),\n HostId = column_ifexists('HostId_s', ''),\n HostTags = column_ifexists('HostTags_s', ''),\n IPAddress = column_ifexists('IPAddress', ''),\n TrackingMethod = column_ifexists('TrackingMethod_s', ''),\n OperatingSystem = column_ifexists('OperatingSystem_s', ''),\n DnsName = column_ifexists('DnsName_s', ''),\n NetBios = column_ifexists('NetBios_s', ''),\n QGHostId = column_ifexists('QGHostId_g', ''),\n LastScanDateTime = column_ifexists('LastScanDateTime_t', ''),\n LastVMScannedDateTime = column_ifexists('LastVMScannedDateTime_t', ''),\n LastVMAuthScannedDateTime = column_ifexists('LastVMAuthScannedDateTime_t', ''),\n QID = column_ifexists('QID_s', ''),\n SSL = column_ifexists('SSL_s', ''),\n Status = column_ifexists('Status_s', ''),\n Ignored = column_ifexists('Ignored_s', ''),\n Severity = column_ifexists('Severity_s', ''),\n Disabled = column_ifexists('Disabled_s', ''),\n LastFixed = column_ifexists('LastFixed_t', ''),\n LastFound = column_ifexists('LastFound_t', ''),\n TimesFound = column_ifexists('TimesFound_s', ''),\n FirstFound = column_ifexists('FirstFound_t', ''),\n LastUpdate = column_ifexists('LastUpdate_t', datetime(null)),\n LastProcessedDateTime = column_ifexists('LastProcessed_t', datetime(null)),\n Result_column_count = tostring(column_ifexists('Result_column_count_d', '')),\n Results_0 = column_ifexists('Results_0_s', ''),\n Type = column_ifexists('Type', ''),\n _ResourceId = column_ifexists('_ResourceId', '')\n };\n let QualysHostDetectionV2_view = view () {\n QualysHostDetectionV2_CL\n | extend\n TenantId = column_ifexists('TenantId', ''),\n SourceSystem = column_ifexists('SourceSystem', ''),\n MG = column_ifexists('MG', ''),\n ManagementGroupName = column_ifexists('ManagementGroupName', ''),\n TimeGenerated = column_ifexists('TimeGenerated', ''),\n Computer = column_ifexists('Computer', ''),\n RawData = column_ifexists('RawData', ''),\n Id = column_ifexists('Id_s', ''),\n HostId = column_ifexists('HostId_s', ''),\n IPAddress = column_ifexists('IPAddress', ''),\n TrackingMethod = column_ifexists('TrackingMethod_s', ''),\n OperatingSystem = column_ifexists('OperatingSystem_s', ''),\n DnsName = column_ifexists('DnsName_s', ''),\n NetBios = column_ifexists('NetBios_s', ''),\n QGHostId = column_ifexists('QGHostId_g', ''),\n LastScanDateTime = column_ifexists('LastScanDateTime_t', ''),\n LastVMScannedDateTime = column_ifexists('LastVMScannedDateTime_t', ''),\n LastVMAuthScannedDateTime = column_ifexists('LastVMAuthScannedDateTime_t', ''),\n QID = column_ifexists('QID_s', ''),\n SSL = column_ifexists('SSL_s', ''),\n Status = column_ifexists('Status_s', ''),\n Ignored = column_ifexists('Ignored_s', ''),\n Severity = column_ifexists('Severity_s', ''),\n Disabled = column_ifexists('Disabled_s', ''),\n LastFixed = column_ifexists('LastFixed_t', ''),\n LastFound = column_ifexists('LastFound_t', ''),\n TimesFound = column_ifexists('TimesFound_s', ''),\n FirstFound = column_ifexists('FirstFound_t', ''),\n LastUpdate = column_ifexists('LastUpdate_t', datetime(null)),\n LastProcessedDateTime = column_ifexists('LastProcessed_t', datetime(null)),\n Result_column_count = tostring(column_ifexists('Result_column_count_d', '')),\n Results_0 = column_ifexists('Results_0_s', ''),\n Type = column_ifexists('Type', ''),\n _ResourceId = column_ifexists('_ResourceId', '')\n };\n let QualysHostDetectionV3_view = view () {\n QualysHostDetectionV3_CL\n | extend DetectionList = todynamic(DetectionList)\n | extend DetectionItems = iff(\n gettype(DetectionList.DETECTION) == \"array\",\n DetectionList.DETECTION,\n pack_array(DetectionList.DETECTION)\n )\n | mv-expand Detections = DetectionItems to typeof(dynamic)\n | extend\n TenantId = column_ifexists('TenantId', ''),\n SourceSystem = column_ifexists('SourceSystem', ''),\n MG = column_ifexists('MG', ''),\n ManagementGroupName = column_ifexists('ManagementGroupName', ''),\n TimeGenerated = column_ifexists('TimeGenerated', ''),\n Computer = column_ifexists('Computer', ''),\n RawData = column_ifexists('RawData', ''),\n Id = column_ifexists('Id', ''),\n HostId = column_ifexists('HostId', ''),\n HostTags = column_ifexists('HostTags', ''),\n IPAddress = column_ifexists('IPAddress', ''),\n TrackingMethod = column_ifexists('TrackingMethod', ''),\n OperatingSystem = column_ifexists('OperatingSystem', ''),\n DnsName = column_ifexists('DnsName', ''),\n NetBios = column_ifexists('NetBios', ''),\n QGHostId = column_ifexists('QGHostId', ''),\n LastScanDateTime = column_ifexists('LastScanDateTime', ''),\n LastVMScannedDateTime = column_ifexists('LastVMScannedDateTime', ''),\n LastVMAuthScannedDateTime = column_ifexists('LastVMAuthScannedDateTime', ''),\n QID = tostring(Detections.QID),\n SSL = tostring(Detections.SSL),\n Status = tostring(Detections.STATUS),\n Ignored = tostring(Detections.IS_IGNORED),\n Severity = tostring(Detections.SEVERITY),\n Disabled = tostring(Detections.IS_DISABLED),\n LastFixed = todatetime(Detections.LAST_FIXED_DATETIME),\n LastFound = todatetime(Detections.LAST_FOUND_DATETIME),\n TimesFound = tostring(Detections.TIMES_FOUND),\n FirstFound = todatetime(Detections.FIRST_FOUND_DATETIME),\n LastUpdate = todatetime(Detections.LAST_UPDATE_DATETIME),\n LastProcessedDateTime = coalesce(\n todatetime(Detections.LAST_PROCESSED_DATETIME),\n todatetime(Detections.LAST_PROCESSED_DATE)),\n Results_0 = tostring(coalesce(Detections.RESULTS['#cdata-section'], Detections.RESULTS)),\n Result_column_count = \"1\",\n Type = tostring(Detections.TYPE),\n _ResourceId = column_ifexists('_ResourceId', '')\n | extend _IngestionTime = todatetime(TimeGenerated)\n | summarize arg_max(_IngestionTime, *) by HostId, QID, Status, SSL, Ignored, Severity, Disabled, LastFixed, LastFound, TimesFound, FirstFound, Result_column_count, Results_0, Type\n | project-away _IngestionTime\n };\n union isfuzzy=true\n (QualysHostDetection_view),\n (QualysHostDetectionV2_view),\n (QualysHostDetectionV3_view)\n | project\n TenantId,\n SourceSystem,\n MG,\n ManagementGroupName,\n TimeGenerated,\n Computer,\n RawData,\n Id,\n HostId,\n HostTags,\n IPAddress,\n TrackingMethod,\n OperatingSystem,\n DnsName,\n NetBios,\n QGHostId,\n LastScanDateTime,\n LastVMScannedDateTime,\n LastVMAuthScannedDateTime,\n QID,\n SSL,\n Type,\n Status,\n Ignored,\n Severity,\n Disabled,\n LastFixed,\n LastFound,\n TimesFound,\n FirstFound,\n LastUpdate,\n LastProcessedDateTime,\n Result_column_count,\n Results_0,\n _ResourceId\n | extend\n HostId = tostring(HostId),\n QID = tostring(QID),\n Status = tostring(Status),\n LastProcessedDateTime = todatetime(LastProcessedDateTime),\n LastUpdate = todatetime(LastUpdate),\n LastFound = todatetime(LastFound)\n | extend DetectionTime = coalesce(LastProcessedDateTime, LastUpdate, LastFound, todatetime(TimeGenerated))\n};\nlet threshold = 10;\nQualysHostDetection\n| extend Status = tostring(Status), Vulnerability = tostring(QID), Severity = tostring(Severity)\n| where Status =~ \"New\" and Severity == \"5\"\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), dcount(NetBios), RepresentativeHost = take_anyif(NetBios, isnotempty(NetBios)) by tostring(QID)\n| where dcount_NetBios >= threshold\n| extend timestamp = StartTime\n", "queryFrequency": "PT1H", "queryPeriod": "PT1H", "severity": "Medium", @@ -1342,10 +1394,10 @@ "status": "Available", "requiredDataConnectors": [ { - "connectorId": "QualysVMLogsCCPDefinition", "dataTypes": [ "QualysHostDetection" - ] + ], + "connectorId": "QualysVMLogsCCPDefinition" } ], "tactics": [ @@ -1353,6 +1405,17 @@ ], "techniques": [ "T1190" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "identifier": "NetBiosName", + "columnName": "RepresentativeHost" + } + ], + "entityType": "Host" + } ] } }, @@ -1396,7 +1459,8 @@ "contentProductId": "[variables('analyticRuleObject2')._analyticRulecontentProductId2]", "id": "[variables('analyticRuleObject2')._analyticRulecontentProductId2]", "version": "[variables('analyticRuleObject2').analyticRuleVersion2]" - } + }, + "condition": "[parameters('DeployAnalyticsRule')]" }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", @@ -1407,7 +1471,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "QualysCustomConnector Playbook with template version 3.1.1", + "description": "QualysCustomConnector Playbook with template version 3.2.2", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('playbookVersion1')]", @@ -3046,7 +3110,8 @@ "contentProductId": "[variables('_playbookcontentProductId1')]", "id": "[variables('_playbookcontentProductId1')]", "version": "[variables('playbookVersion1')]" - } + }, + "condition": "[parameters('DeployPlaybook')]" }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", @@ -3057,7 +3122,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "QualysVM-GetAssetDetails Playbook with template version 3.1.1", + "description": "QualysVM-GetAssetDetails Playbook with template version 3.2.2", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('playbookVersion2')]", @@ -3559,7 +3624,8 @@ "contentProductId": "[variables('_playbookcontentProductId2')]", "id": "[variables('_playbookcontentProductId2')]", "version": "[variables('playbookVersion2')]" - } + }, + "condition": "[parameters('DeployPlaybook')]" }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", @@ -3570,7 +3636,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "QualysVM-GetAssets-ByCVEID Playbook with template version 3.1.1", + "description": "QualysVM-GetAssets-ByCVEID Playbook with template version 3.2.2", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('playbookVersion3')]", @@ -4643,7 +4709,8 @@ "contentProductId": "[variables('_playbookcontentProductId3')]", "id": "[variables('_playbookcontentProductId3')]", "version": "[variables('playbookVersion3')]" - } + }, + "condition": "[parameters('DeployPlaybook')]" }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", @@ -4654,7 +4721,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "QualysVM-GetAssets-ByOpenPort Playbook with template version 3.1.1", + "description": "QualysVM-GetAssets-ByOpenPort Playbook with template version 3.2.2", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('playbookVersion4')]", @@ -5602,7 +5669,8 @@ "contentProductId": "[variables('_playbookcontentProductId4')]", "id": "[variables('_playbookcontentProductId4')]", "version": "[variables('playbookVersion4')]" - } + }, + "condition": "[parameters('DeployPlaybook')]" }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", @@ -5613,7 +5681,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "QualysVM-LaunchVMScan-GenerateReport Playbook with template version 3.1.1", + "description": "QualysVM-LaunchVMScan-GenerateReport Playbook with template version 3.2.2", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('playbookVersion5')]", @@ -8259,19 +8327,20 @@ "contentProductId": "[variables('_playbookcontentProductId5')]", "id": "[variables('_playbookcontentProductId5')]", "version": "[variables('playbookVersion5')]" - } + }, + "condition": "[parameters('DeployPlaybook')]" }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentPackages", "apiVersion": "2023-04-01-preview", "location": "[parameters('workspace-location')]", "properties": { - "version": "3.1.1", + "version": "3.2.2", "kind": "Solution", "contentSchemaVersion": "3.0.0", "displayName": "QualysVM", "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.

\n

The Qualys Vulnerability Management solution for Microsoft Sentinel enables you to ingest host vulnerability detection data into Microsoft Sentinel.

\n

Underlying Microsoft Technologies used:

\n

This 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

• Microsoft Sentinel Codeless Connector Framework

\n

Data Connectors: 1, Parsers: 1, Workbooks: 1, Analytic Rules: 2, Custom Azure Logic Apps Connectors: 1, Playbooks: 4

\n

Learn 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.

\n

The Qualys Vulnerability Management solution for Microsoft Sentinel enables you to ingest host vulnerability detection data into Microsoft Sentinel.

\n

Underlying Microsoft Technologies used:

\n

This 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

• Microsoft Sentinel Codeless Connector Framework

\n

Data Connectors: 1, Parsers: 1, Workbooks: 1, Analytic Rules: 2, XDR Detections: 2, Custom Azure Logic Apps Connectors: 1, Playbooks: 4

\n

Learn more about Microsoft Sentinel | Learn more about Solutions

\n", "contentKind": "Solution", "contentProductId": "[variables('_solutioncontentProductId')]", "id": "[variables('_solutioncontentProductId')]", @@ -8345,6 +8414,16 @@ "kind": "Playbook", "contentId": "[variables('_QualysVM-LaunchVMScan-GenerateReport')]", "version": "[variables('playbookVersion5')]" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-3edb7215-250b-40c0-8b46-79093949242d", + "version": "3.2.1" + }, + { + "kind": "CustomDetection", + "contentId": "xdr-6116dc19-475a-4148-84b2-efe89c073e27", + "version": "3.2.1" } ] }, @@ -8361,6 +8440,401 @@ } }, "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/', variables('_solutionId'))]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "QualysVM-CD-xdr-3edb7215-250b-40c0-8b46-79093949242d", + "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-3edb7215-250b-40c0-8b46-79093949242d', 'xdr-3edb7215-250b-40c0-8b46-79093949242d')]", + "queryCondition": { + "queryText": "let __xdr_inline_QualysHostDetection = view () {\nlet QualysHostDetection_view = view () {\n QualysHostDetection_CL\n | mv-expand todynamic(Detections_s)\n | extend\n Severity_s = tostring(Detections_s.Severity),\n Status_s = tostring(Detections_s.Status),\n QID_s = tostring(Detections_s.Results)\n | extend\n TenantId = column_ifexists('TenantId', ''),\n SourceSystem = column_ifexists('SourceSystem', ''),\n MG = column_ifexists('MG', ''),\n ManagementGroupName = column_ifexists('ManagementGroupName', ''),\n TimeGenerated = column_ifexists('TimeGenerated', ''),\n Computer = column_ifexists('Computer', ''),\n RawData = column_ifexists('RawData', ''),\n Id = column_ifexists('Id_s', ''),\n HostId = column_ifexists('HostId_s', ''),\n HostTags = column_ifexists('HostTags_s', ''),\n IPAddress = column_ifexists('IPAddress', ''),\n TrackingMethod = column_ifexists('TrackingMethod_s', ''),\n OperatingSystem = column_ifexists('OperatingSystem_s', ''),\n DnsName = column_ifexists('DnsName_s', ''),\n NetBios = column_ifexists('NetBios_s', ''),\n QGHostId = column_ifexists('QGHostId_g', ''),\n LastScanDateTime = column_ifexists('LastScanDateTime_t', ''),\n LastVMScannedDateTime = column_ifexists('LastVMScannedDateTime_t', ''),\n LastVMAuthScannedDateTime = column_ifexists('LastVMAuthScannedDateTime_t', ''),\n QID = column_ifexists('QID_s', ''),\n SSL = column_ifexists('SSL_s', ''),\n Status = column_ifexists('Status_s', ''),\n Ignored = column_ifexists('Ignored_s', ''),\n Severity = column_ifexists('Severity_s', ''),\n Disabled = column_ifexists('Disabled_s', ''),\n LastFixed = column_ifexists('LastFixed_t', ''),\n LastFound = column_ifexists('LastFound_t', ''),\n TimesFound = column_ifexists('TimesFound_s', ''),\n FirstFound = column_ifexists('FirstFound_t', ''),\n LastUpdate = column_ifexists('LastUpdate_t', datetime(null)),\n LastProcessedDateTime = column_ifexists('LastProcessed_t', datetime(null)),\n Result_column_count = tostring(column_ifexists('Result_column_count_d', '')),\n Results_0 = column_ifexists('Results_0_s', ''),\n Type = column_ifexists('Type', ''),\n _ResourceId = column_ifexists('_ResourceId', '')\n };\n let QualysHostDetectionV2_view = view () {\n QualysHostDetectionV2_CL\n | extend\n TenantId = column_ifexists('TenantId', ''),\n SourceSystem = column_ifexists('SourceSystem', ''),\n MG = column_ifexists('MG', ''),\n ManagementGroupName = column_ifexists('ManagementGroupName', ''),\n TimeGenerated = column_ifexists('TimeGenerated', ''),\n Computer = column_ifexists('Computer', ''),\n RawData = column_ifexists('RawData', ''),\n Id = column_ifexists('Id_s', ''),\n HostId = column_ifexists('HostId_s', ''),\n IPAddress = column_ifexists('IPAddress', ''),\n TrackingMethod = column_ifexists('TrackingMethod_s', ''),\n OperatingSystem = column_ifexists('OperatingSystem_s', ''),\n DnsName = column_ifexists('DnsName_s', ''),\n NetBios = column_ifexists('NetBios_s', ''),\n QGHostId = column_ifexists('QGHostId_g', ''),\n LastScanDateTime = column_ifexists('LastScanDateTime_t', ''),\n LastVMScannedDateTime = column_ifexists('LastVMScannedDateTime_t', ''),\n LastVMAuthScannedDateTime = column_ifexists('LastVMAuthScannedDateTime_t', ''),\n QID = column_ifexists('QID_s', ''),\n SSL = column_ifexists('SSL_s', ''),\n Status = column_ifexists('Status_s', ''),\n Ignored = column_ifexists('Ignored_s', ''),\n Severity = column_ifexists('Severity_s', ''),\n Disabled = column_ifexists('Disabled_s', ''),\n LastFixed = column_ifexists('LastFixed_t', ''),\n LastFound = column_ifexists('LastFound_t', ''),\n TimesFound = column_ifexists('TimesFound_s', ''),\n FirstFound = column_ifexists('FirstFound_t', ''),\n LastUpdate = column_ifexists('LastUpdate_t', datetime(null)),\n LastProcessedDateTime = column_ifexists('LastProcessed_t', datetime(null)),\n Result_column_count = tostring(column_ifexists('Result_column_count_d', '')),\n Results_0 = column_ifexists('Results_0_s', ''),\n Type = column_ifexists('Type', ''),\n _ResourceId = column_ifexists('_ResourceId', '')\n };\n let QualysHostDetectionV3_view = view () {\n QualysHostDetectionV3_CL\n | extend DetectionList = todynamic(DetectionList)\n | extend DetectionItems = iff(\n gettype(DetectionList.DETECTION) == \"array\",\n DetectionList.DETECTION,\n pack_array(DetectionList.DETECTION)\n )\n | mv-expand Detections = DetectionItems to typeof(dynamic)\n | extend\n TenantId = column_ifexists('TenantId', ''),\n SourceSystem = column_ifexists('SourceSystem', ''),\n MG = column_ifexists('MG', ''),\n ManagementGroupName = column_ifexists('ManagementGroupName', ''),\n TimeGenerated = column_ifexists('TimeGenerated', ''),\n Computer = column_ifexists('Computer', ''),\n RawData = column_ifexists('RawData', ''),\n Id = column_ifexists('Id', ''),\n HostId = column_ifexists('HostId', ''),\n HostTags = column_ifexists('HostTags', ''),\n IPAddress = column_ifexists('IPAddress', ''),\n TrackingMethod = column_ifexists('TrackingMethod', ''),\n OperatingSystem = column_ifexists('OperatingSystem', ''),\n DnsName = column_ifexists('DnsName', ''),\n NetBios = column_ifexists('NetBios', ''),\n QGHostId = column_ifexists('QGHostId', ''),\n LastScanDateTime = column_ifexists('LastScanDateTime', ''),\n LastVMScannedDateTime = column_ifexists('LastVMScannedDateTime', ''),\n LastVMAuthScannedDateTime = column_ifexists('LastVMAuthScannedDateTime', ''),\n QID = tostring(Detections.QID),\n SSL = tostring(Detections.SSL),\n Status = tostring(Detections.STATUS),\n Ignored = tostring(Detections.IS_IGNORED),\n Severity = tostring(Detections.SEVERITY),\n Disabled = tostring(Detections.IS_DISABLED),\n LastFixed = todatetime(Detections.LAST_FIXED_DATETIME),\n LastFound = todatetime(Detections.LAST_FOUND_DATETIME),\n TimesFound = tostring(Detections.TIMES_FOUND),\n FirstFound = todatetime(Detections.FIRST_FOUND_DATETIME),\n LastUpdate = todatetime(Detections.LAST_UPDATE_DATETIME),\n LastProcessedDateTime = coalesce(\n todatetime(Detections.LAST_PROCESSED_DATETIME),\n todatetime(Detections.LAST_PROCESSED_DATE)),\n Results_0 = tostring(coalesce(Detections.RESULTS['#cdata-section'], Detections.RESULTS)),\n Result_column_count = \"1\",\n Type = tostring(Detections.TYPE),\n _ResourceId = column_ifexists('_ResourceId', '')\n | extend _IngestionTime = todatetime(TimeGenerated)\n | summarize arg_max(_IngestionTime, *) by HostId, QID, Status, SSL, Ignored, Severity, Disabled, LastFixed, LastFound, TimesFound, FirstFound, Result_column_count, Results_0, Type\n | project-away _IngestionTime\n };\n union isfuzzy=true\n (QualysHostDetection_view),\n (QualysHostDetectionV2_view),\n (QualysHostDetectionV3_view)\n | project\n TenantId,\n SourceSystem,\n MG,\n ManagementGroupName,\n TimeGenerated,\n Computer,\n RawData,\n Id,\n HostId,\n HostTags,\n IPAddress,\n TrackingMethod,\n OperatingSystem,\n DnsName,\n NetBios,\n QGHostId,\n LastScanDateTime,\n LastVMScannedDateTime,\n LastVMAuthScannedDateTime,\n QID,\n SSL,\n Type,\n Status,\n Ignored,\n Severity,\n Disabled,\n LastFixed,\n LastFound,\n TimesFound,\n FirstFound,\n LastUpdate,\n LastProcessedDateTime,\n Result_column_count,\n Results_0,\n _ResourceId\n | extend\n HostId = tostring(HostId),\n QID = tostring(QID),\n Status = tostring(Status),\n LastProcessedDateTime = todatetime(LastProcessedDateTime),\n LastUpdate = todatetime(LastUpdate),\n LastFound = todatetime(LastFound)\n | extend DetectionTime = coalesce(LastProcessedDateTime, LastUpdate, LastFound, todatetime(TimeGenerated))\n};\nlet threshold = 10;\n__xdr_inline_QualysHostDetection\n| where Severity == \"5\"\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), count() by NetBios, IPAddress\n| where count_ >= threshold" + }, + "displayName": "High Number of Urgent Vulnerabilities Detected", + "detectionAction": { + "alertTemplate": { + "customDetails": { + "HostFullName": "NetBios" + }, + "severity": "medium", + "title": "High Number of Urgent Vulnerabilities Detected", + "entityMappings": { + "hosts": [ + { + "netBiosNameColumn": "NetBios", + "id": "[if(true(), 'host1', 'host1')]" + } + ], + "ips": [ + { + "addressColumn": "IPAddress", + "id": "[if(true(), 'ip1', 'ip1')]" + } + ] + }, + "tactics": [ + { + "tactic": "InitialAccess", + "techniques": [ + { + "technique": "T1190" + } + ] + } + ], + "description": "'This creates an incident when a host has a high number of urgent, severity 5, vulnerabilities detected.'" + } + }, + "status": "disabled", + "schedule": { + "frequency": "PT1H" + }, + "contentProvenance": { + "packageId": "azuresentinel.azure-sentinel-qualysvm", + "packageVersion": "3.2.2", + "contentId": "xdr-3edb7215-250b-40c0-8b46-79093949242d", + "contentVersion": "3.2.1" + } + } + } + } + } + }, + "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-3edb7215-250b-40c0-8b46-79093949242d')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'QualysVM-CD-xdr-3edb7215-250b-40c0-8b46-79093949242d')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'This creates an incident when a host has a high number of urgent, severity 5, vulnerabilities detected.'", + "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-3edb7215-250b-40c0-8b46-79093949242d', 'xdr-3edb7215-250b-40c0-8b46-79093949242d')]", + "queryCondition": { + "queryText": "let __xdr_inline_QualysHostDetection = view () {\nlet QualysHostDetection_view = view () {\n QualysHostDetection_CL\n | mv-expand todynamic(Detections_s)\n | extend\n Severity_s = tostring(Detections_s.Severity),\n Status_s = tostring(Detections_s.Status),\n QID_s = tostring(Detections_s.Results)\n | extend\n TenantId = column_ifexists('TenantId', ''),\n SourceSystem = column_ifexists('SourceSystem', ''),\n MG = column_ifexists('MG', ''),\n ManagementGroupName = column_ifexists('ManagementGroupName', ''),\n TimeGenerated = column_ifexists('TimeGenerated', ''),\n Computer = column_ifexists('Computer', ''),\n RawData = column_ifexists('RawData', ''),\n Id = column_ifexists('Id_s', ''),\n HostId = column_ifexists('HostId_s', ''),\n HostTags = column_ifexists('HostTags_s', ''),\n IPAddress = column_ifexists('IPAddress', ''),\n TrackingMethod = column_ifexists('TrackingMethod_s', ''),\n OperatingSystem = column_ifexists('OperatingSystem_s', ''),\n DnsName = column_ifexists('DnsName_s', ''),\n NetBios = column_ifexists('NetBios_s', ''),\n QGHostId = column_ifexists('QGHostId_g', ''),\n LastScanDateTime = column_ifexists('LastScanDateTime_t', ''),\n LastVMScannedDateTime = column_ifexists('LastVMScannedDateTime_t', ''),\n LastVMAuthScannedDateTime = column_ifexists('LastVMAuthScannedDateTime_t', ''),\n QID = column_ifexists('QID_s', ''),\n SSL = column_ifexists('SSL_s', ''),\n Status = column_ifexists('Status_s', ''),\n Ignored = column_ifexists('Ignored_s', ''),\n Severity = column_ifexists('Severity_s', ''),\n Disabled = column_ifexists('Disabled_s', ''),\n LastFixed = column_ifexists('LastFixed_t', ''),\n LastFound = column_ifexists('LastFound_t', ''),\n TimesFound = column_ifexists('TimesFound_s', ''),\n FirstFound = column_ifexists('FirstFound_t', ''),\n LastUpdate = column_ifexists('LastUpdate_t', datetime(null)),\n LastProcessedDateTime = column_ifexists('LastProcessed_t', datetime(null)),\n Result_column_count = tostring(column_ifexists('Result_column_count_d', '')),\n Results_0 = column_ifexists('Results_0_s', ''),\n Type = column_ifexists('Type', ''),\n _ResourceId = column_ifexists('_ResourceId', '')\n };\n let QualysHostDetectionV2_view = view () {\n QualysHostDetectionV2_CL\n | extend\n TenantId = column_ifexists('TenantId', ''),\n SourceSystem = column_ifexists('SourceSystem', ''),\n MG = column_ifexists('MG', ''),\n ManagementGroupName = column_ifexists('ManagementGroupName', ''),\n TimeGenerated = column_ifexists('TimeGenerated', ''),\n Computer = column_ifexists('Computer', ''),\n RawData = column_ifexists('RawData', ''),\n Id = column_ifexists('Id_s', ''),\n HostId = column_ifexists('HostId_s', ''),\n IPAddress = column_ifexists('IPAddress', ''),\n TrackingMethod = column_ifexists('TrackingMethod_s', ''),\n OperatingSystem = column_ifexists('OperatingSystem_s', ''),\n DnsName = column_ifexists('DnsName_s', ''),\n NetBios = column_ifexists('NetBios_s', ''),\n QGHostId = column_ifexists('QGHostId_g', ''),\n LastScanDateTime = column_ifexists('LastScanDateTime_t', ''),\n LastVMScannedDateTime = column_ifexists('LastVMScannedDateTime_t', ''),\n LastVMAuthScannedDateTime = column_ifexists('LastVMAuthScannedDateTime_t', ''),\n QID = column_ifexists('QID_s', ''),\n SSL = column_ifexists('SSL_s', ''),\n Status = column_ifexists('Status_s', ''),\n Ignored = column_ifexists('Ignored_s', ''),\n Severity = column_ifexists('Severity_s', ''),\n Disabled = column_ifexists('Disabled_s', ''),\n LastFixed = column_ifexists('LastFixed_t', ''),\n LastFound = column_ifexists('LastFound_t', ''),\n TimesFound = column_ifexists('TimesFound_s', ''),\n FirstFound = column_ifexists('FirstFound_t', ''),\n LastUpdate = column_ifexists('LastUpdate_t', datetime(null)),\n LastProcessedDateTime = column_ifexists('LastProcessed_t', datetime(null)),\n Result_column_count = tostring(column_ifexists('Result_column_count_d', '')),\n Results_0 = column_ifexists('Results_0_s', ''),\n Type = column_ifexists('Type', ''),\n _ResourceId = column_ifexists('_ResourceId', '')\n };\n let QualysHostDetectionV3_view = view () {\n QualysHostDetectionV3_CL\n | extend DetectionList = todynamic(DetectionList)\n | extend DetectionItems = iff(\n gettype(DetectionList.DETECTION) == \"array\",\n DetectionList.DETECTION,\n pack_array(DetectionList.DETECTION)\n )\n | mv-expand Detections = DetectionItems to typeof(dynamic)\n | extend\n TenantId = column_ifexists('TenantId', ''),\n SourceSystem = column_ifexists('SourceSystem', ''),\n MG = column_ifexists('MG', ''),\n ManagementGroupName = column_ifexists('ManagementGroupName', ''),\n TimeGenerated = column_ifexists('TimeGenerated', ''),\n Computer = column_ifexists('Computer', ''),\n RawData = column_ifexists('RawData', ''),\n Id = column_ifexists('Id', ''),\n HostId = column_ifexists('HostId', ''),\n HostTags = column_ifexists('HostTags', ''),\n IPAddress = column_ifexists('IPAddress', ''),\n TrackingMethod = column_ifexists('TrackingMethod', ''),\n OperatingSystem = column_ifexists('OperatingSystem', ''),\n DnsName = column_ifexists('DnsName', ''),\n NetBios = column_ifexists('NetBios', ''),\n QGHostId = column_ifexists('QGHostId', ''),\n LastScanDateTime = column_ifexists('LastScanDateTime', ''),\n LastVMScannedDateTime = column_ifexists('LastVMScannedDateTime', ''),\n LastVMAuthScannedDateTime = column_ifexists('LastVMAuthScannedDateTime', ''),\n QID = tostring(Detections.QID),\n SSL = tostring(Detections.SSL),\n Status = tostring(Detections.STATUS),\n Ignored = tostring(Detections.IS_IGNORED),\n Severity = tostring(Detections.SEVERITY),\n Disabled = tostring(Detections.IS_DISABLED),\n LastFixed = todatetime(Detections.LAST_FIXED_DATETIME),\n LastFound = todatetime(Detections.LAST_FOUND_DATETIME),\n TimesFound = tostring(Detections.TIMES_FOUND),\n FirstFound = todatetime(Detections.FIRST_FOUND_DATETIME),\n LastUpdate = todatetime(Detections.LAST_UPDATE_DATETIME),\n LastProcessedDateTime = coalesce(\n todatetime(Detections.LAST_PROCESSED_DATETIME),\n todatetime(Detections.LAST_PROCESSED_DATE)),\n Results_0 = tostring(coalesce(Detections.RESULTS['#cdata-section'], Detections.RESULTS)),\n Result_column_count = \"1\",\n Type = tostring(Detections.TYPE),\n _ResourceId = column_ifexists('_ResourceId', '')\n | extend _IngestionTime = todatetime(TimeGenerated)\n | summarize arg_max(_IngestionTime, *) by HostId, QID, Status, SSL, Ignored, Severity, Disabled, LastFixed, LastFound, TimesFound, FirstFound, Result_column_count, Results_0, Type\n | project-away _IngestionTime\n };\n union isfuzzy=true\n (QualysHostDetection_view),\n (QualysHostDetectionV2_view),\n (QualysHostDetectionV3_view)\n | project\n TenantId,\n SourceSystem,\n MG,\n ManagementGroupName,\n TimeGenerated,\n Computer,\n RawData,\n Id,\n HostId,\n HostTags,\n IPAddress,\n TrackingMethod,\n OperatingSystem,\n DnsName,\n NetBios,\n QGHostId,\n LastScanDateTime,\n LastVMScannedDateTime,\n LastVMAuthScannedDateTime,\n QID,\n SSL,\n Type,\n Status,\n Ignored,\n Severity,\n Disabled,\n LastFixed,\n LastFound,\n TimesFound,\n FirstFound,\n LastUpdate,\n LastProcessedDateTime,\n Result_column_count,\n Results_0,\n _ResourceId\n | extend\n HostId = tostring(HostId),\n QID = tostring(QID),\n Status = tostring(Status),\n LastProcessedDateTime = todatetime(LastProcessedDateTime),\n LastUpdate = todatetime(LastUpdate),\n LastFound = todatetime(LastFound)\n | extend DetectionTime = coalesce(LastProcessedDateTime, LastUpdate, LastFound, todatetime(TimeGenerated))\n};\nlet threshold = 10;\n__xdr_inline_QualysHostDetection\n| where Severity == \"5\"\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), count() by NetBios, IPAddress\n| where count_ >= threshold" + }, + "displayName": "High Number of Urgent Vulnerabilities Detected", + "detectionAction": { + "alertTemplate": { + "customDetails": { + "HostFullName": "NetBios" + }, + "severity": "medium", + "title": "High Number of Urgent Vulnerabilities Detected", + "entityMappings": { + "hosts": [ + { + "netBiosNameColumn": "NetBios", + "id": "[if(true(), 'host1', 'host1')]" + } + ], + "ips": [ + { + "addressColumn": "IPAddress", + "id": "[if(true(), 'ip1', 'ip1')]" + } + ] + }, + "tactics": [ + { + "tactic": "InitialAccess", + "techniques": [ + { + "technique": "T1190" + } + ] + } + ], + "description": "'This creates an incident when a host has a high number of urgent, severity 5, vulnerabilities detected.'" + } + }, + "status": "disabled", + "schedule": { + "frequency": "PT1H" + }, + "contentProvenance": { + "packageId": "azuresentinel.azure-sentinel-qualysvm", + "packageVersion": "3.2.2", + "contentId": "xdr-3edb7215-250b-40c0-8b46-79093949242d", + "contentVersion": "3.2.1" + } + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-3edb7215-250b-40c0-8b46-79093949242d", + "contentKind": "CustomDetection", + "displayName": "High Number of Urgent Vulnerabilities Detected", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-3edb7215-250b-40c0-8b46-79093949242d','-','3.2.1')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-3edb7215-250b-40c0-8b46-79093949242d','-','3.2.1')))]", + "version": "3.2.1", + "contentProvenance": { + "packageId": "azuresentinel.azure-sentinel-qualysvm", + "packageVersion": "3.2.2", + "contentId": "xdr-3edb7215-250b-40c0-8b46-79093949242d", + "contentVersion": "3.2.1", + "requiredWorkloads": [ + { + "workload": "sentinel", + "dataTypes": [ + "QualysHostDetection_CL", + "QualysHostDetectionV2_CL", + "QualysHostDetectionV3_CL" + ] + } + ], + "requiredDataConnectors": [ + { + "dataTypes": [ + "QualysHostDetection" + ], + "connectorId": "QualysVMLogsCCPDefinition" + } + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "QualysVM-CD-xdr-6116dc19-475a-4148-84b2-efe89c073e27", + "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-6116dc19-475a-4148-84b2-efe89c073e27', 'xdr-6116dc19-475a-4148-84b2-efe89c073e27')]", + "queryCondition": { + "queryText": "let __xdr_inline_QualysHostDetection = view () {\nlet QualysHostDetection_view = view () {\n QualysHostDetection_CL\n | mv-expand todynamic(Detections_s)\n | extend\n Severity_s = tostring(Detections_s.Severity),\n Status_s = tostring(Detections_s.Status),\n QID_s = tostring(Detections_s.Results)\n | extend\n TenantId = column_ifexists('TenantId', ''),\n SourceSystem = column_ifexists('SourceSystem', ''),\n MG = column_ifexists('MG', ''),\n ManagementGroupName = column_ifexists('ManagementGroupName', ''),\n TimeGenerated = column_ifexists('TimeGenerated', ''),\n Computer = column_ifexists('Computer', ''),\n RawData = column_ifexists('RawData', ''),\n Id = column_ifexists('Id_s', ''),\n HostId = column_ifexists('HostId_s', ''),\n HostTags = column_ifexists('HostTags_s', ''),\n IPAddress = column_ifexists('IPAddress', ''),\n TrackingMethod = column_ifexists('TrackingMethod_s', ''),\n OperatingSystem = column_ifexists('OperatingSystem_s', ''),\n DnsName = column_ifexists('DnsName_s', ''),\n NetBios = column_ifexists('NetBios_s', ''),\n QGHostId = column_ifexists('QGHostId_g', ''),\n LastScanDateTime = column_ifexists('LastScanDateTime_t', ''),\n LastVMScannedDateTime = column_ifexists('LastVMScannedDateTime_t', ''),\n LastVMAuthScannedDateTime = column_ifexists('LastVMAuthScannedDateTime_t', ''),\n QID = column_ifexists('QID_s', ''),\n SSL = column_ifexists('SSL_s', ''),\n Status = column_ifexists('Status_s', ''),\n Ignored = column_ifexists('Ignored_s', ''),\n Severity = column_ifexists('Severity_s', ''),\n Disabled = column_ifexists('Disabled_s', ''),\n LastFixed = column_ifexists('LastFixed_t', ''),\n LastFound = column_ifexists('LastFound_t', ''),\n TimesFound = column_ifexists('TimesFound_s', ''),\n FirstFound = column_ifexists('FirstFound_t', ''),\n LastUpdate = column_ifexists('LastUpdate_t', datetime(null)),\n LastProcessedDateTime = column_ifexists('LastProcessed_t', datetime(null)),\n Result_column_count = tostring(column_ifexists('Result_column_count_d', '')),\n Results_0 = column_ifexists('Results_0_s', ''),\n Type = column_ifexists('Type', ''),\n _ResourceId = column_ifexists('_ResourceId', '')\n };\n let QualysHostDetectionV2_view = view () {\n QualysHostDetectionV2_CL\n | extend\n TenantId = column_ifexists('TenantId', ''),\n SourceSystem = column_ifexists('SourceSystem', ''),\n MG = column_ifexists('MG', ''),\n ManagementGroupName = column_ifexists('ManagementGroupName', ''),\n TimeGenerated = column_ifexists('TimeGenerated', ''),\n Computer = column_ifexists('Computer', ''),\n RawData = column_ifexists('RawData', ''),\n Id = column_ifexists('Id_s', ''),\n HostId = column_ifexists('HostId_s', ''),\n IPAddress = column_ifexists('IPAddress', ''),\n TrackingMethod = column_ifexists('TrackingMethod_s', ''),\n OperatingSystem = column_ifexists('OperatingSystem_s', ''),\n DnsName = column_ifexists('DnsName_s', ''),\n NetBios = column_ifexists('NetBios_s', ''),\n QGHostId = column_ifexists('QGHostId_g', ''),\n LastScanDateTime = column_ifexists('LastScanDateTime_t', ''),\n LastVMScannedDateTime = column_ifexists('LastVMScannedDateTime_t', ''),\n LastVMAuthScannedDateTime = column_ifexists('LastVMAuthScannedDateTime_t', ''),\n QID = column_ifexists('QID_s', ''),\n SSL = column_ifexists('SSL_s', ''),\n Status = column_ifexists('Status_s', ''),\n Ignored = column_ifexists('Ignored_s', ''),\n Severity = column_ifexists('Severity_s', ''),\n Disabled = column_ifexists('Disabled_s', ''),\n LastFixed = column_ifexists('LastFixed_t', ''),\n LastFound = column_ifexists('LastFound_t', ''),\n TimesFound = column_ifexists('TimesFound_s', ''),\n FirstFound = column_ifexists('FirstFound_t', ''),\n LastUpdate = column_ifexists('LastUpdate_t', datetime(null)),\n LastProcessedDateTime = column_ifexists('LastProcessed_t', datetime(null)),\n Result_column_count = tostring(column_ifexists('Result_column_count_d', '')),\n Results_0 = column_ifexists('Results_0_s', ''),\n Type = column_ifexists('Type', ''),\n _ResourceId = column_ifexists('_ResourceId', '')\n };\n let QualysHostDetectionV3_view = view () {\n QualysHostDetectionV3_CL\n | extend DetectionList = todynamic(DetectionList)\n | extend DetectionItems = iff(\n gettype(DetectionList.DETECTION) == \"array\",\n DetectionList.DETECTION,\n pack_array(DetectionList.DETECTION)\n )\n | mv-expand Detections = DetectionItems to typeof(dynamic)\n | extend\n TenantId = column_ifexists('TenantId', ''),\n SourceSystem = column_ifexists('SourceSystem', ''),\n MG = column_ifexists('MG', ''),\n ManagementGroupName = column_ifexists('ManagementGroupName', ''),\n TimeGenerated = column_ifexists('TimeGenerated', ''),\n Computer = column_ifexists('Computer', ''),\n RawData = column_ifexists('RawData', ''),\n Id = column_ifexists('Id', ''),\n HostId = column_ifexists('HostId', ''),\n HostTags = column_ifexists('HostTags', ''),\n IPAddress = column_ifexists('IPAddress', ''),\n TrackingMethod = column_ifexists('TrackingMethod', ''),\n OperatingSystem = column_ifexists('OperatingSystem', ''),\n DnsName = column_ifexists('DnsName', ''),\n NetBios = column_ifexists('NetBios', ''),\n QGHostId = column_ifexists('QGHostId', ''),\n LastScanDateTime = column_ifexists('LastScanDateTime', ''),\n LastVMScannedDateTime = column_ifexists('LastVMScannedDateTime', ''),\n LastVMAuthScannedDateTime = column_ifexists('LastVMAuthScannedDateTime', ''),\n QID = tostring(Detections.QID),\n SSL = tostring(Detections.SSL),\n Status = tostring(Detections.STATUS),\n Ignored = tostring(Detections.IS_IGNORED),\n Severity = tostring(Detections.SEVERITY),\n Disabled = tostring(Detections.IS_DISABLED),\n LastFixed = todatetime(Detections.LAST_FIXED_DATETIME),\n LastFound = todatetime(Detections.LAST_FOUND_DATETIME),\n TimesFound = tostring(Detections.TIMES_FOUND),\n FirstFound = todatetime(Detections.FIRST_FOUND_DATETIME),\n LastUpdate = todatetime(Detections.LAST_UPDATE_DATETIME),\n LastProcessedDateTime = coalesce(\n todatetime(Detections.LAST_PROCESSED_DATETIME),\n todatetime(Detections.LAST_PROCESSED_DATE)),\n Results_0 = tostring(coalesce(Detections.RESULTS['#cdata-section'], Detections.RESULTS)),\n Result_column_count = \"1\",\n Type = tostring(Detections.TYPE),\n _ResourceId = column_ifexists('_ResourceId', '')\n | extend _IngestionTime = todatetime(TimeGenerated)\n | summarize arg_max(_IngestionTime, *) by HostId, QID, Status, SSL, Ignored, Severity, Disabled, LastFixed, LastFound, TimesFound, FirstFound, Result_column_count, Results_0, Type\n | project-away _IngestionTime\n };\n union isfuzzy=true\n (QualysHostDetection_view),\n (QualysHostDetectionV2_view),\n (QualysHostDetectionV3_view)\n | project\n TenantId,\n SourceSystem,\n MG,\n ManagementGroupName,\n TimeGenerated,\n Computer,\n RawData,\n Id,\n HostId,\n HostTags,\n IPAddress,\n TrackingMethod,\n OperatingSystem,\n DnsName,\n NetBios,\n QGHostId,\n LastScanDateTime,\n LastVMScannedDateTime,\n LastVMAuthScannedDateTime,\n QID,\n SSL,\n Type,\n Status,\n Ignored,\n Severity,\n Disabled,\n LastFixed,\n LastFound,\n TimesFound,\n FirstFound,\n LastUpdate,\n LastProcessedDateTime,\n Result_column_count,\n Results_0,\n _ResourceId\n | extend\n HostId = tostring(HostId),\n QID = tostring(QID),\n Status = tostring(Status),\n LastProcessedDateTime = todatetime(LastProcessedDateTime),\n LastUpdate = todatetime(LastUpdate),\n LastFound = todatetime(LastFound)\n | extend DetectionTime = coalesce(LastProcessedDateTime, LastUpdate, LastFound, todatetime(TimeGenerated))\n};\nlet threshold = 10;\n__xdr_inline_QualysHostDetection\n| extend Status = tostring(Status), Vulnerability = tostring(QID), Severity = tostring(Severity)\n| where Status =~ \"New\" and Severity == \"5\"\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), dcount(NetBios), RepresentativeHost = take_anyif(NetBios, isnotempty(NetBios)) by tostring(QID)\n| where dcount_NetBios >= threshold\n| extend timestamp = StartTime" + }, + "displayName": "New High Severity Vulnerability Detected Across Multiple Hosts", + "detectionAction": { + "alertTemplate": { + "severity": "medium", + "entityMappings": { + "hosts": [ + { + "netBiosNameColumn": "RepresentativeHost", + "id": "[if(true(), 'host1', 'host1')]" + } + ] + }, + "title": "New High Severity Vulnerability Detected Across Multiple Hosts", + "description": "'This creates an incident when a new high severity vulnerability is detected across multilple hosts'", + "tactics": [ + { + "tactic": "InitialAccess", + "techniques": [ + { + "technique": "T1190" + } + ] + } + ] + } + }, + "status": "disabled", + "schedule": { + "frequency": "PT1H" + }, + "contentProvenance": { + "packageId": "azuresentinel.azure-sentinel-qualysvm", + "packageVersion": "3.2.2", + "contentId": "xdr-6116dc19-475a-4148-84b2-efe89c073e27", + "contentVersion": "3.2.1" + } + } + } + } + } + }, + "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-6116dc19-475a-4148-84b2-efe89c073e27')))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'QualysVM-CD-xdr-6116dc19-475a-4148-84b2-efe89c073e27')]", + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "'This creates an incident when a new high severity vulnerability is detected across multilple hosts'", + "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-6116dc19-475a-4148-84b2-efe89c073e27', 'xdr-6116dc19-475a-4148-84b2-efe89c073e27')]", + "queryCondition": { + "queryText": "let __xdr_inline_QualysHostDetection = view () {\nlet QualysHostDetection_view = view () {\n QualysHostDetection_CL\n | mv-expand todynamic(Detections_s)\n | extend\n Severity_s = tostring(Detections_s.Severity),\n Status_s = tostring(Detections_s.Status),\n QID_s = tostring(Detections_s.Results)\n | extend\n TenantId = column_ifexists('TenantId', ''),\n SourceSystem = column_ifexists('SourceSystem', ''),\n MG = column_ifexists('MG', ''),\n ManagementGroupName = column_ifexists('ManagementGroupName', ''),\n TimeGenerated = column_ifexists('TimeGenerated', ''),\n Computer = column_ifexists('Computer', ''),\n RawData = column_ifexists('RawData', ''),\n Id = column_ifexists('Id_s', ''),\n HostId = column_ifexists('HostId_s', ''),\n HostTags = column_ifexists('HostTags_s', ''),\n IPAddress = column_ifexists('IPAddress', ''),\n TrackingMethod = column_ifexists('TrackingMethod_s', ''),\n OperatingSystem = column_ifexists('OperatingSystem_s', ''),\n DnsName = column_ifexists('DnsName_s', ''),\n NetBios = column_ifexists('NetBios_s', ''),\n QGHostId = column_ifexists('QGHostId_g', ''),\n LastScanDateTime = column_ifexists('LastScanDateTime_t', ''),\n LastVMScannedDateTime = column_ifexists('LastVMScannedDateTime_t', ''),\n LastVMAuthScannedDateTime = column_ifexists('LastVMAuthScannedDateTime_t', ''),\n QID = column_ifexists('QID_s', ''),\n SSL = column_ifexists('SSL_s', ''),\n Status = column_ifexists('Status_s', ''),\n Ignored = column_ifexists('Ignored_s', ''),\n Severity = column_ifexists('Severity_s', ''),\n Disabled = column_ifexists('Disabled_s', ''),\n LastFixed = column_ifexists('LastFixed_t', ''),\n LastFound = column_ifexists('LastFound_t', ''),\n TimesFound = column_ifexists('TimesFound_s', ''),\n FirstFound = column_ifexists('FirstFound_t', ''),\n LastUpdate = column_ifexists('LastUpdate_t', datetime(null)),\n LastProcessedDateTime = column_ifexists('LastProcessed_t', datetime(null)),\n Result_column_count = tostring(column_ifexists('Result_column_count_d', '')),\n Results_0 = column_ifexists('Results_0_s', ''),\n Type = column_ifexists('Type', ''),\n _ResourceId = column_ifexists('_ResourceId', '')\n };\n let QualysHostDetectionV2_view = view () {\n QualysHostDetectionV2_CL\n | extend\n TenantId = column_ifexists('TenantId', ''),\n SourceSystem = column_ifexists('SourceSystem', ''),\n MG = column_ifexists('MG', ''),\n ManagementGroupName = column_ifexists('ManagementGroupName', ''),\n TimeGenerated = column_ifexists('TimeGenerated', ''),\n Computer = column_ifexists('Computer', ''),\n RawData = column_ifexists('RawData', ''),\n Id = column_ifexists('Id_s', ''),\n HostId = column_ifexists('HostId_s', ''),\n IPAddress = column_ifexists('IPAddress', ''),\n TrackingMethod = column_ifexists('TrackingMethod_s', ''),\n OperatingSystem = column_ifexists('OperatingSystem_s', ''),\n DnsName = column_ifexists('DnsName_s', ''),\n NetBios = column_ifexists('NetBios_s', ''),\n QGHostId = column_ifexists('QGHostId_g', ''),\n LastScanDateTime = column_ifexists('LastScanDateTime_t', ''),\n LastVMScannedDateTime = column_ifexists('LastVMScannedDateTime_t', ''),\n LastVMAuthScannedDateTime = column_ifexists('LastVMAuthScannedDateTime_t', ''),\n QID = column_ifexists('QID_s', ''),\n SSL = column_ifexists('SSL_s', ''),\n Status = column_ifexists('Status_s', ''),\n Ignored = column_ifexists('Ignored_s', ''),\n Severity = column_ifexists('Severity_s', ''),\n Disabled = column_ifexists('Disabled_s', ''),\n LastFixed = column_ifexists('LastFixed_t', ''),\n LastFound = column_ifexists('LastFound_t', ''),\n TimesFound = column_ifexists('TimesFound_s', ''),\n FirstFound = column_ifexists('FirstFound_t', ''),\n LastUpdate = column_ifexists('LastUpdate_t', datetime(null)),\n LastProcessedDateTime = column_ifexists('LastProcessed_t', datetime(null)),\n Result_column_count = tostring(column_ifexists('Result_column_count_d', '')),\n Results_0 = column_ifexists('Results_0_s', ''),\n Type = column_ifexists('Type', ''),\n _ResourceId = column_ifexists('_ResourceId', '')\n };\n let QualysHostDetectionV3_view = view () {\n QualysHostDetectionV3_CL\n | extend DetectionList = todynamic(DetectionList)\n | extend DetectionItems = iff(\n gettype(DetectionList.DETECTION) == \"array\",\n DetectionList.DETECTION,\n pack_array(DetectionList.DETECTION)\n )\n | mv-expand Detections = DetectionItems to typeof(dynamic)\n | extend\n TenantId = column_ifexists('TenantId', ''),\n SourceSystem = column_ifexists('SourceSystem', ''),\n MG = column_ifexists('MG', ''),\n ManagementGroupName = column_ifexists('ManagementGroupName', ''),\n TimeGenerated = column_ifexists('TimeGenerated', ''),\n Computer = column_ifexists('Computer', ''),\n RawData = column_ifexists('RawData', ''),\n Id = column_ifexists('Id', ''),\n HostId = column_ifexists('HostId', ''),\n HostTags = column_ifexists('HostTags', ''),\n IPAddress = column_ifexists('IPAddress', ''),\n TrackingMethod = column_ifexists('TrackingMethod', ''),\n OperatingSystem = column_ifexists('OperatingSystem', ''),\n DnsName = column_ifexists('DnsName', ''),\n NetBios = column_ifexists('NetBios', ''),\n QGHostId = column_ifexists('QGHostId', ''),\n LastScanDateTime = column_ifexists('LastScanDateTime', ''),\n LastVMScannedDateTime = column_ifexists('LastVMScannedDateTime', ''),\n LastVMAuthScannedDateTime = column_ifexists('LastVMAuthScannedDateTime', ''),\n QID = tostring(Detections.QID),\n SSL = tostring(Detections.SSL),\n Status = tostring(Detections.STATUS),\n Ignored = tostring(Detections.IS_IGNORED),\n Severity = tostring(Detections.SEVERITY),\n Disabled = tostring(Detections.IS_DISABLED),\n LastFixed = todatetime(Detections.LAST_FIXED_DATETIME),\n LastFound = todatetime(Detections.LAST_FOUND_DATETIME),\n TimesFound = tostring(Detections.TIMES_FOUND),\n FirstFound = todatetime(Detections.FIRST_FOUND_DATETIME),\n LastUpdate = todatetime(Detections.LAST_UPDATE_DATETIME),\n LastProcessedDateTime = coalesce(\n todatetime(Detections.LAST_PROCESSED_DATETIME),\n todatetime(Detections.LAST_PROCESSED_DATE)),\n Results_0 = tostring(coalesce(Detections.RESULTS['#cdata-section'], Detections.RESULTS)),\n Result_column_count = \"1\",\n Type = tostring(Detections.TYPE),\n _ResourceId = column_ifexists('_ResourceId', '')\n | extend _IngestionTime = todatetime(TimeGenerated)\n | summarize arg_max(_IngestionTime, *) by HostId, QID, Status, SSL, Ignored, Severity, Disabled, LastFixed, LastFound, TimesFound, FirstFound, Result_column_count, Results_0, Type\n | project-away _IngestionTime\n };\n union isfuzzy=true\n (QualysHostDetection_view),\n (QualysHostDetectionV2_view),\n (QualysHostDetectionV3_view)\n | project\n TenantId,\n SourceSystem,\n MG,\n ManagementGroupName,\n TimeGenerated,\n Computer,\n RawData,\n Id,\n HostId,\n HostTags,\n IPAddress,\n TrackingMethod,\n OperatingSystem,\n DnsName,\n NetBios,\n QGHostId,\n LastScanDateTime,\n LastVMScannedDateTime,\n LastVMAuthScannedDateTime,\n QID,\n SSL,\n Type,\n Status,\n Ignored,\n Severity,\n Disabled,\n LastFixed,\n LastFound,\n TimesFound,\n FirstFound,\n LastUpdate,\n LastProcessedDateTime,\n Result_column_count,\n Results_0,\n _ResourceId\n | extend\n HostId = tostring(HostId),\n QID = tostring(QID),\n Status = tostring(Status),\n LastProcessedDateTime = todatetime(LastProcessedDateTime),\n LastUpdate = todatetime(LastUpdate),\n LastFound = todatetime(LastFound)\n | extend DetectionTime = coalesce(LastProcessedDateTime, LastUpdate, LastFound, todatetime(TimeGenerated))\n};\nlet threshold = 10;\n__xdr_inline_QualysHostDetection\n| extend Status = tostring(Status), Vulnerability = tostring(QID), Severity = tostring(Severity)\n| where Status =~ \"New\" and Severity == \"5\"\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), dcount(NetBios), RepresentativeHost = take_anyif(NetBios, isnotempty(NetBios)) by tostring(QID)\n| where dcount_NetBios >= threshold\n| extend timestamp = StartTime" + }, + "displayName": "New High Severity Vulnerability Detected Across Multiple Hosts", + "detectionAction": { + "alertTemplate": { + "severity": "medium", + "entityMappings": { + "hosts": [ + { + "netBiosNameColumn": "RepresentativeHost", + "id": "[if(true(), 'host1', 'host1')]" + } + ] + }, + "title": "New High Severity Vulnerability Detected Across Multiple Hosts", + "description": "'This creates an incident when a new high severity vulnerability is detected across multilple hosts'", + "tactics": [ + { + "tactic": "InitialAccess", + "techniques": [ + { + "technique": "T1190" + } + ] + } + ] + } + }, + "status": "disabled", + "schedule": { + "frequency": "PT1H" + }, + "contentProvenance": { + "packageId": "azuresentinel.azure-sentinel-qualysvm", + "packageVersion": "3.2.2", + "contentId": "xdr-6116dc19-475a-4148-84b2-efe89c073e27", + "contentVersion": "3.2.1" + } + } + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "xdr-6116dc19-475a-4148-84b2-efe89c073e27", + "contentKind": "CustomDetection", + "displayName": "New High Severity Vulnerability Detected Across Multiple Hosts", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-6116dc19-475a-4148-84b2-efe89c073e27','-','3.2.1')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','cd','-', uniqueString(concat(variables('_solutionId'),'-','CustomDetection','-','xdr-6116dc19-475a-4148-84b2-efe89c073e27','-','3.2.1')))]", + "version": "3.2.1", + "contentProvenance": { + "packageId": "azuresentinel.azure-sentinel-qualysvm", + "packageVersion": "3.2.2", + "contentId": "xdr-6116dc19-475a-4148-84b2-efe89c073e27", + "contentVersion": "3.2.1", + "requiredWorkloads": [ + { + "workload": "sentinel", + "dataTypes": [ + "QualysHostDetection_CL", + "QualysHostDetectionV2_CL", + "QualysHostDetectionV3_CL" + ] + } + ], + "requiredDataConnectors": [ + { + "dataTypes": [ + "QualysHostDetection" + ], + "connectorId": "QualysVMLogsCCPDefinition" + } + ] + } + }, + "condition": "[parameters('DeployCustomDetection')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "pid-7d9ebe77-5cfa-4d99-ae0c-66196a716a93-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/QualysVM/Package/testParameters.json b/Solutions/QualysVM/Package/testParameters.json index aed8fcc514f..8064873e210 100644 --- a/Solutions/QualysVM/Package/testParameters.json +++ b/Solutions/QualysVM/Package/testParameters.json @@ -42,5 +42,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)." + } + }, + "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." + } + }, + "DeployParser": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Deploy the parsers and their registrations carried by this solution." + } } } diff --git a/Solutions/QualysVM/ReleaseNotes.md b/Solutions/QualysVM/ReleaseNotes.md index 35615151108..8788424ff23 100644 --- a/Solutions/QualysVM/ReleaseNotes.md +++ b/Solutions/QualysVM/ReleaseNotes.md @@ -1,5 +1,6 @@ | **Version** | **Date Modified (DD-MM-YYYY)** | **Change History** | |-------------|--------------------------------|----------------------------------------------------------------| +| 3.2.2 | 20-10-2026 | Added two disabled Defender XDR Custom Detections alongside the existing Microsoft Sentinel content. Defender Workbook drafts remain excluded pending review. | | 3.1.1 | 22-09-2026 | Updated the Playbooks to fix the Azure deploy button issue for GOV and corrected the parameter value for Service Endpoint. | | 3.1.0 | 14-09-2026 | Updated the **QualysHostDetection Parser** to reliably parse both single-object and array detection responses from the CCF connector. | | 3.0.11 | 10-09-2026 | Updated the Qualys Host Detection Parser to deduplicate repeated V3 snapshots using stable vulnerability content and lifecycle fields, preserve ingestion TimeGenerated, and expose the source timestamp as DetectionTime. Updated the CCP Data Connector to use explicit table references for Defender portal query compatibility. | diff --git a/Solutions/QualysVM/SolutionMetadata.json b/Solutions/QualysVM/SolutionMetadata.json index 3e34321a2ab..ac3b6bcaaca 100644 --- a/Solutions/QualysVM/SolutionMetadata.json +++ b/Solutions/QualysVM/SolutionMetadata.json @@ -1,16 +1,23 @@ { + "trackingId": "pid-7d9ebe77-5cfa-4d99-ae0c-66196a716a93-partnercenter", "publisherId": "azuresentinel", "offerId": "azure-sentinel-qualysvm", "firstPublishDate": "2020-12-14", "lastPublishDate": "2025-11-18", - "providers": ["Qualys"], + "providers": [ + "Qualys" + ], "categories": { - "domains": ["Security - Vulnerability Management","Security - Automation (SOAR)"] + "domains": [ + "Security - Vulnerability Management", + "Security - Automation (SOAR)" + ] }, "support": { - "name": "Microsoft Corporation", - "email": "support@microsoft.com", - "tier": "Microsoft", - "link": "https://support.microsoft.com" - } -} \ No newline at end of file + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "tier": "Microsoft", + "link": "https://support.microsoft.com" + }, + "version": "3.2.2" +} diff --git a/Solutions/QualysVM/XDR Detections/HighNumberofVulnDetectedV2.yaml b/Solutions/QualysVM/XDR Detections/HighNumberofVulnDetectedV2.yaml new file mode 100644 index 00000000000..53d70dfbd59 --- /dev/null +++ b/Solutions/QualysVM/XDR Detections/HighNumberofVulnDetectedV2.yaml @@ -0,0 +1,299 @@ +schemaVersion: 1.0.0 +version: 3.2.1 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: QualysVMLogsCCPDefinition + dataTypes: + - QualysHostDetection +contentProvenance: + requiredWorkloads: + - workload: sentinel + dataTypes: + - QualysHostDetection_CL + - QualysHostDetectionV2_CL + - QualysHostDetectionV3_CL + requiredDataConnectors: + - connectorId: QualysVMLogsCCPDefinition + dataTypes: + - QualysHostDetection + dependencyReviewRequired: false + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: 3edb7215-250b-40c0-8b46-79093949242d + path: Analytic Rules/HighNumberofVulnDetectedV2.yaml + version: 3.2.1 + querySha256: aadc5cb60a259b492608ca7d2cdbcada738a16b81a3b6ff82e9ac8caf81f1b11 + schedule: + queryFrequency: 1h + queryPeriod: 1h + 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 + - Renamed local parser binding QualysHostDetection to __xdr_inline_QualysHostDetection to avoid a saved parser collision + - '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' + - customDetails 'HostFullName' column `NetBios` 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 + - 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: + - InitialAccess + originalTechniques: + - T1190 + reviewScope: + sourceDocumentSha256: 9f0187880320bb3397193862d5ea19ed38de9fe076672f4600a2ae1b9515d8f0 + targetQuerySha256: 820b0c467ea4b5e97125942fc31eaa229dae373b41b963702ebc9589b31a13ef + reviewDecisions: + - reason: isfuzzy unions can still fail semantic binding in Advanced Hunting + decision: accepted + sourceDocumentSha256: 9f0187880320bb3397193862d5ea19ed38de9fe076672f4600a2ae1b9515d8f0 + targetQuerySha256: 820b0c467ea4b5e97125942fc31eaa229dae373b41b963702ebc9589b31a13ef + eventTimeWindow: + status: default-native-lookback + appliedDefault: hourly-1h-to-native-4h-lookback + queryFrequency: 1h + queryPeriod: 1h + targetFrequency: PT1H + effectiveLookback: PT4H + originalSentinelLookbackSeconds: 3600 + effectiveEventWindowSeconds: 14400 + xdrServiceWindowSeconds: 14400 + filterInjected: false + parityClaimed: false + hasAggregation: true + aggregationWindowDifference: true + timingDifference: Four hours (PT4H / 14400s) is the native XDR ingestion-based lookback window for PT1H execution frequency, + not the execution frequency; original Sentinel queryPeriod was 1h (3600s). + aggregationDifference: Query contains summarize/make-series aggregation; evaluating over the native 4-hour XDR lookback + window without an injected 1h event-time filter may aggregate up to 4 hours of events per hourly run instead of 1 + hour. + sourceDocumentSha256: 9f0187880320bb3397193862d5ea19ed38de9fe076672f4600a2ae1b9515d8f0 + targetQuerySha256: 820b0c467ea4b5e97125942fc31eaa229dae373b41b963702ebc9589b31a13ef + acceptedReviewReasons: + - isfuzzy unions can still fail semantic binding in Advanced Hunting +properties: + id: xdr-3edb7215-250b-40c0-8b46-79093949242d + displayName: High Number of Urgent Vulnerabilities Detected + status: disabled + queryCondition: + queryText: |- + let __xdr_inline_QualysHostDetection = view () { + let QualysHostDetection_view = view () { + QualysHostDetection_CL + | mv-expand todynamic(Detections_s) + | extend + Severity_s = tostring(Detections_s.Severity), + Status_s = tostring(Detections_s.Status), + QID_s = tostring(Detections_s.Results) + | extend + TenantId = column_ifexists('TenantId', ''), + SourceSystem = column_ifexists('SourceSystem', ''), + MG = column_ifexists('MG', ''), + ManagementGroupName = column_ifexists('ManagementGroupName', ''), + TimeGenerated = column_ifexists('TimeGenerated', ''), + Computer = column_ifexists('Computer', ''), + RawData = column_ifexists('RawData', ''), + Id = column_ifexists('Id_s', ''), + HostId = column_ifexists('HostId_s', ''), + HostTags = column_ifexists('HostTags_s', ''), + IPAddress = column_ifexists('IPAddress', ''), + TrackingMethod = column_ifexists('TrackingMethod_s', ''), + OperatingSystem = column_ifexists('OperatingSystem_s', ''), + DnsName = column_ifexists('DnsName_s', ''), + NetBios = column_ifexists('NetBios_s', ''), + QGHostId = column_ifexists('QGHostId_g', ''), + LastScanDateTime = column_ifexists('LastScanDateTime_t', ''), + LastVMScannedDateTime = column_ifexists('LastVMScannedDateTime_t', ''), + LastVMAuthScannedDateTime = column_ifexists('LastVMAuthScannedDateTime_t', ''), + QID = column_ifexists('QID_s', ''), + SSL = column_ifexists('SSL_s', ''), + Status = column_ifexists('Status_s', ''), + Ignored = column_ifexists('Ignored_s', ''), + Severity = column_ifexists('Severity_s', ''), + Disabled = column_ifexists('Disabled_s', ''), + LastFixed = column_ifexists('LastFixed_t', ''), + LastFound = column_ifexists('LastFound_t', ''), + TimesFound = column_ifexists('TimesFound_s', ''), + FirstFound = column_ifexists('FirstFound_t', ''), + LastUpdate = column_ifexists('LastUpdate_t', datetime(null)), + LastProcessedDateTime = column_ifexists('LastProcessed_t', datetime(null)), + Result_column_count = tostring(column_ifexists('Result_column_count_d', '')), + Results_0 = column_ifexists('Results_0_s', ''), + Type = column_ifexists('Type', ''), + _ResourceId = column_ifexists('_ResourceId', '') + }; + let QualysHostDetectionV2_view = view () { + QualysHostDetectionV2_CL + | extend + TenantId = column_ifexists('TenantId', ''), + SourceSystem = column_ifexists('SourceSystem', ''), + MG = column_ifexists('MG', ''), + ManagementGroupName = column_ifexists('ManagementGroupName', ''), + TimeGenerated = column_ifexists('TimeGenerated', ''), + Computer = column_ifexists('Computer', ''), + RawData = column_ifexists('RawData', ''), + Id = column_ifexists('Id_s', ''), + HostId = column_ifexists('HostId_s', ''), + IPAddress = column_ifexists('IPAddress', ''), + TrackingMethod = column_ifexists('TrackingMethod_s', ''), + OperatingSystem = column_ifexists('OperatingSystem_s', ''), + DnsName = column_ifexists('DnsName_s', ''), + NetBios = column_ifexists('NetBios_s', ''), + QGHostId = column_ifexists('QGHostId_g', ''), + LastScanDateTime = column_ifexists('LastScanDateTime_t', ''), + LastVMScannedDateTime = column_ifexists('LastVMScannedDateTime_t', ''), + LastVMAuthScannedDateTime = column_ifexists('LastVMAuthScannedDateTime_t', ''), + QID = column_ifexists('QID_s', ''), + SSL = column_ifexists('SSL_s', ''), + Status = column_ifexists('Status_s', ''), + Ignored = column_ifexists('Ignored_s', ''), + Severity = column_ifexists('Severity_s', ''), + Disabled = column_ifexists('Disabled_s', ''), + LastFixed = column_ifexists('LastFixed_t', ''), + LastFound = column_ifexists('LastFound_t', ''), + TimesFound = column_ifexists('TimesFound_s', ''), + FirstFound = column_ifexists('FirstFound_t', ''), + LastUpdate = column_ifexists('LastUpdate_t', datetime(null)), + LastProcessedDateTime = column_ifexists('LastProcessed_t', datetime(null)), + Result_column_count = tostring(column_ifexists('Result_column_count_d', '')), + Results_0 = column_ifexists('Results_0_s', ''), + Type = column_ifexists('Type', ''), + _ResourceId = column_ifexists('_ResourceId', '') + }; + let QualysHostDetectionV3_view = view () { + QualysHostDetectionV3_CL + | extend DetectionList = todynamic(DetectionList) + | extend DetectionItems = iff( + gettype(DetectionList.DETECTION) == "array", + DetectionList.DETECTION, + pack_array(DetectionList.DETECTION) + ) + | mv-expand Detections = DetectionItems to typeof(dynamic) + | extend + TenantId = column_ifexists('TenantId', ''), + SourceSystem = column_ifexists('SourceSystem', ''), + MG = column_ifexists('MG', ''), + ManagementGroupName = column_ifexists('ManagementGroupName', ''), + TimeGenerated = column_ifexists('TimeGenerated', ''), + Computer = column_ifexists('Computer', ''), + RawData = column_ifexists('RawData', ''), + Id = column_ifexists('Id', ''), + HostId = column_ifexists('HostId', ''), + HostTags = column_ifexists('HostTags', ''), + IPAddress = column_ifexists('IPAddress', ''), + TrackingMethod = column_ifexists('TrackingMethod', ''), + OperatingSystem = column_ifexists('OperatingSystem', ''), + DnsName = column_ifexists('DnsName', ''), + NetBios = column_ifexists('NetBios', ''), + QGHostId = column_ifexists('QGHostId', ''), + LastScanDateTime = column_ifexists('LastScanDateTime', ''), + LastVMScannedDateTime = column_ifexists('LastVMScannedDateTime', ''), + LastVMAuthScannedDateTime = column_ifexists('LastVMAuthScannedDateTime', ''), + QID = tostring(Detections.QID), + SSL = tostring(Detections.SSL), + Status = tostring(Detections.STATUS), + Ignored = tostring(Detections.IS_IGNORED), + Severity = tostring(Detections.SEVERITY), + Disabled = tostring(Detections.IS_DISABLED), + LastFixed = todatetime(Detections.LAST_FIXED_DATETIME), + LastFound = todatetime(Detections.LAST_FOUND_DATETIME), + TimesFound = tostring(Detections.TIMES_FOUND), + FirstFound = todatetime(Detections.FIRST_FOUND_DATETIME), + LastUpdate = todatetime(Detections.LAST_UPDATE_DATETIME), + LastProcessedDateTime = coalesce( + todatetime(Detections.LAST_PROCESSED_DATETIME), + todatetime(Detections.LAST_PROCESSED_DATE)), + Results_0 = tostring(coalesce(Detections.RESULTS['#cdata-section'], Detections.RESULTS)), + Result_column_count = "1", + Type = tostring(Detections.TYPE), + _ResourceId = column_ifexists('_ResourceId', '') + | extend _IngestionTime = todatetime(TimeGenerated) + | summarize arg_max(_IngestionTime, *) by HostId, QID, Status, SSL, Ignored, Severity, Disabled, LastFixed, LastFound, TimesFound, FirstFound, Result_column_count, Results_0, Type + | project-away _IngestionTime + }; + union isfuzzy=true + (QualysHostDetection_view), + (QualysHostDetectionV2_view), + (QualysHostDetectionV3_view) + | project + TenantId, + SourceSystem, + MG, + ManagementGroupName, + TimeGenerated, + Computer, + RawData, + Id, + HostId, + HostTags, + IPAddress, + TrackingMethod, + OperatingSystem, + DnsName, + NetBios, + QGHostId, + LastScanDateTime, + LastVMScannedDateTime, + LastVMAuthScannedDateTime, + QID, + SSL, + Type, + Status, + Ignored, + Severity, + Disabled, + LastFixed, + LastFound, + TimesFound, + FirstFound, + LastUpdate, + LastProcessedDateTime, + Result_column_count, + Results_0, + _ResourceId + | extend + HostId = tostring(HostId), + QID = tostring(QID), + Status = tostring(Status), + LastProcessedDateTime = todatetime(LastProcessedDateTime), + LastUpdate = todatetime(LastUpdate), + LastFound = todatetime(LastFound) + | extend DetectionTime = coalesce(LastProcessedDateTime, LastUpdate, LastFound, todatetime(TimeGenerated)) + }; + let threshold = 10; + __xdr_inline_QualysHostDetection + | where Severity == "5" + | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), count() by NetBios, IPAddress + | where count_ >= threshold + schedule: + frequency: PT1H + detectionAction: + alertTemplate: + title: High Number of Urgent Vulnerabilities Detected + description: '''This creates an incident when a host has a high number of urgent, severity 5, vulnerabilities detected.''' + severity: medium + entityMappings: + hosts: + - id: host1 + netBiosNameColumn: NetBios + ips: + - id: ip1 + addressColumn: IPAddress + tactics: + - tactic: InitialAccess + techniques: + - technique: T1190 + customDetails: + HostFullName: NetBios diff --git a/Solutions/QualysVM/XDR Detections/NewHighSeverityVulnDetectedAcrossMulitpleHostsV2.yaml b/Solutions/QualysVM/XDR Detections/NewHighSeverityVulnDetectedAcrossMulitpleHostsV2.yaml new file mode 100644 index 00000000000..57e06dec70c --- /dev/null +++ b/Solutions/QualysVM/XDR Detections/NewHighSeverityVulnDetectedAcrossMulitpleHostsV2.yaml @@ -0,0 +1,292 @@ +schemaVersion: 1.0.0 +version: 3.2.1 +kind: CustomDetection +resourceType: Microsoft.Security/detectionRules +apiVersion: 2026-06-01-preview +requiredDataConnectors: +- connectorId: QualysVMLogsCCPDefinition + dataTypes: + - QualysHostDetection +contentProvenance: + requiredWorkloads: + - workload: sentinel + dataTypes: + - QualysHostDetection_CL + - QualysHostDetectionV2_CL + - QualysHostDetectionV3_CL + requiredDataConnectors: + - connectorId: QualysVMLogsCCPDefinition + dataTypes: + - QualysHostDetection + dependencyReviewRequired: false + source: + platform: Microsoft Sentinel + kind: AnalyticsRule + id: 6116dc19-475a-4148-84b2-efe89c073e27 + path: Analytic Rules/NewHighSeverityVulnDetectedAcrossMulitpleHostsV2.yaml + version: 3.2.1 + querySha256: af7aa2c23e7e1acfb51633cd9b63b827663618d7f2205293ff9c20ecbbf530ca + schedule: + queryFrequency: 1h + queryPeriod: 1h + 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 + - Renamed local parser binding QualysHostDetection to __xdr_inline_QualysHostDetection to avoid a saved parser collision + - '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: + - InitialAccess + originalTechniques: + - T1190 + reviewScope: + sourceDocumentSha256: 43da0904d914aacebc219bcb7b91325b8009bb00b3f35af32533c4f5e144189d + targetQuerySha256: d204642ad3286c7e0987b6877e2149d4bcdb4ede4b35878edfad0f0ec8b1b661 + reviewDecisions: + - reason: isfuzzy unions can still fail semantic binding in Advanced Hunting + decision: accepted + sourceDocumentSha256: 43da0904d914aacebc219bcb7b91325b8009bb00b3f35af32533c4f5e144189d + targetQuerySha256: d204642ad3286c7e0987b6877e2149d4bcdb4ede4b35878edfad0f0ec8b1b661 + eventTimeWindow: + status: default-native-lookback + appliedDefault: hourly-1h-to-native-4h-lookback + queryFrequency: 1h + queryPeriod: 1h + targetFrequency: PT1H + effectiveLookback: PT4H + originalSentinelLookbackSeconds: 3600 + effectiveEventWindowSeconds: 14400 + xdrServiceWindowSeconds: 14400 + filterInjected: false + parityClaimed: false + hasAggregation: true + aggregationWindowDifference: true + timingDifference: Four hours (PT4H / 14400s) is the native XDR ingestion-based lookback window for PT1H execution frequency, + not the execution frequency; original Sentinel queryPeriod was 1h (3600s). + aggregationDifference: Query contains summarize/make-series aggregation; evaluating over the native 4-hour XDR lookback + window without an injected 1h event-time filter may aggregate up to 4 hours of events per hourly run instead of 1 + hour. + sourceDocumentSha256: 43da0904d914aacebc219bcb7b91325b8009bb00b3f35af32533c4f5e144189d + targetQuerySha256: d204642ad3286c7e0987b6877e2149d4bcdb4ede4b35878edfad0f0ec8b1b661 + acceptedReviewReasons: + - isfuzzy unions can still fail semantic binding in Advanced Hunting +properties: + id: xdr-6116dc19-475a-4148-84b2-efe89c073e27 + displayName: New High Severity Vulnerability Detected Across Multiple Hosts + status: disabled + queryCondition: + queryText: |- + let __xdr_inline_QualysHostDetection = view () { + let QualysHostDetection_view = view () { + QualysHostDetection_CL + | mv-expand todynamic(Detections_s) + | extend + Severity_s = tostring(Detections_s.Severity), + Status_s = tostring(Detections_s.Status), + QID_s = tostring(Detections_s.Results) + | extend + TenantId = column_ifexists('TenantId', ''), + SourceSystem = column_ifexists('SourceSystem', ''), + MG = column_ifexists('MG', ''), + ManagementGroupName = column_ifexists('ManagementGroupName', ''), + TimeGenerated = column_ifexists('TimeGenerated', ''), + Computer = column_ifexists('Computer', ''), + RawData = column_ifexists('RawData', ''), + Id = column_ifexists('Id_s', ''), + HostId = column_ifexists('HostId_s', ''), + HostTags = column_ifexists('HostTags_s', ''), + IPAddress = column_ifexists('IPAddress', ''), + TrackingMethod = column_ifexists('TrackingMethod_s', ''), + OperatingSystem = column_ifexists('OperatingSystem_s', ''), + DnsName = column_ifexists('DnsName_s', ''), + NetBios = column_ifexists('NetBios_s', ''), + QGHostId = column_ifexists('QGHostId_g', ''), + LastScanDateTime = column_ifexists('LastScanDateTime_t', ''), + LastVMScannedDateTime = column_ifexists('LastVMScannedDateTime_t', ''), + LastVMAuthScannedDateTime = column_ifexists('LastVMAuthScannedDateTime_t', ''), + QID = column_ifexists('QID_s', ''), + SSL = column_ifexists('SSL_s', ''), + Status = column_ifexists('Status_s', ''), + Ignored = column_ifexists('Ignored_s', ''), + Severity = column_ifexists('Severity_s', ''), + Disabled = column_ifexists('Disabled_s', ''), + LastFixed = column_ifexists('LastFixed_t', ''), + LastFound = column_ifexists('LastFound_t', ''), + TimesFound = column_ifexists('TimesFound_s', ''), + FirstFound = column_ifexists('FirstFound_t', ''), + LastUpdate = column_ifexists('LastUpdate_t', datetime(null)), + LastProcessedDateTime = column_ifexists('LastProcessed_t', datetime(null)), + Result_column_count = tostring(column_ifexists('Result_column_count_d', '')), + Results_0 = column_ifexists('Results_0_s', ''), + Type = column_ifexists('Type', ''), + _ResourceId = column_ifexists('_ResourceId', '') + }; + let QualysHostDetectionV2_view = view () { + QualysHostDetectionV2_CL + | extend + TenantId = column_ifexists('TenantId', ''), + SourceSystem = column_ifexists('SourceSystem', ''), + MG = column_ifexists('MG', ''), + ManagementGroupName = column_ifexists('ManagementGroupName', ''), + TimeGenerated = column_ifexists('TimeGenerated', ''), + Computer = column_ifexists('Computer', ''), + RawData = column_ifexists('RawData', ''), + Id = column_ifexists('Id_s', ''), + HostId = column_ifexists('HostId_s', ''), + IPAddress = column_ifexists('IPAddress', ''), + TrackingMethod = column_ifexists('TrackingMethod_s', ''), + OperatingSystem = column_ifexists('OperatingSystem_s', ''), + DnsName = column_ifexists('DnsName_s', ''), + NetBios = column_ifexists('NetBios_s', ''), + QGHostId = column_ifexists('QGHostId_g', ''), + LastScanDateTime = column_ifexists('LastScanDateTime_t', ''), + LastVMScannedDateTime = column_ifexists('LastVMScannedDateTime_t', ''), + LastVMAuthScannedDateTime = column_ifexists('LastVMAuthScannedDateTime_t', ''), + QID = column_ifexists('QID_s', ''), + SSL = column_ifexists('SSL_s', ''), + Status = column_ifexists('Status_s', ''), + Ignored = column_ifexists('Ignored_s', ''), + Severity = column_ifexists('Severity_s', ''), + Disabled = column_ifexists('Disabled_s', ''), + LastFixed = column_ifexists('LastFixed_t', ''), + LastFound = column_ifexists('LastFound_t', ''), + TimesFound = column_ifexists('TimesFound_s', ''), + FirstFound = column_ifexists('FirstFound_t', ''), + LastUpdate = column_ifexists('LastUpdate_t', datetime(null)), + LastProcessedDateTime = column_ifexists('LastProcessed_t', datetime(null)), + Result_column_count = tostring(column_ifexists('Result_column_count_d', '')), + Results_0 = column_ifexists('Results_0_s', ''), + Type = column_ifexists('Type', ''), + _ResourceId = column_ifexists('_ResourceId', '') + }; + let QualysHostDetectionV3_view = view () { + QualysHostDetectionV3_CL + | extend DetectionList = todynamic(DetectionList) + | extend DetectionItems = iff( + gettype(DetectionList.DETECTION) == "array", + DetectionList.DETECTION, + pack_array(DetectionList.DETECTION) + ) + | mv-expand Detections = DetectionItems to typeof(dynamic) + | extend + TenantId = column_ifexists('TenantId', ''), + SourceSystem = column_ifexists('SourceSystem', ''), + MG = column_ifexists('MG', ''), + ManagementGroupName = column_ifexists('ManagementGroupName', ''), + TimeGenerated = column_ifexists('TimeGenerated', ''), + Computer = column_ifexists('Computer', ''), + RawData = column_ifexists('RawData', ''), + Id = column_ifexists('Id', ''), + HostId = column_ifexists('HostId', ''), + HostTags = column_ifexists('HostTags', ''), + IPAddress = column_ifexists('IPAddress', ''), + TrackingMethod = column_ifexists('TrackingMethod', ''), + OperatingSystem = column_ifexists('OperatingSystem', ''), + DnsName = column_ifexists('DnsName', ''), + NetBios = column_ifexists('NetBios', ''), + QGHostId = column_ifexists('QGHostId', ''), + LastScanDateTime = column_ifexists('LastScanDateTime', ''), + LastVMScannedDateTime = column_ifexists('LastVMScannedDateTime', ''), + LastVMAuthScannedDateTime = column_ifexists('LastVMAuthScannedDateTime', ''), + QID = tostring(Detections.QID), + SSL = tostring(Detections.SSL), + Status = tostring(Detections.STATUS), + Ignored = tostring(Detections.IS_IGNORED), + Severity = tostring(Detections.SEVERITY), + Disabled = tostring(Detections.IS_DISABLED), + LastFixed = todatetime(Detections.LAST_FIXED_DATETIME), + LastFound = todatetime(Detections.LAST_FOUND_DATETIME), + TimesFound = tostring(Detections.TIMES_FOUND), + FirstFound = todatetime(Detections.FIRST_FOUND_DATETIME), + LastUpdate = todatetime(Detections.LAST_UPDATE_DATETIME), + LastProcessedDateTime = coalesce( + todatetime(Detections.LAST_PROCESSED_DATETIME), + todatetime(Detections.LAST_PROCESSED_DATE)), + Results_0 = tostring(coalesce(Detections.RESULTS['#cdata-section'], Detections.RESULTS)), + Result_column_count = "1", + Type = tostring(Detections.TYPE), + _ResourceId = column_ifexists('_ResourceId', '') + | extend _IngestionTime = todatetime(TimeGenerated) + | summarize arg_max(_IngestionTime, *) by HostId, QID, Status, SSL, Ignored, Severity, Disabled, LastFixed, LastFound, TimesFound, FirstFound, Result_column_count, Results_0, Type + | project-away _IngestionTime + }; + union isfuzzy=true + (QualysHostDetection_view), + (QualysHostDetectionV2_view), + (QualysHostDetectionV3_view) + | project + TenantId, + SourceSystem, + MG, + ManagementGroupName, + TimeGenerated, + Computer, + RawData, + Id, + HostId, + HostTags, + IPAddress, + TrackingMethod, + OperatingSystem, + DnsName, + NetBios, + QGHostId, + LastScanDateTime, + LastVMScannedDateTime, + LastVMAuthScannedDateTime, + QID, + SSL, + Type, + Status, + Ignored, + Severity, + Disabled, + LastFixed, + LastFound, + TimesFound, + FirstFound, + LastUpdate, + LastProcessedDateTime, + Result_column_count, + Results_0, + _ResourceId + | extend + HostId = tostring(HostId), + QID = tostring(QID), + Status = tostring(Status), + LastProcessedDateTime = todatetime(LastProcessedDateTime), + LastUpdate = todatetime(LastUpdate), + LastFound = todatetime(LastFound) + | extend DetectionTime = coalesce(LastProcessedDateTime, LastUpdate, LastFound, todatetime(TimeGenerated)) + }; + let threshold = 10; + __xdr_inline_QualysHostDetection + | extend Status = tostring(Status), Vulnerability = tostring(QID), Severity = tostring(Severity) + | where Status =~ "New" and Severity == "5" + | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), dcount(NetBios), RepresentativeHost = take_anyif(NetBios, isnotempty(NetBios)) by tostring(QID) + | where dcount_NetBios >= threshold + | extend timestamp = StartTime + schedule: + frequency: PT1H + detectionAction: + alertTemplate: + title: New High Severity Vulnerability Detected Across Multiple Hosts + description: '''This creates an incident when a new high severity vulnerability is detected across multilple hosts''' + severity: medium + entityMappings: + hosts: + - id: host1 + netBiosNameColumn: RepresentativeHost + tactics: + - tactic: InitialAccess + techniques: + - technique: T1190 diff --git a/Solutions/QualysVM/data/Solution_QualysVM.json b/Solutions/QualysVM/data/Solution_QualysVM.json index 1ecaba34f9e..3c77c588764 100644 --- a/Solutions/QualysVM/data/Solution_QualysVM.json +++ b/Solutions/QualysVM/data/Solution_QualysVM.json @@ -25,7 +25,12 @@ ], "Metadata": "SolutionMetadata.json", "BasePath": "C:\\GitHub\\Azure-Sentinel\\Solutions\\QualysVM", - "Version": "3.1.1", "TemplateSpec": true, - "Is1PConnector": false + "Is1PConnector": false, + "XDR Workbooks": [], + "XDR Detections": [ + "XDR Detections/HighNumberofVulnDetectedV2.yaml", + "XDR Detections/NewHighSeverityVulnDetectedAcrossMulitpleHostsV2.yaml" + ], + "Version": "3.2.2" }