From 401ec8a82b689c7283ef02e07a1a71170046ee1e Mon Sep 17 00:00:00 2001 From: Rambatla Venkat Rao Date: Fri, 24 Jul 2026 02:56:55 +0530 Subject: [PATCH 1/3] SpyCloud CCF Connector --- .../get_Spycloud_enriched_data.json | 315 ++ .../get_spycloud_compass_data.json | 67 + .../SpyCloudBreachCatalogV2_CL.json | 25 + .../SpyCloudBreachWatchlistV2_CL.json | 297 + .../SpyCloud_ConditionalAccessLogsV2_CL.json | 61 + .../CustomTables/Spycloud_MDE_LogsV2_CL.json | 81 + .../CustomTables/spycloud_compassV2_CL.json | 117 + .../ValidConnectorIds.json | 1 + .../Analytic Rules/AR_Breached_Users_20.yaml | 44 + .../Analytic Rules/AR_malware_25.yaml | 47 + ...pyCloudEnterpriseProtectionLogsV2_DCR.json | 637 +++ ...terpriseProtectionLogsV2_PollerConfig.json | 246 + ...loudEnterpriseProtectionLogsV2_Tables.json | 618 +++ ...eProtectionLogsV2_connectorDefinition.json | 144 + ...Solution_SpyCloudEnterpriseProtection.json | 27 + .../Package/3.0.0.zip | Bin 0 -> 26266 bytes .../Package/createUiDefinition.json | 169 + .../Package/mainTemplate.json | 4841 +++++++++++++++++ .../Package/testParameters.json | 38 + .../Parsers/get_Spycloud_enriched_data.yaml | 102 + .../Parsers/get_spycloud_compass_data.yaml | 20 + .../SpyCloud_AutomationRules/azuredeploy.json | 179 + .../SpyCloud_AutomationRules/readme.md | 37 + .../azuredeploy.json | 868 +++ .../readme.md | 54 + .../SpyCloud_MDE_Automation/azuredeploy.json | 965 ++++ .../SpyCloud_MDE_Automation/readme.md | 55 + .../ReleaseNotes.md | 3 + .../SolutionMetadata.json | 20 + 29 files changed, 10078 insertions(+) create mode 100644 .script/tests/KqlvalidationsTests/CustomFunctions/get_Spycloud_enriched_data.json create mode 100644 .script/tests/KqlvalidationsTests/CustomFunctions/get_spycloud_compass_data.json create mode 100644 .script/tests/KqlvalidationsTests/CustomTables/SpyCloudBreachCatalogV2_CL.json create mode 100644 .script/tests/KqlvalidationsTests/CustomTables/SpyCloudBreachWatchlistV2_CL.json create mode 100644 .script/tests/KqlvalidationsTests/CustomTables/SpyCloud_ConditionalAccessLogsV2_CL.json create mode 100644 .script/tests/KqlvalidationsTests/CustomTables/Spycloud_MDE_LogsV2_CL.json create mode 100644 .script/tests/KqlvalidationsTests/CustomTables/spycloud_compassV2_CL.json create mode 100644 Solutions/SpyCloud Enterprise Protection CCF/Analytic Rules/AR_Breached_Users_20.yaml create mode 100644 Solutions/SpyCloud Enterprise Protection CCF/Analytic Rules/AR_malware_25.yaml create mode 100644 Solutions/SpyCloud Enterprise Protection CCF/Data Connectors/SpyCloudEnterpriseProtectionLogsV2_ccp/SpyCloudEnterpriseProtectionLogsV2_DCR.json create mode 100644 Solutions/SpyCloud Enterprise Protection CCF/Data Connectors/SpyCloudEnterpriseProtectionLogsV2_ccp/SpyCloudEnterpriseProtectionLogsV2_PollerConfig.json create mode 100644 Solutions/SpyCloud Enterprise Protection CCF/Data Connectors/SpyCloudEnterpriseProtectionLogsV2_ccp/SpyCloudEnterpriseProtectionLogsV2_Tables.json create mode 100644 Solutions/SpyCloud Enterprise Protection CCF/Data Connectors/SpyCloudEnterpriseProtectionLogsV2_ccp/SpyCloudEnterpriseProtectionLogsV2_connectorDefinition.json create mode 100644 Solutions/SpyCloud Enterprise Protection CCF/Data/Solution_SpyCloudEnterpriseProtection.json create mode 100644 Solutions/SpyCloud Enterprise Protection CCF/Package/3.0.0.zip create mode 100644 Solutions/SpyCloud Enterprise Protection CCF/Package/createUiDefinition.json create mode 100644 Solutions/SpyCloud Enterprise Protection CCF/Package/mainTemplate.json create mode 100644 Solutions/SpyCloud Enterprise Protection CCF/Package/testParameters.json create mode 100644 Solutions/SpyCloud Enterprise Protection CCF/Parsers/get_Spycloud_enriched_data.yaml create mode 100644 Solutions/SpyCloud Enterprise Protection CCF/Parsers/get_spycloud_compass_data.yaml create mode 100644 Solutions/SpyCloud Enterprise Protection CCF/Playbooks/SpyCloud_AutomationRules/azuredeploy.json create mode 100644 Solutions/SpyCloud Enterprise Protection CCF/Playbooks/SpyCloud_AutomationRules/readme.md create mode 100644 Solutions/SpyCloud Enterprise Protection CCF/Playbooks/SpyCloud_Conditional_Access_Playbook/azuredeploy.json create mode 100644 Solutions/SpyCloud Enterprise Protection CCF/Playbooks/SpyCloud_Conditional_Access_Playbook/readme.md create mode 100644 Solutions/SpyCloud Enterprise Protection CCF/Playbooks/SpyCloud_MDE_Automation/azuredeploy.json create mode 100644 Solutions/SpyCloud Enterprise Protection CCF/Playbooks/SpyCloud_MDE_Automation/readme.md create mode 100644 Solutions/SpyCloud Enterprise Protection CCF/ReleaseNotes.md create mode 100644 Solutions/SpyCloud Enterprise Protection CCF/SolutionMetadata.json diff --git a/.script/tests/KqlvalidationsTests/CustomFunctions/get_Spycloud_enriched_data.json b/.script/tests/KqlvalidationsTests/CustomFunctions/get_Spycloud_enriched_data.json new file mode 100644 index 00000000000..70b74086e05 --- /dev/null +++ b/.script/tests/KqlvalidationsTests/CustomFunctions/get_Spycloud_enriched_data.json @@ -0,0 +1,315 @@ +{ + "FunctionName": "get_Spycloud_enriched_data", + "FunctionParameters": [ + { + "Name": "lookback", + "Type": "timespan" + } + ], + "FunctionResultColumns": [ + { + "Name": "TimeGenerated", + "Type": "DateTime" + }, + { + "Name": "SourceId", + "Type": "Int" + }, + { + "Name": "InfectedPath", + "Type": "String" + }, + { + "Name": "UserHostName", + "Type": "String" + }, + { + "Name": "IPAddresses", + "Type": "Dynamic" + }, + { + "Name": "TimeZone", + "Type": "String" + }, + { + "Name": "TargetUrl", + "Type": "String" + }, + { + "Name": "DocumentId", + "Type": "String" + }, + { + "Name": "TargetDomain", + "Type": "String" + }, + { + "Name": "UserSysRegisteredOwner", + "Type": "String" + }, + { + "Name": "DisplayResolution", + "Type": "String" + }, + { + "Name": "Password", + "Type": "String" + }, + { + "Name": "Email", + "Type": "String" + }, + { + "Name": "Severity", + "Type": "Int" + }, + { + "Name": "AVSoftwares", + "Type": "Dynamic" + }, + { + "Name": "LogId", + "Type": "String" + }, + { + "Name": "UserOS", + "Type": "String" + }, + { + "Name": "EmailUsername", + "Type": "String" + }, + { + "Name": "SpyCloudPublishDate", + "Type": "String" + }, + { + "Name": "InfectedMachineId", + "Type": "String" + }, + { + "Name": "PasswordPlaintext", + "Type": "String" + }, + { + "Name": "InfectedTime", + "Type": "String" + }, + { + "Name": "CountryCode", + "Type": "String" + }, + { + "Name": "KeyboardLanguages", + "Type": "String" + }, + { + "Name": "PasswordType", + "Type": "String" + }, + { + "Name": "Domain", + "Type": "String" + }, + { + "Name": "EmailDomain", + "Type": "String" + }, + { + "Name": "TargetSubdomain", + "Type": "String" + }, + { + "Name": "Sighting", + "Type": "Int" + }, + { + "Name": "AccountLastActivityTime", + "Type": "String" + }, + { + "Name": "AccountNotes", + "Type": "String" + }, + { + "Name": "AccountSignupTime", + "Type": "String" + }, + { + "Name": "Username", + "Type": "String" + }, + { + "Name": "Homepage", + "Type": "String" + }, + { + "Name": "Salt", + "Type": "String" + }, + { + "Name": "AccountLoginTime", + "Type": "String" + }, + { + "Name": "SocialOther", + "Type": "Dynamic" + }, + { + "Name": "LastName", + "Type": "String" + }, + { + "Name": "FullName", + "Type": "String" + }, + { + "Name": "Phone", + "Type": "String" + }, + { + "Name": "FirstName", + "Type": "String" + }, + { + "Name": "Address1", + "Type": "String" + }, + { + "Name": "AccountModificationTime", + "Type": "String" + }, + { + "Name": "Gender", + "Type": "String" + }, + { + "Name": "City", + "Type": "String" + }, + { + "Name": "BirthYear", + "Type": "String" + }, + { + "Name": "DOB", + "Type": "String" + }, + { + "Name": "CompanyWebsite", + "Type": "String" + }, + { + "Name": "Industry", + "Type": "String" + }, + { + "Name": "AccountStatus", + "Type": "String" + }, + { + "Name": "SocialCrunchbase", + "Type": "Dynamic" + }, + { + "Name": "CompanyName", + "Type": "String" + }, + { + "Name": "SocialLinkedIn", + "Type": "Dynamic" + }, + { + "Name": "SocialTwitter", + "Type": "Dynamic" + }, + { + "Name": "AccountCaption", + "Type": "String" + }, + { + "Name": "Address2", + "Type": "String" + }, + { + "Name": "SSNLastFour", + "Type": "String" + }, + { + "Name": "SocialSecurityNumber", + "Type": "String" + }, + { + "Name": "HealthInsuranceId", + "Type": "String" + }, + { + "Name": "PostalCode", + "Type": "String" + }, + { + "Name": "Age", + "Type": "String" + }, + { + "Name": "TaxId", + "Type": "String" + }, + { + "Name": "State", + "Type": "String" + }, + { + "Name": "AccountType", + "Type": "String" + }, + { + "Name": "DeviceName", + "Type": "Dynamic" + }, + { + "Name": "BankNumber", + "Type": "String" + }, + { + "Name": "MobileEquipmentId", + "Type": "String" + }, + { + "Name": "Country", + "Type": "String" + }, + { + "Name": "EducationalInstitution", + "Type": "String" + }, + { + "Name": "JobTitle", + "Type": "String" + }, + { + "Name": "AccountImageUrl", + "Type": "String" + }, + { + "Name": "StudentId", + "Type": "String" + }, + { + "Name": "AccountId", + "Type": "String" + }, + { + "Name": "BreachTitle", + "Type": "String" + }, + { + "Name": "CatalogDescription", + "Type": "String" + }, + { + "Name": "CatalogStatus", + "Type": "String" + } + ] +} diff --git a/.script/tests/KqlvalidationsTests/CustomFunctions/get_spycloud_compass_data.json b/.script/tests/KqlvalidationsTests/CustomFunctions/get_spycloud_compass_data.json new file mode 100644 index 00000000000..c9265b742e8 --- /dev/null +++ b/.script/tests/KqlvalidationsTests/CustomFunctions/get_spycloud_compass_data.json @@ -0,0 +1,67 @@ +{ + "FunctionName": "get_spycloud_compass_data", + "FunctionParameters": [ + { + "Name": "startTime", + "Type": "timespan" + } + ], + "FunctionResultColumns": [ + { + "Name": "TimeGenerated", + "Type": "DateTime" + }, + { + "Name": "DocumentId", + "Type": "String" + }, + { + "Name": "SourceId", + "Type": "Int" + }, + { + "Name": "SpyCloudPublishDate", + "Type": "String" + }, + { + "Name": "Email", + "Type": "String" + }, + { + "Name": "Domain", + "Type": "String" + }, + { + "Name": "Password", + "Type": "String" + }, + { + "Name": "PasswordPlaintext", + "Type": "String" + }, + { + "Name": "Severity", + "Type": "Int" + }, + { + "Name": "IPAddresses", + "Type": "Dynamic" + }, + { + "Name": "InfectedMachineId", + "Type": "String" + }, + { + "Name": "InfectedTime", + "Type": "String" + }, + { + "Name": "BreachTitle", + "Type": "String" + }, + { + "Name": "BreachCategory", + "Type": "String" + } + ] +} diff --git a/.script/tests/KqlvalidationsTests/CustomTables/SpyCloudBreachCatalogV2_CL.json b/.script/tests/KqlvalidationsTests/CustomTables/SpyCloudBreachCatalogV2_CL.json new file mode 100644 index 00000000000..8314d11b5fc --- /dev/null +++ b/.script/tests/KqlvalidationsTests/CustomTables/SpyCloudBreachCatalogV2_CL.json @@ -0,0 +1,25 @@ +{ + "Name": "SpyCloudBreachCatalogV2_CL", + "Properties": [ + { + "Name": "TimeGenerated", + "Type": "DateTime" + }, + { + "Name": "SourceId", + "Type": "Int" + }, + { + "Name": "BreachTitle", + "Type": "String" + }, + { + "Name": "Description", + "Type": "String" + }, + { + "Name": "Status", + "Type": "String" + } + ] +} diff --git a/.script/tests/KqlvalidationsTests/CustomTables/SpyCloudBreachWatchlistV2_CL.json b/.script/tests/KqlvalidationsTests/CustomTables/SpyCloudBreachWatchlistV2_CL.json new file mode 100644 index 00000000000..1a6bafb092f --- /dev/null +++ b/.script/tests/KqlvalidationsTests/CustomTables/SpyCloudBreachWatchlistV2_CL.json @@ -0,0 +1,297 @@ +{ + "Name": "SpyCloudBreachWatchlistV2_CL", + "Properties": [ + { + "Name": "TimeGenerated", + "Type": "DateTime" + }, + { + "Name": "InfectedPath", + "Type": "String" + }, + { + "Name": "UserHostName", + "Type": "String" + }, + { + "Name": "IPAddresses", + "Type": "Dynamic" + }, + { + "Name": "TimeZone", + "Type": "String" + }, + { + "Name": "TargetUrl", + "Type": "String" + }, + { + "Name": "DocumentId", + "Type": "String" + }, + { + "Name": "TargetDomain", + "Type": "String" + }, + { + "Name": "UserSysRegisteredOwner", + "Type": "String" + }, + { + "Name": "DisplayResolution", + "Type": "String" + }, + { + "Name": "Password", + "Type": "String" + }, + { + "Name": "Email", + "Type": "String" + }, + { + "Name": "Severity", + "Type": "Int" + }, + { + "Name": "AVSoftwares", + "Type": "Dynamic" + }, + { + "Name": "LogId", + "Type": "String" + }, + { + "Name": "UserOS", + "Type": "String" + }, + { + "Name": "EmailUsername", + "Type": "String" + }, + { + "Name": "SpyCloudPublishDate", + "Type": "String" + }, + { + "Name": "InfectedMachineId", + "Type": "String" + }, + { + "Name": "PasswordPlaintext", + "Type": "String" + }, + { + "Name": "InfectedTime", + "Type": "String" + }, + { + "Name": "CountryCode", + "Type": "String" + }, + { + "Name": "KeyboardLanguages", + "Type": "String" + }, + { + "Name": "PasswordType", + "Type": "String" + }, + { + "Name": "Domain", + "Type": "String" + }, + { + "Name": "EmailDomain", + "Type": "String" + }, + { + "Name": "SourceId", + "Type": "Int" + }, + { + "Name": "TargetSubdomain", + "Type": "String" + }, + { + "Name": "Sighting", + "Type": "Int" + }, + { + "Name": "AccountLastActivityTime", + "Type": "String" + }, + { + "Name": "AccountNotes", + "Type": "String" + }, + { + "Name": "AccountSignupTime", + "Type": "String" + }, + { + "Name": "Username", + "Type": "String" + }, + { + "Name": "Homepage", + "Type": "String" + }, + { + "Name": "Salt", + "Type": "String" + }, + { + "Name": "AccountLoginTime", + "Type": "String" + }, + { + "Name": "SocialOther", + "Type": "Dynamic" + }, + { + "Name": "LastName", + "Type": "String" + }, + { + "Name": "FullName", + "Type": "String" + }, + { + "Name": "Phone", + "Type": "String" + }, + { + "Name": "FirstName", + "Type": "String" + }, + { + "Name": "Address1", + "Type": "String" + }, + { + "Name": "AccountModificationTime", + "Type": "String" + }, + { + "Name": "Gender", + "Type": "String" + }, + { + "Name": "City", + "Type": "String" + }, + { + "Name": "BirthYear", + "Type": "String" + }, + { + "Name": "DOB", + "Type": "String" + }, + { + "Name": "CompanyWebsite", + "Type": "String" + }, + { + "Name": "Industry", + "Type": "String" + }, + { + "Name": "AccountStatus", + "Type": "String" + }, + { + "Name": "SocialCrunchbase", + "Type": "Dynamic" + }, + { + "Name": "CompanyName", + "Type": "String" + }, + { + "Name": "SocialLinkedIn", + "Type": "Dynamic" + }, + { + "Name": "SocialTwitter", + "Type": "Dynamic" + }, + { + "Name": "AccountCaption", + "Type": "String" + }, + { + "Name": "Address2", + "Type": "String" + }, + { + "Name": "SSNLastFour", + "Type": "String" + }, + { + "Name": "SocialSecurityNumber", + "Type": "String" + }, + { + "Name": "HealthInsuranceId", + "Type": "String" + }, + { + "Name": "PostalCode", + "Type": "String" + }, + { + "Name": "Age", + "Type": "String" + }, + { + "Name": "TaxId", + "Type": "String" + }, + { + "Name": "State", + "Type": "String" + }, + { + "Name": "AccountType", + "Type": "String" + }, + { + "Name": "DeviceName", + "Type": "Dynamic" + }, + { + "Name": "BankNumber", + "Type": "String" + }, + { + "Name": "MobileEquipmentId", + "Type": "String" + }, + { + "Name": "Country", + "Type": "String" + }, + { + "Name": "EducationalInstitution", + "Type": "String" + }, + { + "Name": "JobTitle", + "Type": "String" + }, + { + "Name": "AccountImageUrl", + "Type": "String" + }, + { + "Name": "StudentId", + "Type": "String" + }, + { + "Name": "AccountId", + "Type": "String" + } + ] +} diff --git a/.script/tests/KqlvalidationsTests/CustomTables/SpyCloud_ConditionalAccessLogsV2_CL.json b/.script/tests/KqlvalidationsTests/CustomTables/SpyCloud_ConditionalAccessLogsV2_CL.json new file mode 100644 index 00000000000..35bdc72701a --- /dev/null +++ b/.script/tests/KqlvalidationsTests/CustomTables/SpyCloud_ConditionalAccessLogsV2_CL.json @@ -0,0 +1,61 @@ +{ + "Name": "SpyCloud_ConditionalAccessLogsV2_CL", + "Properties": [ + { + "Name": "TimeGenerated", + "Type": "DateTime" + }, + { + "Name": "IncidentId", + "Type": "String" + }, + { + "Name": "DocumentId", + "Type": "String" + }, + { + "Name": "SpyCloudPublishDate", + "Type": "DateTime" + }, + { + "Name": "InfectedTime", + "Type": "String" + }, + { + "Name": "BreachTitle", + "Type": "String" + }, + { + "Name": "InfectedMachineId", + "Type": "String" + }, + { + "Name": "Username", + "Type": "String" + }, + { + "Name": "UserEmail", + "Type": "String" + }, + { + "Name": "ForcedPasswordResetOnNextSignIn", + "Type": "Boolean" + }, + { + "Name": "UserSessionsRevoked", + "Type": "Boolean" + }, + { + "Name": "CAgroup", + "Type": "Boolean" + }, + { + "Name": "UserDisabled", + "Type": "Boolean" + }, + { + "Name": "PlaybookName", + "Type": "String" + } + ] +} diff --git a/.script/tests/KqlvalidationsTests/CustomTables/Spycloud_MDE_LogsV2_CL.json b/.script/tests/KqlvalidationsTests/CustomTables/Spycloud_MDE_LogsV2_CL.json new file mode 100644 index 00000000000..ea743cc70ce --- /dev/null +++ b/.script/tests/KqlvalidationsTests/CustomTables/Spycloud_MDE_LogsV2_CL.json @@ -0,0 +1,81 @@ +{ + "Name": "Spycloud_MDE_LogsV2_CL", + "Properties": [ + { + "Name": "TimeGenerated", + "Type": "DateTime" + }, + { + "Name": "IncidentId", + "Type": "String" + }, + { + "Name": "DocumentId", + "Type": "String" + }, + { + "Name": "SpyCloudPublishDate", + "Type": "DateTime" + }, + { + "Name": "InfectedTime", + "Type": "String" + }, + { + "Name": "BreachTitle", + "Type": "String" + }, + { + "Name": "InfectedMachineId", + "Type": "String" + }, + { + "Name": "HostName", + "Type": "String" + }, + { + "Name": "NormalizedHostName", + "Type": "String" + }, + { + "Name": "DeviceId", + "Type": "String" + }, + { + "Name": "OSPlatform", + "Type": "String" + }, + { + "Name": "RiskScore", + "Type": "String" + }, + { + "Name": "ExposureLevel", + "Type": "String" + }, + { + "Name": "IsolationRequested", + "Type": "Boolean" + }, + { + "Name": "IsolationStatus", + "Type": "Boolean" + }, + { + "Name": "MachineTagAdded", + "Type": "Boolean" + }, + { + "Name": "MachineTagName", + "Type": "String" + }, + { + "Name": "AddedIOCsToDefender", + "Type": "Boolean" + }, + { + "Name": "PlaybookName", + "Type": "String" + } + ] +} diff --git a/.script/tests/KqlvalidationsTests/CustomTables/spycloud_compassV2_CL.json b/.script/tests/KqlvalidationsTests/CustomTables/spycloud_compassV2_CL.json new file mode 100644 index 00000000000..3460e46f8c7 --- /dev/null +++ b/.script/tests/KqlvalidationsTests/CustomTables/spycloud_compassV2_CL.json @@ -0,0 +1,117 @@ +{ + "Name": "spycloud_compassV2_CL", + "Properties": [ + { + "Name": "TimeGenerated", + "Type": "DateTime" + }, + { + "Name": "SourceId", + "Type": "Int" + }, + { + "Name": "DocumentId", + "Type": "String" + }, + { + "Name": "LogId", + "Type": "String" + }, + { + "Name": "Severity", + "Type": "Int" + }, + { + "Name": "Email", + "Type": "String" + }, + { + "Name": "EmailDomain", + "Type": "String" + }, + { + "Name": "EmailUsername", + "Type": "String" + }, + { + "Name": "Password", + "Type": "String" + }, + { + "Name": "PasswordType", + "Type": "String" + }, + { + "Name": "PasswordPlaintext", + "Type": "String" + }, + { + "Name": "TargetUrl", + "Type": "String" + }, + { + "Name": "TargetDomain", + "Type": "String" + }, + { + "Name": "TargetSubdomain", + "Type": "String" + }, + { + "Name": "InfectedMachineId", + "Type": "String" + }, + { + "Name": "InfectedTime", + "Type": "String" + }, + { + "Name": "InfectedPath", + "Type": "String" + }, + { + "Name": "UserOS", + "Type": "String" + }, + { + "Name": "UserSysRegisteredOwner", + "Type": "String" + }, + { + "Name": "AVSoftwares", + "Type": "Dynamic" + }, + { + "Name": "CountryCode", + "Type": "String" + }, + { + "Name": "DisplayResolution", + "Type": "String" + }, + { + "Name": "IPAddresses", + "Type": "Dynamic" + }, + { + "Name": "TimeZone", + "Type": "String" + }, + { + "Name": "Domain", + "Type": "String" + }, + { + "Name": "SpyCloudPublishDate", + "Type": "String" + }, + { + "Name": "BreachTitle", + "Type": "String" + }, + { + "Name": "BreachCategory", + "Type": "String" + } + ] +} diff --git a/.script/tests/detectionTemplateSchemaValidation/ValidConnectorIds.json b/.script/tests/detectionTemplateSchemaValidation/ValidConnectorIds.json index c7d6dc90898..23a6b5d38f8 100644 --- a/.script/tests/detectionTemplateSchemaValidation/ValidConnectorIds.json +++ b/.script/tests/detectionTemplateSchemaValidation/ValidConnectorIds.json @@ -190,6 +190,7 @@ "SophosCloudOptix", "SophosXGFirewall", "StealthTalkAnomalousAuth", + "SpyCloudEnterpriseProtectionCCF", "SquadraTechnologiesSecRmm", "SquidProxy", "Symantec", diff --git a/Solutions/SpyCloud Enterprise Protection CCF/Analytic Rules/AR_Breached_Users_20.yaml b/Solutions/SpyCloud Enterprise Protection CCF/Analytic Rules/AR_Breached_Users_20.yaml new file mode 100644 index 00000000000..4d9a2384211 --- /dev/null +++ b/Solutions/SpyCloud Enterprise Protection CCF/Analytic Rules/AR_Breached_Users_20.yaml @@ -0,0 +1,44 @@ +id: a25eba0e-ff42-4c97-a379-d76bdb2aa1e3 +name: SpyCloud plaintext credential exposure detected +description: | + 'Identifies user accounts exposed with a plaintext password in a third-party data breach. + Unremediated exposures of this kind can lead directly to account takeover.' +severity: High +requiredDataConnectors: + - connectorId: SpyCloudEnterpriseProtectionCCF + dataTypes: + - SpyCloudBreachWatchlistV2_CL +queryFrequency: 1h +queryPeriod: 2d +triggerOperator: gt +triggerThreshold: 0 +tactics: + - CredentialAccess +relevantTechniques: + - T1589.001 +query: | + // Human-readable constant for the severity threshold used below + let severityThreshold = 20; + SpyCloudBreachWatchlistV2_CL + | where Severity == severityThreshold + | mv-expand IPAddress = IPAddresses to typeof(string) + | extend AccountName = Username, AccountEmail = Email + | project TimeGenerated, DocumentId, SourceId, SpyCloudPublishDate, AccountEmail, + TargetDomain, PasswordPlaintext, AccountName, IPAddress +eventGroupingSettings: + aggregationKind: SingleAlert +entityMappings: + - entityType: Account + fieldMappings: + - identifier: Name + columnName: AccountName + - entityType: IP + fieldMappings: + - identifier: Address + columnName: IPAddress + - entityType: Mailbox + fieldMappings: + - identifier: MailboxPrimaryAddress + columnName: AccountEmail +version: 1.0.0 +kind: scheduled diff --git a/Solutions/SpyCloud Enterprise Protection CCF/Analytic Rules/AR_malware_25.yaml b/Solutions/SpyCloud Enterprise Protection CCF/Analytic Rules/AR_malware_25.yaml new file mode 100644 index 00000000000..6e84a82afd5 --- /dev/null +++ b/Solutions/SpyCloud Enterprise Protection CCF/Analytic Rules/AR_malware_25.yaml @@ -0,0 +1,47 @@ +id: ead4deed-9d48-4646-aee0-6b46c2dd1ae6 +name: SpyCloud infostealer malware credential exposure +description: | + 'Identifies credentials harvested by infostealer malware on a compromised device. This + exposure may indicate an actively compromised endpoint with associated command-and-control + risk.' +severity: High +requiredDataConnectors: + - connectorId: SpyCloudEnterpriseProtectionCCF + dataTypes: + - SpyCloudBreachWatchlistV2_CL +queryFrequency: 1h +queryPeriod: 1d +triggerOperator: gt +triggerThreshold: 0 +tactics: + - CredentialAccess + - CommandAndControl +relevantTechniques: + - T1555 + - T1071 +query: | + // Human-readable constant for the severity threshold used below + let severityThreshold = 25; + SpyCloudBreachWatchlistV2_CL + | where Severity == severityThreshold + | mv-expand IPAddress = IPAddresses to typeof(string) + | extend AccountName = Username, AccountEmail = Email, HostName = UserHostName + | project TimeGenerated, DocumentId, SourceId, SpyCloudPublishDate, AccountEmail, + AccountName, HostName, InfectedMachineId, InfectedTime, UserOS, IPAddress +eventGroupingSettings: + aggregationKind: SingleAlert +entityMappings: + - entityType: Account + fieldMappings: + - identifier: Name + columnName: AccountName + - entityType: Host + fieldMappings: + - identifier: HostName + columnName: HostName + - entityType: IP + fieldMappings: + - identifier: Address + columnName: IPAddress +version: 1.0.0 +kind: scheduled diff --git a/Solutions/SpyCloud Enterprise Protection CCF/Data Connectors/SpyCloudEnterpriseProtectionLogsV2_ccp/SpyCloudEnterpriseProtectionLogsV2_DCR.json b/Solutions/SpyCloud Enterprise Protection CCF/Data Connectors/SpyCloudEnterpriseProtectionLogsV2_ccp/SpyCloudEnterpriseProtectionLogsV2_DCR.json new file mode 100644 index 00000000000..2a23ebc7eb1 --- /dev/null +++ b/Solutions/SpyCloud Enterprise Protection CCF/Data Connectors/SpyCloudEnterpriseProtectionLogsV2_ccp/SpyCloudEnterpriseProtectionLogsV2_DCR.json @@ -0,0 +1,637 @@ +[ + { + "name": "SpyCloudwatchlist-DCR", + "apiVersion": "2021-09-01-preview", + "type": "Microsoft.Insights/dataCollectionRules", + "location": "{{location}}", + "properties": { + "dataCollectionEndpointId": "{{dataCollectionEndpointId}}", + "streamDeclarations": { + "Custom-SpyCloudBreachWatchlistV2_CL": { + "columns": [ + { + "name": "infected_path", + "type": "string" + }, + { + "name": "user_hostname", + "type": "string" + }, + { + "name": "ip_addresses", + "type": "dynamic" + }, + { + "name": "timezone", + "type": "string" + }, + { + "name": "target_url", + "type": "string" + }, + { + "name": "document_id", + "type": "string" + }, + { + "name": "target_domain", + "type": "string" + }, + { + "name": "user_sys_registered_owner", + "type": "string" + }, + { + "name": "display_resolution", + "type": "string" + }, + { + "name": "password", + "type": "string" + }, + { + "name": "email", + "type": "string" + }, + { + "name": "severity", + "type": "int" + }, + { + "name": "av_softwares", + "type": "dynamic" + }, + { + "name": "log_id", + "type": "string" + }, + { + "name": "user_os", + "type": "string" + }, + { + "name": "email_username", + "type": "string" + }, + { + "name": "spycloud_publish_date", + "type": "string" + }, + { + "name": "infected_machine_id", + "type": "string" + }, + { + "name": "password_plaintext", + "type": "string" + }, + { + "name": "infected_time", + "type": "string" + }, + { + "name": "country_code", + "type": "string" + }, + { + "name": "keyboard_languages", + "type": "string" + }, + { + "name": "password_type", + "type": "string" + }, + { + "name": "domain", + "type": "string" + }, + { + "name": "email_domain", + "type": "string" + }, + { + "name": "source_id", + "type": "int" + }, + { + "name": "target_subdomain", + "type": "string" + }, + { + "name": "sighting", + "type": "int" + }, + { + "name": "account_last_activity_time", + "type": "string" + }, + { + "name": "account_notes", + "type": "string" + }, + { + "name": "account_signup_time", + "type": "string" + }, + { + "name": "username", + "type": "string" + }, + { + "name": "homepage", + "type": "string" + }, + { + "name": "salt", + "type": "string" + }, + { + "name": "account_login_time", + "type": "string" + }, + { + "name": "social_other", + "type": "dynamic" + }, + { + "name": "last_name", + "type": "string" + }, + { + "name": "full_name", + "type": "string" + }, + { + "name": "phone", + "type": "string" + }, + { + "name": "first_name", + "type": "string" + }, + { + "name": "address_1", + "type": "string" + }, + { + "name": "account_modification_time", + "type": "string" + }, + { + "name": "gender", + "type": "string" + }, + { + "name": "city", + "type": "string" + }, + { + "name": "birth_year", + "type": "string" + }, + { + "name": "dob", + "type": "string" + }, + { + "name": "company_website", + "type": "string" + }, + { + "name": "industry", + "type": "string" + }, + { + "name": "account_status", + "type": "string" + }, + { + "name": "social_crunchbase", + "type": "dynamic" + }, + { + "name": "company_name", + "type": "string" + }, + { + "name": "social_linkedin", + "type": "dynamic" + }, + { + "name": "social_twitter", + "type": "dynamic" + }, + { + "name": "account_caption", + "type": "string" + }, + { + "name": "address_2", + "type": "string" + }, + { + "name": "ssn_last_four", + "type": "string" + }, + { + "name": "social_security_number", + "type": "string" + }, + { + "name": "health_insurance_id", + "type": "string" + }, + { + "name": "postal_code", + "type": "string" + }, + { + "name": "age", + "type": "string" + }, + { + "name": "taxid", + "type": "string" + }, + { + "name": "state", + "type": "string" + }, + { + "name": "account_type", + "type": "string" + }, + { + "name": "device_name", + "type": "dynamic" + }, + { + "name": "bank_number", + "type": "string" + }, + { + "name": "mobile_equipment_id", + "type": "string" + }, + { + "name": "country", + "type": "string" + }, + { + "name": "educational_institution", + "type": "string" + }, + { + "name": "job_title", + "type": "string" + }, + { + "name": "account_image_url", + "type": "string" + }, + { + "name": "student_id", + "type": "string" + }, + { + "name": "account_id", + "type": "string" + } + ] + }, + "Custom-SpyCloudBreachCatalogV2_CL": { + "columns": [ + { + "name": "id", + "type": "int" + }, + { + "name": "title", + "type": "string" + }, + { + "name": "description", + "type": "string" + }, + { + "name": "status", + "type": "string" + } + ] + }, + "Custom-spycloud_compassV2_CL": { + "columns": [ + { + "name": "source_id", + "type": "int" + }, + { + "name": "document_id", + "type": "string" + }, + { + "name": "log_id", + "type": "string" + }, + { + "name": "severity", + "type": "int" + }, + { + "name": "email", + "type": "string" + }, + { + "name": "email_domain", + "type": "string" + }, + { + "name": "email_username", + "type": "string" + }, + { + "name": "password", + "type": "string" + }, + { + "name": "password_type", + "type": "string" + }, + { + "name": "password_plaintext", + "type": "string" + }, + { + "name": "target_url", + "type": "string" + }, + { + "name": "target_domain", + "type": "string" + }, + { + "name": "target_subdomain", + "type": "string" + }, + { + "name": "infected_machine_id", + "type": "string" + }, + { + "name": "infected_time", + "type": "string" + }, + { + "name": "infected_path", + "type": "string" + }, + { + "name": "user_os", + "type": "string" + }, + { + "name": "user_sys_registered_owner", + "type": "string" + }, + { + "name": "av_softwares", + "type": "dynamic" + }, + { + "name": "country_code", + "type": "string" + }, + { + "name": "display_resolution", + "type": "string" + }, + { + "name": "ip_addresses", + "type": "dynamic" + }, + { + "name": "timezone", + "type": "string" + }, + { + "name": "domain", + "type": "string" + }, + { + "name": "spycloud_publish_date", + "type": "string" + }, + { + "name": "breach_title", + "type": "string" + }, + { + "name": "breach_category", + "type": "string" + } + ] + }, + "Custom-Spycloud_MDE_LogsV2_CL": { + "columns": [ + { + "name": "TimeGenerated", + "type": "datetime" + }, + { + "name": "IncidentId", + "type": "string" + }, + { + "name": "DocumentId", + "type": "string" + }, + { + "name": "SpyCloudPublishDate", + "type": "datetime" + }, + { + "name": "InfectedTime", + "type": "string" + }, + { + "name": "BreachTitle", + "type": "string" + }, + { + "name": "InfectedMachineId", + "type": "string" + }, + { + "name": "HostName", + "type": "string" + }, + { + "name": "NormalizedHostName", + "type": "string" + }, + { + "name": "DeviceId", + "type": "string" + }, + { + "name": "OSPlatform", + "type": "string" + }, + { + "name": "RiskScore", + "type": "string" + }, + { + "name": "ExposureLevel", + "type": "string" + }, + { + "name": "IsolationRequested", + "type": "boolean" + }, + { + "name": "IsolationStatus", + "type": "boolean" + }, + { + "name": "MachineTagAdded", + "type": "boolean" + }, + { + "name": "MachineTagName", + "type": "string" + }, + { + "name": "AddedIOCsToDefender", + "type": "boolean" + }, + { + "name": "PlaybookName", + "type": "string" + } + ] + }, + "Custom-SpyCloud_ConditionalAccessLogsV2_CL": { + "columns": [ + { + "name": "TimeGenerated", + "type": "datetime" + }, + { + "name": "IncidentId", + "type": "string" + }, + { + "name": "DocumentId", + "type": "string" + }, + { + "name": "SpyCloudPublishDate", + "type": "datetime" + }, + { + "name": "InfectedTime", + "type": "string" + }, + { + "name": "BreachTitle", + "type": "string" + }, + { + "name": "InfectedMachineId", + "type": "string" + }, + { + "name": "Username", + "type": "string" + }, + { + "name": "UserEmail", + "type": "string" + }, + { + "name": "ForcedPasswordResetOnNextSignIn", + "type": "boolean" + }, + { + "name": "UserSessionsRevoked", + "type": "boolean" + }, + { + "name": "CAgroup", + "type": "boolean" + }, + { + "name": "UserDisabled", + "type": "boolean" + }, + { + "name": "PlaybookName", + "type": "string" + } + ] + } + }, + "destinations": { + "logAnalytics": [ + { + "workspaceResourceId": "{{workspaceResourceId}}", + "name": "clv2ws1" + } + ] + }, + "dataFlows": [ + { + "streams": [ + "Custom-SpyCloudBreachWatchlistV2_CL" + ], + "destinations": [ + "clv2ws1" + ], + "transformKql": "source\n| extend TimeGenerated = now()\n| project-rename InfectedPath = infected_path, UserHostName = user_hostname, IPAddresses = ip_addresses, TimeZone = timezone, TargetUrl = target_url, DocumentId = document_id, TargetDomain = target_domain, UserSysRegisteredOwner = user_sys_registered_owner, DisplayResolution = display_resolution, Password = password, Email = email, Severity = severity, AVSoftwares = av_softwares, LogId = log_id, UserOS = user_os, EmailUsername = email_username, SpyCloudPublishDate = spycloud_publish_date, InfectedMachineId = infected_machine_id, PasswordPlaintext = password_plaintext, InfectedTime = infected_time, CountryCode = country_code, KeyboardLanguages = keyboard_languages, PasswordType = password_type, Domain = domain, EmailDomain = email_domain, SourceId = source_id, TargetSubdomain = target_subdomain, Sighting = sighting, AccountLastActivityTime = account_last_activity_time, AccountNotes = account_notes, AccountSignupTime = account_signup_time, Username = username, Homepage = homepage, Salt = salt, AccountLoginTime = account_login_time, SocialOther = social_other, LastName = last_name, FullName = full_name, Phone = phone, FirstName = first_name, Address1 = address_1, AccountModificationTime = account_modification_time, Gender = gender, City = city, BirthYear = birth_year, DOB = dob, CompanyWebsite = company_website, Industry = industry, AccountStatus = account_status, SocialCrunchbase = social_crunchbase, CompanyName = company_name, SocialLinkedIn = social_linkedin, SocialTwitter = social_twitter, AccountCaption = account_caption, Address2 = address_2, SSNLastFour = ssn_last_four, SocialSecurityNumber = social_security_number, HealthInsuranceId = health_insurance_id, PostalCode = postal_code, Age = age, TaxId = taxid, State = state, AccountType = account_type, DeviceName = device_name, BankNumber = bank_number, MobileEquipmentId = mobile_equipment_id, Country = country, EducationalInstitution = educational_institution, JobTitle = job_title, AccountImageUrl = account_image_url, StudentId = student_id, AccountId = account_id\n", + "outputStream": "Custom-SpyCloudBreachWatchlistV2_CL" + }, + { + "streams": [ + "Custom-SpyCloudBreachCatalogV2_CL" + ], + "destinations": [ + "clv2ws1" + ], + "transformKql": "source\n| extend TimeGenerated = now()\n| project-rename SourceId = id, BreachTitle = title, Description = description, Status = status\n| project TimeGenerated, SourceId, BreachTitle, Description, Status\n", + "outputStream": "Custom-SpyCloudBreachCatalogV2_CL" + }, + { + "streams": [ + "Custom-spycloud_compassV2_CL" + ], + "destinations": [ + "clv2ws1" + ], + "transformKql": "source\n| extend TimeGenerated = now()\n| project-rename SourceId = source_id, DocumentId = document_id, LogId = log_id, Severity = severity, Email = email, EmailDomain = email_domain, EmailUsername = email_username, Password = password, PasswordType = password_type, PasswordPlaintext = password_plaintext, TargetUrl = target_url, TargetDomain = target_domain, TargetSubdomain = target_subdomain, InfectedMachineId = infected_machine_id, InfectedTime = infected_time, InfectedPath = infected_path, UserOS = user_os, UserSysRegisteredOwner = user_sys_registered_owner, AVSoftwares = av_softwares, CountryCode = country_code, DisplayResolution = display_resolution, IPAddresses = ip_addresses, TimeZone = timezone, Domain = domain, SpyCloudPublishDate = spycloud_publish_date, BreachTitle = breach_title, BreachCategory = breach_category\n", + "outputStream": "Custom-spycloud_compassV2_CL" + }, + { + "streams": [ + "Custom-Spycloud_MDE_LogsV2_CL" + ], + "destinations": [ + "clv2ws1" + ], + "transformKql": "source\n| extend\n TimeGenerated = todatetime(TimeGenerated),\n IncidentId = tostring(IncidentId),\n DocumentId = tostring(DocumentId),\n SpyCloudPublishDate = todatetime(SpyCloudPublishDate),\n InfectedTime = tostring(InfectedTime),\n BreachTitle = tostring(BreachTitle),\n InfectedMachineId = tostring(InfectedMachineId),\n HostName = tostring(HostName),\n NormalizedHostName = tostring(NormalizedHostName),\n DeviceId = tostring(DeviceId),\n OSPlatform = tostring(OSPlatform),\n RiskScore = tostring(RiskScore),\n ExposureLevel = tostring(ExposureLevel),\n IsolationRequested = tobool(IsolationRequested),\n IsolationStatus = tobool(IsolationStatus),\n MachineTagAdded = tobool(MachineTagAdded),\n MachineTagName = tostring(MachineTagName),\n AddedIOCsToDefender = tobool(AddedIOCsToDefender),\n PlaybookName = tostring(PlaybookName)\n| project\n TimeGenerated,\n IncidentId,\n DocumentId,\n SpyCloudPublishDate,\n InfectedTime,\n BreachTitle,\n InfectedMachineId,\n HostName,\n NormalizedHostName,\n DeviceId,\n OSPlatform,\n RiskScore,\n ExposureLevel,\n IsolationRequested,\n IsolationStatus,\n MachineTagAdded,\n MachineTagName,\n AddedIOCsToDefender,\n PlaybookName\n", + "outputStream": "Custom-Spycloud_MDE_LogsV2_CL" + }, + { + "streams": [ + "Custom-SpyCloud_ConditionalAccessLogsV2_CL" + ], + "destinations": [ + "clv2ws1" + ], + "transformKql": "source\n| extend\n TimeGenerated = todatetime(TimeGenerated),\n IncidentId = tostring(IncidentId),\n DocumentId = tostring(DocumentId),\n SpyCloudPublishDate = todatetime(SpyCloudPublishDate),\n InfectedTime = tostring(InfectedTime),\n BreachTitle = tostring(BreachTitle),\n InfectedMachineId = tostring(InfectedMachineId),\n Username = tostring(Username),\n UserEmail = tostring(UserEmail),\n ForcedPasswordResetOnNextSignIn = tobool(ForcedPasswordResetOnNextSignIn),\n UserSessionsRevoked = tobool(UserSessionsRevoked),\n CAgroup = tobool(CAgroup),\n UserDisabled = tobool(UserDisabled),\n PlaybookName = tostring(PlaybookName)\n| project\n TimeGenerated,\n IncidentId,\n DocumentId,\n SpyCloudPublishDate,\n InfectedTime,\n BreachTitle,\n InfectedMachineId,\n Username,\n UserEmail,\n ForcedPasswordResetOnNextSignIn,\n UserSessionsRevoked,\n CAgroup,\n UserDisabled,\n PlaybookName\n", + "outputStream": "Custom-SpyCloud_ConditionalAccessLogsV2_CL" + } + ] + } + } +] \ No newline at end of file diff --git a/Solutions/SpyCloud Enterprise Protection CCF/Data Connectors/SpyCloudEnterpriseProtectionLogsV2_ccp/SpyCloudEnterpriseProtectionLogsV2_PollerConfig.json b/Solutions/SpyCloud Enterprise Protection CCF/Data Connectors/SpyCloudEnterpriseProtectionLogsV2_ccp/SpyCloudEnterpriseProtectionLogsV2_PollerConfig.json new file mode 100644 index 00000000000..b37c3e0871e --- /dev/null +++ b/Solutions/SpyCloud Enterprise Protection CCF/Data Connectors/SpyCloudEnterpriseProtectionLogsV2_ccp/SpyCloudEnterpriseProtectionLogsV2_PollerConfig.json @@ -0,0 +1,246 @@ +[ + { + "type": "Microsoft.SecurityInsights/dataConnectors", + "apiVersion": "2023-02-01-preview", + "name": "SpyCloudWatchlistConnector", + "kind": "RestApiPoller", + "location": "{{location}}", + "properties": { + "connectorDefinitionName": "SpyCloudEnterpriseProtectionCCF", + "dcrConfig": { + "streamName": "Custom-SpyCloudBreachWatchlistV2_CL" + }, + "dataType": "SpyCloudBreachWatchlistV2_CL", + "auth": { + "type": "APIKey", + "ApiKeyName": "X-API-KEY", + "ApiKey": "{{apiKey}}" + }, + "request": { + "apiEndpoint": "https://api.spycloud.io/enterprise-v2/breach/data/watchlist", + "httpMethod": "GET", + "rateLimitQPS": 2, + "queryTimeFormat": "yyyy-MM-ddTHH:mm:ssZ", + "startTimeAttributeName": "since", + "queryWindowInMin": 60, + "headers": { + "Accept": "application/json", + "User-Agent": "spycloud_microsoftccf/1.0.0" + }, + "queryParameters": { + "severity": "{{severity}}" + }, + "retryCount": 3, + "timeoutInSeconds": 60 + }, + "response": { + "eventsJsonPaths": [ + "$.results[*]" + ], + "format": "json" + }, + "paging": { + "pagingType": "NextPageToken", + "nextPageTokenJsonPath": "$.cursor", + "nextPageParaName": "cursor", + "pagingInfoPlacement": "QueryString" + }, + "isActive": true + } + }, + { + "type": "Microsoft.SecurityInsights/dataConnectors", + "apiVersion": "2023-02-01-preview", + "name": "SpyCloudWatchlistConnectorModified", + "kind": "RestApiPoller", + "location": "{{location}}", + "properties": { + "connectorDefinitionName": "SpyCloudEnterpriseProtectionCCF", + "dcrConfig": { + "streamName": "Custom-SpyCloudBreachWatchlistV2_CL" + }, + "dataType": "SpyCloudBreachWatchlistV2_CL", + "auth": { + "type": "APIKey", + "ApiKeyName": "X-API-KEY", + "ApiKey": "{{apiKey}}" + }, + "request": { + "apiEndpoint": "https://api.spycloud.io/enterprise-v2/breach/data/watchlist", + "httpMethod": "GET", + "rateLimitQPS": 2, + "queryTimeFormat": "yyyy-MM-dd", + "queryWindowInMin": 60, + "headers": { + "Accept": "application/json", + "User-Agent": "spycloud_microsoftccf/1.0.0" + }, + "queryParameters": { + "since_modification_date": "{_QueryWindowStartTime}", + "until_modification_date": "{_QueryWindowStartTime}", + "severity": "{{severity}}" + }, + "retryCount": 3, + "timeoutInSeconds": 60 + }, + "response": { + "eventsJsonPaths": [ + "$.results[*]" + ], + "format": "json" + }, + "paging": { + "pagingType": "NextPageToken", + "nextPageTokenJsonPath": "$.cursor", + "nextPageParaName": "cursor", + "pagingInfoPlacement": "QueryString" + }, + "isActive": true + } + }, + { + "type": "Microsoft.SecurityInsights/dataConnectors", + "apiVersion": "2023-02-01-preview", + "name": "SpyCloudUsernameConnector", + "kind": "RestApiPoller", + "location": "{{location}}", + "properties": { + "connectorDefinitionName": "SpyCloudEnterpriseProtectionCCF", + "dcrConfig": { + "streamName": "Custom-SpyCloudBreachWatchlistV2_CL" + }, + "dataType": "SpyCloudBreachWatchlistV2_CL", + "auth": { + "type": "APIKey", + "ApiKeyName": "X-API-KEY", + "ApiKey": "{{apiKey}}" + }, + "request": { + "apiEndpoint": "https://api.spycloud.io/enterprise-v2/breach/data/usernames/username", + "httpMethod": "GET", + "rateLimitQPS": 2, + "queryTimeFormat": "yyyy-MM-dd", + "queryWindowInMin": 60, + "headers": { + "Accept": "application/json", + "User-Agent": "spycloud_microsoftccf/1.0.0" + }, + "queryParameters": { + "since_modification_date": "{_QueryWindowStartTime}", + "until_modification_date": "{_QueryWindowStartTime}" + }, + "retryCount": 3, + "timeoutInSeconds": 60 + }, + "response": { + "eventsJsonPaths": [ + "$.results[*]" + ], + "format": "json" + }, + "paging": { + "pagingType": "NextPageToken", + "nextPageTokenJsonPath": "$.cursor", + "nextPageParaName": "cursor", + "pagingInfoPlacement": "QueryString" + }, + "isActive": true + } + }, + { + "type": "Microsoft.SecurityInsights/dataConnectors", + "apiVersion": "2023-02-01-preview", + "name": "SpyCloudBreachCatalogConnector", + "kind": "RestApiPoller", + "location": "{{location}}", + "properties": { + "connectorDefinitionName": "SpyCloudEnterpriseProtectionCCF", + "dcrConfig": { + "streamName": "Custom-SpyCloudBreachCatalogV2_CL" + }, + "dataType": "SpyCloudBreachCatalogV2_CL", + "auth": { + "type": "APIKey", + "ApiKeyName": "X-API-KEY", + "ApiKey": "{{apiKey}}" + }, + "request": { + "apiEndpoint": "https://api.spycloud.io/enterprise-v2/breach/catalog", + "httpMethod": "GET", + "rateLimitQPS": 2, + "queryTimeFormat": "yyyy-MM-ddTHH:mm:ssZ", + "startTimeAttributeName": "since", + "queryWindowInMin": 60, + "headers": { + "Accept": "application/json", + "User-Agent": "spycloud_microsoftccf/1.0.0" + }, + "retryCount": 3, + "timeoutInSeconds": 60 + }, + "response": { + "eventsJsonPaths": [ + "$.results[*]" + ], + "format": "json" + }, + "paging": { + "pagingType": "NextPageToken", + "nextPageTokenJsonPath": "$.cursor", + "nextPageParaName": "cursor", + "pagingInfoPlacement": "QueryString" + }, + "isActive": true + } + }, + { + "condition": "[[equals(parameters('compassEnabled'),'true')]", + "type": "Microsoft.SecurityInsights/dataConnectors", + "apiVersion": "2023-02-01-preview", + "name": "SpyCloudCompassConnector", + "kind": "RestApiPoller", + "location": "{{location}}", + "properties": { + "connectorDefinitionName": "SpyCloudEnterpriseProtectionCCF", + "dcrConfig": { + "streamName": "Custom-spycloud_compassV2_CL" + }, + "dataType": "spycloud_compassV2_CL", + "auth": { + "type": "APIKey", + "ApiKeyName": "X-API-KEY", + "ApiKey": "{{apiKey}}" + }, + "request": { + "apiEndpoint": "https://api.spycloud.io/enterprise-v2/compass/data", + "httpMethod": "GET", + "rateLimitQPS": 1, + "queryTimeFormat": "yyyy-MM-dd", + "startTimeAttributeName": "since", + "queryWindowInMin": 1440, + "headers": { + "Accept": "application/json", + "User-Agent": "spycloud_microsoftccf/1.0.0" + }, + "queryParameters": { + "until": "{_QueryWindowStartTime}" + }, + "retryCount": 3, + "timeoutInSeconds": 60 + }, + "response": { + "eventsJsonPaths": [ + "$.results[*]" + ], + "format": "json" + }, + "paging": { + "pagingType": "NextPageToken", + "nextPageTokenJsonPath": "$.cursor", + "nextPageParaName": "cursor", + "pagingInfoPlacement": "QueryString" + }, + "isActive": true + } + } +] \ No newline at end of file diff --git a/Solutions/SpyCloud Enterprise Protection CCF/Data Connectors/SpyCloudEnterpriseProtectionLogsV2_ccp/SpyCloudEnterpriseProtectionLogsV2_Tables.json b/Solutions/SpyCloud Enterprise Protection CCF/Data Connectors/SpyCloudEnterpriseProtectionLogsV2_ccp/SpyCloudEnterpriseProtectionLogsV2_Tables.json new file mode 100644 index 00000000000..ef84ec3ef6b --- /dev/null +++ b/Solutions/SpyCloud Enterprise Protection CCF/Data Connectors/SpyCloudEnterpriseProtectionLogsV2_ccp/SpyCloudEnterpriseProtectionLogsV2_Tables.json @@ -0,0 +1,618 @@ +[ + { + "name": "SpyCloudBreachWatchlistV2_CL", + "type": "Microsoft.OperationalInsights/workspaces/tables", + "apiVersion": "2021-03-01-privatepreview", + "properties": { + "schema": { + "name": "SpyCloudBreachWatchlistV2_CL", + "columns": [ + { + "name": "TimeGenerated", + "type": "datetime" + }, + { + "name": "InfectedPath", + "type": "string" + }, + { + "name": "UserHostName", + "type": "string" + }, + { + "name": "IPAddresses", + "type": "dynamic" + }, + { + "name": "TimeZone", + "type": "string" + }, + { + "name": "TargetUrl", + "type": "string" + }, + { + "name": "DocumentId", + "type": "string" + }, + { + "name": "TargetDomain", + "type": "string" + }, + { + "name": "UserSysRegisteredOwner", + "type": "string" + }, + { + "name": "DisplayResolution", + "type": "string" + }, + { + "name": "Password", + "type": "string" + }, + { + "name": "Email", + "type": "string" + }, + { + "name": "Severity", + "type": "int" + }, + { + "name": "AVSoftwares", + "type": "dynamic" + }, + { + "name": "LogId", + "type": "string" + }, + { + "name": "UserOS", + "type": "string" + }, + { + "name": "EmailUsername", + "type": "string" + }, + { + "name": "SpyCloudPublishDate", + "type": "string" + }, + { + "name": "InfectedMachineId", + "type": "string" + }, + { + "name": "PasswordPlaintext", + "type": "string" + }, + { + "name": "InfectedTime", + "type": "string" + }, + { + "name": "CountryCode", + "type": "string" + }, + { + "name": "KeyboardLanguages", + "type": "string" + }, + { + "name": "PasswordType", + "type": "string" + }, + { + "name": "Domain", + "type": "string" + }, + { + "name": "EmailDomain", + "type": "string" + }, + { + "name": "SourceId", + "type": "int" + }, + { + "name": "TargetSubdomain", + "type": "string" + }, + { + "name": "Sighting", + "type": "int" + }, + { + "name": "AccountLastActivityTime", + "type": "string" + }, + { + "name": "AccountNotes", + "type": "string" + }, + { + "name": "AccountSignupTime", + "type": "string" + }, + { + "name": "Username", + "type": "string" + }, + { + "name": "Homepage", + "type": "string" + }, + { + "name": "Salt", + "type": "string" + }, + { + "name": "AccountLoginTime", + "type": "string" + }, + { + "name": "SocialOther", + "type": "dynamic" + }, + { + "name": "LastName", + "type": "string" + }, + { + "name": "FullName", + "type": "string" + }, + { + "name": "Phone", + "type": "string" + }, + { + "name": "FirstName", + "type": "string" + }, + { + "name": "Address1", + "type": "string" + }, + { + "name": "AccountModificationTime", + "type": "string" + }, + { + "name": "Gender", + "type": "string" + }, + { + "name": "City", + "type": "string" + }, + { + "name": "BirthYear", + "type": "string" + }, + { + "name": "DOB", + "type": "string" + }, + { + "name": "CompanyWebsite", + "type": "string" + }, + { + "name": "Industry", + "type": "string" + }, + { + "name": "AccountStatus", + "type": "string" + }, + { + "name": "SocialCrunchbase", + "type": "dynamic" + }, + { + "name": "CompanyName", + "type": "string" + }, + { + "name": "SocialLinkedIn", + "type": "dynamic" + }, + { + "name": "SocialTwitter", + "type": "dynamic" + }, + { + "name": "AccountCaption", + "type": "string" + }, + { + "name": "Address2", + "type": "string" + }, + { + "name": "SSNLastFour", + "type": "string" + }, + { + "name": "SocialSecurityNumber", + "type": "string" + }, + { + "name": "HealthInsuranceId", + "type": "string" + }, + { + "name": "PostalCode", + "type": "string" + }, + { + "name": "Age", + "type": "string" + }, + { + "name": "TaxId", + "type": "string" + }, + { + "name": "State", + "type": "string" + }, + { + "name": "AccountType", + "type": "string" + }, + { + "name": "DeviceName", + "type": "dynamic" + }, + { + "name": "BankNumber", + "type": "string" + }, + { + "name": "MobileEquipmentId", + "type": "string" + }, + { + "name": "Country", + "type": "string" + }, + { + "name": "EducationalInstitution", + "type": "string" + }, + { + "name": "JobTitle", + "type": "string" + }, + { + "name": "AccountImageUrl", + "type": "string" + }, + { + "name": "StudentId", + "type": "string" + }, + { + "name": "AccountId", + "type": "string" + } + ] + } + } + }, + { + "name": "SpyCloudBreachCatalogV2_CL", + "type": "Microsoft.OperationalInsights/workspaces/tables", + "apiVersion": "2021-03-01-privatepreview", + "properties": { + "schema": { + "name": "SpyCloudBreachCatalogV2_CL", + "columns": [ + { + "name": "TimeGenerated", + "type": "datetime" + }, + { + "name": "SourceId", + "type": "int" + }, + { + "name": "BreachTitle", + "type": "string" + }, + { + "name": "Description", + "type": "string" + }, + { + "name": "Status", + "type": "string" + } + ] + } + } + }, + { + "name": "spycloud_compassV2_CL", + "type": "Microsoft.OperationalInsights/workspaces/tables", + "apiVersion": "2021-03-01-privatepreview", + "properties": { + "schema": { + "name": "spycloud_compassV2_CL", + "columns": [ + { + "name": "TimeGenerated", + "type": "datetime" + }, + { + "name": "SourceId", + "type": "int" + }, + { + "name": "DocumentId", + "type": "string" + }, + { + "name": "LogId", + "type": "string" + }, + { + "name": "Severity", + "type": "int" + }, + { + "name": "Email", + "type": "string" + }, + { + "name": "EmailDomain", + "type": "string" + }, + { + "name": "EmailUsername", + "type": "string" + }, + { + "name": "Password", + "type": "string" + }, + { + "name": "PasswordType", + "type": "string" + }, + { + "name": "PasswordPlaintext", + "type": "string" + }, + { + "name": "TargetUrl", + "type": "string" + }, + { + "name": "TargetDomain", + "type": "string" + }, + { + "name": "TargetSubdomain", + "type": "string" + }, + { + "name": "InfectedMachineId", + "type": "string" + }, + { + "name": "InfectedTime", + "type": "string" + }, + { + "name": "InfectedPath", + "type": "string" + }, + { + "name": "UserOS", + "type": "string" + }, + { + "name": "UserSysRegisteredOwner", + "type": "string" + }, + { + "name": "AVSoftwares", + "type": "dynamic" + }, + { + "name": "CountryCode", + "type": "string" + }, + { + "name": "DisplayResolution", + "type": "string" + }, + { + "name": "IPAddresses", + "type": "dynamic" + }, + { + "name": "TimeZone", + "type": "string" + }, + { + "name": "Domain", + "type": "string" + }, + { + "name": "SpyCloudPublishDate", + "type": "string" + }, + { + "name": "BreachTitle", + "type": "string" + }, + { + "name": "BreachCategory", + "type": "string" + } + ] + } + } + }, + { + "name": "Spycloud_MDE_LogsV2_CL", + "type": "Microsoft.OperationalInsights/workspaces/tables", + "apiVersion": "2021-03-01-privatepreview", + "properties": { + "schema": { + "name": "Spycloud_MDE_LogsV2_CL", + "columns": [ + { + "name": "TimeGenerated", + "type": "datetime" + }, + { + "name": "IncidentId", + "type": "string" + }, + { + "name": "DocumentId", + "type": "string" + }, + { + "name": "SpyCloudPublishDate", + "type": "datetime" + }, + { + "name": "InfectedTime", + "type": "string" + }, + { + "name": "BreachTitle", + "type": "string" + }, + { + "name": "InfectedMachineId", + "type": "string" + }, + { + "name": "HostName", + "type": "string" + }, + { + "name": "NormalizedHostName", + "type": "string" + }, + { + "name": "DeviceId", + "type": "string" + }, + { + "name": "OSPlatform", + "type": "string" + }, + { + "name": "RiskScore", + "type": "string" + }, + { + "name": "ExposureLevel", + "type": "string" + }, + { + "name": "IsolationRequested", + "type": "boolean" + }, + { + "name": "IsolationStatus", + "type": "boolean" + }, + { + "name": "MachineTagAdded", + "type": "boolean" + }, + { + "name": "MachineTagName", + "type": "string" + }, + { + "name": "AddedIOCsToDefender", + "type": "boolean" + }, + { + "name": "PlaybookName", + "type": "string" + } + ] + } + } + }, + { + "name": "SpyCloud_ConditionalAccessLogsV2_CL", + "type": "Microsoft.OperationalInsights/workspaces/tables", + "apiVersion": "2021-03-01-privatepreview", + "properties": { + "schema": { + "name": "SpyCloud_ConditionalAccessLogsV2_CL", + "columns": [ + { + "name": "TimeGenerated", + "type": "datetime" + }, + { + "name": "IncidentId", + "type": "string" + }, + { + "name": "DocumentId", + "type": "string" + }, + { + "name": "SpyCloudPublishDate", + "type": "datetime" + }, + { + "name": "InfectedTime", + "type": "string" + }, + { + "name": "BreachTitle", + "type": "string" + }, + { + "name": "InfectedMachineId", + "type": "string" + }, + { + "name": "Username", + "type": "string" + }, + { + "name": "UserEmail", + "type": "string" + }, + { + "name": "ForcedPasswordResetOnNextSignIn", + "type": "boolean" + }, + { + "name": "UserSessionsRevoked", + "type": "boolean" + }, + { + "name": "CAgroup", + "type": "boolean" + }, + { + "name": "UserDisabled", + "type": "boolean" + }, + { + "name": "PlaybookName", + "type": "string" + } + ] + } + } + } +] \ No newline at end of file diff --git a/Solutions/SpyCloud Enterprise Protection CCF/Data Connectors/SpyCloudEnterpriseProtectionLogsV2_ccp/SpyCloudEnterpriseProtectionLogsV2_connectorDefinition.json b/Solutions/SpyCloud Enterprise Protection CCF/Data Connectors/SpyCloudEnterpriseProtectionLogsV2_ccp/SpyCloudEnterpriseProtectionLogsV2_connectorDefinition.json new file mode 100644 index 00000000000..c3f343cdff1 --- /dev/null +++ b/Solutions/SpyCloud Enterprise Protection CCF/Data Connectors/SpyCloudEnterpriseProtectionLogsV2_ccp/SpyCloudEnterpriseProtectionLogsV2_connectorDefinition.json @@ -0,0 +1,144 @@ +{ + "type": "Microsoft.SecurityInsights/dataConnectorDefinitions", + "apiVersion": "2022-09-01-preview", + "name": "SpyCloudEnterpriseProtectionCCF", + "location": "{{location}}", + "kind": "Customizable", + "properties": { + "connectorUiConfig": { + "id": "SpyCloudEnterpriseProtectionCCF", + "title": "SpyCloud Enterprise Protection Connector", + "publisher": "SpyCloud", + "descriptionMarkdown": "Ingests SpyCloud Watchlist exposure data into Microsoft Sentinel, including compromised credentials and infected machine records associated with monitored assets. Also includes SpyCloud breach catalog metadata for contextual enrichment and correlation.", + "graphQueriesTableName": "SpyCloudBreachWatchlistV2_CL", + "graphQueries": [ + { + "metricName": "Total Watchlist", + "legend": "SpyCloud Watchlist", + "baseQuery": "{{graphQueriesTableName}}" + } + ], + "sampleQueries": [ + { + "description": "All Watchlists", + "query": "{{graphQueriesTableName}}\n| sort by TimeGenerated desc" + } + ], + "dataTypes": [ + { + "name": "{{graphQueriesTableName}}", + "lastDataReceivedQuery": "{{graphQueriesTableName}}\n |summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + } + ], + "connectivityCriteria": [ + { + "type": "HasDataConnectors" + } + ], + "availability": { + "isPreview": false + }, + "permissions": { + "resourceProvider": [ + { + "provider": "Microsoft.OperationalInsights/workspaces", + "permissionsDisplayText": "Read and write permissions are required to ingest data into the Log Analytics workspace.", + "providerDisplayName": "Workspace", + "scope": "Workspace", + "requiredPermissions": { + "read": true, + "write": true, + "delete": true + } + } + ], + "customs": [ + { + "name": "Microsoft Sentinel Contributor", + "description": "Microsoft Sentinel Contributor role is required to manage data connectors." + } + ] + }, + "instructionSteps": [ + { + "title": "Configure SpyCloud API", + "description": "Enter your SpyCloud API key.", + "instructions": [ + { + "type": "Textbox", + "parameters": { + "label": "API Key", + "name": "apiKey", + "type": "password", + "placeholder": "Enter your SpyCloud API Key", + "validations": { + "required": true + } + } + }, + { + "type": "Dropdown", + "parameters": { + "label": "Severity", + "name": "severity", + "options": [ + { + "key": "2", + "text": "2" + }, + { + "key": "5", + "text": "5" + }, + { + "key": "20", + "text": "20" + }, + { + "key": "25", + "text": "25" + }, + { + "key": "30", + "text": "30" + } + ], + "placeholder": "You can Select Multiple Severity", + "isMultiSelect": true, + "required": true, + "defaultAllSelected": false + } + }, + { + "type": "Dropdown", + "parameters": { + "label": "Ingest Compass Data (once daily, yesterday data)", + "name": "compassEnabled", + "options": [ + { + "key": "true", + "text": "On" + }, + { + "key": "false", + "text": "Off" + } + ], + "placeholder": "Enable or disable Compass ingestion", + "isMultiSelect": false, + "required": true + } + }, + { + "type": "ConnectionToggleButton", + "parameters": { + "connectLabel": "connect", + "name": "toggle" + } + } + ] + } + ] + } + } +} \ No newline at end of file diff --git a/Solutions/SpyCloud Enterprise Protection CCF/Data/Solution_SpyCloudEnterpriseProtection.json b/Solutions/SpyCloud Enterprise Protection CCF/Data/Solution_SpyCloudEnterpriseProtection.json new file mode 100644 index 00000000000..169411ab7db --- /dev/null +++ b/Solutions/SpyCloud Enterprise Protection CCF/Data/Solution_SpyCloudEnterpriseProtection.json @@ -0,0 +1,27 @@ +{ + "Name": "SpyCloud Enterprise Protection CCF", + "Author": "SpyCloud - support@spycloud.com", + "Logo": "", + "Description": "The [SpyCloud Enterprise Protection](https://spycloud.com/) solution for Microsoft Sentinel ingests SpyCloud breach watchlist and catalog data via the Codeless Connector Framework (CCF), including an optional Compass daily feed. The solution includes two built-in analytic rules, two KQL parsers, and two automation playbooks for Microsoft Defender for Endpoint and Azure AD / Entra ID Conditional Access response.\r\n\r\n**Underlying Microsoft Technologies used:**\r\n\r\nThis solution takes a dependency on the following technologies, and some of these dependencies either may be in [Preview](https://azure.microsoft.com/support/legal/preview-supplemental-terms/) state or might result in additional ingestion or operational costs:\r\n\n a. [Codeless Connector Framework (CCF)](https://learn.microsoft.com/en-us/azure/sentinel/create-codeless-connector)\r\n\n b. [Azure Logic Apps](https://azure.microsoft.com/services/logic-apps/)\r\n\n c. [Microsoft Defender for Endpoint](https://www.microsoft.com/en-us/security/business/endpoint-security/microsoft-defender-endpoint)", + "Analytic Rules": [ + "Analytic Rules/AR_Breached_Users_20.yaml", + "Analytic Rules/AR_malware_25.yaml" + ], + "Data Connectors": [ + "Data Connectors/SpyCloudEnterpriseProtectionLogsV2_ccp/SpyCloudEnterpriseProtectionLogsV2_connectorDefinition.json" + ], + "Parsers": [ + "Parsers/get_Spycloud_enriched_data.yaml", + "Parsers/get_spycloud_compass_data.yaml" + ], + "Playbooks": [ + "Playbooks/SpyCloud_MDE_Automation/azuredeploy.json", + "Playbooks/SpyCloud_Conditional_Access_Playbook/azuredeploy.json", + "Playbooks/SpyCloud_AutomationRules/azuredeploy.json" + ], + "Metadata": "SolutionMetadata.json", + "BasePath": "C:\\GitHub\\Azure-Sentinel\\Solutions\\SpyCloud Enterprise ProtectionV2\\", + "Version": "3.0.0", + "TemplateSpec": true, + "Is1PConnector": false +} \ No newline at end of file diff --git a/Solutions/SpyCloud Enterprise Protection CCF/Package/3.0.0.zip b/Solutions/SpyCloud Enterprise Protection CCF/Package/3.0.0.zip new file mode 100644 index 0000000000000000000000000000000000000000..6979a834168bfffbba9053c557eb977500b90d7b GIT binary patch literal 26266 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
V%p=*5Ui4|<-DRzEHX7ykLz$Pme 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\n\n**Note:** Please refer to the following before installing the solution: \n\n• Review the solution [Release Notes](https://github.com/Azure/Azure-Sentinel/tree/master/Solutions/SpyCloud%20Enterprise%20Protection%20CCF/ReleaseNotes.md)\n\n • There may be [known issues](https://aka.ms/sentinelsolutionsknownissues) pertaining to this Solution, please refer to them before installing.\n\nThe [SpyCloud Enterprise Protection](https://spycloud.com/) solution for Microsoft Sentinel ingests SpyCloud breach watchlist and catalog data via the Codeless Connector Framework (CCF), including an optional Compass daily feed. The solution includes two built-in analytic rules, two KQL parsers, and two automation playbooks for Microsoft Defender for Endpoint and Azure AD / Entra ID Conditional Access response.\r\n\r\n**Underlying Microsoft Technologies used:**\r\n\r\nThis solution takes a dependency on the following technologies, and some of these dependencies either may be in [Preview](https://azure.microsoft.com/support/legal/preview-supplemental-terms/) state or might result in additional ingestion or operational costs:\r\n\n a. [Codeless Connector Framework (CCF)](https://learn.microsoft.com/en-us/azure/sentinel/create-codeless-connector)\r\n\n b. [Azure Logic Apps](https://azure.microsoft.com/services/logic-apps/)\r\n\n c. [Microsoft Defender for Endpoint](https://www.microsoft.com/en-us/security/business/endpoint-security/microsoft-defender-endpoint)\n\n**Data Connectors:** 1, **Parsers:** 2, **Analytic Rules:** 2, **Playbooks:** 3\n\n[Learn more about Microsoft Sentinel](https://aka.ms/azuresentinel) | [Learn more about Solutions](https://aka.ms/azuresentinelsolutionsdoc)", + "subscription": { + "resourceProviders": [ + "Microsoft.OperationsManagement/solutions", + "Microsoft.OperationalInsights/workspaces/providers/alertRules", + "Microsoft.Insights/workbooks", + "Microsoft.Logic/workflows" + ] + }, + "location": { + "metadata": { + "hidden": "Hiding location, we get it from the log analytics workspace" + }, + "visible": false + }, + "resourceGroup": { + "allowExisting": true + } + } + }, + "basics": [ + { + "name": "getLAWorkspace", + "type": "Microsoft.Solutions.ArmApiControl", + "toolTip": "This filters by workspaces that exist in the Resource Group selected", + "condition": "[greater(length(resourceGroup().name),0)]", + "request": { + "method": "GET", + "path": "[concat(subscription().id,'/providers/Microsoft.OperationalInsights/workspaces?api-version=2020-08-01')]" + } + }, + { + "name": "workspace", + "type": "Microsoft.Common.DropDown", + "label": "Workspace", + "placeholder": "Select a workspace", + "toolTip": "This dropdown will list only workspace that exists in the Resource Group selected", + "constraints": { + "allowedValues": "[map(filter(basics('getLAWorkspace').value, (filter) => contains(toLower(filter.id), toLower(resourceGroup().name))), (item) => parse(concat('{\"label\":\"', item.name, '\",\"value\":\"', item.name, '\"}')))]", + "required": true + }, + "visible": true + } + ], + "steps": [ + { + "name": "dataconnectors", + "label": "Data Connectors", + "bladeTitle": "Data Connectors", + "elements": [ + { + "name": "dataconnectors1-text", + "type": "Microsoft.Common.TextBlock", + "options": { + "text": "This Solution installs the data connector for SpyCloud Enterprise Protection Connector. You can get SpyCloud Enterprise Protection Connector data in your Microsoft Sentinel workspace. After installing the solution, configure and enable this data connector by following guidance in Manage solution view." + } + }, + { + "name": "dataconnectors-link1", + "type": "Microsoft.Common.TextBlock", + "options": { + "link": { + "label": "Learn more about connecting data sources", + "uri": "https://docs.microsoft.com/azure/sentinel/connect-data-sources" + } + } + } + ] + }, + { + "name": "analytics", + "label": "Analytics", + "subLabel": { + "preValidation": "Configure the analytics", + "postValidation": "Done" + }, + "bladeTitle": "Analytics", + "elements": [ + { + "name": "analytics-text", + "type": "Microsoft.Common.TextBlock", + "options": { + "text": "This solution installs the following analytic rule templates. After installing the solution, create and enable analytic rules in Manage solution view." + } + }, + { + "name": "analytics-link", + "type": "Microsoft.Common.TextBlock", + "options": { + "link": { + "label": "Learn more", + "uri": "https://docs.microsoft.com/azure/sentinel/tutorial-detect-threats-custom?WT.mc_id=Portal-Microsoft_Azure_CreateUIDef" + } + } + }, + { + "name": "analytic1", + "type": "Microsoft.Common.Section", + "label": "SpyCloud plaintext credential exposure detected", + "elements": [ + { + "name": "analytic1-text", + "type": "Microsoft.Common.TextBlock", + "options": { + "text": "Identifies user accounts exposed with a plaintext password in a third-party data breach.\nUnremediated exposures of this kind can lead directly to account takeover." + } + } + ] + }, + { + "name": "analytic2", + "type": "Microsoft.Common.Section", + "label": "SpyCloud infostealer malware credential exposure", + "elements": [ + { + "name": "analytic2-text", + "type": "Microsoft.Common.TextBlock", + "options": { + "text": "Identifies credentials harvested by infostealer malware on a compromised device. This\nexposure may indicate an actively compromised endpoint with associated command-and-control\nrisk." + } + } + ] + } + ] + }, + { + "name": "playbooks", + "label": "Playbooks", + "subLabel": { + "preValidation": "Configure the playbooks", + "postValidation": "Done" + }, + "bladeTitle": "Playbooks", + "elements": [ + { + "name": "playbooks-text", + "type": "Microsoft.Common.TextBlock", + "options": { + "text": "This solution installs the Playbook templates to help implement your Security Orchestration, Automation and Response (SOAR) operations. After installing the solution, these will be deployed under Playbook Templates in the Automation blade in Microsoft Sentinel. They can be configured and managed from the Manage solution view in Content Hub." + } + }, + { + "name": "playbooks-link", + "type": "Microsoft.Common.TextBlock", + "options": { + "link": { + "label": "Learn more", + "uri": "https://docs.microsoft.com/azure/sentinel/tutorial-respond-threats-playbook?WT.mc_id=Portal-Microsoft_Azure_CreateUIDef" + } + } + } + ] + } + ], + "outputs": { + "workspace-location": "[first(map(filter(basics('getLAWorkspace').value, (filter) => and(contains(toLower(filter.id), toLower(resourceGroup().name)),equals(filter.name,basics('workspace')))), (item) => item.location))]", + "location": "[location()]", + "workspace": "[basics('workspace')]" + } + } +} diff --git a/Solutions/SpyCloud Enterprise Protection CCF/Package/mainTemplate.json b/Solutions/SpyCloud Enterprise Protection CCF/Package/mainTemplate.json new file mode 100644 index 00000000000..01fc42465ef --- /dev/null +++ b/Solutions/SpyCloud Enterprise Protection CCF/Package/mainTemplate.json @@ -0,0 +1,4841 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "author": "SpyCloud - support@spycloud.com", + "comments": "Solution template for SpyCloud Enterprise Protection CCF" + }, + "parameters": { + "location": { + "type": "string", + "minLength": 1, + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Not used, but needed to pass arm-ttk test `Location-Should-Not-Be-Hardcoded`. We instead use the `workspace-location` which is derived from the LA workspace" + } + }, + "workspace-location": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "[concat('Region to deploy solution resources -- separate from location selection',parameters('location'))]" + } + }, + "workspace": { + "defaultValue": "", + "type": "string", + "metadata": { + "description": "Workspace name for Log Analytics where Microsoft Sentinel is setup" + } + }, + "resourceGroupName": { + "type": "string", + "defaultValue": "[resourceGroup().name]", + "metadata": { + "description": "resource group name where Microsoft Sentinel is setup" + } + }, + "subscription": { + "type": "string", + "defaultValue": "[last(split(subscription().id, '/'))]", + "metadata": { + "description": "subscription id where Microsoft Sentinel is setup" + } + } + }, + "variables": { + "email": "support@spycloud.com", + "_email": "[variables('email')]", + "_solutionName": "SpyCloud Enterprise Protection CCF", + "_solutionVersion": "3.0.0", + "solutionId": "spycloud.azure-sentinel-solution-spycloud-enterprise-protection", + "_solutionId": "[variables('solutionId')]", + "analyticRuleObject1": { + "analyticRuleVersion1": "1.0.0", + "_analyticRulecontentId1": "a25eba0e-ff42-4c97-a379-d76bdb2aa1e3", + "analyticRuleId1": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', 'a25eba0e-ff42-4c97-a379-d76bdb2aa1e3')]", + "analyticRuleTemplateSpecName1": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring('a25eba0e-ff42-4c97-a379-d76bdb2aa1e3')))]", + "_analyticRulecontentProductId1": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','a25eba0e-ff42-4c97-a379-d76bdb2aa1e3','-', '1.0.0')))]" + }, + "analyticRuleObject2": { + "analyticRuleVersion2": "1.0.0", + "_analyticRulecontentId2": "ead4deed-9d48-4646-aee0-6b46c2dd1ae6", + "analyticRuleId2": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', 'ead4deed-9d48-4646-aee0-6b46c2dd1ae6')]", + "analyticRuleTemplateSpecName2": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring('ead4deed-9d48-4646-aee0-6b46c2dd1ae6')))]", + "_analyticRulecontentProductId2": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','ead4deed-9d48-4646-aee0-6b46c2dd1ae6','-', '1.0.0')))]" + }, + "workspaceResourceId": "[resourceId('microsoft.OperationalInsights/Workspaces', parameters('workspace'))]", + "dataConnectorCCPVersion": "3.0.0", + "_dataConnectorContentIdConnectorDefinition1": "SpyCloudEnterpriseProtectionCCF", + "dataConnectorTemplateNameConnectorDefinition1": "[concat(parameters('workspace'),'-dc-',uniquestring(variables('_dataConnectorContentIdConnectorDefinition1')))]", + "_dataConnectorContentIdConnections1": "SpyCloudEnterpriseProtectionCCFConnections", + "dataConnectorTemplateNameConnections1": "[concat(parameters('workspace'),'-dc-',uniquestring(variables('_dataConnectorContentIdConnections1')))]", + "dataCollectionEndpointId1": "[concat('/subscriptions/',parameters('subscription'),'/resourceGroups/',parameters('resourceGroupName'),'/providers/Microsoft.Insights/dataCollectionEndpoints/',parameters('workspace'))]", + "blanks": "[replace('b', 'b', '')]", + "parserObject1": { + "_parserName1": "[concat(parameters('workspace'),'/','get_Spycloud_enriched_data')]", + "_parserId1": "[resourceId('Microsoft.OperationalInsights/workspaces/savedSearches', parameters('workspace'), 'get_Spycloud_enriched_data')]", + "parserTemplateSpecName1": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-pr-',uniquestring('get_Spycloud_enriched_data-Parser')))]", + "parserVersion1": "1.0.0", + "parserContentId1": "get_Spycloud_enriched_data-Parser" + }, + "parserObject2": { + "_parserName2": "[concat(parameters('workspace'),'/','get_spycloud_compass_data')]", + "_parserId2": "[resourceId('Microsoft.OperationalInsights/workspaces/savedSearches', parameters('workspace'), 'get_spycloud_compass_data')]", + "parserTemplateSpecName2": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-pr-',uniquestring('get_spycloud_compass_data-Parser')))]", + "parserVersion2": "1.0.0", + "parserContentId2": "get_spycloud_compass_data-Parser" + }, + "SpyCloud_MDE_Automation": "SpyCloud_MDE_Automation", + "_SpyCloud_MDE_Automation": "[variables('SpyCloud_MDE_Automation')]", + "TemplateEmptyArray": "[json('[]')]", + "playbookVersion1": "1.0", + "playbookContentId1": "SpyCloud_MDE_Automation", + "_playbookContentId1": "[variables('playbookContentId1')]", + "playbookId1": "[resourceId('Microsoft.Logic/workflows', variables('playbookContentId1'))]", + "playbookTemplateSpecName1": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-pl-',uniquestring(variables('_playbookContentId1'))))]", + "_playbookcontentProductId1": "[concat(take(variables('_solutionId'),50),'-','pl','-', uniqueString(concat(variables('_solutionId'),'-','Playbook','-',variables('_playbookContentId1'),'-', variables('playbookVersion1'))))]", + "SpyCloud_Conditional_Access_Playbook": "SpyCloud_Conditional_Access_Playbook", + "_SpyCloud_Conditional_Access_Playbook": "[variables('SpyCloud_Conditional_Access_Playbook')]", + "playbookVersion2": "1.0", + "playbookContentId2": "SpyCloud_Conditional_Access_Playbook", + "_playbookContentId2": "[variables('playbookContentId2')]", + "playbookId2": "[resourceId('Microsoft.Logic/workflows', variables('playbookContentId2'))]", + "playbookTemplateSpecName2": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-pl-',uniquestring(variables('_playbookContentId2'))))]", + "_playbookcontentProductId2": "[concat(take(variables('_solutionId'),50),'-','pl','-', uniqueString(concat(variables('_solutionId'),'-','Playbook','-',variables('_playbookContentId2'),'-', variables('playbookVersion2'))))]", + "SpyCloud_AutomationRules": "SpyCloud_AutomationRules", + "_SpyCloud_AutomationRules": "[variables('SpyCloud_AutomationRules')]", + "playbookVersion3": "1.0", + "playbookContentId3": "SpyCloud_AutomationRules", + "_playbookContentId3": "[variables('playbookContentId3')]", + "playbookId3": "[resourceId('Microsoft.Logic/workflows', variables('playbookContentId3'))]", + "playbookTemplateSpecName3": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-pl-',uniquestring(variables('_playbookContentId3'))))]", + "_playbookcontentProductId3": "[concat(take(variables('_solutionId'),50),'-','pl','-', uniqueString(concat(variables('_solutionId'),'-','Playbook','-',variables('_playbookContentId3'),'-', variables('playbookVersion3'))))]", + "_solutioncontentProductId": "[concat(take(variables('_solutionId'),50),'-','sl','-', uniqueString(concat(variables('_solutionId'),'-','Solution','-',variables('_solutionId'),'-', variables('_solutionVersion'))))]" + }, + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleObject1').analyticRuleTemplateSpecName1]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "AR_Breached_Users_20_AnalyticalRules Analytics Rule with template version 3.0.0", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleObject1').analyticRuleVersion1]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRuleObject1')._analyticRulecontentId1]", + "apiVersion": "2023-02-01-preview", + "kind": "scheduled", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "Identifies user accounts exposed with a plaintext password in a third-party data breach.\nUnremediated exposures of this kind can lead directly to account takeover.", + "displayName": "SpyCloud plaintext credential exposure detected", + "enabled": false, + "query": "// Human-readable constant for the severity threshold used below\nlet severityThreshold = 20;\nSpyCloudBreachWatchlistV2_CL\n| where Severity == severityThreshold\n| mv-expand IPAddress = IPAddresses to typeof(string)\n| extend AccountName = Username, AccountEmail = Email\n| project TimeGenerated, DocumentId, SourceId, SpyCloudPublishDate, AccountEmail,\n TargetDomain, PasswordPlaintext, AccountName, IPAddress\n", + "queryFrequency": "PT1H", + "queryPeriod": "P2D", + "severity": "High", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "SpyCloudEnterpriseProtectionCCF", + "dataTypes": [ + "SpyCloudBreachWatchlistV2_CL" + ] + } + ], + "tactics": [ + "CredentialAccess" + ], + "subTechniques": [ + "T1589.001" + ], + "techniques": [ + "T1589" + ], + "entityMappings": [ + { + "entityType": "Account", + "fieldMappings": [ + { + "identifier": "Name", + "columnName": "AccountName" + } + ] + }, + { + "entityType": "IP", + "fieldMappings": [ + { + "identifier": "Address", + "columnName": "IPAddress" + } + ] + }, + { + "entityType": "Mailbox", + "fieldMappings": [ + { + "identifier": "MailboxPrimaryAddress", + "columnName": "AccountEmail" + } + ] + } + ], + "eventGroupingSettings": { + "aggregationKind": "SingleAlert" + } + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleObject1').analyticRuleId1,'/'))))]", + "properties": { + "description": "SpyCloud Enterprise Protection CCF Analytics Rule 1", + "parentId": "[variables('analyticRuleObject1').analyticRuleId1]", + "contentId": "[variables('analyticRuleObject1')._analyticRulecontentId1]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleObject1').analyticRuleVersion1]", + "source": { + "kind": "Solution", + "name": "SpyCloud Enterprise Protection CCF", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "SpyCloud", + "email": "[variables('_email')]" + }, + "support": { + "name": "SpyCloud", + "tier": "Partner", + "link": "https://support.spycloud.com" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('analyticRuleObject1')._analyticRulecontentId1]", + "contentKind": "AnalyticsRule", + "displayName": "SpyCloud plaintext credential exposure detected", + "contentProductId": "[variables('analyticRuleObject1')._analyticRulecontentProductId1]", + "id": "[variables('analyticRuleObject1')._analyticRulecontentProductId1]", + "version": "[variables('analyticRuleObject1').analyticRuleVersion1]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleObject2').analyticRuleTemplateSpecName2]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "AR_malware_25_AnalyticalRules Analytics Rule with template version 3.0.0", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleObject2').analyticRuleVersion2]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRuleObject2')._analyticRulecontentId2]", + "apiVersion": "2023-02-01-preview", + "kind": "scheduled", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "Identifies credentials harvested by infostealer malware on a compromised device. This\nexposure may indicate an actively compromised endpoint with associated command-and-control\nrisk.", + "displayName": "SpyCloud infostealer malware credential exposure", + "enabled": false, + "query": "// Human-readable constant for the severity threshold used below\nlet severityThreshold = 25;\nSpyCloudBreachWatchlistV2_CL\n| where Severity == severityThreshold\n| mv-expand IPAddress = IPAddresses to typeof(string)\n| extend AccountName = Username, AccountEmail = Email, HostName = UserHostName\n| project TimeGenerated, DocumentId, SourceId, SpyCloudPublishDate, AccountEmail,\n AccountName, HostName, InfectedMachineId, InfectedTime, UserOS, IPAddress\n", + "queryFrequency": "PT1H", + "queryPeriod": "P1D", + "severity": "High", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "SpyCloudEnterpriseProtectionCCF", + "dataTypes": [ + "SpyCloudBreachWatchlistV2_CL" + ] + } + ], + "tactics": [ + "CredentialAccess", + "CommandAndControl" + ], + "techniques": [ + "T1555", + "T1071" + ], + "entityMappings": [ + { + "entityType": "Account", + "fieldMappings": [ + { + "identifier": "Name", + "columnName": "AccountName" + } + ] + }, + { + "entityType": "Host", + "fieldMappings": [ + { + "identifier": "HostName", + "columnName": "HostName" + } + ] + }, + { + "entityType": "IP", + "fieldMappings": [ + { + "identifier": "Address", + "columnName": "IPAddress" + } + ] + } + ], + "eventGroupingSettings": { + "aggregationKind": "SingleAlert" + } + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleObject2').analyticRuleId2,'/'))))]", + "properties": { + "description": "SpyCloud Enterprise Protection CCF Analytics Rule 2", + "parentId": "[variables('analyticRuleObject2').analyticRuleId2]", + "contentId": "[variables('analyticRuleObject2')._analyticRulecontentId2]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleObject2').analyticRuleVersion2]", + "source": { + "kind": "Solution", + "name": "SpyCloud Enterprise Protection CCF", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "SpyCloud", + "email": "[variables('_email')]" + }, + "support": { + "name": "SpyCloud", + "tier": "Partner", + "link": "https://support.spycloud.com" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('analyticRuleObject2')._analyticRulecontentId2]", + "contentKind": "AnalyticsRule", + "displayName": "SpyCloud infostealer malware credential exposure", + "contentProductId": "[variables('analyticRuleObject2')._analyticRulecontentProductId2]", + "id": "[variables('analyticRuleObject2')._analyticRulecontentProductId2]", + "version": "[variables('analyticRuleObject2').analyticRuleVersion2]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/', variables('dataConnectorTemplateNameConnectorDefinition1'), variables('dataConnectorCCPVersion'))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "contentId": "[variables('_dataConnectorContentIdConnectorDefinition1')]", + "displayName": "SpyCloud Enterprise Protection Connector", + "contentKind": "DataConnector", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('dataConnectorCCPVersion')]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',variables('_dataConnectorContentIdConnectorDefinition1'))]", + "apiVersion": "2022-09-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectorDefinitions", + "location": "[parameters('workspace-location')]", + "kind": "Customizable", + "properties": { + "connectorUiConfig": { + "id": "SpyCloudEnterpriseProtectionCCF", + "title": "SpyCloud Enterprise Protection Connector", + "publisher": "SpyCloud", + "descriptionMarkdown": "Ingests SpyCloud Watchlist exposure data into Microsoft Sentinel, including compromised credentials and infected machine records associated with monitored assets. Also includes SpyCloud breach catalog metadata for contextual enrichment and correlation.", + "graphQueriesTableName": "SpyCloudBreachWatchlistV2_CL", + "graphQueries": [ + { + "metricName": "Total Watchlist", + "legend": "SpyCloud Watchlist", + "baseQuery": "{{graphQueriesTableName}}" + } + ], + "sampleQueries": [ + { + "description": "All Watchlists", + "query": "{{graphQueriesTableName}}\n| sort by TimeGenerated desc" + } + ], + "dataTypes": [ + { + "name": "{{graphQueriesTableName}}", + "lastDataReceivedQuery": "{{graphQueriesTableName}}\n |summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + } + ], + "connectivityCriteria": [ + { + "type": "HasDataConnectors" + } + ], + "availability": { + "isPreview": false + }, + "permissions": { + "resourceProvider": [ + { + "provider": "Microsoft.OperationalInsights/workspaces", + "permissionsDisplayText": "Read and write permissions are required to ingest data into the Log Analytics workspace.", + "providerDisplayName": "Workspace", + "scope": "Workspace", + "requiredPermissions": { + "read": true, + "write": true, + "delete": true + } + } + ], + "customs": [ + { + "name": "Microsoft Sentinel Contributor", + "description": "Microsoft Sentinel Contributor role is required to manage data connectors." + } + ] + }, + "instructionSteps": [ + { + "title": "Configure SpyCloud API", + "description": "Enter your SpyCloud API key.", + "instructions": [ + { + "type": "Textbox", + "parameters": { + "label": "API Key", + "name": "apiKey", + "type": "password", + "placeholder": "Enter your SpyCloud API Key", + "validations": { + "required": true + } + } + }, + { + "type": "Dropdown", + "parameters": { + "label": "Severity", + "name": "severity", + "options": [ + { + "key": "2", + "text": "2" + }, + { + "key": "5", + "text": "5" + }, + { + "key": "20", + "text": "20" + }, + { + "key": "25", + "text": "25" + }, + { + "key": "30", + "text": "30" + } + ], + "placeholder": "You can Select Multiple Severity", + "isMultiSelect": true, + "required": true, + "defaultAllSelected": false + } + }, + { + "type": "Dropdown", + "parameters": { + "label": "Ingest Compass Data (once daily, yesterday data)", + "name": "compassEnabled", + "options": [ + { + "key": "true", + "text": "On" + }, + { + "key": "false", + "text": "Off" + } + ], + "placeholder": "Enable or disable Compass ingestion", + "isMultiSelect": false, + "required": true + } + }, + { + "type": "ConnectionToggleButton", + "parameters": { + "connectLabel": "connect", + "name": "toggle" + } + } + ] + } + ] + } + } + }, + { + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('DataConnector-', variables('_dataConnectorContentIdConnectorDefinition1')))]", + "apiVersion": "2022-01-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "properties": { + "parentId": "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/dataConnectorDefinitions', variables('_dataConnectorContentIdConnectorDefinition1'))]", + "contentId": "[variables('_dataConnectorContentIdConnectorDefinition1')]", + "kind": "DataConnector", + "version": "[variables('dataConnectorCCPVersion')]", + "source": { + "sourceId": "[variables('_solutionId')]", + "name": "[variables('_solutionName')]", + "kind": "Solution" + }, + "author": { + "name": "SpyCloud", + "email": "[variables('_email')]" + }, + "support": { + "name": "SpyCloud", + "tier": "Partner", + "link": "https://support.spycloud.com" + }, + "dependencies": { + "criteria": [ + { + "version": "[variables('dataConnectorCCPVersion')]", + "contentId": "[variables('_dataConnectorContentIdConnections1')]", + "kind": "ResourcesDataConnector" + } + ] + } + } + }, + { + "name": "SpyCloudwatchlist-DCR", + "apiVersion": "2022-06-01", + "type": "Microsoft.Insights/dataCollectionRules", + "location": "[parameters('workspace-location')]", + "kind": "[variables('blanks')]", + "properties": { + "dataCollectionEndpointId": "[variables('dataCollectionEndpointId1')]", + "streamDeclarations": { + "Custom-SpyCloudBreachWatchlistV2_CL": { + "columns": [ + { + "name": "infected_path", + "type": "string" + }, + { + "name": "user_hostname", + "type": "string" + }, + { + "name": "ip_addresses", + "type": "dynamic" + }, + { + "name": "timezone", + "type": "string" + }, + { + "name": "target_url", + "type": "string" + }, + { + "name": "document_id", + "type": "string" + }, + { + "name": "target_domain", + "type": "string" + }, + { + "name": "user_sys_registered_owner", + "type": "string" + }, + { + "name": "display_resolution", + "type": "string" + }, + { + "name": "password", + "type": "string" + }, + { + "name": "email", + "type": "string" + }, + { + "name": "severity", + "type": "int" + }, + { + "name": "av_softwares", + "type": "dynamic" + }, + { + "name": "log_id", + "type": "string" + }, + { + "name": "user_os", + "type": "string" + }, + { + "name": "email_username", + "type": "string" + }, + { + "name": "spycloud_publish_date", + "type": "string" + }, + { + "name": "infected_machine_id", + "type": "string" + }, + { + "name": "password_plaintext", + "type": "string" + }, + { + "name": "infected_time", + "type": "string" + }, + { + "name": "country_code", + "type": "string" + }, + { + "name": "keyboard_languages", + "type": "string" + }, + { + "name": "password_type", + "type": "string" + }, + { + "name": "domain", + "type": "string" + }, + { + "name": "email_domain", + "type": "string" + }, + { + "name": "source_id", + "type": "int" + }, + { + "name": "target_subdomain", + "type": "string" + }, + { + "name": "sighting", + "type": "int" + }, + { + "name": "account_last_activity_time", + "type": "string" + }, + { + "name": "account_notes", + "type": "string" + }, + { + "name": "account_signup_time", + "type": "string" + }, + { + "name": "username", + "type": "string" + }, + { + "name": "homepage", + "type": "string" + }, + { + "name": "salt", + "type": "string" + }, + { + "name": "account_login_time", + "type": "string" + }, + { + "name": "social_other", + "type": "dynamic" + }, + { + "name": "last_name", + "type": "string" + }, + { + "name": "full_name", + "type": "string" + }, + { + "name": "phone", + "type": "string" + }, + { + "name": "first_name", + "type": "string" + }, + { + "name": "address_1", + "type": "string" + }, + { + "name": "account_modification_time", + "type": "string" + }, + { + "name": "gender", + "type": "string" + }, + { + "name": "city", + "type": "string" + }, + { + "name": "birth_year", + "type": "string" + }, + { + "name": "dob", + "type": "string" + }, + { + "name": "company_website", + "type": "string" + }, + { + "name": "industry", + "type": "string" + }, + { + "name": "account_status", + "type": "string" + }, + { + "name": "social_crunchbase", + "type": "dynamic" + }, + { + "name": "company_name", + "type": "string" + }, + { + "name": "social_linkedin", + "type": "dynamic" + }, + { + "name": "social_twitter", + "type": "dynamic" + }, + { + "name": "account_caption", + "type": "string" + }, + { + "name": "address_2", + "type": "string" + }, + { + "name": "ssn_last_four", + "type": "string" + }, + { + "name": "social_security_number", + "type": "string" + }, + { + "name": "health_insurance_id", + "type": "string" + }, + { + "name": "postal_code", + "type": "string" + }, + { + "name": "age", + "type": "string" + }, + { + "name": "taxid", + "type": "string" + }, + { + "name": "state", + "type": "string" + }, + { + "name": "account_type", + "type": "string" + }, + { + "name": "device_name", + "type": "dynamic" + }, + { + "name": "bank_number", + "type": "string" + }, + { + "name": "mobile_equipment_id", + "type": "string" + }, + { + "name": "country", + "type": "string" + }, + { + "name": "educational_institution", + "type": "string" + }, + { + "name": "job_title", + "type": "string" + }, + { + "name": "account_image_url", + "type": "string" + }, + { + "name": "student_id", + "type": "string" + }, + { + "name": "account_id", + "type": "string" + } + ] + }, + "Custom-SpyCloudBreachCatalogV2_CL": { + "columns": [ + { + "name": "id", + "type": "int" + }, + { + "name": "title", + "type": "string" + }, + { + "name": "description", + "type": "string" + }, + { + "name": "status", + "type": "string" + } + ] + }, + "Custom-spycloud_compassV2_CL": { + "columns": [ + { + "name": "source_id", + "type": "int" + }, + { + "name": "document_id", + "type": "string" + }, + { + "name": "log_id", + "type": "string" + }, + { + "name": "severity", + "type": "int" + }, + { + "name": "email", + "type": "string" + }, + { + "name": "email_domain", + "type": "string" + }, + { + "name": "email_username", + "type": "string" + }, + { + "name": "password", + "type": "string" + }, + { + "name": "password_type", + "type": "string" + }, + { + "name": "password_plaintext", + "type": "string" + }, + { + "name": "target_url", + "type": "string" + }, + { + "name": "target_domain", + "type": "string" + }, + { + "name": "target_subdomain", + "type": "string" + }, + { + "name": "infected_machine_id", + "type": "string" + }, + { + "name": "infected_time", + "type": "string" + }, + { + "name": "infected_path", + "type": "string" + }, + { + "name": "user_os", + "type": "string" + }, + { + "name": "user_sys_registered_owner", + "type": "string" + }, + { + "name": "av_softwares", + "type": "dynamic" + }, + { + "name": "country_code", + "type": "string" + }, + { + "name": "display_resolution", + "type": "string" + }, + { + "name": "ip_addresses", + "type": "dynamic" + }, + { + "name": "timezone", + "type": "string" + }, + { + "name": "domain", + "type": "string" + }, + { + "name": "spycloud_publish_date", + "type": "string" + }, + { + "name": "breach_title", + "type": "string" + }, + { + "name": "breach_category", + "type": "string" + } + ] + }, + "Custom-Spycloud_MDE_LogsV2_CL": { + "columns": [ + { + "name": "TimeGenerated", + "type": "datetime" + }, + { + "name": "IncidentId", + "type": "string" + }, + { + "name": "DocumentId", + "type": "string" + }, + { + "name": "SpyCloudPublishDate", + "type": "datetime" + }, + { + "name": "InfectedTime", + "type": "string" + }, + { + "name": "BreachTitle", + "type": "string" + }, + { + "name": "InfectedMachineId", + "type": "string" + }, + { + "name": "HostName", + "type": "string" + }, + { + "name": "NormalizedHostName", + "type": "string" + }, + { + "name": "DeviceId", + "type": "string" + }, + { + "name": "OSPlatform", + "type": "string" + }, + { + "name": "RiskScore", + "type": "string" + }, + { + "name": "ExposureLevel", + "type": "string" + }, + { + "name": "IsolationRequested", + "type": "boolean" + }, + { + "name": "IsolationStatus", + "type": "boolean" + }, + { + "name": "MachineTagAdded", + "type": "boolean" + }, + { + "name": "MachineTagName", + "type": "string" + }, + { + "name": "AddedIOCsToDefender", + "type": "boolean" + }, + { + "name": "PlaybookName", + "type": "string" + } + ] + }, + "Custom-SpyCloud_ConditionalAccessLogsV2_CL": { + "columns": [ + { + "name": "TimeGenerated", + "type": "datetime" + }, + { + "name": "IncidentId", + "type": "string" + }, + { + "name": "DocumentId", + "type": "string" + }, + { + "name": "SpyCloudPublishDate", + "type": "datetime" + }, + { + "name": "InfectedTime", + "type": "string" + }, + { + "name": "BreachTitle", + "type": "string" + }, + { + "name": "InfectedMachineId", + "type": "string" + }, + { + "name": "Username", + "type": "string" + }, + { + "name": "UserEmail", + "type": "string" + }, + { + "name": "ForcedPasswordResetOnNextSignIn", + "type": "boolean" + }, + { + "name": "UserSessionsRevoked", + "type": "boolean" + }, + { + "name": "CAgroup", + "type": "boolean" + }, + { + "name": "UserDisabled", + "type": "boolean" + }, + { + "name": "PlaybookName", + "type": "string" + } + ] + } + }, + "destinations": { + "logAnalytics": [ + { + "workspaceResourceId": "[variables('workspaceResourceId')]", + "name": "clv2ws1" + } + ] + }, + "dataFlows": [ + { + "streams": [ + "Custom-SpyCloudBreachWatchlistV2_CL" + ], + "destinations": [ + "clv2ws1" + ], + "transformKql": "source\n| extend TimeGenerated = now()\n| project-rename InfectedPath = infected_path, UserHostName = user_hostname, IPAddresses = ip_addresses, TimeZone = timezone, TargetUrl = target_url, DocumentId = document_id, TargetDomain = target_domain, UserSysRegisteredOwner = user_sys_registered_owner, DisplayResolution = display_resolution, Password = password, Email = email, Severity = severity, AVSoftwares = av_softwares, LogId = log_id, UserOS = user_os, EmailUsername = email_username, SpyCloudPublishDate = spycloud_publish_date, InfectedMachineId = infected_machine_id, PasswordPlaintext = password_plaintext, InfectedTime = infected_time, CountryCode = country_code, KeyboardLanguages = keyboard_languages, PasswordType = password_type, Domain = domain, EmailDomain = email_domain, SourceId = source_id, TargetSubdomain = target_subdomain, Sighting = sighting, AccountLastActivityTime = account_last_activity_time, AccountNotes = account_notes, AccountSignupTime = account_signup_time, Username = username, Homepage = homepage, Salt = salt, AccountLoginTime = account_login_time, SocialOther = social_other, LastName = last_name, FullName = full_name, Phone = phone, FirstName = first_name, Address1 = address_1, AccountModificationTime = account_modification_time, Gender = gender, City = city, BirthYear = birth_year, DOB = dob, CompanyWebsite = company_website, Industry = industry, AccountStatus = account_status, SocialCrunchbase = social_crunchbase, CompanyName = company_name, SocialLinkedIn = social_linkedin, SocialTwitter = social_twitter, AccountCaption = account_caption, Address2 = address_2, SSNLastFour = ssn_last_four, SocialSecurityNumber = social_security_number, HealthInsuranceId = health_insurance_id, PostalCode = postal_code, Age = age, TaxId = taxid, State = state, AccountType = account_type, DeviceName = device_name, BankNumber = bank_number, MobileEquipmentId = mobile_equipment_id, Country = country, EducationalInstitution = educational_institution, JobTitle = job_title, AccountImageUrl = account_image_url, StudentId = student_id, AccountId = account_id\n", + "outputStream": "Custom-SpyCloudBreachWatchlistV2_CL" + }, + { + "streams": [ + "Custom-SpyCloudBreachCatalogV2_CL" + ], + "destinations": [ + "clv2ws1" + ], + "transformKql": "source\n| extend TimeGenerated = now()\n| project-rename SourceId = id, BreachTitle = title, Description = description, Status = status\n| project TimeGenerated, SourceId, BreachTitle, Description, Status\n", + "outputStream": "Custom-SpyCloudBreachCatalogV2_CL" + }, + { + "streams": [ + "Custom-spycloud_compassV2_CL" + ], + "destinations": [ + "clv2ws1" + ], + "transformKql": "source\n| extend TimeGenerated = now()\n| project-rename SourceId = source_id, DocumentId = document_id, LogId = log_id, Severity = severity, Email = email, EmailDomain = email_domain, EmailUsername = email_username, Password = password, PasswordType = password_type, PasswordPlaintext = password_plaintext, TargetUrl = target_url, TargetDomain = target_domain, TargetSubdomain = target_subdomain, InfectedMachineId = infected_machine_id, InfectedTime = infected_time, InfectedPath = infected_path, UserOS = user_os, UserSysRegisteredOwner = user_sys_registered_owner, AVSoftwares = av_softwares, CountryCode = country_code, DisplayResolution = display_resolution, IPAddresses = ip_addresses, TimeZone = timezone, Domain = domain, SpyCloudPublishDate = spycloud_publish_date, BreachTitle = breach_title, BreachCategory = breach_category\n", + "outputStream": "Custom-spycloud_compassV2_CL" + }, + { + "streams": [ + "Custom-Spycloud_MDE_LogsV2_CL" + ], + "destinations": [ + "clv2ws1" + ], + "transformKql": "source\n| extend\n TimeGenerated = todatetime(TimeGenerated),\n IncidentId = tostring(IncidentId),\n DocumentId = tostring(DocumentId),\n SpyCloudPublishDate = todatetime(SpyCloudPublishDate),\n InfectedTime = tostring(InfectedTime),\n BreachTitle = tostring(BreachTitle),\n InfectedMachineId = tostring(InfectedMachineId),\n HostName = tostring(HostName),\n NormalizedHostName = tostring(NormalizedHostName),\n DeviceId = tostring(DeviceId),\n OSPlatform = tostring(OSPlatform),\n RiskScore = tostring(RiskScore),\n ExposureLevel = tostring(ExposureLevel),\n IsolationRequested = tobool(IsolationRequested),\n IsolationStatus = tobool(IsolationStatus),\n MachineTagAdded = tobool(MachineTagAdded),\n MachineTagName = tostring(MachineTagName),\n AddedIOCsToDefender = tobool(AddedIOCsToDefender),\n PlaybookName = tostring(PlaybookName)\n| project\n TimeGenerated,\n IncidentId,\n DocumentId,\n SpyCloudPublishDate,\n InfectedTime,\n BreachTitle,\n InfectedMachineId,\n HostName,\n NormalizedHostName,\n DeviceId,\n OSPlatform,\n RiskScore,\n ExposureLevel,\n IsolationRequested,\n IsolationStatus,\n MachineTagAdded,\n MachineTagName,\n AddedIOCsToDefender,\n PlaybookName\n", + "outputStream": "Custom-Spycloud_MDE_LogsV2_CL" + }, + { + "streams": [ + "Custom-SpyCloud_ConditionalAccessLogsV2_CL" + ], + "destinations": [ + "clv2ws1" + ], + "transformKql": "source\n| extend\n TimeGenerated = todatetime(TimeGenerated),\n IncidentId = tostring(IncidentId),\n DocumentId = tostring(DocumentId),\n SpyCloudPublishDate = todatetime(SpyCloudPublishDate),\n InfectedTime = tostring(InfectedTime),\n BreachTitle = tostring(BreachTitle),\n InfectedMachineId = tostring(InfectedMachineId),\n Username = tostring(Username),\n UserEmail = tostring(UserEmail),\n ForcedPasswordResetOnNextSignIn = tobool(ForcedPasswordResetOnNextSignIn),\n UserSessionsRevoked = tobool(UserSessionsRevoked),\n CAgroup = tobool(CAgroup),\n UserDisabled = tobool(UserDisabled),\n PlaybookName = tostring(PlaybookName)\n| project\n TimeGenerated,\n IncidentId,\n DocumentId,\n SpyCloudPublishDate,\n InfectedTime,\n BreachTitle,\n InfectedMachineId,\n Username,\n UserEmail,\n ForcedPasswordResetOnNextSignIn,\n UserSessionsRevoked,\n CAgroup,\n UserDisabled,\n PlaybookName\n", + "outputStream": "Custom-SpyCloud_ConditionalAccessLogsV2_CL" + } + ] + } + }, + { + "name": "SpyCloudBreachWatchlistV2_CL", + "apiVersion": "2022-10-01", + "type": "Microsoft.OperationalInsights/workspaces/tables", + "location": "[parameters('workspace-location')]", + "kind": null, + "properties": { + "schema": { + "name": "SpyCloudBreachWatchlistV2_CL", + "columns": [ + { + "name": "TimeGenerated", + "type": "datetime" + }, + { + "name": "InfectedPath", + "type": "string" + }, + { + "name": "UserHostName", + "type": "string" + }, + { + "name": "IPAddresses", + "type": "dynamic" + }, + { + "name": "TimeZone", + "type": "string" + }, + { + "name": "TargetUrl", + "type": "string" + }, + { + "name": "DocumentId", + "type": "string" + }, + { + "name": "TargetDomain", + "type": "string" + }, + { + "name": "UserSysRegisteredOwner", + "type": "string" + }, + { + "name": "DisplayResolution", + "type": "string" + }, + { + "name": "Password", + "type": "string" + }, + { + "name": "Email", + "type": "string" + }, + { + "name": "Severity", + "type": "int" + }, + { + "name": "AVSoftwares", + "type": "dynamic" + }, + { + "name": "LogId", + "type": "string" + }, + { + "name": "UserOS", + "type": "string" + }, + { + "name": "EmailUsername", + "type": "string" + }, + { + "name": "SpyCloudPublishDate", + "type": "string" + }, + { + "name": "InfectedMachineId", + "type": "string" + }, + { + "name": "PasswordPlaintext", + "type": "string" + }, + { + "name": "InfectedTime", + "type": "string" + }, + { + "name": "CountryCode", + "type": "string" + }, + { + "name": "KeyboardLanguages", + "type": "string" + }, + { + "name": "PasswordType", + "type": "string" + }, + { + "name": "Domain", + "type": "string" + }, + { + "name": "EmailDomain", + "type": "string" + }, + { + "name": "SourceId", + "type": "int" + }, + { + "name": "TargetSubdomain", + "type": "string" + }, + { + "name": "Sighting", + "type": "int" + }, + { + "name": "AccountLastActivityTime", + "type": "string" + }, + { + "name": "AccountNotes", + "type": "string" + }, + { + "name": "AccountSignupTime", + "type": "string" + }, + { + "name": "Username", + "type": "string" + }, + { + "name": "Homepage", + "type": "string" + }, + { + "name": "Salt", + "type": "string" + }, + { + "name": "AccountLoginTime", + "type": "string" + }, + { + "name": "SocialOther", + "type": "dynamic" + }, + { + "name": "LastName", + "type": "string" + }, + { + "name": "FullName", + "type": "string" + }, + { + "name": "Phone", + "type": "string" + }, + { + "name": "FirstName", + "type": "string" + }, + { + "name": "Address1", + "type": "string" + }, + { + "name": "AccountModificationTime", + "type": "string" + }, + { + "name": "Gender", + "type": "string" + }, + { + "name": "City", + "type": "string" + }, + { + "name": "BirthYear", + "type": "string" + }, + { + "name": "DOB", + "type": "string" + }, + { + "name": "CompanyWebsite", + "type": "string" + }, + { + "name": "Industry", + "type": "string" + }, + { + "name": "AccountStatus", + "type": "string" + }, + { + "name": "SocialCrunchbase", + "type": "dynamic" + }, + { + "name": "CompanyName", + "type": "string" + }, + { + "name": "SocialLinkedIn", + "type": "dynamic" + }, + { + "name": "SocialTwitter", + "type": "dynamic" + }, + { + "name": "AccountCaption", + "type": "string" + }, + { + "name": "Address2", + "type": "string" + }, + { + "name": "SSNLastFour", + "type": "string" + }, + { + "name": "SocialSecurityNumber", + "type": "string" + }, + { + "name": "HealthInsuranceId", + "type": "string" + }, + { + "name": "PostalCode", + "type": "string" + }, + { + "name": "Age", + "type": "string" + }, + { + "name": "TaxId", + "type": "string" + }, + { + "name": "State", + "type": "string" + }, + { + "name": "AccountType", + "type": "string" + }, + { + "name": "DeviceName", + "type": "dynamic" + }, + { + "name": "BankNumber", + "type": "string" + }, + { + "name": "MobileEquipmentId", + "type": "string" + }, + { + "name": "Country", + "type": "string" + }, + { + "name": "EducationalInstitution", + "type": "string" + }, + { + "name": "JobTitle", + "type": "string" + }, + { + "name": "AccountImageUrl", + "type": "string" + }, + { + "name": "StudentId", + "type": "string" + }, + { + "name": "AccountId", + "type": "string" + } + ] + } + } + }, + { + "name": "SpyCloudBreachCatalogV2_CL", + "apiVersion": "2022-10-01", + "type": "Microsoft.OperationalInsights/workspaces/tables", + "location": "[parameters('workspace-location')]", + "kind": null, + "properties": { + "schema": { + "name": "SpyCloudBreachCatalogV2_CL", + "columns": [ + { + "name": "TimeGenerated", + "type": "datetime" + }, + { + "name": "SourceId", + "type": "int" + }, + { + "name": "BreachTitle", + "type": "string" + }, + { + "name": "Description", + "type": "string" + }, + { + "name": "Status", + "type": "string" + } + ] + } + } + }, + { + "name": "spycloud_compassV2_CL", + "apiVersion": "2022-10-01", + "type": "Microsoft.OperationalInsights/workspaces/tables", + "location": "[parameters('workspace-location')]", + "kind": null, + "properties": { + "schema": { + "name": "spycloud_compassV2_CL", + "columns": [ + { + "name": "TimeGenerated", + "type": "datetime" + }, + { + "name": "SourceId", + "type": "int" + }, + { + "name": "DocumentId", + "type": "string" + }, + { + "name": "LogId", + "type": "string" + }, + { + "name": "Severity", + "type": "int" + }, + { + "name": "Email", + "type": "string" + }, + { + "name": "EmailDomain", + "type": "string" + }, + { + "name": "EmailUsername", + "type": "string" + }, + { + "name": "Password", + "type": "string" + }, + { + "name": "PasswordType", + "type": "string" + }, + { + "name": "PasswordPlaintext", + "type": "string" + }, + { + "name": "TargetUrl", + "type": "string" + }, + { + "name": "TargetDomain", + "type": "string" + }, + { + "name": "TargetSubdomain", + "type": "string" + }, + { + "name": "InfectedMachineId", + "type": "string" + }, + { + "name": "InfectedTime", + "type": "string" + }, + { + "name": "InfectedPath", + "type": "string" + }, + { + "name": "UserOS", + "type": "string" + }, + { + "name": "UserSysRegisteredOwner", + "type": "string" + }, + { + "name": "AVSoftwares", + "type": "dynamic" + }, + { + "name": "CountryCode", + "type": "string" + }, + { + "name": "DisplayResolution", + "type": "string" + }, + { + "name": "IPAddresses", + "type": "dynamic" + }, + { + "name": "TimeZone", + "type": "string" + }, + { + "name": "Domain", + "type": "string" + }, + { + "name": "SpyCloudPublishDate", + "type": "string" + }, + { + "name": "BreachTitle", + "type": "string" + }, + { + "name": "BreachCategory", + "type": "string" + } + ] + } + } + }, + { + "name": "Spycloud_MDE_LogsV2_CL", + "apiVersion": "2022-10-01", + "type": "Microsoft.OperationalInsights/workspaces/tables", + "location": "[parameters('workspace-location')]", + "kind": null, + "properties": { + "schema": { + "name": "Spycloud_MDE_LogsV2_CL", + "columns": [ + { + "name": "TimeGenerated", + "type": "datetime" + }, + { + "name": "IncidentId", + "type": "string" + }, + { + "name": "DocumentId", + "type": "string" + }, + { + "name": "SpyCloudPublishDate", + "type": "datetime" + }, + { + "name": "InfectedTime", + "type": "string" + }, + { + "name": "BreachTitle", + "type": "string" + }, + { + "name": "InfectedMachineId", + "type": "string" + }, + { + "name": "HostName", + "type": "string" + }, + { + "name": "NormalizedHostName", + "type": "string" + }, + { + "name": "DeviceId", + "type": "string" + }, + { + "name": "OSPlatform", + "type": "string" + }, + { + "name": "RiskScore", + "type": "string" + }, + { + "name": "ExposureLevel", + "type": "string" + }, + { + "name": "IsolationRequested", + "type": "boolean" + }, + { + "name": "IsolationStatus", + "type": "boolean" + }, + { + "name": "MachineTagAdded", + "type": "boolean" + }, + { + "name": "MachineTagName", + "type": "string" + }, + { + "name": "AddedIOCsToDefender", + "type": "boolean" + }, + { + "name": "PlaybookName", + "type": "string" + } + ] + } + } + }, + { + "name": "SpyCloud_ConditionalAccessLogsV2_CL", + "apiVersion": "2022-10-01", + "type": "Microsoft.OperationalInsights/workspaces/tables", + "location": "[parameters('workspace-location')]", + "kind": null, + "properties": { + "schema": { + "name": "SpyCloud_ConditionalAccessLogsV2_CL", + "columns": [ + { + "name": "TimeGenerated", + "type": "datetime" + }, + { + "name": "IncidentId", + "type": "string" + }, + { + "name": "DocumentId", + "type": "string" + }, + { + "name": "SpyCloudPublishDate", + "type": "datetime" + }, + { + "name": "InfectedTime", + "type": "string" + }, + { + "name": "BreachTitle", + "type": "string" + }, + { + "name": "InfectedMachineId", + "type": "string" + }, + { + "name": "Username", + "type": "string" + }, + { + "name": "UserEmail", + "type": "string" + }, + { + "name": "ForcedPasswordResetOnNextSignIn", + "type": "boolean" + }, + { + "name": "UserSessionsRevoked", + "type": "boolean" + }, + { + "name": "CAgroup", + "type": "boolean" + }, + { + "name": "UserDisabled", + "type": "boolean" + }, + { + "name": "PlaybookName", + "type": "string" + } + ] + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "contentProductId": "[concat(take(variables('_solutionId'), 50),'-','dc','-', uniqueString(concat(variables('_solutionId'),'-','DataConnector','-',variables('_dataConnectorContentIdConnectorDefinition1'),'-', variables('dataConnectorCCPVersion'))))]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "version": "[variables('dataConnectorCCPVersion')]" + } + }, + { + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',variables('_dataConnectorContentIdConnectorDefinition1'))]", + "apiVersion": "2022-09-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectorDefinitions", + "location": "[parameters('workspace-location')]", + "kind": "Customizable", + "properties": { + "connectorUiConfig": { + "id": "SpyCloudEnterpriseProtectionCCF", + "title": "SpyCloud Enterprise Protection Connector", + "publisher": "SpyCloud", + "descriptionMarkdown": "Ingests SpyCloud Watchlist exposure data into Microsoft Sentinel, including compromised credentials and infected machine records associated with monitored assets. Also includes SpyCloud breach catalog metadata for contextual enrichment and correlation.", + "graphQueriesTableName": "SpyCloudBreachWatchlistV2_CL", + "graphQueries": [ + { + "metricName": "Total Watchlist", + "legend": "SpyCloud Watchlist", + "baseQuery": "{{graphQueriesTableName}}" + } + ], + "sampleQueries": [ + { + "description": "All Watchlists", + "query": "{{graphQueriesTableName}}\n| sort by TimeGenerated desc" + } + ], + "dataTypes": [ + { + "name": "{{graphQueriesTableName}}", + "lastDataReceivedQuery": "{{graphQueriesTableName}}\n |summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + } + ], + "connectivityCriteria": [ + { + "type": "HasDataConnectors" + } + ], + "availability": { + "isPreview": false + }, + "permissions": { + "resourceProvider": [ + { + "provider": "Microsoft.OperationalInsights/workspaces", + "permissionsDisplayText": "Read and write permissions are required to ingest data into the Log Analytics workspace.", + "providerDisplayName": "Workspace", + "scope": "Workspace", + "requiredPermissions": { + "read": true, + "write": true, + "delete": true + } + } + ], + "customs": [ + { + "name": "Microsoft Sentinel Contributor", + "description": "Microsoft Sentinel Contributor role is required to manage data connectors." + } + ] + }, + "instructionSteps": [ + { + "title": "Configure SpyCloud API", + "description": "Enter your SpyCloud API key.", + "instructions": [ + { + "type": "Textbox", + "parameters": { + "label": "API Key", + "name": "apiKey", + "type": "password", + "placeholder": "Enter your SpyCloud API Key", + "validations": { + "required": true + } + } + }, + { + "type": "Dropdown", + "parameters": { + "label": "Severity", + "name": "severity", + "options": [ + { + "key": "2", + "text": "2" + }, + { + "key": "5", + "text": "5" + }, + { + "key": "20", + "text": "20" + }, + { + "key": "25", + "text": "25" + }, + { + "key": "30", + "text": "30" + } + ], + "placeholder": "You can Select Multiple Severity", + "isMultiSelect": true, + "required": true, + "defaultAllSelected": false + } + }, + { + "type": "Dropdown", + "parameters": { + "label": "Ingest Compass Data (once daily, yesterday data)", + "name": "compassEnabled", + "options": [ + { + "key": "true", + "text": "On" + }, + { + "key": "false", + "text": "Off" + } + ], + "placeholder": "Enable or disable Compass ingestion", + "isMultiSelect": false, + "required": true + } + }, + { + "type": "ConnectionToggleButton", + "parameters": { + "connectLabel": "connect", + "name": "toggle" + } + } + ] + } + ] + } + } + }, + { + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('DataConnector-', variables('_dataConnectorContentIdConnectorDefinition1')))]", + "apiVersion": "2022-01-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "properties": { + "parentId": "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/dataConnectorDefinitions', variables('_dataConnectorContentIdConnectorDefinition1'))]", + "contentId": "[variables('_dataConnectorContentIdConnectorDefinition1')]", + "kind": "DataConnector", + "version": "[variables('dataConnectorCCPVersion')]", + "source": { + "sourceId": "[variables('_solutionId')]", + "name": "[variables('_solutionName')]", + "kind": "Solution" + }, + "author": { + "name": "SpyCloud", + "email": "[variables('_email')]" + }, + "support": { + "name": "SpyCloud", + "tier": "Partner", + "link": "https://support.spycloud.com" + }, + "dependencies": { + "criteria": [ + { + "version": "[variables('dataConnectorCCPVersion')]", + "contentId": "[variables('_dataConnectorContentIdConnections1')]", + "kind": "ResourcesDataConnector" + } + ] + } + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/', variables('dataConnectorTemplateNameConnections1'), variables('dataConnectorCCPVersion'))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "contentId": "[variables('_dataConnectorContentIdConnections1')]", + "displayName": "SpyCloud Enterprise Protection Connector", + "contentKind": "ResourcesDataConnector", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('dataConnectorCCPVersion')]", + "parameters": { + "guidValue": { + "defaultValue": "[[newGuid()]", + "type": "securestring" + }, + "innerWorkspace": { + "defaultValue": "[parameters('workspace')]", + "type": "securestring" + }, + "connectorDefinitionName": { + "defaultValue": "SpyCloud Enterprise Protection Connector", + "type": "securestring", + "minLength": 1 + }, + "workspace": { + "defaultValue": "[parameters('workspace')]", + "type": "securestring" + }, + "dcrConfig": { + "defaultValue": { + "dataCollectionEndpoint": "data collection Endpoint", + "dataCollectionRuleImmutableId": "data collection rule immutableId" + }, + "type": "object" + }, + "apiKey": { + "defaultValue": "apiKey", + "type": "securestring", + "minLength": 1 + }, + "severity": { + "defaultValue": "severity", + "type": "array" + }, + "compassEnabled": { + "defaultValue": "compassEnabled", + "type": "array" + } + }, + "variables": { + "_dataConnectorContentIdConnections1": "[variables('_dataConnectorContentIdConnections1')]" + }, + "resources": [ + { + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('DataConnector-', variables('_dataConnectorContentIdConnections1')))]", + "apiVersion": "2022-01-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "properties": { + "parentId": "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/dataConnectors', variables('_dataConnectorContentIdConnections1'))]", + "contentId": "[variables('_dataConnectorContentIdConnections1')]", + "kind": "ResourcesDataConnector", + "version": "[variables('dataConnectorCCPVersion')]", + "source": { + "sourceId": "[variables('_solutionId')]", + "name": "[variables('_solutionName')]", + "kind": "Solution" + }, + "author": { + "name": "SpyCloud", + "email": "[variables('_email')]" + }, + "support": { + "name": "SpyCloud", + "tier": "Partner", + "link": "https://support.spycloud.com" + } + } + }, + { + "name": "[[concat(parameters('innerWorkspace'),'/Microsoft.SecurityInsights/', 'SpyCloudWatchlistConnector', parameters('guidValue'))]", + "apiVersion": "2023-02-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectors", + "location": "[parameters('workspace-location')]", + "kind": "RestApiPoller", + "properties": { + "connectorDefinitionName": "SpyCloudEnterpriseProtectionCCF", + "dcrConfig": { + "streamName": "Custom-SpyCloudBreachWatchlistV2_CL", + "dataCollectionEndpoint": "[[parameters('dcrConfig').dataCollectionEndpoint]", + "dataCollectionRuleImmutableId": "[[parameters('dcrConfig').dataCollectionRuleImmutableId]" + }, + "dataType": "SpyCloudBreachWatchlistV2_CL", + "auth": { + "type": "APIKey", + "ApiKeyName": "X-API-KEY", + "ApiKey": "[[parameters('apiKey')]" + }, + "request": { + "apiEndpoint": "https://api.spycloud.io/enterprise-v2/breach/data/watchlist", + "httpMethod": "GET", + "rateLimitQPS": 2, + "queryTimeFormat": "yyyy-MM-ddTHH:mm:ssZ", + "startTimeAttributeName": "since", + "queryWindowInMin": 60, + "headers": { + "Accept": "application/json", + "User-Agent": "spycloud_microsoftccf/1.0.0" + }, + "queryParameters": { + "severity": "[[parameters('severity')]" + }, + "retryCount": 3, + "timeoutInSeconds": 60 + }, + "response": { + "eventsJsonPaths": [ + "$.results[*]" + ], + "format": "json" + }, + "paging": { + "pagingType": "NextPageToken", + "nextPageTokenJsonPath": "$.cursor", + "nextPageParaName": "cursor", + "pagingInfoPlacement": "QueryString" + }, + "isActive": true + } + }, + { + "name": "[[concat(parameters('innerWorkspace'),'/Microsoft.SecurityInsights/', 'SpyCloudWatchlistConnectorModified', parameters('guidValue'))]", + "apiVersion": "2023-02-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectors", + "location": "[parameters('workspace-location')]", + "kind": "RestApiPoller", + "properties": { + "connectorDefinitionName": "SpyCloudEnterpriseProtectionCCF", + "dcrConfig": { + "streamName": "Custom-SpyCloudBreachWatchlistV2_CL", + "dataCollectionEndpoint": "[[parameters('dcrConfig').dataCollectionEndpoint]", + "dataCollectionRuleImmutableId": "[[parameters('dcrConfig').dataCollectionRuleImmutableId]" + }, + "dataType": "SpyCloudBreachWatchlistV2_CL", + "auth": { + "type": "APIKey", + "ApiKeyName": "X-API-KEY", + "ApiKey": "[[parameters('apiKey')]" + }, + "request": { + "apiEndpoint": "https://api.spycloud.io/enterprise-v2/breach/data/watchlist", + "httpMethod": "GET", + "rateLimitQPS": 2, + "queryTimeFormat": "yyyy-MM-dd", + "queryWindowInMin": 60, + "headers": { + "Accept": "application/json", + "User-Agent": "spycloud_microsoftccf/1.0.0" + }, + "queryParameters": { + "since_modification_date": "{_QueryWindowStartTime}", + "until_modification_date": "{_QueryWindowStartTime}", + "severity": "[[parameters('severity')]" + }, + "retryCount": 3, + "timeoutInSeconds": 60 + }, + "response": { + "eventsJsonPaths": [ + "$.results[*]" + ], + "format": "json" + }, + "paging": { + "pagingType": "NextPageToken", + "nextPageTokenJsonPath": "$.cursor", + "nextPageParaName": "cursor", + "pagingInfoPlacement": "QueryString" + }, + "isActive": true + } + }, + { + "name": "[[concat(parameters('innerWorkspace'),'/Microsoft.SecurityInsights/', 'SpyCloudUsernameConnector', parameters('guidValue'))]", + "apiVersion": "2023-02-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectors", + "location": "[parameters('workspace-location')]", + "kind": "RestApiPoller", + "properties": { + "connectorDefinitionName": "SpyCloudEnterpriseProtectionCCF", + "dcrConfig": { + "streamName": "Custom-SpyCloudBreachWatchlistV2_CL", + "dataCollectionEndpoint": "[[parameters('dcrConfig').dataCollectionEndpoint]", + "dataCollectionRuleImmutableId": "[[parameters('dcrConfig').dataCollectionRuleImmutableId]" + }, + "dataType": "SpyCloudBreachWatchlistV2_CL", + "auth": { + "type": "APIKey", + "ApiKeyName": "X-API-KEY", + "ApiKey": "[[parameters('apiKey')]" + }, + "request": { + "apiEndpoint": "https://api.spycloud.io/enterprise-v2/breach/data/usernames/username", + "httpMethod": "GET", + "rateLimitQPS": 2, + "queryTimeFormat": "yyyy-MM-dd", + "queryWindowInMin": 60, + "headers": { + "Accept": "application/json", + "User-Agent": "spycloud_microsoftccf/1.0.0" + }, + "queryParameters": { + "since_modification_date": "{_QueryWindowStartTime}", + "until_modification_date": "{_QueryWindowStartTime}" + }, + "retryCount": 3, + "timeoutInSeconds": 60 + }, + "response": { + "eventsJsonPaths": [ + "$.results[*]" + ], + "format": "json" + }, + "paging": { + "pagingType": "NextPageToken", + "nextPageTokenJsonPath": "$.cursor", + "nextPageParaName": "cursor", + "pagingInfoPlacement": "QueryString" + }, + "isActive": true + } + }, + { + "name": "[[concat(parameters('innerWorkspace'),'/Microsoft.SecurityInsights/', 'SpyCloudBreachCatalogConnector', parameters('guidValue'))]", + "apiVersion": "2023-02-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectors", + "location": "[parameters('workspace-location')]", + "kind": "RestApiPoller", + "properties": { + "connectorDefinitionName": "SpyCloudEnterpriseProtectionCCF", + "dcrConfig": { + "streamName": "Custom-SpyCloudBreachCatalogV2_CL", + "dataCollectionEndpoint": "[[parameters('dcrConfig').dataCollectionEndpoint]", + "dataCollectionRuleImmutableId": "[[parameters('dcrConfig').dataCollectionRuleImmutableId]" + }, + "dataType": "SpyCloudBreachCatalogV2_CL", + "auth": { + "type": "APIKey", + "ApiKeyName": "X-API-KEY", + "ApiKey": "[[parameters('apiKey')]" + }, + "request": { + "apiEndpoint": "https://api.spycloud.io/enterprise-v2/breach/catalog", + "httpMethod": "GET", + "rateLimitQPS": 2, + "queryTimeFormat": "yyyy-MM-ddTHH:mm:ssZ", + "startTimeAttributeName": "since", + "queryWindowInMin": 60, + "headers": { + "Accept": "application/json", + "User-Agent": "spycloud_microsoftccf/1.0.0" + }, + "retryCount": 3, + "timeoutInSeconds": 60 + }, + "response": { + "eventsJsonPaths": [ + "$.results[*]" + ], + "format": "json" + }, + "paging": { + "pagingType": "NextPageToken", + "nextPageTokenJsonPath": "$.cursor", + "nextPageParaName": "cursor", + "pagingInfoPlacement": "QueryString" + }, + "isActive": true + } + }, + { + "name": "[[concat(parameters('innerWorkspace'),'/Microsoft.SecurityInsights/', 'SpyCloudCompassConnector', parameters('guidValue'))]", + "apiVersion": "2023-02-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectors", + "location": "[parameters('workspace-location')]", + "kind": "RestApiPoller", + "properties": { + "connectorDefinitionName": "SpyCloudEnterpriseProtectionCCF", + "dcrConfig": { + "streamName": "Custom-spycloud_compassV2_CL", + "dataCollectionEndpoint": "[[parameters('dcrConfig').dataCollectionEndpoint]", + "dataCollectionRuleImmutableId": "[[parameters('dcrConfig').dataCollectionRuleImmutableId]" + }, + "dataType": "spycloud_compassV2_CL", + "auth": { + "type": "APIKey", + "ApiKeyName": "X-API-KEY", + "ApiKey": "[[parameters('apiKey')]" + }, + "request": { + "apiEndpoint": "https://api.spycloud.io/enterprise-v2/compass/data", + "httpMethod": "GET", + "rateLimitQPS": 1, + "queryTimeFormat": "yyyy-MM-dd", + "startTimeAttributeName": "since", + "queryWindowInMin": 1440, + "headers": { + "Accept": "application/json", + "User-Agent": "spycloud_microsoftccf/1.0.0" + }, + "queryParameters": { + "until": "{_QueryWindowStartTime}" + }, + "retryCount": 3, + "timeoutInSeconds": 60 + }, + "response": { + "eventsJsonPaths": [ + "$.results[*]" + ], + "format": "json" + }, + "paging": { + "pagingType": "NextPageToken", + "nextPageTokenJsonPath": "$.cursor", + "nextPageParaName": "cursor", + "pagingInfoPlacement": "QueryString" + }, + "isActive": true + }, + "condition": "[[equals(parameters('compassEnabled'),'true')]" + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "contentProductId": "[concat(take(variables('_solutionId'), 50),'-','rdc','-', uniqueString(concat(variables('_solutionId'),'-','ResourcesDataConnector','-',variables('_dataConnectorContentIdConnections1'),'-', variables('dataConnectorCCPVersion'))))]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "version": "[variables('dataConnectorCCPVersion')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('parserObject1').parserTemplateSpecName1]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "get_Spycloud_enriched_data Data Parser with template version 3.0.0", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('parserObject1').parserVersion1]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "name": "[variables('parserObject1')._parserName1]", + "apiVersion": "2025-07-01", + "type": "Microsoft.OperationalInsights/workspaces/savedSearches", + "location": "[parameters('workspace-location')]", + "properties": { + "eTag": "*", + "displayName": "SpyCloud Enriched Data Parser", + "category": "Microsoft Sentinel Parser", + "functionAlias": "get_Spycloud_enriched_data", + "query": "let _lookback = coalesce(lookback, 1d);\nlet LatestBreachCatalog =\n SpyCloudBreachCatalogV2_CL\n | summarize arg_max(TimeGenerated, BreachTitle, Description, Status) by SourceId\n | project\n SourceId,\n BreachTitle,\n CatalogDescription = Description,\n CatalogStatus = Status;\nSpyCloudBreachWatchlistV2_CL\n| where TimeGenerated >= ago(_lookback)\n| join kind=leftouter LatestBreachCatalog on SourceId\n| project\n TimeGenerated,\n SourceId,\n InfectedPath,\n UserHostName,\n IPAddresses,\n TimeZone,\n TargetUrl,\n DocumentId,\n TargetDomain,\n UserSysRegisteredOwner,\n DisplayResolution,\n Password,\n Email,\n Severity,\n AVSoftwares,\n LogId,\n UserOS,\n EmailUsername,\n SpyCloudPublishDate,\n InfectedMachineId,\n PasswordPlaintext,\n InfectedTime,\n CountryCode,\n KeyboardLanguages,\n PasswordType,\n Domain,\n EmailDomain,\n TargetSubdomain,\n Sighting,\n AccountLastActivityTime,\n AccountNotes,\n AccountSignupTime,\n Username,\n Homepage,\n Salt,\n AccountLoginTime,\n SocialOther,\n LastName,\n FullName,\n Phone,\n FirstName,\n Address1,\n AccountModificationTime,\n Gender,\n City,\n BirthYear,\n DOB,\n CompanyWebsite,\n Industry,\n AccountStatus,\n SocialCrunchbase,\n CompanyName,\n SocialLinkedIn,\n SocialTwitter,\n AccountCaption,\n Address2,\n SSNLastFour,\n SocialSecurityNumber,\n HealthInsuranceId,\n PostalCode,\n Age,\n TaxId,\n State,\n AccountType,\n DeviceName,\n BankNumber,\n MobileEquipmentId,\n Country,\n EducationalInstitution,\n JobTitle,\n AccountImageUrl,\n StudentId,\n AccountId,\n BreachTitle,\n CatalogDescription,\n CatalogStatus\n", + "functionParameters": "lookback:timespan=1d", + "version": 2, + "tags": [ + { + "name": "description", + "value": "" + } + ] + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('Parser-', last(split(variables('parserObject1')._parserId1,'/'))))]", + "dependsOn": [ + "[variables('parserObject1')._parserId1]" + ], + "properties": { + "parentId": "[resourceId('Microsoft.OperationalInsights/workspaces/savedSearches', parameters('workspace'), 'get_Spycloud_enriched_data')]", + "contentId": "[variables('parserObject1').parserContentId1]", + "kind": "Parser", + "version": "[variables('parserObject1').parserVersion1]", + "source": { + "name": "SpyCloud Enterprise Protection CCF", + "kind": "Solution", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "SpyCloud", + "email": "[variables('_email')]" + }, + "support": { + "name": "SpyCloud", + "tier": "Partner", + "link": "https://support.spycloud.com" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('parserObject1').parserContentId1]", + "contentKind": "Parser", + "displayName": "SpyCloud Enriched Data Parser", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','pr','-', uniqueString(concat(variables('_solutionId'),'-','Parser','-',variables('parserObject1').parserContentId1,'-', '1.0.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','pr','-', uniqueString(concat(variables('_solutionId'),'-','Parser','-',variables('parserObject1').parserContentId1,'-', '1.0.0')))]", + "version": "[variables('parserObject1').parserVersion1]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/savedSearches", + "apiVersion": "2025-07-01", + "name": "[variables('parserObject1')._parserName1]", + "location": "[parameters('workspace-location')]", + "properties": { + "eTag": "*", + "displayName": "SpyCloud Enriched Data Parser", + "category": "Microsoft Sentinel Parser", + "functionAlias": "get_Spycloud_enriched_data", + "query": "let _lookback = coalesce(lookback, 1d);\nlet LatestBreachCatalog =\n SpyCloudBreachCatalogV2_CL\n | summarize arg_max(TimeGenerated, BreachTitle, Description, Status) by SourceId\n | project\n SourceId,\n BreachTitle,\n CatalogDescription = Description,\n CatalogStatus = Status;\nSpyCloudBreachWatchlistV2_CL\n| where TimeGenerated >= ago(_lookback)\n| join kind=leftouter LatestBreachCatalog on SourceId\n| project\n TimeGenerated,\n SourceId,\n InfectedPath,\n UserHostName,\n IPAddresses,\n TimeZone,\n TargetUrl,\n DocumentId,\n TargetDomain,\n UserSysRegisteredOwner,\n DisplayResolution,\n Password,\n Email,\n Severity,\n AVSoftwares,\n LogId,\n UserOS,\n EmailUsername,\n SpyCloudPublishDate,\n InfectedMachineId,\n PasswordPlaintext,\n InfectedTime,\n CountryCode,\n KeyboardLanguages,\n PasswordType,\n Domain,\n EmailDomain,\n TargetSubdomain,\n Sighting,\n AccountLastActivityTime,\n AccountNotes,\n AccountSignupTime,\n Username,\n Homepage,\n Salt,\n AccountLoginTime,\n SocialOther,\n LastName,\n FullName,\n Phone,\n FirstName,\n Address1,\n AccountModificationTime,\n Gender,\n City,\n BirthYear,\n DOB,\n CompanyWebsite,\n Industry,\n AccountStatus,\n SocialCrunchbase,\n CompanyName,\n SocialLinkedIn,\n SocialTwitter,\n AccountCaption,\n Address2,\n SSNLastFour,\n SocialSecurityNumber,\n HealthInsuranceId,\n PostalCode,\n Age,\n TaxId,\n State,\n AccountType,\n DeviceName,\n BankNumber,\n MobileEquipmentId,\n Country,\n EducationalInstitution,\n JobTitle,\n AccountImageUrl,\n StudentId,\n AccountId,\n BreachTitle,\n CatalogDescription,\n CatalogStatus\n", + "functionParameters": "lookback:timespan=1d", + "version": 2, + "tags": [ + { + "name": "description", + "value": "" + } + ] + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "location": "[parameters('workspace-location')]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('Parser-', last(split(variables('parserObject1')._parserId1,'/'))))]", + "dependsOn": [ + "[variables('parserObject1')._parserId1]" + ], + "properties": { + "parentId": "[resourceId('Microsoft.OperationalInsights/workspaces/savedSearches', parameters('workspace'), 'get_Spycloud_enriched_data')]", + "contentId": "[variables('parserObject1').parserContentId1]", + "kind": "Parser", + "version": "[variables('parserObject1').parserVersion1]", + "source": { + "kind": "Solution", + "name": "SpyCloud Enterprise Protection CCF", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "SpyCloud", + "email": "[variables('_email')]" + }, + "support": { + "name": "SpyCloud", + "tier": "Partner", + "link": "https://support.spycloud.com" + } + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('parserObject2').parserTemplateSpecName2]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "get_spycloud_compass_data Data Parser with template version 3.0.0", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('parserObject2').parserVersion2]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "name": "[variables('parserObject2')._parserName2]", + "apiVersion": "2025-07-01", + "type": "Microsoft.OperationalInsights/workspaces/savedSearches", + "location": "[parameters('workspace-location')]", + "properties": { + "eTag": "*", + "displayName": "SpyCloud Compass Data Parser", + "category": "Microsoft Sentinel Parser", + "functionAlias": "get_spycloud_compass_data", + "query": "let _startTime = coalesce(startTime, 1d);\nspycloud_compassV2_CL\n| where TimeGenerated > ago(_startTime)\n| project\n TimeGenerated, DocumentId, SourceId, SpyCloudPublishDate, Email, Domain,\n Password, PasswordPlaintext, Severity, IPAddresses, InfectedMachineId,\n InfectedTime, BreachTitle, BreachCategory\n", + "functionParameters": "startTime:timespan=1d", + "version": 2, + "tags": [ + { + "name": "description", + "value": "" + } + ] + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('Parser-', last(split(variables('parserObject2')._parserId2,'/'))))]", + "dependsOn": [ + "[variables('parserObject2')._parserId2]" + ], + "properties": { + "parentId": "[resourceId('Microsoft.OperationalInsights/workspaces/savedSearches', parameters('workspace'), 'get_spycloud_compass_data')]", + "contentId": "[variables('parserObject2').parserContentId2]", + "kind": "Parser", + "version": "[variables('parserObject2').parserVersion2]", + "source": { + "name": "SpyCloud Enterprise Protection CCF", + "kind": "Solution", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "SpyCloud", + "email": "[variables('_email')]" + }, + "support": { + "name": "SpyCloud", + "tier": "Partner", + "link": "https://support.spycloud.com" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('parserObject2').parserContentId2]", + "contentKind": "Parser", + "displayName": "SpyCloud Compass Data Parser", + "contentProductId": "[concat(take(variables('_solutionId'),50),'-','pr','-', uniqueString(concat(variables('_solutionId'),'-','Parser','-',variables('parserObject2').parserContentId2,'-', '1.0.0')))]", + "id": "[concat(take(variables('_solutionId'),50),'-','pr','-', uniqueString(concat(variables('_solutionId'),'-','Parser','-',variables('parserObject2').parserContentId2,'-', '1.0.0')))]", + "version": "[variables('parserObject2').parserVersion2]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/savedSearches", + "apiVersion": "2025-07-01", + "name": "[variables('parserObject2')._parserName2]", + "location": "[parameters('workspace-location')]", + "properties": { + "eTag": "*", + "displayName": "SpyCloud Compass Data Parser", + "category": "Microsoft Sentinel Parser", + "functionAlias": "get_spycloud_compass_data", + "query": "let _startTime = coalesce(startTime, 1d);\nspycloud_compassV2_CL\n| where TimeGenerated > ago(_startTime)\n| project\n TimeGenerated, DocumentId, SourceId, SpyCloudPublishDate, Email, Domain,\n Password, PasswordPlaintext, Severity, IPAddresses, InfectedMachineId,\n InfectedTime, BreachTitle, BreachCategory\n", + "functionParameters": "startTime:timespan=1d", + "version": 2, + "tags": [ + { + "name": "description", + "value": "" + } + ] + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "location": "[parameters('workspace-location')]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('Parser-', last(split(variables('parserObject2')._parserId2,'/'))))]", + "dependsOn": [ + "[variables('parserObject2')._parserId2]" + ], + "properties": { + "parentId": "[resourceId('Microsoft.OperationalInsights/workspaces/savedSearches', parameters('workspace'), 'get_spycloud_compass_data')]", + "contentId": "[variables('parserObject2').parserContentId2]", + "kind": "Parser", + "version": "[variables('parserObject2').parserVersion2]", + "source": { + "kind": "Solution", + "name": "SpyCloud Enterprise Protection CCF", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "SpyCloud", + "email": "[variables('_email')]" + }, + "support": { + "name": "SpyCloud", + "tier": "Partner", + "link": "https://support.spycloud.com" + } + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('playbookTemplateSpecName1')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "SpyCloud_MDE_Automation Playbook with template version 3.0.0", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('playbookVersion1')]", + "parameters": { + "PlaybookName": { + "defaultValue": "SpyCloud_MDE_Automation", + "type": "string" + } + }, + "variables": { + "loginUrl": "[[environment().authentication.loginEndpoint]", + "AzureSentinelConnectionName": "[[concat('azuresentinel-', parameters('PlaybookName'))]", + "Office365V1": "[[concat('office365-', parameters('PlaybookName'))]", + "WDATPConnection": "[[concat('wdatp-', parameters('PlaybookName'))]", + "connection-1": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]", + "_connection-1": "[[variables('connection-1')]", + "connection-2": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/wdatp')]", + "_connection-2": "[[variables('connection-2')]", + "connection-3": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", + "_connection-3": "[[variables('connection-3')]", + "workspace-location-inline": "[concat('[resourceGroup().locatio', 'n]')]", + "workspace-name": "[parameters('workspace')]", + "workspaceResourceId": "[[resourceId('microsoft.OperationalInsights/Workspaces', variables('workspace-name'))]" + }, + "resources": [ + { + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[[variables('Office365V1')]", + "location": "[[variables('workspace-location-inline')]", + "properties": { + "displayName": "[[variables('Office365V1')]", + "api": { + "id": "[[variables('_connection-1')]" + } + } + }, + { + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[[variables('WDATPConnection')]", + "location": "[[variables('workspace-location-inline')]", + "properties": { + "displayName": "WDATP Connection", + "api": { + "id": "[[variables('_connection-2')]" + } + } + }, + { + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[[variables('AzureSentinelConnectionName')]", + "location": "[[variables('workspace-location-inline')]", + "kind": "V1", + "properties": { + "displayName": "[[variables('AzureSentinelConnectionName')]", + "parameterValueType": "Alternative", + "api": { + "id": "[[variables('_connection-3')]" + } + } + }, + { + "type": "Microsoft.Logic/workflows", + "apiVersion": "2017-07-01", + "name": "[[parameters('PlaybookName')]", + "location": "[[variables('workspace-location-inline')]", + "identity": { + "type": "SystemAssigned" + }, + "dependsOn": [ + "[[resourceId('Microsoft.Web/connections', variables('Office365V1'))]", + "[[resourceId('Microsoft.Web/connections', variables('WDATPConnection'))]", + "[[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]" + ], + "properties": { + "state": "Disabled", + "definition": { + "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "$connections": { + "type": "Object" + }, + "PlaybookName": { + "defaultValue": "[[parameters('PlaybookName')]", + "type": "String" + }, + "Isolate_Machine": { + "type": "Bool", + "defaultValue": false + }, + "Machine_Tag_Value": { + "type": "String" + }, + "Save_IOCs_Defender": { + "type": "Bool", + "defaultValue": false + }, + "IOC_Expiration_Days": { + "type": "Int", + "defaultValue": 30 + }, + "Spycloud_Defender_DCE_Endpoint": { + "type": "String" + }, + "Spycloud_Defender_DCE_Immutable_ID": { + "type": "String" + }, + "TenantID": { + "type": "String" + }, + "ClientID": { + "type": "String" + }, + "Client_Secret": { + "type": "String" + }, + "Ingestion_Table_Name": { + "type": "String", + "defaultValue": "Spycloud_MDE_LogsV2_CL" + }, + "create_incident_in_sentinel": { + "type": "Bool", + "defaultValue": false + }, + "Workspace_Name": { + "type": "String", + "defaultValue": "Your workspace name" + }, + "Defender_IOC_Action_Type": { + "type": "String", + "defaultValue": "Alert" + }, + "notification_email": { + "type": "String" + } + }, + "triggers": { + "Microsoft_Sentinel_incident": { + "type": "ApiConnectionWebhook", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "body": { + "callback_url": "@listCallbackUrl()" + }, + "path": "/incident-creation" + } + } + }, + "actions": { + "Entities_-_Get_Hosts": { + "runAfter": { + "For_each_incident_alert": [ + "Succeeded" + ] + }, + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "post", + "body": "@triggerBody()?['object']?['properties']?['relatedEntities']", + "path": "/entities/host" + } + }, + "For_each": { + "foreach": "@body('Entities_-_Get_Hosts')?['Hosts']", + "actions": { + "Machines_-_Get_single_machine": { + "runAfter": { + "Set_host_name": [ + "Succeeded" + ] + }, + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['wdatp']['connectionId']" + } + }, + "method": "get", + "path": "/api/machines/@variables('host_name')" + } + }, + "GetAccessToken": { + "runAfter": { + "Send_an_email_(V2)": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "uri": "@concat(variables('loginUrl'), parameters('TenantID'), '/oauth2/v2.0/token')", + "method": "POST", + "headers": { + "Content-Type": "application/x-www-form-urlencoded" + }, + "body": "grant_type=client_credentials&client_id=@{parameters('ClientID')}&client_secret=@{parameters('Client_Secret')}&scope=https://monitor.azure.com/.default" + }, + "runtimeConfiguration": { + "contentTransfer": { + "transferMode": "Chunked" + } + } + }, + "Log_ingestion": { + "runAfter": { + "GetAccessToken": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "uri": "@variables('log_ingestion_api')", + "method": "POST", + "headers": { + "Authorization": "Bearer @{body('GetAccessToken')?['access_token']}", + "Content-Type": "application/json" + }, + "body": [ + { + "TimeGenerated": "@{utcNow()}", + "IncidentId": "@{body('Create_incident')?['properties']?['providerIncidentId']}", + "DocumentId": "@{variables('DocumentID')}", + "SpyCloudPublishDate": "@{variables('SpyCloudPublishDate')}", + "InfectedTime": "@{variables('InfectedTime')}", + "BreachTitle": "@{variables('BreachTitle')}", + "InfectedMachineId": "@{variables('InfectedMachineId')}", + "HostName": "@{coalesce(body('Machines_-_Get_single_machine')?['computerDnsName'], '')}", + "NormalizedHostName": "@{toLower(coalesce(body('Machines_-_Get_single_machine')?['computerDnsName'], ''))}", + "DeviceId": "@{coalesce(body('Machines_-_Get_single_machine')?['id'], '')}", + "OSPlatform": "@{coalesce(body('Machines_-_Get_single_machine')?['osPlatform'], '')}", + "RiskScore": "@{coalesce(body('Machines_-_Get_single_machine')?['riskScore'], '')}", + "ExposureLevel": "@{coalesce(body('Machines_-_Get_single_machine')?['exposureLevel'], '')}", + "IsolationRequested": "@variables('machine_isolated')", + "IsolationStatus": "@variables('machine_isolated')", + "MachineTagAdded": "@variables('machine_tag_added')", + "MachineTagName": "@{parameters('Machine_Tag_Value')}", + "AddedIOCsToDefender": "@variables('defender_iocs_added')", + "PlaybookName": "[[parameters('PlaybookName')]" + } + ] + }, + "runtimeConfiguration": { + "contentTransfer": { + "transferMode": "Chunked" + } + } + }, + "Set_host_name": { + "type": "SetVariable", + "inputs": { + "name": "host_name", + "value": "@item()?['HostName']" + } + }, + "Check_Create_Sentinel_Incident": { + "actions": { + "Create_incident": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "put", + "body": { + "title": "Spycloud MDE Alert - Machine Comprised @{variables('host_name')}", + "severity": "High", + "status": "Active", + "description": "The Incident is created from Spycloud MDE Automation Playbook" + }, + "path": "[[concat('/Incidents/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/workspaces/', parameters('Workspace_Name'))]" + } + } + }, + "runAfter": { + "Machines_-_Get_single_machine": [ + "Succeeded" + ] + }, + "expression": { + "and": [ + { + "equals": [ + "@parameters('create_incident_in_sentinel')", + "@true" + ] + } + ] + }, + "type": "If" + }, + "Condition_Isolate_Machine": { + "actions": { + "Condition_-_Check_Machine_is_Active": { + "actions": { + "Set_-_machine_active_to_true": { + "type": "SetVariable", + "inputs": { + "name": "is_machine_active", + "value": true + } + } + }, + "else": { + "actions": { + "Set_machine_active_to_false": { + "type": "SetVariable", + "inputs": { + "name": "is_machine_active", + "value": false + } + } + } + }, + "expression": { + "and": [ + { + "equals": [ + "@body('Machines_-_Get_single_machine')?['healthStatus']", + "Active" + ] + } + ] + }, + "type": "If" + }, + "Condition_-_Check_if_the_machine_is_lastseen_in_the_last_6_hours": { + "actions": { + "Set_last_active": { + "type": "SetVariable", + "inputs": { + "name": "is_last_sees_satisfied", + "value": true + } + } + }, + "runAfter": { + "Condition_-_Check_Machine_is_Active": [ + "Succeeded" + ] + }, + "expression": { + "and": [ + { + "greater": [ + "@ticks(body('Machines_-_Get_single_machine')?['lastSeen'])", + "@ticks(addHours(utcNow(), -6))" + ] + } + ] + }, + "type": "If" + }, + "Condition_If_we_can_Isolate_the_machine": { + "actions": { + "Actions_-_Isolate_machine": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['wdatp']['connectionId']" + } + }, + "method": "post", + "body": { + "Comment": "This machine has found comprised - SpyCloud", + "IsolationType": "Selective" + }, + "path": "/api/machines/@{encodeURIComponent(body('Machines_-_Get_single_machine')?['id'])}/isolate" + } + }, + "set_machine_isolatyed": { + "runAfter": { + "Actions_-_Isolate_machine": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "machine_isolated", + "value": true + } + } + }, + "runAfter": { + "Condition_-_Check_if_the_machine_is_lastseen_in_the_last_6_hours": [ + "Succeeded" + ] + }, + "expression": { + "and": [ + { + "equals": [ + "@variables('is_machine_active')", + "@true" + ] + }, + { + "equals": [ + "@variables('is_last_sees_satisfied')", + "@true" + ] + } + ] + }, + "type": "If" + } + }, + "runAfter": { + "Check_Create_Sentinel_Incident": [ + "Succeeded" + ] + }, + "expression": { + "and": [ + { + "equals": [ + "@parameters('Isolate_Machine')", + "@true" + ] + } + ] + }, + "type": "If" + }, + "Condition_-_Add_Machine_Tag": { + "actions": { + "Machines_-_Tag_machine": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['wdatp']['connectionId']" + } + }, + "method": "post", + "body": { + "Value": "@parameters('Machine_Tag_Value')", + "Action": "Add" + }, + "path": "/api/machines/@{encodeURIComponent(body('Machines_-_Get_single_machine')?['id'])}/tags" + } + }, + "Set_machine_tag_added": { + "runAfter": { + "Machines_-_Tag_machine": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "machine_tag_added", + "value": true + } + } + }, + "runAfter": { + "Condition_Isolate_Machine": [ + "Succeeded" + ] + }, + "expression": { + "and": [ + { + "greater": [ + "@length(parameters('Machine_Tag_Value'))", + 0 + ] + } + ] + }, + "type": "If" + }, + "Send_an_email_(V2)": { + "runAfter": { + "Condition_-_Add_Machine_Tag": [ + "Succeeded" + ] + }, + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['office365']['connectionId']" + } + }, + "method": "post", + "body": { + "To": "@parameters('notification_email')", + "Subject": "@{variables('host_name')} - Security Risk", + "Body": "

Security notification! This is automated email sent by Microsoft Sentinel SpyCloud Automation!


For Host @{variables('host_name')} the following actions were taken


Machine Tag Added : @{variables('machine_tag_added')},

Machine Tag Value : @{parameters('Machine_Tag_Value')},

Machine Isolated: @{variables('machine_isolated')}

", + "Importance": "Normal" + }, + "path": "/v2/Mail" + } + } + }, + "runAfter": { + "Condition_Save_IOCS_in_Defender": [ + "Succeeded" + ] + }, + "type": "Foreach" + }, + "Variables_Section": { + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "log_ingestion_api", + "type": "string", + "value": "@{concat(concat(concat(parameters('Spycloud_Defender_DCE_Endpoint'),'/dataCollectionRules/'),parameters('Spycloud_Defender_DCE_Immutable_ID') ),concat('/streams/Custom-',concat(parameters('Ingestion_Table_Name'), '?api-version=2023-01-01') ))}" + }, + { + "name": "access_token_url", + "type": "string", + "value": "test" + }, + { + "name": "log_ingestion_url", + "type": "string", + "value": "test" + }, + { + "name": "host_name", + "type": "string", + "value": " " + }, + { + "name": "defender_iocs_object", + "type": "array", + "value": "[variables('TemplateEmptyArray')]" + }, + { + "name": "machine_isolated", + "type": "boolean", + "value": false + }, + { + "name": "machine_tag_added", + "type": "boolean", + "value": false + }, + { + "name": "defender_iocs_added", + "type": "boolean", + "value": false + }, + { + "name": "SpyCloudPublishDate", + "type": "string" + }, + { + "name": "InfectedTime", + "type": "string" + }, + { + "name": "BreachTitle", + "type": "string" + }, + { + "name": "InfectedMachineId", + "type": "string" + }, + { + "name": "DocumentID", + "type": "string" + }, + { + "name": "incident_custom_details_object", + "type": "object" + }, + { + "name": "is_machine_onboarded", + "type": "boolean" + }, + { + "name": "is_machine_active", + "type": "boolean", + "value": false + }, + { + "name": "is_machine_excluded", + "type": "boolean", + "value": false + }, + { + "name": "is_last_sees_satisfied", + "type": "boolean", + "value": false + } + ] + } + }, + "Condition_Save_IOCS_in_Defender": { + "actions": { + "Entities_-_Get_DNS": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "post", + "body": "@triggerBody()?['object']?['properties']?['relatedEntities']", + "path": "/entities/dnsresolution" + } + }, + "Entities_-_Get_IPs": { + "runAfter": { + "For_each_Domains_in_incident": [ + "Succeeded" + ] + }, + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "post", + "body": "@triggerBody()?['object']?['properties']?['relatedEntities']", + "path": "/entities/ip" + } + }, + "Entities_-_Get_URLs": { + "runAfter": { + "For_each_IPs_in_incident": [ + "Succeeded" + ] + }, + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "post", + "body": "@triggerBody()?['object']?['properties']?['relatedEntities']", + "path": "/entities/url" + } + }, + "For_each_Domains_in_incident": { + "foreach": "@body('Entities_-_Get_DNS')?['Dnsresolutions']", + "actions": { + "Domain_IOC_Obejct": { + "type": "Compose", + "inputs": { + "action": "@parameters('Defender_IOC_Action_Type')", + "description": "SpyCloud MDE Playbook", + "indicatorType": "DomainName", + "indicatorValue": "@item()?['DomainName']", + "title": "SpyCloud MDE Playbook", + "application": "SpyCloud", + "expirationTime": "@addDays(utcNow(),parameters('IOC_Expiration_Days'),'yyyy-MM-ddTHH:mm:ssZ')" + }, + "description": "SpyCloud MDE Playbook" + }, + "Build_IOC_Object": { + "runAfter": { + "Domain_IOC_Obejct": [ + "Succeeded" + ] + }, + "type": "AppendToArrayVariable", + "inputs": { + "name": "defender_iocs_object", + "value": "@outputs('Domain_IOC_Obejct')" + } + } + }, + "runAfter": { + "Entities_-_Get_DNS": [ + "Succeeded" + ] + }, + "type": "Foreach" + }, + "For_each_IPs_in_incident": { + "foreach": "@body('Entities_-_Get_IPs')?['IPs']", + "actions": { + "IP_IOC_Obejct": { + "type": "Compose", + "inputs": { + "action": "Block", + "description": "SpyCloiud MDE Playbook", + "indicatorType": "IpAddress", + "indicatorValue": "@item()?['Address']", + "title": "SpyCloiud MDE Playbook", + "application": "SpyCloud", + "expirationTime": "@addDays(utcNow(),parameters('IOC_Expiration_Days'),'yyyy-MM-ddTHH:mm:ssZ')" + }, + "description": "SpyCloud MDE Playbook" + }, + "Build_IOC_Object_1": { + "runAfter": { + "IP_IOC_Obejct": [ + "Succeeded" + ] + }, + "type": "AppendToArrayVariable", + "inputs": { + "name": "defender_iocs_object", + "value": "@outputs('IP_IOC_Obejct')" + } + } + }, + "runAfter": { + "Entities_-_Get_IPs": [ + "Succeeded" + ] + }, + "type": "Foreach" + }, + "For_each_Url_in_incident": { + "foreach": "@body('Entities_-_Get_URLs')?['URLs']", + "actions": { + "Url_IOC_Obejct": { + "type": "Compose", + "inputs": { + "action": "Block", + "description": "SpyCloiud MDE Playbook", + "indicatorType": "Url", + "indicatorValue": "@item()?['Url']", + "title": "SpyCloiud MDE Playbook", + "application": "SpyCloud", + "expirationTime": "@addDays(utcNow(),parameters('IOC_Expiration_Days'),'yyyy-MM-ddTHH:mm:ssZ')" + }, + "description": "SpyCloud MDE Playbook" + }, + "Build_IOC_Object_2": { + "runAfter": { + "Url_IOC_Obejct": [ + "Succeeded" + ] + }, + "type": "AppendToArrayVariable", + "inputs": { + "name": "defender_iocs_object", + "value": "@outputs('Url_IOC_Obejct')" + } + } + }, + "runAfter": { + "Entities_-_Get_URLs": [ + "Succeeded" + ] + }, + "type": "Foreach" + }, + "Auth_MDE": { + "runAfter": { + "For_each_Url_in_incident": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "uri": "@concat(variables('loginUrl'), parameters('TenantID'), '/oauth2/v2.0/token')", + "method": "POST", + "headers": { + "Content-Type": "application/x-www-form-urlencoded" + }, + "body": "grant_type=client_credentials&client_id=@{parameters('ClientID')}&client_secret=@{parameters('Client_Secret')}&scope=https://securitycenter.onmicrosoft.com/windowsatpservice/.default" + }, + "runtimeConfiguration": { + "contentTransfer": { + "transferMode": "Chunked" + } + } + }, + "HTTP_-_Create_Indicator": { + "runAfter": { + "Auth_MDE": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "uri": "https://api.security.microsoft.com/api/indicators/import", + "method": "POST", + "headers": { + "Authorization": "Bearer @{body('Auth_MDE')?['access_token']}" + }, + "body": { + "Indicators": "@variables('defender_iocs_object')" + } + }, + "runtimeConfiguration": { + "contentTransfer": { + "transferMode": "Chunked" + } + } + }, + "Set_defender_iocs_variable": { + "runAfter": { + "HTTP_-_Create_Indicator": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "defender_iocs_added", + "value": true + } + } + }, + "runAfter": { + "Entities_-_Get_Hosts": [ + "Succeeded" + ] + }, + "expression": { + "and": [ + { + "equals": [ + "@parameters('Save_IOCs_Defender')", + "@true" + ] + } + ] + }, + "type": "If" + }, + "For_each_incident_alert": { + "foreach": "@triggerBody()?['object']?['properties']?['Alerts']", + "actions": { + "Set_custom_details_object": { + "type": "SetVariable", + "inputs": { + "name": "incident_custom_details_object", + "value": "@json(items('For_each_incident_alert')?['properties']?['additionalData']?['Custom Details'])" + } + }, + "Set_Spycloud_publish_date": { + "runAfter": { + "Set_custom_details_object": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "SpyCloudPublishDate", + "value": "@first(coalesce(variables('incident_custom_details_object')?['SpyCloudPublishDate'], createArray('')))" + } + }, + "Set_Infected_Time": { + "runAfter": { + "Set_Spycloud_publish_date": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "InfectedTime", + "value": "@first(coalesce(variables('incident_custom_details_object')?['InfectedTime'], createArray('')))" + } + }, + "Set_Breach_Title": { + "runAfter": { + "Set_Infected_Time": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "BreachTitle", + "value": "@first(coalesce(variables('incident_custom_details_object')?['BreachTitle'], createArray('')))\r\n" + } + }, + "Set_Infected_Machine_ID": { + "runAfter": { + "Set_Breach_Title": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "InfectedMachineId", + "value": "@first(coalesce(variables('incident_custom_details_object')?['InfectedMachineId'], createArray('')))" + } + }, + "Set_Document_ID": { + "runAfter": { + "Set_Infected_Machine_ID": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "DocumentID", + "value": "@first(coalesce(variables('incident_custom_details_object')?['DocumentID'], createArray('')))" + } + } + }, + "runAfter": { + "Variables_Section": [ + "Succeeded" + ] + }, + "type": "Foreach" + } + } + }, + "parameters": { + "$connections": { + "value": { + "wdatp": { + "connectionId": "[[resourceId('Microsoft.Web/connections', variables('WDATPConnection'))]", + "connectionName": "[[variables('WDATPConnection')]", + "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/wdatp')]" + }, + "azuresentinel": { + "connectionId": "[[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]", + "connectionName": "[[variables('AzureSentinelConnectionName')]", + "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", + "connectionProperties": { + "authentication": { + "type": "ManagedServiceIdentity" + } + } + }, + "office365": { + "connectionId": "[[resourceId('Microsoft.Web/connections', variables('Office365V1'))]", + "connectionName": "[[variables('Office365V1')]", + "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]" + } + } + } + } + }, + "tags": { + "hidden-SentinelWorkspaceId": "[[variables('workspaceResourceId')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('Playbook-', last(split(variables('playbookId1'),'/'))))]", + "properties": { + "parentId": "[variables('playbookId1')]", + "contentId": "[variables('_playbookContentId1')]", + "kind": "Playbook", + "version": "[variables('playbookVersion1')]", + "source": { + "kind": "Solution", + "name": "SpyCloud Enterprise Protection CCF", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "SpyCloud", + "email": "[variables('_email')]" + }, + "support": { + "name": "SpyCloud", + "tier": "Partner", + "link": "https://support.spycloud.com" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_playbookContentId1')]", + "contentKind": "Playbook", + "displayName": "SpyCloud_MDE_Automation", + "contentProductId": "[variables('_playbookcontentProductId1')]", + "id": "[variables('_playbookcontentProductId1')]", + "version": "[variables('playbookVersion1')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('playbookTemplateSpecName2')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "SpyCloud_Conditional_Access_Playbook Playbook with template version 3.0.0", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('playbookVersion2')]", + "parameters": { + "PlaybookName": { + "defaultValue": "SpyCloud_Conditional_Access_Playbook", + "type": "string" + } + }, + "variables": { + "loginUrl": "[[environment().authentication.loginEndpoint]", + "AzureSentinelConnectionName": "[[concat('azuresentinel-', parameters('PlaybookName'))]", + "Office365V1": "[[concat('office365-', parameters('PlaybookName'))]", + "subscription": "[[last(split(subscription().id, '/'))]", + "resourceGroupName": "[[resourceGroup().name]", + "connection-1": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]", + "_connection-1": "[[variables('connection-1')]", + "connection-2": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", + "_connection-2": "[[variables('connection-2')]", + "workspace-location-inline": "[concat('[resourceGroup().locatio', 'n]')]", + "workspace-name": "[parameters('workspace')]", + "workspaceResourceId": "[[resourceId('microsoft.OperationalInsights/Workspaces', variables('workspace-name'))]" + }, + "resources": [ + { + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[[variables('Office365V1')]", + "location": "[[variables('workspace-location-inline')]", + "properties": { + "displayName": "[[variables('Office365V1')]", + "api": { + "id": "[[variables('_connection-1')]" + } + } + }, + { + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[[variables('AzureSentinelConnectionName')]", + "location": "[[variables('workspace-location-inline')]", + "kind": "V1", + "properties": { + "displayName": "[[variables('AzureSentinelConnectionName')]", + "parameterValueType": "Alternative", + "api": { + "id": "[[variables('_connection-2')]" + } + } + }, + { + "type": "Microsoft.Logic/workflows", + "apiVersion": "2017-07-01", + "name": "[[parameters('PlaybookName')]", + "location": "[[variables('workspace-location-inline')]", + "identity": { + "type": "SystemAssigned" + }, + "dependsOn": [ + "[[resourceId('Microsoft.Web/connections', variables('Office365V1'))]", + "[[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]" + ], + "properties": { + "state": "Disabled", + "definition": { + "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "$connections": { + "type": "Object" + }, + "PlaybookName": { + "defaultValue": "[[parameters('PlaybookName')]", + "type": "String" + }, + "Notify_Users_Emails": { + "type": "String" + }, + "Force_Password_Reset_On_Next_SignIn": { + "type": "Bool", + "defaultValue": false + }, + "Disable_User": { + "type": "Bool", + "defaultValue": false + }, + "Add_User_To_Azure_CA_Group": { + "type": "Bool", + "defaultValue": false + }, + "Azure_CA_Group_Object_ID": { + "type": "String" + }, + "Revoke_User_Sessions": { + "type": "Bool", + "defaultValue": false + }, + "ClientID": { + "type": "String" + }, + "TenantID": { + "type": "String" + }, + "ClientSecret": { + "type": "String" + }, + "DCE_Endpoint": { + "type": "String" + }, + "DCE_Immutable_ID": { + "type": "String" + }, + "Custom_Table_Name": { + "type": "String", + "defaultValue": "SpyCloud_ConditionalAccessLogsV2_CL" + } + }, + "triggers": { + "Microsoft_Sentinel_incident": { + "type": "ApiConnectionWebhook", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "body": { + "callback_url": "@{listCallbackUrl()}" + }, + "path": "/incident-creation" + } + } + }, + "actions": { + "Entities_-_Get_Accounts": { + "runAfter": { + "For_each_incident_alert": [ + "Succeeded" + ] + }, + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "post", + "body": "@triggerBody()?['object']?['properties']?['relatedEntities']", + "path": "/entities/account" + } + }, + "For_each": { + "foreach": "@body('Entities_-_Get_Accounts')?['Accounts']", + "actions": { + "Get_User_Details": { + "runAfter": { + "Set_user": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "uri": "https://graph.microsoft.com/v1.0/users/@{variables('user_email')}?$select=id,displayName,accountEnabled,lastPasswordChangeDateTime,userPrincipalName", + "method": "GET", + "authentication": { + "type": "ActiveDirectoryOAuth", + "authority": "@{variables('Authority')}", + "tenant": "@{parameters('TenantID')}", + "audience": "@{variables('Audience')}", + "clientId": "@{parameters('ClientID')}", + "secret": "@{parameters('ClientSecret')}" + } + }, + "runtimeConfiguration": { + "contentTransfer": { + "transferMode": "Chunked" + } + } + }, + "Set_user": { + "type": "SetVariable", + "inputs": { + "name": "user_email", + "value": "@{concat(items('For_each')?['Name'],'@',items('for_each')?['UPNSuffix'])}" + } + }, + "Condition_-_Check_if_user_is_enabled": { + "actions": { + "Condition_Check_if_password_has_not_been_reset_since_7_days": { + "actions": { + "Condition_-_Check_if_user_needs_to_be_added_to_CA_group_": { + "actions": { + "Add_user_to_Conditional_Access_Group": { + "type": "Http", + "inputs": { + "uri": "https://graph.microsoft.com/v1.0/groups/@{parameters('Azure_CA_Group_Object_ID')}/members/$ref", + "method": "POST", + "body": { + "@@odata.id": "https://graph.microsoft.com/v1.0/directoryObjects/@{body('Get_User_Details')?['id']}" + }, + "authentication": { + "type": "ActiveDirectoryOAuth", + "authority": "@{variables('Authority')}", + "tenant": "@{parameters('TenantID')}", + "audience": "@{variables('Audience')}", + "clientId": "@{parameters('ClientID')}", + "secret": "@{parameters('ClientSecret')}" + } + }, + "runtimeConfiguration": { + "contentTransfer": { + "transferMode": "Chunked" + } + } + }, + "Set_Added_To_CA_Group_Enforced": { + "runAfter": { + "Add_user_to_Conditional_Access_Group": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "AddedToCAGroupEnforced", + "value": true + } + }, + "Set_Added_To_CA_Group_Enforced_Text": { + "runAfter": { + "Set_Added_To_CA_Group_Enforced": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "AddedToCAGroupText", + "value": "Successfully added the user to Conditional Access Group." + } + } + }, + "runAfter": { + "Condition_-_Check_Revoke_User_Sessions": [ + "Succeeded" + ] + }, + "expression": { + "and": [ + { + "not": { + "equals": [ + "@parameters('Add_User_To_Azure_CA_Group')", + "@true" + ] + } + } + ] + }, + "type": "If" + }, + "Condition_-_If_User_needs_to_be_disabled": { + "actions": { + "HTTP_-_Disable_User": { + "type": "Http", + "inputs": { + "uri": "https://graph.microsoft.com/v1.0/users/@{variables('user_email')}", + "method": "PATCH", + "body": { + "accountEnabled": false + }, + "authentication": { + "type": "ActiveDirectoryOAuth", + "authority": "@{variables('Authority')}", + "tenant": "@{parameters('TenantID')}", + "audience": "@{variables('Audience')}", + "clientId": "@{parameters('ClientID')}", + "secret": "@{parameters('ClientSecret')}" + } + } + }, + "Set_Account_Disabled_": { + "runAfter": { + "HTTP_-_Disable_User": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "AccountDisabledEnforced", + "value": true + } + }, + "Set_Account_Disabled_Text": { + "runAfter": { + "Set_Account_Disabled_": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "AccountDisabledText", + "value": "The User has been successfully Disabled." + } + } + }, + "runAfter": { + "Condition_-_Check_if_user_needs_to_be_added_to_CA_group_": [ + "Succeeded" + ] + }, + "expression": { + "and": [ + { + "equals": [ + "@parameters('Disable_User')", + "@true" + ] + } + ] + }, + "type": "If" + }, + "Condition_-_Check_Revoke_User_Sessions": { + "actions": { + "HTTP_-_Revoke_User_Sessions": { + "type": "Http", + "inputs": { + "uri": "https://graph.microsoft.com/v1.0/users/@{variables('user_email')}/revokeSignInSessions", + "method": "POST", + "authentication": { + "type": "ActiveDirectoryOAuth", + "authority": "@{variables('Authority')}", + "tenant": "@{parameters('TenantID')}", + "audience": "@{variables('Audience')}", + "clientId": "@{parameters('ClientID')}", + "secret": "@{parameters('ClientSecret')}" + } + }, + "runtimeConfiguration": { + "contentTransfer": { + "transferMode": "Chunked" + } + } + }, + "Set_User_Session_Enforced": { + "runAfter": { + "HTTP_-_Revoke_User_Sessions": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "UserSessionsRevokeEnforced", + "value": true + } + }, + "Set_User_Session_Revoke_Text": { + "runAfter": { + "Set_User_Session_Enforced": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "UserSessionRevokeText", + "value": "User sessions has been scessfully revoked." + } + } + }, + "runAfter": { + "Condition-Check_for_Password_Reset": [ + "Succeeded" + ] + }, + "expression": { + "and": [ + { + "equals": [ + "@parameters('Revoke_User_Sessions')", + "@true" + ] + } + ] + }, + "type": "If" + }, + "Condition-Check_for_Password_Reset": { + "actions": { + "Force_Password_Reset": { + "type": "Http", + "inputs": { + "uri": "https://graph.microsoft.com/v1.0/users/@{variables('user_email')}", + "method": "PATCH", + "body": { + "passwordProfile": { + "forceChangePasswordNextSignIn": true + } + }, + "authentication": { + "type": "ActiveDirectoryOAuth", + "authority": "@{variables('Authority')}", + "tenant": "@{parameters('TenantID')}", + "audience": "@{variables('Audience')}", + "clientId": "@{parameters('ClientID')}", + "secret": "@{parameters('ClientSecret')}" + } + }, + "runtimeConfiguration": { + "contentTransfer": { + "transferMode": "Chunked" + } + } + }, + "Set_Passwod_Reset_Enforced": { + "runAfter": { + "Force_Password_Reset": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "PasswordResetEnforced", + "value": true + } + }, + "Set_Password_Reset_Text": { + "runAfter": { + "Set_Passwod_Reset_Enforced": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "PasswordResetText", + "value": "Password has been successfully reset" + } + } + }, + "expression": { + "and": [ + { + "equals": [ + "@parameters('Force_Password_Reset_On_Next_SignIn')", + "@true" + ] + } + ] + }, + "type": "If" + }, + "Add_comment_to_incident": { + "runAfter": { + "Condition_-_If_User_needs_to_be_disabled": [ + "Succeeded" + ] + }, + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "post", + "body": { + "incidentArmId": "@triggerBody()?['object']?['id']", + "message": "

For User @{items('For_each')?['Name']} (UPN -@{variables('user_email')} ) the following actions were done from the Spycloud playbook. Manager () is notified.

@{variables('PasswordResetText')}

@{variables('AddedToCAGroupText')}

@{variables('UserSessionRevokeText')}

@{variables('AccountDisabledText')}


" + }, + "path": "/Incidents/Comment" + } + }, + "Send_an_email_-_to_manager_": { + "runAfter": { + "Add_comment_to_incident": [ + "Succeeded" + ] + }, + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['office365']['connectionId']" + } + }, + "method": "post", + "body": { + "To": "@parameters('Notify_Users_Emails')", + "Subject": "@{items('For_each')?['Name']} - security risk!", + "Body": "

Security notification! This is automated email sent by Microsoft Sentinel SpyCloud Automation!

For User @{items('For_each')?['Name']} (UPN -@{variables('user_email')} ) the following actions were done from the Spycloud playbook.
@{variables('PasswordResetText')}
@{variables('AddedToCAGroupText')}
@{variables('UserSessionRevokeText')}
@{variables('AccountDisabledText')}




Can you please notify the user and work with him to reach our support.


", + "Importance": "High" + }, + "path": "/v2/Mail" + } + } + }, + "else": { + "actions": { + "Add_comment_to_incident_-_Password_Latest": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "post", + "body": { + "incidentArmId": "@triggerBody()?['object']?['id']", + "message": "

For User @{items('For_each')?['Name']} (UPN -@{variables('user_email')} ) no actions were done from the Spycloud playbook.


Reason: Password has been reset after the breached date by the user.





" + }, + "path": "/Incidents/Comment" + } + } + } + }, + "expression": { + "and": [ + { + "not": { + "equals": [ + "@parseDateTime(body('Get_User_Details')?['lastPasswordChangeDateTime'])", + "@parseDateTime(variables('SpyCloudPublishDate'))" + ] + } + } + ] + }, + "type": "If" + }, + "GetAccessToken": { + "runAfter": { + "Condition_Check_if_password_has_not_been_reset_since_7_days": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "uri": "@concat(variables('loginUrl'), parameters('TenantID'), '/oauth2/v2.0/token')", + "method": "POST", + "headers": { + "Content-Type": "application/x-www-form-urlencoded" + }, + "body": "grant_type=client_credentials&client_id=@{parameters('ClientID')}&client_secret=@{parameters('ClientSecret')}&scope=https://monitor.azure.com/.default" + }, + "runtimeConfiguration": { + "contentTransfer": { + "transferMode": "Chunked" + } + } + }, + "Log_ingestion": { + "runAfter": { + "GetAccessToken": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "uri": "@variables('log_ingestion_api')", + "method": "POST", + "headers": { + "Authorization": "Bearer @{body('GetAccessToken')?['access_token']}", + "Content-Type": "application/json" + }, + "body": [ + { + "TimeGenerated": "@{utcNow()}", + "IncidentId": "@{triggerBody()?['object']?['properties']?['providerIncidentId']}", + "DocumentId": "@{variables('DocumentID')}", + "SpyCloudPublishDate": "@{variables('SpyCloudPublishDate')}", + "InfectedTime": "@{variables('InfectedTime')}", + "BreachTitle": "@{variables('BreachTitle')}", + "InfectedMachineId": "@{variables('InfectedMachineId')}", + "Username": "@{variables('user_email')}", + "UserEmail": "@{variables('user_email')}", + "ForcedPasswordResetOnNextSignIn": "@variables('PasswordResetEnforced')", + "UserSessionsRevoked": "@variables('UserSessionsRevokeEnforced')", + "CAgroup": "@variables('AddedToCAGroupEnforced')", + "UserDisabled": "@variables('AccountDisabledEnforced')", + "PlaybookName": "SpyCloud_Conditonal_Access_Automation" + } + ] + }, + "runtimeConfiguration": { + "contentTransfer": { + "transferMode": "Chunked" + } + } + } + }, + "runAfter": { + "Get_User_Details": [ + "Succeeded" + ] + }, + "else": { + "actions": { + "Add_comment_to_incident_-_user_disable": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "post", + "body": { + "incidentArmId": "@triggerBody()?['object']?['id']", + "message": "

For User @{items('For_each')?['Name']} (UPN -@{variables('user_email')} ) no actions were done from the Spycloud playbook.


Reason: The user is currently disabled..



" + }, + "path": "/Incidents/Comment" + } + } + } + }, + "expression": { + "and": [ + { + "equals": [ + "@body('Get_User_Details')?['accountEnabled']", + "@true" + ] + } + ] + }, + "type": "If" + } + }, + "runAfter": { + "Entities_-_Get_Accounts": [ + "Succeeded" + ] + }, + "type": "Foreach" + }, + "For_each_incident_alert": { + "foreach": "@triggerBody()?['object']?['properties']?['Alerts']", + "actions": { + "Set_custom_details_object": { + "type": "SetVariable", + "inputs": { + "name": "incident_custom_details_object", + "value": "@json(items('For_each_incident_alert')?['properties']?['additionalData']?['Custom Details'])" + } + }, + "Set_Spycloud_publish_date": { + "runAfter": { + "Set_custom_details_object": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "SpyCloudPublishDate", + "value": "@first(coalesce(variables('incident_custom_details_object')?['SpyCloudPublishDate'], createArray('')))" + } + }, + "Set_Infected_Time": { + "runAfter": { + "Set_Spycloud_publish_date": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "InfectedTime", + "value": "@first(coalesce(variables('incident_custom_details_object')?['InfectedTime'], createArray('')))" + } + }, + "Set_Breach_Title": { + "runAfter": { + "Set_Infected_Time": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "BreachTitle", + "value": "@first(coalesce(variables('incident_custom_details_object')?['BreachTitle'], createArray('')))\n" + } + }, + "Set_Infected_Machine_ID": { + "runAfter": { + "Set_Breach_Title": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "InfectedMachineId", + "value": "@first(coalesce(variables('incident_custom_details_object')?['InfectedMachineId'], createArray('')))" + } + }, + "Set_Document_ID": { + "runAfter": { + "Set_Infected_Machine_ID": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "DocumentID", + "value": "@first(coalesce(variables('incident_custom_details_object')?['DocumentID'], createArray('')))" + } + }, + "Set_log_ingestion_api_url": { + "runAfter": { + "Set_Document_ID": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "log_ingestion_api", + "value": "@concat(concat(concat(parameters('DCE_Endpoint'),'/dataCollectionRules/'),parameters('DCE_Immutable_ID') ),concat('/streams/Custom-',concat(parameters('Custom_Table_Name'), '?api-version=2023-01-01') ))" + } + } + }, + "runAfter": { + "variables_Section": [ + "Succeeded" + ] + }, + "type": "Foreach" + }, + "variables_Section": { + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "incident_custom_details_object", + "type": "object" + }, + { + "name": "SpyCloudPublishDate", + "type": "string" + }, + { + "name": "InfectedTime", + "type": "string" + }, + { + "name": "BreachTitle", + "type": "string" + }, + { + "name": "InfectedMachineId", + "type": "string" + }, + { + "name": "DocumentID", + "type": "string" + }, + { + "name": "last_password_reset_date", + "type": "string" + }, + { + "name": "Authority", + "type": "string", + "value": "[[variables('loginUrl')]" + }, + { + "name": "Audience", + "type": "string", + "value": "https://graph.microsoft.com" + }, + { + "name": "user_email", + "type": "string" + }, + { + "name": "log_ingestion_api", + "type": "string" + }, + { + "name": "PasswordResetEnforced", + "type": "boolean", + "value": false + }, + { + "name": "AccountDisabledEnforced", + "type": "boolean", + "value": false + }, + { + "name": "AddedToCAGroupEnforced", + "type": "boolean", + "value": false + }, + { + "name": "PasswordResetText", + "type": "string" + }, + { + "name": "AccountDisabledText", + "type": "string" + }, + { + "name": "AddedToCAGroupText", + "type": "string" + }, + { + "name": "UserSessionsRevokeEnforced", + "type": "boolean", + "value": false + }, + { + "name": "UserSessionRevokeText", + "type": "string" + } + ] + } + } + } + }, + "parameters": { + "$connections": { + "value": { + "azuresentinel": { + "connectionId": "[[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]", + "connectionName": "[[variables('AzureSentinelConnectionName')]", + "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", + "connectionProperties": { + "authentication": { + "type": "ManagedServiceIdentity" + } + } + }, + "office365": { + "connectionId": "[[resourceId('Microsoft.Web/connections', variables('Office365V1'))]", + "connectionName": "[[variables('Office365V1')]", + "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]" + } + } + } + } + }, + "tags": { + "hidden-SentinelWorkspaceId": "[[variables('workspaceResourceId')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('Playbook-', last(split(variables('playbookId2'),'/'))))]", + "properties": { + "parentId": "[variables('playbookId2')]", + "contentId": "[variables('_playbookContentId2')]", + "kind": "Playbook", + "version": "[variables('playbookVersion2')]", + "source": { + "kind": "Solution", + "name": "SpyCloud Enterprise Protection CCF", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "SpyCloud", + "email": "[variables('_email')]" + }, + "support": { + "name": "SpyCloud", + "tier": "Partner", + "link": "https://support.spycloud.com" + } + } + } + ], + "metadata": { + "title": "SpyCloud Conditional Access Playbook", + "description": "Spycloud Conditional access playbook", + "prerequisites": "Create an App in App registration and provide permissions and create a client secret", + "lastUpdateTime": "2026-03-11T00:00:00Z", + "entities": [ + "account" + ], + "releaseNotes": { + "version": "1.0", + "title": "[variables('blanks')]", + "notes": [ + "Initial version" + ] + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_playbookContentId2')]", + "contentKind": "Playbook", + "displayName": "SpyCloud_Conditional_Access_Playbook", + "contentProductId": "[variables('_playbookcontentProductId2')]", + "id": "[variables('_playbookcontentProductId2')]", + "version": "[variables('playbookVersion2')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('playbookTemplateSpecName3')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "SpyCloud_AutomationRules Playbook with template version 3.0.0", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('playbookVersion3')]", + "parameters": { + "Sentinel_Workspace_Resource_Id": { + "type": "string", + "metadata": { + "description": "Full resource ID of the Log Analytics workspace with Microsoft Sentinel enabled (e.g., /subscriptions/.../resourceGroups/.../providers/Microsoft.OperationalInsights/workspaces/...)" + } + }, + "MDE_PlaybookName": { + "type": "string", + "defaultValue": "SpyCloud_MDE_Automation", + "metadata": { + "description": "Name of the SpyCloud_MDE_Automation Logic App" + } + }, + "ConditionalAccess_PlaybookName": { + "type": "string", + "defaultValue": "SpyCloud_Conditional_Access_Playbook", + "metadata": { + "description": "Name of the SpyCloud_Conditional_Access_Playbook Logic App" + } + }, + "MalwareAnalyticRuleId": { + "type": "string", + "defaultValue": "ead4deed-9d48-4646-aee0-6b46c2dd1ae6", + "metadata": { + "description": "GUID of the SpyCloud infostealer malware credential exposure analytic rule (AR_malware_25) that triggers the MDE automation rule" + } + }, + "BreachedUsersAnalyticRuleId": { + "type": "string", + "defaultValue": "a25eba0e-ff42-4c97-a379-d76bdb2aa1e3", + "metadata": { + "description": "GUID of the SpyCloud plaintext credential exposure analytic rule (AR_Breached_Users_20) that triggers the Conditional Access automation rule" + } + }, + "MDE_Automation_Rule_Order": { + "type": "int", + "defaultValue": 1, + "metadata": { + "description": "Execution order of the MDE automation rule (lower = higher priority)" + } + }, + "ConditionalAccess_Automation_Rule_Order": { + "type": "int", + "defaultValue": 2, + "metadata": { + "description": "Execution order of the Conditional Access automation rule (lower = higher priority)" + } + } + }, + "variables": { + "mdeAutomationRuleName": "[[guid('SpyCloud-MDE-Rule', parameters('Sentinel_Workspace_Resource_Id'))]", + "conditionalAccessAutomationRuleName": "[[guid('SpyCloud-ConditionalAccess-Rule', parameters('Sentinel_Workspace_Resource_Id'))]", + "workspace-location-inline": "[concat('[resourceGroup().locatio', 'n]')]", + "workspace-name": "[parameters('workspace')]", + "workspaceResourceId": "[[resourceId('microsoft.OperationalInsights/Workspaces', variables('workspace-name'))]" + }, + "resources": [ + { + "type": "Microsoft.SecurityInsights/automationRules", + "name": "[[variables('mdeAutomationRuleName')]", + "scope": "[[parameters('Sentinel_Workspace_Resource_Id')]", + "apiVersion": "2023-02-01-preview", + "properties": { + "displayName": "SpyCloud - Isolate compromised device on malware exposure", + "order": "[[parameters('MDE_Automation_Rule_Order')]", + "triggeringLogic": { + "isEnabled": true, + "triggersOn": "Incidents", + "triggersWhen": "Created", + "conditions": [ + { + "conditionType": "Property", + "conditionProperties": { + "propertyName": "IncidentRelatedAnalyticRuleIds", + "operator": "Contains", + "propertyValues": [ + "[[extensionResourceId(parameters('Sentinel_Workspace_Resource_Id'), 'Microsoft.SecurityInsights/alertRules', parameters('MalwareAnalyticRuleId'))]" + ] + } + } + ] + }, + "actions": [ + { + "order": 1, + "actionType": "RunPlaybook", + "actionConfiguration": { + "logicAppResourceId": "[[resourceId('Microsoft.Logic/workflows', parameters('MDE_PlaybookName'))]", + "tenantId": "[[subscription().tenantId]" + } + } + ] + } + }, + { + "type": "Microsoft.SecurityInsights/automationRules", + "name": "[[variables('conditionalAccessAutomationRuleName')]", + "scope": "[[parameters('Sentinel_Workspace_Resource_Id')]", + "apiVersion": "2023-02-01-preview", + "properties": { + "displayName": "SpyCloud - Enforce Conditional Access on credential exposure", + "order": "[[parameters('ConditionalAccess_Automation_Rule_Order')]", + "triggeringLogic": { + "isEnabled": true, + "triggersOn": "Incidents", + "triggersWhen": "Created", + "conditions": [ + { + "conditionType": "Property", + "conditionProperties": { + "propertyName": "IncidentRelatedAnalyticRuleIds", + "operator": "Contains", + "propertyValues": [ + "[[extensionResourceId(parameters('Sentinel_Workspace_Resource_Id'), 'Microsoft.SecurityInsights/alertRules', parameters('BreachedUsersAnalyticRuleId'))]" + ] + } + } + ] + }, + "actions": [ + { + "order": 1, + "actionType": "RunPlaybook", + "actionConfiguration": { + "logicAppResourceId": "[[resourceId('Microsoft.Logic/workflows', parameters('ConditionalAccess_PlaybookName'))]", + "tenantId": "[[subscription().tenantId]" + } + } + ] + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('Playbook-', last(split(variables('playbookId3'),'/'))))]", + "properties": { + "parentId": "[variables('playbookId3')]", + "contentId": "[variables('_playbookContentId3')]", + "kind": "Playbook", + "version": "[variables('playbookVersion3')]", + "source": { + "kind": "Solution", + "name": "SpyCloud Enterprise Protection CCF", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "SpyCloud", + "email": "[variables('_email')]" + }, + "support": { + "name": "SpyCloud", + "tier": "Partner", + "link": "https://support.spycloud.com" + } + } + } + ], + "metadata": { + "title": "SpyCloud Enterprise Protection - Automation Rules", + "description": "Deploys automation rules that trigger the SpyCloud MDE Automation and SpyCloud Conditional Access playbooks when a matching SpyCloud analytic rule creates an incident.", + "prerequisites": [ + "1. The SpyCloud_MDE_Automation and SpyCloud_Conditional_Access_Playbook playbooks must be deployed in the same resource group.", + "2. The SpyCloud analytic rules (AR_malware_25, AR_Breached_Users_20) must be deployed to the same Microsoft Sentinel workspace.", + "3. Microsoft Sentinel must be enabled on the target Log Analytics workspace." + ], + "postDeployment": [ + "1. Verify the automation rules are visible in Microsoft Sentinel > Automation.", + "2. Grant each playbook's Managed Identity the Microsoft Sentinel Responder role if not already done." + ], + "lastUpdateTime": "2026-07-15T00:00:00Z", + "tags": [ + "Automation" + ], + "source": { + "type": "solution", + "name": "SpyCloud Enterprise Protection" + }, + "releaseNotes": [ + { + "version": "1.0.0", + "title": "SpyCloud Enterprise Protection - Automation Rules", + "notes": [ + "Initial version" + ] + } + ] + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_playbookContentId3')]", + "contentKind": "Playbook", + "displayName": "SpyCloud_AutomationRules", + "contentProductId": "[variables('_playbookcontentProductId3')]", + "id": "[variables('_playbookcontentProductId3')]", + "version": "[variables('playbookVersion3')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentPackages", + "apiVersion": "2023-04-01-preview", + "location": "[parameters('workspace-location')]", + "properties": { + "version": "3.0.0", + "kind": "Solution", + "contentSchemaVersion": "3.0.0", + "displayName": "SpyCloud Enterprise Protection CCF", + "publisherDisplayName": "SpyCloud", + "descriptionHtml": "

Note: Please refer to the following before installing the solution:

\n

• Review the solution Release Notes

\n

• There may be known issues pertaining to this Solution, please refer to them before installing.

\n

The SpyCloud Enterprise Protection solution for Microsoft Sentinel ingests SpyCloud breach watchlist and catalog data via the Codeless Connector Framework (CCF), including an optional Compass daily feed. The solution includes two built-in analytic rules, two KQL parsers, and two automation playbooks for Microsoft Defender for Endpoint and Azure AD / Entra ID Conditional Access response.

\n

Underlying Microsoft Technologies used:

\n

This solution takes a dependency on the following technologies, and some of these dependencies either may be in Preview state or might result in additional ingestion or operational costs:

\n
    \n
  1. Codeless Connector Framework (CCF)

    \n
  2. \n
  3. Azure Logic Apps

    \n
  4. \n
  5. Microsoft Defender for Endpoint

    \n
  6. \n
\n

Data Connectors: 1, Parsers: 2, Analytic Rules: 2, Playbooks: 3

\n

Learn more about Microsoft Sentinel | Learn more about Solutions

\n", + "contentKind": "Solution", + "contentProductId": "[variables('_solutioncontentProductId')]", + "id": "[variables('_solutioncontentProductId')]", + "icon": "", + "contentId": "[variables('_solutionId')]", + "parentId": "[variables('_solutionId')]", + "source": { + "kind": "Solution", + "name": "SpyCloud Enterprise Protection CCF", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "SpyCloud", + "email": "[variables('_email')]" + }, + "support": { + "name": "SpyCloud", + "tier": "Partner", + "link": "https://support.spycloud.com" + }, + "dependencies": { + "operator": "AND", + "criteria": [ + { + "kind": "AnalyticsRule", + "contentId": "[variables('analyticRuleObject1')._analyticRulecontentId1]", + "version": "[variables('analyticRuleObject1').analyticRuleVersion1]" + }, + { + "kind": "AnalyticsRule", + "contentId": "[variables('analyticRuleObject2')._analyticRulecontentId2]", + "version": "[variables('analyticRuleObject2').analyticRuleVersion2]" + }, + { + "kind": "DataConnector", + "contentId": "[variables('_dataConnectorContentIdConnections1')]", + "version": "[variables('dataConnectorCCPVersion')]" + }, + { + "kind": "Parser", + "contentId": "[variables('parserObject1').parserContentId1]", + "version": "[variables('parserObject1').parserVersion1]" + }, + { + "kind": "Parser", + "contentId": "[variables('parserObject2').parserContentId2]", + "version": "[variables('parserObject2').parserVersion2]" + }, + { + "kind": "Playbook", + "contentId": "[variables('_SpyCloud_MDE_Automation')]", + "version": "[variables('playbookVersion1')]" + }, + { + "kind": "Playbook", + "contentId": "[variables('_SpyCloud_Conditional_Access_Playbook')]", + "version": "[variables('playbookVersion2')]" + }, + { + "kind": "Playbook", + "contentId": "[variables('_SpyCloud_AutomationRules')]", + "version": "[variables('playbookVersion3')]" + } + ] + }, + "firstPublishDate": "2026-06-09", + "lastPublishDate": "2026-06-09", + "providers": [ + "SpyCloud" + ], + "categories": { + "domains": [ + "Security - Threat Intelligence", + "Identity" + ] + } + }, + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/', variables('_solutionId'))]" + } + ], + "outputs": {} +} diff --git a/Solutions/SpyCloud Enterprise Protection CCF/Package/testParameters.json b/Solutions/SpyCloud Enterprise Protection CCF/Package/testParameters.json new file mode 100644 index 00000000000..554801e41b7 --- /dev/null +++ b/Solutions/SpyCloud Enterprise Protection CCF/Package/testParameters.json @@ -0,0 +1,38 @@ +{ + "location": { + "type": "string", + "minLength": 1, + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Not used, but needed to pass arm-ttk test `Location-Should-Not-Be-Hardcoded`. We instead use the `workspace-location` which is derived from the LA workspace" + } + }, + "workspace-location": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "[concat('Region to deploy solution resources -- separate from location selection',parameters('location'))]" + } + }, + "workspace": { + "defaultValue": "", + "type": "string", + "metadata": { + "description": "Workspace name for Log Analytics where Microsoft Sentinel is setup" + } + }, + "resourceGroupName": { + "type": "string", + "defaultValue": "[resourceGroup().name]", + "metadata": { + "description": "resource group name where Microsoft Sentinel is setup" + } + }, + "subscription": { + "type": "string", + "defaultValue": "[last(split(subscription().id, '/'))]", + "metadata": { + "description": "subscription id where Microsoft Sentinel is setup" + } + } +} diff --git a/Solutions/SpyCloud Enterprise Protection CCF/Parsers/get_Spycloud_enriched_data.yaml b/Solutions/SpyCloud Enterprise Protection CCF/Parsers/get_Spycloud_enriched_data.yaml new file mode 100644 index 00000000000..af2da1a3167 --- /dev/null +++ b/Solutions/SpyCloud Enterprise Protection CCF/Parsers/get_Spycloud_enriched_data.yaml @@ -0,0 +1,102 @@ +id: ea883c92-ce82-4079-9e1d-5743349c3962 +Function: + Title: SpyCloud Enriched Data Parser + Version: '1.0.0' + LastUpdated: '2026-06-09' +Category: Microsoft Sentinel Parser +FunctionName: get_Spycloud_enriched_data +FunctionAlias: get_Spycloud_enriched_data +FunctionParams: + - Name: lookback + Type: timespan + Default: 1d +FunctionQuery: | + let _lookback = coalesce(lookback, 1d); + let LatestBreachCatalog = + SpyCloudBreachCatalogV2_CL + | summarize arg_max(TimeGenerated, BreachTitle, Description, Status) by SourceId + | project + SourceId, + BreachTitle, + CatalogDescription = Description, + CatalogStatus = Status; + SpyCloudBreachWatchlistV2_CL + | where TimeGenerated >= ago(_lookback) + | join kind=leftouter LatestBreachCatalog on SourceId + | project + TimeGenerated, + SourceId, + InfectedPath, + UserHostName, + IPAddresses, + TimeZone, + TargetUrl, + DocumentId, + TargetDomain, + UserSysRegisteredOwner, + DisplayResolution, + Password, + Email, + Severity, + AVSoftwares, + LogId, + UserOS, + EmailUsername, + SpyCloudPublishDate, + InfectedMachineId, + PasswordPlaintext, + InfectedTime, + CountryCode, + KeyboardLanguages, + PasswordType, + Domain, + EmailDomain, + TargetSubdomain, + Sighting, + AccountLastActivityTime, + AccountNotes, + AccountSignupTime, + Username, + Homepage, + Salt, + AccountLoginTime, + SocialOther, + LastName, + FullName, + Phone, + FirstName, + Address1, + AccountModificationTime, + Gender, + City, + BirthYear, + DOB, + CompanyWebsite, + Industry, + AccountStatus, + SocialCrunchbase, + CompanyName, + SocialLinkedIn, + SocialTwitter, + AccountCaption, + Address2, + SSNLastFour, + SocialSecurityNumber, + HealthInsuranceId, + PostalCode, + Age, + TaxId, + State, + AccountType, + DeviceName, + BankNumber, + MobileEquipmentId, + Country, + EducationalInstitution, + JobTitle, + AccountImageUrl, + StudentId, + AccountId, + BreachTitle, + CatalogDescription, + CatalogStatus diff --git a/Solutions/SpyCloud Enterprise Protection CCF/Parsers/get_spycloud_compass_data.yaml b/Solutions/SpyCloud Enterprise Protection CCF/Parsers/get_spycloud_compass_data.yaml new file mode 100644 index 00000000000..b7261ef5126 --- /dev/null +++ b/Solutions/SpyCloud Enterprise Protection CCF/Parsers/get_spycloud_compass_data.yaml @@ -0,0 +1,20 @@ +id: 60e2f847-1c83-4099-9d2e-1401e3590798 +Function: + Title: SpyCloud Compass Data Parser + Version: '1.0.0' + LastUpdated: '2026-06-09' +Category: Microsoft Sentinel Parser +FunctionName: get_spycloud_compass_data +FunctionAlias: get_spycloud_compass_data +FunctionParams: + - Name: startTime + Type: timespan + Default: 1d +FunctionQuery: | + let _startTime = coalesce(startTime, 1d); + spycloud_compassV2_CL + | where TimeGenerated > ago(_startTime) + | project + TimeGenerated, DocumentId, SourceId, SpyCloudPublishDate, Email, Domain, + Password, PasswordPlaintext, Severity, IPAddresses, InfectedMachineId, + InfectedTime, BreachTitle, BreachCategory diff --git a/Solutions/SpyCloud Enterprise Protection CCF/Playbooks/SpyCloud_AutomationRules/azuredeploy.json b/Solutions/SpyCloud Enterprise Protection CCF/Playbooks/SpyCloud_AutomationRules/azuredeploy.json new file mode 100644 index 00000000000..c0cc5791ed1 --- /dev/null +++ b/Solutions/SpyCloud Enterprise Protection CCF/Playbooks/SpyCloud_AutomationRules/azuredeploy.json @@ -0,0 +1,179 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "title": "SpyCloud Enterprise Protection - Automation Rules", + "description": "Deploys automation rules that trigger the SpyCloud MDE Automation and SpyCloud Conditional Access playbooks when a matching SpyCloud analytic rule creates an incident.", + "prerequisites": [ + "1. The SpyCloud_MDE_Automation and SpyCloud_Conditional_Access_Playbook playbooks must be deployed in the same resource group.", + "2. The SpyCloud analytic rules (AR_malware_25, AR_Breached_Users_20) must be deployed to the same Microsoft Sentinel workspace.", + "3. Microsoft Sentinel must be enabled on the target Log Analytics workspace." + ], + "postDeployment": [ + "1. Verify the automation rules are visible in Microsoft Sentinel > Automation.", + "2. Grant each playbook's Managed Identity the Microsoft Sentinel Responder role if not already done." + ], + "lastUpdateTime": "2026-07-15T00:00:00.000Z", + "entities": [], + "tags": [ "Automation" ], + "support": { + "tier": "Partner", + "name": "SpyCloud", + "link": "https://support.spycloud.com" + }, + "source": { + "type": "solution", + "name": "SpyCloud Enterprise Protection" + }, + "author": { + "name": "SpyCloud" + }, + "releaseNotes": [ + { + "version": "1.0.0", + "title": "SpyCloud Enterprise Protection - Automation Rules", + "notes": [ "Initial version" ] + } + ] + }, + "parameters": { + "Sentinel_Workspace_Resource_Id": { + "type": "string", + "metadata": { + "description": "Full resource ID of the Log Analytics workspace with Microsoft Sentinel enabled (e.g., /subscriptions/.../resourceGroups/.../providers/Microsoft.OperationalInsights/workspaces/...)" + } + }, + "MDE_PlaybookName": { + "type": "string", + "defaultValue": "SpyCloud_MDE_Automation", + "metadata": { + "description": "Name of the SpyCloud_MDE_Automation Logic App" + } + }, + "ConditionalAccess_PlaybookName": { + "type": "string", + "defaultValue": "SpyCloud_Conditional_Access_Playbook", + "metadata": { + "description": "Name of the SpyCloud_Conditional_Access_Playbook Logic App" + } + }, + "MalwareAnalyticRuleId": { + "type": "string", + "defaultValue": "ead4deed-9d48-4646-aee0-6b46c2dd1ae6", + "metadata": { + "description": "GUID of the SpyCloud infostealer malware credential exposure analytic rule (AR_malware_25) that triggers the MDE automation rule" + } + }, + "BreachedUsersAnalyticRuleId": { + "type": "string", + "defaultValue": "a25eba0e-ff42-4c97-a379-d76bdb2aa1e3", + "metadata": { + "description": "GUID of the SpyCloud plaintext credential exposure analytic rule (AR_Breached_Users_20) that triggers the Conditional Access automation rule" + } + }, + "MDE_Automation_Rule_Order": { + "type": "int", + "defaultValue": 1, + "metadata": { + "description": "Execution order of the MDE automation rule (lower = higher priority)" + } + }, + "ConditionalAccess_Automation_Rule_Order": { + "type": "int", + "defaultValue": 2, + "metadata": { + "description": "Execution order of the Conditional Access automation rule (lower = higher priority)" + } + } + }, + "variables": { + "mdeAutomationRuleName": "[guid('SpyCloud-MDE-Rule', parameters('Sentinel_Workspace_Resource_Id'))]", + "conditionalAccessAutomationRuleName": "[guid('SpyCloud-ConditionalAccess-Rule', parameters('Sentinel_Workspace_Resource_Id'))]" + }, + "resources": [ + { + "type": "Microsoft.SecurityInsights/automationRules", + "name": "[variables('mdeAutomationRuleName')]", + "scope": "[parameters('Sentinel_Workspace_Resource_Id')]", + "apiVersion": "2023-02-01-preview", + "properties": { + "displayName": "SpyCloud - Isolate compromised device on malware exposure", + "order": "[parameters('MDE_Automation_Rule_Order')]", + "triggeringLogic": { + "isEnabled": true, + "triggersOn": "Incidents", + "triggersWhen": "Created", + "conditions": [ + { + "conditionType": "Property", + "conditionProperties": { + "propertyName": "IncidentRelatedAnalyticRuleIds", + "operator": "Contains", + "propertyValues": [ + "[extensionResourceId(parameters('Sentinel_Workspace_Resource_Id'), 'Microsoft.SecurityInsights/alertRules', parameters('MalwareAnalyticRuleId'))]" + ] + } + } + ] + }, + "actions": [ + { + "order": 1, + "actionType": "RunPlaybook", + "actionConfiguration": { + "logicAppResourceId": "[resourceId('Microsoft.Logic/workflows', parameters('MDE_PlaybookName'))]", + "tenantId": "[subscription().tenantId]" + } + } + ] + } + }, + { + "type": "Microsoft.SecurityInsights/automationRules", + "name": "[variables('conditionalAccessAutomationRuleName')]", + "scope": "[parameters('Sentinel_Workspace_Resource_Id')]", + "apiVersion": "2023-02-01-preview", + "properties": { + "displayName": "SpyCloud - Enforce Conditional Access on credential exposure", + "order": "[parameters('ConditionalAccess_Automation_Rule_Order')]", + "triggeringLogic": { + "isEnabled": true, + "triggersOn": "Incidents", + "triggersWhen": "Created", + "conditions": [ + { + "conditionType": "Property", + "conditionProperties": { + "propertyName": "IncidentRelatedAnalyticRuleIds", + "operator": "Contains", + "propertyValues": [ + "[extensionResourceId(parameters('Sentinel_Workspace_Resource_Id'), 'Microsoft.SecurityInsights/alertRules', parameters('BreachedUsersAnalyticRuleId'))]" + ] + } + } + ] + }, + "actions": [ + { + "order": 1, + "actionType": "RunPlaybook", + "actionConfiguration": { + "logicAppResourceId": "[resourceId('Microsoft.Logic/workflows', parameters('ConditionalAccess_PlaybookName'))]", + "tenantId": "[subscription().tenantId]" + } + } + ] + } + } + ], + "outputs": { + "mdeAutomationRuleId": { + "type": "string", + "value": "[variables('mdeAutomationRuleName')]" + }, + "conditionalAccessAutomationRuleId": { + "type": "string", + "value": "[variables('conditionalAccessAutomationRuleName')]" + } + } +} diff --git a/Solutions/SpyCloud Enterprise Protection CCF/Playbooks/SpyCloud_AutomationRules/readme.md b/Solutions/SpyCloud Enterprise Protection CCF/Playbooks/SpyCloud_AutomationRules/readme.md new file mode 100644 index 00000000000..bdd58a50c18 --- /dev/null +++ b/Solutions/SpyCloud Enterprise Protection CCF/Playbooks/SpyCloud_AutomationRules/readme.md @@ -0,0 +1,37 @@ +# SpyCloud Automation Rules + +This template deploys two Microsoft Sentinel automation rules that connect the SpyCloud analytic rules to the SpyCloud response playbooks, so incidents are automatically routed to the right automation without manual configuration. + +| Automation Rule | Triggers On | Runs Playbook | +|---|---|---| +| SpyCloud - Isolate compromised device on malware exposure | Incident created from **AR_malware_25** (SpyCloud infostealer malware credential exposure) | `SpyCloud_MDE_Automation` | +| SpyCloud - Enforce Conditional Access on credential exposure | Incident created from **AR_Breached_Users_20** (SpyCloud plaintext credential exposure detected) | `SpyCloud_Conditional_Access_Playbook` | + +## Prerequisites + +- The `SpyCloud_MDE_Automation` and `SpyCloud_Conditional_Access_Playbook` playbooks must already be deployed in the same resource group +- The `AR_malware_25` and `AR_Breached_Users_20` analytic rules must already be deployed to the target Microsoft Sentinel workspace +- Each playbook's Managed Identity must have the **Microsoft Sentinel Responder** role on the workspace (grant this after deployment if not already assigned) + +## Deployment + +1. In the Azure Portal, navigate to **Deploy a custom template** +2. Select this template (`azuredeploy.json`) +3. Confirm Subscription and Resource Group +4. Enter the full resource ID of your Sentinel-enabled Log Analytics workspace for **Sentinel_Workspace_Resource_Id** +5. Leave the playbook name and analytic rule ID parameters at their defaults unless you renamed those resources during deployment +6. Click **Review + Create**, then **Create** + +## Parameters + +| Parameter | Type | Default | Description | +|---|---|---|---| +| Sentinel_Workspace_Resource_Id | String | — | Full resource ID of the Sentinel-enabled Log Analytics workspace | +| MDE_PlaybookName | String | SpyCloud_MDE_Automation | Name of the MDE automation playbook Logic App | +| ConditionalAccess_PlaybookName | String | SpyCloud_Conditional_Access_Playbook | Name of the Conditional Access playbook Logic App | +| MalwareAnalyticRuleId | String | ead4deed-9d48-4646-aee0-6b46c2dd1ae6 | GUID of AR_malware_25 | +| BreachedUsersAnalyticRuleId | String | a25eba0e-ff42-4c97-a379-d76bdb2aa1e3 | GUID of AR_Breached_Users_20 | +| MDE_Automation_Rule_Order | Int | 1 | Execution order of the MDE automation rule | +| ConditionalAccess_Automation_Rule_Order | Int | 2 | Execution order of the Conditional Access automation rule | + +After deployment, confirm both rules appear under **Microsoft Sentinel → Automation** and are enabled. diff --git a/Solutions/SpyCloud Enterprise Protection CCF/Playbooks/SpyCloud_Conditional_Access_Playbook/azuredeploy.json b/Solutions/SpyCloud Enterprise Protection CCF/Playbooks/SpyCloud_Conditional_Access_Playbook/azuredeploy.json new file mode 100644 index 00000000000..04ef0aecdb6 --- /dev/null +++ b/Solutions/SpyCloud Enterprise Protection CCF/Playbooks/SpyCloud_Conditional_Access_Playbook/azuredeploy.json @@ -0,0 +1,868 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "title": "SpyCloud Conditional Access Playbook", + "description": "Spycloud Conditional access playbook", + "prerequisites": "Create an App in App registration and provide permissions and create a client secret", + "lastUpdateTime": "2026-03-11T00:00:00.000Z", + "entities": [ + "account" + ], + "tags": [], + "support": { + "tier": "community", + "armtemplate": "Generated from https://github.com/Azure/Azure-Sentinel/tree/master/Tools/Playbook-ARM-Template-Generator" + }, + "author": { + "name": "SpyCloud" + } + }, + "parameters": { + "PlaybookName": { + "defaultValue": "SpyCloud_Conditional_Access_Playbook", + "type": "string" + } + }, + "variables": { + "loginUrl": "[environment().authentication.loginEndpoint]", + "AzureSentinelConnectionName": "[concat('azuresentinel-', parameters('PlaybookName'))]", + "Office365V1": "[concat('office365-', parameters('PlaybookName'))]", + "subscription": "[last(split(subscription().id, '/'))]", + "resourceGroupName": "[resourceGroup().name]" + }, + "resources": [ + { + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[variables('Office365V1')]", + "location": "[resourceGroup().location]", + "properties": { + "displayName": "[variables('Office365V1')]", + "customParameterValues": {}, + "api": { + "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/office365')]" + } + } + }, + { + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[variables('AzureSentinelConnectionName')]", + "location": "[resourceGroup().location]", + "kind": "V1", + "properties": { + "displayName": "[variables('AzureSentinelConnectionName')]", + "customParameterValues": {}, + "parameterValueType": "Alternative", + "api": { + "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/azuresentinel')]" + } + } + }, + { + "type": "Microsoft.Logic/workflows", + "apiVersion": "2017-07-01", + "name": "[parameters('PlaybookName')]", + "location": "[resourceGroup().location]", + "identity": { + "type": "SystemAssigned" + }, + "dependsOn": [ + "[resourceId('Microsoft.Web/connections', variables('Office365V1'))]", + "[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]" + ], + "properties": { + "state": "Disabled", + "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" + }, + "PlaybookName": { + "defaultValue": "[parameters('PlaybookName')]", + "type": "String" + }, + "Notify_Users_Emails": { + "type": "String" + }, + "Force_Password_Reset_On_Next_SignIn": { + "type": "Bool", + "defaultValue": false + }, + "Disable_User": { + "type": "Bool", + "defaultValue": false + }, + "Add_User_To_Azure_CA_Group": { + "type": "Bool", + "defaultValue": false + }, + "Azure_CA_Group_Object_ID": { + "type": "String" + }, + "Revoke_User_Sessions": { + "type": "Bool", + "defaultValue": false + }, + "ClientID": { + "type": "String" + }, + "TenantID": { + "type": "String" + }, + "ClientSecret": { + "type": "String" + }, + "DCE_Endpoint": { + "type": "String" + }, + "DCE_Immutable_ID": { + "type": "String" + }, + "Custom_Table_Name": { + "type": "String", + "defaultValue": "SpyCloud_ConditionalAccessLogsV2_CL" + } + }, + "triggers": { + "Microsoft_Sentinel_incident": { + "type": "ApiConnectionWebhook", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "body": { + "callback_url": "@{listCallbackUrl()}" + }, + "path": "/incident-creation" + } + } + }, + "actions": { + "Entities_-_Get_Accounts": { + "runAfter": { + "For_each_incident_alert": [ + "Succeeded" + ] + }, + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "post", + "body": "@triggerBody()?['object']?['properties']?['relatedEntities']", + "path": "/entities/account" + } + }, + "For_each": { + "foreach": "@body('Entities_-_Get_Accounts')?['Accounts']", + "actions": { + "Get_User_Details": { + "runAfter": { + "Set_user": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "uri": "https://graph.microsoft.com/v1.0/users/@{variables('user_email')}?$select=id,displayName,accountEnabled,lastPasswordChangeDateTime,userPrincipalName", + "method": "GET", + "authentication": { + "type": "ActiveDirectoryOAuth", + "authority": "@{variables('Authority')}", + "tenant": "@{parameters('TenantID')}", + "audience": "@{variables('Audience')}", + "clientId": "@{parameters('ClientID')}", + "secret": "@{parameters('ClientSecret')}" + } + }, + "runtimeConfiguration": { + "contentTransfer": { + "transferMode": "Chunked" + } + } + }, + "Set_user": { + "type": "SetVariable", + "inputs": { + "name": "user_email", + "value": "@{concat(items('For_each')?['Name'],'@',items('for_each')?['UPNSuffix'])}" + } + }, + "Condition_-_Check_if_user_is_enabled": { + "actions": { + "Condition_Check_if_password_has_not_been_reset_since_7_days": { + "actions": { + "Condition_-_Check_if_user_needs_to_be_added_to_CA_group_": { + "actions": { + "Add_user_to_Conditional_Access_Group": { + "type": "Http", + "inputs": { + "uri": "https://graph.microsoft.com/v1.0/groups/@{parameters('Azure_CA_Group_Object_ID')}/members/$ref", + "method": "POST", + "body": { + "@@odata.id": "https://graph.microsoft.com/v1.0/directoryObjects/@{body('Get_User_Details')?['id']}" + }, + "authentication": { + "type": "ActiveDirectoryOAuth", + "authority": "@{variables('Authority')}", + "tenant": "@{parameters('TenantID')}", + "audience": "@{variables('Audience')}", + "clientId": "@{parameters('ClientID')}", + "secret": "@{parameters('ClientSecret')}" + } + }, + "runtimeConfiguration": { + "contentTransfer": { + "transferMode": "Chunked" + } + } + }, + "Set_Added_To_CA_Group_Enforced": { + "runAfter": { + "Add_user_to_Conditional_Access_Group": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "AddedToCAGroupEnforced", + "value": true + } + }, + "Set_Added_To_CA_Group_Enforced_Text": { + "runAfter": { + "Set_Added_To_CA_Group_Enforced": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "AddedToCAGroupText", + "value": "Successfully added the user to Conditional Access Group." + } + } + }, + "runAfter": { + "Condition_-_Check_Revoke_User_Sessions": [ + "Succeeded" + ] + }, + "else": { + "actions": {} + }, + "expression": { + "and": [ + { + "not": { + "equals": [ + "@parameters('Add_User_To_Azure_CA_Group')", + "@true" + ] + } + } + ] + }, + "type": "If" + }, + "Condition_-_If_User_needs_to_be_disabled": { + "actions": { + "HTTP_-_Disable_User": { + "type": "Http", + "inputs": { + "uri": "https://graph.microsoft.com/v1.0/users/@{variables('user_email')}", + "method": "PATCH", + "body": { + "accountEnabled": false + }, + "authentication": { + "type": "ActiveDirectoryOAuth", + "authority": "@{variables('Authority')}", + "tenant": "@{parameters('TenantID')}", + "audience": "@{variables('Audience')}", + "clientId": "@{parameters('ClientID')}", + "secret": "@{parameters('ClientSecret')}" + } + } + }, + "Set_Account_Disabled_": { + "runAfter": { + "HTTP_-_Disable_User": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "AccountDisabledEnforced", + "value": true + } + }, + "Set_Account_Disabled_Text": { + "runAfter": { + "Set_Account_Disabled_": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "AccountDisabledText", + "value": "The User has been successfully Disabled." + } + } + }, + "runAfter": { + "Condition_-_Check_if_user_needs_to_be_added_to_CA_group_": [ + "Succeeded" + ] + }, + "else": { + "actions": {} + }, + "expression": { + "and": [ + { + "equals": [ + "@parameters('Disable_User')", + "@true" + ] + } + ] + }, + "type": "If" + }, + "Condition_-_Check_Revoke_User_Sessions": { + "actions": { + "HTTP_-_Revoke_User_Sessions": { + "type": "Http", + "inputs": { + "uri": "https://graph.microsoft.com/v1.0/users/@{variables('user_email')}/revokeSignInSessions", + "method": "POST", + "authentication": { + "type": "ActiveDirectoryOAuth", + "authority": "@{variables('Authority')}", + "tenant": "@{parameters('TenantID')}", + "audience": "@{variables('Audience')}", + "clientId": "@{parameters('ClientID')}", + "secret": "@{parameters('ClientSecret')}" + } + }, + "runtimeConfiguration": { + "contentTransfer": { + "transferMode": "Chunked" + } + } + }, + "Set_User_Session_Enforced": { + "runAfter": { + "HTTP_-_Revoke_User_Sessions": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "UserSessionsRevokeEnforced", + "value": true + } + }, + "Set_User_Session_Revoke_Text": { + "runAfter": { + "Set_User_Session_Enforced": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "UserSessionRevokeText", + "value": "User sessions has been scessfully revoked." + } + } + }, + "runAfter": { + "Condition-Check_for_Password_Reset": [ + "Succeeded" + ] + }, + "else": { + "actions": {} + }, + "expression": { + "and": [ + { + "equals": [ + "@parameters('Revoke_User_Sessions')", + "@true" + ] + } + ] + }, + "type": "If" + }, + "Condition-Check_for_Password_Reset": { + "actions": { + "Force_Password_Reset": { + "type": "Http", + "inputs": { + "uri": "https://graph.microsoft.com/v1.0/users/@{variables('user_email')}", + "method": "PATCH", + "body": { + "passwordProfile": { + "forceChangePasswordNextSignIn": true + } + }, + "authentication": { + "type": "ActiveDirectoryOAuth", + "authority": "@{variables('Authority')}", + "tenant": "@{parameters('TenantID')}", + "audience": "@{variables('Audience')}", + "clientId": "@{parameters('ClientID')}", + "secret": "@{parameters('ClientSecret')}" + } + }, + "runtimeConfiguration": { + "contentTransfer": { + "transferMode": "Chunked" + } + } + }, + "Set_Passwod_Reset_Enforced": { + "runAfter": { + "Force_Password_Reset": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "PasswordResetEnforced", + "value": true + } + }, + "Set_Password_Reset_Text": { + "runAfter": { + "Set_Passwod_Reset_Enforced": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "PasswordResetText", + "value": "Password has been successfully reset" + } + } + }, + "else": { + "actions": {} + }, + "expression": { + "and": [ + { + "equals": [ + "@parameters('Force_Password_Reset_On_Next_SignIn')", + "@true" + ] + } + ] + }, + "type": "If" + }, + "Add_comment_to_incident": { + "runAfter": { + "Condition_-_If_User_needs_to_be_disabled": [ + "Succeeded" + ] + }, + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "post", + "body": { + "incidentArmId": "@triggerBody()?['object']?['id']", + "message": "

For User @{items('For_each')?['Name']} (UPN -@{variables('user_email')} ) the following actions were done from the Spycloud playbook. Manager () is notified.

@{variables('PasswordResetText')}

@{variables('AddedToCAGroupText')}

@{variables('UserSessionRevokeText')}

@{variables('AccountDisabledText')}


" + }, + "path": "/Incidents/Comment" + } + }, + "Send_an_email_-_to_manager_": { + "runAfter": { + "Add_comment_to_incident": [ + "Succeeded" + ] + }, + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['office365']['connectionId']" + } + }, + "method": "post", + "body": { + "To": "@parameters('Notify_Users_Emails')", + "Subject": "@{items('For_each')?['Name']} - security risk!", + "Body": "

Security notification! This is automated email sent by Microsoft Sentinel SpyCloud Automation!

For User @{items('For_each')?['Name']} (UPN -@{variables('user_email')} ) the following actions were done from the Spycloud playbook.
@{variables('PasswordResetText')}
@{variables('AddedToCAGroupText')}
@{variables('UserSessionRevokeText')}
@{variables('AccountDisabledText')}




Can you please notify the user and work with him to reach our support.


", + "Importance": "High" + }, + "path": "/v2/Mail" + } + } + }, + "else": { + "actions": { + "Add_comment_to_incident_-_Password_Latest": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "post", + "body": { + "incidentArmId": "@triggerBody()?['object']?['id']", + "message": "

For User @{items('For_each')?['Name']} (UPN -@{variables('user_email')} ) no actions were done from the Spycloud playbook.


Reason: Password has been reset after the breached date by the user.





" + }, + "path": "/Incidents/Comment" + } + } + } + }, + "expression": { + "and": [ + { + "not": { + "equals": [ + "@parseDateTime(body('Get_User_Details')?['lastPasswordChangeDateTime'])", + "@parseDateTime(variables('SpyCloudPublishDate'))" + ] + } + } + ] + }, + "type": "If" + }, + "GetAccessToken": { + "runAfter": { + "Condition_Check_if_password_has_not_been_reset_since_7_days": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "uri": "@concat(variables('loginUrl'), parameters('TenantID'), '/oauth2/v2.0/token')", + "method": "POST", + "headers": { + "Content-Type": "application/x-www-form-urlencoded" + }, + "body": "grant_type=client_credentials&client_id=@{parameters('ClientID')}&client_secret=@{parameters('ClientSecret')}&scope=https://monitor.azure.com/.default" + }, + "runtimeConfiguration": { + "contentTransfer": { + "transferMode": "Chunked" + } + } + }, + "Log_ingestion": { + "runAfter": { + "GetAccessToken": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "uri": "@variables('log_ingestion_api')", + "method": "POST", + "headers": { + "Authorization": "Bearer @{body('GetAccessToken')?['access_token']}", + "Content-Type": "application/json" + }, + "body": [ + { + "TimeGenerated": "@{utcNow()}", + "IncidentId": "@{triggerBody()?['object']?['properties']?['providerIncidentId']}", + "DocumentId": "@{variables('DocumentID')}", + "SpyCloudPublishDate": "@{variables('SpyCloudPublishDate')}", + "InfectedTime": "@{variables('InfectedTime')}", + "BreachTitle": "@{variables('BreachTitle')}", + "InfectedMachineId": "@{variables('InfectedMachineId')}", + "Username": "@{variables('user_email')}", + "UserEmail": "@{variables('user_email')}", + "ForcedPasswordResetOnNextSignIn": "@variables('PasswordResetEnforced')", + "UserSessionsRevoked": "@variables('UserSessionsRevokeEnforced')", + "CAgroup": "@variables('AddedToCAGroupEnforced')", + "UserDisabled": "@variables('AccountDisabledEnforced')", + "PlaybookName": "SpyCloud_Conditonal_Access_Automation" + } + ] + }, + "runtimeConfiguration": { + "contentTransfer": { + "transferMode": "Chunked" + } + } + } + }, + "runAfter": { + "Get_User_Details": [ + "Succeeded" + ] + }, + "else": { + "actions": { + "Add_comment_to_incident_-_user_disable": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "post", + "body": { + "incidentArmId": "@triggerBody()?['object']?['id']", + "message": "

For User @{items('For_each')?['Name']} (UPN -@{variables('user_email')} ) no actions were done from the Spycloud playbook.


Reason: The user is currently disabled..



" + }, + "path": "/Incidents/Comment" + } + } + } + }, + "expression": { + "and": [ + { + "equals": [ + "@body('Get_User_Details')?['accountEnabled']", + "@true" + ] + } + ] + }, + "type": "If" + } + }, + "runAfter": { + "Entities_-_Get_Accounts": [ + "Succeeded" + ] + }, + "type": "Foreach" + }, + "For_each_incident_alert": { + "foreach": "@triggerBody()?['object']?['properties']?['Alerts']", + "actions": { + "Set_custom_details_object": { + "type": "SetVariable", + "inputs": { + "name": "incident_custom_details_object", + "value": "@json(items('For_each_incident_alert')?['properties']?['additionalData']?['Custom Details'])" + } + }, + "Set_Spycloud_publish_date": { + "runAfter": { + "Set_custom_details_object": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "SpyCloudPublishDate", + "value": "@first(coalesce(variables('incident_custom_details_object')?['SpyCloudPublishDate'], createArray('')))" + } + }, + "Set_Infected_Time": { + "runAfter": { + "Set_Spycloud_publish_date": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "InfectedTime", + "value": "@first(coalesce(variables('incident_custom_details_object')?['InfectedTime'], createArray('')))" + } + }, + "Set_Breach_Title": { + "runAfter": { + "Set_Infected_Time": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "BreachTitle", + "value": "@first(coalesce(variables('incident_custom_details_object')?['BreachTitle'], createArray('')))\n" + } + }, + "Set_Infected_Machine_ID": { + "runAfter": { + "Set_Breach_Title": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "InfectedMachineId", + "value": "@first(coalesce(variables('incident_custom_details_object')?['InfectedMachineId'], createArray('')))" + } + }, + "Set_Document_ID": { + "runAfter": { + "Set_Infected_Machine_ID": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "DocumentID", + "value": "@first(coalesce(variables('incident_custom_details_object')?['DocumentID'], createArray('')))" + } + }, + "Set_log_ingestion_api_url": { + "runAfter": { + "Set_Document_ID": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "log_ingestion_api", + "value": "@concat(concat(concat(parameters('DCE_Endpoint'),'/dataCollectionRules/'),parameters('DCE_Immutable_ID') ),concat('/streams/Custom-',concat(parameters('Custom_Table_Name'), '?api-version=2023-01-01') ))" + } + } + }, + "runAfter": { + "variables_Section": [ + "Succeeded" + ] + }, + "type": "Foreach" + }, + "variables_Section": { + "runAfter": {}, + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "incident_custom_details_object", + "type": "object" + }, + { + "name": "SpyCloudPublishDate", + "type": "string" + }, + { + "name": "InfectedTime", + "type": "string" + }, + { + "name": "BreachTitle", + "type": "string" + }, + { + "name": "InfectedMachineId", + "type": "string" + }, + { + "name": "DocumentID", + "type": "string" + }, + { + "name": "last_password_reset_date", + "type": "string" + }, + { + "name": "Authority", + "type": "string", + "value": "[variables('loginUrl')]" + }, + { + "name": "Audience", + "type": "string", + "value": "https://graph.microsoft.com" + }, + { + "name": "user_email", + "type": "string" + }, + { + "name": "log_ingestion_api", + "type": "string" + }, + { + "name": "PasswordResetEnforced", + "type": "boolean", + "value": false + }, + { + "name": "AccountDisabledEnforced", + "type": "boolean", + "value": false + }, + { + "name": "AddedToCAGroupEnforced", + "type": "boolean", + "value": false + }, + { + "name": "PasswordResetText", + "type": "string" + }, + { + "name": "AccountDisabledText", + "type": "string" + }, + { + "name": "AddedToCAGroupText", + "type": "string" + }, + { + "name": "UserSessionsRevokeEnforced", + "type": "boolean", + "value": false + }, + { + "name": "UserSessionRevokeText", + "type": "string" + } + ] + } + } + }, + "outputs": {} + }, + "parameters": { + "$connections": { + "value": { + "azuresentinel": { + "connectionId": "[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]", + "connectionName": "[variables('AzureSentinelConnectionName')]", + "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/azuresentinel')]", + "connectionProperties": { + "authentication": { + "type": "ManagedServiceIdentity" + } + } + }, + "office365": { + "connectionId": "[resourceId('Microsoft.Web/connections', variables('Office365V1'))]", + "connectionName": "[variables('Office365V1')]", + "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/office365')]" + } + } + } + } + } + } + ] +} \ No newline at end of file diff --git a/Solutions/SpyCloud Enterprise Protection CCF/Playbooks/SpyCloud_Conditional_Access_Playbook/readme.md b/Solutions/SpyCloud Enterprise Protection CCF/Playbooks/SpyCloud_Conditional_Access_Playbook/readme.md new file mode 100644 index 00000000000..ed19c7d84f2 --- /dev/null +++ b/Solutions/SpyCloud Enterprise Protection CCF/Playbooks/SpyCloud_Conditional_Access_Playbook/readme.md @@ -0,0 +1,54 @@ +# SpyCloud Conditional Access Playbook + +This playbook automates Azure AD / Entra ID identity response actions when SpyCloud breach data identifies compromised user credentials. + +**Capabilities** +- Account disablement +- Session revocation across all applications +- Forced password reset at next sign-in +- Conditional Access group membership enforcement +- Email notifications +- Execution log ingestion to `SpyCloud_ConditionalAccessLogsV2_CL` + +## Prerequisites + +- App Registration with the Microsoft Graph permissions listed in the [Integration Guide](../../SpyCloud_Sentinel_Integration_Guide.md), Section 2.1 +- DCR Immutable ID and DCE Logs Ingestion Endpoint URL for `SpyCloud_ConditionalAccessLogsV2_CL` (Section 2.2) +- Monitoring Metrics Publisher role assigned to the App Registration on that DCR +- Object ID of the Azure AD Conditional Access enforcement group (if using group membership actions) + +## Deployment + +1. In the Azure Portal, navigate to **Deploy a custom template** +2. Select this template (`azuredeploy.json`) +3. Confirm Subscription, Resource Group, and Region +4. Enter a value for **PlaybookName** (this is the only ARM deployment-time parameter) +5. Click **Review + Create**, then **Create** +6. Authorize the `office365` and `azuresentinel` API connections created by the deployment + +## Post-deployment configuration + +All other settings are **workflow parameters**, baked into the Logic App with default values. After the playbook is deployed, update them with your own values: + +1. Navigate to the Microsoft Sentinel workspace, open **Automation**, and select the `SpyCloud_Conditional_Access_Playbook` playbook — or go directly to the Logic App resource in the Azure Portal +2. Open the Logic App and click **Edit** to open the workflow designer +3. Open the **Parameters** section (in the designer toolbar, or under **Development Tools → Workflow parameters**) +4. For each parameter listed below, enter the appropriate value for your environment +5. Click **Save** to apply the changes to the playbook + +| Parameter | Type | Default | Description | +|---|---|---|---| +| Notify_Users_Emails | String | (empty) | Email address(es) for notifications, semicolon-separated | +| Force_Password_Reset_On_Next_SignIn | Bool | false | Forces password reset at next sign-in for affected users | +| Disable_User | Bool | false | Disables affected Azure AD user accounts | +| Add_User_To_Azure_CA_Group | Bool | false | Adds affected users to the Conditional Access enforcement group | +| Azure_CA_Group_Object_ID | String | (empty) | Object ID of the Azure AD Conditional Access group | +| Revoke_User_Sessions | Bool | false | Revokes all active sign-in sessions for affected users | +| ClientID | String | (empty) | App Registration Client ID | +| TenantID | String | (empty) | Azure Tenant ID | +| ClientSecret | String | (empty) | App Registration Client Secret | +| DCE_Endpoint | String | (empty) | DCE Logs Ingestion Endpoint URL for CA logs | +| DCE_Immutable_ID | String | (empty) | DCR Immutable ID for `SpyCloud_ConditionalAccessLogsV2_CL` | +| Custom_Table_Name | String | SpyCloud_ConditionalAccessLogsV2_CL | Custom Log Analytics table for playbook logs | + +After saving workflow parameters, confirm `SpyCloud_Conditional_Access_Playbook` shows status **Enabled** and check Run History for immediate failures. diff --git a/Solutions/SpyCloud Enterprise Protection CCF/Playbooks/SpyCloud_MDE_Automation/azuredeploy.json b/Solutions/SpyCloud Enterprise Protection CCF/Playbooks/SpyCloud_MDE_Automation/azuredeploy.json new file mode 100644 index 00000000000..95096ca2cbb --- /dev/null +++ b/Solutions/SpyCloud Enterprise Protection CCF/Playbooks/SpyCloud_MDE_Automation/azuredeploy.json @@ -0,0 +1,965 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "PlaybookName": { + "defaultValue": "SpyCloud_MDE_Automation", + "type": "string" + } + }, + "variables": { + "loginUrl": "[environment().authentication.loginEndpoint]", + "AzureSentinelConnectionName": "[concat('azuresentinel-', parameters('PlaybookName'))]", + "Office365V1": "[concat('office365-', parameters('PlaybookName'))]", + "WDATPConnection": "[concat('wdatp-', parameters('PlaybookName'))]" + }, + "resources": [ + { + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[variables('Office365V1')]", + "location": "[resourceGroup().location]", + "properties": { + "displayName": "[variables('Office365V1')]", + "customParameterValues": {}, + "api": { + "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/office365')]" + } + } + }, + { + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[variables('WDATPConnection')]", + "location": "[resourceGroup().location]", + "properties": { + "displayName": "WDATP Connection", + "customParameterValues": {}, + "api": { + "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/wdatp')]" + } + } + }, + { + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[variables('AzureSentinelConnectionName')]", + "location": "[resourceGroup().location]", + "kind": "V1", + "properties": { + "displayName": "[variables('AzureSentinelConnectionName')]", + "customParameterValues": {}, + "parameterValueType": "Alternative", + "api": { + "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/azuresentinel')]" + } + } + }, + { + "type": "Microsoft.Logic/workflows", + "apiVersion": "2017-07-01", + "name": "[parameters('PlaybookName')]", + "location": "[resourceGroup().location]", + "identity": { + "type": "SystemAssigned" + }, + "dependsOn": [ + "[resourceId('Microsoft.Web/connections', variables('Office365V1'))]", + "[resourceId('Microsoft.Web/connections', variables('WDATPConnection'))]", + "[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]" + ], + "properties": { + "state": "Disabled", + "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" + }, + "PlaybookName": { + "defaultValue": "[parameters('PlaybookName')]", + "type": "String" + }, + "Isolate_Machine": { + "type": "Bool", + "defaultValue": false + }, + "Machine_Tag_Value": { + "type": "String" + }, + "Save_IOCs_Defender": { + "type": "Bool", + "defaultValue": false + }, + "IOC_Expiration_Days": { + "type": "Int", + "defaultValue": 30 + }, + "Spycloud_Defender_DCE_Endpoint": { + "type": "String" + }, + "Spycloud_Defender_DCE_Immutable_ID": { + "type": "String" + }, + "TenantID": { + "type": "String" + }, + "ClientID": { + "type": "String" + }, + "Client_Secret": { + "type": "String" + }, + "Ingestion_Table_Name": { + "type": "String", + "defaultValue": "Spycloud_MDE_LogsV2_CL" + }, + "create_incident_in_sentinel": { + "type": "Bool", + "defaultValue": false + }, + "Workspace_Name": { + "type": "String", + "defaultValue": "Your workspace name" + }, + "Defender_IOC_Action_Type": { + "type": "String", + "defaultValue": "Alert" + }, + "notification_email": { + "type": "String" + } + }, + "triggers": { + "Microsoft_Sentinel_incident": { + "type": "ApiConnectionWebhook", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "body": { + "callback_url": "@listCallbackUrl()" + }, + "path": "/incident-creation" + } + } + }, + "actions": { + "Entities_-_Get_Hosts": { + "runAfter": { + "For_each_incident_alert": [ + "Succeeded" + ] + }, + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "post", + "body": "@triggerBody()?['object']?['properties']?['relatedEntities']", + "path": "/entities/host" + } + }, + "For_each": { + "foreach": "@body('Entities_-_Get_Hosts')?['Hosts']", + "actions": { + "Machines_-_Get_single_machine": { + "runAfter": { + "Set_host_name": [ + "Succeeded" + ] + }, + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['wdatp']['connectionId']" + } + }, + "method": "get", + "path": "/api/machines/@variables('host_name')" + } + }, + "GetAccessToken": { + "runAfter": { + "Send_an_email_(V2)": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "uri": "@concat(variables('loginUrl'), parameters('TenantID'), '/oauth2/v2.0/token')", + "method": "POST", + "headers": { + "Content-Type": "application/x-www-form-urlencoded" + }, + "body": "grant_type=client_credentials&client_id=@{parameters('ClientID')}&client_secret=@{parameters('Client_Secret')}&scope=https://monitor.azure.com/.default" + }, + "runtimeConfiguration": { + "contentTransfer": { + "transferMode": "Chunked" + } + } + }, + "Log_ingestion": { + "runAfter": { + "GetAccessToken": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "uri": "@variables('log_ingestion_api')", + "method": "POST", + "headers": { + "Authorization": "Bearer @{body('GetAccessToken')?['access_token']}", + "Content-Type": "application/json" + }, + "body": [ + { + "TimeGenerated": "@{utcNow()}", + "IncidentId": "@{body('Create_incident')?['properties']?['providerIncidentId']}", + "DocumentId": "@{variables('DocumentID')}", + "SpyCloudPublishDate": "@{variables('SpyCloudPublishDate')}", + "InfectedTime": "@{variables('InfectedTime')}", + "BreachTitle": "@{variables('BreachTitle')}", + "InfectedMachineId": "@{variables('InfectedMachineId')}", + "HostName": "@{coalesce(body('Machines_-_Get_single_machine')?['computerDnsName'], '')}", + "NormalizedHostName": "@{toLower(coalesce(body('Machines_-_Get_single_machine')?['computerDnsName'], ''))}", + "DeviceId": "@{coalesce(body('Machines_-_Get_single_machine')?['id'], '')}", + "OSPlatform": "@{coalesce(body('Machines_-_Get_single_machine')?['osPlatform'], '')}", + "RiskScore": "@{coalesce(body('Machines_-_Get_single_machine')?['riskScore'], '')}", + "ExposureLevel": "@{coalesce(body('Machines_-_Get_single_machine')?['exposureLevel'], '')}", + "IsolationRequested": "@variables('machine_isolated')", + "IsolationStatus": "@variables('machine_isolated')", + "MachineTagAdded": "@variables('machine_tag_added')", + "MachineTagName": "@{parameters('Machine_Tag_Value')}", + "AddedIOCsToDefender": "@variables('defender_iocs_added')", + "PlaybookName": "[parameters('PlaybookName')]" + } + ] + }, + "runtimeConfiguration": { + "contentTransfer": { + "transferMode": "Chunked" + } + } + }, + "Set_host_name": { + "type": "SetVariable", + "inputs": { + "name": "host_name", + "value": "@item()?['HostName']" + } + }, + "Check_Create_Sentinel_Incident": { + "actions": { + "Create_incident": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "put", + "body": { + "title": "Spycloud MDE Alert - Machine Comprised @{variables('host_name')}", + "severity": "High", + "status": "Active", + "description": "The Incident is created from Spycloud MDE Automation Playbook" + }, + "path": "[concat('/Incidents/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/workspaces/', parameters('Workspace_Name'))]" + } + } + }, + "runAfter": { + "Machines_-_Get_single_machine": [ + "Succeeded" + ] + }, + "else": { + "actions": {} + }, + "expression": { + "and": [ + { + "equals": [ + "@parameters('create_incident_in_sentinel')", + "@true" + ] + } + ] + }, + "type": "If" + }, + "Condition_Isolate_Machine": { + "actions": { + "Condition_-_Check_Machine_is_Active": { + "actions": { + "Set_-_machine_active_to_true": { + "type": "SetVariable", + "inputs": { + "name": "is_machine_active", + "value": true + } + } + }, + "else": { + "actions": { + "Set_machine_active_to_false": { + "type": "SetVariable", + "inputs": { + "name": "is_machine_active", + "value": false + } + } + } + }, + "expression": { + "and": [ + { + "equals": [ + "@body('Machines_-_Get_single_machine')?['healthStatus']", + "Active" + ] + } + ] + }, + "type": "If" + }, + "Condition_-_Check_if_the_machine_is_lastseen_in_the_last_6_hours": { + "actions": { + "Set_last_active": { + "type": "SetVariable", + "inputs": { + "name": "is_last_sees_satisfied", + "value": true + } + } + }, + "runAfter": { + "Condition_-_Check_Machine_is_Active": [ + "Succeeded" + ] + }, + "else": { + "actions": {} + }, + "expression": { + "and": [ + { + "greater": [ + "@ticks(body('Machines_-_Get_single_machine')?['lastSeen'])", + "@ticks(addHours(utcNow(), -6))" + ] + } + ] + }, + "type": "If" + }, + "Condition_If_we_can_Isolate_the_machine": { + "actions": { + "Actions_-_Isolate_machine": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['wdatp']['connectionId']" + } + }, + "method": "post", + "body": { + "Comment": "This machine has found comprised - SpyCloud", + "IsolationType": "Selective" + }, + "path": "/api/machines/@{encodeURIComponent(body('Machines_-_Get_single_machine')?['id'])}/isolate" + } + }, + "set_machine_isolatyed": { + "runAfter": { + "Actions_-_Isolate_machine": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "machine_isolated", + "value": true + } + } + }, + "runAfter": { + "Condition_-_Check_if_the_machine_is_lastseen_in_the_last_6_hours": [ + "Succeeded" + ] + }, + "else": { + "actions": {} + }, + "expression": { + "and": [ + { + "equals": [ + "@variables('is_machine_active')", + "@true" + ] + }, + { + "equals": [ + "@variables('is_last_sees_satisfied')", + "@true" + ] + } + ] + }, + "type": "If" + } + }, + "runAfter": { + "Check_Create_Sentinel_Incident": [ + "Succeeded" + ] + }, + "else": { + "actions": {} + }, + "expression": { + "and": [ + { + "equals": [ + "@parameters('Isolate_Machine')", + "@true" + ] + } + ] + }, + "type": "If" + }, + "Condition_-_Add_Machine_Tag": { + "actions": { + "Machines_-_Tag_machine": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['wdatp']['connectionId']" + } + }, + "method": "post", + "body": { + "Value": "@parameters('Machine_Tag_Value')", + "Action": "Add" + }, + "path": "/api/machines/@{encodeURIComponent(body('Machines_-_Get_single_machine')?['id'])}/tags" + } + }, + "Set_machine_tag_added": { + "runAfter": { + "Machines_-_Tag_machine": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "machine_tag_added", + "value": true + } + } + }, + "runAfter": { + "Condition_Isolate_Machine": [ + "Succeeded" + ] + }, + "else": { + "actions": {} + }, + "expression": { + "and": [ + { + "greater": [ + "@length(parameters('Machine_Tag_Value'))", + 0 + ] + } + ] + }, + "type": "If" + }, + "Send_an_email_(V2)": { + "runAfter": { + "Condition_-_Add_Machine_Tag": [ + "Succeeded" + ] + }, + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['office365']['connectionId']" + } + }, + "method": "post", + "body": { + "To": "@parameters('notification_email')", + "Subject": "@{variables('host_name')} - Security Risk", + "Body": "

Security notification! This is automated email sent by Microsoft Sentinel SpyCloud Automation!


For Host @{variables('host_name')} the following actions were taken


Machine Tag Added : @{variables('machine_tag_added')},

Machine Tag Value : @{parameters('Machine_Tag_Value')},

Machine Isolated: @{variables('machine_isolated')}

", + "Importance": "Normal" + }, + "path": "/v2/Mail" + } + } + }, + "runAfter": { + "Condition_Save_IOCS_in_Defender": [ + "Succeeded" + ] + }, + "type": "Foreach" + }, + "Variables_Section": { + "runAfter": {}, + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "log_ingestion_api", + "type": "string", + "value": "@{concat(concat(concat(parameters('Spycloud_Defender_DCE_Endpoint'),'/dataCollectionRules/'),parameters('Spycloud_Defender_DCE_Immutable_ID') ),concat('/streams/Custom-',concat(parameters('Ingestion_Table_Name'), '?api-version=2023-01-01') ))}" + }, + { + "name": "access_token_url", + "type": "string", + "value": "test" + }, + { + "name": "log_ingestion_url", + "type": "string", + "value": "test" + }, + { + "name": "host_name", + "type": "string", + "value": " " + }, + { + "name": "defender_iocs_object", + "type": "array", + "value": [] + }, + { + "name": "machine_isolated", + "type": "boolean", + "value": false + }, + { + "name": "machine_tag_added", + "type": "boolean", + "value": false + }, + { + "name": "defender_iocs_added", + "type": "boolean", + "value": false + }, + { + "name": "SpyCloudPublishDate", + "type": "string" + }, + { + "name": "InfectedTime", + "type": "string" + }, + { + "name": "BreachTitle", + "type": "string" + }, + { + "name": "InfectedMachineId", + "type": "string" + }, + { + "name": "DocumentID", + "type": "string" + }, + { + "name": "incident_custom_details_object", + "type": "object" + }, + { + "name": "is_machine_onboarded", + "type": "boolean" + }, + { + "name": "is_machine_active", + "type": "boolean", + "value": false + }, + { + "name": "is_machine_excluded", + "type": "boolean", + "value": false + }, + { + "name": "is_last_sees_satisfied", + "type": "boolean", + "value": false + } + ] + } + }, + "Condition_Save_IOCS_in_Defender": { + "actions": { + "Entities_-_Get_DNS": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "post", + "body": "@triggerBody()?['object']?['properties']?['relatedEntities']", + "path": "/entities/dnsresolution" + } + }, + "Entities_-_Get_IPs": { + "runAfter": { + "For_each_Domains_in_incident": [ + "Succeeded" + ] + }, + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "post", + "body": "@triggerBody()?['object']?['properties']?['relatedEntities']", + "path": "/entities/ip" + } + }, + "Entities_-_Get_URLs": { + "runAfter": { + "For_each_IPs_in_incident": [ + "Succeeded" + ] + }, + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "post", + "body": "@triggerBody()?['object']?['properties']?['relatedEntities']", + "path": "/entities/url" + } + }, + "For_each_Domains_in_incident": { + "foreach": "@body('Entities_-_Get_DNS')?['Dnsresolutions']", + "actions": { + "Domain_IOC_Obejct": { + "type": "Compose", + "inputs": { + "action": "@parameters('Defender_IOC_Action_Type')", + "description": "SpyCloud MDE Playbook", + "indicatorType": "DomainName", + "indicatorValue": "@item()?['DomainName']", + "title": "SpyCloud MDE Playbook", + "application": "SpyCloud", + "expirationTime": "@addDays(utcNow(),parameters('IOC_Expiration_Days'),'yyyy-MM-ddTHH:mm:ssZ')" + }, + "description": "SpyCloud MDE Playbook" + }, + "Build_IOC_Object": { + "runAfter": { + "Domain_IOC_Obejct": [ + "Succeeded" + ] + }, + "type": "AppendToArrayVariable", + "inputs": { + "name": "defender_iocs_object", + "value": "@outputs('Domain_IOC_Obejct')" + } + } + }, + "runAfter": { + "Entities_-_Get_DNS": [ + "Succeeded" + ] + }, + "type": "Foreach" + }, + "For_each_IPs_in_incident": { + "foreach": "@body('Entities_-_Get_IPs')?['IPs']", + "actions": { + "IP_IOC_Obejct": { + "type": "Compose", + "inputs": { + "action": "Block", + "description": "SpyCloiud MDE Playbook", + "indicatorType": "IpAddress", + "indicatorValue": "@item()?['Address']", + "title": "SpyCloiud MDE Playbook", + "application": "SpyCloud", + "expirationTime": "@addDays(utcNow(),parameters('IOC_Expiration_Days'),'yyyy-MM-ddTHH:mm:ssZ')" + }, + "description": "SpyCloud MDE Playbook" + }, + "Build_IOC_Object_1": { + "runAfter": { + "IP_IOC_Obejct": [ + "Succeeded" + ] + }, + "type": "AppendToArrayVariable", + "inputs": { + "name": "defender_iocs_object", + "value": "@outputs('IP_IOC_Obejct')" + } + } + }, + "runAfter": { + "Entities_-_Get_IPs": [ + "Succeeded" + ] + }, + "type": "Foreach" + }, + "For_each_Url_in_incident": { + "foreach": "@body('Entities_-_Get_URLs')?['URLs']", + "actions": { + "Url_IOC_Obejct": { + "type": "Compose", + "inputs": { + "action": "Block", + "description": "SpyCloiud MDE Playbook", + "indicatorType": "Url", + "indicatorValue": "@item()?['Url']", + "title": "SpyCloiud MDE Playbook", + "application": "SpyCloud", + "expirationTime": "@addDays(utcNow(),parameters('IOC_Expiration_Days'),'yyyy-MM-ddTHH:mm:ssZ')" + }, + "description": "SpyCloud MDE Playbook" + }, + "Build_IOC_Object_2": { + "runAfter": { + "Url_IOC_Obejct": [ + "Succeeded" + ] + }, + "type": "AppendToArrayVariable", + "inputs": { + "name": "defender_iocs_object", + "value": "@outputs('Url_IOC_Obejct')" + } + } + }, + "runAfter": { + "Entities_-_Get_URLs": [ + "Succeeded" + ] + }, + "type": "Foreach" + }, + "Auth_MDE": { + "runAfter": { + "For_each_Url_in_incident": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "uri": "@concat(variables('loginUrl'), parameters('TenantID'), '/oauth2/v2.0/token')", + "method": "POST", + "headers": { + "Content-Type": "application/x-www-form-urlencoded" + }, + "body": "grant_type=client_credentials&client_id=@{parameters('ClientID')}&client_secret=@{parameters('Client_Secret')}&scope=https://securitycenter.onmicrosoft.com/windowsatpservice/.default" + }, + "runtimeConfiguration": { + "contentTransfer": { + "transferMode": "Chunked" + } + } + }, + "HTTP_-_Create_Indicator": { + "runAfter": { + "Auth_MDE": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "uri": "https://api.security.microsoft.com/api/indicators/import", + "method": "POST", + "headers": { + "Authorization": "Bearer @{body('Auth_MDE')?['access_token']}" + }, + "body": { + "Indicators": "@variables('defender_iocs_object')" + } + }, + "runtimeConfiguration": { + "contentTransfer": { + "transferMode": "Chunked" + } + } + }, + "Set_defender_iocs_variable": { + "runAfter": { + "HTTP_-_Create_Indicator": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "defender_iocs_added", + "value": true + } + } + }, + "runAfter": { + "Entities_-_Get_Hosts": [ + "Succeeded" + ] + }, + "else": { + "actions": {} + }, + "expression": { + "and": [ + { + "equals": [ + "@parameters('Save_IOCs_Defender')", + "@true" + ] + } + ] + }, + "type": "If" + }, + "For_each_incident_alert": { + "foreach": "@triggerBody()?['object']?['properties']?['Alerts']", + "actions": { + "Set_custom_details_object": { + "type": "SetVariable", + "inputs": { + "name": "incident_custom_details_object", + "value": "@json(items('For_each_incident_alert')?['properties']?['additionalData']?['Custom Details'])" + } + }, + "Set_Spycloud_publish_date": { + "runAfter": { + "Set_custom_details_object": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "SpyCloudPublishDate", + "value": "@first(coalesce(variables('incident_custom_details_object')?['SpyCloudPublishDate'], createArray('')))" + } + }, + "Set_Infected_Time": { + "runAfter": { + "Set_Spycloud_publish_date": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "InfectedTime", + "value": "@first(coalesce(variables('incident_custom_details_object')?['InfectedTime'], createArray('')))" + } + }, + "Set_Breach_Title": { + "runAfter": { + "Set_Infected_Time": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "BreachTitle", + "value": "@first(coalesce(variables('incident_custom_details_object')?['BreachTitle'], createArray('')))\r\n" + } + }, + "Set_Infected_Machine_ID": { + "runAfter": { + "Set_Breach_Title": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "InfectedMachineId", + "value": "@first(coalesce(variables('incident_custom_details_object')?['InfectedMachineId'], createArray('')))" + } + }, + "Set_Document_ID": { + "runAfter": { + "Set_Infected_Machine_ID": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "DocumentID", + "value": "@first(coalesce(variables('incident_custom_details_object')?['DocumentID'], createArray('')))" + } + } + }, + "runAfter": { + "Variables_Section": [ + "Succeeded" + ] + }, + "type": "Foreach" + } + }, + "outputs": {} + }, + "parameters": { + "$connections": { + "value": { + "wdatp": { + "connectionId": "[resourceId('Microsoft.Web/connections', variables('WDATPConnection'))]", + "connectionName": "[variables('WDATPConnection')]", + "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/wdatp')]" + }, + "azuresentinel": { + "connectionId": "[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]", + "connectionName": "[variables('AzureSentinelConnectionName')]", + "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/azuresentinel')]", + "connectionProperties": { + "authentication": { + "type": "ManagedServiceIdentity" + } + } + }, + "office365": { + "connectionId": "[resourceId('Microsoft.Web/connections', variables('Office365V1'))]", + "connectionName": "[variables('Office365V1')]", + "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/office365')]" + } + } + } + } + } + } + ] +} \ No newline at end of file diff --git a/Solutions/SpyCloud Enterprise Protection CCF/Playbooks/SpyCloud_MDE_Automation/readme.md b/Solutions/SpyCloud Enterprise Protection CCF/Playbooks/SpyCloud_MDE_Automation/readme.md new file mode 100644 index 00000000000..4616555a568 --- /dev/null +++ b/Solutions/SpyCloud Enterprise Protection CCF/Playbooks/SpyCloud_MDE_Automation/readme.md @@ -0,0 +1,55 @@ +# SpyCloud MDE Automation Playbook + +This playbook automates endpoint response actions in Microsoft Defender for Endpoint (MDE) when SpyCloud breach data identifies compromised machines. + +**Capabilities** +- Machine isolation in Defender for Endpoint +- Machine tagging for tracking, grouping, and policy targeting +- IOC submission to Defender Threat Intelligence +- Microsoft Sentinel incident creation +- Email notifications +- Execution log ingestion to `Spycloud_MDE_LogsV2_CL` + +## Prerequisites + +- App Registration with the Microsoft Graph and WindowsDefenderATP permissions listed in the [Integration Guide](../../SpyCloud_Sentinel_Integration_Guide.md), Section 2.1 +- DCR Immutable ID and DCE Logs Ingestion Endpoint URL for `Spycloud_MDE_LogsV2_CL` (Section 2.2) +- Monitoring Metrics Publisher role assigned to the App Registration on that DCR + +## Deployment + +1. In the Azure Portal, navigate to **Deploy a custom template** +2. Select this template (`azuredeploy.json`) +3. Confirm Subscription, Resource Group, and Region +4. Enter a value for **PlaybookName** (this is the only ARM deployment-time parameter) +5. Click **Review + Create**, then **Create** +6. Authorize the `office365`, `WindowsDefenderATP`, and `azuresentinel` API connections created by the deployment + +## Post-deployment configuration + +All other settings are **workflow parameters**, baked into the Logic App with default values. After the playbook is deployed, update them with your own values: + +1. Navigate to the Microsoft Sentinel workspace, open **Automation**, and select the `SpyCloud_MDE_Automation` playbook — or go directly to the Logic App resource in the Azure Portal +2. Open the Logic App and click **Edit** to open the workflow designer +3. Open the **Parameters** section (in the designer toolbar, or under **Development Tools → Workflow parameters**) +4. For each parameter listed below, enter the appropriate value for your environment +5. Click **Save** to apply the changes to the playbook + +| Parameter | Type | Default | Description | +|---|---|---|---| +| Isolate_Machine | Bool | false | Enables automatic machine isolation in Defender for Endpoint | +| Machine_Tag_Value | String | (empty) | Tag value applied to affected machines | +| Save_IOCs_Defender | Bool | false | Enables submitting IOCs to Defender Threat Intelligence | +| IOC_Expiration_Days | Int | 30 | Days before a submitted IOC expires in Defender | +| Spycloud_Defender_DCE_Endpoint | String | (empty) | DCE Logs Ingestion Endpoint URL | +| Spycloud_Defender_DCE_Immutable_ID | String | (empty) | DCR Immutable ID for `Spycloud_MDE_LogsV2_CL` | +| TenantID | String | (empty) | Azure Tenant ID | +| ClientID | String | (empty) | App Registration Client ID | +| Client_Secret | String | (empty) | App Registration Client Secret | +| Ingestion_Table_Name | String | Spycloud_MDE_LogsV2_CL | Custom Log Analytics table for playbook logs | +| create_incident_in_sentinel | Bool | false | Enables automatic Sentinel incident creation | +| Workspace_Name | String | Your workspace name | Log Analytics Workspace name | +| Defender_IOC_Action_Type | String | Alert | IOC action in Defender, e.g. Alert, Warn, Block, Audit, or AlertAndBlock | +| notification_email | String | (empty) | Notification email address(es), semicolon-separated | + +After saving workflow parameters, confirm `SpyCloud_MDE_Automation` shows status **Enabled** and check Run History for immediate failures. diff --git a/Solutions/SpyCloud Enterprise Protection CCF/ReleaseNotes.md b/Solutions/SpyCloud Enterprise Protection CCF/ReleaseNotes.md new file mode 100644 index 00000000000..585c8a36d9c --- /dev/null +++ b/Solutions/SpyCloud Enterprise Protection CCF/ReleaseNotes.md @@ -0,0 +1,3 @@ +| **Version** | **Date Modified (DD-MM-YYYY)** | **Change History** | +|-------------|----------------------------------|--------------------------------------------------------| +| 3.0.3 | 09-06-2026 | Initial CCF-based release. SpyCloud Watchlist and Breach Catalog CCF data connector (Compass daily feed included), two built-in analytic rules (**AR_Breached_Users_20**, **AR_malware_25**), two KQL parsers (**get_Spycloud_enriched_data**, **get_spycloud_compass_data**), MDE Automation playbook, and Conditional Access playbook. | diff --git a/Solutions/SpyCloud Enterprise Protection CCF/SolutionMetadata.json b/Solutions/SpyCloud Enterprise Protection CCF/SolutionMetadata.json new file mode 100644 index 00000000000..aa56fc8ea5a --- /dev/null +++ b/Solutions/SpyCloud Enterprise Protection CCF/SolutionMetadata.json @@ -0,0 +1,20 @@ +{ + "publisherId": "spycloud", + "offerId": "azure-sentinel-solution-spycloud-enterprise-protection", + "firstPublishDate": "2026-06-09", + "lastPublishDate": "2026-06-09", + "providers": [ + "SpyCloud" + ], + "categories": { + "domains": [ + "Security - Threat Intelligence", + "Identity" + ] + }, + "support": { + "name": "SpyCloud", + "tier": "Partner", + "link": "https://support.spycloud.com" + } +} From e7daebeaac5162c8b5efd8c2fee4db1a0f7c08ef Mon Sep 17 00:00:00 2001 From: Rambatla Venkat Rao Date: Fri, 24 Jul 2026 13:45:18 +0530 Subject: [PATCH 2/3] Tactics Updated for Analytic rule:Breached users --- .../Analytic Rules/AR_Breached_Users_20.yaml | 2 +- .../Package/3.0.0.zip | Bin 26266 -> 26270 bytes .../Package/mainTemplate.json | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Solutions/SpyCloud Enterprise Protection CCF/Analytic Rules/AR_Breached_Users_20.yaml b/Solutions/SpyCloud Enterprise Protection CCF/Analytic Rules/AR_Breached_Users_20.yaml index 4d9a2384211..14b0d3d909e 100644 --- a/Solutions/SpyCloud Enterprise Protection CCF/Analytic Rules/AR_Breached_Users_20.yaml +++ b/Solutions/SpyCloud Enterprise Protection CCF/Analytic Rules/AR_Breached_Users_20.yaml @@ -13,7 +13,7 @@ queryPeriod: 2d triggerOperator: gt triggerThreshold: 0 tactics: - - CredentialAccess + - Collection relevantTechniques: - T1589.001 query: | diff --git a/Solutions/SpyCloud Enterprise Protection CCF/Package/3.0.0.zip b/Solutions/SpyCloud Enterprise Protection CCF/Package/3.0.0.zip index 6979a834168bfffbba9053c557eb977500b90d7b..02d958b24c249afbbfbc5bac36e778b8de4baea9 100644 GIT binary patch delta 20627 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 Date: Thu, 30 Jul 2026 14:39:04 +0530 Subject: [PATCH 3/3] Release notes Updated and copilot issues resolved --- .../Package/3.0.0.zip | Bin 26270 -> 26862 bytes .../Package/mainTemplate.json | 24 ++++++++---------- .../azuredeploy.json | 22 +++++++--------- .../ReleaseNotes.md | 2 +- 4 files changed, 20 insertions(+), 28 deletions(-) diff --git a/Solutions/SpyCloud Enterprise Protection CCF/Package/3.0.0.zip b/Solutions/SpyCloud Enterprise Protection CCF/Package/3.0.0.zip index 02d958b24c249afbbfbc5bac36e778b8de4baea9..10eb78321c3ca94b5602d4deb9370a74f81b4468 100644 GIT binary patch delta 24471 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 delta 23903 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�fw&`%*n-hna~y1 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 diff --git a/Solutions/SpyCloud Enterprise Protection CCF/Package/mainTemplate.json b/Solutions/SpyCloud Enterprise Protection CCF/Package/mainTemplate.json index 39b88e95dde..c6f49b50a9d 100644 --- a/Solutions/SpyCloud Enterprise Protection CCF/Package/mainTemplate.json +++ b/Solutions/SpyCloud Enterprise Protection CCF/Package/mainTemplate.json @@ -2910,7 +2910,7 @@ }, "method": "put", "body": { - "title": "Spycloud MDE Alert - Machine Comprised @{variables('host_name')}", + "title": "Spycloud MDE Alert - Machine Compromised @{variables('host_name')}", "severity": "High", "status": "Active", "description": "The Incident is created from Spycloud MDE Automation Playbook" @@ -3882,12 +3882,10 @@ "expression": { "and": [ { - "not": { - "equals": [ - "@parameters('Add_User_To_Azure_CA_Group')", - "@true" - ] - } + "equals": [ + "@parameters('Add_User_To_Azure_CA_Group')", + "@true" + ] } ] }, @@ -3998,7 +3996,7 @@ "type": "SetVariable", "inputs": { "name": "UserSessionRevokeText", - "value": "User sessions has been scessfully revoked." + "value": "User sessions has been successfully revoked." } } }, @@ -4151,12 +4149,10 @@ "expression": { "and": [ { - "not": { - "equals": [ - "@parseDateTime(body('Get_User_Details')?['lastPasswordChangeDateTime'])", - "@parseDateTime(variables('SpyCloudPublishDate'))" - ] - } + "less": [ + "@addToDateTime(parseDateTime(body('Get_User_Details')?['lastPasswordChangeDateTime']), 7, 'Day')", + "@parseDateTime(variables('SpyCloudPublishDate'))" + ] } ] }, diff --git a/Solutions/SpyCloud Enterprise Protection CCF/Playbooks/SpyCloud_Conditional_Access_Playbook/azuredeploy.json b/Solutions/SpyCloud Enterprise Protection CCF/Playbooks/SpyCloud_Conditional_Access_Playbook/azuredeploy.json index 04ef0aecdb6..60985056acb 100644 --- a/Solutions/SpyCloud Enterprise Protection CCF/Playbooks/SpyCloud_Conditional_Access_Playbook/azuredeploy.json +++ b/Solutions/SpyCloud Enterprise Protection CCF/Playbooks/SpyCloud_Conditional_Access_Playbook/azuredeploy.json @@ -263,12 +263,10 @@ "expression": { "and": [ { - "not": { - "equals": [ - "@parameters('Add_User_To_Azure_CA_Group')", - "@true" - ] - } + "equals": [ + "@parameters('Add_User_To_Azure_CA_Group')", + "@true" + ] } ] }, @@ -382,7 +380,7 @@ "type": "SetVariable", "inputs": { "name": "UserSessionRevokeText", - "value": "User sessions has been scessfully revoked." + "value": "User sessions has been successfully revoked." } } }, @@ -541,12 +539,10 @@ "expression": { "and": [ { - "not": { - "equals": [ - "@parseDateTime(body('Get_User_Details')?['lastPasswordChangeDateTime'])", - "@parseDateTime(variables('SpyCloudPublishDate'))" - ] - } + "less": [ + "@addToDateTime(parseDateTime(body('Get_User_Details')?['lastPasswordChangeDateTime']), 7, 'Day')", + "@parseDateTime(variables('SpyCloudPublishDate'))" + ] } ] }, diff --git a/Solutions/SpyCloud Enterprise Protection CCF/ReleaseNotes.md b/Solutions/SpyCloud Enterprise Protection CCF/ReleaseNotes.md index 585c8a36d9c..9a0f0d65fe6 100644 --- a/Solutions/SpyCloud Enterprise Protection CCF/ReleaseNotes.md +++ b/Solutions/SpyCloud Enterprise Protection CCF/ReleaseNotes.md @@ -1,3 +1,3 @@ | **Version** | **Date Modified (DD-MM-YYYY)** | **Change History** | |-------------|----------------------------------|--------------------------------------------------------| -| 3.0.3 | 09-06-2026 | Initial CCF-based release. SpyCloud Watchlist and Breach Catalog CCF data connector (Compass daily feed included), two built-in analytic rules (**AR_Breached_Users_20**, **AR_malware_25**), two KQL parsers (**get_Spycloud_enriched_data**, **get_spycloud_compass_data**), MDE Automation playbook, and Conditional Access playbook. | +| 3.0.0 | 09-06-2026 | Initial CCF-based release. SpyCloud Watchlist and Breach Catalog CCF data connector (Compass daily feed included), two built-in analytic rules (**AR_Breached_Users_20**, **AR_malware_25**), two KQL parsers (**get_Spycloud_enriched_data**, **get_spycloud_compass_data**), MDE Automation playbook, and Conditional Access playbook. |