diff --git a/.gitignore b/.gitignore index 1a02111a..ee0b85ed 100644 --- a/.gitignore +++ b/.gitignore @@ -397,3 +397,4 @@ FodyWeavers.xsd # JetBrains Rider *.sln.iml .DS_Store +.vscode/* diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..b242572e --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "githubPullRequests.ignoredPullRequestBranches": [ + "main" + ] +} \ No newline at end of file diff --git a/Images/Community Plugins/RedactPII/RedactPIIPrompt.png b/Images/Community Plugins/RedactPII/RedactPIIPrompt.png new file mode 100644 index 00000000..e0f580aa Binary files /dev/null and b/Images/Community Plugins/RedactPII/RedactPIIPrompt.png differ diff --git a/Images/Community Plugins/SecurityCopilotLogins/LoginsAndAnomalies.png b/Images/Community Plugins/SecurityCopilotLogins/LoginsAndAnomalies.png new file mode 100644 index 00000000..9f4f2c02 Binary files /dev/null and b/Images/Community Plugins/SecurityCopilotLogins/LoginsAndAnomalies.png differ diff --git a/Images/Community Plugins/SentinelIncidentComments/SentinelIncidentComments.png b/Images/Community Plugins/SentinelIncidentComments/SentinelIncidentComments.png new file mode 100644 index 00000000..e3137be1 Binary files /dev/null and b/Images/Community Plugins/SentinelIncidentComments/SentinelIncidentComments.png differ diff --git a/Images/Community Plugins/WatchlistKQL/TrustedUserWatchlist.png b/Images/Community Plugins/WatchlistKQL/TrustedUserWatchlist.png new file mode 100644 index 00000000..5c63cc27 Binary files /dev/null and b/Images/Community Plugins/WatchlistKQL/TrustedUserWatchlist.png differ diff --git a/Logic Apps/CfS-SendPromptbookResultsByEmail/CfS-SendPromptbookResultsByEmail.json b/Logic Apps/CfS-SendPromptbookResultsByEmail/CfS-SendPromptbookResultsByEmail.json new file mode 100644 index 00000000..92d0cd62 --- /dev/null +++ b/Logic Apps/CfS-SendPromptbookResultsByEmail/CfS-SendPromptbookResultsByEmail.json @@ -0,0 +1,1257 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "title": "Send the results of Security Copilot's Promptbook by email", + "description": "This Logic App executes the specified Promptbook in Security Copilot (a.k.a. Copilot for Security). It then converts each prompt's response, written in the simplified markdown language of Security Copilot, into HTML. Using these HTML excerpts or plain text responses and starting from a specified HTML template, it constructs the HTML body of an email and finally sends that email to the specified recipients. It is possible to exclude one or more of the promptbook responses from the email by their position index (1, 2, 3, etc.)", + "prerequisites": "", + "postDeployment": [ + "1. Set the credentials for the OAuth API connection to Security Copilot and Office 365 (the connection to O365 is used to send the email).", + "2. Edit the workflow and set the promptbook name and related parameters in the run-prompt action (after the deployment, they are empty).", + "3. In the workflow editor, if needed, modify the trigger type and/or parameters (e.g., change the recurrence date and time or replace the trigger with the Microsoft Sentinel Incident trigger).", + "4. In the workflow editor, open the parameters and set the desired email title, subject, and recipients.", + "5. In the workflow editor, in the parameters list, if needed, specify the indexes of the prompts that should not be included in the email (use the SkipPromptsInOutput parameter).", + "6. In the workflow editor, in the parameters list, if needed, specify the prompts that should be replaced in the email (use the ReplacePromptsInOutput parameter).", + "7. In the workflow editor, if needed, further customize the email subject in the send email action (e.g., if you have changed the trigger to 'MS Sentinel Incident', you may want to dynamically include the incident ID or title at the end of the email subject; this cannot be done in the paramteres).", + "8. Enable the Logic App (the template deploys it in the disabled state)." + ], + "prerequisitesDeployTemplateFile": "", + "lastUpdateTime": "", + "entities": [ + ], + "tags": [ + ], + "support": { + "tier": "community", + "armtemplate": "Generated from https://github.com/Azure/Azure-Sentinel/tree/master/Tools/Playbook-ARM-Template-Generator" + }, + "author": { + "name": "Stefano Pescosolido (https://www.linkedin.com/in/stefanopescosolido/)" + } + }, + "parameters": { + "PlaybookName": { + "defaultValue": "CfS-SendPromptbookResultsByEmail", + "type": "string" + }, + "HtmlBodyHeader": { + "defaultValue": "
|
Name of CVE: @{items('For_each')?['cveID']}
CVE Date: @{items('For_each')?['dateAdded']}
Impacted Devices: @{body('Submit_a_Copilot_for_Security_prompt_2')?['EvaluationResultContent']}
Impacted Vendors: @{items('For_each')?['vendorProject']}
Details: @{body('Submit_a_Copilot_for_Security_prompt')?['EvaluationResultContent']}
Exploitation Status: @{items('For_each')?['knownRansomwareCampaignUse']}
Mediation Steps: @{items('For_each')?['requiredAction']}
@{body('Generate_HTML_report_from_JSON')}
", + "path": "/html2text" + } + }, + "Alert_-_Get_incident_from_systemalertid": { + "runAfter": { + "If_empty_results_wait_15_minutes_for_logs_to_show_up": [ + "Succeeded" + ] + }, + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "get", + "path": "[concat('/Incidents/subscriptions/@{encodeURIComponent(''', parameters('SubscriptionId'), ''')}/resourceGroups/@{encodeURIComponent(''', parameters('LogAnalyticsResourceGroup'),''')}/workspaces/@{encodeURIComponent(''', parameters('LogAnalyticsWorkspId') ,''')}/alerts/@{encodeURIComponent(variables(''systemalertid_query_results'')[0][''SystemAlertId''])}')]" + } + }, + "Add_comment_to_incident_(V3)_armid": { + "runAfter": { + "Alert_-_Get_incident_from_systemalertid": [ + "Succeeded" + ] + }, + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "post", + "body": { + "incidentArmId": "@body('Alert_-_Get_incident_from_systemalertid')?['id']", + "message": "********** Phishing Analysis Generated by Security Copilot **********
@{body('Html_to_text')}
---
Report generated: @{utcNow()}
Generated with AI, check for accuracy.
@{body('Generate_HTML_report_from_JSON')}
***********
Incident URL:
@{body('Alert_-_Get_incident_from_systemalertid')?['properties']?['incidentUrl']}
Generated with AI, check for accuracy.
***********
", + "Importance": "Normal" + }, + "path": "/v2/SharedMailbox/Mail" + } + }, + "If_empty_results_wait_15_minutes_for_logs_to_show_up": { + "actions": { + "Delay_15_min": { + "type": "Wait", + "inputs": { + "interval": { + "count": 15, + "unit": "Minute" + } + } + }, + "Second_try_set_variable_systemalertid_query_results": { + "runAfter": { + "Query_to_get_systemalertid_second_try": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "systemalertid_query_results", + "value": "@body('Query_to_get_systemalertid_second_try')?['value']" + } + }, + "Query_to_get_systemalertid_second_try": { + "runAfter": { + "Delay_15_min": [ + "Succeeded" + ] + }, + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['azuremonitorlogs']['connectionId']" + } + }, + "method": "post", + "body": "SecurityAlert\n| where isnotempty(Entities)\n| extend MailEntities = parse_json(Entities)\n| mv-expand MailEntities\n| where MailEntities.Type == \"mailMessage\"\n| extend NetworkMessageId = tostring(MailEntities.NetworkMessageId)\n| where NetworkMessageId == \"@{variables('network_message_id')}\"\n| distinct SystemAlertId", + "path": "/queryData", + "queries": { + "subscriptions": "[parameters('SubscriptionId')]", + "resourcegroups": "[parameters('LogAnalyticsResourceGroup')]", + "resourcetype": "Log Analytics Workspace", + "resourcename": "[parameters('LogAnalyticsWorkspaceName')]", + "timerange": "14d" + } + } + } + }, + "runAfter": { + "Set_variable_systemalertid_query_results": [ + "Succeeded" + ] + }, + "else": { + "actions": {} + }, + "expression": { + "and": [ + { + "less": [ + "@length(body('Query_to_get_systemalertid')?['value'])", + 1 + ] + } + ] + }, + "type": "If" + }, + "Set_variable_systemalertid_query_results": { + "runAfter": { + "Query_to_get_systemalertid": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "systemalertid_query_results", + "value": "@body('Query_to_get_systemalertid')?['value']" + } + }, + "Query_to_get_systemalertid": { + "runAfter": { + "Html_to_text": [ + "Succeeded" + ] + }, + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['azuremonitorlogs']['connectionId']" + } + }, + "method": "post", + "body": "SecurityAlert\n| where isnotempty(Entities)\n| extend MailEntities = parse_json(Entities)\n| mv-expand MailEntities\n| where MailEntities.Type == \"mailMessage\"\n| extend NetworkMessageId = tostring(MailEntities.NetworkMessageId)\n| where NetworkMessageId == \"@{variables('network_message_id')}\"\n| distinct SystemAlertId", + "path": "/queryData", + "queries": { + "subscriptions": "[parameters('SubscriptionId')]", + "resourcegroups": "[parameters('LogAnalyticsResourceGroup')]", + "resourcetype": "Log Analytics Workspace", + "resourcename": "[parameters('LogAnalyticsWorkspaceName')]", + "timerange": "14d" + } + } + } + }, + "runAfter": { + "Initialize_systemalert_id_query_results": [ + "Succeeded" + ] + }, + "else": { + "actions": { + "Send_an_email_from_a_shared_mailbox_(V2)_without_incident_url": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['office365-1']['connectionId']" + } + }, + "method": "post", + "body": { + "MailboxAddress": "[parameters('SharedMailboxAddress')]", + "To": "[parameters('HTMLReportRecipient')]", + "Subject": "Phishing Email Analysis", + "Body": "
@{body('Generate_HTML_report_from_JSON')}
***********
Generated with AI, check for accuracy.
***********
", + "Attachments": [ + { + "Name": "original_email.eml", + "ContentBytes": "@base64(body('Export_email_(V2)'))" + } + ], + "Importance": "Normal" + }, + "path": "/v2/SharedMailbox/Mail" + } + } + } + }, + "expression": { + "and": [ + { + "equals": [ + "@variables('is_defender_incident')", + true + ] + } + ] + }, + "type": "If" + }, + "Parse_Email": { + "runAfter": { + "For_each_raw_email_attached_to_carrier_email": [ + "Succeeded" + ] + }, + "type": "Function", + "inputs": { + "body": "@variables('raw_email')", + "function": { + "id": "[concat('/subscriptions/', parameters('SubscriptionId'), '/resourceGroups/', parameters('FunctionAppResourceGroup'), '/providers/Microsoft.Web/sites/', parameters('FunctionAppName'), '/functions/', variables('FunctionName01'))]" + } + } + }, + "Normalize_JSON": { + "runAfter": { + "Security_Copilot_Email_Analysis": [ + "Succeeded" + ] + }, + "type": "Function", + "inputs": { + "body": "@body('Security_Copilot_Email_Analysis')?['EvaluationResultContent']", + "function": { + "id": "[concat('/subscriptions/', parameters('SubscriptionId'), '/resourceGroups/', parameters('FunctionAppResourceGroup'), '/providers/Microsoft.Web/sites/', parameters('FunctionAppName'), '/functions/', variables('FunctionName02'))]" + } + } + }, + "Generate_HTML_report_from_JSON": { + "runAfter": { + "Parse_normalized_JSON": [ + "Succeeded" + ] + }, + "type": "Function", + "inputs": { + "body": "@body('Parse_normalized_JSON')", + "function": { + "id": "[concat('/subscriptions/', parameters('SubscriptionId'), '/resourceGroups/', parameters('FunctionAppResourceGroup'), '/providers/Microsoft.Web/sites/', parameters('FunctionAppName'), '/functions/', variables('FunctionName03'))]" + } + } + } + }, + "outputs": {} + }, + "parameters": { + "$connections": { + "value": { + "office365-1": { + "id": "[concat('/subscriptions/', parameters('SubscriptionId'), '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/office365')]", + "connectionId": "[resourceId('Microsoft.Web/connections', variables('Office365-ConnectionName'))]", + "connectionName": "[variables('Office365-ConnectionName')]" + }, + + "securitycopilot-1": { + "id": "[concat('/subscriptions/', parameters('SubscriptionId'), '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/securitycopilot')]", + "connectionId": "[resourceId('Microsoft.Web/connections', variables('Securitycopilot-ConnectionName'))]", + "connectionName": "[variables('Securitycopilot-ConnectionName')]" + }, + + "azuresentinel": { + "id": "[concat('/subscriptions/', parameters('SubscriptionId'), '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/azuresentinel')]", + "connectionId": "[resourceId('Microsoft.Web/connections', variables('AzureSentinel-ConnectionName'))]", + "connectionName": "[variables('AzureSentinel-ConnectionName')]", + "connectionProperties": { + "authentication": { + "type": "ManagedServiceIdentity" + } + } + }, + "azuremonitorlogs": { + "id": "[concat('/subscriptions/', parameters('SubscriptionId'), '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/azuremonitorlogs')]", + "connectionId": "[resourceId('Microsoft.Web/connections', variables('AzureMonitorLogs-ConnectionName'))]", + "connectionName": "[variables('AzureMonitorLogs-ConnectionName')]", + "connectionProperties": { + "authentication": { + "type": "ManagedServiceIdentity" + } + } + }, + "conversionservice-1": { + "id": "[concat('/subscriptions/', parameters('SubscriptionId'), '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/conversionservice')]", + "connectionId": "[resourceId('Microsoft.Web/connections', variables('ConversionService-ConnectionName'))]", + "connectionName": "[variables('ConversionService-ConnectionName')]" + } + } + } + } + } + } + ] +} \ No newline at end of file diff --git a/Logic Apps/SecCopilot-UserReportedPhishing/DefenderKqlPlugins_automation.yaml b/Logic Apps/SecCopilot-UserReportedPhishing/DefenderKqlPlugins_automation.yaml index 6446d4ea..d4d5ec68 100644 --- a/Logic Apps/SecCopilot-UserReportedPhishing/DefenderKqlPlugins_automation.yaml +++ b/Logic Apps/SecCopilot-UserReportedPhishing/DefenderKqlPlugins_automation.yaml @@ -13,8 +13,8 @@ SkillGroups: Description: The subject of the email Required: true Settings: - Target: Defender - Template: |- + Target: Defender + Template: |- EmailEvents | where Subject == '{{subject}}' - Name: GetUrlClicksBySubjectAndSenderEmail @@ -28,8 +28,8 @@ SkillGroups: Description: The sender of the email Required: true Settings: - Target: Defender - Template: |- + Target: Defender + Template: |- let email = EmailEvents | where Subject == '{{subject}}' and SenderFromAddress == '{{senderEmail}}' | project NetworkMessageId; diff --git a/Logic Apps/SecurityCopilot-Sentinel-Incident-Investigation/azuredeploy.json b/Logic Apps/SecurityCopilot-Sentinel-Incident-Investigation/azuredeploy.json new file mode 100644 index 00000000..3101ea3a --- /dev/null +++ b/Logic Apps/SecurityCopilot-Sentinel-Incident-Investigation/azuredeploy.json @@ -0,0 +1,3020 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "title": "SecurityCopilot-Sentinel-Incident-Investigation", + "description": "Logic App automating incident investigation within Microsoft Sentinel using Security Copilot", + "prerequisites": "", + "postDeployment": [ + ], + "prerequisitesDeployTemplateFile": "", + "lastUpdateTime": "", + "entities": [ + ], + "tags": [ + ], + "support": { + "tier": "community", + "armtemplate": "Generated from https://github.com/Azure/Azure-Sentinel/tree/master/Tools/Playbook-ARM-Template-Generator" + }, + "author": { + "name": "" + } + }, + "parameters": { + "PlaybookName": { + "defaultValue": "SecurityCopilot-Sentinel-Incident-Investigation", + "type": "string" + }, + "CallScpForIPsWithAbuseIPDB": { + "type": "Bool", + "metadata": { + "description": "Leave 'true' if you want Security Copilot to investigate the IP addresses on AbuseIPDB. Set 'false' otherwise." + }, + "defaultValue": true + }, + "CallScpForIPsWithMDTI": { + "type": "Bool", + "metadata": { + "description": "Leave 'true' if you want Security Copilot to investigate the IP addresses on MDTI. Set 'false' otherwise." + }, + "defaultValue": true + }, + "CallScpForAccounts": { + "type": "Bool", + "metadata": { + "description": "Leave 'true' if you want Security Copilot to investigate the accounts on MS Entra. Set 'false' otherwise." + }, + "defaultValue": true + }, + "CallScpForUserRisk": { + "type": "Bool", + "metadata": { + "description": "Leave 'true' if you want Security Copilot to check the risk level of the users on MS Entra. Set 'false' otherwise." + }, + "defaultValue": true + }, + "CallScpForHosts": { + "type": "Bool", + "metadata": { + "description": "Leave 'true' if you want Security Copilot to investigate the devices on Intune. Set 'false' otherwise." + }, + "defaultValue": true + }, + "CallScpForCommandLines": { + "type": "Bool", + "metadata": { + "description": "Leave 'true' if you want Security Copilot to investigate the command lines by using its script analysis capability. Set 'false' otherwise." + }, + "defaultValue": true + }, + "CallScpForFilehashesWithMDTI": { + "type": "Bool", + "metadata": { + "description": "Leave 'true' if you want Security Copilot to investigate the file hashes on MDTI. Set 'false' otherwise." + }, + "defaultValue": true + }, + "CallScpForUrlsWithMDTI": { + "type": "Bool", + "metadata": { + "description": "Leave 'true' if you want Security Copilot to investigate the Urls on MDTI. Set 'false' otherwise." + }, + "defaultValue": true + }, + "CallScpForDomainsWithMDTI": { + "type": "Bool", + "metadata": { + "description": "Leave 'true' if you want Security Copilot to investigate the domains on MDTI. Set 'false' otherwise." + }, + "defaultValue": true + }, + "SkipIPs": { + "type": "Array", + "metadata": { + "description": "Enter, as an array of strings, the IPs that you do not want Security Copilot to investigate" + }, + "defaultValue": [] + }, + "SkipAccounts": { + "type": "Array", + "metadata": { + "description": "Enter, as an array of strings, the accounts that you do not want Security Copilot to investigate" + }, + "defaultValue": [] + }, + "SkipHosts": { + "type": "Array", + "metadata": { + "description": "Enter, as an array of strings, the devices that you do not want Security Copilot to investigate" + }, + "defaultValue": [] + }, + "SkipCommandLines": { + "type": "Array", + "metadata": { + "description": "Enter, as an array of strings, the command lines that you do not want Security Copilot to investigate" + }, + "defaultValue": ["cmd.exe","explorer.exe"] + }, + "SkipFilehashes": { + "type": "Array", + "metadata": { + "description": "Enter, as an array of strings, the file hashes that you do not want Security Copilot to investigate" + }, + "defaultValue": [] + }, + "SkipUrls": { + "type": "Array", + "metadata": { + "description": "Enter, as an array of strings, the urls that you do not want Security Copilot to investigate" + }, + "defaultValue": [] + }, + "SkipDomains": { + "type": "Array", + "metadata": { + "description": "Enter, as an array of strings, the domains that you do not want Security Copilot to investigate" + }, + "defaultValue": [] + }, + "MaxMdtiOutputLenghtForPreSummarization": { + "type": "Int", + "metadata": { + "description": "When the overall length of the aggregated MDTI results report is greater than the number specified here, an additional call is made to Security Copilot to pre-summarize this specific report. This pre-summarization reduces the risk that the final summarization gets an error because the overall input text is too long. " + }, + "defaultValue": 2000 + }, + "WriteUnsummarizedResultsToIncident": { + "type": "Bool", + "metadata": { + "description": "Leave true if you want that the raw results are saved as comment to the Sentinel incident. The raw results are the results before the final summarization. Set false otherwise. " + }, + "defaultValue": true + }, + "WriteFinalSummaryToIncident": { + "type": "Bool", + "metadata": { + "description": "Leave true if you want that the summarized results are saved as comment to the Sentinel incident. Set false otherwise. " + }, + "defaultValue": true + }, + "RecipientEmail": { + "type": "String", + "metadata": { + "description": "Enter the email addrees of the recipient for the emails sent by this automation." + }, + "defaultValue": "" + }, + "SendUnsummarizedResultsByEmail": { + "type": "Bool", + "metadata": { + "description": "Leave true if you want that the raw results are sent by email to the specified recipient. The raw results are the results before the final summarization. Set false otherwise. " + }, + "defaultValue": true + }, + "SendFinalSummaryByEmail": { + "type": "Bool", + "metadata": { + "description": "Leave true if you want that the summarized results are sent by email to the specified recipient. Set false otherwise. " + }, + "defaultValue": true + } + }, + "variables": { + "MicrosoftSentinelConnectionName": "[concat('MicrosoftSentinel-', parameters('PlaybookName'))]", + "SecuritycopilotConnectionName": "[concat('Securitycopilot-', parameters('PlaybookName'))]", + "Office365ConnectionName": "[concat('Office365-', parameters('PlaybookName'))]" + }, + "resources": [ + { + "properties": { + "provisioningState": "Succeeded", + "state": "Enabled", + "definition": { + "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "$connections": { + "defaultValue": { + }, + "type": "Object" + }, + "CallScpForIPsWithAbuseIPDB": { + "defaultValue": "[parameters('CallScpForIPsWithAbuseIPDB')]", + "type": "Bool" + }, + "CallScpForIPsWithMDTI": { + "defaultValue": "[parameters('CallScpForIPsWithMDTI')]", + "type": "Bool" + }, + "CallScpForAccounts": { + "defaultValue": "[parameters('CallScpForAccounts')]", + "type": "Bool" + }, + "CallScpForUserRisk": { + "defaultValue": "[parameters('CallScpForUserRisk')]", + "type": "Bool" + }, + "CallScpForHosts": { + "defaultValue": "[parameters('CallScpForHosts')]", + "type": "Bool" + }, + "CallScpForCommandLines": { + "defaultValue": "[parameters('CallScpForCommandLines')]", + "type": "Bool" + }, + "CallScpForFilehashesWithMDTI": { + "defaultValue": "[parameters('CallScpForFilehashesWithMDTI')]", + "type": "Bool" + }, + "CallScpForUrlsWithMDTI": { + "defaultValue": "[parameters('CallScpForUrlsWithMDTI')]", + "type": "Bool" + }, + "CallScpForDomainsWithMDTI": { + "defaultValue": "[parameters('CallScpForDomainsWithMDTI')]", + "type": "Bool" + }, + "SkipIPs": { + "defaultValue": "[parameters('SkipIPs')]", + "type": "Array" + }, + "SkipAccounts": { + "defaultValue": "[parameters('SkipAccounts')]", + "type": "Array" + }, + "SkipHosts": { + "defaultValue": "[parameters('SkipHosts')]", + "type": "Array" + }, + "SkipCommandLines": { + "defaultValue": "[parameters('SkipCommandLines')]", + "type": "Array" + }, + "SkipFilehashes": { + "defaultValue": "[parameters('SkipFilehashes')]", + "type": "Array" + }, + "SkipUrls": { + "defaultValue": "[parameters('SkipUrls')]", + "type": "Array" + }, + "SkipDomains": { + "defaultValue": "[parameters('SkipDomains')]", + "type": "Array" + }, + "MaxMdtiOutputLenghtForPreSummarization": { + "defaultValue": "[parameters('MaxMdtiOutputLenghtForPreSummarization')]", + "type": "Int" + }, + "WriteUnsummarizedResultsToIncident": { + "defaultValue": "[parameters('WriteUnsummarizedResultsToIncident')]", + "type": "Bool" + }, + "WriteFinalSummaryToIncident": { + "defaultValue": "[parameters('WriteFinalSummaryToIncident')]", + "type": "Bool" + }, + "RecipientEmail": { + "defaultValue": "[parameters('RecipientEmail')]", + "type": "String" + }, + "SendUnsummarizedResultsByEmail": { + "defaultValue": "[parameters('SendUnsummarizedResultsByEmail')]", + "type": "Bool" + }, + "SendFinalSummaryByEmail": { + "defaultValue": "[parameters('SendFinalSummaryByEmail')]", + "type": "Bool" + } + }, + "triggers": { + "Microsoft_Sentinel_incident": { + "type": "ApiConnectionWebhook", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "body": { + "callback_url": "@{listCallbackUrl()}" + }, + "path": "/incident-creation" + } + } + }, + "actions": { + "Compose_Incident_Entities": { + "runAfter": { + }, + "type": "Compose", + "inputs": "@triggerBody()?['object']?['properties']?['relatedEntities']" + }, + "Condition_-_Validate_Entities": { + "actions": { + "For_Each_Entity": { + "foreach": "@outputs('Compose_Incident_Entities')", + "actions": { + "Switch": { + "runAfter": { + "Show_item_for_debug_purposes": [ + "Succeeded" + ] + }, + "cases": { + "Case_-_Ip_Address": { + "case": "Ip", + "actions": { + "Condition_-_IP": { + "actions": { + "Condition_-_IP_-_Use_AbuseIPDB": { + "actions": { + "Append_to_array_forScp-IPs": { + "type": "AppendToArrayVariable", + "inputs": { + "name": "forScp-IPs", + "value": "@items('For_Each_Entity')?['properties']?['address']" + } + } + }, + "runAfter": { + "Append_IP_to_ProcessedItems": [ + "Succeeded" + ] + }, + "else": { + "actions": { + } + }, + "expression": { + "and": [ + { + "equals": [ + "@parameters('CallScpForIPsWithAbuseIPDB')", + true + ] + } + ] + }, + "type": "If" + }, + "Condition_-_IP_-_Use_MDTI": { + "actions": { + "Append_IP_to_array_variable_IndicatorsForMDTI": { + "type": "AppendToArrayVariable", + "inputs": { + "name": "forScp-Indicators", + "value": "@items('For_Each_Entity')?['properties']?['address']" + } + } + }, + "runAfter": { + "Append_IP_to_ProcessedItems": [ + "Succeeded" + ] + }, + "else": { + "actions": { + } + }, + "expression": { + "and": [ + { + "equals": [ + "@parameters('CallScpForIPsWithMDTI')", + true + ] + } + ] + }, + "type": "If" + }, + "Append_IP_to_ProcessedItems": { + "type": "AppendToArrayVariable", + "inputs": { + "name": "ProcessedItems", + "value": "@concat('IP:',trim(toLower(items('For_Each_Entity')?['properties']?['address'])))" + } + } + }, + "else": { + "actions": { + } + }, + "expression": { + "and": [ + { + "or": [ + { + "equals": [ + "@parameters('CallScpForIPsWithAbuseIPDB')", + "ture" + ] + }, + { + "equals": [ + "@parameters('CallScpForIPsWithMDTI')", + true + ] + } + ] + }, + { + "equals": [ + "@empty(items('For_Each_Entity')?['properties']?['address'])", + false + ] + }, + { + "not": { + "contains": [ + "@parameters('SkipIPs')", + "@toLower(items('For_Each_Entity')?['properties']?['address'])" + ] + } + }, + { + "not": { + "equals": [ + "@items('For_Each_Entity')?['properties']?['address']", + "127.0.0.1" + ] + } + }, + { + "not": { + "equals": [ + "@items('For_Each_Entity')?['properties']?['address']", + "::1" + ] + } + }, + { + "not": { + "startsWith": [ + "@items('For_Each_Entity')?['properties']?['address']", + "10." + ] + } + }, + { + "not": { + "startsWith": [ + "@items('For_Each_Entity')?['properties']?['address']", + "192.168." + ] + } + }, + { + "not": { + "startsWith": [ + "@items('For_Each_Entity')?['properties']?['address']", + "172.16." + ] + } + }, + { + "not": { + "startsWith": [ + "@items('For_Each_Entity')?['properties']?['address']", + "172.17." + ] + } + }, + { + "not": { + "startsWith": [ + "@items('For_Each_Entity')?['properties']?['address']", + "172.18." + ] + } + }, + { + "not": { + "startsWith": [ + "@items('For_Each_Entity')?['properties']?['address']", + "172.19." + ] + } + }, + { + "not": { + "startsWith": [ + "@items('For_Each_Entity')?['properties']?['address']", + "172.20." + ] + } + }, + { + "not": { + "startsWith": [ + "@items('For_Each_Entity')?['properties']?['address']", + "172.21." + ] + } + }, + { + "not": { + "startsWith": [ + "@items('For_Each_Entity')?['properties']?['address']", + "172.22." + ] + } + }, + { + "not": { + "startsWith": [ + "@items('For_Each_Entity')?['properties']?['address']", + "172.23." + ] + } + }, + { + "not": { + "startsWith": [ + "@items('For_Each_Entity')?['properties']?['address']", + "172.24." + ] + } + }, + { + "not": { + "startsWith": [ + "@items('For_Each_Entity')?['properties']?['address']", + "172.25." + ] + } + }, + { + "not": { + "endsWith": [ + "@items('For_Each_Entity')?['properties']?['address']", + "172.26." + ] + } + }, + { + "not": { + "startsWith": [ + "@items('For_Each_Entity')?['properties']?['address']", + "172.27." + ] + } + }, + { + "not": { + "startsWith": [ + "@items('For_Each_Entity')?['properties']?['address']", + "172.28." + ] + } + }, + { + "not": { + "startsWith": [ + "@items('For_Each_Entity')?['properties']?['address']", + "172.29." + ] + } + }, + { + "not": { + "startsWith": [ + "@items('For_Each_Entity')?['properties']?['address']", + "172.30." + ] + } + }, + { + "not": { + "startsWith": [ + "@items('For_Each_Entity')?['properties']?['address']", + "172.31." + ] + } + }, + { + "not": { + "startsWith": [ + "@toLower(items('For_Each_Entity')?['properties']?['address'])", + "fd00::" + ] + } + }, + { + "not": { + "startsWith": [ + "@toLower(items('For_Each_Entity')?['properties']?['address'])", + "fc00::" + ] + } + }, + { + "not": { + "startsWith": [ + "@toLower(items('For_Each_Entity')?['properties']?['address'])", + "ff00::" + ] + } + }, + { + "not": { + "startsWith": [ + "@toLower(items('For_Each_Entity')?['properties']?['address'])", + "fe80::" + ] + } + }, + { + "not": { + "startsWith": [ + "@toLower(items('For_Each_Entity')?['properties']?['address'])", + "::ffff:" + ] + } + } + ] + }, + "type": "If" + } + } + }, + "Case_-_Account": { + "case": "Account", + "actions": { + "Condition_-_Account": { + "actions": { + "Append_User_Upn_to_ProcessedItems": { + "type": "AppendToArrayVariable", + "inputs": { + "name": "ProcessedItems", + "value": "@concat('Account:',trim(toLower(items('For_Each_Entity')?['properties']?['additionalData']?['UserPrincipalName'])))" + } + }, + "old_Condition_-_Account_-_Get_User_Details": { + "actions": { + "Append_to_array_forScp-UserForDetails": { + "type": "AppendToArrayVariable", + "inputs": { + "name": "forScp-UsersForDetails", + "value": "@items('For_Each_Entity')?['properties']?['additionalData']?['UserPrincipalName']" + } + } + }, + "runAfter": { + "Append_User_Upn_to_ProcessedItems": [ + "Succeeded" + ] + }, + "else": { + "actions": { + } + }, + "expression": { + "and": [ + { + "equals": [ + "@parameters('CallScpForAccounts')", + true + ] + } + ] + }, + "type": "If" + }, + "Condition_-_Account_-_Get_User_Risk": { + "actions": { + "Append_UPN_to_array_variable_forScp-UsersForRiskAnalysis": { + "type": "AppendToArrayVariable", + "inputs": { + "name": "forScp-UsersForRiskAnalysis", + "value": "@items('For_Each_Entity')?['properties']?['additionalData']?['UserPrincipalName']" + } + } + }, + "runAfter": { + "Append_User_Upn_to_ProcessedItems": [ + "Succeeded" + ] + }, + "else": { + "actions": { + } + }, + "expression": { + "and": [ + { + "equals": [ + "@parameters('CallScpForUserRisk')", + true + ] + } + ] + }, + "type": "If" + } + }, + "else": { + "actions": { + } + }, + "expression": { + "and": [ + { + "or": [ + { + "equals": [ + "@parameters('CallScpForAccounts')", + true + ] + }, + { + "equals": [ + "@parameters('CallScpForUserRisk')", + true + ] + } + ] + }, + { + "equals": [ + "@empty(items('For_Each_Entity')?['properties']?['accountName'])", + false + ] + }, + { + "equals": [ + "@empty(items('For_Each_Entity')?['properties']?['additionalData']?['UserPrincipalName'])", + false + ] + }, + { + "not": { + "contains": [ + "@parameters('SkipAccounts')", + "@toLower(items('For_Each_Entity')?['properties']?['accountName'])" + ] + } + }, + { + "not": { + "endsWith": [ + "@items('For_Each_Entity')?['properties']?['accountName']", + "$" + ] + } + } + ] + }, + "type": "If" + } + } + }, + "Case_-_Host": { + "case": "Host", + "actions": { + "Condition_-_Host": { + "actions": { + "Append_Device_to_ProcessedItems": { + "type": "AppendToArrayVariable", + "inputs": { + "name": "ProcessedItems", + "value": "@concat('Device:',trim(toLower(items('For_Each_Entity')?['properties']?['hostName'])))" + } + }, + "Append_to_array_forScp-Devices": { + "runAfter": { + "Append_Device_to_ProcessedItems": [ + "Succeeded" + ] + }, + "type": "AppendToArrayVariable", + "inputs": { + "name": "forScp-Devices", + "value": "@items('For_Each_Entity')?['properties']?['hostName']" + } + } + }, + "else": { + "actions": { + } + }, + "expression": { + "and": [ + { + "equals": [ + "@empty(items('For_Each_Entity')?['properties']?['hostName'])", + false + ] + }, + { + "equals": [ + "@parameters('CallScpForHosts')", + true + ] + }, + { + "not": { + "contains": [ + "@parameters('SkipHosts')", + "@toLower(items('For_Each_Entity')?['properties']?['hostName'])" + ] + } + } + ] + }, + "type": "If" + } + } + }, + "Case_-_Process": { + "case": "Process", + "actions": { + "Condition_-_Command_Line": { + "actions": { + "Set_variable_CommandLineNormalized": { + "type": "SetVariable", + "inputs": { + "name": "CommandLineNormalized", + "value": "@tolower(trim(replace(replace(items('For_Each_Entity')?['properties']?['commandLine'],' ',' '),'net1 ','net ')))" + } + }, + "Append_CommandLineNormalized_to_ProcessedItem": { + "runAfter": { + "Set_variable_CommandLineNormalized": [ + "Succeeded" + ] + }, + "type": "AppendToArrayVariable", + "inputs": { + "name": "ProcessedItems", + "value": "@concat('CommandLine:',variables('CommandLineNormalized'))" + } + }, + "Append_to_array_variable_forScp-CommandLines": { + "runAfter": { + "Append_CommandLineNormalized_to_ProcessedItem": [ + "Succeeded" + ] + }, + "type": "AppendToArrayVariable", + "inputs": { + "name": "forScp-CommandLines", + "value": "@variables('CommandLineNormalized')" + } + } + }, + "else": { + "actions": { + } + }, + "expression": { + "and": [ + { + "equals": [ + "@empty(items('For_Each_Entity')?['properties']?['commandLine'])", + false + ] + }, + { + "equals": [ + "@parameters('CallScpForCommandLines')", + true + ] + }, + { + "not": { + "contains": [ + "@parameters('SkipCommandLines')", + "@toLower(items('For_Each_Entity')?['properties']?['commandLine'])" + ] + } + } + ] + }, + "type": "If" + } + } + }, + "Case_-_FileHash": { + "case": "FileHash", + "actions": { + "Condition_-_FileHash": { + "actions": { + "Append_Filehash_to_array_variable_IndicatorsForMDTI": { + "runAfter": { + "Append_FileHash_to_ProcessedItems": [ + "Succeeded" + ] + }, + "type": "AppendToArrayVariable", + "inputs": { + "name": "forScp-Indicators", + "value": "@toLower(items('For_Each_Entity')?['properties']?['hashValue'])" + } + }, + "Append_FileHash_to_ProcessedItems": { + "type": "AppendToArrayVariable", + "inputs": { + "name": "ProcessedItems", + "value": "@concat('FileHash:',trim(toLower(items('For_Each_Entity')?['properties']?['hashValue'])))" + } + } + }, + "else": { + "actions": { + } + }, + "expression": { + "and": [ + { + "equals": [ + "@empty(items('For_Each_Entity')?['properties']?['hashValue'])", + false + ] + }, + { + "equals": [ + "@parameters('CallScpForFilehashesWithMDTI')", + true + ] + }, + { + "not": { + "contains": [ + "@parameters('SkipFilehashes')", + "" + ] + } + } + ] + }, + "type": "If" + } + } + }, + "Case_Url": { + "case": "Url", + "actions": { + "Condition_-_Url": { + "actions": { + "Append_Url_to_array_variable_IndicatorsForMDTI": { + "runAfter": { + "Append_URL_to_ProcessedItems": [ + "Succeeded" + ] + }, + "type": "AppendToArrayVariable", + "inputs": { + "name": "forScp-Indicators", + "value": "@toLower(split(items('For_Each_Entity')?['properties']?['url'],'?')[0])" + } + }, + "Append_URL_to_ProcessedItems": { + "type": "AppendToArrayVariable", + "inputs": { + "name": "ProcessedItems", + "value": "@concat('URL:',trim(toLower(split(items('For_Each_Entity')?['properties']?['url'],'?')[0])))" + } + } + }, + "else": { + "actions": { + } + }, + "expression": { + "and": [ + { + "equals": [ + "@empty(items('For_Each_Entity')?['properties']?['url'])", + false + ] + }, + { + "equals": [ + "@parameters('CallScpForUrlsWithMDTI')", + true + ] + }, + { + "not": { + "contains": [ + "@parameters('SkipUrls')", + "@toLower(items('For_Each_Entity')?['properties']?['url'])" + ] + } + } + ] + }, + "type": "If" + } + } + }, + "Case_DNS": { + "case": "DNS", + "actions": { + "Condition_-_DNS": { + "actions": { + "Append_Domain_to_array_variable_IndicatorsForMDTI": { + "runAfter": { + "Append_Domain_to_ProcessedItems": [ + "Succeeded" + ] + }, + "type": "AppendToArrayVariable", + "inputs": { + "name": "forScp-Indicators", + "value": "@toLower(items('For_Each_Entity')?['properties']?['domainName'])" + } + }, + "Append_Domain_to_ProcessedItems": { + "type": "AppendToArrayVariable", + "inputs": { + "name": "ProcessedItems", + "value": "@concat('Domain:',trim(toLower(items('For_Each_Entity')?['properties']?['domainName'])))" + } + } + }, + "else": { + "actions": { + } + }, + "expression": { + "and": [ + { + "equals": [ + "@empty(items('For_Each_Entity')?['properties']?['domainName'])", + false + ] + }, + { + "equals": [ + "@parameters('CallScpForDomainsWithMDTI')", + true + ] + }, + { + "not": { + "contains": [ + "@parameters('SkipDomains')", + "@toLower(items('For_Each_Entity')?['properties']?['domainName'])" + ] + } + } + ] + }, + "type": "If" + } + } + } + }, + "default": { + "actions": { + } + }, + "expression": "@items('For_Each_Entity')?['kind']", + "type": "Switch" + }, + "Show_item_for_debug_purposes": { + "type": "Compose", + "inputs": "@items('For_Each_Entity')" + } + }, + "type": "Foreach" + }, + "Condition_Call_for_IP_Addresses": { + "actions": { + "For_each_forScp-IPs": { + "foreach": "@variables('Unique-forScp-IPs')", + "actions": { + "Security_Copilot_prompt_for_IP": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['securitycopilot']['connectionId']" + } + }, + "method": "post", + "body": { + "PromptContent": "I'm curious about any abuseipdb records for the IP address @{items('For_each_forScp-IPs')}. Can you look that up for me for the last 30 days?" + }, + "path": "/process-prompt" + } + }, + "Condition_-_SCP_-_Call_for_IPs_with_AbuseIPBD_was_successful": { + "actions": { + "Set_variable_ResultsAvailable_-_IPs": { + "runAfter": { + "Append_to_Results-IPs_Success": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "ResultsAvailable", + "value": true + } + }, + "Append_to_Results-IPs_Success": { + "type": "AppendToArrayVariable", + "inputs": { + "name": "Results-IPs", + "value": "\nResults of the analysis for the IP '@{items('For_each_forScp-IPs')}':\n\n@{body('Security_Copilot_prompt_for_IP')?['EvaluationResultContent']}\n " + } + } + }, + "runAfter": { + "Security_Copilot_prompt_for_IP": [ + "Succeeded", + "TimedOut", + "Skipped", + "Failed" + ] + }, + "else": { + "actions": { + "Append_to_Results-IPs_Error": { + "type": "AppendToArrayVariable", + "inputs": { + "name": "Results-IPs", + "value": "\nResults of the analysis for the IP '@{items('For_each_forScp-IPs')}':\n\nError while retrieving the results: @{body('Security_Copilot_prompt_for_IP')?['EvaluationResultContent']}\n " + } + } + } + }, + "expression": { + "and": [ + { + "equals": [ + "@body('Security_Copilot_prompt_for_IP')?['evaluationResultType']", + "Success" + ] + } + ] + }, + "type": "If" + } + }, + "runAfter": { + "Show_Unique-forScp-IPs_for_debug_purposes": [ + "Succeeded" + ] + }, + "type": "Foreach" + }, + "Show_Unique-forScp-IPs_for_debug_purposes": { + "runAfter": { + "Set_variable_-_Unique-forScp-IPs": [ + "Succeeded" + ] + }, + "type": "Compose", + "inputs": "@variables('Unique-forScp-IPs')" + }, + "Set_variable_-_Unique-forScp-IPs": { + "type": "SetVariable", + "inputs": { + "name": "Unique-forScp-IPs", + "value": "@sort(union(variables('forScp-IPs'),variables('forScp-IPs')))" + } + } + }, + "runAfter": { + "For_Each_Entity": [ + "Succeeded" + ] + }, + "else": { + "actions": { + } + }, + "expression": { + "and": [ + { + "equals": [ + "@and(not(equals(variables('forScp-IPs'),null)), greater(length(variables('forScp-IPs')), 0))", + true + ] + } + ] + }, + "type": "If" + }, + "Condition_Call_SCP_for_Users_Details": { + "actions": { + "For_each_forScp-UsersForDetails": { + "foreach": "@variables('Unique-forScp-UsersForDetails')", + "actions": { + "Security_Copilot_prompt_for_Account_": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['securitycopilot']['connectionId']" + } + }, + "method": "post", + "body": { + "PromptContent": "Give me all usr details for @{items('For_each_forScp-UsersForDetails')}. Does have any registered devices in Microsoft Entra? List the recent risky sign-ins for @{items('For_each_forScp-UsersForDetails')}. Get Microsoft Entra audit logs for @{items('For_each_forScp-UsersForDetails')} for the past 72 hours.", + "SkillName": "GetEntraUserDetailsV1" + }, + "path": "/process-prompt" + } + }, + "Condition_-_SCP_-_Call_for_Account_on_Entra_was_successful": { + "actions": { + "Set_variable_-_ResultsAvailable_-_Accounts": { + "runAfter": { + "Append_to_Results-UsersDetails_-_Success": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "ResultsAvailable", + "value": true + } + }, + "Append_to_Results-UsersDetails_-_Success": { + "type": "AppendToArrayVariable", + "inputs": { + "name": "Results-UsersDetails", + "value": "\nResults of the analysis for the account '@{items('For_each_forScp-UsersForDetails')}':\n\n@{body('Security_Copilot_prompt_for_Account_')?['EvaluationResultContent']}\n " + } + } + }, + "runAfter": { + "Security_Copilot_prompt_for_Account_": [ + "Succeeded", + "TimedOut", + "Skipped", + "Failed" + ] + }, + "else": { + "actions": { + "Append_to_Results-UsersDetails_-_Error": { + "type": "AppendToArrayVariable", + "inputs": { + "name": "Results-UsersDetails", + "value": "\nResults of the analysis for the account '@{items('For_each_forScp-UsersForDetails')}':\n\nError while retrieving the results: @{body('Security_Copilot_prompt_for_Account_')?['EvaluationResultContent']}\n " + } + } + } + }, + "expression": { + "and": [ + { + "equals": [ + "@body('Security_Copilot_prompt_for_Account_')?['evaluationResultType']", + "Success" + ] + } + ] + }, + "type": "If" + } + }, + "runAfter": { + "Show_Unique-forScp-UsersForDetails_for_debug_purposes": [ + "Succeeded" + ] + }, + "type": "Foreach" + }, + "Show_Unique-forScp-UsersForDetails_for_debug_purposes": { + "runAfter": { + "Set_variable_-_Unique-forScp-UsersForDetails": [ + "Succeeded" + ] + }, + "type": "Compose", + "inputs": "@variables('Unique-forScp-UsersForDetails')" + }, + "Set_variable_-_Unique-forScp-UsersForDetails": { + "type": "SetVariable", + "inputs": { + "name": "Unique-forScp-UsersForDetails", + "value": "@sort(union(variables('forScp-UsersForDetails'),variables('forScp-UsersForDetails')))" + } + } + }, + "runAfter": { + "For_Each_Entity": [ + "Succeeded" + ] + }, + "else": { + "actions": { + } + }, + "expression": { + "and": [ + { + "equals": [ + "@and(not(equals(variables('forScp-UsersForDetails'),null)), greater(length(variables('forScp-UsersForDetails')), 0))", + true + ] + } + ] + }, + "type": "If" + }, + "Condition_Call_SCP_for_Users_Risk": { + "actions": { + "Security_Copilot_prompt_for_Users_Risk": { + "runAfter": { + "Show_Unique-forScp-UsersForRiskAnalysis_for_debug_purposes": [ + "Succeeded" + ] + }, + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['securitycopilot']['connectionId']" + } + }, + "method": "post", + "body": { + "PromptContent": "@join(variables('Unique-forScp-UsersForRiskAnalysis'),', ')", + "SkillName": "GetEntraRiskyUsers" + }, + "path": "/process-prompt" + } + }, + "Condition_-_Users_Risk_retrieved": { + "actions": { + "Compose_Users_Risk": { + "type": "Compose", + "inputs": "@body('Security_Copilot_prompt_for_Users_Risk')?['EvaluationResultContent']" + }, + "Set_variable_-_ResultsAvailable_-_Users_Risk": { + "runAfter": { + "Append_to_Results-UsersRisk_-_Success": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "ResultsAvailable", + "value": true + } + }, + "Append_to_Results-UsersRisk_-_Success": { + "runAfter": { + "Compose_Users_Risk": [ + "Succeeded" + ] + }, + "type": "AppendToArrayVariable", + "inputs": { + "name": "Results-UsersRisk", + "value": "@body('Security_Copilot_prompt_for_Users_Risk')?['EvaluationResultContent']" + } + } + }, + "runAfter": { + "Security_Copilot_prompt_for_Users_Risk": [ + "Succeeded", + "TimedOut", + "Skipped", + "Failed" + ] + }, + "else": { + "actions": { + "Append_to_Results-UsersRisk_-_Error": { + "type": "AppendToArrayVariable", + "inputs": { + "name": "Results-UsersRisk", + "value": "Error while retrieving the users risk: '@{body('Security_Copilot_prompt_for_Users_Risk')?['EvaluationResultContent']}'" + } + } + } + }, + "expression": { + "and": [ + { + "equals": [ + "@body('Security_Copilot_prompt_for_Users_Risk')?['evaluationResultType']", + "Success" + ] + } + ] + }, + "type": "If" + }, + "Show_Unique-forScp-UsersForRiskAnalysis_for_debug_purposes": { + "runAfter": { + "Set_variable_Unique-forScp-UsersForRiskAnalysis": [ + "Succeeded" + ] + }, + "type": "Compose", + "inputs": "@variables('Unique-forScp-UsersForRiskAnalysis')" + }, + "Set_variable_Unique-forScp-UsersForRiskAnalysis": { + "type": "SetVariable", + "inputs": { + "name": "Unique-forScp-UsersForRiskAnalysis", + "value": "@sort(union(variables('forScp-UsersForRiskAnalysis'),variables('forScp-UsersForRiskAnalysis')))" + } + } + }, + "runAfter": { + "For_Each_Entity": [ + "Succeeded" + ] + }, + "else": { + "actions": { + } + }, + "expression": { + "and": [ + { + "equals": [ + "@and(not(equals(variables('forScp-UsersForRiskAnalysis'),null)), greater(length(variables('forScp-UsersForRiskAnalysis')), 0))", + true + ] + } + ] + }, + "type": "If" + }, + "Condition_Call_SCP_for_Devices_Details": { + "actions": { + "For_each_forScp-Devices": { + "foreach": "@variables('Unique-forScp-Devices')", + "actions": { + "Security_Copilot_prompt_for_Device": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['securitycopilot']['connectionId']" + } + }, + "method": "post", + "body": { + "PromptContent": "Tell me about device @{items('For_each_forScp-Devices')}.", + "SkillName": "GetIntuneDevices" + }, + "path": "/process-prompt" + } + }, + "Condition_-_SCP_-_Call_for_devices_on_Intune_was_successful": { + "actions": { + "Set_variable_-_ResultsAvailable_-_Devices": { + "runAfter": { + "Append_to_Results-Devices-Success": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "ResultsAvailable", + "value": true + } + }, + "Append_to_Results-Devices-Success": { + "type": "AppendToArrayVariable", + "inputs": { + "name": "Results-Devices", + "value": "\nResults of the analysis for the device '@{items('For_each_forScp-Devices')}':\n\n@{body('Security_Copilot_prompt_for_Device')?['EvaluationResultContent']}\n" + } + } + }, + "runAfter": { + "Security_Copilot_prompt_for_Device": [ + "Succeeded", + "TimedOut", + "Skipped", + "Failed" + ] + }, + "else": { + "actions": { + "Append_to_results-Devices-Error": { + "type": "AppendToArrayVariable", + "inputs": { + "name": "Results-Devices", + "value": "\nResults of the analysis for the device '@{items('For_each_forScp-Devices')}': \n\nError while retrieving the results: '@{body('Security_Copilot_prompt_for_Device')?['EvaluationResultContent']}'\n" + } + } + } + }, + "expression": { + "and": [ + { + "equals": [ + "@body('Security_Copilot_prompt_for_Device')?['evaluationResultType']", + "Success" + ] + } + ] + }, + "type": "If" + } + }, + "runAfter": { + "Show_Unique-forScp-Devices_for_debug_purposes": [ + "Succeeded" + ] + }, + "type": "Foreach" + }, + "Show_Unique-forScp-Devices_for_debug_purposes": { + "runAfter": { + "Set_variable_Unique-forScp-Devices": [ + "Succeeded" + ] + }, + "type": "Compose", + "inputs": "@variables('Unique-forScp-Devices')" + }, + "Set_variable_Unique-forScp-Devices": { + "type": "SetVariable", + "inputs": { + "name": "Unique-forScp-Devices", + "value": "@sort(union(variables('forScp-Devices'),variables('forScp-Devices')))" + } + } + }, + "runAfter": { + "For_Each_Entity": [ + "Succeeded" + ] + }, + "else": { + "actions": { + } + }, + "expression": { + "and": [ + { + "equals": [ + "@and(not(equals(variables('forScp-Devices'),null)), greater(length(variables('forScp-Devices')), 0))", + true + ] + } + ] + }, + "type": "If" + }, + "Condition_Call_SCP_for_Command_Lines": { + "actions": { + "Security_Copilot_prompt_for_Unique_Processes": { + "runAfter": { + "Show_Unique-forScp-CommandLines_for_debug_purposes": [ + "Succeeded" + ] + }, + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['securitycopilot']['connectionId']" + } + }, + "method": "post", + "body": { + "PromptContent": "From the following list, extract the command lines and related descriptions containing commands that are most likely DIRECTLY CORRELATED to malicious activities. Remove all command lines containing only the names of well-known portable executable files that are part of the Windows or Linux operating system, where no additional parameters are specified. For example, remove 'notepad.exe' and 'cmd.exe' but keep 'notepad.exe -param1' or 'cmd.exe -paramX' or 'unknownfile.exe'. The list starts here:\n \n@{join(variables('Unique-forScp-CommandLines'),'\n')}", + "SkillName": "ScriptAnalyzer" + }, + "path": "/process-prompt" + } + }, + "Condition_-_SCP_-_Call_for_Processes_was_successful": { + "actions": { + "Compose_Process_Analysis": { + "type": "Compose", + "inputs": "@body('Security_Copilot_prompt_for_Unique_Processes')?['EvaluationResultContent']" + }, + "Set_variable_-_ResultsAvailable_-_Command_Lines": { + "runAfter": { + "Append_to_Results-CommandLines_-_Success": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "ResultsAvailable", + "value": true + } + }, + "Append_to_Results-CommandLines_-_Success": { + "runAfter": { + "Compose_Process_Analysis": [ + "Succeeded" + ] + }, + "type": "AppendToArrayVariable", + "inputs": { + "name": "Results-CommandLines", + "value": "@body('Security_Copilot_prompt_for_Unique_Processes')?['EvaluationResultContent']" + } + } + }, + "runAfter": { + "Security_Copilot_prompt_for_Unique_Processes": [ + "Succeeded", + "TimedOut", + "Skipped", + "Failed" + ] + }, + "else": { + "actions": { + "Append_to_Results-CommandLines_-_Error": { + "type": "AppendToArrayVariable", + "inputs": { + "name": "Results-CommandLines", + "value": "Error while analyzing the command lines: '@{body('Security_Copilot_prompt_for_Unique_Processes')?['EvaluationResultContent']}'" + } + } + } + }, + "expression": { + "and": [ + { + "equals": [ + "@body('Security_Copilot_prompt_for_Unique_Processes')?['evaluationResultType']", + "Success" + ] + } + ] + }, + "type": "If" + }, + "Show_Unique-forScp-CommandLines_for_debug_purposes": { + "runAfter": { + "Set_variable_Unique-forScp-CommandLines": [ + "Succeeded" + ] + }, + "type": "Compose", + "inputs": "@variables('Unique-forScp-CommandLines')" + }, + "Set_variable_Unique-forScp-CommandLines": { + "type": "SetVariable", + "inputs": { + "name": "Unique-forScp-CommandLines", + "value": "@sort(union(variables('forScp-CommandLines'),variables('forScp-CommandLines')))" + } + } + }, + "runAfter": { + "For_Each_Entity": [ + "Succeeded" + ] + }, + "else": { + "actions": { + } + }, + "expression": { + "and": [ + { + "equals": [ + "@and(not(equals(variables('forScp-CommandLines'), null)), greater(length(variables('forScp-CommandLines')), 0))", + true + ] + } + ] + }, + "type": "If" + }, + "Condition_Call_SCP_for_MDTI_indicators": { + "actions": { + "Until": { + "actions": { + "Set_variable_SubarrayIndicatorsForMDTI": { + "type": "SetVariable", + "inputs": { + "name": "SubarrayIndicatorsForMDTI", + "value": "@take(skip(variables('Unique-forScp-Indicators'),variables('CounterIndicatorsForMDTI')),10)" + } + }, + "Set_variable_CsvIndicatorsForMDTI": { + "runAfter": { + "Set_variable_SubarrayIndicatorsForMDTI": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "CsvIndicatorsForMDTI", + "value": "@join(variables('SubarrayIndicatorsForMDTI'),', ')" + } + }, + "Security_Copilot_prompt_for_IoC_to_MDTI": { + "runAfter": { + "Set_variable_CsvIndicatorsForMDTI": [ + "Succeeded" + ] + }, + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['securitycopilot']['connectionId']" + } + }, + "method": "post", + "body": { + "PromptContent": "By looking at MDTI, tell me the reputation of these indicators: @{variables('CsvIndicatorsForMDTI')} ", + "SkillName": "GetReputationsForIndicators" + }, + "path": "/process-prompt" + } + }, + "Compose_New_Counter_Value": { + "runAfter": { + "Condition_-_SCP_-_Call_for_indicators_was_successful": [ + "Succeeded" + ] + }, + "type": "Compose", + "inputs": "@add(variables('CounterIndicatorsForMDTI'),10)" + }, + "Set_variable_Counter": { + "runAfter": { + "Compose_New_Counter_Value": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "CounterIndicatorsForMDTI", + "value": "@outputs('Compose_New_Counter_Value')" + } + }, + "Condition_-_SCP_-_Call_for_indicators_was_successful": { + "actions": { + "Compose_IoC_from_MDTI": { + "type": "Compose", + "inputs": "@body('Security_Copilot_prompt_for_IoC_to_MDTI')?['EvaluationResultContent']" + }, + "Append_to_array_variable_ResponsesFromMDTI_-_Success": { + "runAfter": { + "Compose_IoC_from_MDTI": [ + "Succeeded" + ] + }, + "type": "AppendToArrayVariable", + "inputs": { + "name": "ResponsesFromMDTI", + "value": "@body('Security_Copilot_prompt_for_IoC_to_MDTI')?['EvaluationResultContent']" + } + } + }, + "runAfter": { + "Security_Copilot_prompt_for_IoC_to_MDTI": [ + "Succeeded", + "TimedOut", + "Skipped", + "Failed" + ] + }, + "else": { + "actions": { + "Append_to_array_variable_ResponsesFromMDTI_-_Error": { + "type": "AppendToArrayVariable", + "inputs": { + "name": "ResponsesFromMDTI", + "value": "Error during the iteration @{add(div(variables('CounterIndicatorsForMDTI'),10),1)} wirh MDTI: '@{body('Security_Copilot_prompt_for_IoC_to_MDTI')?['EvaluationResultContent']}'" + } + } + } + }, + "expression": { + "and": [ + { + "equals": [ + "@body('Security_Copilot_prompt_for_IoC_to_MDTI')?['evaluationResultType']", + "Success" + ] + } + ] + }, + "type": "If" + } + }, + "runAfter": { + "Show_Unique-forScp-Indicators_for_debug_purposes": [ + "Succeeded" + ] + }, + "expression": "@equals(greaterOrEquals(length(variables('Unique-forScp-Indicators')),variables('CounterIndicatorsForMDTI')),false)", + "limit": { + "count": 60, + "timeout": "PT1H" + }, + "type": "Until" + }, + "Set_variable_OutputLength_-_MDTI_Output": { + "runAfter": { + "Set_variable_original_Response-MDTI": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "OutputLengthMDTI", + "value": "@length(variables('Response-MDTI'))" + } + }, + "Condition_-_MDTI_Output_Length": { + "actions": { + "Submit_a_Security_Copilot_prompt_-_Summarize_MDTI_response": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['securitycopilot']['connectionId']" + } + }, + "method": "post", + "body": { + "PromptContent": "From the following detailed list containing the results of the analysis of Indicators of Compromise (IoC) made by MDTI, extract suspicious and malicious indicators with the all the related details on reputation and explanations. Do not return unknown indicators. The list starts here: @{variables('Response-MDTI')}\n", + "SkillName": "SummarizeData" + }, + "path": "/process-prompt" + } + }, + "Condition_-_SCP_-_Call_for_indicator_summarization_was_successful": { + "actions": { + "Set_variable_summarized_Response-MDTI_-_Success": { + "type": "SetVariable", + "inputs": { + "name": "Response-MDTI", + "value": "@body('Submit_a_Security_Copilot_prompt_-_Summarize_MDTI_response')?['EvaluationResultContent']" + } + } + }, + "runAfter": { + "Submit_a_Security_Copilot_prompt_-_Summarize_MDTI_response": [ + "Succeeded", + "TimedOut", + "Skipped", + "Failed" + ] + }, + "else": { + "actions": { + "Set_variable_summarized_Response-MDTI_-_Error": { + "type": "SetVariable", + "inputs": { + "name": "Response-MDTI", + "value": "Error while summarizing the results retrieved from MDTI: '@{body('Submit_a_Security_Copilot_prompt_-_Summarize_MDTI_response')?['EvaluationResultContent']}'" + } + } + } + }, + "expression": { + "and": [ + { + "equals": [ + "", + "" + ] + } + ] + }, + "type": "If" + } + }, + "runAfter": { + "Condition_-_MDTI_Results_available": [ + "Succeeded" + ] + }, + "else": { + "actions": { + } + }, + "expression": { + "and": [ + { + "greater": [ + "@variables('OutputLengthMDTI')", + "@parameters('MaxMdtiOutputLenghtForPreSummarization')" + ] + } + ] + }, + "type": "If" + }, + "Set_variable_original_Response-MDTI": { + "runAfter": { + "Until": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "Response-MDTI", + "value": "@join(variables('ResponsesFromMDTI'),' \n\n\n')" + } + }, + "Show_Unique-forScp-Indicators_for_debug_purposes": { + "runAfter": { + "Set_variable_Unique-forScp-Indicators": [ + "Succeeded" + ] + }, + "type": "Compose", + "inputs": "@variables('Unique-forScp-Indicators')" + }, + "Set_variable_Unique-forScp-Indicators": { + "type": "SetVariable", + "inputs": { + "name": "Unique-forScp-Indicators", + "value": "@sort(union(variables('forScp-Indicators'),variables('forScp-Indicators')))" + } + }, + "Condition_-_MDTI_Results_available": { + "actions": { + "Set_variable_-_ResultsAvailable_-_MDTI": { + "type": "SetVariable", + "inputs": { + "name": "ResultsAvailable", + "value": true + } + } + }, + "runAfter": { + "Set_variable_OutputLength_-_MDTI_Output": [ + "Succeeded" + ] + }, + "else": { + "actions": { + } + }, + "expression": { + "and": [ + { + "greater": [ + "@variables('OutputLengthMDTI')", + 0 + ] + } + ] + }, + "type": "If" + } + }, + "runAfter": { + "For_Each_Entity": [ + "Succeeded" + ] + }, + "else": { + "actions": { + } + }, + "expression": { + "or": [ + { + "equals": [ + "@and(not(equals(variables('forScp-Indicators'),null)), greater(length(variables('forScp-Indicators')), 0))", + true + ] + } + ] + }, + "type": "If" + } + }, + "runAfter": { + "Condition_-_Validate_Parameters": [ + "Succeeded" + ] + }, + "else": { + "actions": { + "No_Entities_Found_-_Cancel_Execution": { + "type": "Terminate", + "inputs": { + "runStatus": "Cancelled" + } + } + } + }, + "expression": { + "and": [ + { + "greater": [ + "@length(outputs('Compose_Incident_Entities'))", + 0 + ] + } + ] + }, + "type": "If" + }, + "Initialize_variable_CommandLineNormalized": { + "runAfter": { + "Compose_Incident_Entities": [ + "Succeeded" + ] + }, + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "CommandLineNormalized", + "type": "string" + } + ] + } + }, + "Initialize_variable_forScp-CommandLines": { + "runAfter": { + "Initialize_variable_ProcessedCommandLines": [ + "Succeeded" + ] + }, + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "forScp-CommandLines", + "type": "array" + } + ] + } + }, + "Initialize_variable_ProcessedCommandLines": { + "runAfter": { + "Initialize_variable_CommandLineNormalized": [ + "Succeeded" + ] + }, + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "ProcessedCommandLines", + "type": "array" + } + ] + } + }, + "Initialize_variable_forScp-Indicators": { + "runAfter": { + "Initialize_variable_Results-CommandLines": [ + "Succeeded" + ] + }, + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "forScp-Indicators", + "type": "array" + } + ] + } + }, + "Initialize_variable_CounterIndicatorsForMDTI": { + "runAfter": { + "Initialize_variable_Unique-forScp-Indicators": [ + "Succeeded" + ] + }, + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "CounterIndicatorsForMDTI", + "type": "integer", + "value": 0 + } + ] + } + }, + "Initialize_variable_SubarrayIndicatorsForMDTI": { + "runAfter": { + "Initialize_variable_CounterIndicatorsForMDTI": [ + "Succeeded" + ] + }, + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "SubarrayIndicatorsForMDTI", + "type": "array" + } + ] + } + }, + "Initialize_variable_CsvIndicatorsForMDTI": { + "runAfter": { + "Initialize_variable_SubarrayIndicatorsForMDTI": [ + "Succeeded" + ] + }, + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "CsvIndicatorsForMDTI", + "type": "string" + } + ] + } + }, + "Initialize_variable_ResponsesFromMDTI": { + "runAfter": { + "Initialize_variable_CsvIndicatorsForMDTI": [ + "Succeeded" + ] + }, + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "ResponsesFromMDTI", + "type": "array" + } + ] + } + }, + "Initialize_variable_OutputLength": { + "runAfter": { + "Initialize_variable_Results-IPs": [ + "Succeeded" + ] + }, + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "OutputLengthMDTI", + "type": "integer" + } + ] + } + }, + "Initialize_variable_Response-MDTI": { + "runAfter": { + "Initialize_variable_ResponsesFromMDTI": [ + "Succeeded" + ] + }, + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "Response-MDTI", + "type": "string" + } + ] + } + }, + "Initialize_variable_forScp-UsersForRiskAnalysis": { + "runAfter": { + "Initialize_variable_Results-UsersDetails": [ + "Succeeded" + ] + }, + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "forScp-UsersForRiskAnalysis", + "type": "array" + } + ] + } + }, + "Initialize_variable_ProcessedItems": { + "runAfter": { + "Initialize_variable_OutputLength": [ + "Succeeded" + ] + }, + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "ProcessedItems", + "type": "array" + } + ] + } + }, + "Initialize_variable_forScp-UsersForDetails": { + "runAfter": { + "Initialize_variable_Response-MDTI": [ + "Succeeded" + ] + }, + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "forScp-UsersForDetails", + "type": "array" + } + ] + } + }, + "Initialize_variable_forScp-Devices": { + "runAfter": { + "Initialize_variable_Results-UsersRisk": [ + "Succeeded" + ] + }, + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "forScp-Devices", + "type": "array" + } + ] + } + }, + "Initialize_variable_forScp-IPs": { + "runAfter": { + "Initialize_variable_Unique-forScp-Devices": [ + "Succeeded" + ] + }, + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "forScp-IPs", + "type": "array" + } + ] + } + }, + "Initialize_variable_Unique-forScp-CommandLines": { + "runAfter": { + "Initialize_variable_forScp-CommandLines": [ + "Succeeded" + ] + }, + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "Unique-forScp-CommandLines", + "type": "array", + "value": [ + ] + } + ] + } + }, + "Initialize_variable_Unique-forScp-Indicators": { + "runAfter": { + "Initialize_variable_forScp-Indicators": [ + "Succeeded" + ] + }, + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "Unique-forScp-Indicators", + "type": "array", + "value": [ + ] + } + ] + } + }, + "Initialize_variable_Unique-forScp-UsersForDetails": { + "runAfter": { + "Initialize_variable_forScp-UsersForDetails": [ + "Succeeded" + ] + }, + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "Unique-forScp-UsersForDetails", + "type": "array", + "value": [ + ] + } + ] + } + }, + "Initialize_variable_Unique-forScp-UsersForRiskAnalysis": { + "runAfter": { + "Initialize_variable_forScp-UsersForRiskAnalysis": [ + "Succeeded" + ] + }, + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "Unique-forScp-UsersForRiskAnalysis", + "type": "array", + "value": [ + ] + } + ] + } + }, + "Initialize_variable_Unique-forScp-Devices": { + "runAfter": { + "Initialize_variable_Results-Devices": [ + "Succeeded" + ] + }, + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "Unique-forScp-Devices", + "type": "array", + "value": [ + ] + } + ] + } + }, + "Initialize_variable_Unique-forScp-IPs": { + "runAfter": { + "Initialize_variable_forScp-IPs": [ + "Succeeded" + ] + }, + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "Unique-forScp-IPs", + "type": "array", + "value": [ + ] + } + ] + } + }, + "Initialize_variable_ResultsAvailable": { + "runAfter": { + "Initialize_variable_ProcessedItems": [ + "Succeeded" + ] + }, + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "ResultsAvailable", + "type": "boolean", + "value": false + } + ] + } + }, + "Condition_-_Results_Available": { + "actions": { + "Compose_-_Incident_Data": { + "type": "Compose", + "inputs": "Incident Ttile: \n@{triggerBody()?['object']?['properties']?['title']},\n\nIncident Description: \n@{triggerBody()?['object']?['properties']?['description']},\n\nIncident Severity: \n@{triggerBody()?['object']?['properties']?['severity']},\n\nIncident Tactics: \n@{triggerBody()?['object']?['properties']?['additionalData']?['tactics']},\n\n______________________________________\nIp Addresses Analysis: \n@{if(parameters('CallScpForIPsWithAbuseIPDB'),variables('Results-IPs'),'skipped...')},\n\n______________________________________\nAccounts Analysis: \n@{if(parameters('CallScpForAccounts'),variables('Results-UsersDetails'),'skipped...')},\n\n______________________________________\nUsers Risk Analysis: \n@{if(parameters('CallScpForUserRisk'),outputs('Compose_Users_Risk'),'skipped...')},\n\n______________________________________\nDevices Analysis: \n@{if(parameters('CallScpForHosts'),variables('Results-Devices'),'skipped...')},\n\n______________________________________\nProcesses Analysis: \n@{if(parameters('CallScpForCommandLines'),outputs('Compose_Process_Analysis'),'skipped...')}\n\n______________________________________\nIndicators Analysis from MDTI: \n@{if(or(parameters('CallScpForIPsWithMDTI'),parameters('CallScpForFilehashesWithMDTI'),parameters('CallScpForUrlsWithMDTI'),parameters('CallScpForDomainsWithMDTI')),variables('Response-MDTI'),'skipped...')}" + }, + "Compose_-_Normalized_Incident_Data": { + "runAfter": { + "Compose_-_Incident_Data": [ + "Succeeded" + ] + }, + "type": "Compose", + "inputs": "@replace(replace(outputs('Compose_-_Incident_Data'),',null',''),'[null,','')" + }, + "Condition_-_Send_unsummarized_results_by_email": { + "actions": { + "Send_an_email_(V2)_-_Enrichment_Details": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['office365']['connectionId']" + } + }, + "method": "post", + "body": { + "To": "@trim(parameters('RecipientEmail'))", + "Subject": "Incident @{triggerBody()?['object']?['properties']?['providerIncidentId']} - Enrichment Details", + "Body": "\u003cp class=\"editor-paragraph\"\u003e\u003cb\u003e\u003cstrong class=\"editor-text-bold\"\u003e--- Incident Analysis - Details---\u003c/strong\u003e\u003c/b\u003e\u003c/p\u003e\u003cp class=\"editor-paragraph\"\u003eIncident URL: @{concat('https://security.microsoft.com/incident2/',triggerBody()?['object']?['properties']?['providerIncidentId'],'/overview')}\u003c/p\u003e\u003cbr\u003e\u003cp class=\"editor-paragraph\"\u003e@{outputs('Compose_-_Details_-_Replace_NewLine_char')}\u003c/p\u003e", + "Importance": "Normal" + }, + "path": "/v2/Mail" + } + } + }, + "runAfter": { + "Compose_-_Details_-_Replace_NewLine_char": [ + "Succeeded" + ] + }, + "else": { + "actions": { + } + }, + "expression": { + "and": [ + { + "contains": [ + "@parameters('RecipientEmail')", + "@" + ] + } + ] + }, + "type": "If" + }, + "Condition_-_Write_unsummarized_results_on_incident": { + "actions": { + "Add_unsummarized_results_to_incident": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "post", + "body": { + "incidentArmId": "@triggerBody()?['object']?['id']", + "message": "\u003cp class=\"editor-paragraph\"\u003e\u003cb\u003e\u003cstrong class=\"editor-text-bold\"\u003e--- Incident Analysis - Details---\u003c/strong\u003e\u003c/b\u003e\u003c/p\u003e\u003cbr\u003e\u003cp class=\"editor-paragraph\"\u003e@{outputs('Compose_-_Details_-_Replace_NewLine_char')}\u003c/p\u003e\u003cbr\u003e" + }, + "path": "/Incidents/Comment" + } + } + }, + "runAfter": { + "Compose_-_Details_-_Replace_NewLine_char": [ + "Succeeded" + ] + }, + "else": { + "actions": { + } + }, + "expression": { + "and": [ + { + "equals": [ + "@parameters('WriteUnsummarizedResultsToIncident')", + true + ] + } + ] + }, + "type": "If" + }, + "Security_Copilot_summarize_incident_investigation": { + "runAfter": { + "Condition_-_Send_unsummarized_results_by_email": [ + "Succeeded", + "TimedOut", + "Skipped", + "Failed" + ], + "Condition_-_Write_unsummarized_results_on_incident": [ + "Succeeded", + "TimedOut", + "Skipped", + "Failed" + ] + }, + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['securitycopilot']['connectionId']" + } + }, + "method": "post", + "body": { + "PromptContent": "Here is the security incident detail: @{outputs('Compose_-_Normalized_Incident_Data')}\n\nPerform investigation on security incident in following order. Incident Overview, Incident Description, Ip Addresses Analysis , Account Analysis, Users Risk Analysis, Devices Analysis, Processes Analysis, Indicators Analysis from MDTI, Possible mitigation steps and Conclusion. Ignore all error messages", + "SkillName": "SummarizeData" + }, + "path": "/process-prompt" + } + }, + "Condition_-_SCP_-_Final_prompt_was_successful": { + "actions": { + "Compose_-_Incident_Investigation": { + "type": "Compose", + "inputs": "@body('Security_Copilot_summarize_incident_investigation')?['EvaluationResultContent']" + }, + "Condition_-_Write_final_summary_to_incident_-_Success": { + "actions": { + "Add_Investigation_Final_summary_to_Incident": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "post", + "body": { + "incidentArmId": "@triggerBody()?['object']?['id']", + "message": "\u003cp class=\"editor-paragraph\"\u003e\u003cb\u003e\u003cstrong class=\"editor-text-bold\"\u003e--- Incident Analysis - Summary ---\u003c/strong\u003e\u003c/b\u003e\u003c/p\u003e\u003cp class=\"editor-paragraph\"\u003e\u003cbr\u003e@{outputs('Compose_-_Incident_Investigation')}\u003c/p\u003e\u003cbr\u003e" + }, + "path": "/Incidents/Comment" + } + } + }, + "runAfter": { + "Compose_-_Incident_Investigation": [ + "Succeeded" + ] + }, + "else": { + "actions": { + } + }, + "expression": { + "and": [ + { + "equals": [ + "@parameters('WriteFinalSummaryToIncident')", + true + ] + } + ] + }, + "type": "If" + }, + "Condition_-_RecipientEmail_-_Final_-_Success": { + "actions": { + "Send_an_email_(V2)_-_Enrichment_Summary_-_Success": { + "runAfter": { + "Compose_-_Summary_-_Success_-_Replace_NewLine_char": [ + "Succeeded" + ] + }, + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['office365']['connectionId']" + } + }, + "method": "post", + "body": { + "To": "@trim(parameters('RecipientEmail'))", + "Subject": "Incident @{triggerBody()?['object']?['properties']?['providerIncidentId']} - Enrichment Summary", + "Body": "\u003cp class=\"editor-paragraph\"\u003e\u003cb\u003e\u003cstrong class=\"editor-text-bold\"\u003e--- Incident Analysis - Summary ---\u003c/strong\u003e\u003c/b\u003e\u003cbr\u003eIncident URL: @{concat('https://security.microsoft.com/incident2/',triggerBody()?['object']?['properties']?['providerIncidentId'],'/overview')}\u003c/p\u003e\u003cbr\u003e\u003cp class=\"editor-paragraph\"\u003e@{outputs('Compose_-_Summary_-_Success_-_Replace_NewLine_char')}\u003c/p\u003e", + "Importance": "Normal" + }, + "path": "/v2/Mail" + } + }, + "Compose_-_Summary_-_Success_-_Replace_NewLine_char": { + "type": "Compose", + "inputs": "@replace(replace(outputs('Compose_-_Incident_Investigation'),'\\n','\u003cbr\u003e'),'\n','\u003cbr\u003e')" + } + }, + "runAfter": { + "Compose_-_Incident_Investigation": [ + "Succeeded" + ] + }, + "else": { + "actions": { + } + }, + "expression": { + "and": [ + { + "contains": [ + "@parameters('RecipientEmail')", + "@" + ] + } + ] + }, + "type": "If" + }, + "Terminate_-_Success": { + "runAfter": { + "Condition_-_Write_final_summary_to_incident_-_Success": [ + "Succeeded" + ], + "Condition_-_RecipientEmail_-_Final_-_Success": [ + "Succeeded" + ] + }, + "type": "Terminate", + "inputs": { + "runStatus": "Succeeded" + } + } + }, + "runAfter": { + "Security_Copilot_summarize_incident_investigation": [ + "Succeeded", + "TimedOut", + "Skipped", + "Failed" + ] + }, + "else": { + "actions": { + "Condition_-_Unsummarized_results_not_already_written_to_incident": { + "actions": { + "Add_Investigation_Final_comment_to_Incident": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "post", + "body": { + "incidentArmId": "@triggerBody()?['object']?['id']", + "message": "\u003cp class=\"editor-paragraph\"\u003e\u003cb\u003e\u003cstrong class=\"editor-text-bold\"\u003e--- Incident Analysis - Evidences ---\u003c/strong\u003e\u003c/b\u003e\u003c/p\u003e\u003cp class=\"editor-paragraph\"\u003e\u003ci\u003e\u003cem class=\"editor-text-italic\"\u003e(Content not summarized)\u003c/em\u003e\u003c/i\u003e\u003c/p\u003e\u003cbr\u003e\u003cp class=\"editor-paragraph\"\u003e@{outputs('Compose_-_Details_-_Replace_NewLine_char')}\u003c/p\u003e" + }, + "path": "/Incidents/Comment" + } + } + }, + "else": { + "actions": { + } + }, + "expression": { + "and": [ + { + "equals": [ + "@parameters('WriteUnsummarizedResultsToIncident')", + false + ] + }, + { + "equals": [ + "@parameters('WriteFinalSummaryToIncident')", + true + ] + } + ] + }, + "type": "If" + }, + "Terminate_-_Failed": { + "runAfter": { + "Condition_-_Unsummarized_results_not_already_written_to_incident": [ + "Succeeded" + ], + "Condition_-_Unsummarized_results_not_already_sent_by_email": [ + "Succeeded" + ] + }, + "type": "Terminate", + "inputs": { + "runStatus": "Failed", + "runError": { + "message": "Final summarization failed" + } + } + }, + "Condition_-_Unsummarized_results_not_already_sent_by_email": { + "actions": { + "Send_an_email_(V2)_-_Enrichment_Summary_-_Failure": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['office365']['connectionId']" + } + }, + "method": "post", + "body": { + "To": "@trim(parameters('RecipientEmail'))", + "Subject": "Incident @{triggerBody()?['object']?['properties']?['providerIncidentId']} - Enrichment Summary - Failure", + "Body": "\u003cp class=\"editor-paragraph\"\u003e\u003cb\u003e\u003cstrong class=\"editor-text-bold\"\u003e--- Incident Analysis - Evidences ---\u003c/strong\u003e\u003c/b\u003e\u003cbr\u003e\u003ci\u003e\u003cem class=\"editor-text-italic\"\u003e(Content not summarized)\u003c/em\u003e\u003c/i\u003e\u003cbr\u003e\u003cbr\u003e@{outputs('Compose_-_Details_-_Replace_NewLine_char')}\u003c/p\u003e", + "Importance": "Normal" + }, + "path": "/v2/Mail" + } + } + }, + "else": { + "actions": { + } + }, + "expression": { + "and": [ + { + "equals": [ + "@parameters('SendUnsummarizedResultsByEmail')", + false + ] + }, + { + "equals": [ + "@parameters('SendFinalSummaryByEmail')", + true + ] + } + ] + }, + "type": "If" + } + } + }, + "expression": { + "and": [ + { + "equals": [ + "@body('Security_Copilot_summarize_incident_investigation')?['evaluationResultType']", + "Success" + ] + } + ] + }, + "type": "If" + }, + "Compose_-_Details_-_Replace_NewLine_char": { + "runAfter": { + "Compose_-_Normalized_Incident_Data": [ + "Succeeded" + ] + }, + "type": "Compose", + "inputs": "@replace(replace(outputs('Compose_-_Normalized_Incident_Data'),'\\n','\u003cbr\u003e'),'\n','\u003cbr\u003e')" + } + }, + "runAfter": { + "Condition_-_Validate_Entities": [ + "Succeeded" + ] + }, + "else": { + "actions": { + "No_results_available": { + "type": "Terminate", + "inputs": { + "runStatus": "Cancelled" + } + } + } + }, + "expression": { + "and": [ + { + "equals": [ + "@variables('ResultsAvailable')", + true + ] + } + ] + }, + "type": "If" + }, + "Condition_-_Validate_Parameters": { + "actions": { + }, + "runAfter": { + "Initialize_variable_ResultsAvailable": [ + "Succeeded" + ] + }, + "else": { + "actions": { + "Invalid_Parameters": { + "type": "Terminate", + "inputs": { + "runStatus": "Cancelled" + } + } + } + }, + "expression": { + "and": [ + { + "contains": [ + "@parameters('RecipientEmail')", + "@" + ] + }, + { + "or": [ + { + "equals": [ + "@parameters('SendUnsummarizedResultsByEmail')", + true + ] + }, + { + "equals": [ + "@parameters('SendFinalSummaryByEmail')", + true + ] + } + ] + } + ] + }, + "type": "If" + }, + "Initialize_variable_Results-Devices": { + "runAfter": { + "Initialize_variable_forScp-Devices": [ + "Succeeded" + ] + }, + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "Results-Devices", + "type": "array", + "value": [ + ] + } + ] + } + }, + "Initialize_variable_Results-IPs": { + "runAfter": { + "Initialize_variable_Unique-forScp-IPs": [ + "Succeeded" + ] + }, + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "Results-IPs", + "type": "array", + "value": [ + ] + } + ] + } + }, + "Initialize_variable_Results-UsersDetails": { + "runAfter": { + "Initialize_variable_Unique-forScp-UsersForDetails": [ + "Succeeded" + ] + }, + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "Results-UsersDetails", + "type": "array", + "value": [ + ] + } + ] + } + }, + "Initialize_variable_Results-UsersRisk": { + "runAfter": { + "Initialize_variable_Unique-forScp-UsersForRiskAnalysis": [ + "Succeeded" + ] + }, + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "Results-UsersRisk", + "type": "array", + "value": [ + ] + } + ] + } + }, + "Initialize_variable_Results-CommandLines": { + "runAfter": { + "Initialize_variable_Unique-forScp-CommandLines": [ + "Succeeded" + ] + }, + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "Results-CommandLines", + "type": "array", + "value": [ + ] + } + ] + } + } + }, + "outputs": { + } + }, + "parameters": { + "$connections": { + "value": { + "azuresentinel": { + "connectionId": "[resourceId('Microsoft.Web/connections', variables('MicrosoftSentinelConnectionName'))]", + "connectionName": "[variables('MicrosoftSentinelConnectionName')]", + "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/Azuresentinel')]", + "connectionProperties": { + "authentication": { + "type": "ManagedServiceIdentity" + } + } + }, + "securitycopilot": { + "connectionId": "[resourceId('Microsoft.Web/connections', variables('SecuritycopilotConnectionName'))]", + "connectionName": "[variables('SecuritycopilotConnectionName')]", + "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/Securitycopilot')]" + }, + "office365": { + "connectionId": "[resourceId('Microsoft.Web/connections', variables('Office365ConnectionName'))]", + "connectionName": "[variables('Office365ConnectionName')]", + "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/Office365')]" + } + } + } + } + }, + "name": "[parameters('PlaybookName')]", + "type": "Microsoft.Logic/workflows", + "location": "[resourceGroup().location]", + "tags": { + "hidden-SentinelTemplateName": "SecurityCopilot-Sentinel-Incident-Investigation", + "hidden-SentinelTemplateVersion": "1.0" + }, + "identity": { + "type": "SystemAssigned" + }, + "apiVersion": "2017-07-01", + "dependsOn": [ + "[resourceId('Microsoft.Web/connections', variables('MicrosoftSentinelConnectionName'))]", + "[resourceId('Microsoft.Web/connections', variables('SecuritycopilotConnectionName'))]", + "[resourceId('Microsoft.Web/connections', variables('Office365ConnectionName'))]" + ] + }, + { + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[variables('MicrosoftSentinelConnectionName')]", + "location": "[resourceGroup().location]", + "kind": "V1", + "properties": { + "displayName": "[variables('MicrosoftSentinelConnectionName')]", + "customParameterValues": { + }, + "parameterValueType": "Alternative", + "api": { + "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/Azuresentinel')]" + } + } + }, + { + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[variables('SecuritycopilotConnectionName')]", + "location": "[resourceGroup().location]", + "kind": "V1", + "properties": { + "displayName": "[variables('SecuritycopilotConnectionName')]", + "customParameterValues": { + }, + "api": { + "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/Securitycopilot')]" + } + } + }, + { + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[variables('Office365ConnectionName')]", + "location": "[resourceGroup().location]", + "kind": "V1", + "properties": { + "displayName": "[variables('Office365ConnectionName')]", + "customParameterValues": { + }, + "api": { + "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/Office365')]" + } + } + } + ] +} diff --git a/Logic Apps/SecurityCopilot-Sentinel-Incident-Investigation/images/copilot-for-security-authentication.png b/Logic Apps/SecurityCopilot-Sentinel-Incident-Investigation/images/copilot-for-security-authentication.png new file mode 100644 index 00000000..a93e6f4f Binary files /dev/null and b/Logic Apps/SecurityCopilot-Sentinel-Incident-Investigation/images/copilot-for-security-authentication.png differ diff --git a/Logic Apps/SecurityCopilot-Sentinel-Incident-Investigation/images/copilot-for-security-investigation-prompt.png b/Logic Apps/SecurityCopilot-Sentinel-Incident-Investigation/images/copilot-for-security-investigation-prompt.png new file mode 100644 index 00000000..797871ac Binary files /dev/null and b/Logic Apps/SecurityCopilot-Sentinel-Incident-Investigation/images/copilot-for-security-investigation-prompt.png differ diff --git a/Logic Apps/SecurityCopilot-Sentinel-Incident-Investigation/images/params.png b/Logic Apps/SecurityCopilot-Sentinel-Incident-Investigation/images/params.png new file mode 100644 index 00000000..e97f11ba Binary files /dev/null and b/Logic Apps/SecurityCopilot-Sentinel-Incident-Investigation/images/params.png differ diff --git a/Logic Apps/SecurityCopilot-Sentinel-Incident-Investigation/images/sentinel-trigger-authentication.png b/Logic Apps/SecurityCopilot-Sentinel-Incident-Investigation/images/sentinel-trigger-authentication.png new file mode 100644 index 00000000..5301b4a9 Binary files /dev/null and b/Logic Apps/SecurityCopilot-Sentinel-Incident-Investigation/images/sentinel-trigger-authentication.png differ diff --git a/Logic Apps/SecurityCopilot-Sentinel-Incident-Investigation/readme.md b/Logic Apps/SecurityCopilot-Sentinel-Incident-Investigation/readme.md new file mode 100644 index 00000000..1dad3e5d --- /dev/null +++ b/Logic Apps/SecurityCopilot-Sentinel-Incident-Investigation/readme.md @@ -0,0 +1,74 @@ +# SecurityCopilot-Sentinel-Incident-Investigation +**Author: Pratik Lal, Innocent Wafula, Stefano Pescosolido** + +## Overview + +This Logic App automates incident investigation within Microsoft Sentinel using the Microsoft Security Copilot prompt and built-in skills. It is designed to: +- Read Microsoft Sentinel incident entities. +- Process and normalize the entities. +- Submit prompts to Security Copilot to analyze each entity type. +- Summarize the outputs in a predefined format. +- Update the Microsoft Sentinel incident comments for the incident investigator to review (writing to the Sentinel incident can be disabled for facilitating the initial testing). +- Optionally send the result of the investigation by email. + +By leveraging this Logic App, Security Operations Center (SOC) and incident response teams can significantly reduce investigation time, gain consistent analysis outputs, and enhance their incident response process. + +## Prerequisites +- The user or service principal deploying this logic app should have Contributor role on the Azure Resource Group. +- Microsoft Security Copilot should be enabled on the Azure tenant. +- The user should have access to Microsoft Security Copilot to submit prompts by authenticating to Microsoft Security Copilot connector within the logic app. +- Microsoft Sentinel workspace should be set up. +- Optionally get AbuseIPDB API key to perform IP address reputation check. [Learn more.](https://learn.microsoft.com/en-us/copilot/security/plugin-abuseipdb) +- Enable Defender, Sentinel, Entra, Intune, MDTI and AbuseIPDB plugins from copilot settings for the user account configured on the API connection of the Logic App to Security Copilot. + + +## Deployment + + + +
+- Choose Client Certificate Auth or Oauth (using user account that can submit prompts) to create connection with Microsoft Security Copilot logic app connector.
+
+
+- Important: the account selected for the authentication to Security Copilot must have the Contributor role on Security Copilot and reader privileges on Defender, Sentinel, Entra and Intune.
+- Similarly, authenticate the API connection to Exchange Online (the correct setup of connection is needed even if the Logic App is configured to not send emails)
+- Assign the role of 'Microsoft Sentinel Responder' to the Managed Identity of the Logic App within the Resource Group that contains the Sentinel's Log Analytics workspace.
+- Set the values for the Logic App parameters
+
+- Automate Sentinel incident investigation by adding the Logic App to Microsoft Sentinel automation rule. Alternatively, this logic app can be called on-demand by right-clicking on a Sentinel incident, choose **Run Playbook** option.
+
+## Microsoft Security Copilot skills
+- Following built-in skills are being used to perform investigation on a given incident entity type
+
+| Incident entity | Security Copilot skill |
+| --------------- | -------------------------- |
+| Process name / commandline | ProcessAnalyzer |
+| Account name | GetEntraUserDetails |
+| Account names | GetEntraRiskyUsers |
+| Device name | GetIntuneDevices |
+| IP address | AbuseIPDB |
+| Indicator of Compromise (IoC) | GetReputationsForIndicators |
+
+
+## Incident Investigation Template
+- Automated incident investigation summary is structured in following order. Modify the prompt to re-order or change the investigation template.
+ - Incident Overview,
+ - Incident Description,
+ - IP Addresses Analysis,
+ - Account Analysis,
+ - Users Risk Analysis,
+ - Devices Analysis,
+ - Processes Analysis,
+ - Indicators Analysis from MDTI,
+ - Possible mitigation steps and Conclusion
+
+
diff --git a/Logic Apps/ciso-reporting/ciso-get-users-status.json b/Logic Apps/ciso-reporting/ciso-get-users-status.json
new file mode 100644
index 00000000..28e8a1a4
--- /dev/null
+++ b/Logic Apps/ciso-reporting/ciso-get-users-status.json
@@ -0,0 +1,344 @@
+{
+ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
+ "contentVersion": "1.0.0.0",
+ "metadata": {
+ "title": "Get the status of a set of users in MS Entra",
+ "description": "This Logic App return the status, in Microsoft Entra, of the users specified in input as comma separated values of User Principal Names (UPNs). For each user it returns if the user is Enabled or Disabled and the level of risk High, Medium or Low or Unknown",
+ "prerequisites": "",
+ "prerequisitesDeployTemplateFile": "",
+ "lastUpdateTime": "",
+ "entities": [
+ ],
+ "tags": [
+ ],
+ "support": {
+ "tier": "community",
+ "armtemplate": "Generated from https://github.com/Azure/Azure-Sentinel/tree/master/Tools/Playbook-ARM-Template-Generator"
+ },
+ "author": {
+ "name": "Stefano Pescosolido (https://www.linkedin.com/in/stefanopescosolido/)"
+ }
+ },
+ "parameters": {
+ "PlaybookName": {
+ "defaultValue": "CfS-CisoGetUserStatus",
+ "type": "string"
+ }
+ },
+ "variables": {
+ "SecuritycopilotConnectionName": "[concat('Securitycopilot-', parameters('PlaybookName'))]"
+ },
+ "resources": [
+ {
+ "properties": {
+ "provisioningState": "Succeeded",
+ "state": "Enabled",
+ "definition": {
+ "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
+ "contentVersion": "1.0.0.0",
+ "parameters": {
+ "$connections": {
+ "defaultValue": {
+ },
+ "type": "Object"
+ }
+ },
+ "triggers": {
+ "AnalyzeUPNsCall": {
+ "type": "Request",
+ "kind": "Http",
+ "inputs": {
+ "method": "POST",
+ "schema": {
+ "type": "object",
+ "properties": {
+ "users_upn": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "conditions": [
+ ]
+ }
+ },
+ "actions": {
+ "For_each_-_UPN": {
+ "foreach": "@variables('UPNs')",
+ "actions": {
+ "Submit_a_Security_Copilot_prompt_-_Enablement": {
+ "type": "ApiConnection",
+ "inputs": {
+ "host": {
+ "connection": {
+ "name": "@parameters('$connections')['securitycopilot']['connectionId']"
+ }
+ },
+ "method": "post",
+ "body": {
+ "PromptContent": "User UPN: @{trim(items('For_each_-_UPN'))}. Respond with only 1 word: \"Enabled\" or \"Disabled\", depending on the current value of the \"Account enabled\" attribute, or \"Unknown\" if you can't read the value of this attribute",
+ "SkillName": "GetEntraUserDetailsV1"
+ },
+ "path": "/process-prompt"
+ }
+ },
+ "Condition_-_evaluationResultType_-_Enablement": {
+ "actions": {
+ "Append_to_array_variable_-_Enablement_-_Success": {
+ "type": "AppendToArrayVariable",
+ "inputs": {
+ "name": "ResponseArray",
+ "value": {
+ "UPN": "@{trim(items('For_each_-_UPN'))}",
+ "Enablement Status": "@{trim(body('Submit_a_Security_Copilot_prompt_-_Enablement')?['EvaluationResultContent'])}"
+ }
+ }
+ }
+ },
+ "runAfter": {
+ "Submit_a_Security_Copilot_prompt_-_Enablement": [
+ "Succeeded"
+ ]
+ },
+ "else": {
+ "actions": {
+ "Append_to_array_variable_-_Enablement_-_Error": {
+ "type": "AppendToArrayVariable",
+ "inputs": {
+ "name": "ResponseArray",
+ "value": {
+ "UPN": "@{trim(items('For_each_-_UPN'))}",
+ "Enablement Status": "Error"
+ }
+ }
+ }
+ }
+ },
+ "expression": {
+ "and": [
+ {
+ "equals": [
+ "@body('Submit_a_Security_Copilot_prompt_-_Enablement')?['evaluationResultType']",
+ "Success"
+ ]
+ }
+ ]
+ },
+ "type": "If"
+ },
+ "Submit_a_Security_Copilot_prompt_-_Entra_Risk": {
+ "runAfter": {
+ "Condition_-_evaluationResultType_-_Enablement": [
+ "Succeeded"
+ ]
+ },
+ "type": "ApiConnection",
+ "inputs": {
+ "host": {
+ "connection": {
+ "name": "@parameters('$connections')['securitycopilot']['connectionId']"
+ }
+ },
+ "method": "post",
+ "body": {
+ "PromptContent": "Check if the user @{trim(items('For_each_-_UPN'))} has a Risk Level associated. Respond with only 1 of these possible 5 word: \"High\", \"Medium\", \"Low\", according to the Risk Level of the user account, \"None\" if no risk level is assigned to the user account or \"Unknown\" if it was not possible to read the risk level for the user account.",
+ "SkillName": "GetEntraRiskyUsers"
+ },
+ "path": "/process-prompt"
+ }
+ },
+ "Condition_-_evaluationResultType_-_Entra_Risk": {
+ "actions": {
+ "Append_to_array_variable_-_Risk_-_Success": {
+ "type": "AppendToArrayVariable",
+ "inputs": {
+ "name": "ResponseArray",
+ "value": {
+ "UPN": "@{trim(items('For_each_-_UPN'))}",
+ "Risk Status": "@{trim(body('Submit_a_Security_Copilot_prompt_-_Entra_Risk')?['EvaluationResultContent'])}"
+ }
+ }
+ }
+ },
+ "runAfter": {
+ "Submit_a_Security_Copilot_prompt_-_Entra_Risk": [
+ "Succeeded",
+ "TimedOut",
+ "Failed"
+ ]
+ },
+ "else": {
+ "actions": {
+ "Append_to_array_variable_-_Risk_-_Error": {
+ "type": "AppendToArrayVariable",
+ "inputs": {
+ "name": "ResponseArray",
+ "value": {
+ "UPN": "@{trim(items('For_each_-_UPN'))}",
+ "Risk Status": "Error"
+ }
+ }
+ }
+ }
+ },
+ "expression": {
+ "and": [
+ {
+ "equals": [
+ "@body('Submit_a_Security_Copilot_prompt_-_Entra_Risk')?['evaluationResultType']",
+ "Success"
+ ]
+ }
+ ]
+ },
+ "type": "If"
+ }
+ },
+ "runAfter": {
+ "Initialize_variable_-_ResponseArray": [
+ "Succeeded"
+ ]
+ },
+ "type": "Foreach",
+ "runtimeConfiguration": {
+ "concurrency": {
+ "repetitions": 20
+ }
+ }
+ },
+ "Initialize_variable_-_UPNs": {
+ "runAfter": {
+ "Initialize_variable_-_SessionID_-_Use_it_in_Copilot_calls_if_needed": [
+ "Succeeded"
+ ]
+ },
+ "type": "InitializeVariable",
+ "inputs": {
+ "variables": [
+ {
+ "name": "UPNs",
+ "type": "array",
+ "value": "@split(triggerBody()?['users_upn'],',')"
+ }
+ ]
+ }
+ },
+ "Initialize_variable_-_CallResponse": {
+ "runAfter": {
+ "Initialize_variable_-_UPNs": [
+ "Succeeded"
+ ]
+ },
+ "type": "InitializeVariable",
+ "inputs": {
+ "variables": [
+ {
+ "name": "CallResponse",
+ "type": "string"
+ }
+ ]
+ }
+ },
+ "Initialize_variable_-_SessionID_-_Use_it_in_Copilot_calls_if_needed": {
+ "runAfter": {
+ },
+ "type": "InitializeVariable",
+ "inputs": {
+ "variables": [
+ {
+ "name": "SessionID",
+ "type": "string",
+ "value": "@triggerOutputs()?['headers']?['x-securitycopilot-sessionid']"
+ }
+ ]
+ }
+ },
+ "Response_-_Return_the_users_status_to_the_caller": {
+ "runAfter": {
+ "Set_variable_-_Call_Response": [
+ "Succeeded"
+ ]
+ },
+ "type": "Response",
+ "kind": "Http",
+ "inputs": {
+ "statusCode": 200,
+ "body": "@variables('CallResponse')"
+ }
+ },
+ "Initialize_variable_-_ResponseArray": {
+ "runAfter": {
+ "Initialize_variable_-_CallResponse": [
+ "Succeeded"
+ ]
+ },
+ "type": "InitializeVariable",
+ "inputs": {
+ "variables": [
+ {
+ "name": "ResponseArray",
+ "type": "array"
+ }
+ ]
+ }
+ },
+ "Set_variable_-_Call_Response": {
+ "runAfter": {
+ "For_each_-_UPN": [
+ "Succeeded"
+ ]
+ },
+ "type": "SetVariable",
+ "inputs": {
+ "name": "CallResponse",
+ "value": "@concat('[',join(variables('ResponseArray'),','),']')"
+ }
+ }
+ },
+ "outputs": {
+ }
+ },
+ "parameters": {
+ "$connections": {
+ "value": {
+ "securitycopilot": {
+ "connectionId": "[resourceId('Microsoft.Web/connections', variables('SecuritycopilotConnectionName'))]",
+ "connectionName": "[variables('SecuritycopilotConnectionName')]",
+ "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/Securitycopilot')]"
+ }
+ }
+ }
+ }
+ },
+ "name": "[parameters('PlaybookName')]",
+ "type": "Microsoft.Logic/workflows",
+ "location": "[resourceGroup().location]",
+ "tags": {
+ "hidden-SentinelTemplateName": "CfS-CisoGetUserStatus",
+ "hidden-SentinelTemplateVersion": "1.0"
+ },
+ "identity": {
+ "type": "SystemAssigned"
+ },
+ "apiVersion": "2017-07-01",
+ "dependsOn": [
+ "[resourceId('Microsoft.Web/connections', variables('SecuritycopilotConnectionName'))]"
+ ]
+ },
+ {
+ "type": "Microsoft.Web/connections",
+ "apiVersion": "2016-06-01",
+ "name": "[variables('SecuritycopilotConnectionName')]",
+ "location": "[resourceGroup().location]",
+ "kind": "V1",
+ "properties": {
+ "displayName": "[variables('SecuritycopilotConnectionName')]",
+ "customParameterValues": {
+ },
+ "api": {
+ "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/Securitycopilot')]"
+ }
+ }
+ }
+ ]
+}
diff --git a/Logic Apps/ciso-reporting/ciso-incidents-summary-api-spec.yaml b/Logic Apps/ciso-reporting/ciso-incidents-summary-api-spec.yaml
new file mode 100644
index 00000000..7e0652ad
--- /dev/null
+++ b/Logic Apps/ciso-reporting/ciso-incidents-summary-api-spec.yaml
@@ -0,0 +1,44 @@
+openapi: 3.0.0
+
+info:
+ title: CISO Incidents Summary
+ description: Helper skills used to get specific summary info on the incidents in Defender
+ version: "0.0.1"
+
+servers:
+ - url:
|
|
| SkillName | +Description | +Parameters | +
|---|---|---|
| SecurityCopilotLogins | +Fetches Security Copilot Standalone Portal logins in the last 3 days | +
+
|
+
+| SkillName | +Description | +Parameters | +
|---|---|---|
| SentinelIncidentComments | +Fetch Sentinel incident comments | +
+
|
+
+| SkillName | +Description | +Parameters | +
|---|---|---|
| GetTrustedUsers | +Fetches the list of trusted users that is being maintained as a Microsoft Sentinel watchlist | +
+
|
+
+Example Prompt: Create an eDiscovery case in Purview with the Case name "Test-123", response should be a bulleted list.
+Inputs: [Case name]
+Example Prompt: Add a custodian to the eDiscovery case in Purview, use the Case ID "1xxxx234-XXXX-XXXX-a1cd-fxxxxxxxxxx0" and add this email "test@test123.com".
+Inputs: [Email], [Case ID]
+Example Prompt: Apply hold on eDiscovery custodian using the Custodian ID "2xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx6".
+Inputs: [Custodian ID]
+Example Prompt: Add new userSource object associated with Custodian ID "2xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx6", include custodian email "test@test123.com" and specify sources as Mailbox, Site.
+Inputs: [Custodian ID], [Email]
+Example Prompt: Add a new eDiscovery Search object with Case ID "1xxxx234-XXXX-XXXX-a1cd-fxxxxxxxxxx0" with the display name "Test-123-search", and add dataSourceScopes to allTenantMailboxes, allTenantSites, allCaseCustodians.
+Inputs: [Case ID], [Display Name]
+Example Prompt: Run an estimate of the number of emails and documents in eDiscovery with Search ID "2xxxxxxx-xxx4-xxxd-4xxx-5xxxxxxxxxxx".
+Inputs: [Search ID]
+Example Prompt: Create a new eDiscovery ReviewSet for Case ID "1xxxx234-XXXX-XXXX-a1cd-fxxxxxxxxxx0" with Display Name "Test-123-reviewset".
+Inputs: [Case ID]
+Example Prompt: Use Case ID "1xxxx234-XXXX-XXXX-a1cd-fxxxxxxxxxx0" and ReviewSet ID "dxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" to initiate an export.
+Inputs: [Case ID], [Review Set ID]
+Example Prompt: Initiate an export from the Search with Case ID "1xxxx234-XXXX-XXXX-a1cd-fxxxxxxxxxx0" and Search ID "dxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx". Additional parameters: displayName="Export 1 - simple PST-V2", exportCriteria="searchHits", additionalOptions="none", exportFormat="pst".
+Inputs: [Case ID], [Search ID]
+Example Prompt: Use the Case ID from above or use this Case ID "1xxxx234-XXXX-XXXX-a1cd-fxxxxxxxxxx0", and update index on Custodian.
+Inputs: [Case ID]
+Example Prompt: Use the Case ID from above or use this Case ID "1xxxx234-XXXX-XXXX-a1cd-fxxxxxxxxxx0", get a list of the caseOperation objects and their properties.
+Inputs: [Case ID]
+| SkillName | +Description | +Parameters | +
|---|---|---|
| RedactPII | +Redacts Personally Identifiable Information (PII) from the provided text | +
+
|
+
+- GET /simple/<data> - Will return a JSON contains <data> and few other fields " - text += "
- GET /params/<data> - Will return a JSON contains <data> and few other fields passed in URL Params" - text += "
- GET /params_auth_header/<data> - Will return a JSON contains <data> and few other fields passed in URL Params, along with Authorization field passed in header" - text += "
- GET /params_auth_data/<data> - Will return a JSON contains <data> and few other fields passed in URL Params, along with Authorization field passed in data" - text += "
- POST /json/<data> - Will return a JSON contains <data> and few other fields passed in payload JSON"
- return text
-
-# ---------------- GET methods
-@app.route('/simple/', methods=['GET'])
-def get_simple(data):
- obj = ReflectorSimple(data,getIpAddr(request),request.user_agent.string)
- response = jsonify(obj.getDict())
- return response
-
-@app.route('/simple/multiple/', methods=['GET'])
-def get_simple_multiple(data):
- count = int(data)
- objs = []
- for i in range(0,count):
- obj = ReflectorSimple("Data_"+str(i),getIpAddr(request),request.user_agent.string)
- objs.append(obj.getDict())
- response = jsonify(objs)
- return response
-
-# This method accepts query parameters,passes them to create a ReflectorJson JSON object
-@app.route('/params/', methods=['GET'])
-def get_params_data(data):
- args = request.args
- jsonData = args
- obj = ReflectorJson(data,jsonData,request.remote_addr,request.user_agent.string)
- response = jsonify(obj.getDict())
- return response
-
-@app.route('/params_auth_header/', methods=['GET'])
-def get_params_auth_header(data):
- args = request.args
- jsonData = args
- # Extract the Authorization Value from the Header
- authToken = "via Header:" + request.headers["Authorization"]
- obj = ReflectorJsonAuth(data,authToken,jsonData,request.remote_addr,request.user_agent.string)
- response = jsonify(obj.getDict())
- return response
-
-@app.route('/params_auth_data/', methods=['GET'])
-def get_params_auth_data(data):
- args = request.args
- jsonData = args
- # Extract the Authorization Value from the Parameter
- authToken = args["Authorization"]
- obj = ReflectorJsonAuth(data,authToken,jsonData,request.remote_addr,request.user_agent.string)
- response = jsonify(obj.getDict())
- return response
-
-# ---------------- POST methods
-@app.route('/json/', methods=['POST'])
-def get_json(data):
- jsonData = ""
- if(request.is_json):
- try:
- # Handle Error
- jsonData = request.get_json(force=True) #request.json
- print("Received JSON:",jsonData)
- except Exception as e:
- print("Error",e)
- print("Request Content", str(jsonData))
- result = {'Error': "'" + str(e) + "'"}
- return result, 400 # Return error as HTTP 400
- obj = ReflectorJson(data,jsonData,request.remote_addr,request.user_agent.string)
- response = jsonify(obj.getDict())
- return response
-
-
-#---- OPTIONAL: Use this URL to return YAML files if you do not want to the host the files in FTP/Azure/Blob
-#---- NOTE: All files should be placed in the ./Files folder
-@app.route('/file/
+`https://purview.microsoft.com/datalossprevention/alertspage/fullpage?tid=0527ecb7-06fb-4769-b324-fd4a3bb865eb&alertsviewid=overview&id=da7618d0-35a6-71b8-3400-08dd5766cd5a`
+
+To create a link, I simply need to ensure that the data required to support a given URL format is present in the output or provided some other way. In this case, the output contains a list of DLP alerts along with their associated alert ID. Since my Tenant ID is missing, I'll need to get it. There are multiple methods for getting this, but the easiest is to simply view the [Tenant Properties within the Azure Portal](https://portal.azure.com/#view/Microsoft_AAD_IAM/TenantProperties.ReactView).
+
+Now that I have the Tenant ID, I can hardcode that part of the URL. From my experience working in Defender XDR and Purview, I know that alert IDs associated with Purview include a preceding 'dl' that I'll need to remove if I want to view these alerts from the Purview portal.
+
+To generate this URL, I will again use the **/AskGPT** skill and prompt Security Copilot to:
+- Create a link for the alerts.
+- Provide it with the root URL that contains my Tenant ID.
+- Ask it to remove the first two characters of the alert ID.
+
+⚠️ Please read next prompt before executing and don't forget to insert your Tenant ID in the URL before pasting.
+
+```
+/AskGPT For each user include a direct link to the alert in Microsoft Purview portal using the following URL format:
+Purview: [{Alert Title}](https://purview.microsoft.com/datalossprevention/alertspage/fullpage?tid={Replace-with-your-tenant-ID-and-remove-curly-brackets}&alertsviewid=overview&id={alertId with the first two 'dl' characters of the AlertID removed})
+```
+
+⚠️ If I'd prefer working out of Defender XDR instead of Purview, I can leave the preceding 'dl' characters in the Alert ID and use the Defender XDR URL `https://security.microsoft.com/alerts/{alert ID}`, modifying the prompt accordingly. To avoid confusing the LLM, I'll choose either Purview or Defender XDR before pasting the prompt.
+
+```
+/AskGPT For each user include a direct link to the alert in Defender XDR portal using the following URL format:
+[{Alert Title}](https://security.microsoft.com/alerts/{alert Id})
+```
+
+If the above prompt failed, verify that you updated the Tenant ID.
+
+
+
+
+### Ensuring consistent formatting
+
+While I value the friendly, conversational, and non-repetitive nature that Generative AI provides, I need the output to be consistently formatted each time. To achieve this, I'll provide clear instructions that integrate my previous prompts, URL modifications, and additional format guidelines.
+
+Since large language models (LLMs) work best when using specific delimiters, and Markdown is a well-established language for such delimiters, I will combine both the [Security Copilot prompt engineering best practices](https://learn.microsoft.com/en-us/copilot/security/prompting-tips) and the [general best practices for effective prompting of LLMs](#general-best-practices-for-effective-prompting-llms) outlined at the top of this page. By leveraging both of these resources, I’ve not only harnessed the power of Security Copilot, but I will also ensure that the reasoning output is consistently formatted each time I run this prompt.
+
+```
+Using the Purview plugin, get the last 10 DLP alerts with a severity of high. Assume the role of an expert **Data Loss Prevention (DLP) engineer** tasked with generating a **professional, manager-focused summary** of a DLP triage workflow for DLP alerts.
+
+- For **each user**, write a **concise, actionable summary** addressed to their manager.
+- Begin the summary with the user's **User Principal Name (UPN), Job Title, and Department** to establish context.
+- Highlight **significant trends, behaviors, or issues** observed in their **DLP alerts** using **chain-of-thought reasoning** to identify patterns, similarities, or contributing factors across the alerts.
+- Provide **clear, actionable recommendations** to mitigate risk, prioritize incidents, and improve compliance.
+- Include a direct **link to the alert in Microsoft Purview** using the following URL format: [{Alert Title}](https://purview.microsoft.com/datalossprevention/alertspage/fullpage?tid=0527ecb7-06fb-4769-b324-fd4a3bb865eb&alertsviewid=overview&id={alert Id}
+- Note that if the alert ID begins with 'dl' this portion of the alertId should be removed before creating the URL. Example: https://purview.microsoft.com/datalossprevention/alertspage/fullpage?tid=0527ecb7-06fb-4769-b324-fd4a3bb865eb&alertsviewid=overview&id=dlda7618d0-35a6-71b8-9200-08dd5767802a
+...becomes...
+https://purview.microsoft.com/datalossprevention/alertspage/fullpage?tid=0527ecb7-06fb-4769-b324-fd4a3bb865eb&alertsviewid=overview&id=da7618d0-35a6-71b8-9200-08dd5767802a
+
+**Tone and Style:** Write in clear, professional, and manager-focused language, emphasizing risk, mitigation strategies, and actionable insights.
+
+## Output format ##
+**User**: {User Principal Name (UPN)}
+
+**Summary:**
+{Concise, actionable summary of the DLP alerts for the user, highlighting significant trends, behaviors, or issues observed in their DLP alerts using chain-of-thought reasoning to identify patterns, similarities, or contributing factors across the alerts. Summary should be under 150 words.}
+
+**Recommendations:**
+1. **Recommendation category**: {Any recommendation that supports mitigate risk, prioritize incidents, and improve compliance}
+2. **Recommendation category**: {Any additional recommendations that supports mitigate risk, prioritize incidents, and improve compliance}
+3. etc...
+
+**Alert Links:**
+- [Alert Title](Alert Link)
+- [Alert Title](Alert Link)
+---
+```
+
+
+
+---
+
+### Leveraging Promptbooks
+
+To make repeating the execution of this prompt easier, I'll create a promptbook. Promptbooks can store multiple prompts and support workflows that allow users to easily rerun one or more prompts at a later time. For advanced prompts like this that include multiple lines of instructions and formatting requirements, using a promptbook reduces the likelihood that I'll incur errors from typing, saves me time from having to manually copy and paste prompts from an external library, and allows me to share it with others within my organization.
+
+To create a promptbook from within a session, I simply need to click the checkbox on the top left corner of the prompt, and select the "Create promptbook" icon at the top. However, it's important to note that promptbooks use angle brackets`< >` to denote variables. As such, the existence of them must only be used for variables without spaces.
+
+
+
+Next, I'll provide a name, relevant tags (hit ENTER after each tag), and a description. After this, I'll hover my mouse over the prompt box and click the pencil icon to edit the prompt.
+
+
+
+Since I don't always want "10" alerts exactly, I'll make this a variable by replacing the number "10" with `