diff --git a/Solutions/Cisco Firepower EStreamer/Analytic Rules/CiscoFirepower-IDS-Signature-HighPriority.yaml b/Solutions/Cisco Firepower EStreamer/Analytic Rules/CiscoFirepower-IDS-Signature-HighPriority.yaml new file mode 100644 index 00000000000..bdec89f27f9 --- /dev/null +++ b/Solutions/Cisco Firepower EStreamer/Analytic Rules/CiscoFirepower-IDS-Signature-HighPriority.yaml @@ -0,0 +1,76 @@ +id: a1c9e026-9bb7-4c42-a3a1-83faa3ca26a6 +name: Cisco Firepower - IDS signature high priority classification +description: | + 'Detects classic Cisco Firepower / Snort-family signature hits (Generator ID not equal to SnortML GID 411) + with high-priority classifications commonly associated with malware C2, privilege gain, or network trojans. + These events are stronger signature true-positive candidates than ML-only (GID 411) paths and may justify + gated remediation after analyst or policy review - prefer HITL Gate/Prove over ungated BlockIP automation. + Pair with "Cisco Firepower - SnortML GID 411 ML-only high alert" and "Cisco Firepower - Signature and ML corroboration".' +severity: High +status: Available +requiredDataConnectors: + - connectorId: CefAma + dataTypes: + - CommonSecurityLog +queryFrequency: 15m +queryPeriod: 15m +triggerOperator: gt +triggerThreshold: 0 +tactics: + - CommandAndControl + - Execution +relevantTechniques: + - T1071 + - T1203 +query: | + let HighPriorityClassifications = dynamic([ + "A Network Trojan was Detected", + "A Network Trojan was detected", + "Successful Administrator Privilege Gain", + "Successful User Privilege Gain", + "Attempted Administrator Privilege Gain", + "Attempted User Privilege Gain", + "Known malware command and control traffic", + "Malware Command and Control Activity Detected", + "Known malicious file or file based exploit", + "Known client side exploit attempt", + "Large Scale Information Leak" + ]); + CommonSecurityLog + | where DeviceVendor =~ "Cisco" + | where DeviceProduct has_any ("Firepower", "Secure Firewall", "FTD", "NGFW") + | extend Combined = strcat( + tostring(Message), " ", + tostring(AdditionalExtensions), " ", + tostring(Activity), " ", + tostring(DeviceEventClassID), " ", + tostring(column_ifexists("FlexString1", "")), " ", + tostring(column_ifexists("FlexString2", "")), " ", + tostring(column_ifexists("DeviceCustomString1", "")), " ", + tostring(column_ifexists("DeviceCustomString2", "")), " ", + tostring(column_ifexists("DeviceCustomString3", "")), " ", + tostring(DeviceAction) + ) + | extend ParsedGid = toint(extract(@"(?i)(?:gid|generator[\s_-]?id)[\s:=]*(\d+)", 1, Combined)) + | where ParsedGid != 411 or isnull(ParsedGid) + | where not(Combined has_any ("SnortML", "snortml", "is_ml_only")) + | where Combined has_any (HighPriorityClassifications) + or Activity has_any (HighPriorityClassifications) + | extend HostCustomEntity = DeviceName, SrcIpCustomEntity = SourceIP, DstIpCustomEntity = DestinationIP + | project TimeGenerated, DeviceName, SourceIP, DestinationIP, DestinationPort, Activity, DeviceAction, + DeviceEventClassID, Message, AdditionalExtensions, HostCustomEntity, SrcIpCustomEntity, DstIpCustomEntity +entityMappings: + - entityType: Host + fieldMappings: + - identifier: FullName + columnName: HostCustomEntity + - entityType: IP + fieldMappings: + - identifier: Address + columnName: SrcIpCustomEntity + - entityType: IP + fieldMappings: + - identifier: Address + columnName: DstIpCustomEntity +version: 1.0.2 +kind: Scheduled diff --git a/Solutions/Cisco Firepower EStreamer/Analytic Rules/CiscoFirepower-Signal-Mix-Drift.yaml b/Solutions/Cisco Firepower EStreamer/Analytic Rules/CiscoFirepower-Signal-Mix-Drift.yaml new file mode 100644 index 00000000000..7a229095cd6 --- /dev/null +++ b/Solutions/Cisco Firepower EStreamer/Analytic Rules/CiscoFirepower-Signal-Mix-Drift.yaml @@ -0,0 +1,47 @@ +id: 6ff65bb5-53bd-4ffb-a62a-25ea71c04eed +name: Cisco Firepower - SnortML signal mix drift +description: | + Detects a material increase in the proportion of SnortML GID 411 events compared with the preceding seven-day baseline. + This is a detection-quality regression signal, not evidence that an individual event is malicious. Investigate collector, + sensor, model, policy, and traffic changes before modifying response automation. ML-only events must not trigger automatic containment. +severity: Medium +status: Available +requiredDataConnectors: + - connectorId: CefAma + dataTypes: + - CommonSecurityLog +queryFrequency: 1h +queryPeriod: 8d +triggerOperator: gt +triggerThreshold: 0 +tactics: + - DefenseEvasion +relevantTechniques: + - T1562 +query: | + let FirepowerEvents = materialize( + CommonSecurityLog + | where TimeGenerated >= ago(8d) + | where DeviceVendor =~ "Cisco" + | where DeviceProduct has_any ("Firepower", "Secure Firewall", "FTD", "NGFW") + | extend Combined = strcat(tostring(Message), " ", tostring(AdditionalExtensions), " ", tostring(Activity), " ", tostring(DeviceEventClassID), " ", tostring(column_ifexists("FlexString1", "")), " ", tostring(column_ifexists("FlexString2", "")), " ", tostring(column_ifexists("DeviceCustomString1", "")), " ", tostring(column_ifexists("DeviceCustomString2", "")), " ", tostring(column_ifexists("DeviceCustomString3", ""))) + | extend ParsedGid = toint(extract(@"(?i)(?:gid|generator[\s_-]?id)[\s:=]*(\d+)", 1, Combined)) + | extend IsMlOnly = ParsedGid == 411 or Combined has "is_ml_only" + ); + let Recent = FirepowerEvents + | where TimeGenerated >= ago(1h) + | summarize RecentTotal=count(), RecentMl=countif(IsMlOnly) + | extend RecentRatio=iff(RecentTotal == 0, 0.0, todouble(RecentMl) / RecentTotal); + let Baseline = FirepowerEvents + | where TimeGenerated between (ago(8d) .. ago(1d)) + | summarize BaselineTotal=count(), BaselineMl=countif(IsMlOnly) + | extend BaselineRatio=iff(BaselineTotal == 0, 0.0, todouble(BaselineMl) / BaselineTotal); + Recent + | extend JoinKey=1 + | join kind=inner (Baseline | extend JoinKey=1) on JoinKey + | where RecentTotal >= 20 and BaselineTotal >= 100 + | where RecentRatio >= 0.25 and RecentRatio >= (BaselineRatio * 2.0) + | project TimeGenerated=now(), RecentTotal, RecentMl, RecentRatio, BaselineTotal, BaselineMl, BaselineRatio, + DriftMultiple=round(RecentRatio / iff(BaselineRatio == 0.0, 0.0001, BaselineRatio), 2) +version: 1.0.0 +kind: Scheduled diff --git a/Solutions/Cisco Firepower EStreamer/Analytic Rules/CiscoFirepower-Signature-And-ML-Corroboration.yaml b/Solutions/Cisco Firepower EStreamer/Analytic Rules/CiscoFirepower-Signature-And-ML-Corroboration.yaml new file mode 100644 index 00000000000..24b0e914650 --- /dev/null +++ b/Solutions/Cisco Firepower EStreamer/Analytic Rules/CiscoFirepower-Signature-And-ML-Corroboration.yaml @@ -0,0 +1,90 @@ +id: 511445a6-6f4c-4e6a-a655-76c25b66597b +name: Cisco Firepower - Signature and ML corroboration +description: | + 'Detects dual-signal corroboration on Cisco Firepower CEF: a classic high-priority IDS classification + (Generator ID not SnortML GID 411) co-occurring with an ML-only (GID 411 / SnortML) alert for the same + source and destination within a short window. + Signature + ML corroboration is a stronger remediation candidate than ML-only paths. + Prefer Gate/Prove HITL before BlockIP playbooks. Do not equate standalone ML confidence to signature TP.' +severity: High +status: Available +requiredDataConnectors: + - connectorId: CefAma + dataTypes: + - CommonSecurityLog +queryFrequency: 15m +queryPeriod: 30m +triggerOperator: gt +triggerThreshold: 0 +tactics: + - CommandAndControl + - Exfiltration +relevantTechniques: + - T1071 + - T1041 +query: | + let lookback = 30m; + let HighPriorityClassifications = dynamic([ + "A Network Trojan was Detected", + "A Network Trojan was detected", + "Successful Administrator Privilege Gain", + "Successful User Privilege Gain", + "Attempted Administrator Privilege Gain", + "Attempted User Privilege Gain", + "Known malware command and control traffic", + "Malware Command and Control Activity Detected", + "Large Scale Information Leak" + ]); + let Base = CommonSecurityLog + | where TimeGenerated > ago(lookback) + | where DeviceVendor =~ "Cisco" + | where DeviceProduct has_any ("Firepower", "Secure Firewall", "FTD", "NGFW") + | where isnotempty(SourceIP) and isnotempty(DestinationIP) + | extend Combined = strcat( + tostring(Message), " ", + tostring(AdditionalExtensions), " ", + tostring(Activity), " ", + tostring(DeviceEventClassID), " ", + tostring(column_ifexists("FlexString1", "")), " ", + tostring(column_ifexists("FlexString2", "")), " ", + tostring(column_ifexists("DeviceCustomString1", "")), " ", + tostring(column_ifexists("DeviceCustomString2", "")) + ) + | extend ParsedGid = toint(extract(@"(?i)(?:gid|generator[\s_-]?id)[\s:=]*(\d+)", 1, Combined)) + | extend IsMlOnly = ParsedGid == 411 or Combined has "is_ml_only" + | extend IsSignatureHigh = not(IsMlOnly) + and not(Combined has_any ("SnortML", "snortml")) + and ( + Combined has_any (HighPriorityClassifications) + or Activity has_any (HighPriorityClassifications) + ); + let Signatures = Base + | where IsSignatureHigh + | summarize SigTime=max(TimeGenerated), SigActivity=take_any(Activity), SigMessage=take_any(Message), DeviceName=take_any(DeviceName) + by SourceIP, DestinationIP, DestinationPort=tostring(DestinationPort), TimeBin=bin(TimeGenerated, 1m); + let MlOnly = Base + | where IsMlOnly and not(Combined has "is_corroborated") + | summarize MlTime=max(TimeGenerated), MlActivity=take_any(Activity), MlMessage=take_any(Message) + by SourceIP, DestinationIP, DestinationPort=tostring(DestinationPort), TimeBin=bin(TimeGenerated, 1m); + Signatures + | join kind=inner MlOnly on SourceIP, DestinationIP + | where abs(datetime_diff('minute', SigTime, MlTime)) <= 5 + | summarize arg_max(SigTime, *) by SourceIP, DestinationIP + | extend HostCustomEntity = DeviceName, SrcIpCustomEntity = SourceIP, DstIpCustomEntity = DestinationIP + | project SigTime, MlTime, DeviceName, SourceIP, DestinationIP, SigActivity, MlActivity, SigMessage, MlMessage, + HostCustomEntity, SrcIpCustomEntity, DstIpCustomEntity +entityMappings: + - entityType: Host + fieldMappings: + - identifier: FullName + columnName: HostCustomEntity + - entityType: IP + fieldMappings: + - identifier: Address + columnName: SrcIpCustomEntity + - entityType: IP + fieldMappings: + - identifier: Address + columnName: DstIpCustomEntity +version: 1.0.2 +kind: Scheduled diff --git a/Solutions/Cisco Firepower EStreamer/Analytic Rules/CiscoFirepower-SnortML-GID411-MLOnly.yaml b/Solutions/Cisco Firepower EStreamer/Analytic Rules/CiscoFirepower-SnortML-GID411-MLOnly.yaml new file mode 100644 index 00000000000..8503ab631c4 --- /dev/null +++ b/Solutions/Cisco Firepower EStreamer/Analytic Rules/CiscoFirepower-SnortML-GID411-MLOnly.yaml @@ -0,0 +1,60 @@ +id: bab70c8d-220e-46dc-aef2-1411eb43284e +name: Cisco Firepower - SnortML GID 411 ML-only high alert +description: | + 'Detects Cisco Firepower / Snort-family intrusion events generated by SnortML (Generator ID / GID 411). + SnortML scores are machine-learning probability signals and must not be treated as equivalent to a classic Snort signature true positive (typically GID 1). + High ML-only confidence should escalate for corroboration - not automatic containment via BlockIP playbooks. + Pair with "Cisco Firepower - IDS signature high priority classification" and "Cisco Firepower - Signature and ML corroboration". + Related portable encodings: OCSF is_ml_only (ocsf-schema#1732), SigmaHQ/sigma#6237, elastic/detection-rules#6662.' +severity: Medium +status: Available +requiredDataConnectors: + - connectorId: CefAma + dataTypes: + - CommonSecurityLog +queryFrequency: 15m +queryPeriod: 15m +triggerOperator: gt +triggerThreshold: 0 +tactics: + - CommandAndControl + - Exfiltration +relevantTechniques: + - T1071 + - T1041 +query: | + CommonSecurityLog + | where DeviceVendor =~ "Cisco" + | where DeviceProduct has_any ("Firepower", "Secure Firewall", "FTD", "NGFW") + | extend Combined = strcat( + tostring(Message), " ", + tostring(AdditionalExtensions), " ", + tostring(Activity), " ", + tostring(DeviceEventClassID), " ", + tostring(column_ifexists("FlexString1", "")), " ", + tostring(column_ifexists("FlexString2", "")), " ", + tostring(column_ifexists("DeviceCustomString1", "")), " ", + tostring(column_ifexists("DeviceCustomString2", "")), " ", + tostring(column_ifexists("DeviceCustomString3", "")) + ) + | extend ParsedGid = toint(extract(@"(?i)(?:gid|generator[\s_-]?id)[\s:=]*(\d+)", 1, Combined)) + | where ParsedGid == 411 or Combined has "is_ml_only" + | where not(Combined has "is_corroborated") + | extend HostCustomEntity = DeviceName, SrcIpCustomEntity = SourceIP, DstIpCustomEntity = DestinationIP + | project TimeGenerated, DeviceName, SourceIP, DestinationIP, DestinationPort, Activity, DeviceAction, + DeviceEventClassID, Message, AdditionalExtensions, HostCustomEntity, SrcIpCustomEntity, DstIpCustomEntity +entityMappings: + - entityType: Host + fieldMappings: + - identifier: FullName + columnName: HostCustomEntity + - entityType: IP + fieldMappings: + - identifier: Address + columnName: SrcIpCustomEntity + - entityType: IP + fieldMappings: + - identifier: Address + columnName: DstIpCustomEntity +version: 1.0.2 +kind: Scheduled diff --git a/Solutions/Cisco Firepower EStreamer/Data/Solution_Cisco Firepower EStreamer.json b/Solutions/Cisco Firepower EStreamer/Data/Solution_Cisco Firepower EStreamer.json index 70f2d4291d2..37f60e1383f 100644 --- a/Solutions/Cisco Firepower EStreamer/Data/Solution_Cisco Firepower EStreamer.json +++ b/Solutions/Cisco Firepower EStreamer/Data/Solution_Cisco Firepower EStreamer.json @@ -5,7 +5,16 @@ "Description": "The [Cisco Firepower](https://www.cisco.com/site/in/en/products/security/firewalls/index.html) eStreamer Solution for Microsoft Sentinel works with [Cisco Event Streamer](https://github.com/CiscoSecurity/fp-05-microsoft-sentinel-connector) (also known as eStreamer) and allows you to stream System intrusion, discovery and connection data from Firepower Management Center (FMC) or managed device to Microsoft Sentinel \r\n eStreamer is a Client Server API designed for the Cisco Firepower NGFW Solution. The eStreamer client requests detailed event data on behalf of the SIEM or logging solution in the Common Event Format (CEF).\n\n This solution is dependent on the Common Event Format solution containing the CEF via AMA connector to collect the logs. The CEF solution will be installed as part of this solution installation.\n\n**NOTE: **Microsoft recommends installation of CEF via AMA Connector. The existing connectors are about to be deprecated by Aug 31, 2024.", "Data Connectors": [ "Data Connectors/CiscoFirepowerEStreamerCollector.json", - "Data Connectors/template_CiscoFirepowerEStreamerAMA.json" + "Data Connectors/template_CiscoFirepowerEStreamerAMA.json" + ], + "Analytic Rules": [ + "Analytic Rules/CiscoFirepower-SnortML-GID411-MLOnly.yaml", + "Analytic Rules/CiscoFirepower-IDS-Signature-HighPriority.yaml", + "Analytic Rules/CiscoFirepower-Signature-And-ML-Corroboration.yaml", + "Analytic Rules/CiscoFirepower-Signal-Mix-Drift.yaml" + ], + "Workbooks": [ + "Workbooks/CiscoFirepowerDetectionResponseQuality.json" ], "Playbooks": [ "Playbooks/CiscoFirepowerConnector/azuredeploy.json", @@ -15,10 +24,10 @@ ], "dependentDomainSolutionIds": [ "azuresentinel.azure-sentinel-solution-commoneventformat" - ], + ], "BasePath": "C:\\Github\\Azure-Sentinel\\Solutions\\Cisco Firepower EStreamer", - "Version": "3.0.1", + "Version": "3.1.0", "Metadata": "SolutionMetadata.json", "TemplateSpec": true, "Is1Pconnector": false -} \ No newline at end of file +} diff --git a/Solutions/Cisco Firepower EStreamer/Evaluation/FirepowerOutcome-v1.md b/Solutions/Cisco Firepower EStreamer/Evaluation/FirepowerOutcome-v1.md new file mode 100644 index 00000000000..c3ac332acfb --- /dev/null +++ b/Solutions/Cisco Firepower EStreamer/Evaluation/FirepowerOutcome-v1.md @@ -0,0 +1,38 @@ +# Cisco Firepower response outcome contract v1 + +This contract makes detection and response decisions machine-readable without introducing a new data store or an AI dependency. Playbooks emit the record in a Microsoft Sentinel incident comment. Humans remain authoritative for containment decisions. + +## Record format + +```text +[FirepowerOutcome:v1] signal=; decision=; containment=; reason=; ruleVersion=; policyVersion=1.0.0 +``` + +Values are deliberately bounded. Free-form analyst explanation may follow the record but must not replace it. + +## Safety invariants + +1. `signal=ml-only` cannot produce automatic containment. The Teams HITL path requires an explicit analyst decision and records that decision before any change. +2. An AI-generated recommendation cannot modify production analytics, policies, or Firepower objects directly. +3. Candidate changes must be replayed against the cases below and reviewed by a human. +4. Every promoted change records its rule, playbook, policy, and evaluation-corpus versions. +5. Ambiguous parsing fails closed to `signal=unknown` and cannot silently become an automatic containment path. + +## Deterministic evaluation cases + +| Case | Evidence | Expected signal | Expected decision/outcome | +|---|---|---|---| +| E01 | GID 411 only | `ml-only` | `policy-denied/not-attempted` | +| E02 | `is_ml_only` only | `ml-only` | `policy-denied/not-attempted` | +| E03 | GID 1 and high-priority classification | `signature` | eligible for policy-controlled response | +| E04 | GID 411 plus independent signature for the same flow/window | `corroborated` | eligible for HITL response | +| E05 | malformed or missing GID | `unknown` | no automatic containment | +| E06 | no IP entity | any | `not-required/not-attempted` | +| E07 | Firepower object does not exist | any eligible | `approved/failed` | +| E08 | Firepower update succeeds | any eligible | `approved/succeeded` | +| E09 | analyst rejects Teams card | any | `rejected/not-attempted` | +| E10 | Teams approval expires | any | `unknown/not-attempted` | + +## Controlled improvement loop + +Outcome records and workbook trends may be used by an external agent to propose KQL, mapping, threshold, or playbook changes. A proposal must include the triggering evidence, a diff, replay results for every evaluation case, cost impact, safety-invariant results, and a rollback condition. Promotion occurs only through a reviewed pull request and canary deployment. diff --git a/Solutions/Cisco Firepower EStreamer/Package/3.0.4.zip b/Solutions/Cisco Firepower EStreamer/Package/3.0.4.zip new file mode 100644 index 00000000000..7d2e8d6949a Binary files /dev/null and b/Solutions/Cisco Firepower EStreamer/Package/3.0.4.zip differ diff --git a/Solutions/Cisco Firepower EStreamer/Package/3.0.5.zip b/Solutions/Cisco Firepower EStreamer/Package/3.0.5.zip new file mode 100644 index 00000000000..879a4119312 Binary files /dev/null and b/Solutions/Cisco Firepower EStreamer/Package/3.0.5.zip differ diff --git a/Solutions/Cisco Firepower EStreamer/Package/3.1.0.zip b/Solutions/Cisco Firepower EStreamer/Package/3.1.0.zip new file mode 100644 index 00000000000..b154e231c7c Binary files /dev/null and b/Solutions/Cisco Firepower EStreamer/Package/3.1.0.zip differ diff --git a/Solutions/Cisco Firepower EStreamer/Package/createUiDefinition.json b/Solutions/Cisco Firepower EStreamer/Package/createUiDefinition.json index 97eeeac47e9..1a3f904e987 100644 --- a/Solutions/Cisco Firepower EStreamer/Package/createUiDefinition.json +++ b/Solutions/Cisco Firepower EStreamer/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/Cisco%20Firepower%20EStreamer/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 [Cisco Firepower](https://www.cisco.com/site/in/en/products/security/firewalls/index.html) eStreamer Solution for Microsoft Sentinel works with [Cisco Event Streamer](https://github.com/CiscoSecurity/fp-05-microsoft-sentinel-connector) (also known as eStreamer) and allows you to stream System intrusion, discovery and connection data from Firepower Management Center (FMC) or managed device to Microsoft Sentinel \r\n eStreamer is a Client Server API designed for the Cisco Firepower NGFW Solution. The eStreamer client requests detailed event data on behalf of the SIEM or logging solution in the Common Event Format (CEF).\n\n This solution is dependent on the Common Event Format solution containing the CEF via AMA connector to collect the logs. The CEF solution will be installed as part of this solution installation.\n\n**NOTE: **Microsoft recommends installation of CEF via AMA Connector. The existing connectors are about to be deprecated by Aug 31, 2024.\n\n**Data Connectors:** 2, **Custom Azure Logic Apps Connectors:** 1, **Playbooks:** 3\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/Cisco%20Firepower%20EStreamer/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 [Cisco Firepower](https://www.cisco.com/site/in/en/products/security/firewalls/index.html) eStreamer Solution for Microsoft Sentinel works with [Cisco Event Streamer](https://github.com/CiscoSecurity/fp-05-microsoft-sentinel-connector) (also known as eStreamer) and allows you to stream System intrusion, discovery and connection data from Firepower Management Center (FMC) or managed device to Microsoft Sentinel \r\n eStreamer is a Client Server API designed for the Cisco Firepower NGFW Solution. The eStreamer client requests detailed event data on behalf of the SIEM or logging solution in the Common Event Format (CEF).\n\n This solution is dependent on the Common Event Format solution containing the CEF via AMA connector to collect the logs. The CEF solution will be installed as part of this solution installation.\n\n**NOTE: **Microsoft recommends installation of CEF via AMA Connector. The existing connectors are about to be deprecated by Aug 31, 2024.\n\n**Data Connectors:** 2, **Workbooks:** 1, **Analytic Rules:** 4, **Custom Azure Logic Apps Connectors:** 1, **Playbooks:** 3\n\n[Learn more about Microsoft Sentinel](https://aka.ms/azuresentinel) | [Learn more about Solutions](https://aka.ms/azuresentinelsolutionsdoc)", "subscription": { "resourceProviders": [ "Microsoft.OperationsManagement/solutions", @@ -63,6 +63,13 @@ "text": "This Solution installs the data connector for Cisco Firepower EStreamer. You can get Cisco Firepower EStreamer CommonSecurityLog data in your Microsoft Sentinel workspace. After installing the solution, configure and enable this data connector by following guidance in Manage solution view." } }, + { + "name": "dataconnectors2-text", + "type": "Microsoft.Common.TextBlock", + "options": { + "text": "This Solution installs the data connector for Cisco Firepower EStreamer. You can get Cisco Firepower EStreamer CommonSecurityLog data in your Microsoft Sentinel workspace. After installing the solution, configure and enable this data connector by following guidance in Manage solution view." + } + }, { "name": "dataconnectors-link2", "type": "Microsoft.Common.TextBlock", @@ -75,6 +82,132 @@ } ] }, + { + "name": "workbooks", + "label": "Workbooks", + "subLabel": { + "preValidation": "Configure the workbooks", + "postValidation": "Done" + }, + "bladeTitle": "Workbooks", + "elements": [ + { + "name": "workbooks-text", + "type": "Microsoft.Common.TextBlock", + "options": { + "text": "This solution installs workbook(s) to help you gain insights into the telemetry collected in Microsoft Sentinel. After installing the solution, start using the workbook in Manage solution view." + } + }, + { + "name": "workbooks-link", + "type": "Microsoft.Common.TextBlock", + "options": { + "link": { + "label": "Learn more", + "uri": "https://docs.microsoft.com/azure/sentinel/tutorial-monitor-your-data" + } + } + }, + { + "name": "workbook1", + "type": "Microsoft.Common.Section", + "label": "Cisco Firepower Detection and Response Quality", + "elements": [ + { + "name": "workbook1-text", + "type": "Microsoft.Common.TextBlock", + "options": { + "text": "Evaluates Cisco Firepower detection signal composition and drift while preserving the safety boundary between SnortML GID 411, classic signatures, and corroborated evidence." + } + } + ] + } + ] + }, + { + "name": "analytics", + "label": "Analytics", + "subLabel": { + "preValidation": "Configure the analytics", + "postValidation": "Done" + }, + "bladeTitle": "Analytics", + "elements": [ + { + "name": "analytics-text", + "type": "Microsoft.Common.TextBlock", + "options": { + "text": "This solution installs the following analytic rule templates. After installing the solution, create and enable analytic rules in Manage solution view." + } + }, + { + "name": "analytics-link", + "type": "Microsoft.Common.TextBlock", + "options": { + "link": { + "label": "Learn more", + "uri": "https://docs.microsoft.com/azure/sentinel/tutorial-detect-threats-custom?WT.mc_id=Portal-Microsoft_Azure_CreateUIDef" + } + } + }, + { + "name": "analytic1", + "type": "Microsoft.Common.Section", + "label": "Cisco Firepower - SnortML GID 411 ML-only high alert", + "elements": [ + { + "name": "analytic1-text", + "type": "Microsoft.Common.TextBlock", + "options": { + "text": "Detects Cisco Firepower / Snort-family intrusion events generated by SnortML (Generator ID / GID 411).\nSnortML scores are machine-learning probability signals and must not be treated as equivalent to a classic Snort signature true positive (typically GID 1).\nHigh ML-only confidence should escalate for corroboration - not automatic containment via BlockIP playbooks.\nPair with \"Cisco Firepower - IDS signature high priority classification\" and \"Cisco Firepower - Signature and ML corroboration\".\nRelated portable encodings: OCSF is_ml_only (ocsf-schema#1732), SigmaHQ/sigma#6237, elastic/detection-rules#6662." + } + } + ] + }, + { + "name": "analytic2", + "type": "Microsoft.Common.Section", + "label": "Cisco Firepower - IDS signature high priority classification", + "elements": [ + { + "name": "analytic2-text", + "type": "Microsoft.Common.TextBlock", + "options": { + "text": "Detects classic Cisco Firepower / Snort-family signature hits (Generator ID not equal to SnortML GID 411)\nwith high-priority classifications commonly associated with malware C2, privilege gain, or network trojans.\nThese events are stronger signature true-positive candidates than ML-only (GID 411) paths and may justify\ngated remediation after analyst or policy review - prefer HITL Gate/Prove over ungated BlockIP automation.\nPair with \"Cisco Firepower - SnortML GID 411 ML-only high alert\" and \"Cisco Firepower - Signature and ML corroboration\"." + } + } + ] + }, + { + "name": "analytic3", + "type": "Microsoft.Common.Section", + "label": "Cisco Firepower - Signature and ML corroboration", + "elements": [ + { + "name": "analytic3-text", + "type": "Microsoft.Common.TextBlock", + "options": { + "text": "Detects dual-signal corroboration on Cisco Firepower CEF: a classic high-priority IDS classification\n(Generator ID not SnortML GID 411) co-occurring with an ML-only (GID 411 / SnortML) alert for the same\nsource and destination within a short window.\nSignature + ML corroboration is a stronger remediation candidate than ML-only paths.\nPrefer Gate/Prove HITL before BlockIP playbooks. Do not equate standalone ML confidence to signature TP." + } + } + ] + }, + { + "name": "analytic4", + "type": "Microsoft.Common.Section", + "label": "Cisco Firepower - SnortML signal mix drift", + "elements": [ + { + "name": "analytic4-text", + "type": "Microsoft.Common.TextBlock", + "options": { + "text": "Detects a material increase in the proportion of SnortML GID 411 events compared with the preceding seven-day baseline.\nThis is a detection-quality regression signal, not evidence that an individual event is malicious. Investigate collector,\nsensor, model, policy, and traffic changes before modifying response automation. ML-only events must not trigger automatic containment." + } + } + ] + } + ] + }, { "name": "playbooks", "label": "Playbooks", diff --git a/Solutions/Cisco Firepower EStreamer/Package/mainTemplate.json b/Solutions/Cisco Firepower EStreamer/Package/mainTemplate.json index 28b684b3f05..610a67f77fc 100644 --- a/Solutions/Cisco Firepower EStreamer/Package/mainTemplate.json +++ b/Solutions/Cisco Firepower EStreamer/Package/mainTemplate.json @@ -27,11 +27,19 @@ "metadata": { "description": "Workspace name for Log Analytics where Microsoft Sentinel is setup" } + }, + "workbook1-name": { + "type": "string", + "defaultValue": "Cisco Firepower Detection and Response Quality", + "minLength": 1, + "metadata": { + "description": "Name for the workbook" + } } }, "variables": { "_solutionName": "Cisco Firepower EStreamer", - "_solutionVersion": "3.0.0", + "_solutionVersion": "3.1.0", "solutionId": "cisco.cisco-firepower-estreamer", "_solutionId": "[variables('solutionId')]", "uiConfigId1": "CiscoFirepowerEStreamer", @@ -52,6 +60,41 @@ "dataConnectorTemplateSpecName2": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-dc-',uniquestring(variables('_dataConnectorContentId2'))))]", "dataConnectorVersion2": "1.0.0", "_dataConnectorcontentProductId2": "[concat(take(variables('_solutionId'),50),'-','dc','-', uniqueString(concat(variables('_solutionId'),'-','DataConnector','-',variables('_dataConnectorContentId2'),'-', variables('dataConnectorVersion2'))))]", + "analyticRuleObject1": { + "analyticRuleVersion1": "1.0.2", + "_analyticRulecontentId1": "bab70c8d-220e-46dc-aef2-1411eb43284e", + "analyticRuleId1": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', 'bab70c8d-220e-46dc-aef2-1411eb43284e')]", + "analyticRuleTemplateSpecName1": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring('bab70c8d-220e-46dc-aef2-1411eb43284e')))]", + "_analyticRulecontentProductId1": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','bab70c8d-220e-46dc-aef2-1411eb43284e','-', '1.0.2')))]" + }, + "analyticRuleObject2": { + "analyticRuleVersion2": "1.0.2", + "_analyticRulecontentId2": "a1c9e026-9bb7-4c42-a3a1-83faa3ca26a6", + "analyticRuleId2": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', 'a1c9e026-9bb7-4c42-a3a1-83faa3ca26a6')]", + "analyticRuleTemplateSpecName2": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring('a1c9e026-9bb7-4c42-a3a1-83faa3ca26a6')))]", + "_analyticRulecontentProductId2": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','a1c9e026-9bb7-4c42-a3a1-83faa3ca26a6','-', '1.0.2')))]" + }, + "analyticRuleObject3": { + "analyticRuleVersion3": "1.0.2", + "_analyticRulecontentId3": "511445a6-6f4c-4e6a-a655-76c25b66597b", + "analyticRuleId3": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', '511445a6-6f4c-4e6a-a655-76c25b66597b')]", + "analyticRuleTemplateSpecName3": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring('511445a6-6f4c-4e6a-a655-76c25b66597b')))]", + "_analyticRulecontentProductId3": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','511445a6-6f4c-4e6a-a655-76c25b66597b','-', '1.0.2')))]" + }, + "analyticRuleObject4": { + "analyticRuleVersion4": "1.0.0", + "_analyticRulecontentId4": "6ff65bb5-53bd-4ffb-a62a-25ea71c04eed", + "analyticRuleId4": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', '6ff65bb5-53bd-4ffb-a62a-25ea71c04eed')]", + "analyticRuleTemplateSpecName4": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring('6ff65bb5-53bd-4ffb-a62a-25ea71c04eed')))]", + "_analyticRulecontentProductId4": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','6ff65bb5-53bd-4ffb-a62a-25ea71c04eed','-', '1.0.0')))]" + }, + "workbookVersion1": "1.0.0", + "workbookContentId1": "CiscoFirepowerDetectionResponseQuality", + "workbookId1": "[resourceId('Microsoft.Insights/workbooks', variables('workbookContentId1'))]", + "workbookTemplateSpecName1": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-wb-',uniquestring(variables('_workbookContentId1'))))]", + "_workbookContentId1": "[variables('workbookContentId1')]", + "workspaceResourceId": "[resourceId('microsoft.OperationalInsights/Workspaces', parameters('workspace'))]", + "_workbookcontentProductId1": "[concat(take(variables('_solutionId'),50),'-','wb','-', uniqueString(concat(variables('_solutionId'),'-','Workbook','-',variables('_workbookContentId1'),'-', variables('workbookVersion1'))))]", "CiscoFirepowerConnector": "CiscoFirepowerConnector", "_CiscoFirepowerConnector": "[variables('CiscoFirepowerConnector')]", "TemplateEmptyArray": "[json('[]')]", @@ -59,7 +102,6 @@ "playbookContentId1": "CiscoFirepowerConnector", "_playbookContentId1": "[variables('playbookContentId1')]", "playbookTemplateSpecName1": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-lc-',uniquestring(variables('_playbookContentId1'))))]", - "workspaceResourceId": "[resourceId('microsoft.OperationalInsights/Workspaces', parameters('workspace'))]", "_playbookcontentProductId1": "[concat(take(variables('_solutionId'),50),'-','lc','-', uniqueString(concat(variables('_solutionId'),'-','LogicAppsCustomConnector','-',variables('_playbookContentId1'),'-', variables('playbookVersion1'))))]", "CiscoFirepower-BlockFQDN-NetworkGroup": "CiscoFirepower-BlockFQDN-NetworkGroup", "_CiscoFirepower-BlockFQDN-NetworkGroup": "[variables('CiscoFirepower-BlockFQDN-NetworkGroup')]", @@ -71,7 +113,7 @@ "_playbookcontentProductId2": "[concat(take(variables('_solutionId'),50),'-','pl','-', uniqueString(concat(variables('_solutionId'),'-','Playbook','-',variables('_playbookContentId2'),'-', variables('playbookVersion2'))))]", "CiscoFirepower-BlockIP-NetworkGroup": "CiscoFirepower-BlockIP-NetworkGroup", "_CiscoFirepower-BlockIP-NetworkGroup": "[variables('CiscoFirepower-BlockIP-NetworkGroup')]", - "playbookVersion3": "1.0", + "playbookVersion3": "1.1", "playbookContentId3": "CiscoFirepower-BlockIP-NetworkGroup", "_playbookContentId3": "[variables('playbookContentId3')]", "playbookId3": "[resourceId('Microsoft.Logic/workflows', variables('playbookContentId3'))]", @@ -79,7 +121,7 @@ "_playbookcontentProductId3": "[concat(take(variables('_solutionId'),50),'-','pl','-', uniqueString(concat(variables('_solutionId'),'-','Playbook','-',variables('_playbookContentId3'),'-', variables('playbookVersion3'))))]", "CiscoFirepower-BlockIP-Teams": "CiscoFirepower-BlockIP-Teams", "_CiscoFirepower-BlockIP-Teams": "[variables('CiscoFirepower-BlockIP-Teams')]", - "playbookVersion4": "1.0", + "playbookVersion4": "1.1", "playbookContentId4": "CiscoFirepower-BlockIP-Teams", "_playbookContentId4": "[variables('playbookContentId4')]", "playbookId4": "[resourceId('Microsoft.Logic/workflows', variables('playbookContentId4'))]", @@ -97,7 +139,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "Cisco Firepower EStreamer data connector with template version 3.0.0", + "description": "Cisco Firepower EStreamer data connector with template version 3.1.0", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('dataConnectorVersion1')]", @@ -478,7 +520,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "Cisco Firepower EStreamer data connector with template version 3.0.0", + "description": "Cisco Firepower EStreamer data connector with template version 3.1.0", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('dataConnectorVersion2')]", @@ -577,8 +619,8 @@ "instructionSteps": [ { "title": "Step A. Configure the Common Event Format (CEF) via AMA data connector", - "description": "_Note:- CEF logs are collected only from Linux Agents_\n\n1. Navigate to Microsoft Sentinel workspace ---> configuration ---> Data connector blade .\n\n2. Search for 'Common Event Format (CEF) via AMA' data connector and open it.\n\n3. Check If there is no existing DCR configured to collect required facility of logs, Create a new DCR (Data Collection Rule)\n\n\t_Note:- It is recommended to install minimum 1.27 version of AMA agent [Learn more](https://learn.microsoft.com/azure/azure-monitor/agents/azure-monitor-agent-manage?tabs=azure-portal ) and ensure there is no duplicate DCR as it can cause log duplicacy_\n\n4. Run the command provided in the CEF via AMA data connector page to configure the CEF collector on the machine" - + "description": "_Note:- CEF logs are collected only from Linux Agents_\n\n1. Navigate to Microsoft Sentinel workspace ---> configuration ---> Data connector blade .\n\n2. Search for 'Common Event Format (CEF) via AMA' data connector and open it.\n\n3. Check If there is no existing DCR configured to collect required facility of logs, Create a new DCR (Data Collection Rule)\n\n\t_Note:- It is recommended to install minimum 1.27 version of AMA agent [Learn more](https://learn.microsoft.com/azure/azure-monitor/agents/azure-monitor-agent-manage?tabs=azure-portal ) and ensure there is no duplicate DCR as it can cause log duplicacy_\n\n4. Run the command provided in the CEF via AMA data connector page to configure the CEF collector on the machine", + "instructions": [] }, { "title": "Step B. Install the Firepower eNcore client", @@ -787,8 +829,8 @@ "instructionSteps": [ { "title": "Step A. Configure the Common Event Format (CEF) via AMA data connector", - "description": "_Note:- CEF logs are collected only from Linux Agents_\n\n1. Navigate to Microsoft Sentinel workspace ---> configuration ---> Data connector blade .\n\n2. Search for 'Common Event Format (CEF) via AMA' data connector and open it.\n\n3. Check If there is no existing DCR configured to collect required facility of logs, Create a new DCR (Data Collection Rule)\n\n\t_Note:- It is recommended to install minimum 1.27 version of AMA agent [Learn more](https://learn.microsoft.com/azure/azure-monitor/agents/azure-monitor-agent-manage?tabs=azure-portal ) and ensure there is no duplicate DCR as it can cause log duplicacy_\n\n4. Run the command provided in the CEF via AMA data connector page to configure the CEF collector on the machine" - + "description": "_Note:- CEF logs are collected only from Linux Agents_\n\n1. Navigate to Microsoft Sentinel workspace ---> configuration ---> Data connector blade .\n\n2. Search for 'Common Event Format (CEF) via AMA' data connector and open it.\n\n3. Check If there is no existing DCR configured to collect required facility of logs, Create a new DCR (Data Collection Rule)\n\n\t_Note:- It is recommended to install minimum 1.27 version of AMA agent [Learn more](https://learn.microsoft.com/azure/azure-monitor/agents/azure-monitor-agent-manage?tabs=azure-portal ) and ensure there is no duplicate DCR as it can cause log duplicacy_\n\n4. Run the command provided in the CEF via AMA data connector page to configure the CEF collector on the machine", + "instructions": [] }, { "title": "Step B. Install the Firepower eNcore client", @@ -840,6 +882,549 @@ } } }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleObject1').analyticRuleTemplateSpecName1]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "CiscoFirepower-SnortML-GID411-MLOnly_AnalyticalRules Analytics Rule with template version 3.1.0", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleObject1').analyticRuleVersion1]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRuleObject1')._analyticRulecontentId1]", + "apiVersion": "2023-02-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "Detects Cisco Firepower / Snort-family intrusion events generated by SnortML (Generator ID / GID 411).\nSnortML scores are machine-learning probability signals and must not be treated as equivalent to a classic Snort signature true positive (typically GID 1).\nHigh ML-only confidence should escalate for corroboration - not automatic containment via BlockIP playbooks.\nPair with \"Cisco Firepower - IDS signature high priority classification\" and \"Cisco Firepower - Signature and ML corroboration\".\nRelated portable encodings: OCSF is_ml_only (ocsf-schema#1732), SigmaHQ/sigma#6237, elastic/detection-rules#6662.", + "displayName": "Cisco Firepower - SnortML GID 411 ML-only high alert", + "enabled": false, + "query": "CommonSecurityLog\n| where DeviceVendor =~ \"Cisco\"\n| where DeviceProduct has_any (\"Firepower\", \"Secure Firewall\", \"FTD\", \"NGFW\")\n| extend Combined = strcat(\n tostring(Message), \" \",\n tostring(AdditionalExtensions), \" \",\n tostring(Activity), \" \",\n tostring(DeviceEventClassID), \" \",\n tostring(column_ifexists(\"FlexString1\", \"\")), \" \",\n tostring(column_ifexists(\"FlexString2\", \"\")), \" \",\n tostring(column_ifexists(\"DeviceCustomString1\", \"\")), \" \",\n tostring(column_ifexists(\"DeviceCustomString2\", \"\")), \" \",\n tostring(column_ifexists(\"DeviceCustomString3\", \"\"))\n )\n| extend ParsedGid = toint(extract(@\"(?i)(?:gid|generator[\\s_-]?id)[\\s:=]*(\\d+)\", 1, Combined))\n| where ParsedGid == 411 or Combined has \"is_ml_only\"\n| where not(Combined has \"is_corroborated\")\n| extend HostCustomEntity = DeviceName, SrcIpCustomEntity = SourceIP, DstIpCustomEntity = DestinationIP\n| project TimeGenerated, DeviceName, SourceIP, DestinationIP, DestinationPort, Activity, DeviceAction,\n DeviceEventClassID, Message, AdditionalExtensions, HostCustomEntity, SrcIpCustomEntity, DstIpCustomEntity\n", + "queryFrequency": "PT15M", + "queryPeriod": "PT15M", + "severity": "Medium", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "CefAma", + "dataTypes": [ + "CommonSecurityLog" + ] + } + ], + "tactics": [ + "CommandAndControl", + "Exfiltration" + ], + "techniques": [ + "T1071", + "T1041" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "identifier": "FullName", + "columnName": "HostCustomEntity" + } + ], + "entityType": "Host" + }, + { + "fieldMappings": [ + { + "identifier": "Address", + "columnName": "SrcIpCustomEntity" + } + ], + "entityType": "IP" + }, + { + "fieldMappings": [ + { + "identifier": "Address", + "columnName": "DstIpCustomEntity" + } + ], + "entityType": "IP" + } + ] + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleObject1').analyticRuleId1,'/'))))]", + "properties": { + "description": "Cisco Firepower EStreamer Analytics Rule 1", + "parentId": "[variables('analyticRuleObject1').analyticRuleId1]", + "contentId": "[variables('analyticRuleObject1')._analyticRulecontentId1]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleObject1').analyticRuleVersion1]", + "source": { + "kind": "Solution", + "name": "Cisco Firepower EStreamer", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Cisco" + }, + "support": { + "name": "Cisco", + "tier": "Partner", + "link": "https://www.cisco.com/c/en_in/support/index.html" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('analyticRuleObject1')._analyticRulecontentId1]", + "contentKind": "AnalyticsRule", + "displayName": "Cisco Firepower - SnortML GID 411 ML-only high alert", + "contentProductId": "[variables('analyticRuleObject1')._analyticRulecontentProductId1]", + "id": "[variables('analyticRuleObject1')._analyticRulecontentProductId1]", + "version": "[variables('analyticRuleObject1').analyticRuleVersion1]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleObject2').analyticRuleTemplateSpecName2]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "CiscoFirepower-IDS-Signature-HighPriority_AnalyticalRules Analytics Rule with template version 3.1.0", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleObject2').analyticRuleVersion2]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRuleObject2')._analyticRulecontentId2]", + "apiVersion": "2023-02-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "Detects classic Cisco Firepower / Snort-family signature hits (Generator ID not equal to SnortML GID 411)\nwith high-priority classifications commonly associated with malware C2, privilege gain, or network trojans.\nThese events are stronger signature true-positive candidates than ML-only (GID 411) paths and may justify\ngated remediation after analyst or policy review - prefer HITL Gate/Prove over ungated BlockIP automation.\nPair with \"Cisco Firepower - SnortML GID 411 ML-only high alert\" and \"Cisco Firepower - Signature and ML corroboration\".", + "displayName": "Cisco Firepower - IDS signature high priority classification", + "enabled": false, + "query": "let HighPriorityClassifications = dynamic([\n \"A Network Trojan was Detected\",\n \"A Network Trojan was detected\",\n \"Successful Administrator Privilege Gain\",\n \"Successful User Privilege Gain\",\n \"Attempted Administrator Privilege Gain\",\n \"Attempted User Privilege Gain\",\n \"Known malware command and control traffic\",\n \"Malware Command and Control Activity Detected\",\n \"Known malicious file or file based exploit\",\n \"Known client side exploit attempt\",\n \"Large Scale Information Leak\"\n]);\nCommonSecurityLog\n| where DeviceVendor =~ \"Cisco\"\n| where DeviceProduct has_any (\"Firepower\", \"Secure Firewall\", \"FTD\", \"NGFW\")\n| extend Combined = strcat(\n tostring(Message), \" \",\n tostring(AdditionalExtensions), \" \",\n tostring(Activity), \" \",\n tostring(DeviceEventClassID), \" \",\n tostring(column_ifexists(\"FlexString1\", \"\")), \" \",\n tostring(column_ifexists(\"FlexString2\", \"\")), \" \",\n tostring(column_ifexists(\"DeviceCustomString1\", \"\")), \" \",\n tostring(column_ifexists(\"DeviceCustomString2\", \"\")), \" \",\n tostring(column_ifexists(\"DeviceCustomString3\", \"\")), \" \",\n tostring(DeviceAction)\n )\n| extend ParsedGid = toint(extract(@\"(?i)(?:gid|generator[\\s_-]?id)[\\s:=]*(\\d+)\", 1, Combined))\n| where ParsedGid != 411 or isnull(ParsedGid)\n| where not(Combined has_any (\"SnortML\", \"snortml\", \"is_ml_only\"))\n| where Combined has_any (HighPriorityClassifications)\n or Activity has_any (HighPriorityClassifications)\n| extend HostCustomEntity = DeviceName, SrcIpCustomEntity = SourceIP, DstIpCustomEntity = DestinationIP\n| project TimeGenerated, DeviceName, SourceIP, DestinationIP, DestinationPort, Activity, DeviceAction,\n DeviceEventClassID, Message, AdditionalExtensions, HostCustomEntity, SrcIpCustomEntity, DstIpCustomEntity\n", + "queryFrequency": "PT15M", + "queryPeriod": "PT15M", + "severity": "High", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "CefAma", + "dataTypes": [ + "CommonSecurityLog" + ] + } + ], + "tactics": [ + "CommandAndControl", + "Execution" + ], + "techniques": [ + "T1071", + "T1203" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "identifier": "FullName", + "columnName": "HostCustomEntity" + } + ], + "entityType": "Host" + }, + { + "fieldMappings": [ + { + "identifier": "Address", + "columnName": "SrcIpCustomEntity" + } + ], + "entityType": "IP" + }, + { + "fieldMappings": [ + { + "identifier": "Address", + "columnName": "DstIpCustomEntity" + } + ], + "entityType": "IP" + } + ] + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleObject2').analyticRuleId2,'/'))))]", + "properties": { + "description": "Cisco Firepower EStreamer Analytics Rule 2", + "parentId": "[variables('analyticRuleObject2').analyticRuleId2]", + "contentId": "[variables('analyticRuleObject2')._analyticRulecontentId2]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleObject2').analyticRuleVersion2]", + "source": { + "kind": "Solution", + "name": "Cisco Firepower EStreamer", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Cisco" + }, + "support": { + "name": "Cisco", + "tier": "Partner", + "link": "https://www.cisco.com/c/en_in/support/index.html" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('analyticRuleObject2')._analyticRulecontentId2]", + "contentKind": "AnalyticsRule", + "displayName": "Cisco Firepower - IDS signature high priority classification", + "contentProductId": "[variables('analyticRuleObject2')._analyticRulecontentProductId2]", + "id": "[variables('analyticRuleObject2')._analyticRulecontentProductId2]", + "version": "[variables('analyticRuleObject2').analyticRuleVersion2]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleObject3').analyticRuleTemplateSpecName3]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "CiscoFirepower-Signature-And-ML-Corroboration_AnalyticalRules Analytics Rule with template version 3.1.0", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleObject3').analyticRuleVersion3]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRuleObject3')._analyticRulecontentId3]", + "apiVersion": "2023-02-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "Detects dual-signal corroboration on Cisco Firepower CEF: a classic high-priority IDS classification\n(Generator ID not SnortML GID 411) co-occurring with an ML-only (GID 411 / SnortML) alert for the same\nsource and destination within a short window.\nSignature + ML corroboration is a stronger remediation candidate than ML-only paths.\nPrefer Gate/Prove HITL before BlockIP playbooks. Do not equate standalone ML confidence to signature TP.", + "displayName": "Cisco Firepower - Signature and ML corroboration", + "enabled": false, + "query": "let lookback = 30m;\nlet HighPriorityClassifications = dynamic([\n \"A Network Trojan was Detected\",\n \"A Network Trojan was detected\",\n \"Successful Administrator Privilege Gain\",\n \"Successful User Privilege Gain\",\n \"Attempted Administrator Privilege Gain\",\n \"Attempted User Privilege Gain\",\n \"Known malware command and control traffic\",\n \"Malware Command and Control Activity Detected\",\n \"Large Scale Information Leak\"\n]);\nlet Base = CommonSecurityLog\n| where TimeGenerated > ago(lookback)\n| where DeviceVendor =~ \"Cisco\"\n| where DeviceProduct has_any (\"Firepower\", \"Secure Firewall\", \"FTD\", \"NGFW\")\n| where isnotempty(SourceIP) and isnotempty(DestinationIP)\n| extend Combined = strcat(\n tostring(Message), \" \",\n tostring(AdditionalExtensions), \" \",\n tostring(Activity), \" \",\n tostring(DeviceEventClassID), \" \",\n tostring(column_ifexists(\"FlexString1\", \"\")), \" \",\n tostring(column_ifexists(\"FlexString2\", \"\")), \" \",\n tostring(column_ifexists(\"DeviceCustomString1\", \"\")), \" \",\n tostring(column_ifexists(\"DeviceCustomString2\", \"\"))\n )\n| extend ParsedGid = toint(extract(@\"(?i)(?:gid|generator[\\s_-]?id)[\\s:=]*(\\d+)\", 1, Combined))\n| extend IsMlOnly = ParsedGid == 411 or Combined has \"is_ml_only\"\n| extend IsSignatureHigh = not(IsMlOnly)\n and not(Combined has_any (\"SnortML\", \"snortml\"))\n and (\n Combined has_any (HighPriorityClassifications)\n or Activity has_any (HighPriorityClassifications)\n );\nlet Signatures = Base\n| where IsSignatureHigh\n| summarize SigTime=max(TimeGenerated), SigActivity=take_any(Activity), SigMessage=take_any(Message), DeviceName=take_any(DeviceName)\n by SourceIP, DestinationIP, DestinationPort=tostring(DestinationPort), TimeBin=bin(TimeGenerated, 1m);\nlet MlOnly = Base\n| where IsMlOnly and not(Combined has \"is_corroborated\")\n| summarize MlTime=max(TimeGenerated), MlActivity=take_any(Activity), MlMessage=take_any(Message)\n by SourceIP, DestinationIP, DestinationPort=tostring(DestinationPort), TimeBin=bin(TimeGenerated, 1m);\nSignatures\n| join kind=inner MlOnly on SourceIP, DestinationIP\n| where abs(datetime_diff('minute', SigTime, MlTime)) <= 5\n| summarize arg_max(SigTime, *) by SourceIP, DestinationIP\n| extend HostCustomEntity = DeviceName, SrcIpCustomEntity = SourceIP, DstIpCustomEntity = DestinationIP\n| project SigTime, MlTime, DeviceName, SourceIP, DestinationIP, SigActivity, MlActivity, SigMessage, MlMessage,\n HostCustomEntity, SrcIpCustomEntity, DstIpCustomEntity\n", + "queryFrequency": "PT15M", + "queryPeriod": "PT30M", + "severity": "High", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "CefAma", + "dataTypes": [ + "CommonSecurityLog" + ] + } + ], + "tactics": [ + "CommandAndControl", + "Exfiltration" + ], + "techniques": [ + "T1071", + "T1041" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "identifier": "FullName", + "columnName": "HostCustomEntity" + } + ], + "entityType": "Host" + }, + { + "fieldMappings": [ + { + "identifier": "Address", + "columnName": "SrcIpCustomEntity" + } + ], + "entityType": "IP" + }, + { + "fieldMappings": [ + { + "identifier": "Address", + "columnName": "DstIpCustomEntity" + } + ], + "entityType": "IP" + } + ] + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleObject3').analyticRuleId3,'/'))))]", + "properties": { + "description": "Cisco Firepower EStreamer Analytics Rule 3", + "parentId": "[variables('analyticRuleObject3').analyticRuleId3]", + "contentId": "[variables('analyticRuleObject3')._analyticRulecontentId3]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleObject3').analyticRuleVersion3]", + "source": { + "kind": "Solution", + "name": "Cisco Firepower EStreamer", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Cisco" + }, + "support": { + "name": "Cisco", + "tier": "Partner", + "link": "https://www.cisco.com/c/en_in/support/index.html" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('analyticRuleObject3')._analyticRulecontentId3]", + "contentKind": "AnalyticsRule", + "displayName": "Cisco Firepower - Signature and ML corroboration", + "contentProductId": "[variables('analyticRuleObject3')._analyticRulecontentProductId3]", + "id": "[variables('analyticRuleObject3')._analyticRulecontentProductId3]", + "version": "[variables('analyticRuleObject3').analyticRuleVersion3]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleObject4').analyticRuleTemplateSpecName4]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "CiscoFirepower-Signal-Mix-Drift_AnalyticalRules Analytics Rule with template version 3.1.0", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleObject4').analyticRuleVersion4]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRuleObject4')._analyticRulecontentId4]", + "apiVersion": "2023-02-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "Detects a material increase in the proportion of SnortML GID 411 events compared with the preceding seven-day baseline.\nThis is a detection-quality regression signal, not evidence that an individual event is malicious. Investigate collector,\nsensor, model, policy, and traffic changes before modifying response automation. ML-only events must not trigger automatic containment.", + "displayName": "Cisco Firepower - SnortML signal mix drift", + "enabled": false, + "query": "let FirepowerEvents = materialize(\n CommonSecurityLog\n | where TimeGenerated >= ago(8d)\n | where DeviceVendor =~ \"Cisco\"\n | where DeviceProduct has_any (\"Firepower\", \"Secure Firewall\", \"FTD\", \"NGFW\")\n | extend Combined = strcat(tostring(Message), \" \", tostring(AdditionalExtensions), \" \", tostring(Activity), \" \", tostring(DeviceEventClassID), \" \", tostring(column_ifexists(\"FlexString1\", \"\")), \" \", tostring(column_ifexists(\"FlexString2\", \"\")), \" \", tostring(column_ifexists(\"DeviceCustomString1\", \"\")), \" \", tostring(column_ifexists(\"DeviceCustomString2\", \"\")), \" \", tostring(column_ifexists(\"DeviceCustomString3\", \"\")))\n | extend ParsedGid = toint(extract(@\"(?i)(?:gid|generator[\\s_-]?id)[\\s:=]*(\\d+)\", 1, Combined))\n | extend IsMlOnly = ParsedGid == 411 or Combined has \"is_ml_only\"\n);\nlet Recent = FirepowerEvents\n | where TimeGenerated >= ago(1h)\n | summarize RecentTotal=count(), RecentMl=countif(IsMlOnly)\n | extend RecentRatio=iff(RecentTotal == 0, 0.0, todouble(RecentMl) / RecentTotal);\nlet Baseline = FirepowerEvents\n | where TimeGenerated between (ago(8d) .. ago(1d))\n | summarize BaselineTotal=count(), BaselineMl=countif(IsMlOnly)\n | extend BaselineRatio=iff(BaselineTotal == 0, 0.0, todouble(BaselineMl) / BaselineTotal);\nRecent\n| extend JoinKey=1\n| join kind=inner (Baseline | extend JoinKey=1) on JoinKey\n| where RecentTotal >= 20 and BaselineTotal >= 100\n| where RecentRatio >= 0.25 and RecentRatio >= (BaselineRatio * 2.0)\n| project TimeGenerated=now(), RecentTotal, RecentMl, RecentRatio, BaselineTotal, BaselineMl, BaselineRatio,\n DriftMultiple=round(RecentRatio / iff(BaselineRatio == 0.0, 0.0001, BaselineRatio), 2)\n", + "queryFrequency": "PT1H", + "queryPeriod": "P8D", + "severity": "Medium", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "CefAma", + "dataTypes": [ + "CommonSecurityLog" + ] + } + ], + "tactics": [ + "DefenseEvasion" + ], + "techniques": [ + "T1562" + ] + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleObject4').analyticRuleId4,'/'))))]", + "properties": { + "description": "Cisco Firepower EStreamer Analytics Rule 4", + "parentId": "[variables('analyticRuleObject4').analyticRuleId4]", + "contentId": "[variables('analyticRuleObject4')._analyticRulecontentId4]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleObject4').analyticRuleVersion4]", + "source": { + "kind": "Solution", + "name": "Cisco Firepower EStreamer", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Cisco" + }, + "support": { + "name": "Cisco", + "tier": "Partner", + "link": "https://www.cisco.com/c/en_in/support/index.html" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('analyticRuleObject4')._analyticRulecontentId4]", + "contentKind": "AnalyticsRule", + "displayName": "Cisco Firepower - SnortML signal mix drift", + "contentProductId": "[variables('analyticRuleObject4')._analyticRulecontentProductId4]", + "id": "[variables('analyticRuleObject4')._analyticRulecontentProductId4]", + "version": "[variables('analyticRuleObject4').analyticRuleVersion4]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('workbookTemplateSpecName1')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "CiscoFirepowerDetectionResponseQuality Workbook with template version 3.1.0", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('workbookVersion1')]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.Insights/workbooks", + "name": "[variables('workbookContentId1')]", + "location": "[parameters('workspace-location')]", + "kind": "shared", + "apiVersion": "2021-08-01", + "metadata": { + "description": "Evaluates Cisco Firepower detection signal composition and drift while preserving the safety boundary between SnortML GID 411, classic signatures, and corroborated evidence." + }, + "properties": { + "displayName": "[parameters('workbook1-name')]", + "serializedData": "{\"version\":\"Notebook/1.0\",\"items\":[{\"type\":1,\"content\":{\"json\":\"# Cisco Firepower detection and response quality\\nThis workbook distinguishes ML-only, classic signature, and corroborated evidence. Trends are evaluation signals—not authorization for automatic containment.\"},\"name\":\"overview\"},{\"type\":9,\"content\":{\"version\":\"KqlParameterItem/1.0\",\"parameters\":[{\"id\":\"4a060f53-dba7-42f6-b59d-49289bedecfe\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"TimeRange\",\"type\":4,\"isRequired\":true,\"value\":{\"durationMs\":604800000},\"typeSettings\":{\"selectableValues\":[{\"durationMs\":86400000},{\"durationMs\":604800000},{\"durationMs\":2592000000}],\"allowCustom\":true}}],\"style\":\"pills\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},\"name\":\"parameters\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let F = CommonSecurityLog\\n| where DeviceVendor =~ 'Cisco' and DeviceProduct has_any ('Firepower','Secure Firewall','FTD','NGFW')\\n| extend C=strcat(tostring(Message),' ',tostring(AdditionalExtensions),' ',tostring(Activity),' ',tostring(DeviceEventClassID),' ',tostring(column_ifexists('FlexString1','')),' ',tostring(column_ifexists('FlexString2','')),' ',tostring(column_ifexists('DeviceCustomString1','')),' ',tostring(column_ifexists('DeviceCustomString2','')),' ',tostring(column_ifexists('DeviceCustomString3','')))\\n| extend Gid=toint(extract(@'(?i)(?:gid|generator[\\\\s_-]?id)[\\\\s:=]*(\\\\d+)',1,C))\\n| extend Signal=case(C has 'is_corroborated','Corroborated',Gid == 411 or C has 'is_ml_only','ML-only',isnotnull(Gid),'Signature','Unknown');\\nF | summarize Events=count(), Sources=dcount(SourceIP), Destinations=dcount(DestinationIP) by Signal | order by Events desc\",\"size\":1,\"title\":\"Signal composition\",\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"tiles\"},\"name\":\"signal-composition\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"CommonSecurityLog\\n| where DeviceVendor =~ 'Cisco' and DeviceProduct has_any ('Firepower','Secure Firewall','FTD','NGFW')\\n| extend C=strcat(tostring(Message),' ',tostring(AdditionalExtensions),' ',tostring(Activity),' ',tostring(DeviceEventClassID))\\n| extend Gid=toint(extract(@'(?i)(?:gid|generator[\\\\s_-]?id)[\\\\s:=]*(\\\\d+)',1,C))\\n| extend Signal=case(C has 'is_corroborated','Corroborated',Gid == 411 or C has 'is_ml_only','ML-only',isnotnull(Gid),'Signature','Unknown')\\n| summarize Events=count() by bin(TimeGenerated,1h), Signal\\n| order by TimeGenerated asc\",\"size\":0,\"title\":\"Signal mix over time\",\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"timechart\"},\"name\":\"signal-trend\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"CommonSecurityLog\\n| where DeviceVendor =~ 'Cisco' and DeviceProduct has_any ('Firepower','Secure Firewall','FTD','NGFW')\\n| extend C=strcat(tostring(Message),' ',tostring(AdditionalExtensions),' ',tostring(Activity),' ',tostring(DeviceEventClassID))\\n| extend Gid=toint(extract(@'(?i)(?:gid|generator[\\\\s_-]?id)[\\\\s:=]*(\\\\d+)',1,C))\\n| summarize Total=count(), MlOnly=countif(Gid == 411 or C has 'is_ml_only'), Signatures=countif(isnotnull(Gid) and Gid != 411) by DeviceName\\n| extend MlRatio=round(100.0 * todouble(MlOnly) / iff(Total == 0,1,Total),2)\\n| order by MlRatio desc\",\"size\":0,\"title\":\"Sensor and collector quality\",\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"table\"},\"name\":\"sensor-quality\"}],\"fallbackResourceIds\":[\"Azure Monitor\"],\"fromTemplateId\":\"sentinel-CiscoFirepowerDetectionResponseQuality\",\"$schema\":\"https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json\"}\n", + "version": "1.0", + "sourceId": "[variables('workspaceResourceId')]", + "category": "sentinel" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('Workbook-', last(split(variables('workbookId1'),'/'))))]", + "properties": { + "description": "@{workbookKey=CiscoFirepowerDetectionResponseQuality; logoFileName=cisco-logo-72px.svg; description=Evaluates Cisco Firepower detection signal composition and drift while preserving the safety boundary between SnortML GID 411, classic signatures, and corroborated evidence.; dataTypesDependencies=System.Object[]; dataConnectorsDependencies=System.Object[]; previewImagesFileNames=System.Object[]; version=1.0.0; title=Cisco Firepower Detection and Response Quality; templateRelativePath=CiscoFirepowerDetectionResponseQuality.json; subtitle=Outcome-aware signal quality and drift evaluation; provider=Cisco; support=; author=; source=; categories=}.description", + "parentId": "[variables('workbookId1')]", + "contentId": "[variables('_workbookContentId1')]", + "kind": "Workbook", + "version": "[variables('workbookVersion1')]", + "source": { + "kind": "Solution", + "name": "Cisco Firepower EStreamer", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Cisco" + }, + "support": { + "name": "Cisco", + "tier": "Partner", + "link": "https://www.cisco.com/c/en_in/support/index.html" + }, + "dependencies": { + "operator": "AND", + "criteria": [ + { + "contentId": "CommonSecurityLog", + "kind": "DataType" + }, + { + "contentId": "CiscoFirepowerEStreamerAMA", + "kind": "DataConnector" + } + ] + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_workbookContentId1')]", + "contentKind": "Workbook", + "displayName": "[parameters('workbook1-name')]", + "contentProductId": "[variables('_workbookcontentProductId1')]", + "id": "[variables('_workbookcontentProductId1')]", + "version": "[variables('workbookVersion1')]" + } + }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", @@ -849,7 +1434,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "CiscoFirepowerConnector Playbook with template version 3.0.0", + "description": "CiscoFirepowerConnector Playbook with template version 3.1.0", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('playbookVersion1')]", @@ -3542,7 +4127,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "BlockURL-CiscoFirepower-NetworkGroup Playbook with template version 3.0.0", + "description": "BlockURL-CiscoFirepower-NetworkGroup Playbook with template version 3.1.0", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('playbookVersion2')]", @@ -4777,7 +5362,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "BlockIP-CiscoFirepower Playbook with template version 3.0.0", + "description": "BlockIP-CiscoFirepower Playbook with template version 3.1.0", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('playbookVersion3')]", @@ -4853,7 +5438,7 @@ ], "tags": { "hidden-SentinelTemplateName": "BlockIP-CiscoFirepower", - "hidden-SentinelTemplateVersion": "1.0", + "hidden-SentinelTemplateVersion": "1.1", "hidden-SentinelWorkspaceId": "[[variables('workspaceResourceId')]" }, "identity": { @@ -4891,6 +5476,11 @@ }, "actions": { "Entities_-_Get_IPs": { + "runAfter": { + "Gate_Prove_ML_only_deny_auto_contain": [ + "Succeeded" + ] + }, "type": "ApiConnection", "inputs": { "body": "@triggerBody()?['object']?['properties']?['relatedEntities']", @@ -4916,7 +5506,7 @@ "inputs": { "body": { "incidentArmId": "@triggerBody()?['object']?['id']", - "message": "

Cisco Firepower playbook run summary
\nThe incident did not have any entities with IPs.

" + "message": "

Cisco Firepower playbook run summary
\n[FirepowerOutcome:v1] signal=unknown; decision=not-required; containment=not-attempted; reason=no-ip-entity; ruleVersion=unknown; policyVersion=1.0.0
The incident did not have any entities with IPs.

" }, "host": { "connection": { @@ -4979,7 +5569,7 @@ "inputs": { "body": { "incidentArmId": "@triggerBody()?['object']?['id']", - "message": "

Cisco Firepower playbook run summary
\nThe following IPs were found in the Incident:
\n
@{variables('ipAddressesActionComment')}

" + "message": "

Cisco Firepower playbook run summary
\n[FirepowerOutcome:v1] signal=@{if(or(contains(variables('DualSignalContext'),'is_corroborated'),contains(variables('DualSignalContext'),'dual-signal:corroborated'),contains(variables('DualSignalContext'),'signature and ml')),'corroborated','signature')}; decision=approved; containment=succeeded; reason=fmc-network-group-updated; ruleVersion=unknown; policyVersion=1.0.0
The following IPs were found in the Incident:
\n
@{variables('ipAddressesActionComment')}

" }, "host": { "connection": { @@ -5167,7 +5757,7 @@ "inputs": { "body": { "incidentArmId": "@triggerBody()?['object']?['id']", - "message": "

Cisco Firepower playbook run summary
\n
We could not find the Network Group object with name: '@{variables('Network Group object name')}'

" + "message": "

Cisco Firepower playbook run summary
\n
[FirepowerOutcome:v1] signal=unknown; decision=approved; containment=failed; reason=network-group-not-found; ruleVersion=unknown; policyVersion=1.0.0
We could not find the Network Group object with name: '@{variables('Network Group object name')}'

" }, "host": { "connection": { @@ -5423,6 +6013,156 @@ "method": "post", "path": "/api/fmc_platform/v1/auth/revokeaccess" } + }, + "Initialize_Dual_signal_context": { + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "DualSignalContext", + "type": "string", + "value": "@{toLower(concat(coalesce(triggerBody()?['object']?['properties']?['title'], ''), ' ', coalesce(triggerBody()?['object']?['properties']?['description'], '')))}" + } + ] + }, + "description": "Concatenate incident title+description for dual-signal Gate/Prove (ML-only vs signature/corroborated)." + }, + "Gate_Prove_ML_only_deny_auto_contain": { + "actions": { + "Add_comment_to_incident_V3_ML_only_deny_auto_contain": { + "type": "ApiConnection", + "inputs": { + "body": { + "incidentArmId": "@triggerBody()?['object']?['id']", + "message": "

Gate/Prove: ML-only - auto-contain DENIED
[FirepowerOutcome:v1] signal=ml-only; decision=policy-denied; containment=not-attempted; reason=ml-only-auto-contain-denied; ruleVersion=1.0.2; policyVersion=1.0.0
This incident matches an ML-only path (SnortML / GID 411 / is_ml_only). Machine-learning confidence is not equivalent to a classic signature true positive. Automatic BlockIP was not applied. Escalate for corroboration (signature or dual-signal) before containment. Do not attach this playbook to ML-only analytics.

" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "post", + "path": "/Incidents/Comment" + } + }, + "Terminate_ML_only_deny_auto_contain": { + "runAfter": { + "Add_comment_to_incident_V3_ML_only_deny_auto_contain": [ + "Succeeded" + ] + }, + "type": "Terminate", + "inputs": { + "runStatus": "Cancelled" + }, + "description": "Kill-switch: do not call FMC BlockIP / Network Group APIs on ML-only incidents." + } + }, + "runAfter": { + "Initialize_Dual_signal_context": [ + "Succeeded" + ] + }, + "expression": { + "and": [ + { + "or": [ + { + "contains": [ + "@variables('DualSignalContext')", + "gid 411" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "gid:411" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "generator id 411" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "snortml" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "is_ml_only" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "ml-only" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "dual-signal:ml-only" + ] + } + ] + }, + { + "not": { + "or": [ + { + "contains": [ + "@variables('DualSignalContext')", + "is_corroborated" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "dual-signal:corroborated" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "signature and ml" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "gid 4110" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "gid:4110" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "gid=4110" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "generator id 4110" + ] + } + ] + } + } + ] + }, + "type": "If", + "description": "Gate/Prove: deny auto-contain when ML-only (GID 411 / SnortML). Signature or corroborated incidents continue to BlockIP." } } }, @@ -5488,15 +6228,13 @@ ], "metadata": { "title": "Block IP - Cisco Firepower", - "description": "This playbook allows blocking of IPs in Cisco Firepower, using a **Network Group object**. This allows making changes to a Network Group selected members, instead of making Access List Entries. The Network Group object itself should be part of an Access List Entry.", + "description": "Blocks IPs in Cisco Firepower via a Network Group object, with a Gate/Prove pre-check that DENIES automatic BlockIP when the incident is ML-only (SnortML / GID 411 / is_ml_only). Machine-learning confidence is not treated as a classic signature true positive. Signature or corroborated incidents still block.", "mainSteps": [ "When a new Sentinel incident is created, this playbook gets triggered and performs below actions.", + "0. Gate/Prove: if incident title/description indicates ML-only (SnortML, GID 411, is_ml_only) without corroboration, comment and cancel - do not call FMC BlockIP.", "1. For the IPs we check if they are already selected for the Network Group object", "2. For the IPs not already selected for the Network Group object, add it so it gets blocked", - "3. Comment is added to Microsoft Sentinel incident", - "![Microsoft Sentinel comment](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/Cisco%20Firepower%20EStreamer/Playbooks/CiscoFirepower-BlockFQDN-NetworkGroup/Images/BlockFQDN-NetworkGroup-AzureSentinel-Comments.png)", - "** IP is added to Cisco Firepower Network Group object:**", - "![Cisco Firepower Network Group object](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/Cisco%20Firepower%20EStreamer/Playbooks/CiscoFirepower-BlockFQDN-NetworkGroup/Images/BlockFQDN-NetworkGroup-CiscoFirepowerAdd.png)" + "3. Comment is added to Microsoft Sentinel incident" ], "prerequisites": [ "1. Cisco Firepower custom connector needs to be deployed prior to the deployment of this playbook, in the same resource group and region. Relevant instructions can be found in the connector doc pages.", @@ -5513,9 +6251,11 @@ "6. Repeat steps for other connections such as Cisco Firepower (For authorizing the Cisco Firepower API connection, the username and password needs to be provided)", "**b. Configurations in Sentinel**", "1. In Microsoft sentinel analytical rules should be configured to trigger an incident with IP Entity.", - "2. Configure the automation rules to trigger this playbook" + "2. Configure the automation rules to trigger this playbook", + "**c. Dual-signal / Gate-Prove**", + "Do not attach this playbook to ML-only analytics (SnortML GID 411). Pair with the dual-signal analytic rules in this solution. Attach auto-BlockIP only to signature-high or signature+ML corroboration incidents. ML-only must escalate, not contain." ], - "lastUpdateTime": "2022-07-20T00:00:00Z", + "lastUpdateTime": "2026-08-16T00:00:00Z", "entities": [ "Ip" ], @@ -5529,6 +6269,13 @@ "notes": [ "Initial version" ] + }, + { + "version": "1.1.0", + "title": "Gate/Prove ML-only deny auto-contain", + "notes": [ + "Deny automatic BlockIP when incident context is ML-only (SnortML / GID 411). Signature and corroborated paths unchanged." + ] } ] } @@ -5555,7 +6302,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "CiscoFirepower-BlockIP-Teams Playbook with template version 3.0.0", + "description": "CiscoFirepower-BlockIP-Teams Playbook with template version 3.1.0", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('playbookVersion4')]", @@ -5647,7 +6394,7 @@ "tags": { "LogicAppsCategory": "security", "hidden-SentinelTemplateName": "BlockIP-Firepower-Teams", - "hidden-SentinelTemplateVersion": "1.0", + "hidden-SentinelTemplateVersion": "1.1", "hidden-SentinelWorkspaceId": "[[variables('workspaceResourceId')]" }, "identity": { @@ -5684,7 +6431,150 @@ } }, "actions": { + "Initialize_Dual_signal_context": { + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "DualSignalContext", + "type": "string", + "value": "@{toLower(concat(coalesce(triggerBody()?['object']?['properties']?['title'], ''), ' ', coalesce(triggerBody()?['object']?['properties']?['description'], '')))}" + } + ] + }, + "description": "Concatenate incident title+description for dual-signal Gate/Prove warning on HITL BlockIP." + }, + "Gate_Prove_ML_only_HITL_warning": { + "actions": { + "Add_comment_to_incident_V3_ML_only_HITL_warning": { + "type": "ApiConnection", + "inputs": { + "body": { + "incidentArmId": "@triggerBody()?['object']?['id']", + "message": "

Gate/Prove HITL warning: ML-only
[FirepowerOutcome:v1] signal=ml-only; decision=unknown; containment=not-attempted; reason=hitl-review-requested; ruleVersion=1.0.2; policyVersion=1.0.0
This incident matches an ML-only path (SnortML / GID 411 / is_ml_only). Do not equate ML confidence to a signature true positive. Prefer Ignore unless a classic signature or dual-signal corroboration is present. Analyst confirmation in Teams is still required before BlockIP.

" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "post", + "path": "/Incidents/Comment" + } + } + }, + "runAfter": { + "Initialize_Dual_signal_context": [ + "Succeeded" + ] + }, + "expression": { + "and": [ + { + "or": [ + { + "contains": [ + "@variables('DualSignalContext')", + "gid 411" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "gid:411" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "generator id 411" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "snortml" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "is_ml_only" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "ml-only" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "dual-signal:ml-only" + ] + } + ] + }, + { + "not": { + "or": [ + { + "contains": [ + "@variables('DualSignalContext')", + "is_corroborated" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "dual-signal:corroborated" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "signature and ml" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "gid 4110" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "gid:4110" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "gid=4110" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "generator id 4110" + ] + } + ] + } + } + ] + }, + "type": "If", + "description": "Gate/Prove: warn HITL operators when the incident is ML-only. Does not auto-block; Teams confirmation remains required." + }, "Entities_-_Get_IPs": { + "runAfter": { + "Gate_Prove_ML_only_HITL_warning": [ + "Succeeded" + ] + }, "type": "ApiConnection", "inputs": { "body": "@triggerBody()?['object']?['properties']?['relatedEntities']", @@ -5710,7 +6600,7 @@ "inputs": { "body": { "incidentArmId": "@triggerBody()?['object']?['id']", - "message": "

Cisco Firepower playbook run summary
\nThe incident did not have any entities with IPs.

" + "message": "

Cisco Firepower playbook run summary
\n[FirepowerOutcome:v1] signal=unknown; decision=not-required; containment=not-attempted; reason=no-ip-entity; ruleVersion=unknown; policyVersion=1.0.0
The incident did not have any entities with IPs.

" }, "host": { "connection": { @@ -6095,7 +6985,7 @@ "inputs": { "body": { "incidentArmId": "@triggerBody()?['object']?['id']", - "message": "

Cisco Firepower playbook run summary
\nThe following IPs were found in the Incident:
\n
@{variables('ipAddressesActionComment')}

" + "message": "

Cisco Firepower playbook run summary
\n[FirepowerOutcome:v1] signal=@{if(or(contains(variables('DualSignalContext'),'is_corroborated'),contains(variables('DualSignalContext'),'dual-signal:corroborated'),contains(variables('DualSignalContext'),'signature and ml')),'corroborated',if(or(contains(variables('DualSignalContext'),'gid 411'),contains(variables('DualSignalContext'),'snortml'),contains(variables('DualSignalContext'),'ml-only')),'ml-only','signature'))}; decision=approved; containment=succeeded; reason=fmc-network-group-updated; ruleVersion=unknown; policyVersion=1.0.0
The following IPs were found in the Incident:
\n
@{variables('ipAddressesActionComment')}

" }, "host": { "connection": { @@ -6359,6 +7249,26 @@ "Succeeded" ] }, + "else": { + "actions": { + "Add_outcome_comment_analyst_rejected": { + "type": "ApiConnection", + "inputs": { + "body": { + "incidentArmId": "@triggerBody()?['object']?['id']", + "message": "

Cisco Firepower analyst decision
[FirepowerOutcome:v1] signal=@{if(or(contains(variables('DualSignalContext'),'is_corroborated'),contains(variables('DualSignalContext'),'dual-signal:corroborated'),contains(variables('DualSignalContext'),'signature and ml')),'corroborated',if(or(contains(variables('DualSignalContext'),'gid 411'),contains(variables('DualSignalContext'),'snortml'),contains(variables('DualSignalContext'),'ml-only')),'ml-only','signature'))}; decision=rejected; containment=not-attempted; reason=teams-action-not-submitted; ruleVersion=unknown; policyVersion=1.0.0
The analyst did not submit the containment action. Cisco Firepower was not modified.

" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "post", + "path": "/Incidents/Comment" + } + } + } + }, "expression": { "and": [ { @@ -6649,9 +7559,10 @@ ], "metadata": { "title": "Block IP - Take Action from Teams - Cisco Firepower", - "description": "This playbook allows blocking of IPs in Cisco Firepower, using a **Network Group object**. This allows making changes to a Network Group selected members, instead of making Access List Entries. The Network Group object itself should be part of an Access List Entry.", + "description": "HITL BlockIP via Teams Adaptive Card. Adds a Gate/Prove warning when the incident is ML-only (SnortML / GID 411 / is_ml_only). Analysts must not treat ML confidence as a signature true positive. Teams confirmation remains required before BlockIP.", "mainSteps": [ "When a new Sentinel incident is created, this playbook gets triggered and performs below actions.", + "0. Gate/Prove: if incident title/description indicates ML-only without corroboration, add an incident comment warning. Do not auto-block; Teams HITL continues.", "1. For the IPs we check if they are already selected for the Network Group object", "2. An adaptive card is sent to a Teams channel with information about the incident and giving the option to ignore an IP, or depending on it's current status block it by adding it to the Network Group object or unblock it by removing it from the Network Group object", "![Teams Adaptive Card preview](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/Cisco%20Firepower%20EStreamer/Playbooks/CiscoFirepower-BlockIP-Teams/Images/BlockIP-Teams-AdaptiveCard.png)", @@ -6666,7 +7577,7 @@ "1. Cisco Firepower custom connector needs to be deployed prior to the deployment of this playbook, in the same resource group and region. Relevant instructions can be found in the connector doc pages.", "2. In Cisco Firepower there needs to be a Network Group object. [Creating Network Objects](https://www.cisco.com/c/en/us/td/docs/security/firepower/630/configuration/guide/fpmc-config-guide-v63/reusable_objects.html#ariaid-title15)" ], - "lastUpdateTime": "2022-07-20T00:00:00Z", + "lastUpdateTime": "2026-08-16T00:00:00Z", "entities": [ "Ip" ], @@ -6692,7 +7603,9 @@ "5. Save the Logic App", "**c. Configurations in Sentinel**", "1. In Microsoft sentinel analytical rules should be configured to trigger an incident with IP Entity.", - "2. Configure the automation rules to trigger this playbook" + "2. Configure the automation rules to trigger this playbook", + "**d. Dual-signal / Gate-Prove**", + "Prefer this HITL playbook for ML-only analytics (SnortML GID 411). Auto-BlockIP (NetworkGroup) must not be attached to ML-only incidents. Do not treat ML confidence as a signature true positive." ], "releaseNotes": [ { @@ -6701,6 +7614,13 @@ "notes": [ "Initial version" ] + }, + { + "version": "1.1.0", + "title": "Gate/Prove ML-only HITL warning", + "notes": [ + "Warn Teams operators when incident context is ML-only (SnortML / GID 411) before offering BlockIP. Does not auto-contain." + ] } ] } @@ -6723,12 +7643,12 @@ "apiVersion": "2023-04-01-preview", "location": "[parameters('workspace-location')]", "properties": { - "version": "3.0.0", + "version": "3.1.0", "kind": "Solution", "contentSchemaVersion": "3.0.0", "displayName": "Cisco Firepower EStreamer", "publisherDisplayName": "Cisco", - "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 Cisco Firepower eStreamer Solution for Microsoft Sentinel works with Cisco Event Streamer (also known as eStreamer) and allows you to stream System intrusion, discovery and connection data from Firepower Management Center (FMC) or managed device to Sentinel\neStreamer is a Client Server API designed for the Cisco Firepower NGFW Solution. The eStreamer client requests detailed event data on behalf of the SIEM or logging solution in the Common Event Format (CEF).

\n

This solution is dependent on the Common Event Format solution containing the CEF via AMA connector to collect the logs. The CEF solution will be installed as part of this solution installation.

\n

**NOTE:**Microsoft recommends installation of CEF via AMA Connector. The existing connectors are about to be deprecated by Aug 31, 2024.

\n

Data Connectors: 2, Custom Azure Logic Apps Connectors: 1, Playbooks: 3

\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 Cisco Firepower eStreamer Solution for Microsoft Sentinel works with Cisco Event Streamer (also known as eStreamer) and allows you to stream System intrusion, discovery and connection data from Firepower Management Center (FMC) or managed device to Microsoft Sentinel\neStreamer is a Client Server API designed for the Cisco Firepower NGFW Solution. The eStreamer client requests detailed event data on behalf of the SIEM or logging solution in the Common Event Format (CEF).

\n

This solution is dependent on the Common Event Format solution containing the CEF via AMA connector to collect the logs. The CEF solution will be installed as part of this solution installation.

\n

**NOTE: **Microsoft recommends installation of CEF via AMA Connector. The existing connectors are about to be deprecated by Aug 31, 2024.

\n

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

\n

Learn more about Microsoft Sentinel | Learn more about Solutions

\n", "contentKind": "Solution", "contentProductId": "[variables('_solutioncontentProductId')]", "id": "[variables('_solutioncontentProductId')]", @@ -6760,6 +7680,31 @@ "contentId": "[variables('_dataConnectorContentId2')]", "version": "[variables('dataConnectorVersion2')]" }, + { + "kind": "AnalyticsRule", + "contentId": "[variables('analyticRuleObject1')._analyticRulecontentId1]", + "version": "[variables('analyticRuleObject1').analyticRuleVersion1]" + }, + { + "kind": "AnalyticsRule", + "contentId": "[variables('analyticRuleObject2')._analyticRulecontentId2]", + "version": "[variables('analyticRuleObject2').analyticRuleVersion2]" + }, + { + "kind": "AnalyticsRule", + "contentId": "[variables('analyticRuleObject3')._analyticRulecontentId3]", + "version": "[variables('analyticRuleObject3').analyticRuleVersion3]" + }, + { + "kind": "AnalyticsRule", + "contentId": "[variables('analyticRuleObject4')._analyticRulecontentId4]", + "version": "[variables('analyticRuleObject4').analyticRuleVersion4]" + }, + { + "kind": "Workbook", + "contentId": "[variables('_workbookContentId1')]", + "version": "[variables('workbookVersion1')]" + }, { "kind": "LogicAppsCustomConnector", "contentId": "[variables('_CiscoFirepowerConnector')]", diff --git a/Solutions/Cisco Firepower EStreamer/Package/testParameters.json b/Solutions/Cisco Firepower EStreamer/Package/testParameters.json index e55ec41a9ac..1599ce461fd 100644 --- a/Solutions/Cisco Firepower EStreamer/Package/testParameters.json +++ b/Solutions/Cisco Firepower EStreamer/Package/testParameters.json @@ -20,5 +20,13 @@ "metadata": { "description": "Workspace name for Log Analytics where Microsoft Sentinel is setup" } + }, + "workbook1-name": { + "type": "string", + "defaultValue": "Cisco Firepower Detection and Response Quality", + "minLength": 1, + "metadata": { + "description": "Name for the workbook" + } } } diff --git a/Solutions/Cisco Firepower EStreamer/Playbooks/CiscoFirepower-BlockFQDN-NetworkGroup/readme.md b/Solutions/Cisco Firepower EStreamer/Playbooks/CiscoFirepower-BlockFQDN-NetworkGroup/readme.md index 9e24f8714ac..3d09c73ab79 100644 --- a/Solutions/Cisco Firepower EStreamer/Playbooks/CiscoFirepower-BlockFQDN-NetworkGroup/readme.md +++ b/Solutions/Cisco Firepower EStreamer/Playbooks/CiscoFirepower-BlockFQDN-NetworkGroup/readme.md @@ -32,7 +32,7 @@ When a new Sentinel incident is created, this playbook gets triggered and perfor 1. Deploy the playbook by clicking on "Deploy to Azure" button. This will take you to deploying an ARM Template wizard. [![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FCisco%2520Firepower%2520EStreamer%2FPlaybooks%2FCiscoFirepower-BlockFQDN-NetworkGroup%2Fazuredeploy.json) -[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FCisco%2520Firepower%2520EStreamer%2FPlaybooks%2FCiscoFirepower-BlockFQDN-NetworkGroup%2Fazuredeploy.json) +[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovernbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FCisco%2520Firepower%2520EStreamer%2FPlaybooks%2FCiscoFirepower-BlockFQDN-NetworkGroup%2Fazuredeploy.json) 2. Fill in the required parameters: * Playbook Name: Enter the playbook name here (ex:CiscoFirepower-BlockFQDN-NetworkGroup) diff --git a/Solutions/Cisco Firepower EStreamer/Playbooks/CiscoFirepower-BlockIP-NetworkGroup/azuredeploy.json b/Solutions/Cisco Firepower EStreamer/Playbooks/CiscoFirepower-BlockIP-NetworkGroup/azuredeploy.json index b4b671b0268..671cb2f09dd 100644 --- a/Solutions/Cisco Firepower EStreamer/Playbooks/CiscoFirepower-BlockIP-NetworkGroup/azuredeploy.json +++ b/Solutions/Cisco Firepower EStreamer/Playbooks/CiscoFirepower-BlockIP-NetworkGroup/azuredeploy.json @@ -2,49 +2,63 @@ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "metadata": { - "title": "Block IP - Cisco Firepower", - "description": "This playbook allows blocking of IPs in Cisco Firepower, using a **Network Group object**. This allows making changes to a Network Group selected members, instead of making Access List Entries. The Network Group object itself should be part of an Access List Entry.", - "mainSteps": ["When a new Sentinel incident is created, this playbook gets triggered and performs below actions.", + "title": "Block IP - Cisco Firepower", + "description": "Blocks IPs in Cisco Firepower via a Network Group object, with a Gate/Prove pre-check that DENIES automatic BlockIP when the incident is ML-only (SnortML / GID 411 / is_ml_only). Machine-learning confidence is not treated as a classic signature true positive. Signature or corroborated incidents still block.", + "mainSteps": [ + "When a new Sentinel incident is created, this playbook gets triggered and performs below actions.", + "0. Gate/Prove: if incident title/description indicates ML-only (SnortML, GID 411, is_ml_only) without corroboration, comment and cancel - do not call FMC BlockIP.", "1. For the IPs we check if they are already selected for the Network Group object", "2. For the IPs not already selected for the Network Group object, add it so it gets blocked", - "3. Comment is added to Microsoft Sentinel incident", - "![Microsoft Sentinel comment](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/Cisco%20Firepower%20EStreamer/Playbooks/CiscoFirepower-BlockFQDN-NetworkGroup/Images/BlockFQDN-NetworkGroup-AzureSentinel-Comments.png)", - "** IP is added to Cisco Firepower Network Group object:**", - "![Cisco Firepower Network Group object](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/Cisco%20Firepower%20EStreamer/Playbooks/CiscoFirepower-BlockFQDN-NetworkGroup/Images/BlockFQDN-NetworkGroup-CiscoFirepowerAdd.png)" + "3. Comment is added to Microsoft Sentinel incident" ], - "prerequisites": ["1. Cisco Firepower custom connector needs to be deployed prior to the deployment of this playbook, in the same resource group and region. Relevant instructions can be found in the connector doc pages.", + "prerequisites": [ + "1. Cisco Firepower custom connector needs to be deployed prior to the deployment of this playbook, in the same resource group and region. Relevant instructions can be found in the connector doc pages.", "2. In Cisco Firepower there needs to be a Network Group object. [Creating Network Objects](https://www.cisco.com/c/en/us/td/docs/security/firepower/630/configuration/guide/fpmc-config-guide-v63/reusable_objects.html#ariaid-title15)" ], "prerequisitesDeployTemplateFile": "../CustomConnector/azuredeploy.json", - "postDeployment": ["**a. Authorize connections**", - "Once deployment is complete, you will need to authorize each connection.", - "1. Click the Microsoft Sentinel connection resource", - "2. Click edit API connection", - "3. Click Authorize", - "4. Sign in", - "5. Click Save", - "6. Repeat steps for other connections such as Cisco Firepower (For authorizing the Cisco Firepower API connection, the username and password needs to be provided)", - "**b. Configurations in Sentinel**", - "1. In Microsoft sentinel analytical rules should be configured to trigger an incident with IP Entity.", - "2. Configure the automation rules to trigger this playbook" + "postDeployment": [ + "**a. Authorize connections**", + "Once deployment is complete, you will need to authorize each connection.", + "1. Click the Microsoft Sentinel connection resource", + "2. Click edit API connection", + "3. Click Authorize", + "4. Sign in", + "5. Click Save", + "6. Repeat steps for other connections such as Cisco Firepower (For authorizing the Cisco Firepower API connection, the username and password needs to be provided)", + "**b. Configurations in Sentinel**", + "1. In Microsoft sentinel analytical rules should be configured to trigger an incident with IP Entity.", + "2. Configure the automation rules to trigger this playbook", + "**c. Dual-signal / Gate-Prove**", + "Do not attach this playbook to ML-only analytics (SnortML GID 411). Pair with the dual-signal analytic rules in this solution. Attach auto-BlockIP only to signature-high or signature+ML corroboration incidents. ML-only must escalate, not contain." + ], + "lastUpdateTime": "2026-08-16T00:00:00.000Z", + "entities": [ + "Ip" + ], + "tags": [ + "Remediation" ], - "lastUpdateTime": "2022-07-20T00:00:00.000Z", - "entities": ["Ip"], - "tags": ["Remediation"], "support": { - "tier": "Microsoft" + "tier": "Microsoft" }, "author": { "name": "Lior Tamir" }, "releaseNotes": [ - { - "version": "1.0.0", - "title": "Block IP - Cisco Firepower", - "notes": [ - "Initial version" - ] - } + { + "version": "1.0.0", + "title": "Block IP - Cisco Firepower", + "notes": [ + "Initial version" + ] + }, + { + "version": "1.1.0", + "title": "Gate/Prove ML-only deny auto-contain", + "notes": [ + "Deny automatic BlockIP when incident context is ML-only (SnortML / GID 411). Signature and corroborated paths unchanged." + ] + } ] }, "parameters": { @@ -114,7 +128,7 @@ ], "tags": { "hidden-SentinelTemplateName": "BlockIP-CiscoFirepower", - "hidden-SentinelTemplateVersion": "1.0" + "hidden-SentinelTemplateVersion": "1.1" }, "identity": { "type": "SystemAssigned" @@ -152,7 +166,11 @@ }, "actions": { "Entities_-_Get_IPs": { - "runAfter": {}, + "runAfter": { + "Gate_Prove_ML_only_deny_auto_contain": [ + "Succeeded" + ] + }, "type": "ApiConnection", "inputs": { "body": "@triggerBody()?['object']?['properties']?['relatedEntities']", @@ -180,7 +198,7 @@ "inputs": { "body": { "incidentArmId": "@triggerBody()?['object']?['id']", - "message": "

Cisco Firepower playbook run summary
\nThe incident did not have any entities with IPs.

" + "message": "

Cisco Firepower playbook run summary
\n[FirepowerOutcome:v1] signal=unknown; decision=not-required; containment=not-attempted; reason=no-ip-entity; ruleVersion=unknown; policyVersion=1.0.0
The incident did not have any entities with IPs.

" }, "host": { "connection": { @@ -243,7 +261,7 @@ "inputs": { "body": { "incidentArmId": "@triggerBody()?['object']?['id']", - "message": "

Cisco Firepower playbook run summary
\nThe following IPs were found in the Incident:
\n
@{variables('ipAddressesActionComment')}

" + "message": "

Cisco Firepower playbook run summary
\n[FirepowerOutcome:v1] signal=@{if(or(contains(variables('DualSignalContext'),'is_corroborated'),contains(variables('DualSignalContext'),'dual-signal:corroborated'),contains(variables('DualSignalContext'),'signature and ml')),'corroborated','signature')}; decision=approved; containment=succeeded; reason=fmc-network-group-updated; ruleVersion=unknown; policyVersion=1.0.0
The following IPs were found in the Incident:
\n
@{variables('ipAddressesActionComment')}

" }, "host": { "connection": { @@ -436,7 +454,7 @@ "inputs": { "body": { "incidentArmId": "@triggerBody()?['object']?['id']", - "message": "

Cisco Firepower playbook run summary
\n
We could not find the Network Group object with name: '@{variables('Network Group object name')}'

" + "message": "

Cisco Firepower playbook run summary
\n
[FirepowerOutcome:v1] signal=unknown; decision=approved; containment=failed; reason=network-group-not-found; ruleVersion=unknown; policyVersion=1.0.0
We could not find the Network Group object with name: '@{variables('Network Group object name')}'

" }, "host": { "connection": { @@ -693,6 +711,161 @@ "method": "post", "path": "/api/fmc_platform/v1/auth/revokeaccess" } + }, + "Initialize_Dual_signal_context": { + "runAfter": {}, + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "DualSignalContext", + "type": "string", + "value": "@{toLower(concat(coalesce(triggerBody()?['object']?['properties']?['title'], ''), ' ', coalesce(triggerBody()?['object']?['properties']?['description'], '')))}" + } + ] + }, + "description": "Concatenate incident title+description for dual-signal Gate/Prove (ML-only vs signature/corroborated)." + }, + "Gate_Prove_ML_only_deny_auto_contain": { + "actions": { + "Add_comment_to_incident_V3_ML_only_deny_auto_contain": { + "runAfter": {}, + "type": "ApiConnection", + "inputs": { + "body": { + "incidentArmId": "@triggerBody()?['object']?['id']", + "message": "

Gate/Prove: ML-only - auto-contain DENIED
[FirepowerOutcome:v1] signal=ml-only; decision=policy-denied; containment=not-attempted; reason=ml-only-auto-contain-denied; ruleVersion=1.0.2; policyVersion=1.0.0
This incident matches an ML-only path (SnortML / GID 411 / is_ml_only). Machine-learning confidence is not equivalent to a classic signature true positive. Automatic BlockIP was not applied. Escalate for corroboration (signature or dual-signal) before containment. Do not attach this playbook to ML-only analytics.

" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "post", + "path": "/Incidents/Comment" + } + }, + "Terminate_ML_only_deny_auto_contain": { + "runAfter": { + "Add_comment_to_incident_V3_ML_only_deny_auto_contain": [ + "Succeeded" + ] + }, + "type": "Terminate", + "inputs": { + "runStatus": "Cancelled" + }, + "description": "Kill-switch: do not call FMC BlockIP / Network Group APIs on ML-only incidents." + } + }, + "runAfter": { + "Initialize_Dual_signal_context": [ + "Succeeded" + ] + }, + "else": { + "actions": {} + }, + "expression": { + "and": [ + { + "or": [ + { + "contains": [ + "@variables('DualSignalContext')", + "gid 411" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "gid:411" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "generator id 411" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "snortml" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "is_ml_only" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "ml-only" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "dual-signal:ml-only" + ] + } + ] + }, + { + "not": { + "or": [ + { + "contains": [ + "@variables('DualSignalContext')", + "is_corroborated" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "dual-signal:corroborated" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "signature and ml" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "gid 4110" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "gid:4110" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "gid=4110" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "generator id 4110" + ] + } + ] + } + } + ] + }, + "type": "If", + "description": "Gate/Prove: deny auto-contain when ML-only (GID 411 / SnortML). Signature or corroborated incidents continue to BlockIP." } }, "outputs": {} @@ -724,4 +897,4 @@ } } ] -} \ No newline at end of file +} diff --git a/Solutions/Cisco Firepower EStreamer/Playbooks/CiscoFirepower-BlockIP-NetworkGroup/readme.md b/Solutions/Cisco Firepower EStreamer/Playbooks/CiscoFirepower-BlockIP-NetworkGroup/readme.md index 4e28a2bdd68..177183a3bc5 100644 --- a/Solutions/Cisco Firepower EStreamer/Playbooks/CiscoFirepower-BlockIP-NetworkGroup/readme.md +++ b/Solutions/Cisco Firepower EStreamer/Playbooks/CiscoFirepower-BlockIP-NetworkGroup/readme.md @@ -5,6 +5,8 @@ This playbook allows blocking of IPs in Cisco Firepower, using a **Network Group object**. This allows making changes to a Network Group selected members, instead of making Access List Entries. The Network Group object itself should be part of an Access List Entry. When a new Sentinel incident is created, this playbook gets triggered and performs below actions. +0. **Gate/Prove:** if the incident title/description indicates **ML-only** (SnortML / GID 411 / `is_ml_only`) without signature or dual-signal corroboration, the playbook comments on the incident and **cancels** - it does **not** call FMC BlockIP. Machine-learning confidence is not treated as a classic signature true positive. + The comment includes a structured `[FirepowerOutcome:v1]` policy-denial record for repeatable evaluation. 1. For the IPs we check if they are already selected for the Network Group object 2. For the IPs not already selected for the Network Group object, add it so it gets blocked 3. Comment is added to Microsoft Sentinel incident
@@ -29,7 +31,7 @@ When a new Sentinel incident is created, this playbook gets triggered and perfor 1. Deploy the playbook by clicking on "Deploy to Azure" button. This will take you to deploying an ARM Template wizard. [![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FCisco%2520Firepower%2520EStreamer%2FPlaybooks%2FCiscoFirepower-BlockIP-NetworkGroup%2Fazuredeploy.json) -[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FCisco%2520Firepower%2520EStreamer%2FPlaybooks%2FCiscoFirepower-BlockIP-NetworkGroup%2Fazuredeploy.json) +[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovernbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FCisco%2520Firepower%2520EStreamer%2FPlaybooks%2FCiscoFirepower-BlockIP-NetworkGroup%2Fazuredeploy.json) 2. Fill in the required parameters: * Playbook Name: Enter the playbook name here (ex:CiscoFirepower-BlockIP-NetworkGroup) @@ -48,4 +50,5 @@ Once deployment is complete, you will need to authorize each connection. ### b. Configurations in Sentinel 1. In Microsoft sentinel analytical rules should be configured to trigger an incident with IP Entity. -2. Configure the automation rules to trigger this playbook \ No newline at end of file +2. Configure the automation rules to trigger this playbook +3. **Do not** attach this auto-contain playbook to ML-only analytics (SnortML GID 411). Attach it only to signature-high or signature+ML corroboration incidents. Use the Teams HITL playbook when an analyst must review an ML-only alert. diff --git a/Solutions/Cisco Firepower EStreamer/Playbooks/CiscoFirepower-BlockIP-Teams/azuredeploy.json b/Solutions/Cisco Firepower EStreamer/Playbooks/CiscoFirepower-BlockIP-Teams/azuredeploy.json index d7ab823d7a2..46ee69ec37d 100644 --- a/Solutions/Cisco Firepower EStreamer/Playbooks/CiscoFirepower-BlockIP-Teams/azuredeploy.json +++ b/Solutions/Cisco Firepower EStreamer/Playbooks/CiscoFirepower-BlockIP-Teams/azuredeploy.json @@ -3,8 +3,9 @@ "contentVersion": "1.0.0.0", "metadata": { "title": "Block IP - Take Action from Teams - Cisco Firepower", - "description": "This playbook allows blocking of IPs in Cisco Firepower, using a **Network Group object**. This allows making changes to a Network Group selected members, instead of making Access List Entries. The Network Group object itself should be part of an Access List Entry.", + "description": "HITL BlockIP via Teams Adaptive Card. Adds a Gate/Prove warning when the incident is ML-only (SnortML / GID 411 / is_ml_only). Analysts must not treat ML confidence as a signature true positive. Teams confirmation remains required before BlockIP.", "mainSteps": ["When a new Sentinel incident is created, this playbook gets triggered and performs below actions.", + "0. Gate/Prove: if incident title/description indicates ML-only without corroboration, add an incident comment warning. Do not auto-block; Teams HITL continues.", "1. For the IPs we check if they are already selected for the Network Group object", "2. An adaptive card is sent to a Teams channel with information about the incident and giving the option to ignore an IP, or depending on it's current status block it by adding it to the Network Group object or unblock it by removing it from the Network Group object", "![Teams Adaptive Card preview](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/Cisco%20Firepower%20EStreamer/Playbooks/CiscoFirepower-BlockIP-Teams/Images/BlockIP-Teams-AdaptiveCard.png)", @@ -19,7 +20,7 @@ "2. In Cisco Firepower there needs to be a Network Group object. [Creating Network Objects](https://www.cisco.com/c/en/us/td/docs/security/firepower/630/configuration/guide/fpmc-config-guide-v63/reusable_objects.html#ariaid-title15)" ], "prerequisitesDeployTemplateFile": "../CustomConnector/azuredeploy.json", - "lastUpdateTime": "2022-07-20T00:00:00.000Z", + "lastUpdateTime": "2026-08-16T00:00:00.000Z", "entities": ["Ip"], "tags": ["Remediation", "Response from teams"], "postDeployment":["**a. Authorize connections**", @@ -39,7 +40,9 @@ "5. Save the Logic App", "**c. Configurations in Sentinel**", "1. In Microsoft sentinel analytical rules should be configured to trigger an incident with IP Entity.", - "2. Configure the automation rules to trigger this playbook" + "2. Configure the automation rules to trigger this playbook", + "**d. Dual-signal / Gate-Prove**", + "Prefer this HITL playbook for ML-only analytics (SnortML GID 411). Auto-BlockIP (NetworkGroup) must not be attached to ML-only incidents. Do not treat ML confidence as a signature true positive." ], "support": { "tier": "Microsoft" @@ -54,6 +57,13 @@ "notes": [ "Initial version" ] + }, + { + "version": "1.1.0", + "title": "Gate/Prove ML-only HITL warning", + "notes": [ + "Warn Teams operators when incident context is ML-only (SnortML / GID 411) before offering BlockIP. Does not auto-contain." + ] } ] }, @@ -139,7 +149,7 @@ "tags": { "LogicAppsCategory": "security", "hidden-SentinelTemplateName": "BlockIP-Firepower-Teams", - "hidden-SentinelTemplateVersion": "1.0" + "hidden-SentinelTemplateVersion": "1.1" }, "identity": { "type": "SystemAssigned" @@ -176,8 +186,155 @@ } }, "actions": { - "Entities_-_Get_IPs": { + "Initialize_Dual_signal_context": { "runAfter": {}, + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "DualSignalContext", + "type": "string", + "value": "@{toLower(concat(coalesce(triggerBody()?['object']?['properties']?['title'], ''), ' ', coalesce(triggerBody()?['object']?['properties']?['description'], '')))}" + } + ] + }, + "description": "Concatenate incident title+description for dual-signal Gate/Prove warning on HITL BlockIP." + }, + "Gate_Prove_ML_only_HITL_warning": { + "actions": { + "Add_comment_to_incident_V3_ML_only_HITL_warning": { + "runAfter": {}, + "type": "ApiConnection", + "inputs": { + "body": { + "incidentArmId": "@triggerBody()?['object']?['id']", + "message": "

Gate/Prove HITL warning: ML-only
[FirepowerOutcome:v1] signal=ml-only; decision=unknown; containment=not-attempted; reason=hitl-review-requested; ruleVersion=1.0.2; policyVersion=1.0.0
This incident matches an ML-only path (SnortML / GID 411 / is_ml_only). Do not equate ML confidence to a signature true positive. Prefer Ignore unless a classic signature or dual-signal corroboration is present. Analyst confirmation in Teams is still required before BlockIP.

" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "post", + "path": "/Incidents/Comment" + } + } + }, + "runAfter": { + "Initialize_Dual_signal_context": [ + "Succeeded" + ] + }, + "else": { + "actions": {} + }, + "expression": { + "and": [ + { + "or": [ + { + "contains": [ + "@variables('DualSignalContext')", + "gid 411" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "gid:411" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "generator id 411" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "snortml" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "is_ml_only" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "ml-only" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "dual-signal:ml-only" + ] + } + ] + }, + { + "not": { + "or": [ + { + "contains": [ + "@variables('DualSignalContext')", + "is_corroborated" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "dual-signal:corroborated" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "signature and ml" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "gid 4110" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "gid:4110" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "gid=4110" + ] + }, + { + "contains": [ + "@variables('DualSignalContext')", + "generator id 4110" + ] + } + ] + } + } + ] + }, + "type": "If", + "description": "Gate/Prove: warn HITL operators when the incident is ML-only. Does not auto-block; Teams confirmation remains required." + }, + "Entities_-_Get_IPs": { + "runAfter": { + "Gate_Prove_ML_only_HITL_warning": [ + "Succeeded" + ] + }, "type": "ApiConnection", "inputs": { "body": "@triggerBody()?['object']?['properties']?['relatedEntities']", @@ -205,7 +362,7 @@ "inputs": { "body": { "incidentArmId": "@triggerBody()?['object']?['id']", - "message": "

Cisco Firepower playbook run summary
\nThe incident did not have any entities with IPs.

" + "message": "

Cisco Firepower playbook run summary
\n[FirepowerOutcome:v1] signal=unknown; decision=not-required; containment=not-attempted; reason=no-ip-entity; ruleVersion=unknown; policyVersion=1.0.0
The incident did not have any entities with IPs.

" }, "host": { "connection": { @@ -596,7 +753,7 @@ "inputs": { "body": { "incidentArmId": "@triggerBody()?['object']?['id']", - "message": "

Cisco Firepower playbook run summary
\nThe following IPs were found in the Incident:
\n
@{variables('ipAddressesActionComment')}

" + "message": "

Cisco Firepower playbook run summary
\n[FirepowerOutcome:v1] signal=@{if(or(contains(variables('DualSignalContext'),'is_corroborated'),contains(variables('DualSignalContext'),'dual-signal:corroborated'),contains(variables('DualSignalContext'),'signature and ml')),'corroborated',if(or(contains(variables('DualSignalContext'),'gid 411'),contains(variables('DualSignalContext'),'snortml'),contains(variables('DualSignalContext'),'ml-only')),'ml-only','signature'))}; decision=approved; containment=succeeded; reason=fmc-network-group-updated; ruleVersion=unknown; policyVersion=1.0.0
The following IPs were found in the Incident:
\n
@{variables('ipAddressesActionComment')}

" }, "host": { "connection": { @@ -867,6 +1024,27 @@ "Succeeded" ] }, + "else": { + "actions": { + "Add_outcome_comment_analyst_rejected": { + "runAfter": {}, + "type": "ApiConnection", + "inputs": { + "body": { + "incidentArmId": "@triggerBody()?['object']?['id']", + "message": "

Cisco Firepower analyst decision
[FirepowerOutcome:v1] signal=@{if(or(contains(variables('DualSignalContext'),'is_corroborated'),contains(variables('DualSignalContext'),'dual-signal:corroborated'),contains(variables('DualSignalContext'),'signature and ml')),'corroborated',if(or(contains(variables('DualSignalContext'),'gid 411'),contains(variables('DualSignalContext'),'snortml'),contains(variables('DualSignalContext'),'ml-only')),'ml-only','signature'))}; decision=rejected; containment=not-attempted; reason=teams-action-not-submitted; ruleVersion=unknown; policyVersion=1.0.0
The analyst did not submit the containment action. Cisco Firepower was not modified.

" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "post", + "path": "/Incidents/Comment" + } + } + } + }, "expression": { "and": [ { @@ -1123,4 +1301,4 @@ } } ] -} \ No newline at end of file +} diff --git a/Solutions/Cisco Firepower EStreamer/Playbooks/CiscoFirepower-BlockIP-Teams/readme.md b/Solutions/Cisco Firepower EStreamer/Playbooks/CiscoFirepower-BlockIP-Teams/readme.md index 45644a222fa..73ce5b5fd5c 100644 --- a/Solutions/Cisco Firepower EStreamer/Playbooks/CiscoFirepower-BlockIP-Teams/readme.md +++ b/Solutions/Cisco Firepower EStreamer/Playbooks/CiscoFirepower-BlockIP-Teams/readme.md @@ -4,12 +4,13 @@ This playbook allows blocking of IPs in Cisco Firepower, using a **Network Group object**. This allows making changes to a Network Group selected members, instead of making Access List Entries. The Network Group object itself should be part of an Access List Entry. -When a new Sentinel incident is created, this playbook gets triggered and performs below actions. -1. For the IPs we check if they are already selected for the Network Group object -2. An adaptive card is sent to a Teams channel with information about the incident and giving the option to ignore an IP, or depending on it's current status block it by adding it to the Network Group object or unblock it by removing it from the Network Group object +When a new Sentinel incident is created, this playbook gets triggered and performs below actions. It writes a bounded `[FirepowerOutcome:v1]` record for the HITL request and final approval or rejection, making the analyst decision available for repeatable evaluation. +1. **Gate/Prove:** if the incident title/description indicates **ML-only** (SnortML / GID 411 / `is_ml_only`) without corroboration, an incident comment warns the operator. The playbook does **not** auto-block; Teams confirmation is still required. Do not treat ML confidence as a signature true positive. +2. For the IPs we check if they are already selected for the Network Group object +3. An adaptive card is sent to a Teams channel with information about the incident and giving the option to ignore an IP, or depending on it's current status block it by adding it to the Network Group object or unblock it by removing it from the Network Group object ![Teams Adaptive Card preview](./Images/BlockIP-Teams-AdaptiveCard.png) -3. The chosen changes are applied to the Network Group object -4. Comment is added to Microsoft Sentinel incident +4. The chosen changes are applied to the Network Group object +5. Comment is added to Microsoft Sentinel incident ![Microsoft Sentinel comment](./Images/BlockIP-Teams-AzureSentinel-Comments.png) ** IP is added to Cisco Firepower Network Group object:** @@ -30,7 +31,7 @@ When a new Sentinel incident is created, this playbook gets triggered and perfor 1. Deploy the playbook by clicking on "Deploy to Azure" button. This will take you to deploying an ARM Template wizard. [![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FCisco%2520Firepower%2520EStreamer%2FPlaybooks%2FCiscoFirepower-BlockIP-Teams%2Fazuredeploy.json) -[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FCisco%2520Firepower%2520EStreamer%2FPlaybooks%2FCiscoFirepower-BlockIP-Teams%2Fazuredeploy.json) +[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovernbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FCisco%2520Firepower%2520EStreamer%2FPlaybooks%2FCiscoFirepower-BlockIP-Teams%2Fazuredeploy.json) 2. Fill in the required parameters: * Playbook Name: Enter the playbook name here (ex:CiscoFirepower-BlockIP-Teams) @@ -57,4 +58,5 @@ The Teams channel to which the adaptive card will be posted will need to be conf #### c. Configurations in Sentinel 1. In Microsoft sentinel analytical rules should be configured to trigger an incident with IP Entity. -2. Configure the automation rules to trigger this playbook \ No newline at end of file +2. Configure the automation rules to trigger this playbook +3. Prefer this HITL playbook for ML-only analytics (SnortML GID 411). Do not attach the auto-contain NetworkGroup playbook to ML-only incidents. diff --git a/Solutions/Cisco Firepower EStreamer/Playbooks/CiscoFirepowerConnector/readme.md b/Solutions/Cisco Firepower EStreamer/Playbooks/CiscoFirepowerConnector/readme.md index 1289f756457..60ae56f27c2 100644 --- a/Solutions/Cisco Firepower EStreamer/Playbooks/CiscoFirepowerConnector/readme.md +++ b/Solutions/Cisco Firepower EStreamer/Playbooks/CiscoFirepowerConnector/readme.md @@ -60,7 +60,7 @@ Prior using this custom connector, it should be deployed in the Resource Group w [![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FCisco%2520Firepower%2520EStreamer%2FPlaybooks%2FCustomConnector%2Fazuredeploy.json) -[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FCisco%2520Firepower%2520EStreamer%2FPlaybooks%2FCustomConnector%2Fazuredeploy.json) +[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovernbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FCisco%2520Firepower%2520EStreamer%2FPlaybooks%2FCustomConnector%2Fazuredeploy.json) ### Connector via on-premises data gateway 1. Deploy the Custom Connector by clicking on "Deploy to Azure" button. This will take you to deplyoing an ARM Template wizard. @@ -69,7 +69,7 @@ Prior using this custom connector, it should be deployed in the Resource Group w * Service Endpoint: The URL to the Cisco Firepower REST API [![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FCisco%2520Firepower%2520EStreamer%2FPlaybooks%2FCustomConnector%2Fazuredeploy.json) -[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FCisco%2520Firepower%2520EStreamer%2FPlaybooks%2FCustomConnector%2Fazuredeploy.json) +[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovernbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FCisco%2520Firepower%2520EStreamer%2FPlaybooks%2FCustomConnector%2Fazuredeploy.json) diff --git a/Solutions/Cisco Firepower EStreamer/Playbooks/readme.md b/Solutions/Cisco Firepower EStreamer/Playbooks/readme.md index fd922e6f434..e470fdfcc19 100644 --- a/Solutions/Cisco Firepower EStreamer/Playbooks/readme.md +++ b/Solutions/Cisco Firepower EStreamer/Playbooks/readme.md @@ -66,7 +66,7 @@ Custom connector should be deployed in the Resource Group where the playbooks th [![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FCisco%2520Firepower%2520EStreamer%2FPlaybooks%2FCustomConnector%2Fazuredeploy.json) -[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FCisco%2520Firepower%2520EStreamer%2FPlaybooks%2FCustomConnector%2Fazuredeploy.json) +[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovernbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FCisco%2520Firepower%2520EStreamer%2FPlaybooks%2FCustomConnector%2Fazuredeploy.json) ### Connector via on-premises data gateway 1. Deploy the Custom Connector by clicking on "Deploy to Azure" button. This will take you to deplyoing an ARM Template wizard. @@ -75,15 +75,17 @@ Custom connector should be deployed in the Resource Group where the playbooks th * Service Endpoint: The URL to the Cisco Firepower REST API [![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FCisco%2520Firepower%2520EStreamer%2FPlaybooks%2FCustomConnector%2Fazuredeploy-gateway.json) -[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FCisco%2520Firepower%2520EStreamer%2FPlaybooks%2FCustomConnector%2Fazuredeploy-gateway.json) +[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovernbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FCisco%2520Firepower%2520EStreamer%2FPlaybooks%2FCustomConnector%2Fazuredeploy-gateway.json)

## 2. Deploy the required playbook template (or create your own playbook from scratch) This integration offers 3 playbook templates that blocks IP in 3 different methods. Each one has it's own documentation and quick deployment button: * [Cisco Firepower - Add FQDN to a Network Group object](./CiscoFirepower-BlockFQDN-NetworkGroup#deployment-instructions) -* [Cisco Firepower - Add IP Addresses to a Network Group object](./CiscoFirepower-BlockIP-NetworkGroup#deployment-instructions) -* [Cisco Firepower - Add IP Addresses to a Network Group object with Teams](./CiscoFirepower-BlockIP-Teams#deployment-instructions) +* [Cisco Firepower - Add IP Addresses to a Network Group object](./CiscoFirepower-BlockIP-NetworkGroup#deployment-instructions) - auto-contain. **Gate/Prove:** auto-contain is denied when the incident is ML-only (SnortML / GID 411). Attach only to signature-high or corroborated analytics. +* [Cisco Firepower - Add IP Addresses to a Network Group object with Teams](./CiscoFirepower-BlockIP-Teams#deployment-instructions) - HITL. Warns on ML-only; analyst confirmation is still required before BlockIP. + +Both BlockIP playbooks add a bounded `[FirepowerOutcome:v1]` record to their Microsoft Sentinel incident comments. The record distinguishes signal, analyst or policy decision, containment outcome, stable reason code, and policy version so decisions can be evaluated without a separate data store. See the [response outcome contract](../Evaluation/FirepowerOutcome-v1.md) for its safety invariants and deterministic evaluation cases. diff --git a/Solutions/Cisco Firepower EStreamer/ReleaseNotes.md b/Solutions/Cisco Firepower EStreamer/ReleaseNotes.md index b01525318d9..76f9ac8e450 100644 --- a/Solutions/Cisco Firepower EStreamer/ReleaseNotes.md +++ b/Solutions/Cisco Firepower EStreamer/ReleaseNotes.md @@ -1,4 +1,8 @@ | **Version** | **Date Modified (DD-MM-YYYY)** | **Change History** | |-------------|--------------------------------|---------------------------------------------------------------------| +| 3.1.0 | 27-08-2026 | Added outcome-aware response evidence, a detection and response quality workbook, SnortML signal-mix drift analytics, and a versioned deterministic evaluation contract. | +| 3.0.5 | 27-08-2026 | Fixed Kusto SEM0420 in all three dual-signal Analytic Rules by replacing unsupported regex lookahead with numeric GID extraction and exact GID 411 comparison. | +| 3.0.4 | 25-08-2026 | Repackaged solution (Create-Azure-Sentinel-Solution V3 tool) to pick up the 3.0.3 dual-signal Analytic Rules and Gate/Prove BlockIP changes. | +| 3.0.3 | 17-08-2026 | Dual-signal Analytic Rules (SnortML GID 411 != signature TP) and Gate/Prove BlockIP (deny ML-only auto-contain; Teams HITL warning). | | 3.0.1 | 10-07-2024 | Deprecating data connectors. | | 3.0.0 | 26-09-2023 | Addition of new Cisco Firepower EStreamer AMA **Data Connector** | diff --git a/Solutions/Cisco Firepower EStreamer/Workbooks/CiscoFirepowerDetectionResponseQuality.json b/Solutions/Cisco Firepower EStreamer/Workbooks/CiscoFirepowerDetectionResponseQuality.json new file mode 100644 index 00000000000..f2c086b30e1 --- /dev/null +++ b/Solutions/Cisco Firepower EStreamer/Workbooks/CiscoFirepowerDetectionResponseQuality.json @@ -0,0 +1,85 @@ +{ + "version": "Notebook/1.0", + "items": [ + { + "type": 1, + "content": { + "json": "# Cisco Firepower detection and response quality\nThis workbook distinguishes ML-only, classic signature, and corroborated evidence. Trends are evaluation signals—not authorization for automatic containment." + }, + "name": "overview" + }, + { + "type": 9, + "content": { + "version": "KqlParameterItem/1.0", + "parameters": [ + { + "id": "4a060f53-dba7-42f6-b59d-49289bedecfe", + "version": "KqlParameterItem/1.0", + "name": "TimeRange", + "type": 4, + "isRequired": true, + "value": { "durationMs": 604800000 }, + "typeSettings": { + "selectableValues": [ + { "durationMs": 86400000 }, + { "durationMs": 604800000 }, + { "durationMs": 2592000000 } + ], + "allowCustom": true + } + } + ], + "style": "pills", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces" + }, + "name": "parameters" + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "let F = CommonSecurityLog\n| where DeviceVendor =~ 'Cisco' and DeviceProduct has_any ('Firepower','Secure Firewall','FTD','NGFW')\n| extend C=strcat(tostring(Message),' ',tostring(AdditionalExtensions),' ',tostring(Activity),' ',tostring(DeviceEventClassID),' ',tostring(column_ifexists('FlexString1','')),' ',tostring(column_ifexists('FlexString2','')),' ',tostring(column_ifexists('DeviceCustomString1','')),' ',tostring(column_ifexists('DeviceCustomString2','')),' ',tostring(column_ifexists('DeviceCustomString3','')))\n| extend Gid=toint(extract(@'(?i)(?:gid|generator[\\s_-]?id)[\\s:=]*(\\d+)',1,C))\n| extend Signal=case(C has 'is_corroborated','Corroborated',Gid == 411 or C has 'is_ml_only','ML-only',isnotnull(Gid),'Signature','Unknown');\nF | summarize Events=count(), Sources=dcount(SourceIP), Destinations=dcount(DestinationIP) by Signal | order by Events desc", + "size": 1, + "title": "Signal composition", + "timeContextFromParameter": "TimeRange", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces", + "visualization": "tiles" + }, + "name": "signal-composition" + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "CommonSecurityLog\n| where DeviceVendor =~ 'Cisco' and DeviceProduct has_any ('Firepower','Secure Firewall','FTD','NGFW')\n| extend C=strcat(tostring(Message),' ',tostring(AdditionalExtensions),' ',tostring(Activity),' ',tostring(DeviceEventClassID))\n| extend Gid=toint(extract(@'(?i)(?:gid|generator[\\s_-]?id)[\\s:=]*(\\d+)',1,C))\n| extend Signal=case(C has 'is_corroborated','Corroborated',Gid == 411 or C has 'is_ml_only','ML-only',isnotnull(Gid),'Signature','Unknown')\n| summarize Events=count() by bin(TimeGenerated,1h), Signal\n| order by TimeGenerated asc", + "size": 0, + "title": "Signal mix over time", + "timeContextFromParameter": "TimeRange", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces", + "visualization": "timechart" + }, + "name": "signal-trend" + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "CommonSecurityLog\n| where DeviceVendor =~ 'Cisco' and DeviceProduct has_any ('Firepower','Secure Firewall','FTD','NGFW')\n| extend C=strcat(tostring(Message),' ',tostring(AdditionalExtensions),' ',tostring(Activity),' ',tostring(DeviceEventClassID))\n| extend Gid=toint(extract(@'(?i)(?:gid|generator[\\s_-]?id)[\\s:=]*(\\d+)',1,C))\n| summarize Total=count(), MlOnly=countif(Gid == 411 or C has 'is_ml_only'), Signatures=countif(isnotnull(Gid) and Gid != 411) by DeviceName\n| extend MlRatio=round(100.0 * todouble(MlOnly) / iff(Total == 0,1,Total),2)\n| order by MlRatio desc", + "size": 0, + "title": "Sensor and collector quality", + "timeContextFromParameter": "TimeRange", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces", + "visualization": "table" + }, + "name": "sensor-quality" + } + ], + "fallbackResourceIds": ["Azure Monitor"], + "fromTemplateId": "sentinel-CiscoFirepowerDetectionResponseQuality", + "$schema": "https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json" +} diff --git a/Workbooks/WorkbooksMetadata.json b/Workbooks/WorkbooksMetadata.json index 124c93f275d..c50a8627639 100644 --- a/Workbooks/WorkbooksMetadata.json +++ b/Workbooks/WorkbooksMetadata.json @@ -3744,6 +3744,43 @@ ] } }, + { + "workbookKey": "CiscoFirepowerDetectionResponseQuality", + "logoFileName": "cisco-logo-72px.svg", + "description": "Evaluates Cisco Firepower detection signal composition and drift while preserving the safety boundary between SnortML GID 411, classic signatures, and corroborated evidence.", + "dataTypesDependencies": [ + "CommonSecurityLog" + ], + "dataConnectorsDependencies": [ + "CiscoFirepowerEStreamerAMA" + ], + "previewImagesFileNames": [ + "CiscoFirepowerBlack.png", + "CiscoFirepowerWhite.png" + ], + "version": "1.0.0", + "title": "Cisco Firepower Detection and Response Quality", + "templateRelativePath": "CiscoFirepowerDetectionResponseQuality.json", + "subtitle": "Outcome-aware signal quality and drift evaluation", + "provider": "Cisco", + "support": { + "name": "Cisco", + "tier": "Partner", + "link": "https://www.cisco.com/c/en_in/support/index.html" + }, + "author": { + "name": "Cisco" + }, + "source": { + "kind": "Solution", + "name": "Cisco Firepower EStreamer" + }, + "categories": { + "domains": [ + "Security - Network" + ] + } + }, { "workbookKey": "MicrosoftTeams", "logoFileName": "microsoftteams.svg",