diff --git a/.script/tests/KqlvalidationsTests/CustomTables/ZeroFoxAlertPoller_CL.json b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFoxAlertPoller_CL.json new file mode 100644 index 00000000000..067face6d25 --- /dev/null +++ b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFoxAlertPoller_CL.json @@ -0,0 +1,205 @@ +{ + "Name": "ZeroFoxAlertPoller_CL", + "Properties": [ + { + "Name": "TimeGenerated", + "Type": "DateTime" + }, + { + "Name": "alert_type_s", + "Type": "String" + }, + { + "Name": "logs_s", + "Type": "String" + }, + { + "Name": "offending_content_url_s", + "Type": "String" + }, + { + "Name": "asset_term_s", + "Type": "String" + }, + { + "Name": "assignee_s", + "Type": "String" + }, + { + "Name": "entity_id_d", + "Type": "Double" + }, + { + "Name": "entity_name_s", + "Type": "String" + }, + { + "Name": "entity_image_s", + "Type": "String" + }, + { + "Name": "entity_labels_s", + "Type": "String" + }, + { + "Name": "entity_entity_group_id_d", + "Type": "Double" + }, + { + "Name": "entity_entity_group_name_s", + "Type": "String" + }, + { + "Name": "entity_term_s", + "Type": "String" + }, + { + "Name": "content_created_at_t", + "Type": "DateTime" + }, + { + "Name": "id_d", + "Type": "Double" + }, + { + "Name": "Severity", + "Type": "Double" + }, + { + "Name": "perpetrator_name_s", + "Type": "String" + }, + { + "Name": "perpetrator_display_name_s", + "Type": "String" + }, + { + "Name": "perpetrator_id_d", + "Type": "Double" + }, + { + "Name": "perpetrator_url_s", + "Type": "String" + }, + { + "Name": "perpetrator_content_s", + "Type": "String" + }, + { + "Name": "perpetrator_type_s", + "Type": "String" + }, + { + "Name": "perpetrator_timestamp_t", + "Type": "DateTime" + }, + { + "Name": "perpetrator_network_s", + "Type": "String" + }, + { + "Name": "rule_group_id_d", + "Type": "Double" + }, + { + "Name": "asset_id_d", + "Type": "Double" + }, + { + "Name": "asset_name_s", + "Type": "String" + }, + { + "Name": "asset_image_s", + "Type": "String" + }, + { + "Name": "asset_labels_s", + "Type": "String" + }, + { + "Name": "asset_entity_group_id_d", + "Type": "Double" + }, + { + "Name": "asset_entity_group_name_s", + "Type": "String" + }, + { + "Name": "entered_by_s", + "Type": "String" + }, + { + "Name": "metadata_s", + "Type": "String" + }, + { + "Name": "status_s", + "Type": "String" + }, + { + "Name": "timestamp_t", + "Type": "DateTime" + }, + { + "Name": "rule_name_s", + "Type": "String" + }, + { + "Name": "last_modified_t", + "Type": "DateTime" + }, + { + "Name": "protected_locations_s", + "Type": "String" + }, + { + "Name": "darkweb_term_s", + "Type": "String" + }, + { + "Name": "business_network_s", + "Type": "String" + }, + { + "Name": "reviewed_b", + "Type": "Boolean" + }, + { + "Name": "escalated_b", + "Type": "Boolean" + }, + { + "Name": "network_s", + "Type": "String" + }, + { + "Name": "protected_social_object_s", + "Type": "String" + }, + { + "Name": "notes_s", + "Type": "String" + }, + { + "Name": "reviews_s", + "Type": "String" + }, + { + "Name": "rule_id_d", + "Type": "Double" + }, + { + "Name": "entity_account_s", + "Type": "String" + }, + { + "Name": "entity_email_receiver_id_s", + "Type": "String" + }, + { + "Name": "tags_s", + "Type": "String" + } + ] +} diff --git a/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_C2_CL.json b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_C2_CL.json new file mode 100644 index 00000000000..3ce0888f464 --- /dev/null +++ b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_C2_CL.json @@ -0,0 +1,33 @@ +{ + "Name": "ZeroFox_CTI_C2_CL", + "Properties": [ + { + "Name": "TimeGenerated", + "Type": "DateTime" + }, + { + "Name": "domain_s", + "Type": "String" + }, + { + "Name": "port_d", + "Type": "Double" + }, + { + "Name": "tags_s", + "Type": "String" + }, + { + "Name": "ip_addresses_s", + "Type": "String" + }, + { + "Name": "updated_at_t", + "Type": "DateTime" + }, + { + "Name": "created_at_t", + "Type": "DateTime" + } + ] +} diff --git a/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_advanced_dark_web_CL.json b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_advanced_dark_web_CL.json new file mode 100644 index 00000000000..0e0195429a3 --- /dev/null +++ b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_advanced_dark_web_CL.json @@ -0,0 +1,78 @@ +{ + "Name": "ZeroFox_CTI_advanced_dark_web_CL", + "Properties": [ + { + "Name": "TimeGenerated", + "Type": "DateTime" + }, + { + "Name": "id_d", + "Type": "Double" + }, + { + "Name": "created_at_t", + "Type": "DateTime" + }, + { + "Name": "title_s", + "Type": "String" + }, + { + "Name": "confidence_s", + "Type": "String" + }, + { + "Name": "reliability_s", + "Type": "String" + }, + { + "Name": "tlp", + "Type": "String" + }, + { + "Name": "contents_s", + "Type": "String" + }, + { + "Name": "comments_s", + "Type": "String" + }, + { + "Name": "threat_types_s", + "Type": "String" + }, + { + "Name": "target_targets_s", + "Type": "String" + }, + { + "Name": "target_regions_s", + "Type": "String" + }, + { + "Name": "target_industries_s", + "Type": "String" + }, + { + "Name": "languages_s", + "Type": "String" + }, + { + "Name": "actors_s", + "Type": "String" + }, + { + "Name": "tags_s", + "Type": "String" + } + , + { + "Name": "source_urls_s", + "Type": "String" + }, + { + "Name": "source_names_s", + "Type": "String" + } + ] +} diff --git a/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_botnet_CL.json b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_botnet_CL.json new file mode 100644 index 00000000000..f6e37a670be --- /dev/null +++ b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_botnet_CL.json @@ -0,0 +1,89 @@ +{ + "Name": "ZeroFox_CTI_botnet_CL", + "Properties": [ + { + "Name": "TimeGenerated", + "Type": "DateTime" + }, + { + "Name": "listed_at_t", + "Type": "DateTime" + }, + { + "Name": "bot_name_s", + "Type": "String" + }, + { + "Name": "c2_ip_address_s", + "Type": "String" + }, + { + "Name": "c2_domain_s", + "Type": "String" + }, + { + "Name": "is_common_domain_b", + "Type": "Boolean" + }, + { + "Name": "file_location_s", + "Type": "String" + }, + { + "Name": "operating_system_s", + "Type": "String" + }, + { + "Name": "anti_viruses_s", + "Type": "String" + }, + { + "Name": "country_code_s", + "Type": "String" + }, + { + "Name": "zip_code_s", + "Type": "String" + }, + { + "Name": "location_s", + "Type": "String" + }, + { + "Name": "current_language_s", + "Type": "String" + }, + { + "Name": "available_keyboards_s", + "Type": "String" + }, + { + "Name": "uac_s", + "Type": "String" + }, + { + "Name": "process_elevation_s", + "Type": "String" + }, + { + "Name": "acquired_at_t", + "Type": "DateTime" + }, + { + "Name": "logged_at_t", + "Type": "DateTime" + }, + { + "Name": "estimated_infected_at_t", + "Type": "DateTime" + }, + { + "Name": "breached_at", + "Type": "DateTime" + }, + { + "Name": "tags_s", + "Type": "String" + } + ] +} diff --git a/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_breaches_CL.json b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_breaches_CL.json new file mode 100644 index 00000000000..15af661b0c7 --- /dev/null +++ b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_breaches_CL.json @@ -0,0 +1,85 @@ +{ + "Name": "ZeroFox_CTI_breaches_CL", + "Properties": [ + { + "Name": "TimeGenerated", + "Type": "DateTime" + }, + { + "Name": "id_s", + "Type": "Double" + }, + { + "Name": "name_s", + "Type": "String" + }, + { + "Name": "description_s", + "Type": "String" + }, + { + "Name": "breach_date_t", + "Type": "DateTime" + }, + { + "Name": "created_at_t", + "Type": "DateTime" + }, + { + "Name": "included_fields_s", + "Type": "String" + }, + { + "Name": "record_count_d", + "Type": "Double" + }, + { + "Name": "threat_type_s", + "Type": "String" + }, + { + "Name": "geography_region_code_s", + "Type": "String" + }, + { + "Name": "geography_sub_region_code_s", + "Type": "String" + }, + { + "Name": "geography_country_code_s", + "Type": "String" + }, + { + "Name": "geography_country_iso_alpha3_code_s", + "Type": "String" + }, + { + "Name": "geography_region_s", + "Type": "String" + }, + { + "Name": "geography_sub_region_s", + "Type": "String" + }, + { + "Name": "geography_country_s", + "Type": "String" + }, + { + "Name": "confidence_s", + "Type": "String" + }, + { + "Name": "reliability_s", + "Type": "String" + }, + { + "Name": "tlp_s", + "Type": "String" + }, + { + "Name": "industry_s", + "Type": "String" + } + ] +} diff --git a/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_compromised_credentials_CL.json b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_compromised_credentials_CL.json new file mode 100644 index 00000000000..40e45795106 --- /dev/null +++ b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_compromised_credentials_CL.json @@ -0,0 +1,41 @@ +{ + "Name": "ZeroFox_CTI_compromised_credentials_CL", + "Properties": [ + { + "Name": "TimeGenerated", + "Type": "DateTime" + }, + { + "Name": "domain_s", + "Type": "String" + }, + { + "Name": "email_s", + "Type": "String" + }, + { + "Name": "username_s", + "Type": "String" + }, + { + "Name": "password_s", + "Type": "String" + }, + { + "Name": "breach_name_s", + "Type": "String" + }, + { + "Name": "breach_id_s", + "Type": "String" + }, + { + "Name": "impacted_domain_s", + "Type": "String" + }, + { + "Name": "created_at_t", + "Type": "DateTime" + } + ] +} diff --git a/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_credit_cards_CL.json b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_credit_cards_CL.json new file mode 100644 index 00000000000..e2abb880e00 --- /dev/null +++ b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_credit_cards_CL.json @@ -0,0 +1,45 @@ +{ + "Name": "ZeroFox_CTI_credit_cards_CL", + "Properties": [ + { + "Name": "TimeGenerated", + "Type": "DateTime" + }, + { + "Name": "cc_num_s", + "Type": "String" + }, + { + "Name": "month_s", + "Type": "String" + }, + { + "Name": "year_s", + "Type": "String" + }, + { + "Name": "cvv_s", + "Type": "Double" + }, + { + "Name": "issuer_s", + "Type": "String" + }, + { + "Name": "source_s", + "Type": "String" + }, + { + "Name": "cc_bin_s", + "Type": "String" + }, + { + "Name": "breach_name_s", + "Type": "String" + }, + { + "Name": "created_at_t", + "Type": "DateTime" + } + ] +} diff --git a/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_dark_web_CL.json b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_dark_web_CL.json new file mode 100644 index 00000000000..553a9a49131 --- /dev/null +++ b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_dark_web_CL.json @@ -0,0 +1,82 @@ +{ + "Name": "ZeroFox_CTI_dark_web_CL", + "Properties": [ + { + "Name": "TimeGenerated", + "Type": "DateTime" + }, + { + "Name": "content_audience_s", + "Type": "String" + }, + { + "Name": "forum_name_s", + "Type": "String" + }, + { + "Name": "forum_uuid_g", + "Type": "GUID" + }, + { + "Name": "general_topic_s", + "Type": "String" + }, + { + "Name": "language_code_s", + "Type": "String" + }, + { + "Name": "network_type_s", + "Type": "String" + }, + { + "Name": "parent_uuid_g", + "Type": "GUID" + }, + { + "Name": "post_body_s", + "Type": "String" + }, + { + "Name": "timestamp_t", + "Type": "DateTime" + }, + { + "Name": "post_member_name_s", + "Type": "String" + }, + { + "Name": "post_type_s", + "Type": "String" + }, + { + "Name": "post_uuid_g", + "Type": "GUID" + }, + { + "Name": "sequence_number_d", + "Type": "Double" + }, + { + "Name": "thread_name_s", + "Type": "String" + }, + { + "Name": "thread_url_s", + "Type": "String" + }, + { + "Name": "thread_uuid_g", + "Type": "GUID" + }, + { + "Name": "domain_s", + "Type": "String" + }, + { + "Name": "created_at_t", + "Type": "DateTime" + } + + ] +} diff --git a/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_discord_CL.json b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_discord_CL.json new file mode 100644 index 00000000000..e79a1a0ea0c --- /dev/null +++ b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_discord_CL.json @@ -0,0 +1,33 @@ +{ + "Name": "ZeroFox_CTI_discord_CL", + "Properties": [ + { + "Name": "TimeGenerated", + "Type": "DateTime" + }, + { + "Name": "author_id_s", + "Type": "String" + }, + { + "Name": "author_username_s", + "Type": "String" + }, + { + "Name": "channel_name_s", + "Type": "String" + }, + { + "Name": "content_s", + "Type": "String" + }, + { + "Name": "server_name_s", + "Type": "String" + }, + { + "Name": "timestamp_t", + "Type": "DateTime" + } + ] +} diff --git a/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_disruption_CL.json b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_disruption_CL.json new file mode 100644 index 00000000000..0fadbf26ca6 --- /dev/null +++ b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_disruption_CL.json @@ -0,0 +1,61 @@ +{ + "Name": "ZeroFox_CTI_disruption_CL", + "Properties": [ + { + "Name": "TimeGenerated", + "Type": "DateTime" + }, + { + "Name": "url_s", + "Type": "String" + }, + { + "Name": "fqdn_s", + "Type": "String" + }, + { + "Name": "ip_s", + "Type": "String" + }, + { + "Name": "host_s", + "Type": "String" + }, + { + "Name": "registrar_s", + "Type": "String" + }, + { + "Name": "threat_type_s", + "Type": "String" + }, + { + "Name": "http_status_d", + "Type": "Double" + }, + { + "Name": "asn_d", + "Type": "Double" + }, + { + "Name": "iana_d", + "Type": "Double" + }, + { + "Name": "created_at_t", + "Type": "DateTime" + }, + { + "Name": "updated_at_t", + "Type": "DateTime" + }, + { + "Name": "category_s", + "Type": "String" + }, + { + "Name": "network_s", + "Type": "String" + } + ] +} diff --git a/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_email_addresses_CL.json b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_email_addresses_CL.json new file mode 100644 index 00000000000..b9b6d1cc173 --- /dev/null +++ b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_email_addresses_CL.json @@ -0,0 +1,25 @@ +{ + "Name": "ZeroFox_CTI_email_addresses_CL", + "Properties": [ + { + "Name": "TimeGenerated", + "Type": "DateTime" + }, + { + "Name": "created_at_t", + "Type": "DateTime" + }, + { + "Name": "email_s", + "Type": "String" + }, + { + "Name": "domain_s", + "Type": "String" + }, + { + "Name": "tags_s", + "Type": "String" + } + ] +} diff --git a/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_exploits_CL.json b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_exploits_CL.json new file mode 100644 index 00000000000..1d0ab2af1af --- /dev/null +++ b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_exploits_CL.json @@ -0,0 +1,25 @@ +{ + "Name": "ZeroFox_CTI_exploits_CL", + "Properties": [ + { + "Name": "TimeGenerated", + "Type": "DateTime" + }, + { + "Name": "created_at_t", + "Type": "DateTime" + }, + { + "Name": "cve_s", + "Type": "String" + }, + { + "Name": "urls_s", + "Type": "String" + }, + { + "Name": "exploit_s", + "Type": "String" + } + ] +} diff --git a/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_identity_breach_CL.json b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_identity_breach_CL.json new file mode 100644 index 00000000000..0360e33a818 --- /dev/null +++ b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_identity_breach_CL.json @@ -0,0 +1,69 @@ +{ + "Name": "ZeroFox_CTI_identity_breach_CL", + "Properties": [ + { + "Name": "TimeGenerated", + "Type": "DateTime" + }, + { + "Name": "cac_username_hash_s", + "Type": "String" + }, + { + "Name": "cac_email_hash_s", + "Type": "String" + }, + { + "Name": "cac_password_hash_s", + "Type": "String" + }, + { + "Name": "ncid_id_hash_s", + "Type": "String" + }, + { + "Name": "cc_num_hash_s", + "Type": "String" + }, + { + "Name": "passport_id_hash_s", + "Type": "String" + }, + { + "Name": "bank_account_id_hash_s", + "Type": "String" + }, + { + "Name": "medical_account_id_hash_s", + "Type": "String" + }, + { + "Name": "phone_number_e164_hash_s", + "Type": "String" + }, + { + "Name": "dl_id_hash_s", + "Type": "String" + }, + { + "Name": "ui_discovered_ts_s", + "Type": "String" + }, + { + "Name": "ui_insertion_ts_s", + "Type": "String" + }, + { + "Name": "ui_breach_id_d", + "Type": "Double" + }, + { + "Name": "ui_breach_name_s", + "Type": "String" + }, + { + "Name": "ui_breach_description_s", + "Type": "String" + } + ] +} diff --git a/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_irc_CL.json b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_irc_CL.json new file mode 100644 index 00000000000..75021e8b88d --- /dev/null +++ b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_irc_CL.json @@ -0,0 +1,53 @@ +{ + "Name": "ZeroFox_CTI_irc_CL", + "Properties": [ + { + "Name": "TimeGenerated", + "Type": "DateTime" + }, + { + "Name": "channel_s", + "Type": "String" + }, + { + "Name": "message_s", + "Type": "String" + }, + { + "Name": "sender_s", + "Type": "String" + }, + { + "Name": "timestamp_t", + "Type": "DateTime" + }, + { + "Name": "username_s", + "Type": "String" + }, + { + "Name": "hostname_s", + "Type": "String" + }, + { + "Name": "real_name_s", + "Type": "String" + }, + { + "Name": "server_s", + "Type": "String" + }, + { + "Name": "server_info_s", + "Type": "String" + }, + { + "Name": "secure_b", + "Type": "Boolean" + }, + { + "Name": "account_s", + "Type": "String" + } + ] +} diff --git a/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_malware_CL.json b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_malware_CL.json new file mode 100644 index 00000000000..4252ed14975 --- /dev/null +++ b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_malware_CL.json @@ -0,0 +1,45 @@ +{ + "Name": "ZeroFox_CTI_malware_CL", + "Properties": [ + { + "Name": "TimeGenerated", + "Type": "DateTime" + }, + { + "Name": "created_at_t", + "Type": "DateTime" + }, + { + "Name": "family_s", + "Type": "String" + }, + { + "Name": "md5_s", + "Type": "String" + }, + { + "Name": "sha1_s", + "Type": "String" + }, + { + "Name": "sha256_s", + "Type": "String" + }, + { + "Name": "sha512_s", + "Type": "String" + }, + { + "Name": "tags_s", + "Type": "String" + }, + { + "Name": "botnet_s", + "Type": "String" + }, + { + "Name": "c2_s", + "Type": "String" + } + ] +} diff --git a/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_national_ids_CL.json b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_national_ids_CL.json new file mode 100644 index 00000000000..e566dc95ed1 --- /dev/null +++ b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_national_ids_CL.json @@ -0,0 +1,41 @@ +{ + "Name": "ZeroFox_CTI_national_ids_CL", + "Properties": [ + { + "Name": "TimeGenerated", + "Type": "DateTime" + }, + { + "Name": "national_identifier_s", + "Type": "String" + }, + { + "Name": "country_s", + "Type": "String" + }, + { + "Name": "first_name_s", + "Type": "String" + }, + { + "Name": "last_name_s", + "Type": "String" + }, + { + "Name": "person_name_s", + "Type": "String" + }, + { + "Name": "created_at_t", + "Type": "DateTime" + }, + { + "Name": "source_s", + "Type": "String" + }, + { + "Name": "breach_name_s", + "Type": "String" + } + ] +} diff --git a/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_phishing_CL.json b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_phishing_CL.json new file mode 100644 index 00000000000..d077710bb2a --- /dev/null +++ b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_phishing_CL.json @@ -0,0 +1,45 @@ +{ + "Name": "ZeroFox_CTI_phishing_CL", + "Properties": [ + { + "Name": "TimeGenerated", + "Type": "DateTime" + }, + { + "Name": "scanned_t", + "Type": "DateTime" + }, + { + "Name": "domain_s", + "Type": "String" + }, + { + "Name": "url_s", + "Type": "String" + }, + { + "Name": "cert_authority_s", + "Type": "String" + }, + { + "Name": "cert_fingerprint_s", + "Type": "String" + }, + { + "Name": "cert_issued_s", + "Type": "String" + }, + { + "Name": "host_ip_s", + "Type": "String" + }, + { + "Name": "host_asn_d", + "Type": "Double" + }, + { + "Name": "host_geo_s", + "Type": "String" + } + ] +} diff --git a/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_phone_numbers_CL.json b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_phone_numbers_CL.json new file mode 100644 index 00000000000..7dd99d14813 --- /dev/null +++ b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_phone_numbers_CL.json @@ -0,0 +1,17 @@ +{ + "Name": "ZeroFox_CTI_phone_numbers_CL", + "Properties": [ + { + "Name": "TimeGenerated", + "Type": "DateTime" + }, + { + "Name": "phone_number_s", + "Type": "String" + }, + { + "Name": "created_at_t", + "Type": "DateTime" + } + ] +} diff --git a/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_ransomware_CL.json b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_ransomware_CL.json new file mode 100644 index 00000000000..e8bc0e1f94e --- /dev/null +++ b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_ransomware_CL.json @@ -0,0 +1,53 @@ +{ + "Name": "ZeroFox_CTI_ransomware_CL", + "Properties": [ + { + "Name": "TimeGenerated", + "Type": "DateTime" + }, + { + "Name": "created_at_t", + "Type": "DateTime" + }, + { + "Name": "md5_s", + "Type": "String" + }, + { + "Name": "sha1_s", + "Type": "String" + }, + { + "Name": "sha256_s", + "Type": "String" + }, + { + "Name": "sha512_s", + "Type": "String" + }, + { + "Name": "emails_s", + "Type": "String" + }, + { + "Name": "ransom_note_s", + "Type": "String" + }, + { + "Name": "note_urls_s", + "Type": "String" + }, + { + "Name": "crypto_wallets_s", + "Type": "String" + }, + { + "Name": "ransomware_name_s", + "Type": "String" + }, + { + "Name": "tags_s", + "Type": "String" + } + ] +} diff --git a/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_telegram_CL.json b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_telegram_CL.json new file mode 100644 index 00000000000..add588d3a8b --- /dev/null +++ b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_telegram_CL.json @@ -0,0 +1,37 @@ +{ + "Name": "ZeroFox_CTI_telegram_CL", + "Properties": [ + { + "Name": "TimeGenerated", + "Type": "DateTime" + }, + { + "Name": "channel_name_s", + "Type": "String" + }, + { + "Name": "timestamp_t", + "Type": "DateTime" + }, + { + "Name": "first_name_s", + "Type": "String" + }, + { + "Name": "last_name_s", + "Type": "String" + }, + { + "Name": "message_s", + "Type": "String" + }, + { + "Name": "user_s", + "Type": "String" + }, + { + "Name": "message_url_s", + "Type": "String" + } + ] +} diff --git a/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_threat_actors_CL.json b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_threat_actors_CL.json new file mode 100644 index 00000000000..4b4c2181aa2 --- /dev/null +++ b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_threat_actors_CL.json @@ -0,0 +1,57 @@ +{ + "Name": "ZeroFox_CTI_threat_actors_CL", + "Properties": [ + { + "Name": "TimeGenerated", + "Type": "DateTime" + }, + { + "Name": "id_d", + "Type": "Double" + }, + { + "Name": "mitre_id_s", + "Type": "String" + }, + { + "Name": "name_s", + "Type": "String" + }, + { + "Name": "created_at_t", + "Type": "DateTime" + }, + { + "Name": "updated_at_t", + "Type": "DateTime" + }, + { + "Name": "description_s", + "Type": "String" + }, + { + "Name": "references_s", + "Type": "String" + }, + { + "Name": "software_s", + "Type": "String" + }, + { + "Name": "associated_groups_s", + "Type": "String" + }, + { + "Name": "target_geo_s", + "Type": "String" + }, + { + "Name": "target_industries_s", + "Type": "String" + }, + { + "Name": "mitre_ttps_s", + "Type": "String" + } + ] +} diff --git a/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_vulnerabilities_CL.json b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_vulnerabilities_CL.json new file mode 100644 index 00000000000..cb4736155b1 --- /dev/null +++ b/.script/tests/KqlvalidationsTests/CustomTables/ZeroFox_CTI_vulnerabilities_CL.json @@ -0,0 +1,53 @@ +{ + "Name": "ZeroFox_CTI_vulnerabilities_CL", + "Properties": [ + { + "Name": "TimeGenerated", + "Type": "DateTime" + }, + { + "Name": "base_score_d", + "Type": "Double" + }, + { + "Name": "description_s", + "Type": "String" + }, + { + "Name": "exploitability_score_d", + "Type": "Double" + }, + { + "Name": "impact_score_d", + "Type": "Double" + }, + { + "Name": "created_at_t", + "Type": "DateTime" + }, + { + "Name": "updated_at_t", + "Type": "DateTime" + }, + { + "Name": "vector_string_s", + "Type": "String" + }, + { + "Name": "cve_s", + "Type": "String" + }, + { + "Name": "summary_s", + "Type": "String" + }, + { + "Name": "remediation_s", + "Type": "String" + }, + { + "Name": "products_s", + "Type": "String" + } + ] +} diff --git a/.script/tests/detectionTemplateSchemaValidation/ValidConnectorIds.json b/.script/tests/detectionTemplateSchemaValidation/ValidConnectorIds.json index aff456865ec..718f2be80b5 100644 --- a/.script/tests/detectionTemplateSchemaValidation/ValidConnectorIds.json +++ b/.script/tests/detectionTemplateSchemaValidation/ValidConnectorIds.json @@ -197,6 +197,7 @@ "DynatraceAuditLogs", "DynatraceProblems", "MicrosoftDefenderThreatIntelligence", + "ZeroFox_Alert_Polling", "CortexXDR", "MimecastTTPAPI", "MimecastAuditAPI", diff --git a/Logos/foxy-mark.svg b/Logos/foxy-mark.svg new file mode 100644 index 00000000000..625541fa8b1 --- /dev/null +++ b/Logos/foxy-mark.svg @@ -0,0 +1,11 @@ + + + + + + + + + + diff --git a/Solutions/ZeroFox/Analytic Rules/ZF_Alerts_HighSeverityRule.yaml b/Solutions/ZeroFox/Analytic Rules/ZF_Alerts_HighSeverityRule.yaml new file mode 100644 index 00000000000..2f15873cb34 --- /dev/null +++ b/Solutions/ZeroFox/Analytic Rules/ZF_Alerts_HighSeverityRule.yaml @@ -0,0 +1,33 @@ +id: deb45e6d-892f-40bf-9118-e2a6f26b788d +name: ZeroFox Alerts - High Severity Alerts +description: | + 'Detects high severity alerts from ZeroFox' +severity: High +status: Available +requiredDataConnectors: + - connectorId: ZeroFox_Alert_Polling + dataTypes: + - ZeroFoxAlertPoller_CL +queryFrequency: 5m +queryPeriod: 5m +triggerOperator: gt +triggerThreshold: 0 +tactics: + - ResourceDevelopment + - InitialAccess +relevantTechniques: + - T1583 + - T1586 + - T1566 +query: | + ZeroFoxAlertPoller_CL + | where Severity in (5) +entityMappings: + - entityType: Account + fieldMappings: + - identifier: FullName + columnName: entity_name_s +eventGroupingSettings: + aggregationKind: AlertPerResult +kind: Scheduled +version: 1.0.0 diff --git a/Solutions/ZeroFox/Analytic Rules/ZF_Alerts_InformationalSeverityRule.yaml b/Solutions/ZeroFox/Analytic Rules/ZF_Alerts_InformationalSeverityRule.yaml new file mode 100644 index 00000000000..b27fcbd22d6 --- /dev/null +++ b/Solutions/ZeroFox/Analytic Rules/ZF_Alerts_InformationalSeverityRule.yaml @@ -0,0 +1,33 @@ +id: 6f7a7413-b72f-4361-84ee-897baeb9c6d4 +name: ZeroFox Alerts - Informational Severity Alerts +description: | + 'Detects informational severity alerts from ZeroFox' +severity: Informational +status: Available +requiredDataConnectors: + - connectorId: ZeroFox_Alert_Polling + dataTypes: + - ZeroFoxAlertPoller_CL +queryFrequency: 5m +queryPeriod: 5m +triggerOperator: gt +triggerThreshold: 0 +tactics: + - ResourceDevelopment + - InitialAccess +relevantTechniques: + - T1583 + - T1586 + - T1566 +query: | + ZeroFoxAlertPoller_CL + | where Severity in (1,2) +entityMappings: + - entityType: Account + fieldMappings: + - identifier: FullName + columnName: entity_name_s +eventGroupingSettings: + aggregationKind: AlertPerResult +kind: Scheduled +version: 1.0.0 diff --git a/Solutions/ZeroFox/Analytic Rules/ZF_Alerts_LowSeverityRule.yaml b/Solutions/ZeroFox/Analytic Rules/ZF_Alerts_LowSeverityRule.yaml new file mode 100644 index 00000000000..d36f396b2b3 --- /dev/null +++ b/Solutions/ZeroFox/Analytic Rules/ZF_Alerts_LowSeverityRule.yaml @@ -0,0 +1,33 @@ +id: e0c7a91a-7aa1-498a-9c20-cd6c721f9345 +name: ZeroFox Alerts - Low Severity Alerts +description: | + 'Detects low severity alerts from ZeroFox' +severity: Low +status: Available +requiredDataConnectors: + - connectorId: ZeroFox_Alert_Polling + dataTypes: + - ZeroFoxAlertPoller_CL +queryFrequency: 5m +queryPeriod: 5m +triggerOperator: gt +triggerThreshold: 0 +tactics: + - ResourceDevelopment + - InitialAccess +relevantTechniques: + - T1583 + - T1586 + - T1566 +query: | + ZeroFoxAlertPoller_CL + | where Severity in (3) +entityMappings: + - entityType: Account + fieldMappings: + - identifier: FullName + columnName: entity_name_s +eventGroupingSettings: + aggregationKind: AlertPerResult +kind: Scheduled +version: 1.0.0 diff --git a/Solutions/ZeroFox/Analytic Rules/ZF_Alerts_MediumSeverityRule.yaml b/Solutions/ZeroFox/Analytic Rules/ZF_Alerts_MediumSeverityRule.yaml new file mode 100644 index 00000000000..17e586c53fd --- /dev/null +++ b/Solutions/ZeroFox/Analytic Rules/ZF_Alerts_MediumSeverityRule.yaml @@ -0,0 +1,33 @@ +id: a6496de5-911b-4199-b7db-d34ac9d70df3 +name: ZeroFox Alerts - Medium Severity Alerts +description: | + 'Detects medium severity alerts from ZeroFox' +severity: Medium +status: Available +requiredDataConnectors: + - connectorId: ZeroFox_Alert_Polling + dataTypes: + - ZeroFoxAlertPoller_CL +queryFrequency: 5m +queryPeriod: 5m +triggerOperator: gt +triggerThreshold: 0 +tactics: + - ResourceDevelopment + - InitialAccess +relevantTechniques: + - T1583 + - T1586 + - T1566 +query: | + ZeroFoxAlertPoller_CL + | where Severity in (4) +entityMappings: + - entityType: Account + fieldMappings: + - identifier: FullName + columnName: entity_name_s +eventGroupingSettings: + aggregationKind: AlertPerResult +kind: Scheduled +version: 1.0.0 diff --git a/Solutions/ZeroFox/Data Connectors/Alerts/alerts_connector.json b/Solutions/ZeroFox/Data Connectors/Alerts/alerts_connector.json new file mode 100644 index 00000000000..861e945c1e3 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/Alerts/alerts_connector.json @@ -0,0 +1,128 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "workspace": { + "type": "string", + "defaultValue": "" + } + }, + "resources": [ + { + "id": "[concat('/subscriptions/',subscription().subscriptionId,'/resourceGroups/',resourceGroup().name,'/providers/Microsoft.OperationalInsights/workspaces/',parameters('workspace'),'/providers/Microsoft.SecurityInsights/dataConnectors/',guid(subscription().subscriptionId))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',guid(subscription().subscriptionId))]", + "apiVersion": "2021-03-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectors", + "kind": "APIPolling", + "properties": { + "connectorUiConfig": { + "id":"ZeroFox_Alert_Polling", + "title": "ZeroFox Enterprise - Alerts (Polling CCP)", + "publisher": "ZeroFox Enterprise", + "descriptionMarkdown": "Collects alerts from ZeroFox API.", + "graphQueriesTableName": "ZeroFoxAlertPoller_CL", + "graphQueries": [ + { + "metricName": "Total alerts received", + "legend": "ZeroFox Alerts", + "baseQuery": "{{graphQueriesTableName}}" + } + ], + "sampleQueries": [ + { + "description": "List all ZeroFox alerts", + "query": "{{graphQueriesTableName}}\n| sort by TimeGenerated asc" + }, + { + "description": "Count alerts by network type", + "query": "{{graphQueriesTableName}}\n| summarize Count = count() by ThreatSource=network_s" + }, + { + "description": "Count alerts by entity", + "query": "{{graphQueriesTableName}}\n| summarize Count = count() by Entity=entity_name_s" + } + ], + "dataTypes": [ + { + "name": "{{graphQueriesTableName}}", + "lastDataReceivedQuery": "{{graphQueriesTableName}}\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + } + ], + "connectivityCriteria": [ + { + "type": "SentinelKindsV2", + "value": [ + "APIPolling" + ] + } + ], + "availability": { + "status": 1, + "isPreview": false + }, + "permissions": { + "resourceProvider": [ + { + "provider": "Microsoft.OperationalInsights/solutions", + "permissionsDisplayText": "read and write permissions are required.", + "providerDisplayName": "Workspace", + "scope": "Workspace", + "requiredPermissions": { + "action": true, + "write": true, + "read": true, + "delete": true + } + } + ], + "customs": [ + { + "name": "ZeroFox Personal Access Token (PAT)", + "description": "A ZeroFox PAT is required. You can get it in Data Connectors > [API Data Feeds](https://cloud.zerofox.com/data_connectors/api)." + } + ] + }, + "instructionSteps": [ + { + "title": "Connect ZeroFox to Microsoft Sentinel", + "description": "Provide your ZeroFox PAT", + "instructions": [ + { + "type": "APIKey" + } + ] + } + ] + }, + "pollingConfig": { + "auth": { + "authType": "APIKey", + "APIKeyName": "Authorization", + "APIKeyIdentifier": "Token" + }, + "request": { + "apiEndpoint": "https://api.zerofox.com/1.0/alerts/", + "httpMethod": "Get", + "queryTimeFormat": "yyyy-MM-ddTHH:mm:ssZ", + "startTimeAttributeName": "min_timestamp", + "endTimeAttributeName": "max_timestamp", + "queryParameters": { + "sort_direction": "asc" + } + }, + "response": { + "eventsJsonPaths": [ + "$.alerts[*]" + ] + }, + "paging": { + "pagingType": "Offset", + "offsetParaName": "offset", + "pageSizeParaName": "limit", + "pageSize": 100 + } + } + } + } + ] +} diff --git a/Solutions/ZeroFox/Data Connectors/CTI/ZeroFox_CTI_FunctionApp.json b/Solutions/ZeroFox/Data Connectors/CTI/ZeroFox_CTI_FunctionApp.json new file mode 100644 index 00000000000..5adb812dd36 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/ZeroFox_CTI_FunctionApp.json @@ -0,0 +1,348 @@ +{ + "id": "ZeroFoxCTIDataConnector", + "title": "ZeroFox CTI", + "publisher": "ZeroFox", + "descriptionMarkdown": "The ZeroFox CTI data connectors provide the capability to ingest the different [ZeroFox](https://www.zerofox.com/threat-intelligence/) cyber threat intelligence alerts into Microsoft Sentinel.", + "graphQueries": [ + { + "metricName": "ZeroFox CTI Advanced Dark Web Logs", + "legend": "ZeroFox_CTI_advanced_dark_web_CL", + "baseQuery": "ZeroFox_CTI_advanced_dark_web_CL" + }, + { + "metricName": "ZeroFox CTI Botnet Logs", + "baseQuery": "ZeroFox_CTI_botnet_CL" + }, + { + "metricName": "ZeroFox CTI Breaches Logs", + "legend": "ZeroFox_CTI_breaches_CL", + "baseQuery": "ZeroFox_CTI_breaches_CL" + }, + { + "metricName": "ZeroFox CTI C2 Domains Logs", + "legend": "ZeroFox_CTI_C2_CL", + "baseQuery": "ZeroFox_CTI_C2_CL" + }, + { + "metricName": "ZeroFox CTI Compromised Credentials Logs", + "legend": "ZeroFox_CTI_compromised_credentials_CL", + "baseQuery": "ZeroFox_CTI_compromised_credentials_CL" + }, + { + "metricName": "ZeroFox CTI Credit Cards Logs", + "legend": "ZeroFox_CTI_credit_cards_CL", + "baseQuery": "ZeroFox_CTI_credit_cards_CL" + }, + { + "metricName": "ZeroFox CTI Dark Web Logs", + "legend": "ZeroFox_CTI_dark_web_CL", + "baseQuery": "ZeroFox_CTI_dark_web_CL" + }, + { + "metricName": "ZeroFox CTI Discord Logs", + "legend": "ZeroFox_CTI_discord_CL", + "baseQuery": "ZeroFox_CTI_discord_CL" + }, + { + "metricName": "ZeroFox CTI Disruption Logs", + "legend": "ZeroFox_CTI_disruption_CL", + "baseQuery": "ZeroFox_CTI_disruption_CL" + }, + { + "metricName": "ZeroFox CTI Email Addresses Logs", + "legend": "ZeroFox_CTI_email_addresses_CL", + "baseQuery": "ZeroFox_CTI_email_addresses_CL" + }, + { + "metricName": "ZeroFox CTI Exploits Logs", + "legend": "ZeroFox_CTI_exploits_CL", + "baseQuery": "ZeroFox_CTI_exploits_CL" + }, + { + "metricName": "ZeroFox CTI Identity Breach Logs", + "legend": "ZeroFox_CTI_identity_breach_CL", + "baseQuery": "ZeroFox_CTI_identity_breach_CL" + }, + { + "metricName": "ZeroFox CTI IRC Logs", + "legend": "ZeroFox_CTI_irc_CL", + "baseQuery": "ZeroFox_CTI_irc_CL" + }, + { + "metricName": "ZeroFox CTI Malware Logs", + "legend": "ZeroFox_CTI_malware_CL", + "baseQuery": "ZeroFox_CTI_malware_CL" + }, + { + "metricName": "ZeroFox CTI National Ids Logs", + "legend": "ZeroFox_CTI_national_ids_CL", + "baseQuery": "ZeroFox_CTI_national_ids_CL" + }, + { + "metricName": "ZeroFox CTI Phishing Logs", + "legend": "ZeroFox_CTI_phishing_CL", + "baseQuery": "ZeroFox_CTI_phishing_CL" + }, + { + "metricName": "ZeroFox CTI Phone Numbers Logs", + "legend": "ZeroFox_CTI_phone_numbers_CL", + "baseQuery": "ZeroFox_CTI_phone_numbers_CL" + }, + { + "metricName": "ZeroFox CTI Ransomware Logs", + "legend": "ZeroFox_CTI_ransomware_CL", + "baseQuery": "ZeroFox_CTI_ransomware_CL" + }, + { + "metricName": "ZeroFox CTI Telegram Logs", + "legend": "ZeroFox_CTI_telegram_CL", + "baseQuery": "ZeroFox_CTI_telegram_CL" + }, + { + "metricName": "ZeroFox CTI Threat Actors Logs", + "legend": "ZeroFox_CTI_threat_actors_CL", + "baseQuery": "ZeroFox_CTI_threat_actors_CL" + }, + { + "metricName": "ZeroFox CTI Vulnerabilities Logs", + "legend": "ZeroFox_CTI_vulnerabilities_CL", + "baseQuery": "ZeroFox_CTI_vulnerabilities_CL" + } + + ], + "sampleQueries": [ + { + "description": "ZeroFox CTI C2-domains Logs", + "query": "ZeroFox_CTI_C2_CL\n | sort by TimeGenerated desc" + }, + { + "description": "ZeroFox CTI Email Addresses Logs", + "query": "ZeroFox_CTI_email_addresses_CL\n | sort by TimeGenerated desc" + }, + { + "description": "ZeroFox CTI Malware Logs", + "query": "ZeroFox_CTI_malware_CL\n | sort by TimeGenerated desc" + } + + + ], + "dataTypes": [ + { + "name": "ZeroFox_CTI_advanced_dark_web_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_advanced_dark_web_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_botnet_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_botnet_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_breaches_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_breaches_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_C2_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_C2_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_compromised_credentials_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_compromised_credentials_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_credit_cards_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_credit_cards_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_dark_web_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_dark_web_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_discord_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_discord_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_disruption_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_disruption_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_email_addresses_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_email_addresses_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_exploits_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_exploits_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_identity_breach_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_identity_breach_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_irc_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_irc_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_malware_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_malware_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_national_ids_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_national_ids_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_phishing_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_phishing_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_phone_numbers_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_phone_numbers_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_ransomware_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_ransomware_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_telegram_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_telegram_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_threat_actors_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_threat_actors_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_vulnerabilities_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_vulnerabilities_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + } + + ], + "connectivityCriterias": [ + { + "type": "IsConnectedQuery", + "value": [ + "ZeroFox_CTI_advanced_dark_web_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_botnet_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_breaches_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_C2_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_compromised_credentials_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_credit_cards_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_dark_web_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_discord_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_disruption_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_email_addresses_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_exploits_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_identity_breach_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_irc_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_malware_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_national_ids_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_phishing_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_phone_numbers_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_ransomware_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_telegram_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_threat_actors_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_vulnerabilities_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)" + ] + } + ], + "availability": { + "status": 1, + "isPreview": false + }, + "permissions": { + "resourceProvider": [ + { + "provider": "Microsoft.OperationalInsights/workspaces", + "permissionsDisplayText": "read and write permissions on the workspace are required.", + "providerDisplayName": "Workspace", + "scope": "Workspace", + "requiredPermissions": { + "write": true, + "read": true, + "delete": true + } + }, + { + "provider": "Microsoft.OperationalInsights/workspaces/sharedKeys", + "permissionsDisplayText": "read permissions to shared keys for the workspace are required. [See the documentation to learn more about workspace keys](https://docs.microsoft.com/azure/azure-monitor/platform/agent-windows#obtain-workspace-id-and-key).", + "providerDisplayName": "Keys", + "scope": "Workspace", + "requiredPermissions": { + "action": true + } + } + ], + "customs": [ + { + "name": "Microsoft.Web/sites permissions", + "description": "Read and write permissions to Azure Functions to create a Function App is required. [See the documentation to learn more about Azure Functions](https://docs.microsoft.com/azure/azure-functions/)." + }, + { + "name": "ZeroFox API Credentials/permissions", + "description": "**ZeroFox Username**, **ZeroFox Personal Access Token** are required for ZeroFox CTI REST API." + } + ] + }, + "instructionSteps": [ + { + "title": "", + "description": ">**NOTE:** This connector uses Azure Functions to connect to the ZeroFox CTI REST API to pull logs into Microsoft Sentinel. This might result in additional data ingestion costs. Check the [Azure Functions pricing page](https://azure.microsoft.com/pricing/details/functions/) for details." + }, + { + "title": "", + "description": ">**(Optional Step)** Securely store workspace and API authorization key(s) or token(s) in Azure Key Vault. Azure Key Vault provides a secure mechanism to store and retrieve key values. [Follow these instructions](https://docs.microsoft.com/azure/app-service/app-service-key-vault-references) to use Azure Key Vault with an Azure Function App." + }, + { + "title": "", + "description": "**STEP 1 - Retrieval of ZeroFox credentials:**\n\n Follow these instructions for set up logging and obtain credentials." + }, + { + "title": "", + "description": "**STEP 1.1 - [Log into ZeroFox's website.](https://cloud.zerofox.com/login) using your username and password" + }, + { + "title": "", + "description": "**STEP 1.2 - Click into the Settings button and go to the Data Connectors Section." + }, + { + "title": "", + "description": "**STEP 1.3 - Select the API DATA FEEDS tab and head to the bottom of the page, select <> in the API Information box, to obtain a Personal Access Token to be used along with your username." + }, + { + "title": "", + "description": "**STEP 2 - Choose ONE from the following two deployment options to deploy the connector and the associated Azure Function**\n\n>**IMPORTANT:** Before deploying the ZeroFox CTI data connector, have the Workspace ID and Workspace Primary Key (can be copied from the following), as well as the Amazon S3 REST API Authorization credentials, readily available.", + "instructions": [ + { + "parameters": { + "fillWith": [ + "WorkspaceId" + ], + "label": "Workspace ID" + }, + "type": "CopyableLabel" + }, + { + "parameters": { + "fillWith": [ + "PrimaryKey" + ], + "label": "Primary Key" + }, + "type": "CopyableLabel" + } + ] + }, + { + "title": "Option 1 - Azure Resource Manager (ARM) Template", + "description": "Use this method for automated deployment of the ZeroFox CTI data connectors using an ARM Tempate.\n\n1. Click the **Deploy to Azure** button below. \n\n\t[![Deploy To Azure](https://aka.ms/deploytoazurebutton)](https://aka.ms/sentinelCiscoUmbrellaazuredeploy)\n2. Select the preferred **Subscription**, **Resource Group** and **Location**. \n3. Enter the **Workspace ID**, **Workspace Key**, **ZeroFox Username**, **ZeroFox Personal Access Token**\n4. Mark the checkbox labeled **I agree to the terms and conditions stated above**.\n5. Click **Purchase** to deploy." + }, + { + "title": "Option 2 - Manual Deployment of Azure Functions", + "description": "Use the following step-by-step instructions to deploy the ZeroFox CTI data connector manually with Azure Functions (Deployment via Visual Studio Code)." + }, + { + "title": "", + "description": "**1. Deploy a Function App**\n\n> **NOTE:** You will need to [prepare VS code](https://docs.microsoft.com/azure/azure-functions/create-first-function-vs-code-python) for Azure function development.\n\n1. Download the [Azure Function App](https://aka.ms/sentinel-ZeroFoxCTIConn-functionapp) file. Extract archive to your local development computer.\n2. Start VS Code. Choose File in the main menu and select Open Folder.\n3. Select the top level folder from extracted files.\n4. Choose the Azure icon in the Activity bar, then in the **Azure: Functions** area, choose the **Deploy to function app** button.\nIf you aren't already signed in, choose the Azure icon in the Activity bar, then in the **Azure: Functions** area, choose **Sign in to Azure**\nIf you're already signed in, go to the next step.\n5. Provide the following information at the prompts:\n\n\ta. **Select folder:** Choose a folder from your workspace or browse to one that contains your function app.\n\n\tb. **Select Subscription:** Choose the subscription to use.\n\n\tc. Select **Create new Function App in Azure** (Don't choose the Advanced option)\n\n\td. **Enter a globally unique name for the function app:** Type a name that is valid in a URL path. The name you type is validated to make sure that it's unique in Azure Functions. (e.g. CTIXYZ).\n\n\te. **Select a runtime:** Choose Python 3.8.\n\n\tf. Select a location for new resources. For better performance and lower costs choose the same [region](https://azure.microsoft.com/regions/) where Microsoft Sentinel is located.\n\n6. Deployment will begin. A notification is displayed after your function app is created and the deployment package is applied.\n7. Go to Azure Portal for the Function App configuration." + }, + { + "title": "", + "description": "**2. Configure the Function App**\n\n1. In the Function App, select the Function App Name and select **Configuration**.\n2. In the **Application settings** tab, select **+ New application setting**.\n3. Add each of the following application settings individually, with their respective string values (case-sensitive): \n\t\tWorkspaceID\n\t\tWorkspaceKey\n\t\tS3Bucket\n\t\tAWSAccessKeyId\n\t\tAWSSecretAccessKey\n\t\tlogAnalyticsUri (optional)\n> - Use logAnalyticsUri to override the log analytics API endpoint for dedicated cloud. For example, for public cloud, leave the value empty; for Azure GovUS cloud environment, specify the value in the following format: `https://.ods.opinsights.azure.us`.\n3. Once all application settings have been entered, click **Save**." + } + ] +} diff --git a/Solutions/ZeroFox/Data Connectors/CTI/advanced_dark_web_connector/__init__.py b/Solutions/ZeroFox/Data Connectors/CTI/advanced_dark_web_connector/__init__.py new file mode 100644 index 00000000000..986c2342652 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/advanced_dark_web_connector/__init__.py @@ -0,0 +1,59 @@ +import datetime +import logging +import os + +import azure.functions as func + +from connections.sentinel import SentinelConnector +from connections.zerofox import ZeroFoxClient + + +def main(mytimer: func.TimerRequest) -> None: + utc_timestamp = ( + datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + + if mytimer.past_due: + logging.info("The timer is past due!") + + customer_id = os.environ.get("WorkspaceID") + shared_key = os.environ.get("WorkspaceKey") + + query_from = mytimer.schedule_status["Last"] + query_to = datetime.datetime.utcnow() - datetime.timedelta(minutes=1) + + zf_client = get_zf_client() + + results = get_cti_advanced_dark_web( + zf_client, created_after=query_from, created_before=query_to) + + logging.debug("Trigger function retrieved results") + + # The log type is the name of the event that is being submitted + log_type = "ZeroFox_CTI_advanced_dark_web" + + sentinel_client = SentinelConnector( + customer_id=customer_id, shared_key=shared_key, log_type=log_type + ) + + for result in results: + sentinel_client.send(result) + + logging.info("Python timer trigger function ran at %s", utc_timestamp) + + +def get_zf_client(): + user = os.environ.get("zf_username") + token = os.environ.get("token") + return ZeroFoxClient(user, token) + + +def get_cti_advanced_dark_web(client: ZeroFoxClient, created_before, created_after): + url_suffix = "advanced-dark-web/" + params = dict(created_after=created_after, created_before=created_before) + return client.cti_request( + "GET", + url_suffix, + params=params, + ) diff --git a/Solutions/ZeroFox/Data Connectors/CTI/advanced_dark_web_connector/function.json b/Solutions/ZeroFox/Data Connectors/CTI/advanced_dark_web_connector/function.json new file mode 100644 index 00000000000..c84ce78a5a5 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/advanced_dark_web_connector/function.json @@ -0,0 +1,11 @@ +{ + "scriptFile": "__init__.py", + "bindings": [ + { + "name": "mytimer", + "type": "timerTrigger", + "direction": "in", + "schedule": "0 0 18 * * *" + } + ] + } \ No newline at end of file diff --git a/Solutions/ZeroFox/Data Connectors/CTI/azuredeploy_ZeroFox_CTI_FunctionApp.json b/Solutions/ZeroFox/Data Connectors/CTI/azuredeploy_ZeroFox_CTI_FunctionApp.json new file mode 100644 index 00000000000..adceb17bffd --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/azuredeploy_ZeroFox_CTI_FunctionApp.json @@ -0,0 +1,197 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "FunctionName": { + "defaultValue": "ZeroFoxCTI", + "minLength": 1, + "type": "string" + }, + "ZeroFoxToken": { + "type": "securestring", + "defaultValue": "" + }, + "ZeroFoxUsername": { + "type": "string", + "defaultValue": "" + }, + "WorkspaceID": { + "type": "string", + "defaultValue": "" + }, + "WorkspaceKey": { + "type": "securestring", + "defaultValue": "" + } + }, + "variables": { + "FunctionName": "[concat(toLower(parameters('FunctionName')), uniqueString(resourceGroup().id))]", + "StorageAccountName":"[substring(tolower(variables('FunctionName')), 0, 22)]", + "StorageSuffix": "[environment().suffixes.storage]", + "LogAnaltyicsUri": "[replace(environment().portal, 'https://portal', concat('https://', toLower(parameters('WorkspaceID')), '.ods.opinsights'))]" + }, + "resources": [ + { + "type": "Microsoft.Insights/components", + "apiVersion": "2015-05-01", + "name": "[variables('FunctionName')]", + "location": "[resourceGroup().location]", + "kind": "web", + "properties": { + "Application_Type": "web", + "ApplicationId": "[variables('FunctionName')]" + } + }, + { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2019-06-01", + "name": "[variables('StorageAccountName')]", + "location": "[resourceGroup().location]", + "sku": { + "name": "Standard_LRS", + "tier": "Standard" + }, + "kind": "StorageV2", + "properties": { + "networkAcls": { + "bypass": "AzureServices", + "virtualNetworkRules": [], + "ipRules": [], + "defaultAction": "Allow" + }, + "supportsHttpsTrafficOnly": true, + "encryption": { + "services": { + "file": { + "keyType": "Account", + "enabled": true + }, + "blob": { + "keyType": "Account", + "enabled": true + } + }, + "keySource": "Microsoft.Storage" + } + } + }, + { + "type": "Microsoft.Storage/storageAccounts/blobServices", + "apiVersion": "2019-06-01", + "name": "[concat(variables('StorageAccountName'), '/default')]", + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts', variables('StorageAccountName'))]" + ], + "sku": { + "name": "Standard_LRS", + "tier": "Standard" + }, + "properties": { + "cors": { + "corsRules": [] + }, + "deleteRetentionPolicy": { + "enabled": false + } + } + }, + { + "type": "Microsoft.Storage/storageAccounts/fileServices", + "apiVersion": "2019-06-01", + "name": "[concat(variables('StorageAccountName'), '/default')]", + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts', variables('StorageAccountName'))]" + ], + "sku": { + "name": "Standard_LRS", + "tier": "Standard" + }, + "properties": { + "cors": { + "corsRules": [] + } + } + }, + { + "type": "Microsoft.Web/sites", + "apiVersion": "2018-11-01", + "name": "[variables('FunctionName')]", + "location": "[resourceGroup().location]", + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts', variables('StorageAccountName'))]", + "[resourceId('Microsoft.Insights/components', variables('FunctionName'))]" + ], + "kind": "functionapp,linux", + "identity": { + "type": "SystemAssigned" + }, + "properties": { + "name": "[variables('FunctionName')]", + "httpsOnly": true, + "clientAffinityEnabled": true, + "alwaysOn": true, + "reserved": true, + "siteConfig": { + "linuxFxVersion": "python|3.8" + } + }, + "resources": [ + { + "apiVersion": "2018-11-01", + "type": "config", + "name": "appsettings", + "dependsOn": [ + "[concat('Microsoft.Web/sites/', variables('FunctionName'))]" + ], + "properties": { + "FUNCTIONS_EXTENSION_VERSION": "~4", + "FUNCTIONS_WORKER_RUNTIME": "python", + "APPINSIGHTS_INSTRUMENTATIONKEY": "[reference(resourceId('Microsoft.insights/components', variables('FunctionName')), '2015-05-01').InstrumentationKey]", + "APPLICATIONINSIGHTS_CONNECTION_STRING": "[reference(resourceId('microsoft.insights/components', variables('FunctionName')), '2015-05-01').ConnectionString]", + "AzureWebJobsStorage": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('StorageAccountName'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('StorageAccountName')), '2019-06-01').keys[0].value, ';EndpointSuffix=',toLower(variables('StorageSuffix')))]", + "logAnalyticsUri": "[variables('LogAnaltyicsUri')]", + "WorkspaceID": "[parameters('WorkspaceID')]", + "WorkspaceKey": "[parameters('WorkspaceKey')]", + "WEBSITE_RUN_FROM_PACKAGE": "https://aka.ms/sentinel-ZeroFoxCTI-functionapp" + } + } + ] + }, + { + "type": "Microsoft.Storage/storageAccounts/blobServices/containers", + "apiVersion": "2019-06-01", + "name": "[concat(variables('StorageAccountName'), '/default/azure-webjobs-hosts')]", + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts/blobServices', variables('StorageAccountName'), 'default')]", + "[resourceId('Microsoft.Storage/storageAccounts', variables('StorageAccountName'))]" + ], + "properties": { + "publicAccess": "None" + } + }, + { + "type": "Microsoft.Storage/storageAccounts/blobServices/containers", + "apiVersion": "2019-06-01", + "name": "[concat(variables('StorageAccountName'), '/default/azure-webjobs-secrets')]", + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts/blobServices', variables('StorageAccountName'), 'default')]", + "[resourceId('Microsoft.Storage/storageAccounts', variables('StorageAccountName'))]" + ], + "properties": { + "publicAccess": "None" + } + }, + { + "type": "Microsoft.Storage/storageAccounts/fileServices/shares", + "apiVersion": "2019-06-01", + "name": "[concat(variables('StorageAccountName'), '/default/', variables('StorageAccountName'))]", + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts/fileServices', variables('StorageAccountName'), 'default')]", + "[resourceId('Microsoft.Storage/storageAccounts', variables('StorageAccountName'))]" + ], + "properties": { + "shareQuota": 5120 + } + } + ] +} \ No newline at end of file diff --git a/Solutions/ZeroFox/Data Connectors/CTI/botnet_compromised_credentials_connector/__init__.py b/Solutions/ZeroFox/Data Connectors/CTI/botnet_compromised_credentials_connector/__init__.py new file mode 100644 index 00000000000..0e95735d9ca --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/botnet_compromised_credentials_connector/__init__.py @@ -0,0 +1,63 @@ +import datetime +import logging +import os + +import azure.functions as func + +from connections.sentinel import SentinelConnector +from connections.zerofox import ZeroFoxClient + + +def main(mytimer: func.TimerRequest) -> None: + utc_timestamp = ( + datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + + if mytimer.past_due: + logging.info("The timer is past due!") + + # Update the customer ID to your Log Analytics workspace ID + customer_id = os.environ.get("WorkspaceID") + + # For the shared key, use either the primary or the secondary Connected Sources client authentication key + shared_key = os.environ.get("WorkspaceKey") + + query_from = mytimer.schedule_status["Last"] + query_to = datetime.datetime.utcnow() - datetime.timedelta(minutes=1) + + zf_client = get_zf_client() + + results = get_cti_botnet_compromised_credentials( + zf_client, created_after=query_from, created_before=query_to) + + logging.debug("Trigger function retrieved results") + + # The log type is the name of the event that is being submitted + log_type = "ZeroFox_CTI_botnet_compromised_credentials" + + sentinel_client = SentinelConnector( + customer_id=customer_id, shared_key=shared_key, log_type=log_type + ) + + for result in results: + sentinel_client.send(result) + + logging.info("Python timer trigger function ran at %s", utc_timestamp) + + +def get_zf_client(): + user = os.environ.get("zf_username") + token = os.environ.get("token") + return ZeroFoxClient(user, token) + + +def get_cti_botnet_compromised_credentials(client: ZeroFoxClient, + created_before, created_after): + url_suffix = "botnet-compromised-credentials/" + params = dict(created_after=created_after, created_before=created_before) + return client.cti_request( + "GET", + url_suffix, + params=params, + ) diff --git a/Solutions/ZeroFox/Data Connectors/CTI/botnet_compromised_credentials_connector/function.json b/Solutions/ZeroFox/Data Connectors/CTI/botnet_compromised_credentials_connector/function.json new file mode 100644 index 00000000000..c84ce78a5a5 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/botnet_compromised_credentials_connector/function.json @@ -0,0 +1,11 @@ +{ + "scriptFile": "__init__.py", + "bindings": [ + { + "name": "mytimer", + "type": "timerTrigger", + "direction": "in", + "schedule": "0 0 18 * * *" + } + ] + } \ No newline at end of file diff --git a/Solutions/ZeroFox/Data Connectors/CTI/botnet_connector/__init__.py b/Solutions/ZeroFox/Data Connectors/CTI/botnet_connector/__init__.py new file mode 100644 index 00000000000..c16d87bd4be --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/botnet_connector/__init__.py @@ -0,0 +1,64 @@ +import datetime +import logging +import os + +import azure.functions as func + +from connections.sentinel import SentinelConnector +from connections.zerofox import ZeroFoxClient + + +def main(mytimer: func.TimerRequest) -> None: + utc_timestamp = ( + datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + ) + + if mytimer.past_due: + logging.info("The timer is past due!") + + # Update the customer ID to your Log Analytics workspace ID + customer_id = os.environ.get("WorkspaceID") + + # For the shared key, use either the primary or the secondary Connected Sources client authentication key + shared_key = os.environ.get("WorkspaceKey") + + query_from = mytimer.schedule_status["Last"] + query_to = datetime.datetime.utcnow() - datetime.timedelta(minutes=1) + + zf_client = get_zf_client() + + results = get_cti_botnet(zf_client, listed_after=query_from, listed_before=query_to) + + logging.debug("Trigger function retrieved results") + + # The log type is the name of the event that is being submitted + log_type = "ZeroFox_CTI_botnet" + + sentinel_client = SentinelConnector( + customer_id=customer_id, shared_key=shared_key, log_type=log_type + ) + + for result in results: + sentinel_client.send(result) + + logging.info(f"Python timer trigger function ran at {utc_timestamp}") + + +def get_zf_client(): + user = os.environ.get("zf_username") + token = os.environ.get("token") + return ZeroFoxClient(user, token) + + +def get_cti_botnet(client: ZeroFoxClient, listed_after: str, listed_before: str): + """ + :param domain: The domain to lookup in botnet CTI Feed + :return: HTTP request content. + """ + url_suffix = "botnet/" + params = dict(listed_after=listed_after, listed_before=listed_before) + return client.cti_request( + "GET", + url_suffix, + params=params, + ) diff --git a/Solutions/ZeroFox/Data Connectors/CTI/botnet_connector/function.json b/Solutions/ZeroFox/Data Connectors/CTI/botnet_connector/function.json new file mode 100644 index 00000000000..0fb7c296f13 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/botnet_connector/function.json @@ -0,0 +1,11 @@ +{ + "scriptFile": "__init__.py", + "bindings": [ + { + "name": "mytimer", + "type": "timerTrigger", + "direction": "in", + "schedule": "0 0 18 * * *" + } + ] +} \ No newline at end of file diff --git a/Solutions/ZeroFox/Data Connectors/CTI/breaches_connector/__init__.py b/Solutions/ZeroFox/Data Connectors/CTI/breaches_connector/__init__.py new file mode 100644 index 00000000000..4194007489a --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/breaches_connector/__init__.py @@ -0,0 +1,62 @@ +import datetime +import logging +import os + +import azure.functions as func + +from connections.sentinel import SentinelConnector +from connections.zerofox import ZeroFoxClient + + +def main(mytimer: func.TimerRequest) -> None: + utc_timestamp = ( + datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + ) + + if mytimer.past_due: + logging.info("The timer is past due!") + + # Update the customer ID to your Log Analytics workspace ID + customer_id = os.environ.get("WorkspaceID") + + # For the shared key, use either the primary or the secondary Connected Sources client authentication key + shared_key = os.environ.get("WorkspaceKey") + + + query_from = mytimer.schedule_status["Last"] + query_to = datetime.datetime.utcnow() - datetime.timedelta(minutes=1) + + zf_client = get_zf_client() + + results = get_cti_breaches(zf_client, created_at_after= query_from, created_at_before= query_to) + + logging.debug("Trigger function retrieved results") + + # The log type is the name of the event that is being submitted + log_type = "ZeroFox_CTI_breaches" + + sentinel_client = SentinelConnector( + customer_id=customer_id, shared_key=shared_key, log_type=log_type + ) + + for result in results: + sentinel_client.send(result) + + logging.info(f"Python timer trigger function ran at {utc_timestamp}") + + +def get_zf_client(): + user = os.environ.get("zf_username") + token = os.environ.get("token") + return ZeroFoxClient(user, token) + + +def get_cti_breaches(client: ZeroFoxClient, created_at_after: str, created_at_before: str): + url_suffix = "breaches/" + params = dict(created_at_after=created_at_after, created_at_before=created_at_before) + return client.cti_request( + "GET", + url_suffix, + params=params, + ) + diff --git a/Solutions/ZeroFox/Data Connectors/CTI/breaches_connector/function.json b/Solutions/ZeroFox/Data Connectors/CTI/breaches_connector/function.json new file mode 100644 index 00000000000..0fb7c296f13 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/breaches_connector/function.json @@ -0,0 +1,11 @@ +{ + "scriptFile": "__init__.py", + "bindings": [ + { + "name": "mytimer", + "type": "timerTrigger", + "direction": "in", + "schedule": "0 0 18 * * *" + } + ] +} \ No newline at end of file diff --git a/Solutions/ZeroFox/Data Connectors/CTI/c2_domains_connector/__init__.py b/Solutions/ZeroFox/Data Connectors/CTI/c2_domains_connector/__init__.py new file mode 100644 index 00000000000..4f24723ffa9 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/c2_domains_connector/__init__.py @@ -0,0 +1,61 @@ +import datetime +import logging +import os + +import azure.functions as func + +from connections.sentinel import SentinelConnector +from connections.zerofox import ZeroFoxClient + + +def main(mytimer: func.TimerRequest) -> None: + utc_timestamp = ( + datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + ) + + if mytimer.past_due: + logging.info("The timer is past due!") + + # Update the customer ID to your Log Analytics workspace ID + customer_id = os.environ.get("WorkspaceID") + + # For the shared key, use either the primary or the secondary Connected Sources client authentication key + shared_key = os.environ.get("WorkspaceKey") + + query_from = mytimer.schedule_status["Last"] + query_to = datetime.datetime.utcnow() - datetime.timedelta(minutes=1) + + zf_client = get_zf_client() + + results = get_cti_c2_domains(zf_client, created_after= query_from, created_before= query_to) + + logging.info("Trigger function retrieved results") + + # The log type is the name of the event that is being submitted + log_type = "ZeroFox_CTI_C2" + + sentinel_client = SentinelConnector( + customer_id=customer_id, shared_key=shared_key, log_type=log_type + ) + + for result in results: + sentinel_client.send(result) + + logging.info(f"Python timer trigger function ran at {utc_timestamp}") + + +def get_zf_client(): + user = os.environ.get("zf_username") + token = os.environ.get("token") + return ZeroFoxClient(user, token) + + +def get_cti_c2_domains(client: ZeroFoxClient, created_after: str, created_before: str): + url_suffix = "c2-domains/" + params = dict(created_after=created_after, created_before=created_before) + return client.cti_request( + "GET", + url_suffix, + params=params, + ) + diff --git a/Solutions/ZeroFox/Data Connectors/CTI/c2_domains_connector/function.json b/Solutions/ZeroFox/Data Connectors/CTI/c2_domains_connector/function.json new file mode 100644 index 00000000000..0fb7c296f13 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/c2_domains_connector/function.json @@ -0,0 +1,11 @@ +{ + "scriptFile": "__init__.py", + "bindings": [ + { + "name": "mytimer", + "type": "timerTrigger", + "direction": "in", + "schedule": "0 0 18 * * *" + } + ] +} \ No newline at end of file diff --git a/Solutions/ZeroFox/Data Connectors/CTI/compromised_credentials_connector/__init__.py b/Solutions/ZeroFox/Data Connectors/CTI/compromised_credentials_connector/__init__.py new file mode 100644 index 00000000000..c5beb7cf3e2 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/compromised_credentials_connector/__init__.py @@ -0,0 +1,64 @@ +import datetime +import logging +import os + +import azure.functions as func + +from connections.sentinel import SentinelConnector +from connections.zerofox import ZeroFoxClient + + +def main(mytimer: func.TimerRequest) -> None: + utc_timestamp = ( + datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + ) + + if mytimer.past_due: + logging.info("The timer is past due!") + + # Update the customer ID to your Log Analytics workspace ID + customer_id = os.environ.get("WorkspaceID") + + # For the shared key, use either the primary or the secondary Connected Sources client authentication key + shared_key = os.environ.get("WorkspaceKey") + + query_from = mytimer.schedule_status["Last"] + query_to = datetime.datetime.utcnow() - datetime.timedelta(minutes=1) + + zf_client = get_zf_client() + + results = get_cti_compromised_credentials( + zf_client, created_after=query_from, created_before=query_to + ) + + logging.debug("Trigger function retrieved results") + + # The log type is the name of the event that is being submitted + log_type = "ZeroFox_CTI_compromised_credentials" + + sentinel_client = SentinelConnector( + customer_id=customer_id, shared_key=shared_key, log_type=log_type + ) + + for result in results: + sentinel_client.send(result) + + logging.info(f"Python timer trigger function ran at {utc_timestamp}") + + +def get_zf_client(): + user = os.environ.get("zf_username") + token = os.environ.get("token") + return ZeroFoxClient(user, token) + + +def get_cti_compromised_credentials( + client: ZeroFoxClient, created_after: str, created_before: str +): + url_suffix = "compromised-credentials/" + params = dict(created_after=created_after, created_before=created_before) + return client.cti_request( + "GET", + url_suffix, + params=params, + ) diff --git a/Solutions/ZeroFox/Data Connectors/CTI/compromised_credentials_connector/function.json b/Solutions/ZeroFox/Data Connectors/CTI/compromised_credentials_connector/function.json new file mode 100644 index 00000000000..0fb7c296f13 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/compromised_credentials_connector/function.json @@ -0,0 +1,11 @@ +{ + "scriptFile": "__init__.py", + "bindings": [ + { + "name": "mytimer", + "type": "timerTrigger", + "direction": "in", + "schedule": "0 0 18 * * *" + } + ] +} \ No newline at end of file diff --git a/Solutions/ZeroFox/Data Connectors/CTI/connections/__init__.py b/Solutions/ZeroFox/Data Connectors/CTI/connections/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/Solutions/ZeroFox/Data Connectors/CTI/connections/sentinel.py b/Solutions/ZeroFox/Data Connectors/CTI/connections/sentinel.py new file mode 100644 index 00000000000..4c4fa26e97a --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/connections/sentinel.py @@ -0,0 +1,162 @@ +import base64 +import datetime +import hashlib +import hmac +import json +import logging +from threading import Thread +import requests + + +class SentinelConnector: + def __init__( + self, + customer_id, + shared_key, + log_type, + queue_size=200, + bulks_number=10, + queue_size_bytes=25 * (2**20), + ): + self.log_analytics_uri = f"https://{customer_id}.ods.opinsights.azure.com" + self.customer_id = customer_id + self.shared_key = shared_key + self.log_type = log_type + self.queue_size = queue_size + self.bulks_number = bulks_number + self.queue_size_bytes = queue_size_bytes + self._queue = [] + self._bulks_list = [] + self.successfull_sent_events_number = 0 + self.failed_sent_events_number = 0 + + def send(self, event): + self._queue.append(event) + if len(self._queue) >= self.queue_size: + self.flush(force=False) + + def flush(self, force=True): + self._bulks_list.append(self._queue) + if force: + self._flush_bulks() + else: + if len(self._bulks_list) >= self.bulks_number: + self._flush_bulks() + + self._queue = [] + + def _flush_bulks(self): + jobs = [] + for queue in self._bulks_list: + if queue: + queue_list = self._split_big_request(queue) + for q in queue_list: + jobs.append( + Thread( + target=self._post_data, + args=( + self.customer_id, + self.shared_key, + q, + self.log_type, + ), + ) + ) + + for job in jobs: + job.start() + + for job in jobs: + job.join() + + self._bulks_list = [] + + def __enter__(self): + pass + + def __exit__(self, type, value, traceback): + self.flush() + + def _build_signature( + self, + customer_id, + shared_key, + date, + content_length, + method, + content_type, + resource, + ): + x_headers = "x-ms-date:" + date + string_to_hash = ( + method + + "\n" + + str(content_length) + + "\n" + + content_type + + "\n" + + x_headers + + "\n" + + resource + ) + bytes_to_hash = bytes(string_to_hash, encoding="utf-8") + decoded_key = base64.b64decode(shared_key) + encoded_hash = base64.b64encode( + hmac.new(decoded_key, bytes_to_hash, digestmod=hashlib.sha256).digest() + ).decode() + authorization = "SharedKey {}:{}".format(customer_id, encoded_hash) + return authorization + + def _post_data(self, customer_id, shared_key, body, log_type): + events_number = len(body) + body = json.dumps(body) + method = "POST" + content_type = "application/json" + resource = "/api/logs" + rfc1123date = datetime.datetime.utcnow().strftime("%a, %d %b %Y %H:%M:%S GMT") + content_length = len(body) + signature = self._build_signature( + customer_id, + shared_key, + rfc1123date, + content_length, + method, + content_type, + resource, + ) + uri = self.log_analytics_uri + resource + "?api-version=2016-04-01" + + headers = { + "content-type": content_type, + "Authorization": signature, + "Log-Type": log_type, + "x-ms-date": rfc1123date, + } + + response = requests.post(uri, data=body, headers=headers) + if response.status_code >= 200 and response.status_code <= 299: + logging.info( + "{} events have been successfully sent to Microsoft Sentinel".format( + events_number + ) + ) + self.successfull_sent_events_number += events_number + else: + logging.error( + f"Error during sending events to Microsoft Sentinel. Response code: {response.status_code}, with message: {response.text}" + ) + self.failed_sent_events_number += events_number + + def _check_size(self, queue): + data_bytes_len = len(json.dumps(queue).encode()) + return data_bytes_len < self.queue_size_bytes + + def _split_big_request(self, queue): + if self._check_size(queue): + return [queue] + else: + middle = int(len(queue) / 2) + queues_list = [queue[:middle], queue[middle:]] + return self._split_big_request(queues_list[0]) + self._split_big_request( + queues_list[1] + ) diff --git a/Solutions/ZeroFox/Data Connectors/CTI/connections/zerofox.py b/Solutions/ZeroFox/Data Connectors/CTI/connections/zerofox.py new file mode 100644 index 00000000000..fa2a25a6092 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/connections/zerofox.py @@ -0,0 +1,194 @@ +from typing import Dict +import requests +import json + + +class ZeroFoxClient: + def __init__(self, user, token) -> None: + self.credentials = {"username": user, "password": token} + self._base_url = "https://api.zerofox.com" + + def cti_request( + self, + method: str, + url_suffix: str, + params=None, + data=None, + error_handler=None, + ): + """ + :param method: HTTP request type + :param url_suffix: The suffix of the URL + :param params: The request's query parameters + :param data: The request's body parameters + :param version: api prefix to consider, default is to use version '1.0' + :param res_type: Selects the decoder of the response. It can be + `json` (default), `xml`, `text`, `content`, `response` + :param empty_response: Indicates if the response data is empty or not + :param error_handler: Function that receives the response and manage + the error + :return: Returns the content of the response received from the API. + """ + headers = self._get_cti_request_header() + + response = self._http_request( + method=method, + url_suffix=f"/cti/{url_suffix}", + headers=headers, + params=params, + data=data, + empty_valid_codes=(200, 201), + error_handler=error_handler, + ) + + for result in response["results"]: + yield result + while response["next"]: + response = self._http_request( + method="GET", + headers=headers, + full_address=response["next"], + ) + for result in response["results"]: + yield result + + def _client_error_handler(self, res: requests.Response): + err_msg = f"Error in API call [{res.status_code}] - {res.reason}" + try: + # Try to parse json error response + error_entry = res.json() + err_msg += f"\n{json.dumps(error_entry)}" + raise Exception(err_msg) + except ValueError: + err_msg += f"\n{res.text}" + raise Exception(err_msg) + + def _http_request( + self, + method, + url_suffix="", + full_address=None, + headers=None, + auth=None, + json_data=None, + params=None, + data=None, + files=None, + timeout=None, + ok_codes=None, + return_empty_response=False, + retries=0, + error_handler=None, + empty_valid_codes=None, + **kwargs, + ): + try: + # Replace params if supplied + address = full_address if full_address else f"{self._base_url}{url_suffix}" + if not timeout: + timeout = 10 + + # Execute + res = requests.request( + method, + address, + params=params, + data=data, + json=json_data, + files=files, + headers=headers, + auth=auth, + timeout=timeout, + **kwargs, + ) + # Handle error responses gracefully + if not self._is_status_code_valid(res, ok_codes): + if error_handler: + error_handler(res) + else: + self._client_error_handler(res) + + if not empty_valid_codes: + empty_valid_codes = [204] + is_response_empty_and_successful = res.status_code in empty_valid_codes + if is_response_empty_and_successful and return_empty_response: + return res + + try: + return res.json() + except ValueError as exception: + raise Exception( + f"Failed to parse object from response: {res.content}", + exception, + res, + ) + except requests.exceptions.ConnectTimeout as exception: + err_msg = ( + "Connection Timeout Error - potential reasons might be that the Server URL parameter" + " is incorrect or that the Server is not accessible from your host." + ) + raise Exception(err_msg, exception) + except requests.exceptions.SSLError as exception: + # in case the "Trust any certificate" is already checked + err_msg = ( + "SSL Certificate Verification Failed - try selecting 'Trust any certificate' checkbox in" + " the integration configuration." + ) + raise Exception(err_msg, exception) + except requests.exceptions.ProxyError as exception: + err_msg = ( + "Proxy Error - if the 'Use system proxy' checkbox in the integration configuration is" + " selected, try clearing the checkbox." + ) + raise Exception(err_msg, exception) + except requests.exceptions.ConnectionError as exception: + # Get originating Exception in Exception chain + error_class = str(exception.__class__) + err_type = f"""<{error_class[error_class.find("'") + 1 : error_class.rfind("'")]}>""" + err_msg = ( + "Verify that the server URL parameter" + " is correct and that you have access to the server from your host." + f"\nError Type: {err_type}\n" + "Error Number: [{exception.errno}]\n" + "Message: {exception.strerror}\n" + ) + raise Exception(err_msg, exception) + except requests.exceptions.RetryError as exception: + try: + reason = f"Reason: {exception.args[0].reason.args[0]}" + except Exception: # noqa: disable=broad-except + reason = "" + err_msg = f"Max Retries Error- Request attempts with {retries} retries failed. \n{reason}" + raise Exception(err_msg, exception) + + def _is_status_code_valid(self, response: requests.Response, codes): + return codes is None or response.status_code in codes + + def _get_new_access_token(self): + url_suffix: str = "/auth/token/" + try: + response_content: Dict = self._http_request( + method="POST", + url_suffix=url_suffix, + data=self.credentials, + ) + return response_content.get("access", "") + except Exception as e: + raise e + + def get_cti_authorization_token(self) -> str: + """ + :return: returns the authorization token for the CTI feed + """ + token = self._get_new_access_token() + if not token: + raise Exception("Unable to retrieve token.") + return token + + def _get_cti_request_header(self): + token: str = self.get_cti_authorization_token() + return { + "Authorization": f"Bearer {token}", + "Content-Type": "application/json", + "Accept": "application/json", + } diff --git a/Solutions/ZeroFox/Data Connectors/CTI/credit_cards_connector/__init__.py b/Solutions/ZeroFox/Data Connectors/CTI/credit_cards_connector/__init__.py new file mode 100644 index 00000000000..7967877600c --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/credit_cards_connector/__init__.py @@ -0,0 +1,65 @@ +import datetime +import logging +import os + +import azure.functions as func + +from connections.sentinel import SentinelConnector +from connections.zerofox import ZeroFoxClient + + +def main(mytimer: func.TimerRequest) -> None: + utc_timestamp = ( + datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + + if mytimer.past_due: + logging.info("The timer is past due!") + + # Update the customer ID to your Log Analytics workspace ID + customer_id = os.environ.get("WorkspaceID") + + # For the shared key, use either the primary or the secondary Connected Sources client authentication key + shared_key = os.environ.get("WorkspaceKey") + + query_from = mytimer.schedule_status["Last"] + query_to = datetime.datetime.utcnow() - datetime.timedelta(minutes=1) + + zf_client = get_zf_client() + + results = get_cti_credit_cards( + zf_client, created_after=query_from, created_before=query_to + ) + + logging.debug("Trigger function retrieved results") + + # The log type is the name of the event that is being submitted + log_type = "ZeroFox_CTI_credit_cards" + + sentinel_client = SentinelConnector( + customer_id=customer_id, shared_key=shared_key, log_type=log_type + ) + + for result in results: + sentinel_client.send(result) + + logging.info(f"Python timer trigger function ran at {utc_timestamp}") + + +def get_zf_client(): + user = os.environ.get("zf_username") + token = os.environ.get("token") + return ZeroFoxClient(user, token) + + +def get_cti_credit_cards( + client: ZeroFoxClient, created_after: str, created_before: str +): + url_suffix = "credit-cards/" + params = dict(created_after=created_after, created_before=created_before) + return client.cti_request( + "GET", + url_suffix, + params=params, + ) diff --git a/Solutions/ZeroFox/Data Connectors/CTI/credit_cards_connector/function.json b/Solutions/ZeroFox/Data Connectors/CTI/credit_cards_connector/function.json new file mode 100644 index 00000000000..0fb7c296f13 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/credit_cards_connector/function.json @@ -0,0 +1,11 @@ +{ + "scriptFile": "__init__.py", + "bindings": [ + { + "name": "mytimer", + "type": "timerTrigger", + "direction": "in", + "schedule": "0 0 18 * * *" + } + ] +} \ No newline at end of file diff --git a/Solutions/ZeroFox/Data Connectors/CTI/dark_web_connector/__init__.py b/Solutions/ZeroFox/Data Connectors/CTI/dark_web_connector/__init__.py new file mode 100644 index 00000000000..7d6e0f0af54 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/dark_web_connector/__init__.py @@ -0,0 +1,62 @@ +import datetime +import logging +import os + +import azure.functions as func + +from connections.sentinel import SentinelConnector +from connections.zerofox import ZeroFoxClient + + +def main(mytimer: func.TimerRequest) -> None: + utc_timestamp = ( + datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + ) + + if mytimer.past_due: + logging.info("The timer is past due!") + + # Update the customer ID to your Log Analytics workspace ID + customer_id = os.environ.get("WorkspaceID") + + # For the shared key, use either the primary or the secondary Connected Sources client authentication key + shared_key = os.environ.get("WorkspaceKey") + + query_from = mytimer.schedule_status["Last"] + query_to = datetime.datetime.utcnow() - datetime.timedelta(minutes=1) + + zf_client = get_zf_client() + + results = get_cti_dark_web( + zf_client, created_after=query_from, created_before=query_to + ) + + logging.debug("Trigger function retrieved results") + + # The log type is the name of the event that is being submitted + log_type = "ZeroFox_CTI_dark_web" + + sentinel_client = SentinelConnector( + customer_id=customer_id, shared_key=shared_key, log_type=log_type + ) + + for result in results: + sentinel_client.send(result) + + logging.info(f"Python timer trigger function ran at {utc_timestamp}") + + +def get_zf_client(): + user = os.environ.get("zf_username") + token = os.environ.get("token") + return ZeroFoxClient(user, token) + + +def get_cti_dark_web(client: ZeroFoxClient, created_after: str, created_before: str): + url_suffix = "dark-web/" + params = dict(created_after=created_after, created_before=created_before) + return client.cti_request( + "GET", + url_suffix, + params=params, + ) diff --git a/Solutions/ZeroFox/Data Connectors/CTI/dark_web_connector/function.json b/Solutions/ZeroFox/Data Connectors/CTI/dark_web_connector/function.json new file mode 100644 index 00000000000..0fb7c296f13 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/dark_web_connector/function.json @@ -0,0 +1,11 @@ +{ + "scriptFile": "__init__.py", + "bindings": [ + { + "name": "mytimer", + "type": "timerTrigger", + "direction": "in", + "schedule": "0 0 18 * * *" + } + ] +} \ No newline at end of file diff --git a/Solutions/ZeroFox/Data Connectors/CTI/discord_connector/__init__.py b/Solutions/ZeroFox/Data Connectors/CTI/discord_connector/__init__.py new file mode 100644 index 00000000000..eb66c2b7d4d --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/discord_connector/__init__.py @@ -0,0 +1,62 @@ +import datetime +import logging +import os + +import azure.functions as func + +from connections.sentinel import SentinelConnector +from connections.zerofox import ZeroFoxClient + + +def main(mytimer: func.TimerRequest) -> None: + utc_timestamp = ( + datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + ) + + if mytimer.past_due: + logging.info("The timer is past due!") + + # Update the customer ID to your Log Analytics workspace ID + customer_id = os.environ.get("WorkspaceID") + + # For the shared key, use either the primary or the secondary Connected Sources client authentication key + shared_key = os.environ.get("WorkspaceKey") + + query_from = mytimer.schedule_status["Last"] + query_to = datetime.datetime.utcnow() - datetime.timedelta(minutes=1) + + zf_client = get_zf_client() + + results = get_cti_discord( + zf_client, timestamp_after=query_from, timestamp_before=query_to + ) + + logging.debug("Trigger function retrieved results") + + # The log type is the name of the event that is being submitted + log_type = "ZeroFox_CTI_discord" + + sentinel_client = SentinelConnector( + customer_id=customer_id, shared_key=shared_key, log_type=log_type + ) + + for result in results: + sentinel_client.send(result) + + logging.info(f"Python timer trigger function ran at {utc_timestamp}") + + +def get_zf_client(): + user = os.environ.get("zf_username") + token = os.environ.get("token") + return ZeroFoxClient(user, token) + + +def get_cti_discord(client: ZeroFoxClient, timestamp_after: str, timestamp_before: str): + url_suffix = "discord/" + params = dict(timestamp_after=timestamp_after, timestamp_before=timestamp_before) + return client.cti_request( + "GET", + url_suffix, + params=params, + ) diff --git a/Solutions/ZeroFox/Data Connectors/CTI/discord_connector/function.json b/Solutions/ZeroFox/Data Connectors/CTI/discord_connector/function.json new file mode 100644 index 00000000000..0fb7c296f13 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/discord_connector/function.json @@ -0,0 +1,11 @@ +{ + "scriptFile": "__init__.py", + "bindings": [ + { + "name": "mytimer", + "type": "timerTrigger", + "direction": "in", + "schedule": "0 0 18 * * *" + } + ] +} \ No newline at end of file diff --git a/Solutions/ZeroFox/Data Connectors/CTI/disruption_connector/__init__.py b/Solutions/ZeroFox/Data Connectors/CTI/disruption_connector/__init__.py new file mode 100644 index 00000000000..1f77c9cfba2 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/disruption_connector/__init__.py @@ -0,0 +1,62 @@ +import datetime +import logging +import os + +import azure.functions as func + +from connections.sentinel import SentinelConnector +from connections.zerofox import ZeroFoxClient + + +def main(mytimer: func.TimerRequest) -> None: + utc_timestamp = ( + datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + ) + + if mytimer.past_due: + logging.info("The timer is past due!") + + # Update the customer ID to your Log Analytics workspace ID + customer_id = os.environ.get("WorkspaceID") + + # For the shared key, use either the primary or the secondary Connected Sources client authentication key + shared_key = os.environ.get("WorkspaceKey") + + query_from = mytimer.schedule_status["Last"] + query_to = datetime.datetime.utcnow() - datetime.timedelta(minutes=1) + + zf_client = get_zf_client() + + results = get_cti_disruption( + zf_client, created_after=query_from, created_before=query_to + ) + + logging.debug("Trigger function retrieved results") + + # The log type is the name of the event that is being submitted + log_type = "ZeroFox_CTI_disruption" + + sentinel_client = SentinelConnector( + customer_id=customer_id, shared_key=shared_key, log_type=log_type + ) + + for result in results: + sentinel_client.send(result) + + logging.info(f"Python timer trigger function ran at {utc_timestamp}") + + +def get_zf_client(): + user = os.environ.get("zf_username") + token = os.environ.get("token") + return ZeroFoxClient(user, token) + + +def get_cti_disruption(client: ZeroFoxClient, created_after: str, created_before: str): + url_suffix = "disruption/" + params = dict(created_after=created_after, created_before=created_before) + return client.cti_request( + "GET", + url_suffix, + params=params, + ) diff --git a/Solutions/ZeroFox/Data Connectors/CTI/disruption_connector/function.json b/Solutions/ZeroFox/Data Connectors/CTI/disruption_connector/function.json new file mode 100644 index 00000000000..0fb7c296f13 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/disruption_connector/function.json @@ -0,0 +1,11 @@ +{ + "scriptFile": "__init__.py", + "bindings": [ + { + "name": "mytimer", + "type": "timerTrigger", + "direction": "in", + "schedule": "0 0 18 * * *" + } + ] +} \ No newline at end of file diff --git a/Solutions/ZeroFox/Data Connectors/CTI/email_addresses_connector/__init__.py b/Solutions/ZeroFox/Data Connectors/CTI/email_addresses_connector/__init__.py new file mode 100644 index 00000000000..d98a716f333 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/email_addresses_connector/__init__.py @@ -0,0 +1,61 @@ +import datetime +import logging +import os + +import azure.functions as func + +from connections.sentinel import SentinelConnector +from connections.zerofox import ZeroFoxClient + + +def main(mytimer: func.TimerRequest) -> None: + utc_timestamp = ( + datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + ) + + if mytimer.past_due: + logging.info("The timer is past due!") + + # Update the customer ID to your Log Analytics workspace ID + customer_id = os.environ.get("WorkspaceID") + + # For the shared key, use either the primary or the secondary Connected Sources client authentication key + shared_key = os.environ.get("WorkspaceKey") + + query_from = mytimer.schedule_status["Last"] + query_to = datetime.datetime.utcnow() - datetime.timedelta(minutes=1) + + zf_client = get_zf_client() + + results = get_cti_email_addresses(zf_client, created_after=query_from, created_before=query_to) + + logging.debug("Trigger function retrieved results") + + # The log type is the name of the event that is being submitted + log_type = "ZeroFox_CTI_email_addresses" + + sentinel_client = SentinelConnector( + customer_id=customer_id, shared_key=shared_key, log_type=log_type + ) + + for result in results: + sentinel_client.send(result) + + logging.info("Python timer trigger function ran at %s", utc_timestamp) + + +def get_zf_client(): + user = os.environ.get("zf_username") + token = os.environ.get("token") + return ZeroFoxClient(user, token) + + +def get_cti_email_addresses(client: ZeroFoxClient, created_before, created_after): + url_suffix = "email-addresses/" + params = dict(created_after=created_after, created_before=created_before) + return client.cti_request( + "GET", + url_suffix, + params=params, + ) + diff --git a/Solutions/ZeroFox/Data Connectors/CTI/email_addresses_connector/function.json b/Solutions/ZeroFox/Data Connectors/CTI/email_addresses_connector/function.json new file mode 100644 index 00000000000..c84ce78a5a5 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/email_addresses_connector/function.json @@ -0,0 +1,11 @@ +{ + "scriptFile": "__init__.py", + "bindings": [ + { + "name": "mytimer", + "type": "timerTrigger", + "direction": "in", + "schedule": "0 0 18 * * *" + } + ] + } \ No newline at end of file diff --git a/Solutions/ZeroFox/Data Connectors/CTI/exploits_connector/__init__.py b/Solutions/ZeroFox/Data Connectors/CTI/exploits_connector/__init__.py new file mode 100644 index 00000000000..c5b670e5bc6 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/exploits_connector/__init__.py @@ -0,0 +1,65 @@ +import datetime +import logging +import os + +import azure.functions as func + +from connections.sentinel import SentinelConnector +from connections.zerofox import ZeroFoxClient + + +def main(mytimer: func.TimerRequest) -> None: + utc_timestamp = ( + datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + ) + + if mytimer.past_due: + logging.info("The timer is past due!") + + # Update the customer ID to your Log Analytics workspace ID + customer_id = os.environ.get("WorkspaceID") + + # For the shared key, use either the primary or the secondary Connected Sources client authentication key + shared_key = os.environ.get("WorkspaceKey") + + query_from = mytimer.schedule_status["Last"] + query_to = datetime.datetime.utcnow() - datetime.timedelta(minutes=1) + + zf_client = get_zf_client() + + results = get_cti_exploits( + zf_client, created_after=query_from, created_before=query_to + ) + + logging.debug("Trigger function retrieved results") + + # The log type is the name of the event that is being submitted + log_type = "ZeroFox_CTI_exploits" + + sentinel_client = SentinelConnector( + customer_id=customer_id, shared_key=shared_key, log_type=log_type + ) + + for result in results: + sentinel_client.send(result) + + logging.info(f"Python timer trigger function ran at {utc_timestamp}") + + +def get_zf_client(): + user = os.environ.get("zf_username") + token = os.environ.get("token") + return ZeroFoxClient(user, token) + + +def get_cti_exploits(client: ZeroFoxClient, created_after: str, created_before: str): + """ + :return: HTTP request content. + """ + url_suffix = "exploits/" + params = dict(created_after=created_after, created_before=created_before) + return client.cti_request( + "GET", + url_suffix, + params=params, + ) diff --git a/Solutions/ZeroFox/Data Connectors/CTI/exploits_connector/function.json b/Solutions/ZeroFox/Data Connectors/CTI/exploits_connector/function.json new file mode 100644 index 00000000000..0fb7c296f13 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/exploits_connector/function.json @@ -0,0 +1,11 @@ +{ + "scriptFile": "__init__.py", + "bindings": [ + { + "name": "mytimer", + "type": "timerTrigger", + "direction": "in", + "schedule": "0 0 18 * * *" + } + ] +} \ No newline at end of file diff --git a/Solutions/ZeroFox/Data Connectors/CTI/host.json b/Solutions/ZeroFox/Data Connectors/CTI/host.json new file mode 100644 index 00000000000..d6e08a8bf78 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/host.json @@ -0,0 +1,15 @@ +{ + "version": "2.0", + "logging": { + "applicationInsights": { + "samplingSettings": { + "isEnabled": true, + "excludedTypes": "Request" + } + } + }, + "extensionBundle": { + "id": "Microsoft.Azure.Functions.ExtensionBundle", + "version": "[3.*, 4.0.0)" + } + } \ No newline at end of file diff --git a/Solutions/ZeroFox/Data Connectors/CTI/identity_breach_connector/__init__.py b/Solutions/ZeroFox/Data Connectors/CTI/identity_breach_connector/__init__.py new file mode 100644 index 00000000000..a90fbf0a566 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/identity_breach_connector/__init__.py @@ -0,0 +1,61 @@ +import datetime +import logging +import os + +import azure.functions as func + +from connections.sentinel import SentinelConnector +from connections.zerofox import ZeroFoxClient + + +def main(mytimer: func.TimerRequest) -> None: + utc_timestamp = ( + datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + ) + + if mytimer.past_due: + logging.info("The timer is past due!") + + # Update the customer ID to your Log Analytics workspace ID + customer_id = os.environ.get("WorkspaceID") + + # For the shared key, use either the primary or the secondary Connected Sources client authentication key + shared_key = os.environ.get("WorkspaceKey") + + query_from = mytimer.schedule_status["Last"] + query_to = datetime.datetime.utcnow() - datetime.timedelta(minutes=1) + + zf_client = get_zf_client() + + results = get_cti_identity_breach(zf_client, created_after=query_from, created_before=query_to) + + logging.debug("Trigger function retrieved results") + + # The log type is the name of the event that is being submitted + log_type = "ZeroFox_CTI_identity_breach" + + sentinel_client = SentinelConnector( + customer_id=customer_id, shared_key=shared_key, log_type=log_type + ) + + for result in results: + sentinel_client.send(result) + + logging.info("Python timer trigger function ran at %s", utc_timestamp) + + +def get_zf_client(): + user = os.environ.get("zf_username") + token = os.environ.get("token") + return ZeroFoxClient(user, token) + + +def get_cti_identity_breach(client: ZeroFoxClient, created_before, created_after): + url_suffix = "identity-breach/" + params = dict(created_after=created_after, created_before=created_before) + return client.cti_request( + "GET", + url_suffix, + params=params, + ) + diff --git a/Solutions/ZeroFox/Data Connectors/CTI/identity_breach_connector/function.json b/Solutions/ZeroFox/Data Connectors/CTI/identity_breach_connector/function.json new file mode 100644 index 00000000000..c84ce78a5a5 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/identity_breach_connector/function.json @@ -0,0 +1,11 @@ +{ + "scriptFile": "__init__.py", + "bindings": [ + { + "name": "mytimer", + "type": "timerTrigger", + "direction": "in", + "schedule": "0 0 18 * * *" + } + ] + } \ No newline at end of file diff --git a/Solutions/ZeroFox/Data Connectors/CTI/irc_connector/__init__.py b/Solutions/ZeroFox/Data Connectors/CTI/irc_connector/__init__.py new file mode 100644 index 00000000000..1072beec6fc --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/irc_connector/__init__.py @@ -0,0 +1,62 @@ +import datetime +import logging +import os + +import azure.functions as func + +from connections.sentinel import SentinelConnector +from connections.zerofox import ZeroFoxClient + + +def main(mytimer: func.TimerRequest) -> None: + utc_timestamp = ( + datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + ) + + if mytimer.past_due: + logging.info("The timer is past due!") + + # Update the customer ID to your Log Analytics workspace ID + customer_id = os.environ.get("WorkspaceID") + + # For the shared key, use either the primary or the secondary Connected Sources client authentication key + shared_key = os.environ.get("WorkspaceKey") + + query_from = mytimer.schedule_status["Last"] + query_to = datetime.datetime.utcnow() - datetime.timedelta(minutes=1) + + zf_client = get_zf_client() + + results = get_cti_irc(zf_client, timestamp_after= query_from, timestamp_before= query_to) + + logging.debug("Trigger function retrieved results") + + # The log type is the name of the event that is being submitted + log_type = "ZeroFox_CTI_irc" + + sentinel_client = SentinelConnector( + customer_id=customer_id, shared_key=shared_key, log_type=log_type + ) + + for result in results: + sentinel_client.send(result) + + logging.info(f"Python timer trigger function ran at {utc_timestamp}") + + +def get_zf_client(): + user = os.environ.get("zf_username") + token = os.environ.get("token") + return ZeroFoxClient(user, token) + + +def get_cti_irc(client: ZeroFoxClient, timestamp_after: str, timestamp_before: str): + + url_suffix = "irc/" + params = dict(timestamp_after=timestamp_after, timestamp_before=timestamp_before) + return client.cti_request( + "GET", + url_suffix, + params=params, + ) + diff --git a/Solutions/ZeroFox/Data Connectors/CTI/irc_connector/function.json b/Solutions/ZeroFox/Data Connectors/CTI/irc_connector/function.json new file mode 100644 index 00000000000..0fb7c296f13 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/irc_connector/function.json @@ -0,0 +1,11 @@ +{ + "scriptFile": "__init__.py", + "bindings": [ + { + "name": "mytimer", + "type": "timerTrigger", + "direction": "in", + "schedule": "0 0 18 * * *" + } + ] +} \ No newline at end of file diff --git a/Solutions/ZeroFox/Data Connectors/CTI/malware_connector/__init__.py b/Solutions/ZeroFox/Data Connectors/CTI/malware_connector/__init__.py new file mode 100644 index 00000000000..1da817fc5c3 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/malware_connector/__init__.py @@ -0,0 +1,63 @@ +import datetime +import logging +import os + +import azure.functions as func + +from connections.sentinel import SentinelConnector +from connections.zerofox import ZeroFoxClient + + +def main(mytimer: func.TimerRequest) -> None: + utc_timestamp = ( + datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + ) + + if mytimer.past_due: + logging.info("The timer is past due!") + + # Update the customer ID to your Log Analytics workspace ID + customer_id = os.environ.get("WorkspaceID") + + # For the shared key, use either the primary + # or the secondary Connected Sources client authentication key + shared_key = os.environ.get("WorkspaceKey") + + query_from = mytimer.schedule_status["Last"] + query_to = datetime.datetime.utcnow() - datetime.timedelta(minutes=1) + + zf_client = get_zf_client() + + results = get_cti_malware( + zf_client, created_after=query_from, created_before=query_to + ) + + logging.debug("Trigger function retrieved results") + + # The log type is the name of the event that is being submitted + log_type = "ZeroFox_CTI_malware" + + sentinel_client = SentinelConnector( + customer_id=customer_id, shared_key=shared_key, log_type=log_type + ) + + for result in results: + sentinel_client.send(result) + + logging.info("Python timer trigger function ran at %s", utc_timestamp) + + +def get_zf_client(): + user = os.environ.get("zf_username") + token = os.environ.get("token") + return ZeroFoxClient(user, token) + + +def get_cti_malware(client: ZeroFoxClient, created_before, created_after): + url_suffix = "malware/" + params = dict(created_after=created_after, created_before=created_before) + return client.cti_request( + "GET", + url_suffix, + params=params, + ) diff --git a/Solutions/ZeroFox/Data Connectors/CTI/malware_connector/function.json b/Solutions/ZeroFox/Data Connectors/CTI/malware_connector/function.json new file mode 100644 index 00000000000..c84ce78a5a5 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/malware_connector/function.json @@ -0,0 +1,11 @@ +{ + "scriptFile": "__init__.py", + "bindings": [ + { + "name": "mytimer", + "type": "timerTrigger", + "direction": "in", + "schedule": "0 0 18 * * *" + } + ] + } \ No newline at end of file diff --git a/Solutions/ZeroFox/Data Connectors/CTI/national_ids_connector/__init__.py b/Solutions/ZeroFox/Data Connectors/CTI/national_ids_connector/__init__.py new file mode 100644 index 00000000000..0c31aabad56 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/national_ids_connector/__init__.py @@ -0,0 +1,64 @@ +import datetime +import logging +import os + +import azure.functions as func + +from connections.sentinel import SentinelConnector +from connections.zerofox import ZeroFoxClient + + +def main(mytimer: func.TimerRequest) -> None: + utc_timestamp = ( + datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + ) + + if mytimer.past_due: + logging.info("The timer is past due!") + + # Update the customer ID to your Log Analytics workspace ID + customer_id = os.environ.get("WorkspaceID") + + # For the shared key, use either the primary or the secondary Connected Sources client authentication key + shared_key = os.environ.get("WorkspaceKey") + + query_from = mytimer.schedule_status["Last"] + query_to = datetime.datetime.utcnow() - datetime.timedelta(minutes=1) + + zf_client = get_zf_client() + + results = get_cti_national_ids( + zf_client, created_after=query_from, created_before=query_to + ) + + logging.debug("Trigger function retrieved results") + + # The log type is the name of the event that is being submitted + log_type = "ZeroFox_CTI_national_ids" + + sentinel_client = SentinelConnector( + customer_id=customer_id, shared_key=shared_key, log_type=log_type + ) + + for result in results: + sentinel_client.send(result) + + logging.info(f"Python timer trigger function ran at {utc_timestamp}") + + +def get_zf_client(): + user = os.environ.get("zf_username") + token = os.environ.get("token") + return ZeroFoxClient(user, token) + + +def get_cti_national_ids( + client: ZeroFoxClient, created_after: str, created_before: str +): + url_suffix = "national-ids/" + params = dict(created_after=created_after, created_before=created_before) + return client.cti_request( + "GET", + url_suffix, + params=params, + ) diff --git a/Solutions/ZeroFox/Data Connectors/CTI/national_ids_connector/function.json b/Solutions/ZeroFox/Data Connectors/CTI/national_ids_connector/function.json new file mode 100644 index 00000000000..0fb7c296f13 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/national_ids_connector/function.json @@ -0,0 +1,11 @@ +{ + "scriptFile": "__init__.py", + "bindings": [ + { + "name": "mytimer", + "type": "timerTrigger", + "direction": "in", + "schedule": "0 0 18 * * *" + } + ] +} \ No newline at end of file diff --git a/Solutions/ZeroFox/Data Connectors/CTI/phishing_connector/__init__.py b/Solutions/ZeroFox/Data Connectors/CTI/phishing_connector/__init__.py new file mode 100644 index 00000000000..bc17192f504 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/phishing_connector/__init__.py @@ -0,0 +1,62 @@ +import datetime +import logging +import os + +import azure.functions as func + +from connections.sentinel import SentinelConnector +from connections.zerofox import ZeroFoxClient + + +def main(mytimer: func.TimerRequest) -> None: + utc_timestamp = ( + datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + ) + + if mytimer.past_due: + logging.info("The timer is past due!") + + # Update the customer ID to your Log Analytics workspace ID + customer_id = os.environ.get("WorkspaceID") + + # For the shared key, use either the primary or the secondary Connected Sources client authentication key + shared_key = os.environ.get("WorkspaceKey") + + query_from = mytimer.schedule_status["Last"] + query_to = datetime.datetime.utcnow() - datetime.timedelta(minutes=1) + + zf_client = get_zf_client() + + results = get_cti_phishing( + zf_client, scanned_after=query_from, scanned_before=query_to + ) + + logging.debug("Trigger function retrieved results") + + # The log type is the name of the event that is being submitted + log_type = "ZeroFox_CTI_phishing" + + sentinel_client = SentinelConnector( + customer_id=customer_id, shared_key=shared_key, log_type=log_type + ) + + for result in results: + sentinel_client.send(result) + + logging.info("Python timer trigger function ran at %s", utc_timestamp) + + +def get_zf_client(): + user = os.environ.get("zf_username") + token = os.environ.get("token") + return ZeroFoxClient(user, token) + + +def get_cti_phishing(client: ZeroFoxClient, scanned_before, scanned_after): + url_suffix = "phishing/" + params = dict(scanned_after=scanned_after, scanned_before=scanned_before) + return client.cti_request( + "GET", + url_suffix, + params=params, + ) diff --git a/Solutions/ZeroFox/Data Connectors/CTI/phishing_connector/function.json b/Solutions/ZeroFox/Data Connectors/CTI/phishing_connector/function.json new file mode 100644 index 00000000000..c84ce78a5a5 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/phishing_connector/function.json @@ -0,0 +1,11 @@ +{ + "scriptFile": "__init__.py", + "bindings": [ + { + "name": "mytimer", + "type": "timerTrigger", + "direction": "in", + "schedule": "0 0 18 * * *" + } + ] + } \ No newline at end of file diff --git a/Solutions/ZeroFox/Data Connectors/CTI/phone_numbers_connector/__init__.py b/Solutions/ZeroFox/Data Connectors/CTI/phone_numbers_connector/__init__.py new file mode 100644 index 00000000000..7fd0951fa07 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/phone_numbers_connector/__init__.py @@ -0,0 +1,64 @@ +import datetime +import logging +import os + +import azure.functions as func + +from connections.sentinel import SentinelConnector +from connections.zerofox import ZeroFoxClient + + +def main(mytimer: func.TimerRequest) -> None: + utc_timestamp = ( + datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + ) + + if mytimer.past_due: + logging.info("The timer is past due!") + + # Update the customer ID to your Log Analytics workspace ID + customer_id = os.environ.get("WorkspaceID") + + # For the shared key, use either the primary or the secondary Connected Sources client authentication key + shared_key = os.environ.get("WorkspaceKey") + + query_from = mytimer.schedule_status["Last"] + query_to = datetime.datetime.utcnow() - datetime.timedelta(minutes=1) + + zf_client = get_zf_client() + + results = get_cti_phone_numbers( + zf_client, created_after=query_from, created_before=query_to + ) + + logging.debug("Trigger function retrieved results") + + # The log type is the name of the event that is being submitted + log_type = "ZeroFox_CTI_phone_numbers" + + sentinel_client = SentinelConnector( + customer_id=customer_id, shared_key=shared_key, log_type=log_type + ) + + for result in results: + sentinel_client.send(result) + + logging.info(f"Python timer trigger function ran at {utc_timestamp}") + + +def get_zf_client(): + user = os.environ.get("zf_username") + token = os.environ.get("token") + return ZeroFoxClient(user, token) + + +def get_cti_phone_numbers( + client: ZeroFoxClient, created_after: str, created_before: str +): + url_suffix = "phone-numbers/" + params = dict(created_after=created_after, created_before=created_before) + return client.cti_request( + "GET", + url_suffix, + params=params, + ) diff --git a/Solutions/ZeroFox/Data Connectors/CTI/phone_numbers_connector/function.json b/Solutions/ZeroFox/Data Connectors/CTI/phone_numbers_connector/function.json new file mode 100644 index 00000000000..0fb7c296f13 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/phone_numbers_connector/function.json @@ -0,0 +1,11 @@ +{ + "scriptFile": "__init__.py", + "bindings": [ + { + "name": "mytimer", + "type": "timerTrigger", + "direction": "in", + "schedule": "0 0 18 * * *" + } + ] +} \ No newline at end of file diff --git a/Solutions/ZeroFox/Data Connectors/CTI/proxies.json b/Solutions/ZeroFox/Data Connectors/CTI/proxies.json new file mode 100644 index 00000000000..a1695a9b97a --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/proxies.json @@ -0,0 +1,4 @@ +{ + "$schema": "http://json.schemastore.org/proxies", + "proxies": {} + } \ No newline at end of file diff --git a/Solutions/ZeroFox/Data Connectors/CTI/ransomware_connector/__init__.py b/Solutions/ZeroFox/Data Connectors/CTI/ransomware_connector/__init__.py new file mode 100644 index 00000000000..acf39514af5 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/ransomware_connector/__init__.py @@ -0,0 +1,62 @@ +import datetime +import logging +import os + +import azure.functions as func + +from connections.sentinel import SentinelConnector +from connections.zerofox import ZeroFoxClient + + +def main(mytimer: func.TimerRequest) -> None: + utc_timestamp = ( + datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + ) + + if mytimer.past_due: + logging.info("The timer is past due!") + + # Update the customer ID to your Log Analytics workspace ID + customer_id = os.environ.get("WorkspaceID") + + # For the shared key, use either the primary or the secondary Connected Sources client authentication key + shared_key = os.environ.get("WorkspaceKey") + + query_from = mytimer.schedule_status["Last"] + query_to = datetime.datetime.utcnow() - datetime.timedelta(minutes=1) + + zf_client = get_zf_client() + + results = get_cti_ransomware( + zf_client, created_after=query_from, created_before=query_to + ) + + logging.debug("Trigger function retrieved results") + + # The log type is the name of the event that is being submitted + log_type = "ZeroFox_CTI_ransomware" + + sentinel_client = SentinelConnector( + customer_id=customer_id, shared_key=shared_key, log_type=log_type + ) + + for result in results: + sentinel_client.send(result) + + logging.info(f"Python timer trigger function ran at {utc_timestamp}") + + +def get_zf_client(): + user = os.environ.get("zf_username") + token = os.environ.get("token") + return ZeroFoxClient(user, token) + + +def get_cti_ransomware(client: ZeroFoxClient, created_after: str, created_before: str): + url_suffix = "ransomware/" + params = dict(created_after=created_after, created_before=created_before) + return client.cti_request( + "GET", + url_suffix, + params=params, + ) diff --git a/Solutions/ZeroFox/Data Connectors/CTI/ransomware_connector/function.json b/Solutions/ZeroFox/Data Connectors/CTI/ransomware_connector/function.json new file mode 100644 index 00000000000..0fb7c296f13 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/ransomware_connector/function.json @@ -0,0 +1,11 @@ +{ + "scriptFile": "__init__.py", + "bindings": [ + { + "name": "mytimer", + "type": "timerTrigger", + "direction": "in", + "schedule": "0 0 18 * * *" + } + ] +} \ No newline at end of file diff --git a/Solutions/ZeroFox/Data Connectors/CTI/requirements.txt b/Solutions/ZeroFox/Data Connectors/CTI/requirements.txt new file mode 100644 index 00000000000..67bd1d64791 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/requirements.txt @@ -0,0 +1,8 @@ +# Do not include azure-functions-worker in this file +# The Python Worker is managed by the Azure Functions platform +# Manually managing azure-functions-worker may cause unexpected issues + +azure-functions +pytest +requests +responses \ No newline at end of file diff --git a/Solutions/ZeroFox/Data Connectors/CTI/telegram_connector/__init__.py b/Solutions/ZeroFox/Data Connectors/CTI/telegram_connector/__init__.py new file mode 100644 index 00000000000..90b140b7a31 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/telegram_connector/__init__.py @@ -0,0 +1,64 @@ +import datetime +import logging +import os + +import azure.functions as func + +from connections.sentinel import SentinelConnector +from connections.zerofox import ZeroFoxClient + + +def main(mytimer: func.TimerRequest) -> None: + utc_timestamp = ( + datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + ) + + if mytimer.past_due: + logging.info("The timer is past due!") + + # Update the customer ID to your Log Analytics workspace ID + customer_id = os.environ.get("WorkspaceID") + + # For the shared key, use either the primary or the secondary Connected Sources client authentication key + shared_key = os.environ.get("WorkspaceKey") + + query_from = mytimer.schedule_status["Last"] + query_to = datetime.datetime.utcnow() - datetime.timedelta(minutes=1) + + zf_client = get_zf_client() + + results = get_cti_telegram( + zf_client, timestamp_after=query_from, timestamp_before=query_to + ) + + logging.debug("Trigger function retrieved results") + + # The log type is the name of the event that is being submitted + log_type = "ZeroFox_CTI_telegram" + + sentinel_client = SentinelConnector( + customer_id=customer_id, shared_key=shared_key, log_type=log_type + ) + + for result in results: + sentinel_client.send(result) + + logging.info(f"Python timer trigger function ran at {utc_timestamp}") + + +def get_zf_client(): + user = os.environ.get("zf_username") + token = os.environ.get("token") + return ZeroFoxClient(user, token) + + +def get_cti_telegram( + client: ZeroFoxClient, timestamp_after: str, timestamp_before: str +): + url_suffix = "telegram/" + params = dict(timestamp_after=timestamp_after, timestamp_before=timestamp_before) + return client.cti_request( + "GET", + url_suffix, + params=params, + ) diff --git a/Solutions/ZeroFox/Data Connectors/CTI/telegram_connector/function.json b/Solutions/ZeroFox/Data Connectors/CTI/telegram_connector/function.json new file mode 100644 index 00000000000..0fb7c296f13 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/telegram_connector/function.json @@ -0,0 +1,11 @@ +{ + "scriptFile": "__init__.py", + "bindings": [ + { + "name": "mytimer", + "type": "timerTrigger", + "direction": "in", + "schedule": "0 0 18 * * *" + } + ] +} \ No newline at end of file diff --git a/Solutions/ZeroFox/Data Connectors/CTI/tests/ZeroFox_test.py b/Solutions/ZeroFox/Data Connectors/CTI/tests/ZeroFox_test.py new file mode 100644 index 00000000000..e9fe24224f7 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/tests/ZeroFox_test.py @@ -0,0 +1,57 @@ +from itertools import zip_longest + +import responses +from responses import matchers +from connections.zerofox import ZeroFoxClient + +USER = "user" +TOKEN = "token" +ENDPOINT = "dummy-endpoint/" +CTI_TOKEN = "cti_token" +SECOND_PAGE_URL = "https://second_page" +URL = "https://api.zerofox.com" + + +class TestZeroFoxCTI(): + @responses.activate + def test_cti_generator_is_provided(self): + zf_client = ZeroFoxClient(user=USER, token=TOKEN) + self.build_cti_responses() + + output = zf_client.cti_request(method="GET", url_suffix=ENDPOINT) + expected = (dict(index=f"r{i}") for i in range(4)) + all_match = all(a == b for a, b in zip_longest(output, expected)) + assert all_match + + def build_cti_responses(self): + """Prepare mock responses for queries through the requests package.""" + responses.post( + url=f"{URL}/auth/token/", + match=[matchers.urlencoded_params_matcher( + dict(username=USER, password=TOKEN)) + ], + json=dict(access=CTI_TOKEN), + ) + + cti_header = { + "Authorization": f"Bearer {CTI_TOKEN}", + "Content-Type": "application/json", + "Accept": "application/json", + } + + endpoint_first_page_json = dict( + next=SECOND_PAGE_URL, results=[ + dict(index=f"r{i}") for i in range(2)] + ) + responses.get( + url=f"{URL}/cti/{ENDPOINT}", headers=cti_header, + json=endpoint_first_page_json + ) + + endpoint_second_page_json = dict( + next=None, results=[dict(index=f"r{i}") for i in range(2, 4)] + ) + responses.get( + url=SECOND_PAGE_URL, headers=cti_header, + json=endpoint_second_page_json + ) diff --git a/Solutions/ZeroFox/Data Connectors/CTI/threat_actors_connector/__init__.py b/Solutions/ZeroFox/Data Connectors/CTI/threat_actors_connector/__init__.py new file mode 100644 index 00000000000..0c52869d6c9 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/threat_actors_connector/__init__.py @@ -0,0 +1,62 @@ +import datetime +import logging +import os + +import azure.functions as func + +from connections.sentinel import SentinelConnector +from connections.zerofox import ZeroFoxClient + + +def main(mytimer: func.TimerRequest) -> None: + utc_timestamp = ( + datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + ) + + if mytimer.past_due: + logging.info("The timer is past due!") + + # Update the customer ID to your Log Analytics workspace ID + customer_id = os.environ.get("WorkspaceID") + + # For the shared key, use either the primary or the secondary Connected Sources client authentication key + shared_key = os.environ.get("WorkspaceKey") + + query_from = mytimer.schedule_status["Last"] + query_to = datetime.datetime.utcnow() - datetime.timedelta(minutes=1) + + zf_client = get_zf_client() + + results = get_cti_threat_actors( + zf_client, created_after=query_from, created_before=query_to + ) + + logging.debug("Trigger function retrieved results") + + # The log type is the name of the event that is being submitted + log_type = "ZeroFox_CTI_threat_actors" + + sentinel_client = SentinelConnector( + customer_id=customer_id, shared_key=shared_key, log_type=log_type + ) + + for result in results: + sentinel_client.send(result) + + logging.info("Python timer trigger function ran at %s", utc_timestamp) + + +def get_zf_client(): + user = os.environ.get("zf_username") + token = os.environ.get("token") + return ZeroFoxClient(user, token) + + +def get_cti_threat_actors(client: ZeroFoxClient, created_after, created_before): + url_suffix = "threat-actors/" + params = dict(created_after=created_after, created_before=created_before) + return client.cti_request( + "GET", + url_suffix, + params=params, + ) diff --git a/Solutions/ZeroFox/Data Connectors/CTI/threat_actors_connector/function.json b/Solutions/ZeroFox/Data Connectors/CTI/threat_actors_connector/function.json new file mode 100644 index 00000000000..c84ce78a5a5 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/threat_actors_connector/function.json @@ -0,0 +1,11 @@ +{ + "scriptFile": "__init__.py", + "bindings": [ + { + "name": "mytimer", + "type": "timerTrigger", + "direction": "in", + "schedule": "0 0 18 * * *" + } + ] + } \ No newline at end of file diff --git a/Solutions/ZeroFox/Data Connectors/CTI/vulnerabilities_connector/__init__.py b/Solutions/ZeroFox/Data Connectors/CTI/vulnerabilities_connector/__init__.py new file mode 100644 index 00000000000..43409c31165 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/vulnerabilities_connector/__init__.py @@ -0,0 +1,64 @@ +import datetime +import logging +import os + +import azure.functions as func + +from connections.sentinel import SentinelConnector +from connections.zerofox import ZeroFoxClient + + +def main(mytimer: func.TimerRequest) -> None: + utc_timestamp = ( + datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + ) + + if mytimer.past_due: + logging.info("The timer is past due!") + + # Update the customer ID to your Log Analytics workspace ID + customer_id = os.environ.get("WorkspaceID") + + # For the shared key, use either the primary or the secondary Connected Sources client authentication key + shared_key = os.environ.get("WorkspaceKey") + + query_from = mytimer.schedule_status["Last"] + query_to = datetime.datetime.utcnow() - datetime.timedelta(minutes=1) + + zf_client = get_zf_client() + + results = get_cti_vulnerabilities( + zf_client, created_after=query_from, created_before=query_to + ) + + logging.debug("Trigger function retrieved results") + + # The log type is the name of the event that is being submitted + log_type = "ZeroFox_CTI_vulnerabilities" + + sentinel_client = SentinelConnector( + customer_id=customer_id, shared_key=shared_key, log_type=log_type + ) + + for result in results: + sentinel_client.send(result) + + logging.info(f"Python timer trigger function ran at {utc_timestamp}") + + +def get_zf_client(): + user = os.environ.get("zf_username") + token = os.environ.get("token") + return ZeroFoxClient(user, token) + + +def get_cti_vulnerabilities( + client: ZeroFoxClient, created_after: str, created_before: str +): + url_suffix = "vulnerabilities/" + params = dict(created_after=created_after, created_before=created_before) + return client.cti_request( + "GET", + url_suffix, + params=params, + ) diff --git a/Solutions/ZeroFox/Data Connectors/CTI/vulnerabilities_connector/function.json b/Solutions/ZeroFox/Data Connectors/CTI/vulnerabilities_connector/function.json new file mode 100644 index 00000000000..0fb7c296f13 --- /dev/null +++ b/Solutions/ZeroFox/Data Connectors/CTI/vulnerabilities_connector/function.json @@ -0,0 +1,11 @@ +{ + "scriptFile": "__init__.py", + "bindings": [ + { + "name": "mytimer", + "type": "timerTrigger", + "direction": "in", + "schedule": "0 0 18 * * *" + } + ] +} \ No newline at end of file diff --git a/Solutions/ZeroFox/Data/Solution_ZeroFox.json b/Solutions/ZeroFox/Data/Solution_ZeroFox.json new file mode 100644 index 00000000000..e1c86233adf --- /dev/null +++ b/Solutions/ZeroFox/Data/Solution_ZeroFox.json @@ -0,0 +1,22 @@ +{ + "Name": "ZeroFox", + "Author": "Microsoft - support@microsoft.com", + "Logo": "", + "Description": "The [ZeroFox](https://www.zerofox.com/) solution for Microsoft Sentinel enables you to ingest [ZeroFox Alerts](https://www.zerofox.com/platform/) and [ZeroFox CTI events](https://www.zerofox.com/threat-intelligence/) into Microsoft Sentinel using the ZeroFox API. \n\n**Underlying Microsoft Technologies used:**\n\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:\n\na. [Azure Monitor HTTP Data Collector API](https://docs.microsoft.com/azure/azure-monitor/logs/data-collector-api)\n\nb. [Azure Functions](https://azure.microsoft.com/services/functions/#overview)", + "Data Connectors": [ + "Data Connectors/CTI/ZeroFox_CTI_FunctionApp.json", + "Data Connectors/Alerts/alerts_connector.json" + ], + "Analytic Rules": [ + "Analytic Rules/ZF_Alerts_HighSeverityRule.yaml", + "Analytic Rules/ZF_Alerts_InformationalSeverityRule.yaml", + "Analytic Rules/ZF_Alerts_LowSeverityRule.yaml", + "Analytic Rules/ZF_Alerts_MediumSeverityRule.yaml" + ], + "BasePath": "C:\\GitHub\\Azure-Sentinel\\Solutions\\ZeroFox", + "Version": "3.0.0", + "Metadata": "SolutionMetadata.json", + "TemplateSpec": true, + "Is1Pconnector": false + } + \ No newline at end of file diff --git a/Solutions/ZeroFox/Package/3.0.0.zip b/Solutions/ZeroFox/Package/3.0.0.zip new file mode 100644 index 00000000000..9a8b1fde9a7 Binary files /dev/null and b/Solutions/ZeroFox/Package/3.0.0.zip differ diff --git a/Solutions/ZeroFox/Package/createUiDefinition.json b/Solutions/ZeroFox/Package/createUiDefinition.json new file mode 100644 index 00000000000..e9c1b20dfb0 --- /dev/null +++ b/Solutions/ZeroFox/Package/createUiDefinition.json @@ -0,0 +1,176 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/0.1.2-preview/CreateUIDefinition.MultiVm.json#", + "handler": "Microsoft.Azure.CreateUIDef", + "version": "0.1.2-preview", + "parameters": { + "config": { + "isWizard": false, + "basics": { + "description": "\n\n**Note:** _There may be [known issues](https://aka.ms/sentinelsolutionsknownissues) pertaining to this Solution, please refer to them before installing._\n\nThe [ZeroFox](https://www.zerofox.com/) solution for Microsoft Sentinel enables you to ingest [ZeroFox Alerts](https://www.zerofox.com/platform/) and [ZeroFox CTI events](https://www.zerofox.com/threat-intelligence/) into Microsoft Sentinel using the ZeroFox API. \n\n**Underlying Microsoft Technologies used:**\n\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:\n\na. [Azure Monitor HTTP Data Collector API](https://docs.microsoft.com/azure/azure-monitor/logs/data-collector-api)\n\nb. [Azure Functions](https://azure.microsoft.com/services/functions/#overview)\n\n**Data Connectors:** 2, **Analytic Rules:** 4\n\n[Learn more about Microsoft Sentinel](https://aka.ms/azuresentinel) | [Learn more about Solutions](https://aka.ms/azuresentinelsolutionsdoc)", + "subscription": { + "resourceProviders": [ + "Microsoft.OperationsManagement/solutions", + "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 ZeroFox. You can get ZeroFox custom log data in your Microsoft Sentinel workspace. After installing the solution, configure and enable this data connector by following guidance in Manage solution view." + } + }, + { + "name": "dataconnectors2-text", + "type": "Microsoft.Common.TextBlock", + "options": { + "text": "This Solution installs the data connector for ZeroFox. You can get ZeroFox custom log data in your Microsoft Sentinel workspace. After installing the solution, configure and enable this data connector by following guidance in Manage solution view." + } + }, + { + "name": "dataconnectors-link2", + "type": "Microsoft.Common.TextBlock", + "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": "ZeroFox Alerts - High Severity Alerts", + "elements": [ + { + "name": "analytic1-text", + "type": "Microsoft.Common.TextBlock", + "options": { + "text": "Detects high severity alerts from ZeroFox" + } + } + ] + }, + { + "name": "analytic2", + "type": "Microsoft.Common.Section", + "label": "ZeroFox Alerts - Informational Severity Alerts", + "elements": [ + { + "name": "analytic2-text", + "type": "Microsoft.Common.TextBlock", + "options": { + "text": "Detects informational severity alerts from ZeroFox" + } + } + ] + }, + { + "name": "analytic3", + "type": "Microsoft.Common.Section", + "label": "ZeroFox Alerts - Low Severity Alerts", + "elements": [ + { + "name": "analytic3-text", + "type": "Microsoft.Common.TextBlock", + "options": { + "text": "Detects low severity alerts from ZeroFox" + } + } + ] + }, + { + "name": "analytic4", + "type": "Microsoft.Common.Section", + "label": "ZeroFox Alerts - Medium Severity Alerts", + "elements": [ + { + "name": "analytic4-text", + "type": "Microsoft.Common.TextBlock", + "options": { + "text": "Detects medium severity alerts from ZeroFox" + } + } + ] + } + ] + } + ], + "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/ZeroFox/Package/mainTemplate.json b/Solutions/ZeroFox/Package/mainTemplate.json new file mode 100644 index 00000000000..83c76da2013 --- /dev/null +++ b/Solutions/ZeroFox/Package/mainTemplate.json @@ -0,0 +1,1707 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "author": "Microsoft - support@microsoft.com", + "comments": "Solution template for ZeroFox" + }, + "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" + } + } + }, + "variables": { + "email": "support@microsoft.com", + "_email": "[variables('email')]", + "_solutionName": "ZeroFox", + "_solutionVersion": "3.0.0", + "solutionId": "azuresentinel.azure-sentinel-solution-zerofox", + "_solutionId": "[variables('solutionId')]", + "uiConfigId1": "ZeroFoxCTIDataConnector", + "_uiConfigId1": "[variables('uiConfigId1')]", + "dataConnectorContentId1": "ZeroFoxCTIDataConnector", + "_dataConnectorContentId1": "[variables('dataConnectorContentId1')]", + "dataConnectorId1": "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/dataConnectors', variables('_dataConnectorContentId1'))]", + "_dataConnectorId1": "[variables('dataConnectorId1')]", + "dataConnectorTemplateSpecName1": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-dc-',uniquestring(variables('_dataConnectorContentId1'))))]", + "dataConnectorVersion1": "1.0.0", + "dataConnectorcontentProductId1": "[concat(take(variables('_solutionId'),50),'-','dc','-', uniqueString(concat(variables('_solutionId'),'-','DataConnector','-',variables('_dataConnectorContentId1'),'-', variables('dataConnectorVersion1'))))]", + "_dataConnectorcontentProductId1": "[variables('dataConnectorcontentProductId1')]", + "uiConfigId2": "ZeroFox_Alert_Polling", + "_uiConfigId2": "[variables('uiConfigId2')]", + "dataConnectorContentId2": "ZeroFox_Alert_Polling", + "_dataConnectorContentId2": "[variables('dataConnectorContentId2')]", + "dataConnectorId2": "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/dataConnectors', variables('_dataConnectorContentId2'))]", + "_dataConnectorId2": "[variables('dataConnectorId2')]", + "dataConnectorTemplateSpecName2": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-dc-',uniquestring(variables('_dataConnectorContentId2'))))]", + "dataConnectorVersion2": "1.0.0", + "dataConnectorcontentProductId2": "[concat(take(variables('_solutionId'),50),'-','dc','-', uniqueString(concat(variables('_solutionId'),'-','DataConnector','-',variables('_dataConnectorContentId2'),'-', variables('dataConnectorVersion2'))))]", + "_dataConnectorcontentProductId2": "[variables('dataConnectorcontentProductId2')]", + "analyticRuleVersion1": "1.0.0", + "analyticRulecontentId1": "deb45e6d-892f-40bf-9118-e2a6f26b788d", + "_analyticRulecontentId1": "[variables('analyticRulecontentId1')]", + "analyticRuleId1": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', variables('analyticRulecontentId1'))]", + "analyticRuleTemplateSpecName1": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring(variables('_analyticRulecontentId1'))))]", + "analyticRulecontentProductId1": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-',variables('_analyticRulecontentId1'),'-', variables('analyticRuleVersion1'))))]", + "_analyticRulecontentProductId1": "[variables('analyticRulecontentProductId1')]", + "analyticRuleVersion2": "1.0.0", + "analyticRulecontentId2": "6f7a7413-b72f-4361-84ee-897baeb9c6d4", + "_analyticRulecontentId2": "[variables('analyticRulecontentId2')]", + "analyticRuleId2": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', variables('analyticRulecontentId2'))]", + "analyticRuleTemplateSpecName2": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring(variables('_analyticRulecontentId2'))))]", + "analyticRulecontentProductId2": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-',variables('_analyticRulecontentId2'),'-', variables('analyticRuleVersion2'))))]", + "_analyticRulecontentProductId2": "[variables('analyticRulecontentProductId2')]", + "analyticRuleVersion3": "1.0.0", + "analyticRulecontentId3": "e0c7a91a-7aa1-498a-9c20-cd6c721f9345", + "_analyticRulecontentId3": "[variables('analyticRulecontentId3')]", + "analyticRuleId3": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', variables('analyticRulecontentId3'))]", + "analyticRuleTemplateSpecName3": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring(variables('_analyticRulecontentId3'))))]", + "analyticRulecontentProductId3": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-',variables('_analyticRulecontentId3'),'-', variables('analyticRuleVersion3'))))]", + "_analyticRulecontentProductId3": "[variables('analyticRulecontentProductId3')]", + "analyticRuleVersion4": "1.0.0", + "analyticRulecontentId4": "a6496de5-911b-4199-b7db-d34ac9d70df3", + "_analyticRulecontentId4": "[variables('analyticRulecontentId4')]", + "analyticRuleId4": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', variables('analyticRulecontentId4'))]", + "analyticRuleTemplateSpecName4": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring(variables('_analyticRulecontentId4'))))]", + "analyticRulecontentProductId4": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-',variables('_analyticRulecontentId4'),'-', variables('analyticRuleVersion4'))))]", + "_analyticRulecontentProductId4": "[variables('analyticRulecontentProductId4')]", + "solutioncontentProductId": "[concat(take(variables('_solutionId'),50),'-','sl','-', uniqueString(concat(variables('_solutionId'),'-','Solution','-',variables('_solutionId'),'-', variables('_solutionVersion'))))]", + "_solutioncontentProductId" : "[variables('solutioncontentProductId')]" + }, + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('dataConnectorTemplateSpecName1')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "ZeroFox data connector with template version 3.0.0", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('dataConnectorVersion1')]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',variables('_dataConnectorContentId1'))]", + "apiVersion": "2021-03-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectors", + "location": "[parameters('workspace-location')]", + "kind": "GenericUI", + "properties": { + "connectorUiConfig": { + "id": "[variables('_uiConfigId1')]", + "title": "ZeroFox CTI (using Azure Functions)", + "publisher": "ZeroFox", + "descriptionMarkdown": "The ZeroFox CTI data connectors provide the capability to ingest the different [ZeroFox](https://www.zerofox.com/threat-intelligence/) cyber threat intelligence alerts into Microsoft Sentinel.", + "graphQueries": [ + { + "metricName": "ZeroFox CTI Advanced Dark Web Logs", + "legend": "ZeroFox_CTI_advanced_dark_web_CL", + "baseQuery": "ZeroFox_CTI_advanced_dark_web_CL" + }, + { + "metricName": "ZeroFox CTI Botnet Logs", + "baseQuery": "ZeroFox_CTI_botnet_CL" + }, + { + "metricName": "ZeroFox CTI Breaches Logs", + "legend": "ZeroFox_CTI_breaches_CL", + "baseQuery": "ZeroFox_CTI_breaches_CL" + }, + { + "metricName": "ZeroFox CTI C2 Domains Logs", + "legend": "ZeroFox_CTI_C2_CL", + "baseQuery": "ZeroFox_CTI_C2_CL" + }, + { + "metricName": "ZeroFox CTI Compromised Credentials Logs", + "legend": "ZeroFox_CTI_compromised_credentials_CL", + "baseQuery": "ZeroFox_CTI_compromised_credentials_CL" + }, + { + "metricName": "ZeroFox CTI Credit Cards Logs", + "legend": "ZeroFox_CTI_credit_cards_CL", + "baseQuery": "ZeroFox_CTI_credit_cards_CL" + }, + { + "metricName": "ZeroFox CTI Dark Web Logs", + "legend": "ZeroFox_CTI_dark_web_CL", + "baseQuery": "ZeroFox_CTI_dark_web_CL" + }, + { + "metricName": "ZeroFox CTI Discord Logs", + "legend": "ZeroFox_CTI_discord_CL", + "baseQuery": "ZeroFox_CTI_discord_CL" + }, + { + "metricName": "ZeroFox CTI Disruption Logs", + "legend": "ZeroFox_CTI_disruption_CL", + "baseQuery": "ZeroFox_CTI_disruption_CL" + }, + { + "metricName": "ZeroFox CTI Email Addresses Logs", + "legend": "ZeroFox_CTI_email_addresses_CL", + "baseQuery": "ZeroFox_CTI_email_addresses_CL" + }, + { + "metricName": "ZeroFox CTI Exploits Logs", + "legend": "ZeroFox_CTI_exploits_CL", + "baseQuery": "ZeroFox_CTI_exploits_CL" + }, + { + "metricName": "ZeroFox CTI Identity Breach Logs", + "legend": "ZeroFox_CTI_identity_breach_CL", + "baseQuery": "ZeroFox_CTI_identity_breach_CL" + }, + { + "metricName": "ZeroFox CTI IRC Logs", + "legend": "ZeroFox_CTI_irc_CL", + "baseQuery": "ZeroFox_CTI_irc_CL" + }, + { + "metricName": "ZeroFox CTI Malware Logs", + "legend": "ZeroFox_CTI_malware_CL", + "baseQuery": "ZeroFox_CTI_malware_CL" + }, + { + "metricName": "ZeroFox CTI National Ids Logs", + "legend": "ZeroFox_CTI_national_ids_CL", + "baseQuery": "ZeroFox_CTI_national_ids_CL" + }, + { + "metricName": "ZeroFox CTI Phishing Logs", + "legend": "ZeroFox_CTI_phishing_CL", + "baseQuery": "ZeroFox_CTI_phishing_CL" + }, + { + "metricName": "ZeroFox CTI Phone Numbers Logs", + "legend": "ZeroFox_CTI_phone_numbers_CL", + "baseQuery": "ZeroFox_CTI_phone_numbers_CL" + }, + { + "metricName": "ZeroFox CTI Ransomware Logs", + "legend": "ZeroFox_CTI_ransomware_CL", + "baseQuery": "ZeroFox_CTI_ransomware_CL" + }, + { + "metricName": "ZeroFox CTI Telegram Logs", + "legend": "ZeroFox_CTI_telegram_CL", + "baseQuery": "ZeroFox_CTI_telegram_CL" + }, + { + "metricName": "ZeroFox CTI Threat Actors Logs", + "legend": "ZeroFox_CTI_threat_actors_CL", + "baseQuery": "ZeroFox_CTI_threat_actors_CL" + }, + { + "metricName": "ZeroFox CTI Vulnerabilities Logs", + "legend": "ZeroFox_CTI_vulnerabilities_CL", + "baseQuery": "ZeroFox_CTI_vulnerabilities_CL" + } + ], + "sampleQueries": [ + { + "description": "ZeroFox CTI C2-domains Logs", + "query": "ZeroFox_CTI_C2_CL\n | sort by TimeGenerated desc" + }, + { + "description": "ZeroFox CTI Email Addresses Logs", + "query": "ZeroFox_CTI_email_addresses_CL\n | sort by TimeGenerated desc" + }, + { + "description": "ZeroFox CTI Malware Logs", + "query": "ZeroFox_CTI_malware_CL\n | sort by TimeGenerated desc" + } + ], + "dataTypes": [ + { + "name": "ZeroFox_CTI_advanced_dark_web_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_advanced_dark_web_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_botnet_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_botnet_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_breaches_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_breaches_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_C2_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_C2_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_compromised_credentials_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_compromised_credentials_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_credit_cards_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_credit_cards_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_dark_web_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_dark_web_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_discord_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_discord_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_disruption_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_disruption_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_email_addresses_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_email_addresses_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_exploits_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_exploits_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_identity_breach_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_identity_breach_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_irc_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_irc_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_malware_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_malware_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_national_ids_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_national_ids_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_phishing_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_phishing_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_phone_numbers_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_phone_numbers_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_ransomware_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_ransomware_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_telegram_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_telegram_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_threat_actors_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_threat_actors_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_vulnerabilities_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_vulnerabilities_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + } + ], + "connectivityCriterias": [ + { + "type": "IsConnectedQuery", + "value": [ + "ZeroFox_CTI_advanced_dark_web_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_botnet_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_breaches_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_C2_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_compromised_credentials_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_credit_cards_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_dark_web_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_discord_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_disruption_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_email_addresses_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_exploits_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_identity_breach_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_irc_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_malware_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_national_ids_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_phishing_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_phone_numbers_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_ransomware_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_telegram_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_threat_actors_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_vulnerabilities_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)" + ] + } + ], + "availability": { + "status": 1, + "isPreview": false + }, + "permissions": { + "resourceProvider": [ + { + "provider": "Microsoft.OperationalInsights/workspaces", + "permissionsDisplayText": "read and write permissions on the workspace are required.", + "providerDisplayName": "Workspace", + "scope": "Workspace", + "requiredPermissions": { + "write": true, + "read": true, + "delete": true + } + }, + { + "provider": "Microsoft.OperationalInsights/workspaces/sharedKeys", + "permissionsDisplayText": "read permissions to shared keys for the workspace are required. [See the documentation to learn more about workspace keys](https://docs.microsoft.com/azure/azure-monitor/platform/agent-windows#obtain-workspace-id-and-key).", + "providerDisplayName": "Keys", + "scope": "Workspace", + "requiredPermissions": { + "action": true + } + } + ], + "customs": [ + { + "name": "Microsoft.Web/sites permissions", + "description": "Read and write permissions to Azure Functions to create a Function App is required. [See the documentation to learn more about Azure Functions](https://docs.microsoft.com/azure/azure-functions/)." + }, + { + "name": "ZeroFox API Credentials/permissions", + "description": "**ZeroFox Username**, **ZeroFox Personal Access Token** are required for ZeroFox CTI REST API." + } + ] + }, + "instructionSteps": [ + { + "description": ">**NOTE:** This connector uses Azure Functions to connect to the ZeroFox CTI REST API to pull logs into Microsoft Sentinel. This might result in additional data ingestion costs. Check the [Azure Functions pricing page](https://azure.microsoft.com/pricing/details/functions/) for details." + }, + { + "description": ">**(Optional Step)** Securely store workspace and API authorization key(s) or token(s) in Azure Key Vault. Azure Key Vault provides a secure mechanism to store and retrieve key values. [Follow these instructions](https://docs.microsoft.com/azure/app-service/app-service-key-vault-references) to use Azure Key Vault with an Azure Function App." + }, + { + "description": "**STEP 1 - Retrieval of ZeroFox credentials:**\n\n Follow these instructions for set up logging and obtain credentials." + }, + { + "description": "**STEP 1.1 - [Log into ZeroFox's website.](https://cloud.zerofox.com/login) using your username and password" + }, + { + "description": "**STEP 1.2 - Click into the Settings button and go to the Data Connectors Section." + }, + { + "description": "**STEP 1.3 - Select the API DATA FEEDS tab and head to the bottom of the page, select <> in the API Information box, to obtain a Personal Access Token to be used along with your username." + }, + { + "description": "**STEP 2 - Choose ONE from the following two deployment options to deploy the connector and the associated Azure Function**\n\n>**IMPORTANT:** Before deploying the ZeroFox CTI data connector, have the Workspace ID and Workspace Primary Key (can be copied from the following), as well as the Amazon S3 REST API Authorization credentials, readily available.", + "instructions": [ + { + "parameters": { + "fillWith": [ + "WorkspaceId" + ], + "label": "Workspace ID" + }, + "type": "CopyableLabel" + }, + { + "parameters": { + "fillWith": [ + "PrimaryKey" + ], + "label": "Primary Key" + }, + "type": "CopyableLabel" + } + ] + }, + { + "description": "Use this method for automated deployment of the ZeroFox CTI data connectors using an ARM Tempate.\n\n1. Click the **Deploy to Azure** button below. \n\n\t[![Deploy To Azure](https://aka.ms/deploytoazurebutton)](https://aka.ms/sentinelCiscoUmbrellaazuredeploy)\n2. Select the preferred **Subscription**, **Resource Group** and **Location**. \n3. Enter the **Workspace ID**, **Workspace Key**, **ZeroFox Username**, **ZeroFox Personal Access Token**\n4. Mark the checkbox labeled **I agree to the terms and conditions stated above**.\n5. Click **Purchase** to deploy.", + "title": "Option 1 - Azure Resource Manager (ARM) Template" + }, + { + "description": "Use the following step-by-step instructions to deploy the ZeroFox CTI data connector manually with Azure Functions (Deployment via Visual Studio Code).", + "title": "Option 2 - Manual Deployment of Azure Functions" + }, + { + "description": "**1. Deploy a Function App**\n\n> **NOTE:** You will need to [prepare VS code](https://docs.microsoft.com/azure/azure-functions/create-first-function-vs-code-python) for Azure function development.\n\n1. Download the [Azure Function App](https://aka.ms/sentinel-ZeroFoxCTIConn-functionapp) file. Extract archive to your local development computer.\n2. Start VS Code. Choose File in the main menu and select Open Folder.\n3. Select the top level folder from extracted files.\n4. Choose the Azure icon in the Activity bar, then in the **Azure: Functions** area, choose the **Deploy to function app** button.\nIf you aren't already signed in, choose the Azure icon in the Activity bar, then in the **Azure: Functions** area, choose **Sign in to Azure**\nIf you're already signed in, go to the next step.\n5. Provide the following information at the prompts:\n\n\ta. **Select folder:** Choose a folder from your workspace or browse to one that contains your function app.\n\n\tb. **Select Subscription:** Choose the subscription to use.\n\n\tc. Select **Create new Function App in Azure** (Don't choose the Advanced option)\n\n\td. **Enter a globally unique name for the function app:** Type a name that is valid in a URL path. The name you type is validated to make sure that it's unique in Azure Functions. (e.g. CTIXYZ).\n\n\te. **Select a runtime:** Choose Python 3.8.\n\n\tf. Select a location for new resources. For better performance and lower costs choose the same [region](https://azure.microsoft.com/regions/) where Microsoft Sentinel is located.\n\n6. Deployment will begin. A notification is displayed after your function app is created and the deployment package is applied.\n7. Go to Azure Portal for the Function App configuration." + }, + { + "description": "**2. Configure the Function App**\n\n1. In the Function App, select the Function App Name and select **Configuration**.\n2. In the **Application settings** tab, select **+ New application setting**.\n3. Add each of the following application settings individually, with their respective string values (case-sensitive): \n\t\tWorkspaceID\n\t\tWorkspaceKey\n\t\tS3Bucket\n\t\tAWSAccessKeyId\n\t\tAWSSecretAccessKey\n\t\tlogAnalyticsUri (optional)\n> - Use logAnalyticsUri to override the log analytics API endpoint for dedicated cloud. For example, for public cloud, leave the value empty; for Azure GovUS cloud environment, specify the value in the following format: `https://.ods.opinsights.azure.us`.\n3. Once all application settings have been entered, click **Save**." + } + ] + } + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('DataConnector-', last(split(variables('_dataConnectorId1'),'/'))))]", + "properties": { + "parentId": "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/dataConnectors', variables('_dataConnectorContentId1'))]", + "contentId": "[variables('_dataConnectorContentId1')]", + "kind": "DataConnector", + "version": "[variables('dataConnectorVersion1')]", + "source": { + "kind": "Solution", + "name": "ZeroFox", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Microsoft", + "email": "[variables('_email')]" + }, + "support": { + "tier": "Microsoft", + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "link": "https://support.microsoft.com/" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_dataConnectorContentId1')]", + "contentKind": "DataConnector", + "displayName": "ZeroFox CTI (using Azure Functions)", + "contentProductId": "[variables('_dataConnectorcontentProductId1')]", + "id": "[variables('_dataConnectorcontentProductId1')]", + "version": "[variables('dataConnectorVersion1')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('DataConnector-', last(split(variables('_dataConnectorId1'),'/'))))]", + "dependsOn": [ + "[variables('_dataConnectorId1')]" + ], + "location": "[parameters('workspace-location')]", + "properties": { + "parentId": "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/dataConnectors', variables('_dataConnectorContentId1'))]", + "contentId": "[variables('_dataConnectorContentId1')]", + "kind": "DataConnector", + "version": "[variables('dataConnectorVersion1')]", + "source": { + "kind": "Solution", + "name": "ZeroFox", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Microsoft", + "email": "[variables('_email')]" + }, + "support": { + "tier": "Microsoft", + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "link": "https://support.microsoft.com/" + } + } + }, + { + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',variables('_dataConnectorContentId1'))]", + "apiVersion": "2021-03-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectors", + "location": "[parameters('workspace-location')]", + "kind": "GenericUI", + "properties": { + "connectorUiConfig": { + "title": "ZeroFox CTI (using Azure Functions)", + "publisher": "ZeroFox", + "descriptionMarkdown": "The ZeroFox CTI data connectors provide the capability to ingest the different [ZeroFox](https://www.zerofox.com/threat-intelligence/) cyber threat intelligence alerts into Microsoft Sentinel.", + "graphQueries": [ + { + "metricName": "ZeroFox CTI Advanced Dark Web Logs", + "legend": "ZeroFox_CTI_advanced_dark_web_CL", + "baseQuery": "ZeroFox_CTI_advanced_dark_web_CL" + }, + { + "metricName": "ZeroFox CTI Botnet Logs", + "baseQuery": "ZeroFox_CTI_botnet_CL" + }, + { + "metricName": "ZeroFox CTI Breaches Logs", + "legend": "ZeroFox_CTI_breaches_CL", + "baseQuery": "ZeroFox_CTI_breaches_CL" + }, + { + "metricName": "ZeroFox CTI C2 Domains Logs", + "legend": "ZeroFox_CTI_C2_CL", + "baseQuery": "ZeroFox_CTI_C2_CL" + }, + { + "metricName": "ZeroFox CTI Compromised Credentials Logs", + "legend": "ZeroFox_CTI_compromised_credentials_CL", + "baseQuery": "ZeroFox_CTI_compromised_credentials_CL" + }, + { + "metricName": "ZeroFox CTI Credit Cards Logs", + "legend": "ZeroFox_CTI_credit_cards_CL", + "baseQuery": "ZeroFox_CTI_credit_cards_CL" + }, + { + "metricName": "ZeroFox CTI Dark Web Logs", + "legend": "ZeroFox_CTI_dark_web_CL", + "baseQuery": "ZeroFox_CTI_dark_web_CL" + }, + { + "metricName": "ZeroFox CTI Discord Logs", + "legend": "ZeroFox_CTI_discord_CL", + "baseQuery": "ZeroFox_CTI_discord_CL" + }, + { + "metricName": "ZeroFox CTI Disruption Logs", + "legend": "ZeroFox_CTI_disruption_CL", + "baseQuery": "ZeroFox_CTI_disruption_CL" + }, + { + "metricName": "ZeroFox CTI Email Addresses Logs", + "legend": "ZeroFox_CTI_email_addresses_CL", + "baseQuery": "ZeroFox_CTI_email_addresses_CL" + }, + { + "metricName": "ZeroFox CTI Exploits Logs", + "legend": "ZeroFox_CTI_exploits_CL", + "baseQuery": "ZeroFox_CTI_exploits_CL" + }, + { + "metricName": "ZeroFox CTI Identity Breach Logs", + "legend": "ZeroFox_CTI_identity_breach_CL", + "baseQuery": "ZeroFox_CTI_identity_breach_CL" + }, + { + "metricName": "ZeroFox CTI IRC Logs", + "legend": "ZeroFox_CTI_irc_CL", + "baseQuery": "ZeroFox_CTI_irc_CL" + }, + { + "metricName": "ZeroFox CTI Malware Logs", + "legend": "ZeroFox_CTI_malware_CL", + "baseQuery": "ZeroFox_CTI_malware_CL" + }, + { + "metricName": "ZeroFox CTI National Ids Logs", + "legend": "ZeroFox_CTI_national_ids_CL", + "baseQuery": "ZeroFox_CTI_national_ids_CL" + }, + { + "metricName": "ZeroFox CTI Phishing Logs", + "legend": "ZeroFox_CTI_phishing_CL", + "baseQuery": "ZeroFox_CTI_phishing_CL" + }, + { + "metricName": "ZeroFox CTI Phone Numbers Logs", + "legend": "ZeroFox_CTI_phone_numbers_CL", + "baseQuery": "ZeroFox_CTI_phone_numbers_CL" + }, + { + "metricName": "ZeroFox CTI Ransomware Logs", + "legend": "ZeroFox_CTI_ransomware_CL", + "baseQuery": "ZeroFox_CTI_ransomware_CL" + }, + { + "metricName": "ZeroFox CTI Telegram Logs", + "legend": "ZeroFox_CTI_telegram_CL", + "baseQuery": "ZeroFox_CTI_telegram_CL" + }, + { + "metricName": "ZeroFox CTI Threat Actors Logs", + "legend": "ZeroFox_CTI_threat_actors_CL", + "baseQuery": "ZeroFox_CTI_threat_actors_CL" + }, + { + "metricName": "ZeroFox CTI Vulnerabilities Logs", + "legend": "ZeroFox_CTI_vulnerabilities_CL", + "baseQuery": "ZeroFox_CTI_vulnerabilities_CL" + } + ], + "dataTypes": [ + { + "name": "ZeroFox_CTI_advanced_dark_web_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_advanced_dark_web_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_botnet_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_botnet_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_breaches_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_breaches_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_C2_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_C2_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_compromised_credentials_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_compromised_credentials_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_credit_cards_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_credit_cards_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_dark_web_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_dark_web_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_discord_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_discord_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_disruption_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_disruption_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_email_addresses_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_email_addresses_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_exploits_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_exploits_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_identity_breach_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_identity_breach_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_irc_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_irc_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_malware_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_malware_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_national_ids_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_national_ids_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_phishing_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_phishing_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_phone_numbers_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_phone_numbers_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_ransomware_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_ransomware_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_telegram_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_telegram_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_threat_actors_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_threat_actors_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + }, + { + "name": "ZeroFox_CTI_vulnerabilities_CL", + "lastDataReceivedQuery": "ZeroFox_CTI_vulnerabilities_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + } + ], + "connectivityCriterias": [ + { + "type": "IsConnectedQuery", + "value": [ + "ZeroFox_CTI_advanced_dark_web_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_botnet_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_breaches_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_C2_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_compromised_credentials_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_credit_cards_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_dark_web_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_discord_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_disruption_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_email_addresses_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_exploits_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_identity_breach_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_irc_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_malware_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_national_ids_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_phishing_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_phone_numbers_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_ransomware_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_telegram_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_threat_actors_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)", + "ZeroFox_CTI_vulnerabilities_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)" + ] + } + ], + "sampleQueries": [ + { + "description": "ZeroFox CTI C2-domains Logs", + "query": "ZeroFox_CTI_C2_CL\n | sort by TimeGenerated desc" + }, + { + "description": "ZeroFox CTI Email Addresses Logs", + "query": "ZeroFox_CTI_email_addresses_CL\n | sort by TimeGenerated desc" + }, + { + "description": "ZeroFox CTI Malware Logs", + "query": "ZeroFox_CTI_malware_CL\n | sort by TimeGenerated desc" + } + ], + "availability": { + "status": 1, + "isPreview": false + }, + "permissions": { + "resourceProvider": [ + { + "provider": "Microsoft.OperationalInsights/workspaces", + "permissionsDisplayText": "read and write permissions on the workspace are required.", + "providerDisplayName": "Workspace", + "scope": "Workspace", + "requiredPermissions": { + "write": true, + "read": true, + "delete": true + } + }, + { + "provider": "Microsoft.OperationalInsights/workspaces/sharedKeys", + "permissionsDisplayText": "read permissions to shared keys for the workspace are required. [See the documentation to learn more about workspace keys](https://docs.microsoft.com/azure/azure-monitor/platform/agent-windows#obtain-workspace-id-and-key).", + "providerDisplayName": "Keys", + "scope": "Workspace", + "requiredPermissions": { + "action": true + } + } + ], + "customs": [ + { + "name": "Microsoft.Web/sites permissions", + "description": "Read and write permissions to Azure Functions to create a Function App is required. [See the documentation to learn more about Azure Functions](https://docs.microsoft.com/azure/azure-functions/)." + }, + { + "name": "ZeroFox API Credentials/permissions", + "description": "**ZeroFox Username**, **ZeroFox Personal Access Token** are required for ZeroFox CTI REST API." + } + ] + }, + "instructionSteps": [ + { + "description": ">**NOTE:** This connector uses Azure Functions to connect to the ZeroFox CTI REST API to pull logs into Microsoft Sentinel. This might result in additional data ingestion costs. Check the [Azure Functions pricing page](https://azure.microsoft.com/pricing/details/functions/) for details." + }, + { + "description": ">**(Optional Step)** Securely store workspace and API authorization key(s) or token(s) in Azure Key Vault. Azure Key Vault provides a secure mechanism to store and retrieve key values. [Follow these instructions](https://docs.microsoft.com/azure/app-service/app-service-key-vault-references) to use Azure Key Vault with an Azure Function App." + }, + { + "description": "**STEP 1 - Retrieval of ZeroFox credentials:**\n\n Follow these instructions for set up logging and obtain credentials." + }, + { + "description": "**STEP 1.1 - [Log into ZeroFox's website.](https://cloud.zerofox.com/login) using your username and password" + }, + { + "description": "**STEP 1.2 - Click into the Settings button and go to the Data Connectors Section." + }, + { + "description": "**STEP 1.3 - Select the API DATA FEEDS tab and head to the bottom of the page, select <> in the API Information box, to obtain a Personal Access Token to be used along with your username." + }, + { + "description": "**STEP 2 - Choose ONE from the following two deployment options to deploy the connector and the associated Azure Function**\n\n>**IMPORTANT:** Before deploying the ZeroFox CTI data connector, have the Workspace ID and Workspace Primary Key (can be copied from the following), as well as the Amazon S3 REST API Authorization credentials, readily available.", + "instructions": [ + { + "parameters": { + "fillWith": [ + "WorkspaceId" + ], + "label": "Workspace ID" + }, + "type": "CopyableLabel" + }, + { + "parameters": { + "fillWith": [ + "PrimaryKey" + ], + "label": "Primary Key" + }, + "type": "CopyableLabel" + } + ] + }, + { + "description": "Use this method for automated deployment of the ZeroFox CTI data connectors using an ARM Tempate.\n\n1. Click the **Deploy to Azure** button below. \n\n\t[![Deploy To Azure](https://aka.ms/deploytoazurebutton)](https://aka.ms/sentinelCiscoUmbrellaazuredeploy)\n2. Select the preferred **Subscription**, **Resource Group** and **Location**. \n3. Enter the **Workspace ID**, **Workspace Key**, **ZeroFox Username**, **ZeroFox Personal Access Token**\n4. Mark the checkbox labeled **I agree to the terms and conditions stated above**.\n5. Click **Purchase** to deploy.", + "title": "Option 1 - Azure Resource Manager (ARM) Template" + }, + { + "description": "Use the following step-by-step instructions to deploy the ZeroFox CTI data connector manually with Azure Functions (Deployment via Visual Studio Code).", + "title": "Option 2 - Manual Deployment of Azure Functions" + }, + { + "description": "**1. Deploy a Function App**\n\n> **NOTE:** You will need to [prepare VS code](https://docs.microsoft.com/azure/azure-functions/create-first-function-vs-code-python) for Azure function development.\n\n1. Download the [Azure Function App](https://aka.ms/sentinel-ZeroFoxCTIConn-functionapp) file. Extract archive to your local development computer.\n2. Start VS Code. Choose File in the main menu and select Open Folder.\n3. Select the top level folder from extracted files.\n4. Choose the Azure icon in the Activity bar, then in the **Azure: Functions** area, choose the **Deploy to function app** button.\nIf you aren't already signed in, choose the Azure icon in the Activity bar, then in the **Azure: Functions** area, choose **Sign in to Azure**\nIf you're already signed in, go to the next step.\n5. Provide the following information at the prompts:\n\n\ta. **Select folder:** Choose a folder from your workspace or browse to one that contains your function app.\n\n\tb. **Select Subscription:** Choose the subscription to use.\n\n\tc. Select **Create new Function App in Azure** (Don't choose the Advanced option)\n\n\td. **Enter a globally unique name for the function app:** Type a name that is valid in a URL path. The name you type is validated to make sure that it's unique in Azure Functions. (e.g. CTIXYZ).\n\n\te. **Select a runtime:** Choose Python 3.8.\n\n\tf. Select a location for new resources. For better performance and lower costs choose the same [region](https://azure.microsoft.com/regions/) where Microsoft Sentinel is located.\n\n6. Deployment will begin. A notification is displayed after your function app is created and the deployment package is applied.\n7. Go to Azure Portal for the Function App configuration." + }, + { + "description": "**2. Configure the Function App**\n\n1. In the Function App, select the Function App Name and select **Configuration**.\n2. In the **Application settings** tab, select **+ New application setting**.\n3. Add each of the following application settings individually, with their respective string values (case-sensitive): \n\t\tWorkspaceID\n\t\tWorkspaceKey\n\t\tS3Bucket\n\t\tAWSAccessKeyId\n\t\tAWSSecretAccessKey\n\t\tlogAnalyticsUri (optional)\n> - Use logAnalyticsUri to override the log analytics API endpoint for dedicated cloud. For example, for public cloud, leave the value empty; for Azure GovUS cloud environment, specify the value in the following format: `https://.ods.opinsights.azure.us`.\n3. Once all application settings have been entered, click **Save**." + } + ], + "id": "[variables('_uiConfigId1')]" + } + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('dataConnectorTemplateSpecName2')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "ZeroFox data connector with template version 3.0.0", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('dataConnectorVersion2')]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',variables('_dataConnectorContentId2'))]", + "apiVersion": "2021-03-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectors", + "location": "[parameters('workspace-location')]", + "kind": "APIPolling", + "properties": { + "connectorUiConfig": { + "id": "[variables('_uiConfigId2')]", + "title": "ZeroFox Enterprise - Alerts (Polling CCP)", + "publisher": "ZeroFox Enterprise", + "descriptionMarkdown": "Collects alerts from ZeroFox API.", + "graphQueriesTableName": "ZeroFoxAlertPoller_CL", + "graphQueries": [ + { + "metricName": "Total alerts received", + "legend": "ZeroFox Alerts", + "baseQuery": "{{graphQueriesTableName}}" + } + ], + "sampleQueries": [ + { + "description": "List all ZeroFox alerts", + "query": "{{graphQueriesTableName}}\n| sort by TimeGenerated asc" + }, + { + "description": "Count alerts by network type", + "query": "{{graphQueriesTableName}}\n| summarize Count = count() by ThreatSource=network_s" + }, + { + "description": "Count alerts by entity", + "query": "{{graphQueriesTableName}}\n| summarize Count = count() by Entity=entity_name_s" + } + ], + "dataTypes": [ + { + "name": "{{graphQueriesTableName}}", + "lastDataReceivedQuery": "{{graphQueriesTableName}}\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + } + ], + "connectivityCriteria": [ + { + "type": "SentinelKindsV2", + "value": [ + "APIPolling" + ] + } + ], + "availability": { + "status": 1, + "isPreview": false + }, + "permissions": { + "resourceProvider": [ + { + "provider": "Microsoft.OperationalInsights/solutions", + "permissionsDisplayText": "read and write permissions are required.", + "providerDisplayName": "Workspace", + "scope": "Workspace", + "requiredPermissions": { + "action": true, + "write": true, + "read": true, + "delete": true + } + } + ], + "customs": [ + { + "name": "ZeroFox Personal Access Token (PAT)", + "description": "A ZeroFox PAT is required. You can get it in Data Connectors > [API Data Feeds](https://cloud.zerofox.com/data_connectors/api)." + } + ] + }, + "instructionSteps": [ + { + "description": "Provide your ZeroFox PAT", + "instructions": [ + { + "type": "APIKey" + } + ], + "title": "Connect ZeroFox to Microsoft Sentinel" + } + ] + }, + "pollingConfig": { + "auth": { + "authType": "APIKey", + "APIKeyName": "Authorization", + "APIKeyIdentifier": "Token" + }, + "request": { + "apiEndpoint": "https://api.zerofox.com/1.0/alerts/", + "httpMethod": "Get", + "queryTimeFormat": "yyyy-MM-ddTHH:mm:ssZ", + "startTimeAttributeName": "min_timestamp", + "endTimeAttributeName": "max_timestamp", + "queryParameters": { + "sort_direction": "asc" + } + }, + "response": { + "eventsJsonPaths": [ + "$.alerts[*]" + ] + }, + "paging": { + "pagingType": "Offset", + "offsetParaName": "offset", + "pageSizeParaName": "limit", + "pageSize": 100 + } + } + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('DataConnector-', last(split(variables('_dataConnectorId2'),'/'))))]", + "properties": { + "parentId": "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/dataConnectors', variables('_dataConnectorContentId2'))]", + "contentId": "[variables('_dataConnectorContentId2')]", + "kind": "DataConnector", + "version": "[variables('dataConnectorVersion2')]", + "source": { + "kind": "Solution", + "name": "ZeroFox", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Microsoft", + "email": "[variables('_email')]" + }, + "support": { + "tier": "Microsoft", + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "link": "https://support.microsoft.com/" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_dataConnectorContentId2')]", + "contentKind": "DataConnector", + "displayName": "ZeroFox Enterprise - Alerts (Polling CCP)", + "contentProductId": "[variables('_dataConnectorcontentProductId2')]", + "id": "[variables('_dataConnectorcontentProductId2')]", + "version": "[variables('dataConnectorVersion2')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('DataConnector-', last(split(variables('_dataConnectorId2'),'/'))))]", + "dependsOn": [ + "[variables('_dataConnectorId2')]" + ], + "location": "[parameters('workspace-location')]", + "properties": { + "parentId": "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/dataConnectors', variables('_dataConnectorContentId2'))]", + "contentId": "[variables('_dataConnectorContentId2')]", + "kind": "DataConnector", + "version": "[variables('dataConnectorVersion2')]", + "source": { + "kind": "Solution", + "name": "ZeroFox", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Microsoft", + "email": "[variables('_email')]" + }, + "support": { + "tier": "Microsoft", + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "link": "https://support.microsoft.com/" + } + } + }, + { + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',variables('_dataConnectorContentId2'))]", + "apiVersion": "2021-03-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectors", + "location": "[parameters('workspace-location')]", + "kind": "APIPolling", + "properties": { + "connectorUiConfig": { + "id": "[variables('_uiConfigId2')]", + "title": "ZeroFox Enterprise - Alerts (Polling CCP)", + "publisher": "ZeroFox Enterprise", + "descriptionMarkdown": "Collects alerts from ZeroFox API.", + "graphQueriesTableName": "ZeroFoxAlertPoller_CL", + "graphQueries": [ + { + "metricName": "Total alerts received", + "legend": "ZeroFox Alerts", + "baseQuery": "{{graphQueriesTableName}}" + } + ], + "sampleQueries": [ + { + "description": "List all ZeroFox alerts", + "query": "{{graphQueriesTableName}}\n| sort by TimeGenerated asc" + }, + { + "description": "Count alerts by network type", + "query": "{{graphQueriesTableName}}\n| summarize Count = count() by ThreatSource=network_s" + }, + { + "description": "Count alerts by entity", + "query": "{{graphQueriesTableName}}\n| summarize Count = count() by Entity=entity_name_s" + } + ], + "dataTypes": [ + { + "name": "{{graphQueriesTableName}}", + "lastDataReceivedQuery": "{{graphQueriesTableName}}\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + } + ], + "connectivityCriteria": [ + { + "type": "SentinelKindsV2", + "value": [ + "APIPolling" + ] + } + ], + "availability": { + "status": 1, + "isPreview": false + }, + "permissions": { + "resourceProvider": [ + { + "provider": "Microsoft.OperationalInsights/solutions", + "permissionsDisplayText": "read and write permissions are required.", + "providerDisplayName": "Workspace", + "scope": "Workspace", + "requiredPermissions": { + "action": true, + "write": true, + "read": true, + "delete": true + } + } + ], + "customs": [ + { + "name": "ZeroFox Personal Access Token (PAT)", + "description": "A ZeroFox PAT is required. You can get it in Data Connectors > [API Data Feeds](https://cloud.zerofox.com/data_connectors/api)." + } + ] + }, + "instructionSteps": [ + { + "description": "Provide your ZeroFox PAT", + "instructions": [ + { + "type": "APIKey" + } + ], + "title": "Connect ZeroFox to Microsoft Sentinel" + } + ] + }, + "pollingConfig": { + "auth": { + "authType": "APIKey", + "APIKeyName": "Authorization", + "APIKeyIdentifier": "Token" + }, + "request": { + "apiEndpoint": "https://api.zerofox.com/1.0/alerts/", + "httpMethod": "Get", + "queryTimeFormat": "yyyy-MM-ddTHH:mm:ssZ", + "startTimeAttributeName": "min_timestamp", + "endTimeAttributeName": "max_timestamp", + "queryParameters": { + "sort_direction": "asc" + } + }, + "response": { + "eventsJsonPaths": [ + "$.alerts[*]" + ] + }, + "paging": { + "pagingType": "Offset", + "offsetParaName": "offset", + "pageSizeParaName": "limit", + "pageSize": 100 + } + } + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleTemplateSpecName1')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "ZF_Alerts_HighSeverityRule_AnalyticalRules Analytics Rule with template version 3.0.0", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleVersion1')]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId1')]", + "apiVersion": "2022-04-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "Detects high severity alerts from ZeroFox", + "displayName": "ZeroFox Alerts - High Severity Alerts", + "enabled": false, + "query": "ZeroFoxAlertPoller_CL\n| where Severity in (5)\n", + "queryFrequency": "PT5M", + "queryPeriod": "PT5M", + "severity": "High", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "ZeroFox_Alert_Polling", + "dataTypes": [ + "ZeroFoxAlertPoller_CL" + ] + } + ], + "tactics": [ + "ResourceDevelopment", + "InitialAccess" + ], + "techniques": [ + "T1583", + "T1586", + "T1566" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "entity_name_s", + "identifier": "FullName" + } + ], + "entityType": "Account" + } + ], + "eventGroupingSettings": { + "aggregationKind": "AlertPerResult" + } + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId1'),'/'))))]", + "properties": { + "description": "ZeroFox Analytics Rule 1", + "parentId": "[variables('analyticRuleId1')]", + "contentId": "[variables('_analyticRulecontentId1')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion1')]", + "source": { + "kind": "Solution", + "name": "ZeroFox", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Microsoft", + "email": "[variables('_email')]" + }, + "support": { + "tier": "Microsoft", + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "link": "https://support.microsoft.com/" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_analyticRulecontentId1')]", + "contentKind": "AnalyticsRule", + "displayName": "ZeroFox Alerts - High Severity Alerts", + "contentProductId": "[variables('_analyticRulecontentProductId1')]", + "id": "[variables('_analyticRulecontentProductId1')]", + "version": "[variables('analyticRuleVersion1')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleTemplateSpecName2')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "ZF_Alerts_InformationalSeverityRule_AnalyticalRules Analytics Rule with template version 3.0.0", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleVersion2')]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId2')]", + "apiVersion": "2022-04-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "Detects informational severity alerts from ZeroFox", + "displayName": "ZeroFox Alerts - Informational Severity Alerts", + "enabled": false, + "query": "ZeroFoxAlertPoller_CL\n| where Severity in (1,2)\n", + "queryFrequency": "PT5M", + "queryPeriod": "PT5M", + "severity": "Informational", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "ZeroFox_Alert_Polling", + "dataTypes": [ + "ZeroFoxAlertPoller_CL" + ] + } + ], + "tactics": [ + "ResourceDevelopment", + "InitialAccess" + ], + "techniques": [ + "T1583", + "T1586", + "T1566" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "entity_name_s", + "identifier": "FullName" + } + ], + "entityType": "Account" + } + ], + "eventGroupingSettings": { + "aggregationKind": "AlertPerResult" + } + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId2'),'/'))))]", + "properties": { + "description": "ZeroFox Analytics Rule 2", + "parentId": "[variables('analyticRuleId2')]", + "contentId": "[variables('_analyticRulecontentId2')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion2')]", + "source": { + "kind": "Solution", + "name": "ZeroFox", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Microsoft", + "email": "[variables('_email')]" + }, + "support": { + "tier": "Microsoft", + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "link": "https://support.microsoft.com/" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_analyticRulecontentId2')]", + "contentKind": "AnalyticsRule", + "displayName": "ZeroFox Alerts - Informational Severity Alerts", + "contentProductId": "[variables('_analyticRulecontentProductId2')]", + "id": "[variables('_analyticRulecontentProductId2')]", + "version": "[variables('analyticRuleVersion2')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleTemplateSpecName3')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "ZF_Alerts_LowSeverityRule_AnalyticalRules Analytics Rule with template version 3.0.0", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleVersion3')]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId3')]", + "apiVersion": "2022-04-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "Detects low severity alerts from ZeroFox", + "displayName": "ZeroFox Alerts - Low Severity Alerts", + "enabled": false, + "query": "ZeroFoxAlertPoller_CL\n| where Severity in (3)\n", + "queryFrequency": "PT5M", + "queryPeriod": "PT5M", + "severity": "Low", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "ZeroFox_Alert_Polling", + "dataTypes": [ + "ZeroFoxAlertPoller_CL" + ] + } + ], + "tactics": [ + "ResourceDevelopment", + "InitialAccess" + ], + "techniques": [ + "T1583", + "T1586", + "T1566" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "entity_name_s", + "identifier": "FullName" + } + ], + "entityType": "Account" + } + ], + "eventGroupingSettings": { + "aggregationKind": "AlertPerResult" + } + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId3'),'/'))))]", + "properties": { + "description": "ZeroFox Analytics Rule 3", + "parentId": "[variables('analyticRuleId3')]", + "contentId": "[variables('_analyticRulecontentId3')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion3')]", + "source": { + "kind": "Solution", + "name": "ZeroFox", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Microsoft", + "email": "[variables('_email')]" + }, + "support": { + "tier": "Microsoft", + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "link": "https://support.microsoft.com/" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_analyticRulecontentId3')]", + "contentKind": "AnalyticsRule", + "displayName": "ZeroFox Alerts - Low Severity Alerts", + "contentProductId": "[variables('_analyticRulecontentProductId3')]", + "id": "[variables('_analyticRulecontentProductId3')]", + "version": "[variables('analyticRuleVersion3')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleTemplateSpecName4')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "ZF_Alerts_MediumSeverityRule_AnalyticalRules Analytics Rule with template version 3.0.0", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleVersion4')]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId4')]", + "apiVersion": "2022-04-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "Detects medium severity alerts from ZeroFox", + "displayName": "ZeroFox Alerts - Medium Severity Alerts", + "enabled": false, + "query": "ZeroFoxAlertPoller_CL\n| where Severity in (4)\n", + "queryFrequency": "PT5M", + "queryPeriod": "PT5M", + "severity": "Medium", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "ZeroFox_Alert_Polling", + "dataTypes": [ + "ZeroFoxAlertPoller_CL" + ] + } + ], + "tactics": [ + "ResourceDevelopment", + "InitialAccess" + ], + "techniques": [ + "T1583", + "T1586", + "T1566" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "entity_name_s", + "identifier": "FullName" + } + ], + "entityType": "Account" + } + ], + "eventGroupingSettings": { + "aggregationKind": "AlertPerResult" + } + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId4'),'/'))))]", + "properties": { + "description": "ZeroFox Analytics Rule 4", + "parentId": "[variables('analyticRuleId4')]", + "contentId": "[variables('_analyticRulecontentId4')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion4')]", + "source": { + "kind": "Solution", + "name": "ZeroFox", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Microsoft", + "email": "[variables('_email')]" + }, + "support": { + "tier": "Microsoft", + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "link": "https://support.microsoft.com/" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_analyticRulecontentId4')]", + "contentKind": "AnalyticsRule", + "displayName": "ZeroFox Alerts - Medium Severity Alerts", + "contentProductId": "[variables('_analyticRulecontentProductId4')]", + "id": "[variables('_analyticRulecontentProductId4')]", + "version": "[variables('analyticRuleVersion4')]" + } + }, + { + "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": "ZeroFox", + "publisherDisplayName": "Microsoft Sentinel, Microsoft Corporation", + "descriptionHtml": "

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

\n

The ZeroFox solution for Microsoft Sentinel enables you to ingest ZeroFox Alerts and [ZeroFox CTI events]](https://www.zerofox.com/threat-intelligence/) into Microsoft Sentinel using the ZeroFox API.

\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. Azure Monitor HTTP Data Collector API

    \n
  2. \n
  3. Azure Functions

    \n
  4. \n
\n

Data Connectors: 2, Analytic Rules: 4

\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": "ZeroFox", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Microsoft", + "email": "[variables('_email')]" + }, + "support": { + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "tier": "Microsoft", + "link": "https://support.microsoft.com/" + }, + "dependencies": { + "operator": "AND", + "criteria": [ + { + "kind": "DataConnector", + "contentId": "[variables('_dataConnectorContentId1')]", + "version": "[variables('dataConnectorVersion1')]" + }, + { + "kind": "DataConnector", + "contentId": "[variables('_dataConnectorContentId2')]", + "version": "[variables('dataConnectorVersion2')]" + }, + { + "kind": "AnalyticsRule", + "contentId": "[variables('analyticRulecontentId1')]", + "version": "[variables('analyticRuleVersion1')]" + }, + { + "kind": "AnalyticsRule", + "contentId": "[variables('analyticRulecontentId2')]", + "version": "[variables('analyticRuleVersion2')]" + }, + { + "kind": "AnalyticsRule", + "contentId": "[variables('analyticRulecontentId3')]", + "version": "[variables('analyticRuleVersion3')]" + }, + { + "kind": "AnalyticsRule", + "contentId": "[variables('analyticRulecontentId4')]", + "version": "[variables('analyticRuleVersion4')]" + } + ] + }, + "firstPublishDate": "2023-07-28", + "providers": [ + "ZeroFox" + ], + "categories": { + "domains": [ + "Security - Threat Protection", + "Security - Automation (SOAR)" + ] + } + }, + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/', variables('_solutionId'))]" + } + ], + "outputs": {} +} diff --git a/Solutions/ZeroFox/ReleaseNotes.md b/Solutions/ZeroFox/ReleaseNotes.md new file mode 100644 index 00000000000..869ddfa7c38 --- /dev/null +++ b/Solutions/ZeroFox/ReleaseNotes.md @@ -0,0 +1,3 @@ +| **Version** | **Date Modified (DD-MM-YYYY)** | **Change History** | +|-------------|--------------------------------|---------------------------------------------| +| 3.0.0 | 04-08-2023 | **Data Connector** Added Data Connectors for ZeroFox's Alerts and CTI feeds \ No newline at end of file diff --git a/Solutions/ZeroFox/SolutionMetadata.json b/Solutions/ZeroFox/SolutionMetadata.json new file mode 100644 index 00000000000..51193dd17d5 --- /dev/null +++ b/Solutions/ZeroFox/SolutionMetadata.json @@ -0,0 +1,16 @@ +{ + "publisherId": "azuresentinel", + "offerId": "azure-sentinel-solution-zerofox", + "firstPublishDate": "2023-07-28", + "providers": [ "ZeroFox" ], + "categories": { + "domains" : ["Security - Threat Protection","Security - Automation (SOAR)"], + "verticals": [] + }, + "support": { + "tier": "Microsoft", + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "link": "https://support.microsoft.com/" + } +} \ No newline at end of file