From 1cbcd51ffd13eeec6ee433ceef4568dc50783189 Mon Sep 17 00:00:00 2001 From: akozlovets098 Date: Wed, 2 Oct 2024 18:28:21 +0300 Subject: [PATCH 1/4] THREAT-397 Reformat deep_get(event to event.deep_get( --- .scripts/mitre_mapping_check.py | 33 +++++++++------- global_helpers/gcp_base_helpers.py | 23 +++++------ global_helpers/global_filter_auth0.py | 5 +-- global_helpers/global_filter_azuresignin.py | 5 +-- global_helpers/global_filter_cloudflare.py | 3 -- global_helpers/global_filter_github.py | 5 +-- global_helpers/global_filter_notion.py | 5 +-- global_helpers/global_filter_snyk.py | 5 +-- global_helpers/global_filter_tailscale.py | 5 +-- global_helpers/global_filter_tines.py | 5 +-- global_helpers/panther_asana_helpers.py | 21 +++++----- global_helpers/panther_auth0_helpers.py | 11 ++---- global_helpers/panther_azuresignin_helpers.py | 21 +++++----- global_helpers/panther_base_helpers.py | 32 +++++++-------- global_helpers/panther_greynoise_helpers.py | 5 +-- global_helpers/panther_ipinfo_helpers.py | 6 +-- global_helpers/panther_lookuptable_helpers.py | 2 +- global_helpers/panther_notion_helpers.py | 7 +--- global_helpers/panther_tailscale_helpers.py | 9 ++--- ...ation_from_crowdstrike_unmanaged_device.py | 2 +- ...login_from_crowdstrike_unmanaged_device.py | 5 +-- ...login_from_crowdstrike_unmanaged_device.py | 5 +-- .../asana_service_account_created.py | 7 +--- .../asana_rules/asana_team_privacy_public.py | 9 ++--- ...orkspace_default_session_duration_never.py | 9 ++--- .../asana_workspace_email_domain_added.py | 9 ++--- ...ace_form_link_auth_requirement_disabled.py | 7 +--- ...rkspace_guest_invite_permissions_anyone.py | 9 ++--- .../asana_rules/asana_workspace_new_admin.py | 7 ++-- .../asana_rules/asana_workspace_org_export.py | 7 +--- ..._workspace_password_requirements_simple.py | 11 ++---- ...orkspace_require_app_approvals_disabled.py | 9 ++--- .../asana_workspace_saml_optional.py | 9 ++--- .../atlassian_rules/user_logged_in_as_user.py | 15 +++---- .../auth0_rules/auth0_custom_role_created.py | 25 ++++++------ .../auth0_integration_installed.py | 13 +++---- .../auth0_mfa_factor_setting_enabled.py | 13 +++---- .../auth0_rules/auth0_mfa_policy_disabled.py | 15 ++++--- rules/auth0_rules/auth0_mfa_policy_enabled.py | 13 +++---- .../auth0_mfa_risk_assessment_disabled.py | 17 ++++---- .../auth0_mfa_risk_assessment_enabled.py | 17 ++++---- .../auth0_post_login_action_flow.py | 18 ++++----- .../auth0_user_invitation_created.py | 13 +++---- rules/auth0_rules/auth0_user_joined_tenant.py | 14 +++---- .../aws_ami_modified_for_public_access.py | 6 +-- .../aws_cloudtrail_account_discovery.py | 4 +- .../aws_cloudtrail_created.py | 4 +- ...loudtrail_loginprofilecreatedormodified.py | 10 ++--- ...ws_cloudtrail_password_policy_discovery.py | 4 +- .../aws_cloudtrail_stopped.py | 4 +- ...aws_cloudtrail_unsuccessful_mfa_attempt.py | 10 ++--- .../aws_codebuild_made_public.py | 8 ++-- .../aws_console_login_failed.py | 6 +-- .../aws_console_login_without_mfa.py | 20 +++++----- .../aws_console_login_without_saml.py | 4 +- .../aws_console_root_login.py | 11 +++--- .../aws_console_root_login_failed.py | 6 +-- .../aws_ec2_manual_security_group_changes.py | 10 ++--- .../aws_ec2_monitoring.py | 10 ++--- .../aws_ec2_startup_script_change.py | 14 +++---- .../aws_ec2_traffic_mirroring.py | 4 +- rules/aws_cloudtrail_rules/aws_ecr_crud.py | 8 ++-- rules/aws_cloudtrail_rules/aws_ecr_events.py | 4 +- .../aws_iam_assume_role_blocklist_ignored.py | 6 +-- ...m_entity_created_without_cloudformation.py | 8 ++-- .../aws_iam_user_key_created.py | 12 +++--- .../aws_iam_user_recon_denied.py | 10 ++--- .../aws_key_compromised.py | 6 +-- rules/aws_cloudtrail_rules/aws_lambda_crud.py | 8 ++-- .../aws_cloudtrail_rules/aws_macie_evasion.py | 4 +- ...aws_modify_cloud_compute_infrastructure.py | 16 ++++---- .../aws_network_acl_permissive_entry.py | 8 ++-- .../aws_rds_master_pass_updated.py | 9 +---- .../aws_rds_publicrestore.py | 4 +- .../aws_resource_made_public.py | 3 +- .../aws_root_access_key_created.py | 4 +- .../aws_cloudtrail_rules/aws_root_activity.py | 11 +++--- .../aws_root_console_login.py | 6 +-- .../aws_root_failed_console_login.py | 6 +-- .../aws_root_password_changed.py | 6 +-- .../aws_s3_activity_greynoise.py | 10 ++--- .../aws_s3_bucket_deleted.py | 4 +- .../aws_s3_bucket_policy_modified.py | 4 +- .../aws_cloudtrail_rules/aws_saml_activity.py | 6 +-- .../aws_security_configuration_change.py | 11 +++--- .../aws_snapshot_backup_exfiltration.py | 6 +-- .../aws_software_discovery.py | 6 +-- .../aws_unauthorized_api_call.py | 6 +-- .../aws_cloudtrail_rules/aws_unused_region.py | 4 +- .../aws_update_credentials.py | 6 +-- .../aws_user_login_profile_modified.py | 12 +++--- .../aws_waf_disassociation.py | 9 ++--- .../system_namespace_public_ip.py | 4 +- .../aws_guardduty_high_sev_findings.py | 4 +- .../aws_guardduty_low_sev_findings.py | 4 +- .../aws_guardduty_med_sev_findings.py | 4 +- .../azure_failed_signins.py | 3 +- rules/azure_signin_rules/azure_legacyauth.py | 7 ++-- .../azure_risklevel_passthrough.py | 7 ++-- rules/box_rules/box_access_granted.py | 5 +-- rules/box_rules/box_anomalous_download.py | 2 +- rules/box_rules/box_brute_force_login.py | 5 +-- .../box_event_triggered_externally.py | 3 +- rules/box_rules/box_item_shared_externally.py | 12 +++--- rules/box_rules/box_malicious_content.py | 4 +- rules/box_rules/box_new_login.py | 5 +-- rules/box_rules/box_policy_violation.py | 4 +- rules/box_rules/box_untrusted_device.py | 5 +-- rules/box_rules/box_user_downloads.py | 5 +-- .../box_rules/box_user_permission_updates.py | 4 +- .../dropbox_admin_sign_in_as_session.py | 9 ++--- rules/dropbox_rules/dropbox_external_share.py | 5 +-- .../dropbox_linked_team_application_added.py | 23 +++++------ .../dropbox_ownership_transfer.py | 13 +++---- .../dropbox_user_disabled_2fa.py | 11 ++---- rules/duo_rules/duo_user_action_fraudulent.py | 15 +++---- rules/duo_rules/duo_user_anomalous_push.py | 15 +++---- rules/duo_rules/duo_user_bypass_code_used.py | 15 +++---- .../duo_user_endpoint_failure_multi.py | 15 +++---- ...attempts_violating_vpc_service_controls.py | 17 ++++---- .../gcp_bigquery_large_scan.py | 30 ++++++-------- .../gcp_cloud_run_service_created.py | 16 ++++---- .../gcp_cloud_run_set_iam_policy.py | 20 +++++----- ...oud_storage_buckets_modified_or_deleted.py | 16 ++++---- ...oudbuild_potential_privilege_escalation.py | 13 +++---- .../gcp_cloudfunctions_functions_create.py | 11 +++--- .../gcp_cloudfunctions_functions_update.py | 11 +++--- ...teinstances_create_privilege_escalation.py | 17 ++++---- .../gcp_destructive_queries.py | 39 +++++++------------ .../gcp_dns_zone_modified_or_deleted.py | 9 ++--- .../gcp_firewall_rule_created.py | 13 +++---- .../gcp_firewall_rule_deleted.py | 13 +++---- .../gcp_firewall_rule_modified.py | 9 ++--- rules/gcp_audit_rules/gcp_gcs_iam_changes.py | 9 ++--- rules/gcp_audit_rules/gcp_gcs_public.py | 6 +-- .../gcp_iam_admin_role_assigned.py | 4 +- rules/gcp_audit_rules/gcp_iam_corp_email.py | 6 +-- .../gcp_iam_custom_role_changes.py | 8 ++-- .../gcp_iam_org_folder_changes.py | 15 +++---- ...p_iam_roles_update_privilege_escalation.py | 11 +++--- .../gcp_iam_service_account_key_create.py | 11 +++--- ...s_get_access_token_privilege_escalation.py | 5 +-- .../gcp_iam_service_accounts_sign_blob.py | 9 ++--- .../gcp_iam_serviceaccounts_signjwt.py | 17 ++++---- .../gcp_log_bucket_or_sink_deleted.py | 12 +++--- .../gcp_logging_settings_modified.py | 20 ++++------ .../gcp_logging_sink_modified.py | 10 ++--- ...to_create_or_manage_service_account_key.py | 26 ++++++------- ...vilege_escalation_by_deployments_create.py | 11 +++--- .../gcp_service_account_access_denied.py | 7 ++-- .../gcp_service_account_or_keys_created.py | 21 +++++----- ...age_apikeys_create_privilege_escalation.py | 11 +++--- .../gcp_audit_rules/gcp_sql_config_changes.py | 7 +--- rules/gcp_audit_rules/gcp_unused_regions.py | 4 +- ...gcp_user_added_to_iap_protected_service.py | 13 +++---- .../gcp_vpc_flow_logs_disabled.py | 13 +++---- ..._attempts_violating_iap_access_controls.py | 15 +++---- .../gcp_k8s_cron_job_created_or_modified.py | 11 +++--- rules/gcp_k8s_rules/gcp_k8s_exec_into_pod.py | 4 +- rules/gcp_k8s_rules/gcp_k8s_ioc_activity.py | 15 ++++--- .../gcp_k8s_new_daemonset_deployed.py | 11 +++--- ...p_k8s_pod_attached_to_node_host_network.py | 11 +++--- ...od_create_or_modify_host_path_vol_mount.py | 27 +++++++------ .../gcp_k8s_pod_using_host_pid_namespace.py | 13 +++---- .../gcp_k8s_privileged_pod_created.py | 24 ++++++------ ...gcp_k8s_service_type_node_port_deployed.py | 17 ++++---- rules/github_rules/github_webhook_modified.py | 6 +-- ...e_workspace_advanced_protection_program.py | 5 +-- ...le_workspace_apps_marketplace_allowlist.py | 15 +++---- .../gsuite_advanced_protection.py | 7 +--- .../gsuite_brute_force_login.py | 5 +-- .../gsuite_calendar_made_public.py | 9 ++--- .../gsuite_doc_ownership_transfer.py | 5 +-- .../gsuite_external_forwarding.py | 11 ++---- .../gsuite_google_access.py | 5 +-- .../gsuite_gov_attack.py | 7 +--- .../gsuite_group_banned_user.py | 7 +--- .../gsuite_leaked_password.py | 6 +-- .../gsuite_login_type.py | 8 ++-- .../gsuite_mobile_device_compromise.py | 9 ++--- ...gsuite_mobile_device_screen_unlock_fail.py | 8 ++-- ...suite_mobile_device_suspicious_activity.py | 7 +--- .../gsuite_passthrough_rule.py | 15 +++---- .../gsuite_permissions_delegated.py | 10 ++--- .../gsuite_suspicious_logins.py | 6 +-- .../gsuite_two_step_verification.py | 7 +--- .../gsuite_user_suspended.py | 6 +-- ...ite_workspace_calendar_external_sharing.py | 13 +++---- .../gsuite_workspace_data_export_created.py | 5 +-- ...te_workspace_gmail_default_routing_rule.py | 7 +--- ...ace_gmail_enhanced_predelivery_scanning.py | 15 +++---- ...rkspace_gmail_security_sandbox_disabled.py | 15 +++---- ...kspace_password_enforce_strong_disabled.py | 11 ++---- ...gsuite_workspace_password_reuse_enabled.py | 11 ++---- ...ite_workspace_trusted_domains_allowlist.py | 7 +--- .../gsuite_drive_external_share.py | 8 ++-- .../gsuite_drive_overly_visible.py | 11 +++--- .../gsuite_drive_visibility_change.py | 9 ++--- .../mongodb_atlas_api_key_created.py | 13 +++---- .../mongodb_external_user_invited.py | 5 +-- .../netskope_unauthorized_api_calls.py | 5 +-- .../notion_page_view_impossible_travel.py | 6 +-- ...ettings_enforce_saml_sso_config_updated.py | 7 +--- ...orkspace_settings_public_homepage_added.py | 7 +--- rules/okta_rules/okta_admin_role_assigned.py | 20 +++++----- .../okta_rules/okta_anonymizing_vpn_login.py | 12 +++--- rules/okta_rules/okta_api_key_created.py | 6 +-- rules/okta_rules/okta_api_key_revoked.py | 6 +-- .../okta_app_unauthorized_access_attempt.py | 4 +- rules/okta_rules/okta_brute_force_logins.py | 8 ++-- .../okta_rules/okta_geo_improbable_access.py | 20 +++++----- rules/okta_rules/okta_idp_create_modify.py | 10 ++--- rules/okta_rules/okta_idp_signin.py | 10 ++--- ...ta_new_behavior_accessing_admin_console.py | 22 +++++------ .../okta_org2org_creation_modification.py | 12 +++--- rules/okta_rules/okta_password_accessed.py | 8 ++-- .../okta_password_extraction_via_scim.py | 14 +++---- ...ta_phishing_attempt_blocked_by_fastpass.py | 10 ++--- .../okta_potentially_stolen_session.py | 30 +++++++------- rules/okta_rules/okta_support_reset.py | 10 ++--- ..._threatinsight_security_threat_detected.py | 4 +- .../onepassword_lut_sensitive_item_access.py | 12 +++--- .../onepassword_sensitive_item_access.py | 10 ++--- .../onepassword_unusual_client.py | 12 +++--- .../osquery_linux_aws_commands.py | 8 ++-- .../osquery_linux_logins_non_office.py | 8 ++-- .../osquery_mac_application_firewall.py | 6 +-- .../osquery_mac_enable_auto_update.py | 9 ++--- ...osquery_mac_osx_attacks_keyboard_events.py | 6 +-- rules/osquery_rules/osquery_outdated.py | 6 +-- rules/osquery_rules/osquery_outdated_macos.py | 6 +-- rules/osquery_rules/osquery_ssh_listener.py | 5 +-- .../osquery_rules/osquery_suspicious_cron.py | 4 +- .../panther_detection_deleted.py | 6 +-- .../panther_sensitive_role_created.py | 11 +++--- .../panther_sensitive_role_created.yml | 2 +- .../panther_user_modified.py | 11 +++--- .../sentinelone_alert_passthrough.py | 8 ++-- .../sentinelone_rules/sentinelone_threats.py | 10 ++--- .../slack_rules/slack_app_access_expanded.py | 16 ++++---- rules/slack_rules/slack_app_added.py | 14 +++---- rules/slack_rules/slack_app_removed.py | 6 +-- rules/slack_rules/slack_application_dos.py | 4 +- .../slack_legal_hold_policy_modified.py | 4 +- .../slack_privilege_changed_to_user.py | 6 +-- .../slack_user_privilege_escalation.py | 10 ++--- .../standard_rules/impossible_travel_login.py | 6 +-- .../tailscale_https_disabled.py | 11 +++--- ..._machine_approval_requirements_disabled.py | 9 ++--- .../tailscale_magicdns_disabled.py | 11 +++--- .../tines_actions_disabled_changes.py | 7 ++-- rules/tines_rules/tines_custom_ca.py | 11 +++--- .../tines_enqueued_retrying_job_deletion.py | 9 ++--- .../tines_global_resource_destruction.py | 9 ++--- rules/tines_rules/tines_sso_settings.py | 11 +++--- .../tines_story_items_destruction.py | 9 ++--- .../tines_rules/tines_story_jobs_clearance.py | 9 ++--- rules/tines_rules/tines_team_destruction.py | 9 ++--- rules/tines_rules/tines_tenant_authtoken.py | 17 ++++---- templates/example_rule.py | 4 +- 260 files changed, 1086 insertions(+), 1461 deletions(-) diff --git a/.scripts/mitre_mapping_check.py b/.scripts/mitre_mapping_check.py index d856ec7a7..0f5d0e91c 100644 --- a/.scripts/mitre_mapping_check.py +++ b/.scripts/mitre_mapping_check.py @@ -11,28 +11,26 @@ # All MITRE Tags must match this regex pattern MITRE_PATTERN = re.compile("^TA\d+\:T\d+(\.\d+)?$") + def main(path: Path) -> bool: # Load Repo analysis_items = load_analysis_specs([path], ignore_files=[]) - items_with_invalid_mappings = [] # Record all items with bad tags + items_with_invalid_mappings = [] # Record all items with bad tags for analysis_item in analysis_items: - rel_path = analysis_item[0] # Relative path to YAML file - spec = analysis_item[2] # YAML spec as a dict + rel_path = analysis_item[0] # Relative path to YAML file + spec = analysis_item[2] # YAML spec as a dict - bad_tags = [] # Record the invalid tags for this analysis item + bad_tags = [] # Record the invalid tags for this analysis item if reports := spec.get("Reports"): if mitre := reports.get("MITRE ATT&CK"): for mapping in mitre: if not MITRE_PATTERN.match(mapping): bad_tags.append(mapping) - + if bad_tags: - items_with_invalid_mappings.append({ - "rel_path": rel_path, - "bad_tags": bad_tags - }) - + items_with_invalid_mappings.append({"rel_path": rel_path, "bad_tags": bad_tags}) + if items_with_invalid_mappings: print("❌ Some items had invalid MITRE mapping formats:") print() @@ -42,16 +40,21 @@ def main(path: Path) -> bool: print("\t" + bad_tag) print() - print(("To ensure that your MITRE mappings are correctly displayed in the Panther " - "console, make sure your MITRE mappings are formatted like 'TA0000:T0000'.")) + print( + ( + "To ensure that your MITRE mappings are correctly displayed in the Panther " + "console, make sure your MITRE mappings are formatted like 'TA0000:T0000'." + ) + ) else: print("✅ No invalid MITRE mappings found! You're in the clear! 👍") - + return bool(items_with_invalid_mappings) + if __name__ == "__main__": - path = Path.cwd() # Default to current directory + path = Path.cwd() # Default to current directory if len(sys.argv) > 1: path = Path(sys.argv[1]) if main(path): - exit(1) # Exit with error if issues were found \ No newline at end of file + exit(1) # Exit with error if issues were found diff --git a/global_helpers/gcp_base_helpers.py b/global_helpers/gcp_base_helpers.py index d085fc458..82246a21f 100644 --- a/global_helpers/gcp_base_helpers.py +++ b/global_helpers/gcp_base_helpers.py @@ -1,6 +1,3 @@ -from panther_base_helpers import deep_get - - def get_info(event): fields = { "principal": "protoPayload.authenticationInfo.principalEmail", @@ -9,7 +6,7 @@ def get_info(event): "user_agent": "protoPayload.requestMetadata.callerSuppliedUserAgent", "method_name": "protoPayload.methodName", } - return {name: deep_get(event, *(path.split("."))) for name, path in fields.items()} + return {name: event.deep_get(*(path.split("."))) for name, path in fields.items()} def get_k8s_info(event): @@ -17,7 +14,7 @@ def get_k8s_info(event): Get GCP K8s info such as pod, authorized user etc. return a tuple of strings """ - pod_slug = deep_get(event, "protoPayload", "resourceName") + pod_slug = event.deep_get("protoPayload", "resourceName") # core/v1/namespaces//pods// _, _, _, namespace, _, pod, _ = pod_slug.split("/") return get_info(event) | {"namespace": namespace, "pod": pod} @@ -33,17 +30,17 @@ def get_flow_log_info(event): "bytes_sent": "jsonPayload.bytes_sent", "reporter": "jsonPayload.reporter", } - return {name: deep_get(event, *(path.split("."))) for name, path in fields.items()} + return {name: event.deep_get(*(path.split("."))) for name, path in fields.items()} def gcp_alert_context(event): return { - "project": deep_get(event, "resource", "labels", "project_id", default=""), - "principal": deep_get( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + "project": event.deep_get("resource", "labels", "project_id", default=""), + "principal": event.deep_get( + "protoPayload", "authenticationInfo", "principalEmail", default="" ), - "caller_ip": deep_get(event, "protoPayload", "requestMetadata", "callerIP", default=""), - "methodName": deep_get(event, "protoPayload", "methodName", default=""), - "resourceName": deep_get(event, "protoPayload", "resourceName", default=""), - "serviceName": deep_get(event, "protoPayload", "serviceName", default=""), + "caller_ip": event.deep_get("protoPayload", "requestMetadata", "callerIP", default=""), + "methodName": event.deep_get("protoPayload", "methodName", default=""), + "resourceName": event.deep_get("protoPayload", "resourceName", default=""), + "serviceName": event.deep_get("protoPayload", "serviceName", default=""), } diff --git a/global_helpers/global_filter_auth0.py b/global_helpers/global_filter_auth0.py index 1ebcffd20..dc240a1bb 100644 --- a/global_helpers/global_filter_auth0.py +++ b/global_helpers/global_filter_auth0.py @@ -1,6 +1,3 @@ -from panther_base_helpers import deep_get # pylint: disable=unused-import - - def filter_include_event(event) -> bool: # pylint: disable=unused-argument """ filter_include_event provides a global include filter for all Auth0 detections @@ -20,7 +17,7 @@ def filter_include_event(event) -> bool: # pylint: disable=unused-argument # # not all Auth0 enterprise events have org # # example: request domain # # if we don't know the request_domain, we want default behavior to be to alert on this event. - # request_domain = deep_get(event, "data", "details", "request", "channel", default="") + # request_domain = event.deep_get("data", "details", "request", "channel", default="") # return request_domain in ["https://manage.auth0.com/", "https://mycompany.auth0.com", ""] # return True diff --git a/global_helpers/global_filter_azuresignin.py b/global_helpers/global_filter_azuresignin.py index a98ad8da8..60354bd8c 100644 --- a/global_helpers/global_filter_azuresignin.py +++ b/global_helpers/global_filter_azuresignin.py @@ -1,6 +1,3 @@ -from panther_base_helpers import deep_get # pylint: disable=unused-import - - def filter_include_event(event) -> bool: # pylint: disable=unused-argument """ filter_include_event provides a global include filter for all AzureSignIn detections @@ -17,7 +14,7 @@ def filter_include_event(event) -> bool: # pylint: disable=unused-argument # # # example: event['tenantId'] # # if tenantId were missing, we want default behavior to be to alert on this event. - # tenant_id = deep_get(event, "tenantId", default="") + # tenant_id = event.deep_get("tenantId", default="") # return event_origin in ["333333eb-a222-33cc-9baf-4a1111111111", ""] # return True diff --git a/global_helpers/global_filter_cloudflare.py b/global_helpers/global_filter_cloudflare.py index 1480a605c..aecbdb606 100644 --- a/global_helpers/global_filter_cloudflare.py +++ b/global_helpers/global_filter_cloudflare.py @@ -1,6 +1,3 @@ -from panther_base_helpers import deep_get # pylint: disable=unused-import - - def filter_include_event(event) -> bool: # pylint: disable=unused-argument """ filter_include_event provides a global include filter for all cloudflare detections diff --git a/global_helpers/global_filter_github.py b/global_helpers/global_filter_github.py index f871c3c3a..e89da5fbf 100644 --- a/global_helpers/global_filter_github.py +++ b/global_helpers/global_filter_github.py @@ -1,6 +1,3 @@ -from panther_base_helpers import deep_get # pylint: disable=unused-import - - def filter_include_event(event) -> bool: # pylint: disable=unused-argument """ filter_include_event provides a global include filter for all github detections @@ -19,7 +16,7 @@ def filter_include_event(event) -> bool: # pylint: disable=unused-argument # # # not all github enterprise events have org # # example: enterprise.self_hosted_runner_online - # org = deep_get(event, "org", default="") + # org = event.deep_get("org", default="") # return org in ["my-prod-org", ""] # return True diff --git a/global_helpers/global_filter_notion.py b/global_helpers/global_filter_notion.py index 79936f6f0..7961e0225 100644 --- a/global_helpers/global_filter_notion.py +++ b/global_helpers/global_filter_notion.py @@ -1,6 +1,3 @@ -from panther_base_helpers import deep_get # pylint: disable=unused-import - - def filter_include_event(event) -> bool: # pylint: disable=unused-argument """ filter_include_event provides a global include filter for all Notion detections @@ -17,7 +14,7 @@ def filter_include_event(event) -> bool: # pylint: disable=unused-argument # # # example: workspace_id # # if we don't know the workspace_id, we want default behavior to be to alert on this event. - # workspace_id = deep_get(event, "workspace_id", default="") + # workspace_id = event.deep_get("workspace_id", default="") # return workspace_id in ["ea65b016-6abc-4dcf-808b-e000099999999", ""] # return True diff --git a/global_helpers/global_filter_snyk.py b/global_helpers/global_filter_snyk.py index 25f08ef99..4d96346f7 100644 --- a/global_helpers/global_filter_snyk.py +++ b/global_helpers/global_filter_snyk.py @@ -1,6 +1,3 @@ -from panther_base_helpers import deep_get # pylint: disable=unused-import - - def filter_include_event(event) -> bool: # pylint: disable=unused-argument """ filter_include_event provides a global include filter for all snyk detections @@ -16,7 +13,7 @@ def filter_include_event(event) -> bool: # pylint: disable=unused-argument # # # not all snyk audit events have orgId & projectId # # example: group.user.add, sometimes api.access - # org = deep_get(event, "orgId", default="") + # org = event.deep_get("orgId", default="") # return org in ["21111111-a222-4eee-8ddd-a99999999999", ""] # return True diff --git a/global_helpers/global_filter_tailscale.py b/global_helpers/global_filter_tailscale.py index 4ab47fe63..20be9fe9d 100644 --- a/global_helpers/global_filter_tailscale.py +++ b/global_helpers/global_filter_tailscale.py @@ -1,6 +1,3 @@ -from panther_base_helpers import deep_get # pylint: disable=unused-import - - def filter_include_event(event) -> bool: # pylint: disable=unused-argument """ filter_include_event provides a global include filter for all Tailscale detections @@ -17,7 +14,7 @@ def filter_include_event(event) -> bool: # pylint: disable=unused-argument # # # example: event.origin # # if we don't know the event_origin, we want default behavior to be to alert on this event. - # event_origin = deep_get(event, "event", "origin", default="") + # event_origin = event.deep_get("event", "origin", default="") # return event_origin in ["ADMIN_CONSOLE", ""] # return True diff --git a/global_helpers/global_filter_tines.py b/global_helpers/global_filter_tines.py index cfeca257d..fd0d63ca4 100644 --- a/global_helpers/global_filter_tines.py +++ b/global_helpers/global_filter_tines.py @@ -1,6 +1,3 @@ -from panther_base_helpers import deep_get # pylint: disable=unused-import - - def filter_include_event(event) -> bool: # pylint: disable=unused-argument """ filter_include_event provides a global include filter for all Tines detections @@ -14,7 +11,7 @@ def filter_include_event(event) -> bool: # pylint: disable=unused-argument # 1. the specific tenant_id mentioned. # 2. events where tenant_id is undefined # - # tenant_id = deep_get(event, "tenant_id", default="") + # tenant_id = event.deep_get("tenant_id", default="") # return tenant_id in ["1234", ""] # return True diff --git a/global_helpers/panther_asana_helpers.py b/global_helpers/panther_asana_helpers.py index ae82e3790..72dfef37b 100644 --- a/global_helpers/panther_asana_helpers.py +++ b/global_helpers/panther_asana_helpers.py @@ -1,7 +1,4 @@ -from panther_base_helpers import deep_get - - -def asana_alert_context(event: dict) -> dict: +def asana_alert_context(event) -> dict: a_c = { "actor": "", "context": "", @@ -10,23 +7,23 @@ def asana_alert_context(event: dict) -> dict: "resource_name": "", "resource_gid": "", } - if deep_get(event, "actor", "actor_type", default="") == "user": - a_c["actor"] = deep_get(event, "actor", "email", default="") + if event.deep_get("actor", "actor_type", default="") == "user": + a_c["actor"] = event.deep_get("actor", "email", default="") else: - a_c["actor"] = deep_get(event, "actor", "actor_type", default="") + a_c["actor"] = event.deep_get("actor", "actor_type", default="") if "event_type" in event: # Events have categories and event_type # We have not seen category overlap -> only including event_type a_c["event_type"] = event.get("event_type") - a_c["resource_name"] = deep_get(event, "resource", "name", default="") - a_c["resource_gid"] = deep_get(event, "resource", "gid", default="") - r_t = deep_get(event, "resource", "resource_type") + a_c["resource_name"] = event.deep_get("resource", "name", default="") + a_c["resource_gid"] = event.deep_get("resource", "gid", default="") + r_t = event.deep_get("resource", "resource_type") if r_t: a_c["resource_type"] = r_t - r_s_t = deep_get(event, "resource", "resource_subtype") + r_s_t = event.deep_get("resource", "resource_subtype") if r_t and r_s_t and r_s_t != r_t: a_c["resource_type"] += "__" + r_s_t - ctx = deep_get(event, "context", "context_type") + ctx = event.deep_get("context", "context_type") if ctx: a_c["context"] = ctx return a_c diff --git a/global_helpers/panther_auth0_helpers.py b/global_helpers/panther_auth0_helpers.py index d5455e24b..b47f8cbc7 100644 --- a/global_helpers/panther_auth0_helpers.py +++ b/global_helpers/panther_auth0_helpers.py @@ -1,15 +1,12 @@ -from panther_base_helpers import deep_get - - def auth0_alert_context(event) -> dict: a_c = {} - a_c["actor"] = deep_get( - event, "data", "details", "request", "auth", "user", default="" + a_c["actor"] = event.deep_get( + "data", "details", "request", "auth", "user", default="" ) - a_c["action"] = deep_get(event, "data", "description", default="") + a_c["action"] = event.deep_get("data", "description", default="") return a_c def is_auth0_config_event(event): - channel = deep_get(event, "data", "details", "request", "channel", default="") + channel = event.deep_get("data", "details", "request", "channel", default="") return channel == "https://manage.auth0.com/" diff --git a/global_helpers/panther_azuresignin_helpers.py b/global_helpers/panther_azuresignin_helpers.py index 4ce265f42..16dca71bd 100644 --- a/global_helpers/panther_azuresignin_helpers.py +++ b/global_helpers/panther_azuresignin_helpers.py @@ -1,17 +1,14 @@ -from panther_base_helpers import deep_get - - def actor_user(event): - category = deep_get(event, "category", default="") + category = event.deep_get("category", default="") if category in {"ServicePrincipalSignInLogs"}: - return deep_get(event, "properties", "servicePrincipalName") + return event.deep_get("properties", "servicePrincipalName") if category in {"SignInLogs", "NonInteractiveUserSignInLogs"}: - return deep_get(event, "properties", "userPrincipalName") + return event.deep_get("properties", "userPrincipalName") return None def is_sign_in_event(event): - return deep_get(event, "operationName", default="") == "Sign-in activity" + return event.deep_get("operationName", default="") == "Sign-in activity" def azure_signin_alert_context(event) -> dict: @@ -19,11 +16,11 @@ def azure_signin_alert_context(event) -> dict: if ac_actor_user is None: ac_actor_user = "" a_c = {} - a_c["tenantId"] = deep_get(event, "tenantId", default="") - a_c["source_ip"] = deep_get(event, "properties", "ipAddress", default="") + a_c["tenantId"] = event.deep_get("tenantId", default="") + a_c["source_ip"] = event.deep_get("properties", "ipAddress", default="") a_c["actor_user"] = ac_actor_user - a_c["resourceDisplayName"] = deep_get( - event, "properties", "resourceDisplayName", default="" + a_c["resourceDisplayName"] = event.deep_get( + "properties", "resourceDisplayName", default="" ) - a_c["resourceId"] = deep_get(event, "properties", "resourceId", default="") + a_c["resourceId"] = event.deep_get("properties", "resourceId", default="") return a_c diff --git a/global_helpers/panther_base_helpers.py b/global_helpers/panther_base_helpers.py index ea7cbbfb8..f17549a6a 100644 --- a/global_helpers/panther_base_helpers.py +++ b/global_helpers/panther_base_helpers.py @@ -269,27 +269,27 @@ def filter_crowdstrike_fdr_event_type(event, name: str) -> bool: def get_crowdstrike_field(event, field_name, default=None): return ( - deep_get(event, field_name) - or deep_get(event, "event", field_name) - or deep_get(event, "unknown_payload", field_name) + event.deep_get(field_name) + or event.deep_get("event", field_name) + or event.deep_get("unknown_payload", field_name) or default ) -def slack_alert_context(event: dict): +def slack_alert_context(event): return { - "actor-name": deep_get(event, "actor", "user", "name", default=""), - "actor-email": deep_get(event, "actor", "user", "email", default=""), - "actor-ip": deep_get(event, "context", "ip_address", default=""), - "user-agent": deep_get(event, "context", "ua", default=""), + "actor-name": event.deep_get("actor", "user", "name", default=""), + "actor-email": event.deep_get("actor", "user", "email", default=""), + "actor-ip": event.deep_get("context", "ip_address", default=""), + "user-agent": event.deep_get("context", "ua", default=""), } -def github_alert_context(event: dict): +def github_alert_context(event): return { "action": event.get("action", ""), "actor": event.get("actor", ""), - "actor_location": deep_get(event, "actor_location", "country_code"), + "actor_location": event.deep_get("actor_location", "country_code"), "org": event.get("org", ""), "repo": event.get("repo", ""), "user": event.get("user", ""), @@ -412,14 +412,14 @@ def aws_guardduty_context(event: dict): } -def eks_panther_obj_ref(event: dict): - user = deep_get(event, "user", "username", default="") +def eks_panther_obj_ref(event): + user = event.deep_get("user", "username", default="") source_ips = event.get("sourceIPs", ["0.0.0.0"]) # nosec verb = event.get("verb", "") - obj_name = deep_get(event, "objectRef", "name", default="") - obj_ns = deep_get(event, "objectRef", "namespace", default="") - obj_res = deep_get(event, "objectRef", "resource", default="") - obj_subres = deep_get(event, "objectRef", "subresource", default="") + obj_name = event.deep_get("objectRef", "name", default="") + obj_ns = event.deep_get("objectRef", "namespace", default="") + obj_res = event.deep_get("objectRef", "resource", default="") + obj_subres = event.deep_get("objectRef", "subresource", default="") p_source_label = event.get("p_source_label", "") if obj_subres: obj_res = "/".join([obj_res, obj_subres]) diff --git a/global_helpers/panther_greynoise_helpers.py b/global_helpers/panther_greynoise_helpers.py index c73b77a68..6d7a09c2d 100644 --- a/global_helpers/panther_greynoise_helpers.py +++ b/global_helpers/panther_greynoise_helpers.py @@ -4,7 +4,6 @@ from typing import Union from dateutil import parser -from panther_base_helpers import deep_get from panther_lookuptable_helpers import LookupTableMatches @@ -285,13 +284,13 @@ def context(self, match_field: str) -> dict: # pylint: disable=invalid-name def GetGreyNoiseObject(event): - if deep_get(event, "p_enrichment", "greynoise_noise_advanced"): + if event.deep_get("p_enrichment", "greynoise_noise_advanced"): return GreyNoiseAdvanced(event) return GreyNoiseBasic(event) def GetGreyNoiseRiotObject(event): - if deep_get(event, "p_enrichment", "greynoise_riot_advanced"): + if event.deep_get("p_enrichment", "greynoise_riot_advanced"): return GreyNoiseRIOTAdvanced(event) return GreyNoiseRIOTBasic(event) diff --git a/global_helpers/panther_ipinfo_helpers.py b/global_helpers/panther_ipinfo_helpers.py index 55cdb4115..9aa7d01f4 100644 --- a/global_helpers/panther_ipinfo_helpers.py +++ b/global_helpers/panther_ipinfo_helpers.py @@ -126,21 +126,21 @@ def context(self, match_field: str) -> object: def get_ipinfo_location(event): """Returns an IPInfoLocation object for the event or None if it is not available""" - if deep_get(event, "p_enrichment", IPINFO_LOCATION_LUT_NAME): + if event.deep_get("p_enrichment", IPINFO_LOCATION_LUT_NAME): return IPInfoLocation(event) return None def get_ipinfo_asn(event): """Returns an IPInfoASN object for the event or None if it is not available""" - if deep_get(event, "p_enrichment", IPINFO_ASN_LUT_NAME): + if event.deep_get("p_enrichment", IPINFO_ASN_LUT_NAME): return IPInfoASN(event) return None def get_ipinfo_privacy(event): """Returns an IPInfoPrivacy object for the event or None if it is not available""" - if deep_get(event, "p_enrichment", IPINFO_PRIVACY_LUT_NAME): + if event.deep_get("p_enrichment", IPINFO_PRIVACY_LUT_NAME): return IPInfoPrivacy(event) return None diff --git a/global_helpers/panther_lookuptable_helpers.py b/global_helpers/panther_lookuptable_helpers.py index db7a87324..295db4a2a 100644 --- a/global_helpers/panther_lookuptable_helpers.py +++ b/global_helpers/panther_lookuptable_helpers.py @@ -13,7 +13,7 @@ def __init__(self): self._p_matched = {} def _register(self, event, lookuptable_name: str): - self.lut_matches = deep_get(event, ENRICHMENT_KEY, lookuptable_name) + self.lut_matches = event.deep_get(ENRICHMENT_KEY, lookuptable_name) def _lookup(self, match_field: str, *keys) -> list or str: match = deep_get(self.lut_matches, match_field) diff --git a/global_helpers/panther_notion_helpers.py b/global_helpers/panther_notion_helpers.py index 3329e9114..51b7c79b8 100644 --- a/global_helpers/panther_notion_helpers.py +++ b/global_helpers/panther_notion_helpers.py @@ -1,8 +1,5 @@ -from panther_base_helpers import deep_get - - def notion_alert_context(event) -> dict: a_c = {} - a_c["actor"] = deep_get(event, "event", "actor", default="") - a_c["action"] = deep_get(event, "event", "type", default="") + a_c["actor"] = event.deep_get("event", "actor", default="") + a_c["action"] = event.deep_get("event", "type", default="") return a_c diff --git a/global_helpers/panther_tailscale_helpers.py b/global_helpers/panther_tailscale_helpers.py index 2f4bdbada..45daaab22 100644 --- a/global_helpers/panther_tailscale_helpers.py +++ b/global_helpers/panther_tailscale_helpers.py @@ -1,13 +1,10 @@ -from panther_base_helpers import deep_get - - def tailscale_alert_context(event) -> dict: a_c = {} - a_c["actor"] = deep_get(event, "event", "actor", default="") - a_c["action"] = deep_get(event, "event", "action", default="") + a_c["actor"] = event.deep_get("event", "actor", default="") + a_c["action"] = event.deep_get("event", "action", default="") return a_c def is_tailscale_admin_console_event(event): - origin = deep_get(event, "event", "origin", default="") + origin = event.deep_get("event", "origin", default="") return origin == "ADMIN_CONSOLE" diff --git a/queries/crowdstrike_queries/aws_authentication_from_crowdstrike_unmanaged_device.py b/queries/crowdstrike_queries/aws_authentication_from_crowdstrike_unmanaged_device.py index aa45f04b4..d51347589 100644 --- a/queries/crowdstrike_queries/aws_authentication_from_crowdstrike_unmanaged_device.py +++ b/queries/crowdstrike_queries/aws_authentication_from_crowdstrike_unmanaged_device.py @@ -8,7 +8,7 @@ def rule(_): def title(event): return ( f"AWS [{event.get('eventName')}] for " - f"[{deep_get(event, 'userIdentity', 'arn', default = '')}]" + f"[{event.deep_get('userIdentity', 'arn', default = '')}]" " from unmanaged IP Address." ) diff --git a/queries/crowdstrike_queries/okta_login_from_crowdstrike_unmanaged_device.py b/queries/crowdstrike_queries/okta_login_from_crowdstrike_unmanaged_device.py index 9006ad985..e70f90295 100644 --- a/queries/crowdstrike_queries/okta_login_from_crowdstrike_unmanaged_device.py +++ b/queries/crowdstrike_queries/okta_login_from_crowdstrike_unmanaged_device.py @@ -1,6 +1,3 @@ -from panther_base_helpers import deep_get - - def rule(_): return True @@ -8,6 +5,6 @@ def rule(_): def title(event): return ( "Okta Login for " - f"[{deep_get(event, 'actor', 'alternateId', default = '')}]" + f"[{event.deep_get('actor', 'alternateId', default = '')}]" " from unmanaged IP Address." ) diff --git a/queries/crowdstrike_queries/onepassword_login_from_crowdstrike_unmanaged_device.py b/queries/crowdstrike_queries/onepassword_login_from_crowdstrike_unmanaged_device.py index dec6a5d15..cd4588abb 100644 --- a/queries/crowdstrike_queries/onepassword_login_from_crowdstrike_unmanaged_device.py +++ b/queries/crowdstrike_queries/onepassword_login_from_crowdstrike_unmanaged_device.py @@ -1,6 +1,3 @@ -from panther_base_helpers import deep_get - - def rule(_): return True @@ -8,6 +5,6 @@ def rule(_): def title(event): return ( "1Password Login for " - f"[{deep_get(event, 'target_user', 'email', default = '')}]" + f"[{event.deep_get('target_user', 'email', default = '')}]" " from unmanaged IP Address." ) diff --git a/rules/asana_rules/asana_service_account_created.py b/rules/asana_rules/asana_service_account_created.py index 33fb9d9b2..c65ebe6e6 100644 --- a/rules/asana_rules/asana_service_account_created.py +++ b/rules/asana_rules/asana_service_account_created.py @@ -1,11 +1,8 @@ -from panther_base_helpers import deep_get - - def rule(event): return event.get("event_type", "") == "service_account_created" def title(event): - actor_email = deep_get(event, "actor", "email", default="") - svc_acct_name = deep_get(event, "resource", "name", default="") + actor_email = event.deep_get("actor", "email", default="") + svc_acct_name = event.deep_get("resource", "name", default="") return f"Asana user [{actor_email}] created a new service account [{svc_acct_name}]." diff --git a/rules/asana_rules/asana_team_privacy_public.py b/rules/asana_rules/asana_team_privacy_public.py index 459c1e0b5..c423bffc8 100644 --- a/rules/asana_rules/asana_team_privacy_public.py +++ b/rules/asana_rules/asana_team_privacy_public.py @@ -1,14 +1,11 @@ -from panther_base_helpers import deep_get - - def rule(event): return ( event.get("event_type") == "team_privacy_settings_changed" - and deep_get(event, "details", "new_value") == "public" + and event.deep_get("details", "new_value") == "public" ) def title(event): - team = deep_get(event, "resource", "name", default="") - actor = deep_get(event, "actor", "email", default="") + team = event.deep_get("resource", "name", default="") + actor = event.deep_get("actor", "email", default="") return f"Asana team [{team}] has been made public to the org by [{actor}]." diff --git a/rules/asana_rules/asana_workspace_default_session_duration_never.py b/rules/asana_rules/asana_workspace_default_session_duration_never.py index 059d20e68..21d70c59c 100644 --- a/rules/asana_rules/asana_workspace_default_session_duration_never.py +++ b/rules/asana_rules/asana_workspace_default_session_duration_never.py @@ -1,16 +1,13 @@ -from panther_base_helpers import deep_get - - def rule(event): return ( event.get("event_type") == "workspace_default_session_duration_changed" - and deep_get(event, "details", "new_value") == "never" + and event.deep_get("details", "new_value") == "never" ) def title(event): - workspace = deep_get(event, "resource", "name", default="") - actor = deep_get(event, "actor", "email", default="") + workspace = event.deep_get("resource", "name", default="") + actor = event.deep_get("actor", "email", default="") return ( f"Asana workspace [{workspace}]'s default session duration " f"has been set to never expire by [{actor}]." diff --git a/rules/asana_rules/asana_workspace_email_domain_added.py b/rules/asana_rules/asana_workspace_email_domain_added.py index d7924c57b..de629a80d 100644 --- a/rules/asana_rules/asana_workspace_email_domain_added.py +++ b/rules/asana_rules/asana_workspace_email_domain_added.py @@ -1,12 +1,9 @@ -from panther_base_helpers import deep_get - - def rule(event): return event.get("event_type") == "workspace_associated_email_domain_added" def title(event): - workspace = deep_get(event, "resource", "name", default="") - domain = deep_get(event, "details", "new_value", default="") - actor = deep_get(event, "actor", "email", default="") + workspace = event.deep_get("resource", "name", default="") + domain = event.deep_get("details", "new_value", default="") + actor = event.deep_get("actor", "email", default="") return f"Asana new email domain [{domain}] added to Workspace [{workspace}] by [{actor}]." diff --git a/rules/asana_rules/asana_workspace_form_link_auth_requirement_disabled.py b/rules/asana_rules/asana_workspace_form_link_auth_requirement_disabled.py index 5b871171d..325eb7468 100644 --- a/rules/asana_rules/asana_workspace_form_link_auth_requirement_disabled.py +++ b/rules/asana_rules/asana_workspace_form_link_auth_requirement_disabled.py @@ -1,13 +1,10 @@ -from panther_base_helpers import deep_get - - def rule(event): return event.get("event_type") == "workspace_form_link_authentication_required_disabled" def title(event): - workspace = deep_get(event, "resource", "name", default="") - actor = deep_get(event, "actor", "email", default="") + workspace = event.deep_get("resource", "name", default="") + actor = event.deep_get("actor", "email", default="") return ( f"Asana Workspace [{workspace}] Form Link Auth Requirement " f" was disabled by [{actor}]." ) diff --git a/rules/asana_rules/asana_workspace_guest_invite_permissions_anyone.py b/rules/asana_rules/asana_workspace_guest_invite_permissions_anyone.py index cda7098f9..b9f84fcd1 100644 --- a/rules/asana_rules/asana_workspace_guest_invite_permissions_anyone.py +++ b/rules/asana_rules/asana_workspace_guest_invite_permissions_anyone.py @@ -1,16 +1,13 @@ -from panther_base_helpers import deep_get - - def rule(event): return ( event.get("event_type") == "workspace_guest_invite_permissions_changed" - and deep_get(event, "details", "new_value") == "anyone" + and event.deep_get("details", "new_value") == "anyone" ) def title(event): - workspace = deep_get(event, "resource", "name", default="") - actor = deep_get(event, "actor", "email", default="") + workspace = event.deep_get("resource", "name", default="") + actor = event.deep_get("actor", "email", default="") return ( f"Asana Workspace [{workspace}] guest invite permissions " f"changed to anyone by [{actor}]." diff --git a/rules/asana_rules/asana_workspace_new_admin.py b/rules/asana_rules/asana_workspace_new_admin.py index 5b6c01e4b..15c7c369a 100644 --- a/rules/asana_rules/asana_workspace_new_admin.py +++ b/rules/asana_rules/asana_workspace_new_admin.py @@ -1,10 +1,9 @@ from panther_asana_helpers import asana_alert_context -from panther_base_helpers import deep_get def rule(event): - new = deep_get(event, "details", "new_value", default="") - old = deep_get(event, "details", "old_value", default="") + new = event.deep_get("details", "new_value", default="") + old = event.deep_get("details", "old_value", default="") return all( [ event.get("event_type") == "user_workspace_admin_role_changed", @@ -16,7 +15,7 @@ def rule(event): def title(event): a_c = asana_alert_context(event) - w_s = deep_get(event, "details", "group", "name", default="") + w_s = event.deep_get("details", "group", "name", default="") return ( f"Asana user [{a_c.get('resource_name')}] was made an admin " f"in workspace [{w_s}] by [{a_c.get('actor')}]." diff --git a/rules/asana_rules/asana_workspace_org_export.py b/rules/asana_rules/asana_workspace_org_export.py index 2ac5950e4..83288b37f 100644 --- a/rules/asana_rules/asana_workspace_org_export.py +++ b/rules/asana_rules/asana_workspace_org_export.py @@ -1,11 +1,8 @@ -from panther_base_helpers import deep_get - - def rule(event): return event.get("event_type", "") == "workspace_export_started" def title(event): - actor_email = deep_get(event, "actor", "email", default="") - context_type = deep_get(event, "context", "context_type", default="") + actor_email = event.deep_get("actor", "email", default="") + context_type = event.deep_get("context", "context_type", default="") return f"Asana user [{actor_email}] started a [{context_type}] export for your organization." diff --git a/rules/asana_rules/asana_workspace_password_requirements_simple.py b/rules/asana_rules/asana_workspace_password_requirements_simple.py index bc637dea3..56452a764 100644 --- a/rules/asana_rules/asana_workspace_password_requirements_simple.py +++ b/rules/asana_rules/asana_workspace_password_requirements_simple.py @@ -1,8 +1,5 @@ -from panther_base_helpers import deep_get - - def rule(event): - new_val = deep_get(event, "details", "new_value", default="") + new_val = event.deep_get("details", "new_value", default="") return all( [ event.get("event_type", "") @@ -13,9 +10,9 @@ def rule(event): def title(event): - actor_email = deep_get(event, "actor", "email", default="") - new_value = deep_get(event, "details", "new_value", default="") - old_value = deep_get(event, "details", "old_value", default="") + actor_email = event.deep_get("actor", "email", default="") + new_value = event.deep_get("details", "new_value", default="") + old_value = event.deep_get("details", "old_value", default="") return ( f"Asana user [{actor_email}] changed your organization's password requirements " f"from [{old_value}] to [{new_value}]." diff --git a/rules/asana_rules/asana_workspace_require_app_approvals_disabled.py b/rules/asana_rules/asana_workspace_require_app_approvals_disabled.py index cc3b0c27a..f47eb477f 100644 --- a/rules/asana_rules/asana_workspace_require_app_approvals_disabled.py +++ b/rules/asana_rules/asana_workspace_require_app_approvals_disabled.py @@ -1,8 +1,5 @@ -from panther_base_helpers import deep_get - - def rule(event): - new_val = deep_get(event, "details", "new_value", default="") + new_val = event.deep_get("details", "new_value", default="") return all( [ event.get("event_type", "") @@ -13,8 +10,8 @@ def rule(event): def title(event): - actor_email = deep_get(event, "actor", "email", default="") - context = deep_get(event, "context", "context_type", default="") + actor_email = event.deep_get("actor", "email", default="") + context = event.deep_get("context", "context_type", default="") return ( f"Asana user [{actor_email}] disabled application approval requirements " f"for [{context}] type applications." diff --git a/rules/asana_rules/asana_workspace_saml_optional.py b/rules/asana_rules/asana_workspace_saml_optional.py index 88e5a7e9a..544619267 100644 --- a/rules/asana_rules/asana_workspace_saml_optional.py +++ b/rules/asana_rules/asana_workspace_saml_optional.py @@ -1,9 +1,6 @@ -from panther_base_helpers import deep_get - - def rule(event): - old_val = deep_get(event, "details", "old_value", default="") - new_val = deep_get(event, "details", "new_value", default="") + old_val = event.deep_get("details", "old_value", default="") + new_val = event.deep_get("details", "new_value", default="") return all( [ event.get("event_type", "") == "workspace_saml_settings_changed", @@ -14,5 +11,5 @@ def rule(event): def title(event): - actor_email = deep_get(event, "actor", "email", default="") + actor_email = event.deep_get("actor", "email", default="") return f"Asana user [{actor_email}] made SAML optional for your organization." diff --git a/rules/atlassian_rules/user_logged_in_as_user.py b/rules/atlassian_rules/user_logged_in_as_user.py index 613490f4d..ebefdd580 100644 --- a/rules/atlassian_rules/user_logged_in_as_user.py +++ b/rules/atlassian_rules/user_logged_in_as_user.py @@ -1,25 +1,22 @@ -from panther_base_helpers import deep_get - - def rule(event): return ( - deep_get(event, "attributes", "action", default="") + event.deep_get("attributes", "action", default="") == "user_logged_in_as_user" ) def title(event): - actor = deep_get(event, "attributes", "actor", "email", default="") - context = deep_get(event, "attributes", "context", default=[{}]) + actor = event.deep_get("attributes", "actor", "email", default="") + context = event.deep_get("attributes", "context", default=[{}]) impersonated_user = context[0].get("attributes", {}).get("email", "") return f"{actor} logged in as {impersonated_user}." def alert_context(event): return { - "Timestamp": deep_get(event, "attributes", "time", default=""), - "Actor": deep_get(event, "attributes", "actor", "email", default=""), - "Impersonated user": deep_get(event, "attributes", "context", default=[{}])[0] + "Timestamp": event.deep_get("attributes", "time", default=""), + "Actor": event.deep_get("attributes", "actor", "email", default=""), + "Impersonated user": event.deep_get("attributes", "context", default=[{}])[0] .get("attributes", {}) .get("email", ""), "Event ID": event.get("id"), diff --git a/rules/auth0_rules/auth0_custom_role_created.py b/rules/auth0_rules/auth0_custom_role_created.py index 22804e97a..584678f7a 100644 --- a/rules/auth0_rules/auth0_custom_role_created.py +++ b/rules/auth0_rules/auth0_custom_role_created.py @@ -1,12 +1,11 @@ from global_filter_auth0 import filter_include_event from panther_auth0_helpers import auth0_alert_context, is_auth0_config_event -from panther_base_helpers import deep_get def rule(event): if not filter_include_event(event): return False - data_description = deep_get(event, "data", "description", default="") + data_description = event.deep_get("data", "description", default="") return all( [ data_description == "Create a role", @@ -16,14 +15,14 @@ def rule(event): def title(event): - user = deep_get( - event, "data", "details", "request", "auth", "user", "email", default="" + user = event.deep_get( + "data", "details", "request", "auth", "user", "email", default="" ) - request_body_name = deep_get( - event, "data", "details", "request", "body", "name", default="" + request_body_name = event.deep_get( + "data", "details", "request", "body", "name", default="" ) - request_body_description = deep_get( - event, "data", "details", "request", "body", default="" + request_body_description = event.deep_get( + "data", "details", "request", "body", default="" ) if "admin" in request_body_description or "admin" in request_body_name: @@ -31,7 +30,7 @@ def title(event): else: role_type = "custom" - p_source_label = deep_get(event, "p_source_label", default="") + p_source_label = event.deep_get("p_source_label", default="") return ( f"Auth0 User [{user}] created a " f"role [{request_body_name}] with [{role_type}] " @@ -40,11 +39,11 @@ def title(event): def severity(event): - request_body_name = deep_get( - event, "data", "details", "request", "body", "name", default="" + request_body_name = event.deep_get( + "data", "details", "request", "body", "name", default="" ) - request_body_description = deep_get( - event, "data", "details", "request", "body", "description", default="" + request_body_description = event.deep_get( + "data", "details", "request", "body", "description", default="" ) if "admin" in request_body_description or "admin" in request_body_name: return "MEDIUM" diff --git a/rules/auth0_rules/auth0_integration_installed.py b/rules/auth0_rules/auth0_integration_installed.py index dad275d3c..7bd823127 100644 --- a/rules/auth0_rules/auth0_integration_installed.py +++ b/rules/auth0_rules/auth0_integration_installed.py @@ -1,14 +1,13 @@ from global_filter_auth0 import filter_include_event from panther_auth0_helpers import auth0_alert_context, is_auth0_config_event -from panther_base_helpers import deep_get def rule(event): if not filter_include_event(event): return False - data_description = deep_get(event, "data", "description", default="") - request_path = deep_get( - event, "data", "details", "request", "path", default="" + data_description = event.deep_get("data", "description", default="") + request_path = event.deep_get( + "data", "details", "request", "path", default="" ) return all( [ @@ -20,10 +19,10 @@ def rule(event): def title(event): - user = deep_get( - event, "data", "details", "request", "auth", "user", "email", default="" + user = event.deep_get( + "data", "details", "request", "auth", "user", "email", default="" ) - p_source_label = deep_get(event, "p_source_label", default="") + p_source_label = event.deep_get("p_source_label", default="") return ( f"Auth0 User [{user}] installed an integration from the actions library for " f"your organization's tenant [{p_source_label}]." diff --git a/rules/auth0_rules/auth0_mfa_factor_setting_enabled.py b/rules/auth0_rules/auth0_mfa_factor_setting_enabled.py index 8ee031cde..9f7b501a4 100644 --- a/rules/auth0_rules/auth0_mfa_factor_setting_enabled.py +++ b/rules/auth0_rules/auth0_mfa_factor_setting_enabled.py @@ -1,13 +1,12 @@ from global_filter_auth0 import filter_include_event from panther_auth0_helpers import auth0_alert_context, is_auth0_config_event -from panther_base_helpers import deep_get def rule(event): if not filter_include_event(event): return False - description = deep_get(event, "data", "description", default="") - enabled = deep_get(event, "data", "details", "response", "body", "enabled") + description = event.deep_get("data", "description", default="") + enabled = event.deep_get("data", "details", "response", "body", "enabled") return all( [ description == "Update a Multi-factor Authentication Factor", @@ -18,11 +17,11 @@ def rule(event): def title(event): - user = deep_get( - event, "data", "details", "request", "auth", "user", "email", default="" + user = event.deep_get( + "data", "details", "request", "auth", "user", "email", default="" ) - path = deep_get(event, "data", "details", "request", "path", default="") - p_source_label = deep_get(event, "p_source_label", default="") + path = event.deep_get("data", "details", "request", "path", default="") + p_source_label = event.deep_get("p_source_label", default="") return ( f"Auth0 User [{user}] enabled mfa factor settings for [{path}] " f"in your organization’s tenant [{p_source_label}]." diff --git a/rules/auth0_rules/auth0_mfa_policy_disabled.py b/rules/auth0_rules/auth0_mfa_policy_disabled.py index ec5cf874d..d11794796 100644 --- a/rules/auth0_rules/auth0_mfa_policy_disabled.py +++ b/rules/auth0_rules/auth0_mfa_policy_disabled.py @@ -1,16 +1,15 @@ from global_filter_auth0 import filter_include_event from panther_auth0_helpers import auth0_alert_context, is_auth0_config_event -from panther_base_helpers import deep_get def rule(event): if not filter_include_event(event): return False - data_description = deep_get(event, "data", "description", default="") - request_path = deep_get( - event, "data", "details", "request", "path", default="" + data_description = event.deep_get("data", "description", default="") + request_path = event.deep_get( + "data", "details", "request", "path", default="" ) - request_body = deep_get(event, "data", "details", "request", "body", default=[-1]) + request_body = event.deep_get("data", "details", "request", "body", default=[-1]) return all( [ data_description == "Set the Multi-factor Authentication policies", @@ -22,10 +21,10 @@ def rule(event): def title(event): - user = deep_get( - event, "data", "details", "request", "auth", "user", "email", default="" + user = event.deep_get( + "data", "details", "request", "auth", "user", "email", default="" ) - p_source_label = deep_get(event, "p_source_label", default="") + p_source_label = event.deep_get("p_source_label", default="") return ( f"Auth0 User [{user}] set mfa requirement settings to 'Never' for your " f"organization's tenant [{p_source_label}]." diff --git a/rules/auth0_rules/auth0_mfa_policy_enabled.py b/rules/auth0_rules/auth0_mfa_policy_enabled.py index 331ebf192..bede1f0f6 100644 --- a/rules/auth0_rules/auth0_mfa_policy_enabled.py +++ b/rules/auth0_rules/auth0_mfa_policy_enabled.py @@ -1,14 +1,13 @@ from global_filter_auth0 import filter_include_event from panther_auth0_helpers import auth0_alert_context, is_auth0_config_event -from panther_base_helpers import deep_get def rule(event): if not filter_include_event(event): return False - data_description = deep_get(event, "data", "description", default="") - request_path = deep_get( - event, "data", "details", "request", "path", default="" + data_description = event.deep_get("data", "description", default="") + request_path = event.deep_get( + "data", "details", "request", "path", default="" ) return all( [ @@ -20,10 +19,10 @@ def rule(event): def title(event): - user_email = deep_get( - event, "data", "details", "request", "auth", "user", "email", default="" + user_email = event.deep_get( + "data", "details", "request", "auth", "user", "email", default="" ) - request_body = deep_get(event, "data", "details", "request", "body", default=[]) + request_body = event.deep_get("data", "details", "request", "body", default=[]) if "all-applications" in request_body: setting_change = "Always Require" diff --git a/rules/auth0_rules/auth0_mfa_risk_assessment_disabled.py b/rules/auth0_rules/auth0_mfa_risk_assessment_disabled.py index 6d26fb2be..5a3bac941 100644 --- a/rules/auth0_rules/auth0_mfa_risk_assessment_disabled.py +++ b/rules/auth0_rules/auth0_mfa_risk_assessment_disabled.py @@ -1,17 +1,16 @@ from global_filter_auth0 import filter_include_event from panther_auth0_helpers import auth0_alert_context, is_auth0_config_event -from panther_base_helpers import deep_get def rule(event): if not filter_include_event(event): return False - data_description = deep_get(event, "data", "description", default="") - request_path = deep_get( - event, "data", "details", "request", "path", default="" + data_description = event.deep_get("data", "description", default="") + request_path = event.deep_get( + "data", "details", "request", "path", default="" ) - request_body = deep_get( - event, "data", "details", "request", "body", "AfterAuthentication", default=[] + request_body = event.deep_get( + "data", "details", "request", "body", "AfterAuthentication", default=[] ) return all( [ @@ -24,10 +23,10 @@ def rule(event): def title(event): - user = deep_get( - event, "data", "details", "request", "auth", "user", "email", default="" + user = event.deep_get( + "data", "details", "request", "auth", "user", "email", default="" ) - p_source_label = deep_get(event, "p_source_label", default="") + p_source_label = event.deep_get("p_source_label", default="") return ( f"Auth0 User [{user}] disabled mfa risk assessment settings for your " f"organization’s tenant [{p_source_label}]." diff --git a/rules/auth0_rules/auth0_mfa_risk_assessment_enabled.py b/rules/auth0_rules/auth0_mfa_risk_assessment_enabled.py index 857c98eeb..3a8bb0ba8 100644 --- a/rules/auth0_rules/auth0_mfa_risk_assessment_enabled.py +++ b/rules/auth0_rules/auth0_mfa_risk_assessment_enabled.py @@ -1,17 +1,16 @@ from global_filter_auth0 import filter_include_event from panther_auth0_helpers import auth0_alert_context, is_auth0_config_event -from panther_base_helpers import deep_get def rule(event): if not filter_include_event(event): return False - data_description = deep_get(event, "data", "description", default="") - request_path = deep_get( - event, "data", "details", "request", "path", default="" + data_description = event.deep_get("data", "description", default="") + request_path = event.deep_get( + "data", "details", "request", "path", default="" ) - request_body = deep_get( - event, "data", "details", "request", "body", "AfterAuthentication", default=[] + request_body = event.deep_get( + "data", "details", "request", "body", "AfterAuthentication", default=[] ) return all( [ @@ -24,10 +23,10 @@ def rule(event): def title(event): - user = deep_get( - event, "data", "details", "request", "auth", "user", "email", default="" + user = event.deep_get( + "data", "details", "request", "auth", "user", "email", default="" ) - p_source_label = deep_get(event, "p_source_label", default="") + p_source_label = event.deep_get("p_source_label", default="") return ( f"Auth0 User [{user}] enabled mfa risk assessment settings for your " f"organization’s tenant [{p_source_label}]." diff --git a/rules/auth0_rules/auth0_post_login_action_flow.py b/rules/auth0_rules/auth0_post_login_action_flow.py index fb6f02afa..9c6d9d24c 100644 --- a/rules/auth0_rules/auth0_post_login_action_flow.py +++ b/rules/auth0_rules/auth0_post_login_action_flow.py @@ -7,9 +7,9 @@ def rule(event): if not filter_include_event(event): return False - data_description = deep_get(event, "data", "description", default="") - request_path = deep_get( - event, "data", "details", "request", "path", default="" + data_description = event.deep_get("data", "description", default="") + request_path = event.deep_get( + "data", "details", "request", "path", default="" ) return all( @@ -22,13 +22,13 @@ def rule(event): def title(event): - user = deep_get( - event, "data", "details", "request", "auth", "user", "email", default="" + user = event.deep_get( + "data", "details", "request", "auth", "user", "email", default="" ) - p_source_label = deep_get(event, "p_source_label", default="") - request_bindings = deep_get(event, "data", "details", "request", "body", "bindings", default=[]) - response_bindings = deep_get( - event, "data", "details", "response", "body", "bindings", default=[] + p_source_label = event.deep_get("p_source_label", default="") + request_bindings = event.deep_get("data", "details", "request", "body", "bindings", default=[]) + response_bindings = event.deep_get( + "data", "details", "response", "body", "bindings", default=[] ) actions_added_list = [] diff --git a/rules/auth0_rules/auth0_user_invitation_created.py b/rules/auth0_rules/auth0_user_invitation_created.py index 12c71a2b4..110fd5a8d 100644 --- a/rules/auth0_rules/auth0_user_invitation_created.py +++ b/rules/auth0_rules/auth0_user_invitation_created.py @@ -2,7 +2,6 @@ from global_filter_auth0 import filter_include_event from panther_auth0_helpers import auth0_alert_context, is_auth0_config_event -from panther_base_helpers import deep_get org_re = re.compile(r"^/api/v2/organizations/[^/\s]+/invitations$") @@ -18,23 +17,23 @@ def title(event): inv_type = invitation_type(event) if inv_type == "tenant": try: - invitee = deep_get(event, "data", "details", "request", "body", "owners", default=[])[0] + invitee = event.deep_get("data", "details", "request", "body", "owners", default=[])[0] except IndexError: invitee = "" elif inv_type == "organization": - invitee = deep_get(event, "data", "details", "request", "body", "invitee", "email") + invitee = event.deep_get("data", "details", "request", "body", "invitee", "email") else: invitee = "" - inviter = deep_get( - event, "data", "details", "request", "auth", "user", "email", default="" + inviter = event.deep_get( + "data", "details", "request", "auth", "user", "email", default="" ) - source = deep_get(event, "p_source_label", default="") + source = event.deep_get("p_source_label", default="") return f"Auth0 User [{inviter}] invited [{invitee}] to {inv_type} [{source}]]" def invitation_type(event): - path = deep_get(event, "data", "details", "request", "path", default="") + path = event.deep_get("data", "details", "request", "path", default="") if path == "/api/v2/tenants/invitations": return "tenant" diff --git a/rules/auth0_rules/auth0_user_joined_tenant.py b/rules/auth0_rules/auth0_user_joined_tenant.py index 99a5fcfd5..8d7776442 100644 --- a/rules/auth0_rules/auth0_user_joined_tenant.py +++ b/rules/auth0_rules/auth0_user_joined_tenant.py @@ -1,14 +1,12 @@ from global_filter_auth0 import filter_include_event from panther_auth0_helpers import auth0_alert_context, is_auth0_config_event -from panther_base_helpers import deep_get def rule(event): if not filter_include_event(event): return False - data_description = deep_get(event, "data", "description", default="") - scopes = deep_get( - event, + data_description = event.deep_get("data", "description", default="") + scopes = event.deep_get( "data", "details", "request", @@ -17,7 +15,7 @@ def rule(event): "scopes", default=[""], ) - state = deep_get(event, "data", "details", "request", "body", "state", default="") + state = event.deep_get("data", "details", "request", "body", "state", default="") return all( [ data_description == "Update an invitation", @@ -29,10 +27,10 @@ def rule(event): def title(event): - user = deep_get( - event, "data", "details", "request", "auth", "user", "email", default="" + user = event.deep_get( + "data", "details", "request", "auth", "user", "email", default="" ) - p_source_label = deep_get(event, "p_source_label", default="") + p_source_label = event.deep_get("p_source_label", default="") return ( f"Auth0 User [{user}] has accepted an invitation to join your " f"organization's tenant [{p_source_label}]." diff --git a/rules/aws_cloudtrail_rules/aws_ami_modified_for_public_access.py b/rules/aws_cloudtrail_rules/aws_ami_modified_for_public_access.py index 819a87e49..cfca5857e 100644 --- a/rules/aws_cloudtrail_rules/aws_ami_modified_for_public_access.py +++ b/rules/aws_cloudtrail_rules/aws_ami_modified_for_public_access.py @@ -1,4 +1,4 @@ -from panther_base_helpers import aws_rule_context, deep_get +from panther_base_helpers import aws_rule_context from panther_default import aws_cloudtrail_success @@ -7,8 +7,8 @@ def rule(event): if not aws_cloudtrail_success(event) or event.get("eventName") != "ModifyImageAttribute": return False - added_perms = deep_get( - event, "requestParameters", "launchPermission", "add", "items", default=[] + added_perms = event.deep_get( + "requestParameters", "launchPermission", "add", "items", default=[] ) for item in added_perms: diff --git a/rules/aws_cloudtrail_rules/aws_cloudtrail_account_discovery.py b/rules/aws_cloudtrail_rules/aws_cloudtrail_account_discovery.py index 85ea25cec..ec31115f6 100644 --- a/rules/aws_cloudtrail_rules/aws_cloudtrail_account_discovery.py +++ b/rules/aws_cloudtrail_rules/aws_cloudtrail_account_discovery.py @@ -1,5 +1,3 @@ -from panther_base_helpers import deep_get - DISCOVERY_EVENTS = [ "GetAlternateContact", "GetContactInformation", @@ -15,7 +13,7 @@ def rule(event): def title(event): return ( - f"User [{deep_get(event, 'userIdentity', 'arn')}]" + f"User [{event.deep_get('userIdentity', 'arn')}]" f"performed a [{event.get('eventName')}] " f"action in AWS account [{event.get('recipientAccountId')}]." ) diff --git a/rules/aws_cloudtrail_rules/aws_cloudtrail_created.py b/rules/aws_cloudtrail_rules/aws_cloudtrail_created.py index a3d54f291..7f6694839 100644 --- a/rules/aws_cloudtrail_rules/aws_cloudtrail_created.py +++ b/rules/aws_cloudtrail_rules/aws_cloudtrail_created.py @@ -1,4 +1,4 @@ -from panther_base_helpers import aws_rule_context, deep_get +from panther_base_helpers import aws_rule_context from panther_default import aws_cloudtrail_success # API calls that are indicative of CloudTrail changes @@ -14,7 +14,7 @@ def rule(event): def title(event): - return f"CloudTrail [{deep_get(event, 'requestParameters', 'name')}] was created/updated" + return f"CloudTrail [{event.deep_get('requestParameters', 'name')}] was created/updated" def alert_context(event): diff --git a/rules/aws_cloudtrail_rules/aws_cloudtrail_loginprofilecreatedormodified.py b/rules/aws_cloudtrail_rules/aws_cloudtrail_loginprofilecreatedormodified.py index 4d376261d..e6e01a70c 100644 --- a/rules/aws_cloudtrail_rules/aws_cloudtrail_loginprofilecreatedormodified.py +++ b/rules/aws_cloudtrail_rules/aws_cloudtrail_loginprofilecreatedormodified.py @@ -1,4 +1,4 @@ -from panther_base_helpers import aws_rule_context, deep_get +from panther_base_helpers import aws_rule_context PROFILE_EVENTS = { "UpdateLoginProfile", @@ -15,17 +15,17 @@ def rule(event): return ( event.get("eventSource", "") == "iam.amazonaws.com" and event.get("eventName", "") in PROFILE_EVENTS - and not deep_get(event, "userIdentity", "arn", default="").endswith( - f"/{deep_get(event, 'requestParameters', 'userName', default='')}" + and not event.deep_get("userIdentity", "arn", default="").endswith( + f"/{event.deep_get('requestParameters', 'userName', default='')}" ) ) def title(event): return ( - f"[{deep_get(event, 'userIdentity', 'arn')}] " + f"[{event.deep_get('userIdentity', 'arn')}] " f"changed the password for " - f"[{deep_get(event, 'requestParameters','userName')}]" + f"[{event.deep_get('requestParameters','userName')}]" ) diff --git a/rules/aws_cloudtrail_rules/aws_cloudtrail_password_policy_discovery.py b/rules/aws_cloudtrail_rules/aws_cloudtrail_password_policy_discovery.py index 81d7d113e..da144c0aa 100644 --- a/rules/aws_cloudtrail_rules/aws_cloudtrail_password_policy_discovery.py +++ b/rules/aws_cloudtrail_rules/aws_cloudtrail_password_policy_discovery.py @@ -1,4 +1,4 @@ -from panther_base_helpers import aws_rule_context, deep_get +from panther_base_helpers import aws_rule_context PASSWORD_DISCOVERY_EVENTS = [ "GetAccountPasswordPolicy", @@ -13,7 +13,7 @@ def rule(event): def title(event): - user_arn = deep_get(event, "useridentity", "arn", default="") + user_arn = event.deep_get("useridentity", "arn", default="") return f"Password Policy Discovery detected in AWS CloudTrail from [{user_arn}]" diff --git a/rules/aws_cloudtrail_rules/aws_cloudtrail_stopped.py b/rules/aws_cloudtrail_rules/aws_cloudtrail_stopped.py index e734d42a1..468a7298f 100644 --- a/rules/aws_cloudtrail_rules/aws_cloudtrail_stopped.py +++ b/rules/aws_cloudtrail_rules/aws_cloudtrail_stopped.py @@ -1,4 +1,4 @@ -from panther_base_helpers import aws_rule_context, deep_get +from panther_base_helpers import aws_rule_context from panther_default import aws_cloudtrail_success, lookup_aws_account_name # API calls that are indicative of CloudTrail changes @@ -14,7 +14,7 @@ def rule(event): def dedup(event): # Merge on the CloudTrail ARN - return deep_get(event, "requestParameters", "name", default="") + return event.deep_get("requestParameters", "name", default="") def title(event): diff --git a/rules/aws_cloudtrail_rules/aws_cloudtrail_unsuccessful_mfa_attempt.py b/rules/aws_cloudtrail_rules/aws_cloudtrail_unsuccessful_mfa_attempt.py index bc83c4876..2ef367fd6 100644 --- a/rules/aws_cloudtrail_rules/aws_cloudtrail_unsuccessful_mfa_attempt.py +++ b/rules/aws_cloudtrail_rules/aws_cloudtrail_unsuccessful_mfa_attempt.py @@ -1,4 +1,4 @@ -from panther_base_helpers import aws_rule_context, deep_get +from panther_base_helpers import aws_rule_context def rule(event): @@ -8,8 +8,8 @@ def rule(event): ): return False - mfa_used = deep_get(event, "additionalEventData", "MFAUsed", default="") - console_login = deep_get(event, "responseElements", "ConsoleLogin", default="") + mfa_used = event.deep_get("additionalEventData", "MFAUsed", default="") + console_login = event.deep_get("responseElements", "ConsoleLogin", default="") if mfa_used == "Yes" and console_login == "Failure": return True @@ -17,8 +17,8 @@ def rule(event): def title(event): - arn = deep_get(event, "userIdenity", "arn", default="No ARN") - username = deep_get(event, "userIdentity", "userName", default="No Username") + arn = event.deep_get("userIdenity", "arn", default="No ARN") + username = event.deep_get("userIdentity", "userName", default="No Username") return f"Failed MFA login from [{arn}] [{username}]" diff --git a/rules/aws_cloudtrail_rules/aws_codebuild_made_public.py b/rules/aws_cloudtrail_rules/aws_codebuild_made_public.py index 6c3b0616c..49b8b90f3 100644 --- a/rules/aws_cloudtrail_rules/aws_codebuild_made_public.py +++ b/rules/aws_cloudtrail_rules/aws_codebuild_made_public.py @@ -1,18 +1,18 @@ -from panther_base_helpers import aws_rule_context, deep_get +from panther_base_helpers import aws_rule_context from panther_default import lookup_aws_account_name def rule(event): return ( event["eventName"] == "UpdateProjectVisibility" - and deep_get(event, "requestParameters", "projectVisibility") == "PUBLIC_READ" + and event.deep_get("requestParameters", "projectVisibility") == "PUBLIC_READ" ) def title(event): return ( - f"AWS CodeBuild Project made Public by {deep_get(event, 'userIdentity', 'arn')} " - f"in account {lookup_aws_account_name(deep_get(event, 'recipientAccountId'))}" + f"AWS CodeBuild Project made Public by {event.deep_get('userIdentity', 'arn')} " + f"in account {lookup_aws_account_name(event.deep_get('recipientAccountId'))}" ) diff --git a/rules/aws_cloudtrail_rules/aws_console_login_failed.py b/rules/aws_cloudtrail_rules/aws_console_login_failed.py index 9cbe7dab7..41de316ce 100644 --- a/rules/aws_cloudtrail_rules/aws_console_login_failed.py +++ b/rules/aws_cloudtrail_rules/aws_console_login_failed.py @@ -1,12 +1,12 @@ -from panther_base_helpers import aws_rule_context, deep_get +from panther_base_helpers import aws_rule_context from panther_default import lookup_aws_account_name def rule(event): return ( event.get("eventName") == "ConsoleLogin" - and deep_get(event, "userIdentity", "type") == "IAMUser" - and deep_get(event, "responseElements", "ConsoleLogin") == "Failure" + and event.deep_get("userIdentity", "type") == "IAMUser" + and event.deep_get("responseElements", "ConsoleLogin") == "Failure" ) diff --git a/rules/aws_cloudtrail_rules/aws_console_login_without_mfa.py b/rules/aws_cloudtrail_rules/aws_console_login_without_mfa.py index 9524e5e51..d4dd811c9 100644 --- a/rules/aws_cloudtrail_rules/aws_console_login_without_mfa.py +++ b/rules/aws_cloudtrail_rules/aws_console_login_without_mfa.py @@ -1,6 +1,6 @@ import logging -from panther_base_helpers import aws_rule_context, deep_get +from panther_base_helpers import aws_rule_context from panther_default import lookup_aws_account_name from panther_detection_helpers.caching import check_account_age @@ -16,7 +16,7 @@ def rule(event): # Extract some nested JSON structure additional_event_data = event.get("additionalEventData", {}) response_elements = event.get("responseElements", {}) - user_identity_type = deep_get(event, "userIdentity", "type", default="") + user_identity_type = event.deep_get("userIdentity", "type", default="") # When there is an external IdP setup and users directly assume roles # the additionalData.MFAUsed attribute will be set to "no" @@ -32,7 +32,7 @@ def rule(event): # If using AWS SSOv2 or other SAML provider return False if ( - "AWSReservedSSO" in deep_get(event, "userIdentity", "arn", default=" ") + "AWSReservedSSO" in event.deep_get("userIdentity", "arn", default=" ") or additional_event_data.get("SamlProviderArn") is not None ): return False @@ -41,9 +41,9 @@ def rule(event): # This functionality is not enabled by default, in order to start logging new user creations # Enable indicator_creation_rules/new_account_logging to start logging new users new_user_string = ( - deep_get(event, "userIdentity", "userName", default="") + event.deep_get("userIdentity", "userName", default="") + "-" - + deep_get(event, "userIdentity", "principalId", default="") + + event.deep_get("userIdentity", "principalId", default="") ) is_new_user = check_account_age(new_user_string) if isinstance(is_new_user, str): @@ -71,7 +71,7 @@ def rule(event): # It is not recommended to remove this 'double negative" if ( additional_event_data.get("MFAUsed") != "Yes" - and deep_get(event, "userIdentity", "sessionContext", "attributes", "mfaAuthenticated") + and event.deep_get("userIdentity", "sessionContext", "attributes", "mfaAuthenticated") != "true" ): return True @@ -79,14 +79,14 @@ def rule(event): def title(event): - if deep_get(event, "userIdentity", "type") == "Root": + if event.deep_get("userIdentity", "type") == "Root": user_string = "the root user" else: - user = deep_get(event, "userIdentity", "userName") or deep_get( + user = event.deep_get("userIdentity", "userName") or deep_get( event, "userIdentity", "sessionContext", "sessionIssuer", "userName" ) - type_ = deep_get( - event, "userIdentity", "sessionContext", "sessionIssuer", "type", default="user" + type_ = event.deep_get( + "userIdentity", "sessionContext", "sessionIssuer", "type", default="user" ).lower() user_string = f"{type_} {user}" account_id = event.get("recipientAccountId") diff --git a/rules/aws_cloudtrail_rules/aws_console_login_without_saml.py b/rules/aws_cloudtrail_rules/aws_console_login_without_saml.py index b4b421079..a8761353d 100644 --- a/rules/aws_cloudtrail_rules/aws_console_login_without_saml.py +++ b/rules/aws_cloudtrail_rules/aws_console_login_without_saml.py @@ -1,4 +1,4 @@ -from panther_base_helpers import aws_rule_context, deep_get +from panther_base_helpers import aws_rule_context from panther_default import lookup_aws_account_name @@ -6,7 +6,7 @@ def rule(event): additional_event_data = event.get("additionalEventData", {}) return ( event.get("eventName") == "ConsoleLogin" - and deep_get(event, "userIdentity", "type") != "AssumedRole" + and event.deep_get("userIdentity", "type") != "AssumedRole" and not additional_event_data.get("SamlProviderArn") ) diff --git a/rules/aws_cloudtrail_rules/aws_console_root_login.py b/rules/aws_cloudtrail_rules/aws_console_root_login.py index 8e99877e1..3b76e34bb 100644 --- a/rules/aws_cloudtrail_rules/aws_console_root_login.py +++ b/rules/aws_cloudtrail_rules/aws_console_root_login.py @@ -1,4 +1,3 @@ -from panther_base_helpers import deep_get from panther_default import lookup_aws_account_name from panther_oss_helpers import geoinfo_from_ip_formatted @@ -6,8 +5,8 @@ def rule(event): return ( event.get("eventName") == "ConsoleLogin" - and deep_get(event, "userIdentity", "type") == "Root" - and deep_get(event, "responseElements", "ConsoleLogin") == "Success" + and event.deep_get("userIdentity", "type") == "Root" + and event.deep_get("responseElements", "ConsoleLogin") == "Success" ) @@ -31,8 +30,8 @@ def dedup(event): def alert_context(event): return { "sourceIPAddress": event.get("sourceIPAddress"), - "userIdentityAccountId": deep_get(event, "userIdentity", "accountId"), - "userIdentityArn": deep_get(event, "userIdentity", "arn"), + "userIdentityAccountId": event.deep_get("userIdentity", "accountId"), + "userIdentityArn": event.deep_get("userIdentity", "arn"), "eventTime": event.get("eventTime"), - "mfaUsed": deep_get(event, "additionalEventData", "MFAUsed"), + "mfaUsed": event.deep_get("additionalEventData", "MFAUsed"), } diff --git a/rules/aws_cloudtrail_rules/aws_console_root_login_failed.py b/rules/aws_cloudtrail_rules/aws_console_root_login_failed.py index 513f0d43d..030353307 100644 --- a/rules/aws_cloudtrail_rules/aws_console_root_login_failed.py +++ b/rules/aws_cloudtrail_rules/aws_console_root_login_failed.py @@ -1,12 +1,12 @@ -from panther_base_helpers import aws_rule_context, deep_get +from panther_base_helpers import aws_rule_context from panther_default import lookup_aws_account_name def rule(event): return ( event.get("eventName") == "ConsoleLogin" - and deep_get(event, "userIdentity", "type") == "Root" - and deep_get(event, "responseElements", "ConsoleLogin") == "Failure" + and event.deep_get("userIdentity", "type") == "Root" + and event.deep_get("responseElements", "ConsoleLogin") == "Failure" ) diff --git a/rules/aws_cloudtrail_rules/aws_ec2_manual_security_group_changes.py b/rules/aws_cloudtrail_rules/aws_ec2_manual_security_group_changes.py index 021d98ca3..5deda785b 100644 --- a/rules/aws_cloudtrail_rules/aws_ec2_manual_security_group_changes.py +++ b/rules/aws_cloudtrail_rules/aws_ec2_manual_security_group_changes.py @@ -1,4 +1,4 @@ -from panther_base_helpers import aws_rule_context, deep_get, pattern_match_list +from panther_base_helpers import aws_rule_context, pattern_match_list from panther_default import aws_cloudtrail_success PROD_ACCOUNT_IDS = {"11111111111111", "112233445566"} @@ -37,24 +37,24 @@ def rule(event): pattern_match_list(event.get("userAgent"), ALLOWED_USER_AGENTS) and # Validate the IAM Role used is in our acceptable list - any(role in deep_get(event, "userIdentity", "arn") for role in ALLOWED_ROLE_NAMES) + any(role in event.deep_get("userIdentity", "arn") for role in ALLOWED_ROLE_NAMES) ) ) def dedup(event): return ":".join( - deep_get(event, "requestParameters", field, default="") + event.deep_get("requestParameters", field, default="") for field in SG_CHANGE_EVENTS[event.get("eventName")]["fields"] ) def title(event): title_fields = { - field: deep_get(event, "requestParameters", field, default="") + field: event.deep_get("requestParameters", field, default="") for field in SG_CHANGE_EVENTS[event.get("eventName")]["fields"] } - user = deep_get(event, "userIdentity", "arn", default="").split("/")[-1] + user = event.deep_get("userIdentity", "arn", default="").split("/")[-1] title_template = SG_CHANGE_EVENTS[event.get("eventName")]["title"] title_fields["actor"] = user return title_template.format(**title_fields) diff --git a/rules/aws_cloudtrail_rules/aws_ec2_monitoring.py b/rules/aws_cloudtrail_rules/aws_ec2_monitoring.py index 3f41c6af8..b50be7120 100644 --- a/rules/aws_cloudtrail_rules/aws_ec2_monitoring.py +++ b/rules/aws_cloudtrail_rules/aws_ec2_monitoring.py @@ -1,5 +1,3 @@ -from panther_base_helpers import deep_get - # AWS CloudTrail API eventNames for EC2 Image Actions EC2_IMAGE_ACTIONS = [ "CopyFpgaImage", @@ -24,9 +22,9 @@ def rule(event): # though their userIdentity will be more normal. # Example cloudtrail event in the "Terminate instance From WebUI with assumedRole" test event.get("sourceIPAddress", "").endswith(".amazonaws.com") - or deep_get(event, "userIdentity", "type", default="") == "AWSService" - or deep_get(event, "userIdentity", "invokedBy", default="") == "AWS Internal" - or deep_get(event, "userIdentity", "invokedBy", default="").endswith(".amazonaws.com") + or event.deep_get("userIdentity", "type", default="") == "AWSService" + or event.deep_get("userIdentity", "invokedBy", default="") == "AWS Internal" + or event.deep_get("userIdentity", "invokedBy", default="").endswith(".amazonaws.com") ): return False # Dry run operations get logged as SES Internal in the sourceIPAddress @@ -43,7 +41,7 @@ def rule(event): def title(event): return ( - f"[{deep_get(event, 'userIdentity', 'sessionContext', 'sessionIssuer', 'userName')}] " + f"[{event.deep_get('userIdentity', 'sessionContext', 'sessionIssuer', 'userName')}] " f"triggered a CloudTrail action [{event.get('eventName')}] " f"within AWS Account ID: [{event.get('recipientAccountId')}]" ) diff --git a/rules/aws_cloudtrail_rules/aws_ec2_startup_script_change.py b/rules/aws_cloudtrail_rules/aws_ec2_startup_script_change.py index b41b045d9..fd74dbd82 100644 --- a/rules/aws_cloudtrail_rules/aws_ec2_startup_script_change.py +++ b/rules/aws_cloudtrail_rules/aws_ec2_startup_script_change.py @@ -1,9 +1,9 @@ -from panther_base_helpers import aws_rule_context, deep_get +from panther_base_helpers import aws_rule_context def rule(event): - if event.get("eventName") == "ModifyInstanceAttribute" and deep_get( - event, "requestParameters", "userData" + if event.get("eventName") == "ModifyInstanceAttribute" and event.deep_get( + "requestParameters", "userData" ): return True return False @@ -11,18 +11,18 @@ def rule(event): def title(event): return ( - f"[{deep_get(event,'userIdentity','arn')}] " + f"[{event.deep_get('userIdentity','arn')}] " "modified the startup script for " - f" [{deep_get(event, 'requestParameters', 'instanceId')}] " + f" [{event.deep_get('requestParameters', 'instanceId')}] " f"in [{event.get('recipientAccountId')}] - [{event.get('awsRegion')}]" ) def dedup(event): - return deep_get(event, "requestParameters", "instanceId") + return event.deep_get("requestParameters", "instanceId") def alert_context(event): context = aws_rule_context(event) - context["instance_ids"] = [deep_get(event, "requestParameters", "instanceId"), "no_instance_id"] + context["instance_ids"] = [event.deep_get("requestParameters", "instanceId"), "no_instance_id"] return context diff --git a/rules/aws_cloudtrail_rules/aws_ec2_traffic_mirroring.py b/rules/aws_cloudtrail_rules/aws_ec2_traffic_mirroring.py index 564261c2f..44c84a59b 100644 --- a/rules/aws_cloudtrail_rules/aws_ec2_traffic_mirroring.py +++ b/rules/aws_cloudtrail_rules/aws_ec2_traffic_mirroring.py @@ -1,4 +1,4 @@ -from panther_base_helpers import aws_rule_context, deep_get +from panther_base_helpers import aws_rule_context def rule(event): @@ -19,7 +19,7 @@ def rule(event): "ModifyTrafficMirrorFilterRule", "ModifyTrafficMirrorSession", ] - if deep_get(event, "userIdentity", "invokedBy", default="").endswith(".amazonaws.com"): + if event.deep_get("userIdentity", "invokedBy", default="").endswith(".amazonaws.com"): return False return ( event.get("eventSource", "") == "ec2.amazonaws.com" diff --git a/rules/aws_cloudtrail_rules/aws_ecr_crud.py b/rules/aws_cloudtrail_rules/aws_ecr_crud.py index efe79e20b..f5b7c6a81 100644 --- a/rules/aws_cloudtrail_rules/aws_ecr_crud.py +++ b/rules/aws_cloudtrail_rules/aws_ecr_crud.py @@ -1,6 +1,6 @@ from fnmatch import fnmatch -from panther_base_helpers import aws_rule_context, deep_get +from panther_base_helpers import aws_rule_context ECR_CRUD_EVENTS = { "BatchCheckLayerAvailability", @@ -30,7 +30,7 @@ def rule(event): and event.get("eventName") in ECR_CRUD_EVENTS ): for role in ALLOWED_ROLES: - if fnmatch(deep_get(event, "userIdentity", "arn", default="unknown-arn"), role): + if fnmatch(event.deep_get("userIdentity", "arn", default="unknown-arn"), role): return False return True @@ -39,14 +39,14 @@ def rule(event): def title(event): return ( - f"[{deep_get(event, 'userIdentity','arn', default = 'unknown-arn')}] " + f"[{event.deep_get('userIdentity','arn', default = 'unknown-arn')}] " f"performed ECR {event.get('eventName')} in " f"[{event.get('recipientAccountId')} {event.get('awsRegion')}]." ) def dedup(event): - return f"{deep_get(event, 'userIdentity','arn', default = 'unknown-arn')}" + return f"{event.deep_get('userIdentity','arn', default = 'unknown-arn')}" def alert_context(event): diff --git a/rules/aws_cloudtrail_rules/aws_ecr_events.py b/rules/aws_cloudtrail_rules/aws_ecr_events.py index 5d0c91690..2932d2c70 100644 --- a/rules/aws_cloudtrail_rules/aws_ecr_events.py +++ b/rules/aws_cloudtrail_rules/aws_ecr_events.py @@ -1,4 +1,4 @@ -from panther_base_helpers import aws_rule_context, deep_get +from panther_base_helpers import aws_rule_context # CONFIGURATION REQUIRED: Update with your expected AWS Accounts/Regions AWS_ACCOUNTS_AND_REGIONS = { @@ -9,7 +9,7 @@ def rule(event): if event.get("eventSource") == "ecr.amazonaws.com": - aws_account_id = deep_get(event, "userIdentity", "accountId") + aws_account_id = event.deep_get("userIdentity", "accountId") if aws_account_id in AWS_ACCOUNTS_AND_REGIONS: if event.get("awsRegion") not in AWS_ACCOUNTS_AND_REGIONS[aws_account_id]: return True diff --git a/rules/aws_cloudtrail_rules/aws_iam_assume_role_blocklist_ignored.py b/rules/aws_cloudtrail_rules/aws_iam_assume_role_blocklist_ignored.py index 4e14547a7..ccb2a25c9 100644 --- a/rules/aws_cloudtrail_rules/aws_iam_assume_role_blocklist_ignored.py +++ b/rules/aws_cloudtrail_rules/aws_iam_assume_role_blocklist_ignored.py @@ -1,4 +1,4 @@ -from panther_base_helpers import aws_rule_context, deep_get +from panther_base_helpers import aws_rule_context from panther_default import aws_cloudtrail_success # This is a list of role ARNs that should not be assumed by users in normal operations @@ -13,10 +13,10 @@ def rule(event): return False # Only considering user actions - if deep_get(event, "userIdentity", "type") not in ["IAMUser", "FederatedUser"]: + if event.deep_get("userIdentity", "type") not in ["IAMUser", "FederatedUser"]: return False - return deep_get(event, "requestParameters", "roleArn") in ASSUME_ROLE_BLOCKLIST + return event.deep_get("requestParameters", "roleArn") in ASSUME_ROLE_BLOCKLIST def alert_context(event): diff --git a/rules/aws_cloudtrail_rules/aws_iam_entity_created_without_cloudformation.py b/rules/aws_cloudtrail_rules/aws_iam_entity_created_without_cloudformation.py index 82546404c..91f6db9ee 100644 --- a/rules/aws_cloudtrail_rules/aws_iam_entity_created_without_cloudformation.py +++ b/rules/aws_cloudtrail_rules/aws_iam_entity_created_without_cloudformation.py @@ -1,6 +1,6 @@ import re -from panther_base_helpers import aws_rule_context, deep_get +from panther_base_helpers import aws_rule_context from panther_default import aws_cloudtrail_success # The role dedicated for IAM administration @@ -33,7 +33,7 @@ def rule(event): return False # All IAM changes MUST go through CloudFormation - if deep_get(event, "userIdentity", "invokedBy") != "cloudformation.amazonaws.com": + if event.deep_get("userIdentity", "invokedBy") != "cloudformation.amazonaws.com": return True # Only approved IAM Roles can make IAM Changes @@ -43,7 +43,7 @@ def rule(event): len( re.findall( admin_role_pattern, - deep_get(event, "userIdentity", "sessionContext", "sessionIssuer", "arn"), + event.deep_get("userIdentity", "sessionContext", "sessionIssuer", "arn"), ) ) > 0 @@ -51,7 +51,7 @@ def rule(event): return False return ( - deep_get(event, "userIdentity", "sessionContext", "sessionIssuer", "arn") + event.deep_get("userIdentity", "sessionContext", "sessionIssuer", "arn") not in IAM_ADMIN_ROLES ) diff --git a/rules/aws_cloudtrail_rules/aws_iam_user_key_created.py b/rules/aws_cloudtrail_rules/aws_iam_user_key_created.py index d6b82a905..afeaf695d 100644 --- a/rules/aws_cloudtrail_rules/aws_iam_user_key_created.py +++ b/rules/aws_cloudtrail_rules/aws_iam_user_key_created.py @@ -1,4 +1,4 @@ -from panther_base_helpers import aws_rule_context, deep_get +from panther_base_helpers import aws_rule_context from panther_default import aws_cloudtrail_success @@ -8,8 +8,8 @@ def rule(event): and event.get("eventSource") == "iam.amazonaws.com" and event.get("eventName") == "CreateAccessKey" and ( - not deep_get(event, "userIdentity", "arn", default="").endswith( - f"user/{deep_get(event, 'responseElements', 'accessKey', 'userName', default='')}" + not event.deep_get("userIdentity", "arn", default="").endswith( + f"user/{event.deep_get('responseElements', 'accessKey', 'userName', default='')}" ) ) ) @@ -17,14 +17,14 @@ def rule(event): def title(event): return ( - f"[{deep_get(event,'userIdentity','arn')}]" + f"[{event.deep_get('userIdentity','arn')}]" " created API keys for " - f"[{deep_get(event,'responseElements','accessKey','userName', default = '')}]" + f"[{event.deep_get('responseElements','accessKey','userName', default = '')}]" ) def dedup(event): - return f"{deep_get(event,'userIdentity','arn')}" + return f"{event.deep_get('userIdentity','arn')}" def alert_context(event): diff --git a/rules/aws_cloudtrail_rules/aws_iam_user_recon_denied.py b/rules/aws_cloudtrail_rules/aws_iam_user_recon_denied.py index 27563c7b1..77ffe49b1 100644 --- a/rules/aws_cloudtrail_rules/aws_iam_user_recon_denied.py +++ b/rules/aws_cloudtrail_rules/aws_iam_user_recon_denied.py @@ -1,6 +1,6 @@ from ipaddress import ip_address -from panther_base_helpers import aws_rule_context, deep_get +from panther_base_helpers import aws_rule_context from panther_default import lookup_aws_account_name # service/event patterns to monitor @@ -17,7 +17,7 @@ def rule(event): # Filter events if event.get("errorCode") != "AccessDenied": return False - if deep_get(event, "userIdentity", "type") != "IAMUser": + if event.deep_get("userIdentity", "type") != "IAMUser": return False # Console Activity can easily result in false positives as some pages contain a mix of @@ -41,13 +41,13 @@ def rule(event): def dedup(event): - return deep_get(event, "userIdentity", "arn") + return event.deep_get("userIdentity", "arn") def title(event): - user_type = deep_get(event, "userIdentity", "type") + user_type = event.deep_get("userIdentity", "type") if user_type == "IAMUser": - user = deep_get(event, "userIdentity", "userName") + user = event.deep_get("userIdentity", "userName") # root user elif user_type == "Root": user = user_type diff --git a/rules/aws_cloudtrail_rules/aws_key_compromised.py b/rules/aws_cloudtrail_rules/aws_key_compromised.py index 72100aa88..04035f957 100644 --- a/rules/aws_cloudtrail_rules/aws_key_compromised.py +++ b/rules/aws_cloudtrail_rules/aws_key_compromised.py @@ -1,4 +1,4 @@ -from panther_base_helpers import aws_rule_context, deep_get +from panther_base_helpers import aws_rule_context EXPOSED_CRED_POLICY = "AWSExposedCredentialPolicy_DO_NOT_REMOVE" @@ -14,12 +14,12 @@ def rule(event): def dedup(event): - return deep_get(event, "userIdentity", "userName") + return event.deep_get("userIdentity", "userName") def title(event): return ( - f"{dedup(event)}'s access key ID [{deep_get(event, 'userIdentity', 'accessKeyId')}]" + f"{dedup(event)}'s access key ID [{event.deep_get('userIdentity', 'accessKeyId')}]" f" was uploaded to a public GitHub repo" ) diff --git a/rules/aws_cloudtrail_rules/aws_lambda_crud.py b/rules/aws_cloudtrail_rules/aws_lambda_crud.py index 8d67c3886..3a5f5ab10 100644 --- a/rules/aws_cloudtrail_rules/aws_lambda_crud.py +++ b/rules/aws_cloudtrail_rules/aws_lambda_crud.py @@ -1,6 +1,6 @@ from fnmatch import fnmatch -from panther_base_helpers import aws_rule_context, deep_get +from panther_base_helpers import aws_rule_context LAMBDA_CRUD_EVENTS = { "AddPermission", @@ -29,7 +29,7 @@ def rule(event): and event.get("eventName") in LAMBDA_CRUD_EVENTS ): for role in ALLOWED_ROLES: - if fnmatch(deep_get(event, "userIdentity", "arn", default="unknown-arn"), role): + if fnmatch(event.deep_get("userIdentity", "arn", default="unknown-arn"), role): return False return True return False @@ -37,7 +37,7 @@ def rule(event): def title(event): return ( - f"[{deep_get(event, 'userIdentity','arn', default = 'unknown-arn')}] " + f"[{event.deep_get('userIdentity','arn', default = 'unknown-arn')}] " f"performed Lambda " f"[{event.get('eventName')}] in " f"[{event.get('recipientAccountId')} {event.get('awsRegion')}]." @@ -45,7 +45,7 @@ def title(event): def dedup(event): - return f"{deep_get(event, 'userIdentity','arn', default = 'unknown-arn')}" + return f"{event.deep_get('userIdentity','arn', default = 'unknown-arn')}" def alert_context(event): diff --git a/rules/aws_cloudtrail_rules/aws_macie_evasion.py b/rules/aws_cloudtrail_rules/aws_macie_evasion.py index b412dce05..b3cfa02a2 100644 --- a/rules/aws_cloudtrail_rules/aws_macie_evasion.py +++ b/rules/aws_cloudtrail_rules/aws_macie_evasion.py @@ -1,4 +1,4 @@ -from panther_base_helpers import deep_get, pattern_match +from panther_base_helpers import pattern_match MACIE_EVENTS = { "ArchiveFindings", @@ -23,5 +23,5 @@ def rule(event): def title(event): account = event.get("recipientAccountId") - user_arn = deep_get(event, "userIdentity", "arn") + user_arn = event.deep_get("userIdentity", "arn") return f"AWS Macie in AWS Account [{account}] Disabled/Updated by [{user_arn}]" diff --git a/rules/aws_cloudtrail_rules/aws_modify_cloud_compute_infrastructure.py b/rules/aws_cloudtrail_rules/aws_modify_cloud_compute_infrastructure.py index eea7e3a1d..106fc3d06 100644 --- a/rules/aws_cloudtrail_rules/aws_modify_cloud_compute_infrastructure.py +++ b/rules/aws_cloudtrail_rules/aws_modify_cloud_compute_infrastructure.py @@ -1,5 +1,3 @@ -from panther_base_helpers import deep_get - EC2_CRUD_ACTIONS = { "AssociateIamInstanceProfile", "AssociateInstanceEventWindow", @@ -47,9 +45,9 @@ def rule(event): # though their userIdentity will be more normal. # Example cloudtrail event in the "Terminate instance From WebUI with assumedRole" test event.get("sourceIPAddress", "").endswith(".amazonaws.com") - or deep_get(event, "userIdentity", "type", default="") == "AWSService" - or deep_get(event, "userIdentity", "invokedBy", default="") == "AWS Internal" - or deep_get(event, "userIdentity", "invokedBy", default="").endswith(".amazonaws.com") + or event.deep_get("userIdentity", "type", default="") == "AWSService" + or event.deep_get("userIdentity", "invokedBy", default="") == "AWS Internal" + or event.deep_get("userIdentity", "invokedBy", default="").endswith(".amazonaws.com") ): return False # Dry run operations get logged as SES Internal in the sourceIPAddress @@ -64,8 +62,8 @@ def rule(event): def title(event): - items = deep_get( - event, "requestParameters", "instancesSet", "items", default=[{"instanceId": "none"}] + items = event.deep_get( + "requestParameters", "instancesSet", "items", default=[{"instanceId": "none"}] ) return ( f"AWS Event [{event.get('eventName')}] Instance ID " @@ -74,8 +72,8 @@ def title(event): def alert_context(event): - items = deep_get( - event, "requestParameters", "instancesSet", "items", default=[{"instanceId": "none"}] + items = event.deep_get( + "requestParameters", "instancesSet", "items", default=[{"instanceId": "none"}] ) return { "awsRegion": event.get("awsRegion"), diff --git a/rules/aws_cloudtrail_rules/aws_network_acl_permissive_entry.py b/rules/aws_cloudtrail_rules/aws_network_acl_permissive_entry.py index 55e82c6ae..9ff9b29c0 100644 --- a/rules/aws_cloudtrail_rules/aws_network_acl_permissive_entry.py +++ b/rules/aws_cloudtrail_rules/aws_network_acl_permissive_entry.py @@ -1,4 +1,4 @@ -from panther_base_helpers import aws_rule_context, deep_get +from panther_base_helpers import aws_rule_context from panther_default import aws_cloudtrail_success @@ -9,9 +9,9 @@ def rule(event): # Check if this new NACL entry is allowing traffic from anywhere return ( - deep_get(event, "requestParameters", "cidrBlock") == "0.0.0.0/0" - and deep_get(event, "requestParameters", "ruleAction") == "allow" - and deep_get(event, "requestParameters", "egress") is False + event.deep_get("requestParameters", "cidrBlock") == "0.0.0.0/0" + and event.deep_get("requestParameters", "ruleAction") == "allow" + and event.deep_get("requestParameters", "egress") is False ) diff --git a/rules/aws_cloudtrail_rules/aws_rds_master_pass_updated.py b/rules/aws_cloudtrail_rules/aws_rds_master_pass_updated.py index 6cbac1cb5..1ffe1f345 100644 --- a/rules/aws_cloudtrail_rules/aws_rds_master_pass_updated.py +++ b/rules/aws_cloudtrail_rules/aws_rds_master_pass_updated.py @@ -1,15 +1,10 @@ -from panther_base_helpers import deep_get - - def rule(event): return ( event.get("eventName") == "ModifyDBInstance" and event.get("eventSource") == "rds.amazonaws.com" - and bool(deep_get(event, "responseElements", "pendingModifiedValues", "masterUserPassword")) + and bool(event.deep_get("responseElements", "pendingModifiedValues", "masterUserPassword")) ) def title(event): - return ( - f"RDS Master Password Updated on [{deep_get(event, 'responseElements', 'dBInstanceArn')}]" - ) + return f"RDS Master Password Updated on [{event.deep_get('responseElements', 'dBInstanceArn')}]" diff --git a/rules/aws_cloudtrail_rules/aws_rds_publicrestore.py b/rules/aws_cloudtrail_rules/aws_rds_publicrestore.py index 1079e52ec..3a09a26d3 100644 --- a/rules/aws_cloudtrail_rules/aws_rds_publicrestore.py +++ b/rules/aws_cloudtrail_rules/aws_rds_publicrestore.py @@ -1,4 +1,4 @@ -from panther_base_helpers import aws_rule_context, deep_get +from panther_base_helpers import aws_rule_context def rule(event): @@ -6,7 +6,7 @@ def rule(event): event.get("eventSource", "") == "rds.amazonaws.com" and event.get("eventName", "") == "RestoreDBInstanceFromDBSnapshot" ): - if deep_get(event, "responseElements", "publiclyAccessible"): + if event.deep_get("responseElements", "publiclyAccessible"): return True return False diff --git a/rules/aws_cloudtrail_rules/aws_resource_made_public.py b/rules/aws_cloudtrail_rules/aws_resource_made_public.py index 70614c274..9290d820d 100644 --- a/rules/aws_cloudtrail_rules/aws_resource_made_public.py +++ b/rules/aws_cloudtrail_rules/aws_resource_made_public.py @@ -70,8 +70,7 @@ def rule(event): def title(event): # TODO(): Update this rule to use data models - user = deep_get(event, "userIdentity", "userName") or deep_get( - event, + user = event.deep_get("userIdentity", "userName") or event.deep_get( "userIdentity", "sessionContext", "sessionIssuer", diff --git a/rules/aws_cloudtrail_rules/aws_root_access_key_created.py b/rules/aws_cloudtrail_rules/aws_root_access_key_created.py index 0304333ec..f359799b4 100644 --- a/rules/aws_cloudtrail_rules/aws_root_access_key_created.py +++ b/rules/aws_cloudtrail_rules/aws_root_access_key_created.py @@ -1,4 +1,4 @@ -from panther_base_helpers import aws_rule_context, deep_get +from panther_base_helpers import aws_rule_context def rule(event): @@ -7,7 +7,7 @@ def rule(event): return False # Only root can create root access keys - if deep_get(event, "userIdentity", "type") != "Root": + if event.deep_get("userIdentity", "type") != "Root": return False # Only alert if the root user is creating an access key for itself diff --git a/rules/aws_cloudtrail_rules/aws_root_activity.py b/rules/aws_cloudtrail_rules/aws_root_activity.py index 1246f21e8..5439f6a90 100644 --- a/rules/aws_cloudtrail_rules/aws_root_activity.py +++ b/rules/aws_cloudtrail_rules/aws_root_activity.py @@ -1,4 +1,3 @@ -from panther_base_helpers import deep_get from panther_default import aws_cloudtrail_success, lookup_aws_account_name EVENT_ALLOW_LIST = {"CreateServiceLinkedRole"} @@ -6,9 +5,9 @@ def rule(event): return ( - deep_get(event, "userIdentity", "type") == "Root" + event.deep_get("userIdentity", "type") == "Root" and aws_cloudtrail_success(event) - and deep_get(event, "userIdentity", "invokedBy") is None + and event.deep_get("userIdentity", "invokedBy") is None and event.get("eventType") != "AwsServiceEvent" and event.get("eventName") not in EVENT_ALLOW_LIST ) @@ -36,10 +35,10 @@ def title(event): def alert_context(event): return { "sourceIPAddress": event.get("sourceIPAddress"), - "userIdentityAccountId": deep_get(event, "userIdentity", "accountId"), - "userIdentityArn": deep_get(event, "userIdentity", "arn"), + "userIdentityAccountId": event.deep_get("userIdentity", "accountId"), + "userIdentityArn": event.deep_get("userIdentity", "arn"), "eventTime": event.get("eventTime"), - "mfaUsed": deep_get(event, "additionalEventData", "MFAUsed"), + "mfaUsed": event.deep_get("additionalEventData", "MFAUsed"), } diff --git a/rules/aws_cloudtrail_rules/aws_root_console_login.py b/rules/aws_cloudtrail_rules/aws_root_console_login.py index cbfd686ad..8cab6a3b2 100644 --- a/rules/aws_cloudtrail_rules/aws_root_console_login.py +++ b/rules/aws_cloudtrail_rules/aws_root_console_login.py @@ -1,4 +1,4 @@ -from panther_base_helpers import aws_rule_context, deep_get +from panther_base_helpers import aws_rule_context def rule(event): @@ -7,11 +7,11 @@ def rule(event): return False # Only check root activity - if deep_get(event, "userIdentity", "type") != "Root": + if event.deep_get("userIdentity", "type") != "Root": return False # Only alert if the login was a success - return deep_get(event, "responseElements", "ConsoleLogin") == "Success" + return event.deep_get("responseElements", "ConsoleLogin") == "Success" def alert_context(event): diff --git a/rules/aws_cloudtrail_rules/aws_root_failed_console_login.py b/rules/aws_cloudtrail_rules/aws_root_failed_console_login.py index 4435c25cc..4af371b85 100644 --- a/rules/aws_cloudtrail_rules/aws_root_failed_console_login.py +++ b/rules/aws_cloudtrail_rules/aws_root_failed_console_login.py @@ -1,4 +1,4 @@ -from panther_base_helpers import aws_rule_context, deep_get +from panther_base_helpers import aws_rule_context def rule(event): @@ -7,11 +7,11 @@ def rule(event): return False # Only check root activity - if deep_get(event, "userIdentity", "type") != "Root": + if event.deep_get("userIdentity", "type") != "Root": return False # Only alert if the login was a failure - return deep_get(event, "responseElements", "ConsoleLogin") != "Success" + return event.deep_get("responseElements", "ConsoleLogin") != "Success" def alert_context(event): diff --git a/rules/aws_cloudtrail_rules/aws_root_password_changed.py b/rules/aws_cloudtrail_rules/aws_root_password_changed.py index 59b76cb69..769a0ccc5 100644 --- a/rules/aws_cloudtrail_rules/aws_root_password_changed.py +++ b/rules/aws_cloudtrail_rules/aws_root_password_changed.py @@ -1,4 +1,4 @@ -from panther_base_helpers import aws_rule_context, deep_get +from panther_base_helpers import aws_rule_context def rule(event): @@ -7,11 +7,11 @@ def rule(event): return False # Only check root activity - if deep_get(event, "userIdentity", "type") != "Root": + if event.deep_get("userIdentity", "type") != "Root": return False # Only alert if the login was a success - return deep_get(event, "responseElements", "PasswordUpdated") == "Success" + return event.deep_get("responseElements", "PasswordUpdated") == "Success" def alert_context(event): diff --git a/rules/aws_cloudtrail_rules/aws_s3_activity_greynoise.py b/rules/aws_cloudtrail_rules/aws_s3_activity_greynoise.py index 1be740fc3..3ee15a472 100644 --- a/rules/aws_cloudtrail_rules/aws_s3_activity_greynoise.py +++ b/rules/aws_cloudtrail_rules/aws_s3_activity_greynoise.py @@ -1,6 +1,6 @@ from ipaddress import ip_address -from panther_base_helpers import deep_get, pattern_match_list +from panther_base_helpers import pattern_match_list from panther_greynoise_helpers import GetGreyNoiseObject, GetGreyNoiseRiotObject # pylint: disable=too-many-return-statements,invalid-name,unused-argument,global-at-module-level,global-variable-undefined @@ -29,7 +29,7 @@ def rule(event): if event.get("errorCode"): return False # Filter: Internal AWS - if deep_get(event, "userIdentity", "type") in ("AWSAccount", "AWSService"): + if event.deep_get("userIdentity", "type") in ("AWSAccount", "AWSService"): return False # Filter: Non "Get" events if not pattern_match_list(event.get("eventName"), _S3_EVENT_LIST): @@ -53,7 +53,7 @@ def rule(event): # Check that the IP is classified as 'malicious' if NOISE.classification("sourceIPAddress") == "malicious": # Filter: Roles that generate FP's if used from AWS IP Space - if pattern_match_list(deep_get(event, "userIdentity", "arn"), _ALLOWED_ROLES): + if pattern_match_list(event.deep_get("userIdentity", "arn"), _ALLOWED_ROLES): # Only Greynoise advanced provides AS organization info if NOISE.subscription_level() == "advanced": if NOISE.organization("sourceIPAddress") == "Amazon.com, Inc.": @@ -68,8 +68,8 @@ def rule(event): def title(event): # Group by ip-arn combinations - ip = deep_get(event, "sourceIPAddress") - arn = deep_get(event, "userIdentity", "arn") + ip = event.deep_get("sourceIPAddress") + arn = event.deep_get("userIdentity", "arn") return f"GreyNoise malicious S3 events detected by {ip} from {arn}" diff --git a/rules/aws_cloudtrail_rules/aws_s3_bucket_deleted.py b/rules/aws_cloudtrail_rules/aws_s3_bucket_deleted.py index 73e57f59e..5e8ee9f11 100644 --- a/rules/aws_cloudtrail_rules/aws_s3_bucket_deleted.py +++ b/rules/aws_cloudtrail_rules/aws_s3_bucket_deleted.py @@ -1,4 +1,4 @@ -from panther_base_helpers import aws_rule_context, deep_get +from panther_base_helpers import aws_rule_context from panther_default import aws_cloudtrail_success @@ -23,7 +23,7 @@ def dedup(event): def title(event): - return f"{deep_get(event, 'userIdentity', 'type')} [{dedup(event)}] destroyed a bucket" + return f"{event.deep_get('userIdentity', 'type')} [{dedup(event)}] destroyed a bucket" def alert_context(event): diff --git a/rules/aws_cloudtrail_rules/aws_s3_bucket_policy_modified.py b/rules/aws_cloudtrail_rules/aws_s3_bucket_policy_modified.py index 5faa33c72..49d92f7d6 100644 --- a/rules/aws_cloudtrail_rules/aws_s3_bucket_policy_modified.py +++ b/rules/aws_cloudtrail_rules/aws_s3_bucket_policy_modified.py @@ -1,4 +1,4 @@ -from panther_base_helpers import aws_rule_context, deep_get +from panther_base_helpers import aws_rule_context from panther_default import aws_cloudtrail_success # API calls that are indicative of KMS CMK Deletion @@ -20,7 +20,7 @@ def rule(event): def title(event): - return f"S3 bucket modified by [{deep_get(event, 'userIdentity', 'arn')}]" + return f"S3 bucket modified by [{event.deep_get('userIdentity', 'arn')}]" def alert_context(event): diff --git a/rules/aws_cloudtrail_rules/aws_saml_activity.py b/rules/aws_cloudtrail_rules/aws_saml_activity.py index be99ecb62..2a43a1e12 100644 --- a/rules/aws_cloudtrail_rules/aws_saml_activity.py +++ b/rules/aws_cloudtrail_rules/aws_saml_activity.py @@ -1,11 +1,11 @@ -from panther_base_helpers import aws_rule_context, deep_get +from panther_base_helpers import aws_rule_context SAML_ACTIONS = ["UpdateSAMLProvider", "CreateSAMLProvider", "DeleteSAMLProvider"] def rule(event): # Allow AWSSSO to manage - if deep_get(event, "userIdentity", "arn", default="").endswith( + if event.deep_get("userIdentity", "arn", default="").endswith( ":assumed-role/AWSServiceRoleForSSO/AWS-SSO" ): return False @@ -19,7 +19,7 @@ def rule(event): def title(event): return ( - f"[{deep_get(event,'userIdentity','arn')}] " + f"[{event.deep_get('userIdentity','arn')}] " f"performed [{event.get('eventName')}] " f"in account [{event.get('recipientAccountId')}]" ) diff --git a/rules/aws_cloudtrail_rules/aws_security_configuration_change.py b/rules/aws_cloudtrail_rules/aws_security_configuration_change.py index 8bc13018a..1a8e281fd 100644 --- a/rules/aws_cloudtrail_rules/aws_security_configuration_change.py +++ b/rules/aws_cloudtrail_rules/aws_security_configuration_change.py @@ -2,7 +2,7 @@ from fnmatch import fnmatch from unittest.mock import MagicMock -from panther_base_helpers import aws_rule_context, deep_get +from panther_base_helpers import aws_rule_context from panther_default import aws_cloudtrail_success SECURITY_CONFIG_ACTIONS = { @@ -34,8 +34,7 @@ def rule(event): for entry in ALLOW_LIST: if fnmatch( - deep_get( - event, + event.deep_get( "userIdentity", "sessionContext", "sessionIssuer", @@ -48,14 +47,14 @@ def rule(event): return False if event.get("eventName") == "UpdateDetector": - return not deep_get(event, "requestParameters", "enable", default=True) + return not event.deep_get("requestParameters", "enable", default=True) return event.get("eventName") in SECURITY_CONFIG_ACTIONS def title(event): - user = deep_get(event, "userIdentity", "userName") or deep_get( - event, "userIdentity", "sessionContext", "sessionIssuer", "userName" + user = event.deep_get("userIdentity", "userName") or event.deep_get( + "userIdentity", "sessionContext", "sessionIssuer", "userName" ) return f"Sensitive AWS API call {event.get('eventName')} made by {user}" diff --git a/rules/aws_cloudtrail_rules/aws_snapshot_backup_exfiltration.py b/rules/aws_cloudtrail_rules/aws_snapshot_backup_exfiltration.py index 99172bbf6..35a44035c 100644 --- a/rules/aws_cloudtrail_rules/aws_snapshot_backup_exfiltration.py +++ b/rules/aws_cloudtrail_rules/aws_snapshot_backup_exfiltration.py @@ -1,4 +1,4 @@ -from panther_base_helpers import aws_rule_context, deep_get +from panther_base_helpers import aws_rule_context def rule(event): @@ -10,9 +10,9 @@ def rule(event): def title(event): return ( - f"[{deep_get(event,'userIdentity','arn')}] " + f"[{event.deep_get('userIdentity','arn')}] " "modified snapshot attributes for " - f"[{deep_get(event,'requestParameters','snapshotId')}] " + f"[{event.deep_get('requestParameters','snapshotId')}] " f"in [{event.get('recipientAccountId')}] - [{event.get('awsRegion')}]." ) diff --git a/rules/aws_cloudtrail_rules/aws_software_discovery.py b/rules/aws_cloudtrail_rules/aws_software_discovery.py index 7439361f2..f0b8ca712 100644 --- a/rules/aws_cloudtrail_rules/aws_software_discovery.py +++ b/rules/aws_cloudtrail_rules/aws_software_discovery.py @@ -1,4 +1,4 @@ -from panther_base_helpers import aws_rule_context, deep_get +from panther_base_helpers import aws_rule_context DISCOVERY_EVENTS = [ "ListDocuments", @@ -29,14 +29,14 @@ def rule(event): def title(event): return ( - f"User [{deep_get(event, 'userIdentity', 'principalId')}] " + f"User [{event.deep_get('userIdentity', 'principalId')}] " f"performed a [{event.get('eventName')}] " f"action in AWS account [{event.get('recipientAccountId')}]." ) def dedup(event): - return deep_get(event, "userIdentity", "principalId", default="NO_PRINCIPAL_ID_FOUND") + return event.deep_get("userIdentity", "principalId", default="NO_PRINCIPAL_ID_FOUND") def alert_context(event): diff --git a/rules/aws_cloudtrail_rules/aws_unauthorized_api_call.py b/rules/aws_cloudtrail_rules/aws_unauthorized_api_call.py index 2f81243e7..e62616c77 100644 --- a/rules/aws_cloudtrail_rules/aws_unauthorized_api_call.py +++ b/rules/aws_cloudtrail_rules/aws_unauthorized_api_call.py @@ -1,6 +1,6 @@ from ipaddress import ip_address -from panther_base_helpers import aws_rule_context, deep_get +from panther_base_helpers import aws_rule_context # Do not alert on these access denied errors for these events. # Events could be exceptions because they are particularly noisy and provide little to no value, @@ -23,11 +23,11 @@ def rule(event): def dedup(event): - return deep_get(event, "userIdentity", "principalId", default="") + return event.deep_get("userIdentity", "principalId", default="") def title(event): - return f"Access denied to {deep_get(event, 'userIdentity', 'type')} [{dedup(event)}]" + return f"Access denied to {event.deep_get('userIdentity', 'type')} [{dedup(event)}]" def alert_context(event): diff --git a/rules/aws_cloudtrail_rules/aws_unused_region.py b/rules/aws_cloudtrail_rules/aws_unused_region.py index c254793c8..3af9f15da 100644 --- a/rules/aws_cloudtrail_rules/aws_unused_region.py +++ b/rules/aws_cloudtrail_rules/aws_unused_region.py @@ -1,4 +1,4 @@ -from panther_base_helpers import aws_rule_context, deep_get +from panther_base_helpers import aws_rule_context # Define a list of verboten or unused regions # Could modify to include expected user mappings: { "123456789012": { "us-west-1", "us-east-2" } } @@ -15,7 +15,7 @@ def rule(event): def title(event): - aws_username = deep_get(event, "userIdentity", "sessionContext", "sessionIssuer", "userName") + aws_username = event.deep_get("userIdentity", "sessionContext", "sessionIssuer", "userName") return ( "Non-read-only API call in unused region" f" {event.get('awsRegion', '')} by user {aws_username}" diff --git a/rules/aws_cloudtrail_rules/aws_update_credentials.py b/rules/aws_cloudtrail_rules/aws_update_credentials.py index ffb7de5f4..9e79e2113 100644 --- a/rules/aws_cloudtrail_rules/aws_update_credentials.py +++ b/rules/aws_cloudtrail_rules/aws_update_credentials.py @@ -1,4 +1,4 @@ -from panther_base_helpers import aws_rule_context, deep_get +from panther_base_helpers import aws_rule_context from panther_default import aws_cloudtrail_success UPDATE_EVENTS = {"ChangePassword", "CreateAccessKey", "CreateLoginProfile", "CreateUser"} @@ -9,12 +9,12 @@ def rule(event): def dedup(event): - return deep_get(event, "userIdentity", "userName", default="") + return event.deep_get("userIdentity", "userName", default="") def title(event): return ( - f"{deep_get(event, 'userIdentity', 'type')} [{deep_get(event, 'userIdentity', 'arn')}]" + f"{event.deep_get('userIdentity', 'type')} [{event.deep_get('userIdentity', 'arn')}]" f" has updated their IAM credentials" ) diff --git a/rules/aws_cloudtrail_rules/aws_user_login_profile_modified.py b/rules/aws_cloudtrail_rules/aws_user_login_profile_modified.py index 73999ca06..e706c0597 100644 --- a/rules/aws_cloudtrail_rules/aws_user_login_profile_modified.py +++ b/rules/aws_cloudtrail_rules/aws_user_login_profile_modified.py @@ -1,22 +1,22 @@ -from panther_base_helpers import aws_rule_context, deep_get +from panther_base_helpers import aws_rule_context def rule(event): return ( event.get("eventSource", "") == "iam.amazonaws.com" and event.get("eventName", "") == "UpdateLoginProfile" - and not deep_get(event, "requestParameters", "passwordResetRequired", default=False) - and not deep_get(event, "userIdentity", "arn", default="").endswith( - f"/{deep_get(event, 'requestParameters', 'userName', default='')}" + and not event.deep_get("requestParameters", "passwordResetRequired", default=False) + and not event.deep_get("userIdentity", "arn", default="").endswith( + f"/{event.deep_get('requestParameters', 'userName', default='')}" ) ) def title(event): return ( - f"User [{deep_get(event, 'userIdentity', 'arn').split('/')[-1]}] " + f"User [{event.deep_get('userIdentity', 'arn').split('/')[-1]}] " f"changed the password for " - f"[{deep_get(event, 'requestParameters','userName')}]" + f"[{event.deep_get('requestParameters','userName')}]" ) diff --git a/rules/aws_cloudtrail_rules/aws_waf_disassociation.py b/rules/aws_cloudtrail_rules/aws_waf_disassociation.py index 39ace2f3b..42a325e4f 100644 --- a/rules/aws_cloudtrail_rules/aws_waf_disassociation.py +++ b/rules/aws_cloudtrail_rules/aws_waf_disassociation.py @@ -1,6 +1,3 @@ -from panther_base_helpers import deep_get - - def rule(event): return event.get("eventName") == "DisassociateWebACL" @@ -8,7 +5,7 @@ def rule(event): def title(event): return ( f"AWS Account ID [{event.get('recipientAccountId')}] " - f"disassociated WebACL [{deep_get(event, 'requestParameters', 'resourceArn')}]" + f"disassociated WebACL [{event.deep_get('requestParameters', 'resourceArn')}]" ) @@ -18,6 +15,6 @@ def alert_context(event): "eventName": event.get("eventName"), "recipientAccountId": event.get("recipientAccountId"), "requestID": event.get("requestID"), - "requestParameters": deep_get(event, "requestParameters", "resourceArn"), - "userIdentity": deep_get(event, "userIdentity", "principalId"), + "requestParameters": event.deep_get("requestParameters", "resourceArn"), + "userIdentity": event.deep_get("userIdentity", "principalId"), } diff --git a/rules/aws_eks_rules/system_namespace_public_ip.py b/rules/aws_eks_rules/system_namespace_public_ip.py index 06795689b..2095224b7 100644 --- a/rules/aws_eks_rules/system_namespace_public_ip.py +++ b/rules/aws_eks_rules/system_namespace_public_ip.py @@ -1,6 +1,6 @@ from ipaddress import ip_address -from panther_base_helpers import deep_get, eks_panther_obj_ref +from panther_base_helpers import eks_panther_obj_ref # Explicitly ignore eks:node-manager and eks:addon-manager # which are run as Lambdas and originate from public IPs @@ -22,7 +22,7 @@ def rule(event): if ( p_eks.get("actor") in AMZ_PUBLICS and ":assumed-role/AWSWesleyClusterManagerLambda" - in deep_get(event, "user", "extra", "arn", default=["not found"])[0] + in event.deep_get("user", "extra", "arn", default=["not found"])[0] ): return False if ( diff --git a/rules/aws_guardduty_rules/aws_guardduty_high_sev_findings.py b/rules/aws_guardduty_rules/aws_guardduty_high_sev_findings.py index 2ef274956..97434670f 100644 --- a/rules/aws_guardduty_rules/aws_guardduty_high_sev_findings.py +++ b/rules/aws_guardduty_rules/aws_guardduty_high_sev_findings.py @@ -1,8 +1,8 @@ -from panther_base_helpers import aws_guardduty_context, deep_get +from panther_base_helpers import aws_guardduty_context def rule(event): - if deep_get(event, "service", "additionalInfo", "sample"): + if event.deep_get("service", "additionalInfo", "sample"): # in case of sample data # https://docs.aws.amazon.com/guardduty/latest/ug/sample_findings.html return False diff --git a/rules/aws_guardduty_rules/aws_guardduty_low_sev_findings.py b/rules/aws_guardduty_rules/aws_guardduty_low_sev_findings.py index 2a2071f18..086b05984 100644 --- a/rules/aws_guardduty_rules/aws_guardduty_low_sev_findings.py +++ b/rules/aws_guardduty_rules/aws_guardduty_low_sev_findings.py @@ -1,8 +1,8 @@ -from panther_base_helpers import aws_guardduty_context, deep_get +from panther_base_helpers import aws_guardduty_context def rule(event): - if deep_get(event, "service", "additionalInfo", "sample"): + if event.deep_get("service", "additionalInfo", "sample"): # in case of sample data # https://docs.aws.amazon.com/guardduty/latest/ug/sample_findings.html return False diff --git a/rules/aws_guardduty_rules/aws_guardduty_med_sev_findings.py b/rules/aws_guardduty_rules/aws_guardduty_med_sev_findings.py index 1f5c183de..6931d9567 100644 --- a/rules/aws_guardduty_rules/aws_guardduty_med_sev_findings.py +++ b/rules/aws_guardduty_rules/aws_guardduty_med_sev_findings.py @@ -1,8 +1,8 @@ -from panther_base_helpers import aws_guardduty_context, deep_get +from panther_base_helpers import aws_guardduty_context def rule(event): - if deep_get(event, "service", "additionalInfo", "sample"): + if event.deep_get("service", "additionalInfo", "sample"): # in case of sample data # https://docs.aws.amazon.com/guardduty/latest/ug/sample_findings.html return False diff --git a/rules/azure_signin_rules/azure_failed_signins.py b/rules/azure_signin_rules/azure_failed_signins.py index d8d3917e1..ca7593abd 100644 --- a/rules/azure_signin_rules/azure_failed_signins.py +++ b/rules/azure_signin_rules/azure_failed_signins.py @@ -1,6 +1,5 @@ from global_filter_azuresignin import filter_include_event from panther_azuresignin_helpers import actor_user, azure_signin_alert_context, is_sign_in_event -from panther_base_helpers import deep_get def rule(event): @@ -9,7 +8,7 @@ def rule(event): if not filter_include_event(event): return False - error_code = deep_get(event, "properties", "status", "errorCode", default=0) + error_code = event.deep_get("properties", "status", "errorCode", default=0) return error_code > 0 diff --git a/rules/azure_signin_rules/azure_legacyauth.py b/rules/azure_signin_rules/azure_legacyauth.py index 36fbb6065..a605819e6 100644 --- a/rules/azure_signin_rules/azure_legacyauth.py +++ b/rules/azure_signin_rules/azure_legacyauth.py @@ -3,7 +3,6 @@ from global_filter_azuresignin import filter_include_event from panther_azuresignin_helpers import actor_user, azure_signin_alert_context, is_sign_in_event -from panther_base_helpers import deep_get LEGACY_AUTH_USERAGENTS = ["BAV2ROPC", "CBAInPROD"] # CBAInPROD is reported to be IMAP @@ -23,8 +22,8 @@ def rule(event): return False if actor_user(event) in KNOWN_EXCEPTIONS: return False - user_agent = deep_get(event, "properties", "userAgent", default="") - error_code = deep_get(event, "properties", "status", "errorCode", default=0) + user_agent = event.deep_get("properties", "userAgent", default="") + error_code = event.deep_get("properties", "status", "errorCode", default=0) return all([user_agent in LEGACY_AUTH_USERAGENTS, error_code == 0]) @@ -45,5 +44,5 @@ def dedup(event): def alert_context(event): a_c = azure_signin_alert_context(event) - a_c["userAgent"] = deep_get(event, "properties", "userAgent", "") + a_c["userAgent"] = event.deep_get("properties", "userAgent", "") return a_c diff --git a/rules/azure_signin_rules/azure_risklevel_passthrough.py b/rules/azure_signin_rules/azure_risklevel_passthrough.py index 3972c1d0b..515bca767 100644 --- a/rules/azure_signin_rules/azure_risklevel_passthrough.py +++ b/rules/azure_signin_rules/azure_risklevel_passthrough.py @@ -1,6 +1,5 @@ from global_filter_azuresignin import filter_include_event from panther_azuresignin_helpers import actor_user, azure_signin_alert_context, is_sign_in_event -from panther_base_helpers import deep_get PASSTHROUGH_SEVERITIES = {"low", "medium", "high"} @@ -14,15 +13,15 @@ def rule(event): global IDENTIFIED_RISK_LEVEL # pylint: disable=global-variable-undefined IDENTIFIED_RISK_LEVEL = "" # Do not pass through risks marked as dismissed or remediated in AD - if deep_get(event, "properties", "riskState", default="").lower() in [ + if event.deep_get("properties", "riskState", default="").lower() in [ "dismissed", "remediated", ]: return False # check riskLevelAggregated for risk_type in ["riskLevelAggregated", "riskLevelDuringSignIn"]: - if deep_get(event, "properties", risk_type, default="").lower() in PASSTHROUGH_SEVERITIES: - IDENTIFIED_RISK_LEVEL = deep_get(event, "properties", risk_type).lower() + if event.deep_get("properties", risk_type, default="").lower() in PASSTHROUGH_SEVERITIES: + IDENTIFIED_RISK_LEVEL = event.deep_get("properties", risk_type).lower() return True return False diff --git a/rules/box_rules/box_access_granted.py b/rules/box_rules/box_access_granted.py index 1d09f8b11..10a34c1c3 100644 --- a/rules/box_rules/box_access_granted.py +++ b/rules/box_rules/box_access_granted.py @@ -1,12 +1,9 @@ -from panther_base_helpers import deep_get - - def rule(event): return event.get("event_type") == "ACCESS_GRANTED" def title(event): return ( - f"User [{deep_get(event, 'created_by', 'name', default='')}] granted " + f"User [{event.deep_get('created_by', 'name', default='')}] granted " f"access to their account" ) diff --git a/rules/box_rules/box_anomalous_download.py b/rules/box_rules/box_anomalous_download.py index fa6550efc..6e96785f0 100644 --- a/rules/box_rules/box_anomalous_download.py +++ b/rules/box_rules/box_anomalous_download.py @@ -19,5 +19,5 @@ def title(event): return description return ( f"Anomalous download activity triggered by user " - f"[{deep_get(event, 'created_by', 'name', default='')}]." + f"[{event.deep_get('created_by', 'name', default='')}]." ) diff --git a/rules/box_rules/box_brute_force_login.py b/rules/box_rules/box_brute_force_login.py index e2cb6994c..e40213e79 100644 --- a/rules/box_rules/box_brute_force_login.py +++ b/rules/box_rules/box_brute_force_login.py @@ -1,12 +1,9 @@ -from panther_base_helpers import deep_get - - def rule(event): return event.get("event_type") == "FAILED_LOGIN" def title(event): return ( - f"User [{deep_get(event, 'source', 'name', default='')}]" + f"User [{event.deep_get('source', 'name', default='')}]" f" has exceeded the failed login threshold." ) diff --git a/rules/box_rules/box_event_triggered_externally.py b/rules/box_rules/box_event_triggered_externally.py index defda7226..a882a39da 100644 --- a/rules/box_rules/box_event_triggered_externally.py +++ b/rules/box_rules/box_event_triggered_externally.py @@ -1,4 +1,3 @@ -from panther_base_helpers import deep_get from panther_config import config DOMAINS = {"@" + domain for domain in config.ORGANIZATION_DOMAINS} @@ -19,6 +18,6 @@ def rule(event): def title(event): return ( - f"External user [{deep_get(event, 'created_by', 'login', default='')}] " + f"External user [{event.deep_get('created_by', 'login', default='')}] " f"triggered a box event." ) diff --git a/rules/box_rules/box_item_shared_externally.py b/rules/box_rules/box_item_shared_externally.py index 49a3f19be..aaa0898c5 100644 --- a/rules/box_rules/box_item_shared_externally.py +++ b/rules/box_rules/box_item_shared_externally.py @@ -24,18 +24,18 @@ def rule(event): def get_item(event): - item_id = deep_get(event, "source", "item_id", default="") - user_id = deep_get(event, "source", "owned_by", "id", default="") + item_id = event.deep_get("source", "item_id", default="") + user_id = event.deep_get("source", "owned_by", "id", default="") item = {} - if deep_get(event, "source", "item_type") == "folder": + if event.deep_get("source", "item_type") == "folder": item = lookup_box_folder(user_id, item_id) - elif deep_get(event, "source", "item_type") == "file": + elif event.deep_get("source", "item_type") == "file": item = lookup_box_file(user_id, item_id) return item def title(event): return ( - f"User [{deep_get(event, 'created_by', 'login', default='')}] shared an item " - f"[{deep_get(event, 'source', 'item_name', default='')}] externally." + f"User [{event.deep_get('created_by', 'login', default='')}] shared an item " + f"[{event.deep_get('source', 'item_name', default='')}] externally." ) diff --git a/rules/box_rules/box_malicious_content.py b/rules/box_rules/box_malicious_content.py index f6b294ab0..ab040fa5b 100644 --- a/rules/box_rules/box_malicious_content.py +++ b/rules/box_rules/box_malicious_content.py @@ -18,8 +18,8 @@ def rule(event): def title(event): if event.get("event_type") == "FILE_MARKED_MALICIOUS": return ( - f"File [{deep_get(event, 'source', 'item_name', default='')}], owned by " - f"[{deep_get(event, 'source', 'owned_by', 'login', default='')}], " + f"File [{event.deep_get('source', 'item_name', default='')}], owned by " + f"[{event.deep_get('source', 'owned_by', 'login', default='')}], " f"was marked malicious." ) diff --git a/rules/box_rules/box_new_login.py b/rules/box_rules/box_new_login.py index 80e6d60e2..1a064e38f 100644 --- a/rules/box_rules/box_new_login.py +++ b/rules/box_rules/box_new_login.py @@ -1,6 +1,3 @@ -from panther_base_helpers import deep_get - - def rule(event): # ADD_LOGIN_ACTIVITY_DEVICE # detect when a user logs in from a device not previously seen @@ -9,6 +6,6 @@ def rule(event): def title(event): return ( - f"User [{deep_get(event, 'created_by', 'name', default='')}] " + f"User [{event.deep_get('created_by', 'name', default='')}] " f"logged in from a new device." ) diff --git a/rules/box_rules/box_policy_violation.py b/rules/box_rules/box_policy_violation.py index 05a055eee..5aba51d38 100644 --- a/rules/box_rules/box_policy_violation.py +++ b/rules/box_rules/box_policy_violation.py @@ -1,5 +1,3 @@ -from panther_base_helpers import deep_get - POLICY_VIOLATIONS = { "CONTENT_WORKFLOW_UPLOAD_POLICY_VIOLATION", "CONTENT_WORKFLOW_SHARING_POLICY_VIOLATION", @@ -12,6 +10,6 @@ def rule(event): def title(event): return ( - f"User [{deep_get(event, 'created_by', 'name', default='')}] " + f"User [{event.deep_get('created_by', 'name', default='')}] " f"violated a content workflow policy." ) diff --git a/rules/box_rules/box_untrusted_device.py b/rules/box_rules/box_untrusted_device.py index 58a4eb70d..2511c3261 100644 --- a/rules/box_rules/box_untrusted_device.py +++ b/rules/box_rules/box_untrusted_device.py @@ -1,6 +1,3 @@ -from panther_base_helpers import deep_get - - def rule(event): # DEVICE_TRUST_CHECK_FAILED # detect when a user attempts to login from an untrusted device @@ -9,6 +6,6 @@ def rule(event): def title(event): return ( - f"User [{deep_get(event, 'created_by', 'name', default='')}] " + f"User [{event.deep_get('created_by', 'name', default='')}] " f"attempted to login from an untrusted device." ) diff --git a/rules/box_rules/box_user_downloads.py b/rules/box_rules/box_user_downloads.py index 535379224..90a70c082 100644 --- a/rules/box_rules/box_user_downloads.py +++ b/rules/box_rules/box_user_downloads.py @@ -1,12 +1,9 @@ -from panther_base_helpers import deep_get - - def rule(event): return event.get("event_type") == "DOWNLOAD" def title(event): return ( - f"User [{deep_get(event, 'created_by', 'login', default='')}] " + f"User [{event.deep_get('created_by', 'login', default='')}] " f"exceeded threshold for number of downloads in the configured time frame." ) diff --git a/rules/box_rules/box_user_permission_updates.py b/rules/box_rules/box_user_permission_updates.py index cf51e0432..1026b2fd1 100644 --- a/rules/box_rules/box_user_permission_updates.py +++ b/rules/box_rules/box_user_permission_updates.py @@ -1,5 +1,3 @@ -from panther_base_helpers import deep_get - PERMISSION_UPDATE_EVENT_TYPES = { "CHANGE_FOLDER_PERMISSION", "ITEM_SHARED_CREATE", @@ -14,6 +12,6 @@ def rule(event): def title(event): return ( - f"User [{deep_get(event, 'created_by', 'login', default='')}]" + f"User [{event.deep_get('created_by', 'login', default='')}]" f" exceeded threshold for number of permission changes in the configured time frame." ) diff --git a/rules/dropbox_rules/dropbox_admin_sign_in_as_session.py b/rules/dropbox_rules/dropbox_admin_sign_in_as_session.py index fff38699e..1d841910c 100644 --- a/rules/dropbox_rules/dropbox_admin_sign_in_as_session.py +++ b/rules/dropbox_rules/dropbox_admin_sign_in_as_session.py @@ -1,11 +1,8 @@ -from panther_base_helpers import deep_get - - def rule(event): - return deep_get(event, "event_type", "_tag", default="") == "sign_in_as_session_start" + return event.deep_get("event_type", "_tag", default="") == "sign_in_as_session_start" def title(event): - actor = deep_get(event, "actor", "admin", "email", default="") - target = deep_get(event, "context", "email", default="") + actor = event.deep_get("actor", "admin", "email", default="") + target = event.deep_get("context", "email", default="") return f"Dropbox: Admin [{actor}] started a sign-in-as session as user [{target}]." diff --git a/rules/dropbox_rules/dropbox_external_share.py b/rules/dropbox_rules/dropbox_external_share.py index 86a9f206a..813749567 100644 --- a/rules/dropbox_rules/dropbox_external_share.py +++ b/rules/dropbox_rules/dropbox_external_share.py @@ -1,7 +1,6 @@ import json from unittest.mock import MagicMock -from panther_base_helpers import deep_get from panther_config import config DROPBOX_ALLOWED_SHARE_DOMAINS = config.DROPBOX_ALLOWED_SHARE_DOMAINS @@ -13,7 +12,7 @@ def rule(event): DROPBOX_ALLOWED_SHARE_DOMAINS = set( json.loads(DROPBOX_ALLOWED_SHARE_DOMAINS()) ) # pylint: disable=not-callable - if deep_get(event, "event_type", "_tag", default="") == "shared_content_add_member": + if event.deep_get("event_type", "_tag", default="") == "shared_content_add_member": participants = event.get("participants", [{}]) for participant in participants: email = participant.get("user", {}).get("email", "") @@ -23,7 +22,7 @@ def rule(event): def title(event): - actor = deep_get(event, "actor", "user", "email", default="") + actor = event.deep_get("actor", "user", "email", default="") assets = [e.get("display_name", "") for e in event.get("assets", [{}])] participants = event.get("participants", [{}]) external_participants = [] diff --git a/rules/dropbox_rules/dropbox_linked_team_application_added.py b/rules/dropbox_rules/dropbox_linked_team_application_added.py index 74dce17e4..ec3a47691 100644 --- a/rules/dropbox_rules/dropbox_linked_team_application_added.py +++ b/rules/dropbox_rules/dropbox_linked_team_application_added.py @@ -1,11 +1,8 @@ -from panther_base_helpers import deep_get - - def rule(event): return all( [ - deep_get(event, "event_type", "_tag", default="") == "app_link_team", - deep_get(event, "event_type", "description", default="") == "Linked app for team", + event.deep_get("event_type", "_tag", default="") == "app_link_team", + event.deep_get("event_type", "description", default="") == "Linked app for team", ] ) @@ -39,8 +36,8 @@ def title(event): # find the intersection and use that for the key actor_key = set(tuple(event.get("actor", {}).keys())).intersection(get_actor_type()) if len(actor_key) == 1: - display_name = deep_get( - event, "actor", tuple(actor_key)[0], "display_name", default="" + display_name = event.deep_get( + "actor", tuple(actor_key)[0], "display_name", default="" ) # Explicitly use "" if we find any length of keys != 1 else: @@ -64,13 +61,13 @@ def alert_context(event): additional_user_details = user_details(event) return { "additional_user_details": additional_user_details, - "app_display_name": deep_get( - event, "details", "app_info", "display_name", default="" + "app_display_name": event.deep_get( + "details", "app_info", "display_name", default="" ), - "ip_address": deep_get( - event, "origin", "geo_location", "ip_address", default="" + "ip_address": event.deep_get( + "origin", "geo_location", "ip_address", default="" ), - "request_id": deep_get( - event, "origin", "access_method", "request_id", default="" + "request_id": event.deep_get( + "origin", "access_method", "request_id", default="" ), } diff --git a/rules/dropbox_rules/dropbox_ownership_transfer.py b/rules/dropbox_rules/dropbox_ownership_transfer.py index 0392372c6..a12597a94 100644 --- a/rules/dropbox_rules/dropbox_ownership_transfer.py +++ b/rules/dropbox_rules/dropbox_ownership_transfer.py @@ -1,22 +1,21 @@ import json from unittest.mock import MagicMock -from panther_base_helpers import deep_get from panther_config import config DROPBOX_TRUSTED_OWNERSHIP_DOMAINS = config.DROPBOX_TRUSTED_OWNERSHIP_DOMAINS def rule(event): - return "Transferred ownership " in deep_get(event, "event_type", "description", default="") + return "Transferred ownership " in event.deep_get("event_type", "description", default="") def title(event): - actor = deep_get(event, "actor", "user", "email", default="") - previous_owner = deep_get( - event, "details", "previous_owner_email", default="" + actor = event.deep_get("actor", "user", "email", default="") + previous_owner = event.deep_get( + "details", "previous_owner_email", default="" ) - new_owner = deep_get(event, "details", "new_owner_email", default="") + new_owner = event.deep_get("details", "new_owner_email", default="") assets = event.get("assets", [{}]) asset = [a.get("display_name", "") for a in assets] return ( @@ -31,7 +30,7 @@ def severity(event): DROPBOX_TRUSTED_OWNERSHIP_DOMAINS = set( json.loads(DROPBOX_TRUSTED_OWNERSHIP_DOMAINS()) ) # pylint: disable=not-callable - new_owner = deep_get(event, "details", "new_owner_email", default="") + new_owner = event.deep_get("details", "new_owner_email", default="") if new_owner.split("@")[-1] not in DROPBOX_TRUSTED_OWNERSHIP_DOMAINS: return "HIGH" return "LOW" diff --git a/rules/dropbox_rules/dropbox_user_disabled_2fa.py b/rules/dropbox_rules/dropbox_user_disabled_2fa.py index 5667d003f..0c9cfa954 100644 --- a/rules/dropbox_rules/dropbox_user_disabled_2fa.py +++ b/rules/dropbox_rules/dropbox_user_disabled_2fa.py @@ -1,16 +1,13 @@ -from panther_base_helpers import deep_get - - def rule(event): return all( [ - deep_get(event, "details", ".tag", default="") == "tfa_change_status_details", - deep_get(event, "details", "new_value", ".tag") == "disabled", + event.deep_get("details", ".tag", default="") == "tfa_change_status_details", + event.deep_get("details", "new_value", ".tag") == "disabled", ] ) def title(event): - actor = deep_get(event, "actor", "user", "email", default="") - target = deep_get(event, "context", "email", default="") + actor = event.deep_get("actor", "user", "email", default="") + target = event.deep_get("context", "email", default="") return f"Dropbox: [{actor}] disabled 2FA for [{target}]." diff --git a/rules/duo_rules/duo_user_action_fraudulent.py b/rules/duo_rules/duo_user_action_fraudulent.py index ac67946c9..102e1aac4 100644 --- a/rules/duo_rules/duo_user_action_fraudulent.py +++ b/rules/duo_rules/duo_user_action_fraudulent.py @@ -1,12 +1,9 @@ -from panther_base_helpers import deep_get - - def rule(event): return event.get("result") == "fraud" def title(event): - user = deep_get(event, "user", "name", default="Unknown") + user = event.deep_get("user", "name", default="Unknown") return f"A Duo action was marked as fraudulent by [{user}]" @@ -14,9 +11,9 @@ def alert_context(event): return { "factor": event.get("factor"), "reason": event.get("reason"), - "user": deep_get(event, "user", "name", default=""), - "os": deep_get(event, "access_device", "os", default=""), - "ip_access": deep_get(event, "access_device", "ip", default=""), - "ip_auth": deep_get(event, "auth_device", "ip", default=""), - "application": deep_get(event, "application", "name", default=""), + "user": event.deep_get("user", "name", default=""), + "os": event.deep_get("access_device", "os", default=""), + "ip_access": event.deep_get("access_device", "ip", default=""), + "ip_auth": event.deep_get("auth_device", "ip", default=""), + "application": event.deep_get("application", "name", default=""), } diff --git a/rules/duo_rules/duo_user_anomalous_push.py b/rules/duo_rules/duo_user_anomalous_push.py index 9e4a7a766..8400bbc59 100644 --- a/rules/duo_rules/duo_user_anomalous_push.py +++ b/rules/duo_rules/duo_user_anomalous_push.py @@ -1,12 +1,9 @@ -from panther_base_helpers import deep_get - - def rule(event): return event.get("reason") == "anomalous_push" and event.get("result") == "denied" def title(event): - user = deep_get(event, "user", "name", default="Unknown") + user = event.deep_get("user", "name", default="Unknown") return f"Duo Auth denied due to an anomalous 2FA push for [{user}]" @@ -14,9 +11,9 @@ def alert_context(event): return { "factor": event.get("factor"), "reason": event.get("reason"), - "user": deep_get(event, "user", "name", default=""), - "os": deep_get(event, "access_device", "os", default=""), - "ip_access": deep_get(event, "access_device", "ip", default=""), - "ip_auth": deep_get(event, "auth_device", "ip", default=""), - "application": deep_get(event, "application", "name", default=""), + "user": event.deep_get("user", "name", default=""), + "os": event.deep_get("access_device", "os", default=""), + "ip_access": event.deep_get("access_device", "ip", default=""), + "ip_auth": event.deep_get("auth_device", "ip", default=""), + "application": event.deep_get("application", "name", default=""), } diff --git a/rules/duo_rules/duo_user_bypass_code_used.py b/rules/duo_rules/duo_user_bypass_code_used.py index a8ac568c8..dbfbf9366 100644 --- a/rules/duo_rules/duo_user_bypass_code_used.py +++ b/rules/duo_rules/duo_user_bypass_code_used.py @@ -1,12 +1,9 @@ -from panther_base_helpers import deep_get - - def rule(event): return event.get("reason") == "bypass_user" and event.get("result") == "success" def title(event): - user = deep_get(event, "user", "name", default="Unknown") + user = event.deep_get("user", "name", default="Unknown") return f"Bypass code for Duo User [{user}] used" @@ -14,9 +11,9 @@ def alert_context(event): return { "factor": event.get("factor"), "reason": event.get("reason"), - "user": deep_get(event, "user", "name", default=""), - "os": deep_get(event, "access_device", "os", default=""), - "ip_access": deep_get(event, "access_device", "ip", default=""), - "ip_auth": deep_get(event, "auth_device", "ip", default=""), - "application": deep_get(event, "application", "name", default=""), + "user": event.deep_get("user", "name", default=""), + "os": event.deep_get("access_device", "os", default=""), + "ip_access": event.deep_get("access_device", "ip", default=""), + "ip_auth": event.deep_get("auth_device", "ip", default=""), + "application": event.deep_get("application", "name", default=""), } diff --git a/rules/duo_rules/duo_user_endpoint_failure_multi.py b/rules/duo_rules/duo_user_endpoint_failure_multi.py index c6bec282f..5053905b7 100644 --- a/rules/duo_rules/duo_user_endpoint_failure_multi.py +++ b/rules/duo_rules/duo_user_endpoint_failure_multi.py @@ -1,6 +1,3 @@ -from panther_base_helpers import deep_get - - def rule(event): endpoint_reasons = [ "endpoint_is_not_in_management_system", @@ -13,7 +10,7 @@ def rule(event): def title(event): - user = deep_get(event, "user", "name", default="Unknown") + user = event.deep_get("user", "name", default="Unknown") reason = event.get("reason", "Unknown") return f"Duo User [{user}] encountered suspicious endpoint issue [{reason}]" @@ -22,9 +19,9 @@ def alert_context(event): return { "factor": event.get("factor"), "reason": event.get("reason"), - "user": deep_get(event, "user", "name", default=""), - "os": deep_get(event, "access_device", "os", default=""), - "ip_access": deep_get(event, "access_device", "ip", default=""), - "ip_auth": deep_get(event, "auth_device", "ip", default=""), - "application": deep_get(event, "application", "name", default=""), + "user": event.deep_get("user", "name", default=""), + "os": event.deep_get("access_device", "os", default=""), + "ip_access": event.deep_get("access_device", "ip", default=""), + "ip_auth": event.deep_get("auth_device", "ip", default=""), + "application": event.deep_get("application", "name", default=""), } diff --git a/rules/gcp_audit_rules/gcp_access_attempts_violating_vpc_service_controls.py b/rules/gcp_audit_rules/gcp_access_attempts_violating_vpc_service_controls.py index 9eb8fcb7a..763c00b7d 100644 --- a/rules/gcp_audit_rules/gcp_access_attempts_violating_vpc_service_controls.py +++ b/rules/gcp_audit_rules/gcp_access_attempts_violating_vpc_service_controls.py @@ -1,11 +1,8 @@ -from panther_base_helpers import deep_get, deep_walk - - def rule(event): - severity = deep_get(event, "severity", default="") - status_code = deep_get(event, "protoPayload", "status", "code", default="") - violation_types = deep_walk( - event, "protoPayload", "status", "details", "violations", "type", default=[] + severity = event.deep_get("severity", default="") + status_code = event.deep_get("protoPayload", "status", "code", default="") + violation_types = event.deep_walk( + "protoPayload", "status", "details", "violations", "type", default=[] ) if all( [ @@ -19,8 +16,8 @@ def rule(event): def title(event): - actor = deep_get( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + actor = event.deep_get( + "protoPayload", "authenticationInfo", "principalEmail", default="" ) - method = deep_get(event, "protoPayload", "methodName", default="") + method = event.deep_get("protoPayload", "methodName", default="") return f"GCP: [{actor}] performed a [{method}] request that violates VPC Service Controls" diff --git a/rules/gcp_audit_rules/gcp_bigquery_large_scan.py b/rules/gcp_audit_rules/gcp_bigquery_large_scan.py index ea3e0bbd7..4c22ba70d 100644 --- a/rules/gcp_audit_rules/gcp_bigquery_large_scan.py +++ b/rules/gcp_audit_rules/gcp_bigquery_large_scan.py @@ -1,5 +1,3 @@ -from panther_base_helpers import deep_get - # 1.07 GB QUERY_THRESHOLD_BYTES = 1073741824 @@ -7,12 +5,11 @@ def rule(event): return all( [ - deep_get(event, "resource", "type", default="").startswith("bigquery"), - deep_get(event, "operation", "last") is True, - deep_get(event, "protoPayload", "metadata", "jobChange", "job", "jobConfig", "type") + event.deep_get("resource", "type", default="").startswith("bigquery"), + event.deep_get("operation", "last") is True, + event.deep_get("protoPayload", "metadata", "jobChange", "job", "jobConfig", "type") == "QUERY", - deep_get( - event, + event.deep_get( "protoPayload", "metadata", "jobChange", @@ -23,8 +20,7 @@ def rule(event): ) == "SELECT", int( - deep_get( - event, + event.deep_get( "protoPayload", "metadata", "jobChange", @@ -41,11 +37,10 @@ def rule(event): def title(event): - actor = deep_get( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + actor = event.deep_get( + "protoPayload", "authenticationInfo", "principalEmail", default="" ) - query_size = deep_get( - event, + query_size = event.deep_get( "protoPayload", "metadata", "jobChange", @@ -60,8 +55,7 @@ def title(event): def alert_context(event): return { - "query": deep_get( - event, + "query": event.deep_get( "protoPayload", "metadata", "jobChange", @@ -71,15 +65,13 @@ def alert_context(event): "query", default="", ), - "actor": deep_get( - event, + "actor": event.deep_get( "protoPayload", "authenticationInfo", "principalEmail", default="", ), - "query_size": deep_get( - event, + "query_size": event.deep_get( "protoPayload", "metadata", "jobChange", diff --git a/rules/gcp_audit_rules/gcp_cloud_run_service_created.py b/rules/gcp_audit_rules/gcp_cloud_run_service_created.py index 488f29588..2a29a4ff8 100644 --- a/rules/gcp_audit_rules/gcp_cloud_run_service_created.py +++ b/rules/gcp_audit_rules/gcp_cloud_run_service_created.py @@ -1,16 +1,15 @@ from gcp_base_helpers import gcp_alert_context -from panther_base_helpers import deep_get, deep_walk def rule(event): - if deep_get(event, "severity") == "ERROR": + if event.get("severity") == "ERROR": return False - method_name = deep_get(event, "protoPayload", "methodName", default="") + method_name = event.deep_get("protoPayload", "methodName", default="") if not method_name.endswith("Services.CreateService"): return False - authorization_info = deep_walk(event, "protoPayload", "authorizationInfo") + authorization_info = event.deep_walk("protoPayload", "authorizationInfo") if not authorization_info: return False @@ -21,18 +20,17 @@ def rule(event): def title(event): - actor = deep_get( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + actor = event.deep_get( + "protoPayload", "authenticationInfo", "principalEmail", default="" ) - project_id = deep_get(event, "resource", "labels", "project_id", default="") + project_id = event.deep_get("resource", "labels", "project_id", default="") return f"[GCP]: [{actor}] created new Run Service in project [{project_id}]" def alert_context(event): context = gcp_alert_context(event) - context["service_account"] = deep_get( - event, + context["service_account"] = event.deep_get( "protoPayload", "request", "service", diff --git a/rules/gcp_audit_rules/gcp_cloud_run_set_iam_policy.py b/rules/gcp_audit_rules/gcp_cloud_run_set_iam_policy.py index 09e33a44a..48b21472f 100644 --- a/rules/gcp_audit_rules/gcp_cloud_run_set_iam_policy.py +++ b/rules/gcp_audit_rules/gcp_cloud_run_set_iam_policy.py @@ -1,16 +1,15 @@ from gcp_base_helpers import gcp_alert_context -from panther_base_helpers import deep_get, deep_walk def rule(event): - if deep_get(event, "severity") == "ERROR": + if event.get("severity") == "ERROR": return False - method_name = deep_get(event, "protoPayload", "methodName", default="") + method_name = event.deep_get("protoPayload", "methodName", default="") if not method_name.endswith("Services.SetIamPolicy"): return False - authorization_info = deep_walk(event, "protoPayload", "authorizationInfo") + authorization_info = event.deep_walk("protoPayload", "authorizationInfo") if not authorization_info: return False @@ -21,12 +20,12 @@ def rule(event): def title(event): - actor = deep_get( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + actor = event.deep_get( + "protoPayload", "authenticationInfo", "principalEmail", default="" ) - resource = deep_get(event, "resource", "resourceName", default="") - assigned_role = deep_walk(event, "protoPayload", "response", "bindings", "role") - project_id = deep_get(event, "resource", "labels", "project_id", default="") + resource = event.deep_get("resource", "resourceName", default="") + assigned_role = event.deep_walk("protoPayload", "response", "bindings", "role") + project_id = event.deep_get("resource", "labels", "project_id", default="") return ( f"[GCP]: [{actor}] was granted access to [{resource}] service with " @@ -36,8 +35,7 @@ def title(event): def alert_context(event): context = gcp_alert_context(event) - context["assigned_role"] = deep_walk( - event, + context["assigned_role"] = event.deep_walk( "protoPayload", "response", "bindings", diff --git a/rules/gcp_audit_rules/gcp_cloud_storage_buckets_modified_or_deleted.py b/rules/gcp_audit_rules/gcp_cloud_storage_buckets_modified_or_deleted.py index be8fd958d..139a4e59c 100644 --- a/rules/gcp_audit_rules/gcp_cloud_storage_buckets_modified_or_deleted.py +++ b/rules/gcp_audit_rules/gcp_cloud_storage_buckets_modified_or_deleted.py @@ -1,23 +1,21 @@ -from panther_base_helpers import deep_get - BUCKET_OPERATIONS = ["storage.buckets.delete", "storage.buckets.update"] def rule(event): return all( [ - deep_get(event, "protoPayload", "serviceName", default="") == "storage.googleapis.com", - deep_get(event, "protoPayload", "methodName", default="") in BUCKET_OPERATIONS, + event.deep_get("protoPayload", "serviceName", default="") == "storage.googleapis.com", + event.deep_get("protoPayload", "methodName", default="") in BUCKET_OPERATIONS, ] ) def title(event): - actor = deep_get( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + actor = event.deep_get( + "protoPayload", "authenticationInfo", "principalEmail", default="" ) - operation = deep_get(event, "protoPayload", "methodName", default="") - project = deep_get(event, "resource", "labels", "project_id", default="") - bucket = deep_get(event, "resource", "labels", "bucket_name", default="") + operation = event.deep_get("protoPayload", "methodName", default="") + project = event.deep_get("resource", "labels", "project_id", default="") + bucket = event.deep_get("resource", "labels", "bucket_name", default="") return f"GCP: [{actor}] performed a [{operation}] on bucket [{bucket}] in project [{project}]." diff --git a/rules/gcp_audit_rules/gcp_cloudbuild_potential_privilege_escalation.py b/rules/gcp_audit_rules/gcp_cloudbuild_potential_privilege_escalation.py index c3d7eb243..d6dd3a946 100644 --- a/rules/gcp_audit_rules/gcp_cloudbuild_potential_privilege_escalation.py +++ b/rules/gcp_audit_rules/gcp_cloudbuild_potential_privilege_escalation.py @@ -1,14 +1,13 @@ from gcp_base_helpers import gcp_alert_context -from panther_base_helpers import deep_get, deep_walk def rule(event): - if not deep_get(event, "protoPayload", "methodName", default="METHOD_NOT_FOUND").endswith( + if not event.deep_get("protoPayload", "methodName", default="METHOD_NOT_FOUND").endswith( "CloudBuild.CreateBuild" ): return False - authorization_info = deep_walk(event, "protoPayload", "authorizationInfo") + authorization_info = event.deep_walk("protoPayload", "authorizationInfo") if not authorization_info: return False @@ -19,11 +18,11 @@ def rule(event): def title(event): - actor = deep_get( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + actor = event.deep_get( + "protoPayload", "authenticationInfo", "principalEmail", default="" ) - operation = deep_get(event, "protoPayload", "methodName", default="") - project_id = deep_get(event, "resource", "labels", "project_id", default="") + operation = event.deep_get("protoPayload", "methodName", default="") + project_id = event.deep_get("resource", "labels", "project_id", default="") return f"[GCP]: [{actor}] performed [{operation}] on project [{project_id}]" diff --git a/rules/gcp_audit_rules/gcp_cloudfunctions_functions_create.py b/rules/gcp_audit_rules/gcp_cloudfunctions_functions_create.py index ad90a1ff6..d46bbbef7 100644 --- a/rules/gcp_audit_rules/gcp_cloudfunctions_functions_create.py +++ b/rules/gcp_audit_rules/gcp_cloudfunctions_functions_create.py @@ -1,9 +1,8 @@ from gcp_base_helpers import gcp_alert_context -from panther_base_helpers import deep_get, deep_walk def rule(event): - authorization_info = deep_walk(event, "protoPayload", "authorizationInfo") + authorization_info = event.deep_walk("protoPayload", "authorizationInfo") if not authorization_info: return False @@ -17,11 +16,11 @@ def rule(event): def title(event): - actor = deep_get( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + actor = event.deep_get( + "protoPayload", "authenticationInfo", "principalEmail", default="" ) - operation = deep_get(event, "protoPayload", "methodName", default="") - project_id = deep_get(event, "resource", "labels", "project_id", default="") + operation = event.deep_get("protoPayload", "methodName", default="") + project_id = event.deep_get("resource", "labels", "project_id", default="") return f"[GCP]: [{actor}] performed [{operation}] on project [{project_id}]" diff --git a/rules/gcp_audit_rules/gcp_cloudfunctions_functions_update.py b/rules/gcp_audit_rules/gcp_cloudfunctions_functions_update.py index a54a89074..c72a2535f 100644 --- a/rules/gcp_audit_rules/gcp_cloudfunctions_functions_update.py +++ b/rules/gcp_audit_rules/gcp_cloudfunctions_functions_update.py @@ -1,9 +1,8 @@ from gcp_base_helpers import gcp_alert_context -from panther_base_helpers import deep_get, deep_walk def rule(event): - authorization_info = deep_walk(event, "protoPayload", "authorizationInfo") + authorization_info = event.deep_walk("protoPayload", "authorizationInfo") if not authorization_info: return False @@ -17,11 +16,11 @@ def rule(event): def title(event): - actor = deep_get( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + actor = event.deep_get( + "protoPayload", "authenticationInfo", "principalEmail", default="" ) - operation = deep_get(event, "protoPayload", "methodName", default="") - project_id = deep_get(event, "resource", "labels", "project_id", default="") + operation = event.deep_get("protoPayload", "methodName", default="") + project_id = event.deep_get("resource", "labels", "project_id", default="") return f"[GCP]: [{actor}] performed [{operation}] on project [{project_id}]" diff --git a/rules/gcp_audit_rules/gcp_computeinstances_create_privilege_escalation.py b/rules/gcp_audit_rules/gcp_computeinstances_create_privilege_escalation.py index 386009956..f37ae5de5 100644 --- a/rules/gcp_audit_rules/gcp_computeinstances_create_privilege_escalation.py +++ b/rules/gcp_audit_rules/gcp_computeinstances_create_privilege_escalation.py @@ -1,5 +1,4 @@ from gcp_base_helpers import gcp_alert_context -from panther_base_helpers import deep_get REQUIRED_PERMISSIONS = [ "compute.disks.create", @@ -12,14 +11,14 @@ def rule(event): - if deep_get(event, "protoPayload", "response", "error"): + if event.deep_get("protoPayload", "response", "error"): return False - method = deep_get(event, "protoPayload", "methodName", default="METHOD_NOT_FOUND") + method = event.deep_get("protoPayload", "methodName", default="METHOD_NOT_FOUND") if not method.endswith("compute.instances.insert"): return False - authorization_info = deep_get(event, "protoPayload", "authorizationInfo") + authorization_info = event.deep_get("protoPayload", "authorizationInfo") if not authorization_info: return False @@ -34,17 +33,17 @@ def rule(event): def title(event): - actor = deep_get( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + actor = event.deep_get( + "protoPayload", "authenticationInfo", "principalEmail", default="" ) - service_accounts = deep_get(event, "protoPayload", "request", "serviceAccounts") + service_accounts = event.deep_get("protoPayload", "request", "serviceAccounts") if not service_accounts: service_account_emails = "" else: service_account_emails = [service_acc["email"] for service_acc in service_accounts] - project = deep_get(event, "resource", "labels", "project_id", default="") + project = event.deep_get("resource", "labels", "project_id", default="") return ( f"[GCP]: [{actor}] created a new Compute Engine instance with [{service_account_emails}] " f"Service Account on project [{project}]" @@ -53,7 +52,7 @@ def title(event): def alert_context(event): context = gcp_alert_context(event) - service_accounts = deep_get(event, "protoPayload", "request", "serviceAccounts") + service_accounts = event.deep_get("protoPayload", "request", "serviceAccounts") if not service_accounts: service_account_emails = "" else: diff --git a/rules/gcp_audit_rules/gcp_destructive_queries.py b/rules/gcp_audit_rules/gcp_destructive_queries.py index 72ded3214..7c67677e3 100644 --- a/rules/gcp_audit_rules/gcp_destructive_queries.py +++ b/rules/gcp_audit_rules/gcp_destructive_queries.py @@ -1,18 +1,15 @@ -from panther_base_helpers import deep_get - DESTRUCTIVE_STATEMENTS = ["UPDATE", "DELETE", "DROP_TABLE", "ALTER_TABLE", "TRUNCATE_TABLE"] def rule(event): if all( [ - deep_get(event, "resource", "type", default="").startswith( + event.deep_get("resource", "type", default="").startswith( "bigquery" ), - deep_get(event, "protoPayload", "metadata", "jobChange", "job", "jobConfig", "type") + event.deep_get("protoPayload", "metadata", "jobChange", "job", "jobConfig", "type") == "QUERY", - deep_get( - event, + event.deep_get( "protoPayload", "metadata", "jobChange", @@ -27,21 +24,20 @@ def rule(event): ): return True - if deep_get(event, "protoPayload", "metadata", "tableDeletion"): + if event.deep_get("protoPayload", "metadata", "tableDeletion"): return True - if deep_get(event, "protoPayload", "metadata", "datasetDeletion"): + if event.deep_get("protoPayload", "metadata", "datasetDeletion"): return True return False def title(event): - actor = deep_get( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + actor = event.deep_get( + "protoPayload", "authenticationInfo", "principalEmail", default="" ) - statement = deep_get( - event, + statement = event.deep_get( "protoPayload", "metadata", "jobChange", @@ -51,8 +47,7 @@ def title(event): "statementType", default="", ) - table = deep_get( - event, + table = event.deep_get( "protoPayload", "metadata", "jobChange", @@ -60,14 +55,13 @@ def title(event): "jobConfig", "queryConfig", "destinationTable", - ) or deep_get(event, "protoPayload", "metadata", "resourceName", default="") + ) or event.deep_get("protoPayload", "metadata", "resourceName", default="") return f"GCP: [{actor}] performed a destructive BigQuery [{statement}] query on [{table}]." def alert_context(event): return { - "query": deep_get( - event, + "query": event.deep_get( "protoPayload", "metadata", "jobChange", @@ -77,15 +71,13 @@ def alert_context(event): "query", default="", ), - "actor": deep_get( - event, + "actor": event.deep_get( "protoPayload", "authenticationInfo", "principalEmail", default="", ), - "statement": deep_get( - event, + "statement": event.deep_get( "protoPayload", "metadata", "jobChange", @@ -95,8 +87,7 @@ def alert_context(event): "statementType", default="", ), - "table": deep_get( - event, + "table": event.deep_get( "protoPayload", "metadata", "jobChange", @@ -105,5 +96,5 @@ def alert_context(event): "queryConfig", "destinationTable", ) - or deep_get(event, "protoPayload", "metadata", "resourceName", default=""), + or event.deep_get("protoPayload", "metadata", "resourceName", default=""), } diff --git a/rules/gcp_audit_rules/gcp_dns_zone_modified_or_deleted.py b/rules/gcp_audit_rules/gcp_dns_zone_modified_or_deleted.py index f7c990507..edde9df60 100644 --- a/rules/gcp_audit_rules/gcp_dns_zone_modified_or_deleted.py +++ b/rules/gcp_audit_rules/gcp_dns_zone_modified_or_deleted.py @@ -1,5 +1,4 @@ from gcp_base_helpers import gcp_alert_context -from panther_base_helpers import deep_get def rule(event): @@ -9,14 +8,14 @@ def rule(event): "dns.managedZones.patch", "dns.managedZones.update", ) - return deep_get(event, "protoPayload", "methodName", default="") in methods + return event.deep_get("protoPayload", "methodName", default="") in methods def title(event): - actor = deep_get( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + actor = event.deep_get( + "protoPayload", "authenticationInfo", "principalEmail", default="" ) - resource = deep_get(event, "protoPayload", "resourceName", default="") + resource = event.deep_get("protoPayload", "resourceName", default="") return f"[GCP]: [{actor}] modified managed DNS zone [{resource}]" diff --git a/rules/gcp_audit_rules/gcp_firewall_rule_created.py b/rules/gcp_audit_rules/gcp_firewall_rule_created.py index 61155d1bf..80a17c711 100644 --- a/rules/gcp_audit_rules/gcp_firewall_rule_created.py +++ b/rules/gcp_audit_rules/gcp_firewall_rule_created.py @@ -1,27 +1,24 @@ import re from gcp_base_helpers import gcp_alert_context -from panther_base_helpers import deep_get def rule(event): method_pattern = r"(?:\w+\.)*v\d\.(?:Firewall\.Create)|(compute\.firewalls\.insert)" - match = re.search(method_pattern, deep_get(event, "protoPayload", "methodName", default="")) + match = re.search(method_pattern, event.deep_get("protoPayload", "methodName", default="")) return match is not None def title(event): - actor = deep_get( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + actor = event.deep_get( + "protoPayload", "authenticationInfo", "principalEmail", default="" ) - resource = deep_get( - event, + resource = event.deep_get( "protoPayload", "resourceName", default="", ) - resource_id = deep_get( - event, + resource_id = event.deep_get( "resource", "labels", "firewall_rule_id", diff --git a/rules/gcp_audit_rules/gcp_firewall_rule_deleted.py b/rules/gcp_audit_rules/gcp_firewall_rule_deleted.py index 0970fdbff..90eb7001e 100644 --- a/rules/gcp_audit_rules/gcp_firewall_rule_deleted.py +++ b/rules/gcp_audit_rules/gcp_firewall_rule_deleted.py @@ -1,27 +1,24 @@ import re from gcp_base_helpers import gcp_alert_context -from panther_base_helpers import deep_get def rule(event): method_pattern = r"(?:\w+\.)*v\d\.(?:Firewall\.Delete)|(compute\.firewalls\.delete)" - match = re.search(method_pattern, deep_get(event, "protoPayload", "methodName", default="")) + match = re.search(method_pattern, event.deep_get("protoPayload", "methodName", default="")) return match is not None def title(event): - actor = deep_get( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + actor = event.deep_get( + "protoPayload", "authenticationInfo", "principalEmail", default="" ) - resource = deep_get( - event, + resource = event.deep_get( "protoPayload", "resourceName", default="", ) - resource_id = deep_get( - event, + resource_id = event.deep_get( "resource", "labels", "firewall_rule_id", diff --git a/rules/gcp_audit_rules/gcp_firewall_rule_modified.py b/rules/gcp_audit_rules/gcp_firewall_rule_modified.py index 1bf4af4f0..a0eb6b774 100644 --- a/rules/gcp_audit_rules/gcp_firewall_rule_modified.py +++ b/rules/gcp_audit_rules/gcp_firewall_rule_modified.py @@ -1,20 +1,19 @@ import re from gcp_base_helpers import gcp_alert_context -from panther_base_helpers import deep_get def rule(event): method_pattern = r"(?:\w+\.)*v\d\.(?:Firewall\.Update)|(compute\.firewalls\.(patch|update))" - match = re.search(method_pattern, deep_get(event, "protoPayload", "methodName", default="")) + match = re.search(method_pattern, event.deep_get("protoPayload", "methodName", default="")) return match is not None def title(event): - actor = deep_get( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + actor = event.deep_get( + "protoPayload", "authenticationInfo", "principalEmail", default="" ) - resource = deep_get(event, "protoPayload", "resourceName", default="") + resource = event.deep_get("protoPayload", "resourceName", default="") return f"[GCP]: [{actor}] modified firewall rule on [{resource}]" diff --git a/rules/gcp_audit_rules/gcp_gcs_iam_changes.py b/rules/gcp_audit_rules/gcp_gcs_iam_changes.py index 2bc7a0760..9cab1fdcf 100644 --- a/rules/gcp_audit_rules/gcp_gcs_iam_changes.py +++ b/rules/gcp_audit_rules/gcp_gcs_iam_changes.py @@ -1,12 +1,9 @@ -from panther_base_helpers import deep_get - - def rule(event): return ( - deep_get(event, "resource", "type") == "gcs_bucket" - and deep_get(event, "protoPayload", "methodName") == "storage.setIamPermissions" + event.deep_get("resource", "type") == "gcs_bucket" + and event.deep_get("protoPayload", "methodName") == "storage.setIamPermissions" ) def dedup(event): - return deep_get(event, "resource", "labels", "project_id", default="") + return event.deep_get("resource", "labels", "project_id", default="") diff --git a/rules/gcp_audit_rules/gcp_gcs_public.py b/rules/gcp_audit_rules/gcp_gcs_public.py index 28743607d..b76cf7ab9 100644 --- a/rules/gcp_audit_rules/gcp_gcs_public.py +++ b/rules/gcp_audit_rules/gcp_gcs_public.py @@ -5,10 +5,10 @@ def rule(event): - if deep_get(event, "protoPayload", "methodName") != "storage.setIamPermissions": + if event.deep_get("protoPayload", "methodName") != "storage.setIamPermissions": return False - service_data = deep_get(event, "protoPayload", "serviceData") + service_data = event.deep_get("protoPayload", "serviceData") if not service_data: return False @@ -28,6 +28,6 @@ def rule(event): def title(event): return ( f"GCS bucket " - f"[{deep_get(event, 'resource', 'labels', 'bucket_name', default='')}] " + f"[{event.deep_get('resource', 'labels', 'bucket_name', default='')}] " f"made public" ) diff --git a/rules/gcp_audit_rules/gcp_iam_admin_role_assigned.py b/rules/gcp_audit_rules/gcp_iam_admin_role_assigned.py index 847bbd9ea..79d0150aa 100644 --- a/rules/gcp_audit_rules/gcp_iam_admin_role_assigned.py +++ b/rules/gcp_audit_rules/gcp_iam_admin_role_assigned.py @@ -1,6 +1,6 @@ from fnmatch import fnmatch -from panther_base_helpers import deep_get, get_binding_deltas +from panther_base_helpers import get_binding_deltas ADMIN_ROLES = { # Primitive Roles @@ -27,5 +27,5 @@ def rule(event): def title(event): return ( f"An admin role has been configured in GCP project " - f"{deep_get(event, 'resource', 'labels', 'project_id', default='')}" + f"{event.deep_get('resource', 'labels', 'project_id', default='')}" ) diff --git a/rules/gcp_audit_rules/gcp_iam_corp_email.py b/rules/gcp_audit_rules/gcp_iam_corp_email.py index 909206817..436df396e 100644 --- a/rules/gcp_audit_rules/gcp_iam_corp_email.py +++ b/rules/gcp_audit_rules/gcp_iam_corp_email.py @@ -2,10 +2,10 @@ def rule(event): - if deep_get(event, "protoPayload", "methodName") != "SetIamPolicy": + if event.deep_get("protoPayload", "methodName") != "SetIamPolicy": return False - service_data = deep_get(event, "protoPayload", "serviceData") + service_data = event.deep_get("protoPayload", "serviceData") if not service_data: return False @@ -25,5 +25,5 @@ def rule(event): def title(event): return ( f"A GCP IAM account has been created with a Gmail email in " - f"{deep_get(event, 'resource', 'labels', 'project_id', default='')}" + f"{event.deep_get('resource', 'labels', 'project_id', default='')}" ) diff --git a/rules/gcp_audit_rules/gcp_iam_custom_role_changes.py b/rules/gcp_audit_rules/gcp_iam_custom_role_changes.py index 17f59d563..bf0c992b2 100644 --- a/rules/gcp_audit_rules/gcp_iam_custom_role_changes.py +++ b/rules/gcp_audit_rules/gcp_iam_custom_role_changes.py @@ -1,5 +1,3 @@ -from panther_base_helpers import deep_get - ROLE_METHODS = { "google.iam.admin.v1.CreateRole", "google.iam.admin.v1.DeleteRole", @@ -9,10 +7,10 @@ def rule(event): return ( - deep_get(event, "resource", "type") == "iam_role" - and deep_get(event, "protoPayload", "methodName") in ROLE_METHODS + event.deep_get("resource", "type") == "iam_role" + and event.deep_get("protoPayload", "methodName") in ROLE_METHODS ) def dedup(event): - return deep_get(event, "resource", "labels", "project_id", default="") + return event.deep_get("resource", "labels", "project_id", default="") diff --git a/rules/gcp_audit_rules/gcp_iam_org_folder_changes.py b/rules/gcp_audit_rules/gcp_iam_org_folder_changes.py index 3943ff40b..031d44420 100644 --- a/rules/gcp_audit_rules/gcp_iam_org_folder_changes.py +++ b/rules/gcp_audit_rules/gcp_iam_org_folder_changes.py @@ -1,11 +1,8 @@ -from panther_base_helpers import deep_get - - def rule(event): # Return True to match the log event and trigger an alert. - logname = deep_get(event, "logName") + logname = event.get("logName") return ( - deep_get(event, "protoPayload", "methodName") == "SetIamPolicy" + event.deep_get("protoPayload", "methodName") == "SetIamPolicy" and (logname.startswith("organizations") or logname.startswith("folder")) and logname.endswith("/logs/cloudaudit.googleapis.com%2Factivity") ) @@ -21,15 +18,15 @@ def title(event): def alert_context(event): return { "actor": event.udm("actor_user"), - "policy_change": deep_get(event, "protoPayload", "serviceData", "policyDelta"), - "caller_ip": deep_get(event, "protoPayload", "requestMetadata", "callerIP"), - "user_agent": deep_get(event, "protoPayload", "requestMetadata", "callerSuppliedUserAgent"), + "policy_change": event.deep_get("protoPayload", "serviceData", "policyDelta"), + "caller_ip": event.deep_get("protoPayload", "requestMetadata", "callerIP"), + "user_agent": event.deep_get("protoPayload", "requestMetadata", "callerSuppliedUserAgent"), } def severity(event): if ( - deep_get(event, "protoPayload", "requestMetadata", "callerSuppliedUserAgent") + event.deep_get("protoPayload", "requestMetadata", "callerSuppliedUserAgent") .lower() .find("terraform") != -1 diff --git a/rules/gcp_audit_rules/gcp_iam_roles_update_privilege_escalation.py b/rules/gcp_audit_rules/gcp_iam_roles_update_privilege_escalation.py index 2b274c5f4..f367a0739 100644 --- a/rules/gcp_audit_rules/gcp_iam_roles_update_privilege_escalation.py +++ b/rules/gcp_audit_rules/gcp_iam_roles_update_privilege_escalation.py @@ -1,9 +1,8 @@ from gcp_base_helpers import gcp_alert_context -from panther_base_helpers import deep_get, deep_walk def rule(event): - authorization_info = deep_walk(event, "protoPayload", "authorizationInfo") + authorization_info = event.deep_walk("protoPayload", "authorizationInfo") if not authorization_info: return False @@ -14,11 +13,11 @@ def rule(event): def title(event): - actor = deep_get( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + actor = event.deep_get( + "protoPayload", "authenticationInfo", "principalEmail", default="" ) - operation = deep_get(event, "protoPayload", "methodName", default="") - project_id = deep_get(event, "resource", "labels", "project_id", default="") + operation = event.deep_get("protoPayload", "methodName", default="") + project_id = event.deep_get("resource", "labels", "project_id", default="") return f"[GCP]: [{actor}] performed [{operation}] on project [{project_id}]" diff --git a/rules/gcp_audit_rules/gcp_iam_service_account_key_create.py b/rules/gcp_audit_rules/gcp_iam_service_account_key_create.py index d506611bd..7997caf25 100644 --- a/rules/gcp_audit_rules/gcp_iam_service_account_key_create.py +++ b/rules/gcp_audit_rules/gcp_iam_service_account_key_create.py @@ -1,9 +1,8 @@ from gcp_base_helpers import gcp_alert_context -from panther_base_helpers import deep_get, deep_walk def rule(event): - authorization_info = deep_walk(event, "protoPayload", "authorizationInfo") + authorization_info = event.deep_walk("protoPayload", "authorizationInfo") if not authorization_info: return False @@ -17,11 +16,11 @@ def rule(event): def title(event): - actor = deep_get( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + actor = event.deep_get( + "protoPayload", "authenticationInfo", "principalEmail", default="" ) - operation = deep_get(event, "protoPayload", "methodName", default="") - project_id = deep_get(event, "resource", "labels", "project_id", default="") + operation = event.deep_get("protoPayload", "methodName", default="") + project_id = event.deep_get("resource", "labels", "project_id", default="") return f"[GCP]: [{actor}] performed [{operation}] on project [{project_id}]" diff --git a/rules/gcp_audit_rules/gcp_iam_service_accounts_get_access_token_privilege_escalation.py b/rules/gcp_audit_rules/gcp_iam_service_accounts_get_access_token_privilege_escalation.py index 44b90b4f9..d35bcc1d7 100644 --- a/rules/gcp_audit_rules/gcp_iam_service_accounts_get_access_token_privilege_escalation.py +++ b/rules/gcp_audit_rules/gcp_iam_service_accounts_get_access_token_privilege_escalation.py @@ -1,5 +1,4 @@ from gcp_base_helpers import gcp_alert_context -from panther_base_helpers import deep_get def rule(event): @@ -18,8 +17,8 @@ def rule(event): def title(event): actor = event.udm("actor_user") - operation = deep_get(event, "protoPayload", "methodName", default="") - project_id = deep_get(event, "resource", "labels", "project_id", default="") + operation = event.deep_get("protoPayload", "methodName", default="") + project_id = event.deep_get("resource", "labels", "project_id", default="") return f"[GCP]: [{actor}] performed [{operation}] on project [{project_id}]" diff --git a/rules/gcp_audit_rules/gcp_iam_service_accounts_sign_blob.py b/rules/gcp_audit_rules/gcp_iam_service_accounts_sign_blob.py index 74ad13b7a..285ac3b1a 100644 --- a/rules/gcp_audit_rules/gcp_iam_service_accounts_sign_blob.py +++ b/rules/gcp_audit_rules/gcp_iam_service_accounts_sign_blob.py @@ -1,5 +1,4 @@ from gcp_base_helpers import gcp_alert_context -from panther_base_helpers import deep_get def rule(event): @@ -14,11 +13,11 @@ def rule(event): def title(event): - actor = deep_get( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + actor = event.deep_get( + "protoPayload", "authenticationInfo", "principalEmail", default="" ) - operation = deep_get(event, "protoPayload", "methodName", default="") - project_id = deep_get(event, "resource", "labels", "project_id", default="") + operation = event.deep_get("protoPayload", "methodName", default="") + project_id = event.deep_get("resource", "labels", "project_id", default="") return f"[GCP]: [{actor}] performed [{operation}] on project [{project_id}]" diff --git a/rules/gcp_audit_rules/gcp_iam_serviceaccounts_signjwt.py b/rules/gcp_audit_rules/gcp_iam_serviceaccounts_signjwt.py index 4662b5e7e..7a5403075 100644 --- a/rules/gcp_audit_rules/gcp_iam_serviceaccounts_signjwt.py +++ b/rules/gcp_audit_rules/gcp_iam_serviceaccounts_signjwt.py @@ -1,12 +1,11 @@ from gcp_base_helpers import gcp_alert_context -from panther_base_helpers import deep_get, deep_walk def rule(event): - if deep_get(event, "protoPayload", "methodName") != "SignJwt": + if event.deep_get("protoPayload", "methodName") != "SignJwt": return False - authorization_info = deep_walk(event, "protoPayload", "authorizationInfo") + authorization_info = event.deep_walk("protoPayload", "authorizationInfo") if not authorization_info: return False @@ -17,18 +16,18 @@ def rule(event): def title(event): - actor = deep_get( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + actor = event.deep_get( + "protoPayload", "authenticationInfo", "principalEmail", default="" ) - operation = deep_get(event, "protoPayload", "methodName", default="") - project_id = deep_get(event, "resource", "labels", "project_id", default="") + operation = event.deep_get("protoPayload", "methodName", default="") + project_id = event.deep_get("resource", "labels", "project_id", default="") return f"[GCP]: [{actor}] performed [{operation}] on project [{project_id}]" def alert_context(event): context = gcp_alert_context(event) - context["serviceAccountKeyName"] = deep_get( - event, "protoPayload", "authenticationInfo", "serviceAccountKeyName" + context["serviceAccountKeyName"] = event.deep_get( + "protoPayload", "authenticationInfo", "serviceAccountKeyName" ) return context diff --git a/rules/gcp_audit_rules/gcp_log_bucket_or_sink_deleted.py b/rules/gcp_audit_rules/gcp_log_bucket_or_sink_deleted.py index 86979d7ae..e378e3665 100644 --- a/rules/gcp_audit_rules/gcp_log_bucket_or_sink_deleted.py +++ b/rules/gcp_audit_rules/gcp_log_bucket_or_sink_deleted.py @@ -1,22 +1,20 @@ import re from gcp_base_helpers import gcp_alert_context -from panther_base_helpers import deep_get, deep_walk def rule(event): - authenticated = deep_walk(event, "protoPayload", "authorizationInfo", "granted", default=False) + authenticated = event.deep_walk("protoPayload", "authorizationInfo", "granted", default=False) method_pattern = r"(?:\w+\.)*v\d\.(?:ConfigServiceV\d\.(?:Delete(Bucket|Sink)))" - match = re.search(method_pattern, deep_get(event, "protoPayload", "methodName", default="")) + match = re.search(method_pattern, event.deep_get("protoPayload", "methodName", default="")) return authenticated and match is not None def title(event): - actor = deep_get( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + actor = event.deep_get( + "protoPayload", "authenticationInfo", "principalEmail", default="" ) - resource = deep_get( - event, + resource = event.deep_get( "protoPayload", "resourceName", default="", diff --git a/rules/gcp_audit_rules/gcp_logging_settings_modified.py b/rules/gcp_audit_rules/gcp_logging_settings_modified.py index c1c55bb35..053f02618 100644 --- a/rules/gcp_audit_rules/gcp_logging_settings_modified.py +++ b/rules/gcp_audit_rules/gcp_logging_settings_modified.py @@ -1,32 +1,28 @@ -from panther_base_helpers import deep_get - - def rule(event): return all( [ - deep_get(event, "protoPayload", "serviceName", default="") == "logging.googleapis.com", - "Update" in deep_get(event, "protoPayload", "methodName", default=""), + event.deep_get("protoPayload", "serviceName", default="") == "logging.googleapis.com", + "Update" in event.deep_get("protoPayload", "methodName", default=""), ] ) def title(event): - resource = deep_get(event, "protoPayload", "resourceName", default="") - actor = deep_get( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + resource = event.deep_get("protoPayload", "resourceName", default="") + actor = event.deep_get( + "protoPayload", "authenticationInfo", "principalEmail", default="" ) return f"GCP [{resource}] logging settings modified by [{actor}]." def alert_context(event): return { - "resource": deep_get(event, "protoPayload", "resourceName", default=""), - "actor": deep_get( - event, + "resource": event.deep_get("protoPayload", "resourceName", default=""), + "actor": event.deep_get( "protoPayload", "authenticationInfo", "principalEmail", default="", ), - "method": deep_get(event, "protoPayload", "methodName", default=""), + "method": event.deep_get("protoPayload", "methodName", default=""), } diff --git a/rules/gcp_audit_rules/gcp_logging_sink_modified.py b/rules/gcp_audit_rules/gcp_logging_sink_modified.py index fc815ff17..e230a4030 100644 --- a/rules/gcp_audit_rules/gcp_logging_sink_modified.py +++ b/rules/gcp_audit_rules/gcp_logging_sink_modified.py @@ -1,21 +1,19 @@ import re from gcp_base_helpers import gcp_alert_context -from panther_base_helpers import deep_get def rule(event): method_pattern = r"(?:\w+\.)*v\d\.(?:ConfigServiceV\d\.(?:UpdateSink))" - match = re.search(method_pattern, deep_get(event, "protoPayload", "methodName", default="")) + match = re.search(method_pattern, event.deep_get("protoPayload", "methodName", default="")) return match is not None def title(event): - actor = deep_get( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + actor = event.deep_get( + "protoPayload", "authenticationInfo", "principalEmail", default="" ) - resource = deep_get( - event, + resource = event.deep_get( "protoPayload", "resourceName", default="", diff --git a/rules/gcp_audit_rules/gcp_permissions_granted_to_create_or_manage_service_account_key.py b/rules/gcp_audit_rules/gcp_permissions_granted_to_create_or_manage_service_account_key.py index 3e1581245..d475b8f4a 100644 --- a/rules/gcp_audit_rules/gcp_permissions_granted_to_create_or_manage_service_account_key.py +++ b/rules/gcp_audit_rules/gcp_permissions_granted_to_create_or_manage_service_account_key.py @@ -1,4 +1,4 @@ -from panther_base_helpers import deep_get, deep_walk +from panther_base_helpers import deep_walk SERVICE_ACCOUNT_MANAGE_ROLES = [ "roles/iam.serviceAccountTokenCreator", @@ -7,10 +7,9 @@ def rule(event): - if "SetIAMPolicy" in deep_get(event, "protoPayload", "methodName", default=""): - role = deep_walk( - event, - "ProtoPayload", + if "SetIAMPolicy" in event.deep_get("protoPayload", "methodName", default=""): + role = event.deep_walk( + "protoPayload", "serviceData", "policyDelta", "bindingDeltas", @@ -18,9 +17,8 @@ def rule(event): default="", return_val="last", ) - action = deep_walk( - event, - "ProtoPayload", + action = event.deep_walk( + "protoPayload", "serviceData", "policyDelta", "bindingDeltas", @@ -33,11 +31,11 @@ def rule(event): def title(event): - actor = deep_get( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + actor = event.deep_get( + "protoPayload", "authenticationInfo", "principalEmail", default="" ) - target = deep_get(event, "resource", "labels", "email_id") or deep_get( - event, "resource", "labels", "project_id", default="" + target = event.deep_get("resource", "labels", "email_id") or event.deep_get( + "resource", "labels", "project_id", default="" ) return ( f"GCP: [{actor}] granted permissions to create or manage service account keys to [{target}]" @@ -46,6 +44,6 @@ def title(event): def alert_context(event): return { - "resource": deep_get(event, "resource"), - "serviceData": deep_get(event, "protoPayload", "serviceData"), + "resource": event.get("resource"), + "serviceData": event.deep_get("protoPayload", "serviceData"), } diff --git a/rules/gcp_audit_rules/gcp_privilege_escalation_by_deployments_create.py b/rules/gcp_audit_rules/gcp_privilege_escalation_by_deployments_create.py index c88390795..16c15b8d2 100644 --- a/rules/gcp_audit_rules/gcp_privilege_escalation_by_deployments_create.py +++ b/rules/gcp_audit_rules/gcp_privilege_escalation_by_deployments_create.py @@ -1,9 +1,8 @@ from gcp_base_helpers import gcp_alert_context -from panther_base_helpers import deep_get, deep_walk def rule(event): - authorization_info = deep_walk(event, "protoPayload", "authorizationInfo") + authorization_info = event.deep_walk("protoPayload", "authorizationInfo") if not authorization_info: return False @@ -17,11 +16,11 @@ def rule(event): def title(event): - actor = deep_get( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + actor = event.deep_get( + "protoPayload", "authenticationInfo", "principalEmail", default="" ) - operation = deep_get(event, "protoPayload", "methodName", default="") - project_id = deep_get(event, "resource", "labels", "project_id", default="") + operation = event.deep_get("protoPayload", "methodName", default="") + project_id = event.deep_get("resource", "labels", "project_id", default="") return f"[GCP]: [{actor}] performed [{operation}] on project [{project_id}]" diff --git a/rules/gcp_audit_rules/gcp_service_account_access_denied.py b/rules/gcp_audit_rules/gcp_service_account_access_denied.py index d9b0f0c8e..f40e0044f 100644 --- a/rules/gcp_audit_rules/gcp_service_account_access_denied.py +++ b/rules/gcp_audit_rules/gcp_service_account_access_denied.py @@ -1,15 +1,14 @@ from gcp_base_helpers import gcp_alert_context -from panther_base_helpers import deep_walk def rule(event): - reason = deep_walk(event, "protoPayload", "status", "details", "reason", default="") + reason = event.deep_walk("protoPayload", "status", "details", "reason", default="") return reason == "IAM_PERMISSION_DENIED" def title(event): - actor = deep_walk( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + actor = event.deep_walk( + "protoPayload", "authenticationInfo", "principalEmail", default="" ) return f"[GCP]: [{actor}] performed multiple requests resulting in [IAM_PERMISSION_DENIED]" diff --git a/rules/gcp_audit_rules/gcp_service_account_or_keys_created.py b/rules/gcp_audit_rules/gcp_service_account_or_keys_created.py index 49e466345..e19fd9ea1 100644 --- a/rules/gcp_audit_rules/gcp_service_account_or_keys_created.py +++ b/rules/gcp_audit_rules/gcp_service_account_or_keys_created.py @@ -1,27 +1,24 @@ -from panther_base_helpers import deep_get - - def rule(event): return all( [ - deep_get(event, "resource", "type", default="") == "service_account", - "CreateServiceAccount" in deep_get(event, "protoPayload", "methodName", default=""), - not deep_get( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + event.deep_get("resource", "type", default="") == "service_account", + "CreateServiceAccount" in event.deep_get("protoPayload", "methodName", default=""), + not event.deep_get( + "protoPayload", "authenticationInfo", "principalEmail", default="" ).endswith(".gserviceaccount.com"), ] ) def title(event): - actor = deep_get( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + actor = event.deep_get( + "protoPayload", "authenticationInfo", "principalEmail", default="" ) - target = deep_get(event, "resource", "labels", "email_id") - project = deep_get(event, "resource", "labels", "project_id") + target = event.deep_get("resource", "labels", "email_id") + project = event.deep_get("resource", "labels", "project_id") resource = ( "Service Account Key for" - if deep_get(event, "protoPayload", "methodName", default="") + if event.deep_get("protoPayload", "methodName", default="") == "google.iam.admin.v1.CreateServiceAccountKey" else "Service Account" ) diff --git a/rules/gcp_audit_rules/gcp_serviceusage_apikeys_create_privilege_escalation.py b/rules/gcp_audit_rules/gcp_serviceusage_apikeys_create_privilege_escalation.py index 5ce656f63..1380e3e73 100644 --- a/rules/gcp_audit_rules/gcp_serviceusage_apikeys_create_privilege_escalation.py +++ b/rules/gcp_audit_rules/gcp_serviceusage_apikeys_create_privilege_escalation.py @@ -1,14 +1,13 @@ from gcp_base_helpers import gcp_alert_context -from panther_base_helpers import deep_get, deep_walk def rule(event): - if not deep_get(event, "protoPayload", "methodName", default="METHOD_NOT_FOUND").endswith( + if not event.deep_get("protoPayload", "methodName", default="METHOD_NOT_FOUND").endswith( "ApiKeys.CreateKey" ): return False - authorization_info = deep_walk(event, "protoPayload", "authorizationInfo") + authorization_info = event.deep_walk("protoPayload", "authorizationInfo") if not authorization_info: return False @@ -19,10 +18,10 @@ def rule(event): def title(event): - actor = deep_get( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + actor = event.deep_get( + "protoPayload", "authenticationInfo", "principalEmail", default="" ) - project_id = deep_get(event, "resource", "labels", "project_id", default="") + project_id = event.deep_get("resource", "labels", "project_id", default="") return f"[GCP]: [{actor}] created new API Key in project [{project_id}]" diff --git a/rules/gcp_audit_rules/gcp_sql_config_changes.py b/rules/gcp_audit_rules/gcp_sql_config_changes.py index d8b961347..0cff312c4 100644 --- a/rules/gcp_audit_rules/gcp_sql_config_changes.py +++ b/rules/gcp_audit_rules/gcp_sql_config_changes.py @@ -1,9 +1,6 @@ -from panther_base_helpers import deep_get - - def rule(event): - return deep_get(event, "protoPayload", "methodName") == "cloudsql.instances.update" + return event.deep_get("protoPayload", "methodName") == "cloudsql.instances.update" def dedup(event): - return deep_get(event, "resource", "labels", "project_id", default="") + return event.deep_get("resource", "labels", "project_id", default="") diff --git a/rules/gcp_audit_rules/gcp_unused_regions.py b/rules/gcp_audit_rules/gcp_unused_regions.py index 15ec7ba68..9b1518b11 100644 --- a/rules/gcp_audit_rules/gcp_unused_regions.py +++ b/rules/gcp_audit_rules/gcp_unused_regions.py @@ -38,7 +38,7 @@ def _get_location_or_zone(event): def rule(event): - method_name = deep_get(event, "protoPayload", "methodName", default="") + method_name = event.deep_get("protoPayload", "methodName", default="") if not method_name.endswith(("insert", "create")): return False return _resource_in_active_region(_get_location_or_zone(event)) @@ -47,5 +47,5 @@ def rule(event): def title(event): return ( f"GCP resource(s) created in unused region/zone in project " - f"{deep_get(event, 'resource', 'labels', 'project_id', default='')}" + f"{event.deep_get('resource', 'labels', 'project_id', default='')}" ) diff --git a/rules/gcp_audit_rules/gcp_user_added_to_iap_protected_service.py b/rules/gcp_audit_rules/gcp_user_added_to_iap_protected_service.py index 164394b12..c0d1ac130 100644 --- a/rules/gcp_audit_rules/gcp_user_added_to_iap_protected_service.py +++ b/rules/gcp_audit_rules/gcp_user_added_to_iap_protected_service.py @@ -1,22 +1,19 @@ -from panther_base_helpers import deep_get - - def rule(event): return ( - deep_get(event, "protoPayload", "methodName", default="") + event.deep_get("protoPayload", "methodName", default="") == "google.cloud.iap.v1.IdentityAwareProxyAdminService.SetIamPolicy" ) def title(event): - actor = deep_get( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + actor = event.deep_get( + "protoPayload", "authenticationInfo", "principalEmail", default="" ) - service = deep_get(event, "protoPayload", "request", "resource", default="") + service = event.deep_get("protoPayload", "request", "resource", default="") return f"GCP: [{actor}] modified user access to IAP Protected Service [{service}]" def alert_context(event): - bindings = deep_get(event, "protoPayload", "request", "policy", "bindings", default=[{}]) + bindings = event.deep_get("protoPayload", "request", "policy", "bindings", default=[{}]) return {"bindings": bindings} diff --git a/rules/gcp_audit_rules/gcp_vpc_flow_logs_disabled.py b/rules/gcp_audit_rules/gcp_vpc_flow_logs_disabled.py index 159b51783..3933b9806 100644 --- a/rules/gcp_audit_rules/gcp_vpc_flow_logs_disabled.py +++ b/rules/gcp_audit_rules/gcp_vpc_flow_logs_disabled.py @@ -1,20 +1,17 @@ -from panther_base_helpers import deep_get - - def rule(event): return all( [ event.get("protoPayload"), - deep_get(event, "protoPayload", "methodName", default="") + event.deep_get("protoPayload", "methodName", default="") == "v1.compute.subnetworks.patch", - deep_get(event, "protoPayload", "request", "enableFlowLogs") is False, + event.deep_get("protoPayload", "request", "enableFlowLogs") is False, ] ) def title(event): - actor = deep_get( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + actor = event.deep_get( + "protoPayload", "authenticationInfo", "principalEmail", default="" ) - resource = deep_get(event, "protoPayload", "resourceName", default="") + resource = event.deep_get("protoPayload", "resourceName", default="") return f"GCP: [{actor}] disabled VPC Flow Logs for [{resource}]" diff --git a/rules/gcp_http_lb_rules/gcp_access_attempts_violating_iap_access_controls.py b/rules/gcp_http_lb_rules/gcp_access_attempts_violating_iap_access_controls.py index cbdf74d27..9c31afc41 100644 --- a/rules/gcp_http_lb_rules/gcp_access_attempts_violating_iap_access_controls.py +++ b/rules/gcp_http_lb_rules/gcp_access_attempts_violating_iap_access_controls.py @@ -1,16 +1,13 @@ -from panther_base_helpers import deep_get - - def rule(event): return all( [ - deep_get(event, "resource", "type", default="") == "http_load_balancer", - deep_get(event, "jsonPayload", "statusDetails", default="") + event.deep_get("resource", "type", default="") == "http_load_balancer", + event.deep_get("jsonPayload", "statusDetails", default="") == "handled_by_identity_aware_proxy", not any( [ - str(deep_get(event, "httprequest", "status", default=000)).startswith("2"), - str(deep_get(event, "httprequest", "status", default=000)).startswith("3"), + str(event.deep_get("httprequest", "status", default=000)).startswith("2"), + str(event.deep_get("httprequest", "status", default=000)).startswith("3"), ] ), ] @@ -18,6 +15,6 @@ def rule(event): def title(event): - source = deep_get(event, "jsonPayload", "remoteIp", default="") - request_url = deep_get(event, "httprequest", "requestUrl", default="") + source = event.deep_get("jsonPayload", "remoteIp", default="") + request_url = event.deep_get("httprequest", "requestUrl", default="") return f"GCP: Request Violating IAP controls from [{source}] to [{request_url}]" diff --git a/rules/gcp_k8s_rules/gcp_k8s_cron_job_created_or_modified.py b/rules/gcp_k8s_rules/gcp_k8s_cron_job_created_or_modified.py index 81668e586..4c0b5e7ad 100644 --- a/rules/gcp_k8s_rules/gcp_k8s_cron_job_created_or_modified.py +++ b/rules/gcp_k8s_rules/gcp_k8s_cron_job_created_or_modified.py @@ -1,9 +1,8 @@ from gcp_base_helpers import gcp_alert_context -from panther_base_helpers import deep_get, deep_walk def rule(event): - authorization_info = deep_walk(event, "protoPayload", "authorizationInfo") + authorization_info = event.deep_walk("protoPayload", "authorizationInfo") if not authorization_info: return False for auth in authorization_info: @@ -17,11 +16,11 @@ def rule(event): def title(event): - actor = deep_get( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + actor = event.deep_get( + "protoPayload", "authenticationInfo", "principalEmail", default="" ) - operation = deep_get(event, "protoPayload", "methodName", default="") - project_id = deep_get(event, "resource", "labels", "project_id", default="") + operation = event.deep_get("protoPayload", "methodName", default="") + project_id = event.deep_get("resource", "labels", "project_id", default="") return f"[GCP]: [{actor}] performed [{operation}] on project [{project_id}]" diff --git a/rules/gcp_k8s_rules/gcp_k8s_exec_into_pod.py b/rules/gcp_k8s_rules/gcp_k8s_exec_into_pod.py index 6e4ff324b..19329a987 100644 --- a/rules/gcp_k8s_rules/gcp_k8s_exec_into_pod.py +++ b/rules/gcp_k8s_rules/gcp_k8s_exec_into_pod.py @@ -7,8 +7,8 @@ def rule(event): # Defaults to False (no alert) unless method is exec and principal not allowed if not all( [ - deep_walk(event, "protoPayload", "methodName") == "io.k8s.core.v1.pods.exec.create", - deep_walk(event, "resource", "type") == "k8s_cluster", + event.deep_walk("protoPayload", "methodName") == "io.k8s.core.v1.pods.exec.create", + event.deep_walk("resource", "type") == "k8s_cluster", ] ): return False diff --git a/rules/gcp_k8s_rules/gcp_k8s_ioc_activity.py b/rules/gcp_k8s_rules/gcp_k8s_ioc_activity.py index 24abdffa3..26c42242d 100644 --- a/rules/gcp_k8s_rules/gcp_k8s_ioc_activity.py +++ b/rules/gcp_k8s_rules/gcp_k8s_ioc_activity.py @@ -1,26 +1,25 @@ from gcp_base_helpers import gcp_alert_context -from panther_base_helpers import deep_get def rule(event): - if deep_get(event, "operation", "producer") == "k8s.io" and deep_get( - event, "p_enrichment", "tor_exit_nodes" + if event.deep_get("operation", "producer") == "k8s.io" and event.deep_get( + "p_enrichment", "tor_exit_nodes" ): return True return False def title(event): - actor = deep_get( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + actor = event.deep_get( + "protoPayload", "authenticationInfo", "principalEmail", default="" ) - operation = deep_get(event, "protoPayload", "methodName", default="") - project_id = deep_get(event, "resource", "labels", "project_id", default="") + operation = event.deep_get("protoPayload", "methodName", default="") + project_id = event.deep_get("resource", "labels", "project_id", default="") return f"[GCP]: [{actor}] performed [{operation}] on project [{project_id}]" def alert_context(event): context = gcp_alert_context(event) - context["tor_exit_nodes"] = deep_get(event, "p_enrichment", "tor_exit_nodes") + context["tor_exit_nodes"] = event.deep_get("p_enrichment", "tor_exit_nodes") return context diff --git a/rules/gcp_k8s_rules/gcp_k8s_new_daemonset_deployed.py b/rules/gcp_k8s_rules/gcp_k8s_new_daemonset_deployed.py index 6d926e044..ee6b070ec 100644 --- a/rules/gcp_k8s_rules/gcp_k8s_new_daemonset_deployed.py +++ b/rules/gcp_k8s_rules/gcp_k8s_new_daemonset_deployed.py @@ -1,9 +1,8 @@ from gcp_base_helpers import gcp_alert_context -from panther_base_helpers import deep_get, deep_walk def rule(event): - authorization_info = deep_walk(event, "protoPayload", "authorizationInfo") + authorization_info = event.deep_walk("protoPayload", "authorizationInfo") if not authorization_info: return False for auth in authorization_info: @@ -16,11 +15,11 @@ def rule(event): def title(event): - actor = deep_get( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + actor = event.deep_get( + "protoPayload", "authenticationInfo", "principalEmail", default="" ) - operation = deep_get(event, "protoPayload", "methodName", default="") - project_id = deep_get(event, "resource", "labels", "project_id", default="") + operation = event.deep_get("protoPayload", "methodName", default="") + project_id = event.deep_get("resource", "labels", "project_id", default="") return f"[GCP]: [{actor}] performed [{operation}] on project [{project_id}]" diff --git a/rules/gcp_k8s_rules/gcp_k8s_pod_attached_to_node_host_network.py b/rules/gcp_k8s_rules/gcp_k8s_pod_attached_to_node_host_network.py index bcb43d540..d505c524f 100644 --- a/rules/gcp_k8s_rules/gcp_k8s_pod_attached_to_node_host_network.py +++ b/rules/gcp_k8s_rules/gcp_k8s_pod_attached_to_node_host_network.py @@ -1,16 +1,15 @@ from gcp_base_helpers import gcp_alert_context -from panther_base_helpers import deep_get, deep_walk def rule(event): - if deep_get(event, "protoPayload", "methodName") not in ( + if event.deep_get("protoPayload", "methodName") not in ( "io.k8s.core.v1.pods.create", "io.k8s.core.v1.pods.update", "io.k8s.core.v1.pods.patch", ): return False - host_network = deep_walk(event, "protoPayload", "request", "spec", "hostNetwork") + host_network = event.deep_walk("protoPayload", "request", "spec", "hostNetwork") if host_network is not True: return False @@ -18,10 +17,10 @@ def rule(event): def title(event): - actor = deep_get( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + actor = event.deep_get( + "protoPayload", "authenticationInfo", "principalEmail", default="" ) - project_id = deep_get(event, "resource", "labels", "project_id", default="") + project_id = event.deep_get("resource", "labels", "project_id", default="") return ( f"[GCP]: [{actor}] created or modified pod which is attached to the host's network " diff --git a/rules/gcp_k8s_rules/gcp_k8s_pod_create_or_modify_host_path_vol_mount.py b/rules/gcp_k8s_rules/gcp_k8s_pod_create_or_modify_host_path_vol_mount.py index a31cd58c2..3ab845673 100644 --- a/rules/gcp_k8s_rules/gcp_k8s_pod_create_or_modify_host_path_vol_mount.py +++ b/rules/gcp_k8s_rules/gcp_k8s_pod_create_or_modify_host_path_vol_mount.py @@ -1,5 +1,4 @@ from gcp_base_helpers import gcp_alert_context -from panther_base_helpers import deep_get, deep_walk SUSPICIOUS_PATHS = [ "/var/run/docker.sock", @@ -15,18 +14,18 @@ def rule(event): - if deep_get(event, "protoPayload", "response", "status") == "Failure": + if event.deep_get("protoPayload", "response", "status") == "Failure": return False - if deep_get(event, "protoPayload", "methodName") not in ( + if event.deep_get("protoPayload", "methodName") not in ( "io.k8s.core.v1.pods.create", "io.k8s.core.v1.pods.update", "io.k8s.core.v1.pods.patch", ): return False - volume_mount_path = deep_walk( - event, "protoPayload", "request", "spec", "volumes", "hostPath", "path" + volume_mount_path = event.deep_walk( + "protoPayload", "request", "spec", "volumes", "hostPath", "path" ) if ( @@ -36,7 +35,7 @@ def rule(event): ): return False - authorization_info = deep_walk(event, "protoPayload", "authorizationInfo") + authorization_info = event.deep_walk("protoPayload", "authorizationInfo") if not authorization_info: return False @@ -55,11 +54,11 @@ def rule(event): def title(event): - actor = deep_get( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + actor = event.deep_get( + "protoPayload", "authenticationInfo", "principalEmail", default="" ) - pod_name = deep_get(event, "protoPayload", "resourceName", default="") - project_id = deep_get(event, "resource", "labels", "project_id", default="") + pod_name = event.deep_get("protoPayload", "resourceName", default="") + project_id = event.deep_get("resource", "labels", "project_id", default="") return ( f"[GCP]: [{actor}] created k8s pod [{pod_name}] with a hostPath volume mount " @@ -68,15 +67,15 @@ def title(event): def dedup(event): - return deep_get( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + return event.deep_get( + "protoPayload", "authenticationInfo", "principalEmail", default="" ) def alert_context(event): context = gcp_alert_context(event) - volume_mount_path = deep_walk( - event, "protoPayload", "request", "spec", "volumes", "hostPath", "path" + volume_mount_path = event.deep_walk( + "protoPayload", "request", "spec", "volumes", "hostPath", "path" ) context["volume_mount_path"] = volume_mount_path return context diff --git a/rules/gcp_k8s_rules/gcp_k8s_pod_using_host_pid_namespace.py b/rules/gcp_k8s_rules/gcp_k8s_pod_using_host_pid_namespace.py index 1feefccf0..f40254b72 100644 --- a/rules/gcp_k8s_rules/gcp_k8s_pod_using_host_pid_namespace.py +++ b/rules/gcp_k8s_rules/gcp_k8s_pod_using_host_pid_namespace.py @@ -1,5 +1,4 @@ from gcp_base_helpers import gcp_alert_context -from panther_base_helpers import deep_get METHODS_TO_CHECK = [ "io.k8s.core.v1.pods.create", @@ -9,19 +8,19 @@ def rule(event): - method = deep_get(event, "protoPayload", "methodName") - request_host_pid = deep_get(event, "protoPayload", "request", "spec", "hostPID") - response_host_pid = deep_get(event, "protoPayload", "responce", "spec", "hostPID") + method = event.deep_get("protoPayload", "methodName") + request_host_pid = event.deep_get("protoPayload", "request", "spec", "hostPID") + response_host_pid = event.deep_get("protoPayload", "responce", "spec", "hostPID") if (request_host_pid is True or response_host_pid is True) and method in METHODS_TO_CHECK: return True return False def title(event): - actor = deep_get( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + actor = event.deep_get( + "protoPayload", "authenticationInfo", "principalEmail", default="" ) - project_id = deep_get(event, "resource", "labels", "project_id", default="") + project_id = event.deep_get("resource", "labels", "project_id", default="") return ( f"[GCP]: [{actor}] created or modified pod using the host PID namespace " diff --git a/rules/gcp_k8s_rules/gcp_k8s_privileged_pod_created.py b/rules/gcp_k8s_rules/gcp_k8s_privileged_pod_created.py index 4ab533e38..d626f87c7 100644 --- a/rules/gcp_k8s_rules/gcp_k8s_privileged_pod_created.py +++ b/rules/gcp_k8s_rules/gcp_k8s_privileged_pod_created.py @@ -1,18 +1,18 @@ from gcp_base_helpers import gcp_alert_context -from panther_base_helpers import deep_get, deep_walk +from panther_base_helpers import deep_get def rule(event): - if deep_get(event, "protoPayload", "response", "status") == "Failure": + if event.deep_get("protoPayload", "response", "status") == "Failure": return False - if deep_get(event, "protoPayload", "methodName") != "io.k8s.core.v1.pods.create": + if event.deep_get("protoPayload", "methodName") != "io.k8s.core.v1.pods.create": return False - authorization_info = deep_walk(event, "protoPayload", "authorizationInfo") + authorization_info = event.deep_walk("protoPayload", "authorizationInfo") if not authorization_info: return False - containers_info = deep_walk(event, "protoPayload", "response", "spec", "containers") + containers_info = event.deep_walk("protoPayload", "response", "spec", "containers") for auth in authorization_info: if auth.get("permission") == "io.k8s.core.v1.pods.create" and auth.get("granted") is True: for security_context in containers_info: @@ -26,23 +26,23 @@ def rule(event): def title(event): - actor = deep_get( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + actor = event.deep_get( + "protoPayload", "authenticationInfo", "principalEmail", default="" ) - pod_name = deep_get(event, "protoPayload", "resourceName", default="") - project_id = deep_get(event, "resource", "labels", "project_id", default="") + pod_name = event.deep_get("protoPayload", "resourceName", default="") + project_id = event.deep_get("resource", "labels", "project_id", default="") return f"[GCP]: [{actor}] created a privileged pod [{pod_name}] in project [{project_id}]" def dedup(event): - return deep_get( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + return event.deep_get( + "protoPayload", "authenticationInfo", "principalEmail", default="" ) def alert_context(event): context = gcp_alert_context(event) - containers_info = deep_walk(event, "protoPayload", "response", "spec", "containers", default=[]) + containers_info = event.deep_walk("protoPayload", "response", "spec", "containers", default=[]) context["pod_security_context"] = [i.get("securityContext") for i in containers_info] return context diff --git a/rules/gcp_k8s_rules/gcp_k8s_service_type_node_port_deployed.py b/rules/gcp_k8s_rules/gcp_k8s_service_type_node_port_deployed.py index 8db2e21ee..9e85761c9 100644 --- a/rules/gcp_k8s_rules/gcp_k8s_service_type_node_port_deployed.py +++ b/rules/gcp_k8s_rules/gcp_k8s_service_type_node_port_deployed.py @@ -1,18 +1,17 @@ from gcp_base_helpers import gcp_alert_context -from panther_base_helpers import deep_get, deep_walk def rule(event): - if deep_get(event, "protoPayload", "response", "status") == "Failure": + if event.deep_get("protoPayload", "response", "status") == "Failure": return False - if deep_get(event, "protoPayload", "methodName") != "io.k8s.core.v1.services.create": + if event.deep_get("protoPayload", "methodName") != "io.k8s.core.v1.services.create": return False - if deep_get(event, "protoPayload", "request", "spec", "type") != "NodePort": + if event.deep_get("protoPayload", "request", "spec", "type") != "NodePort": return False - authorization_info = deep_walk(event, "protoPayload", "authorizationInfo") + authorization_info = event.deep_walk("protoPayload", "authorizationInfo") if not authorization_info: return False @@ -26,16 +25,16 @@ def rule(event): def title(event): - actor = deep_get( - event, "protoPayload", "authenticationInfo", "principalEmail", default="" + actor = event.deep_get( + "protoPayload", "authenticationInfo", "principalEmail", default="" ) - project_id = deep_get(event, "resource", "labels", "project_id", default="") + project_id = event.deep_get("resource", "labels", "project_id", default="") return f"[GCP]: [{actor}] created NodePort service in project [{project_id}]" def alert_context(event): context = gcp_alert_context(event) - request_spec = deep_walk(event, "protoPayload", "request", "spec") + request_spec = event.deep_walk("protoPayload", "request", "spec") context["request_spec"] = request_spec return context diff --git a/rules/github_rules/github_webhook_modified.py b/rules/github_rules/github_webhook_modified.py index 928c5b2de..18ce1f259 100644 --- a/rules/github_rules/github_webhook_modified.py +++ b/rules/github_rules/github_webhook_modified.py @@ -1,5 +1,5 @@ from global_filter_github import filter_include_event -from panther_base_helpers import deep_get, github_alert_context +from panther_base_helpers import github_alert_context def rule(event): @@ -17,7 +17,7 @@ def title(event): action = "created" title_str = ( - f"Github webhook [{deep_get(event,'config','url',default='')}]" + f"Github webhook [{event.deep_get('config','url',default='')}]" f" {action} by [{event.get('actor','')}]" ) if repo != "": @@ -37,5 +37,5 @@ def alert_context(event): ctx["hook_id"] = event.get("hook_id", "") ctx["integration"] = event.get("integration", "") ctx["operation_type"] = event.get("operation_type", "") - ctx["url"] = deep_get(event, "config", "url", default="") + ctx["url"] = event.deep_get("config", "url", default="") return ctx diff --git a/rules/gsuite_activityevent_rules/google_workspace_advanced_protection_program.py b/rules/gsuite_activityevent_rules/google_workspace_advanced_protection_program.py index 1c5cceddb..88537ed6a 100644 --- a/rules/gsuite_activityevent_rules/google_workspace_advanced_protection_program.py +++ b/rules/gsuite_activityevent_rules/google_workspace_advanced_protection_program.py @@ -1,10 +1,7 @@ -from panther_base_helpers import deep_get - - def rule(event): # Return True to match the log event and trigger an alert. setting_name = ( - deep_get(event, "parameters", "SETTING_NAME", default="NO_SETTING_NAME") + event.deep_get("parameters", "SETTING_NAME", default="NO_SETTING_NAME") .split("-")[0] .strip() ) diff --git a/rules/gsuite_activityevent_rules/google_workspace_apps_marketplace_allowlist.py b/rules/gsuite_activityevent_rules/google_workspace_apps_marketplace_allowlist.py index ac74286e9..d50fd70e4 100644 --- a/rules/gsuite_activityevent_rules/google_workspace_apps_marketplace_allowlist.py +++ b/rules/gsuite_activityevent_rules/google_workspace_apps_marketplace_allowlist.py @@ -1,11 +1,8 @@ -from panther_base_helpers import deep_get - - def rule(event): # Return True to match the log event and trigger an alert. - setting_name = deep_get(event, "parameters", "SETTING_NAME", default="") - old_val = deep_get(event, "parameters", "OLD_VALUE", default="") - new_val = deep_get(event, "parameters", "NEW_VALUE", default="") + setting_name = event.deep_get("parameters", "SETTING_NAME", default="") + old_val = event.deep_get("parameters", "OLD_VALUE", default="") + new_val = event.deep_get("parameters", "NEW_VALUE", default="") return setting_name == "ENABLE_G_SUITE_MARKETPLACE" and old_val != new_val @@ -19,9 +16,9 @@ def title(event): "2": "Allow users to install and run any app from the Marketplace", "3": "Allow users to install and run only selected apps from the Marketplace", } - old_val = deep_get(event, "parameters", "OLD_VALUE", default="") - new_val = deep_get(event, "parameters", "NEW_VALUE", default="") - actor = deep_get(event, "actor", "email", default="") + old_val = event.deep_get("parameters", "OLD_VALUE", default="") + new_val = event.deep_get("parameters", "NEW_VALUE", default="") + actor = event.deep_get("actor", "email", default="") return ( f"Google Workspace User [{actor}] " f"made an application allowlist setting change from [{value_dict.get(str(old_val))}] " diff --git a/rules/gsuite_activityevent_rules/gsuite_advanced_protection.py b/rules/gsuite_activityevent_rules/gsuite_advanced_protection.py index 5da1bb109..c4054eaa9 100644 --- a/rules/gsuite_activityevent_rules/gsuite_advanced_protection.py +++ b/rules/gsuite_activityevent_rules/gsuite_advanced_protection.py @@ -1,8 +1,5 @@ -from panther_base_helpers import deep_get - - def rule(event): - if deep_get(event, "id", "applicationName") != "user_accounts": + if event.deep_get("id", "applicationName") != "user_accounts": return False return bool(event.get("name") == "titanium_unenroll") @@ -11,5 +8,5 @@ def rule(event): def title(event): return ( f"Advanced protection was disabled for user " - f"[{deep_get(event, 'actor', 'email', default='')}]" + f"[{event.deep_get('actor', 'email', default='')}]" ) diff --git a/rules/gsuite_activityevent_rules/gsuite_brute_force_login.py b/rules/gsuite_activityevent_rules/gsuite_brute_force_login.py index b25e2fa5a..6a60c8642 100644 --- a/rules/gsuite_activityevent_rules/gsuite_brute_force_login.py +++ b/rules/gsuite_activityevent_rules/gsuite_brute_force_login.py @@ -1,6 +1,3 @@ -from panther_base_helpers import deep_get - - def rule(event): # Filter login events if event.get("type") != "login": @@ -13,5 +10,5 @@ def rule(event): def title(event): return ( f"Brute force login suspected for user " - f"[{deep_get(event, 'actor', 'email', default='')}]" + f"[{event.deep_get('actor', 'email', default='')}]" ) diff --git a/rules/gsuite_activityevent_rules/gsuite_calendar_made_public.py b/rules/gsuite_activityevent_rules/gsuite_calendar_made_public.py index ef96aa053..eef4441ba 100644 --- a/rules/gsuite_activityevent_rules/gsuite_calendar_made_public.py +++ b/rules/gsuite_activityevent_rules/gsuite_calendar_made_public.py @@ -1,6 +1,3 @@ -from panther_base_helpers import deep_get - - def rule(event): return ( event.get("name") == "change_calendar_acls" @@ -12,9 +9,9 @@ def rule(event): def title(event): return ( f"GSuite calendar " - f"[{deep_get(event, 'parameters', 'calendar_id', default='')}] made " + f"[{event.deep_get('parameters', 'calendar_id', default='')}] made " f"{public_or_private(event)} by " - f"[{deep_get(event, 'actor', 'email', default='')}]" + f"[{event.deep_get('actor', 'email', default='')}]" ) @@ -23,4 +20,4 @@ def severity(event): def public_or_private(event): - return "private" if deep_get(event, "parameters", "access_level") == "none" else "public" + return "private" if event.deep_get("parameters", "access_level") == "none" else "public" diff --git a/rules/gsuite_activityevent_rules/gsuite_doc_ownership_transfer.py b/rules/gsuite_activityevent_rules/gsuite_doc_ownership_transfer.py index 6aa5e9920..1910b1ef6 100644 --- a/rules/gsuite_activityevent_rules/gsuite_doc_ownership_transfer.py +++ b/rules/gsuite_activityevent_rules/gsuite_doc_ownership_transfer.py @@ -1,4 +1,3 @@ -from panther_base_helpers import deep_get from panther_config import config GSUITE_TRUSTED_OWNERSHIP_DOMAINS = { @@ -7,11 +6,11 @@ def rule(event): - if deep_get(event, "id", "applicationName") != "admin": + if event.deep_get("id", "applicationName") != "admin": return False if bool(event.get("name") == "TRANSFER_DOCUMENT_OWNERSHIP"): - new_owner = deep_get(event, "parameters", "NEW_VALUE", default="") + new_owner = event.deep_get("parameters", "NEW_VALUE", default="") return bool(new_owner) and not any( new_owner.endswith(x) for x in GSUITE_TRUSTED_OWNERSHIP_DOMAINS ) diff --git a/rules/gsuite_activityevent_rules/gsuite_external_forwarding.py b/rules/gsuite_activityevent_rules/gsuite_external_forwarding.py index 0b2306c6b..c7f3b0c8c 100644 --- a/rules/gsuite_activityevent_rules/gsuite_external_forwarding.py +++ b/rules/gsuite_activityevent_rules/gsuite_external_forwarding.py @@ -1,15 +1,12 @@ -from panther_base_helpers import deep_get from panther_config import config def rule(event): - if deep_get(event, "id", "applicationName") != "user_accounts": + if event.deep_get("id", "applicationName") != "user_accounts": return False if event.get("name") == "email_forwarding_out_of_domain": - domain = deep_get(event, "parameters", "email_forwarding_destination_address").split("@")[ - -1 - ] + domain = event.deep_get("parameters", "email_forwarding_destination_address").split("@")[-1] if domain not in config.GSUITE_TRUSTED_FORWARDING_DESTINATION_DOMAINS: return True @@ -17,7 +14,7 @@ def rule(event): def title(event): - external_address = deep_get(event, "parameters", "email_forwarding_destination_address") - user = deep_get(event, "actor", "email") + external_address = event.deep_get("parameters", "email_forwarding_destination_address") + user = event.deep_get("actor", "email") return f"An email forwarding rule was created by {user} to {external_address}" diff --git a/rules/gsuite_activityevent_rules/gsuite_google_access.py b/rules/gsuite_activityevent_rules/gsuite_google_access.py index 7c862d76e..28a0eea48 100644 --- a/rules/gsuite_activityevent_rules/gsuite_google_access.py +++ b/rules/gsuite_activityevent_rules/gsuite_google_access.py @@ -1,8 +1,5 @@ -from panther_base_helpers import deep_get - - def rule(event): - if deep_get(event, "id", "applicationName") != "access_transparency": + if event.deep_get("id", "applicationName") != "access_transparency": return False return bool(event.get("type") == "GSUITE_RESOURCE") diff --git a/rules/gsuite_activityevent_rules/gsuite_gov_attack.py b/rules/gsuite_activityevent_rules/gsuite_gov_attack.py index 3213ebf78..92a09f276 100644 --- a/rules/gsuite_activityevent_rules/gsuite_gov_attack.py +++ b/rules/gsuite_activityevent_rules/gsuite_gov_attack.py @@ -1,8 +1,5 @@ -from panther_base_helpers import deep_get - - def rule(event): - if deep_get(event, "id", "applicationName") != "login": + if event.deep_get("id", "applicationName") != "login": return False return bool(event.get("name") == "gov_attack_warning") @@ -10,6 +7,6 @@ def rule(event): def title(event): return ( - f"User [{deep_get(event, 'actor', 'email', default='')}] may have been " + f"User [{event.deep_get('actor', 'email', default='')}] may have been " f"targeted by a government attack" ) diff --git a/rules/gsuite_activityevent_rules/gsuite_group_banned_user.py b/rules/gsuite_activityevent_rules/gsuite_group_banned_user.py index d74a16506..39a1f18a3 100644 --- a/rules/gsuite_activityevent_rules/gsuite_group_banned_user.py +++ b/rules/gsuite_activityevent_rules/gsuite_group_banned_user.py @@ -1,8 +1,5 @@ -from panther_base_helpers import deep_get - - def rule(event): - if deep_get(event, "id", "applicationName") != "groups_enterprise": + if event.deep_get("id", "applicationName") != "groups_enterprise": return False if event.get("type") == "moderator_action": @@ -13,6 +10,6 @@ def rule(event): def title(event): return ( - f"User [{deep_get(event, 'actor', 'email', default='')}] " + f"User [{event.deep_get('actor', 'email', default='')}] " f"banned another user from a group." ) diff --git a/rules/gsuite_activityevent_rules/gsuite_leaked_password.py b/rules/gsuite_activityevent_rules/gsuite_leaked_password.py index 7dac0ef9e..39f5b26ab 100644 --- a/rules/gsuite_activityevent_rules/gsuite_leaked_password.py +++ b/rules/gsuite_activityevent_rules/gsuite_leaked_password.py @@ -1,12 +1,10 @@ -from panther_base_helpers import deep_get - PASSWORD_LEAKED_EVENTS = { "account_disabled_password_leak", } def rule(event): - if deep_get(event, "id", "applicationName") != "login": + if event.deep_get("id", "applicationName") != "login": return False if event.get("type") == "account_warning": @@ -15,7 +13,7 @@ def rule(event): def title(event): - user = deep_get(event, "parameters", "affected_email_address") + user = event.deep_get("parameters", "affected_email_address") if not user: user = "" return f"User [{user}]'s account was disabled due to a password leak" diff --git a/rules/gsuite_activityevent_rules/gsuite_login_type.py b/rules/gsuite_activityevent_rules/gsuite_login_type.py index b9aa7d2bc..51405b22e 100644 --- a/rules/gsuite_activityevent_rules/gsuite_login_type.py +++ b/rules/gsuite_activityevent_rules/gsuite_login_type.py @@ -1,5 +1,3 @@ -from panther_base_helpers import deep_get - # allow-list of approved login types APPROVED_LOGIN_TYPES = { "exchange", @@ -21,8 +19,8 @@ def rule(event): return False if ( - deep_get(event, "parameters", "login_type") in APPROVED_LOGIN_TYPES - or deep_get(event, "id", "applicationName") in APPROVED_APPLICATION_NAMES + event.deep_get("parameters", "login_type") in APPROVED_LOGIN_TYPES + or event.deep_get("id", "applicationName") in APPROVED_APPLICATION_NAMES ): return False @@ -32,5 +30,5 @@ def rule(event): def title(event): return ( f"A login attempt of a non-approved type was detected for user " - f"[{deep_get(event, 'actor', 'email', default='')}]" + f"[{event.deep_get('actor', 'email', default='')}]" ) diff --git a/rules/gsuite_activityevent_rules/gsuite_mobile_device_compromise.py b/rules/gsuite_activityevent_rules/gsuite_mobile_device_compromise.py index 9d909b54a..1d4f60bde 100644 --- a/rules/gsuite_activityevent_rules/gsuite_mobile_device_compromise.py +++ b/rules/gsuite_activityevent_rules/gsuite_mobile_device_compromise.py @@ -1,18 +1,15 @@ -from panther_base_helpers import deep_get - - def rule(event): - if deep_get(event, "id", "applicationName") != "mobile": + if event.deep_get("id", "applicationName") != "mobile": return False if event.get("name") == "DEVICE_COMPROMISED_EVENT": - return bool(deep_get(event, "parameters", "DEVICE_COMPROMISED_STATE") == "COMPROMISED") + return bool(event.deep_get("parameters", "DEVICE_COMPROMISED_STATE") == "COMPROMISED") return False def title(event): return ( - f"User [{deep_get(event, 'parameters', 'USER_EMAIL', default='')}]'s " + f"User [{event.deep_get('parameters', 'USER_EMAIL', default='')}]'s " f"device was compromised" ) diff --git a/rules/gsuite_activityevent_rules/gsuite_mobile_device_screen_unlock_fail.py b/rules/gsuite_activityevent_rules/gsuite_mobile_device_screen_unlock_fail.py index aeb9a3803..5f9227cca 100644 --- a/rules/gsuite_activityevent_rules/gsuite_mobile_device_screen_unlock_fail.py +++ b/rules/gsuite_activityevent_rules/gsuite_mobile_device_screen_unlock_fail.py @@ -1,14 +1,12 @@ -from panther_base_helpers import deep_get - MAX_UNLOCK_ATTEMPTS = 10 def rule(event): - if deep_get(event, "id", "applicationName") != "mobile": + if event.deep_get("id", "applicationName") != "mobile": return False if event.get("name") == "FAILED_PASSWORD_ATTEMPTS_EVENT": - attempts = deep_get(event, "parameters", "FAILED_PASSWD_ATTEMPTS") + attempts = event.deep_get("parameters", "FAILED_PASSWD_ATTEMPTS") return int(attempts if attempts else 0) > MAX_UNLOCK_ATTEMPTS return False @@ -16,6 +14,6 @@ def rule(event): def title(event): return ( - f"User [{deep_get(event, 'actor', 'email', default='')}]" + f"User [{event.deep_get('actor', 'email', default='')}]" f"'s device had multiple failed unlock attempts" ) diff --git a/rules/gsuite_activityevent_rules/gsuite_mobile_device_suspicious_activity.py b/rules/gsuite_activityevent_rules/gsuite_mobile_device_suspicious_activity.py index ee9e32768..e12254785 100644 --- a/rules/gsuite_activityevent_rules/gsuite_mobile_device_suspicious_activity.py +++ b/rules/gsuite_activityevent_rules/gsuite_mobile_device_suspicious_activity.py @@ -1,8 +1,5 @@ -from panther_base_helpers import deep_get - - def rule(event): - if deep_get(event, "id", "applicationName") != "mobile": + if event.deep_get("id", "applicationName") != "mobile": return False return bool(event.get("name") == "SUSPICIOUS_ACTIVITY_EVENT") @@ -10,6 +7,6 @@ def rule(event): def title(event): return ( - f"User [{deep_get(event, 'actor', 'email', default='')}]" + f"User [{event.deep_get('actor', 'email', default='')}]" f"'s device was compromised" ) diff --git a/rules/gsuite_activityevent_rules/gsuite_passthrough_rule.py b/rules/gsuite_activityevent_rules/gsuite_passthrough_rule.py index 33b0eee09..2018afb62 100644 --- a/rules/gsuite_activityevent_rules/gsuite_passthrough_rule.py +++ b/rules/gsuite_activityevent_rules/gsuite_passthrough_rule.py @@ -1,26 +1,23 @@ -from panther_base_helpers import deep_get - - def rule(event): - if deep_get(event, "id", "applicationName") != "rules": + if event.deep_get("id", "applicationName") != "rules": return False - if not deep_get(event, "parameters", "triggered_actions"): + if not event.deep_get("parameters", "triggered_actions"): return False return True def title(event): - rule_severity = deep_get(event, "parameters", "severity") - if deep_get(event, "parameters", "rule_name"): + rule_severity = event.deep_get("parameters", "severity") + if event.deep_get("parameters", "rule_name"): return ( "GSuite " + rule_severity + " Severity Rule Triggered: " - + deep_get(event, "parameters", "rule_name") + + event.deep_get("parameters", "rule_name") ) return "GSuite " + rule_severity + " Severity Rule Triggered" def severity(event): - return deep_get(event, "parameters", "severity", default="INFO") + return event.deep_get("parameters", "severity", default="INFO") diff --git a/rules/gsuite_activityevent_rules/gsuite_permissions_delegated.py b/rules/gsuite_activityevent_rules/gsuite_permissions_delegated.py index fb5938292..96fbe1a09 100644 --- a/rules/gsuite_activityevent_rules/gsuite_permissions_delegated.py +++ b/rules/gsuite_activityevent_rules/gsuite_permissions_delegated.py @@ -1,12 +1,10 @@ -from panther_base_helpers import deep_get - PERMISSION_DELEGATED_EVENTS = { "ASSIGN_ROLE", } def rule(event): - if deep_get(event, "id", "applicationName") != "admin": + if event.deep_get("id", "applicationName") != "admin": return False if event.get("type") == "DELEGATED_ADMIN_SETTINGS": return bool(event.get("name") in PERMISSION_DELEGATED_EVENTS) @@ -14,13 +12,13 @@ def rule(event): def title(event): - role = deep_get(event, "parameters", "ROLE_NAME") - user = deep_get(event, "parameters", "USER_EMAIL") + role = event.deep_get("parameters", "ROLE_NAME") + user = event.deep_get("parameters", "USER_EMAIL") if not role: role = "" if not user: user = "" return ( - f"User [{deep_get(event, 'actor', 'email', default='')}] delegated new" + f"User [{event.deep_get('actor', 'email', default='')}] delegated new" f" administrator privileges [{role}] to [{user}]" ) diff --git a/rules/gsuite_activityevent_rules/gsuite_suspicious_logins.py b/rules/gsuite_activityevent_rules/gsuite_suspicious_logins.py index 8cd73941b..51d71961b 100644 --- a/rules/gsuite_activityevent_rules/gsuite_suspicious_logins.py +++ b/rules/gsuite_activityevent_rules/gsuite_suspicious_logins.py @@ -1,5 +1,3 @@ -from panther_base_helpers import deep_get - SUSPICIOUS_LOGIN_TYPES = { "suspicious_login", "suspicious_login_less_secure_app", @@ -8,14 +6,14 @@ def rule(event): - if deep_get(event, "id", "applicationName") != "login": + if event.deep_get("id", "applicationName") != "login": return False return bool(event.get("name") in SUSPICIOUS_LOGIN_TYPES) def title(event): - user = deep_get(event, "parameters", "affected_email_address") + user = event.deep_get("parameters", "affected_email_address") if not user: user = "" return f"A suspicious login was reported for user [{user}]" diff --git a/rules/gsuite_activityevent_rules/gsuite_two_step_verification.py b/rules/gsuite_activityevent_rules/gsuite_two_step_verification.py index cece50b43..700508e22 100644 --- a/rules/gsuite_activityevent_rules/gsuite_two_step_verification.py +++ b/rules/gsuite_activityevent_rules/gsuite_two_step_verification.py @@ -1,8 +1,5 @@ -from panther_base_helpers import deep_get - - def rule(event): - if deep_get(event, "id", "applicationName") != "user_accounts": + if event.deep_get("id", "applicationName") != "user_accounts": return False if event.get("type") == "2sv_change" and event.get("name") == "2sv_disable": @@ -14,5 +11,5 @@ def rule(event): def title(event): return ( f"Two step verification was disabled for user" - f" [{deep_get(event, 'actor', 'email', default='')}]" + f" [{event.deep_get('actor', 'email', default='')}]" ) diff --git a/rules/gsuite_activityevent_rules/gsuite_user_suspended.py b/rules/gsuite_activityevent_rules/gsuite_user_suspended.py index c8a37a0a0..5fffb635d 100644 --- a/rules/gsuite_activityevent_rules/gsuite_user_suspended.py +++ b/rules/gsuite_activityevent_rules/gsuite_user_suspended.py @@ -1,5 +1,3 @@ -from panther_base_helpers import deep_get - USER_SUSPENDED_EVENTS = { "account_disabled_generic", "account_disabled_spamming_through_relay", @@ -9,14 +7,14 @@ def rule(event): - if deep_get(event, "id", "applicationName") != "login": + if event.deep_get("id", "applicationName") != "login": return False return bool(event.get("name") in USER_SUSPENDED_EVENTS) def title(event): - user = deep_get(event, "parameters", "affected_email_address") + user = event.deep_get("parameters", "affected_email_address") if not user: user = "" return f"User [{user}]'s account was disabled" diff --git a/rules/gsuite_activityevent_rules/gsuite_workspace_calendar_external_sharing.py b/rules/gsuite_activityevent_rules/gsuite_workspace_calendar_external_sharing.py index 2dcc60f13..1a9c7b97f 100644 --- a/rules/gsuite_activityevent_rules/gsuite_workspace_calendar_external_sharing.py +++ b/rules/gsuite_activityevent_rules/gsuite_workspace_calendar_external_sharing.py @@ -1,15 +1,12 @@ -from panther_base_helpers import deep_get - - def rule(event): if not all( [ (event.get("name", "") == "CHANGE_CALENDAR_SETTING"), - (deep_get(event, "parameters", "SETTING_NAME", default="") == "SHARING_OUTSIDE_DOMAIN"), + (event.deep_get("parameters", "SETTING_NAME", default="") == "SHARING_OUTSIDE_DOMAIN"), ] ): return False - return deep_get(event, "parameters", "NEW_VALUE", default="") in [ + return event.deep_get("parameters", "NEW_VALUE", default="") in [ "READ_WRITE_ACCESS", "READ_ONLY_ACCESS", "MANAGE_ACCESS", @@ -19,7 +16,7 @@ def rule(event): def title(event): return ( f"GSuite workspace setting for default calendar sharing was changed by " - f"[{deep_get(event, 'actor', 'email', default='')}] " - f"from [{deep_get(event, 'parameters', 'OLD_VALUE', default='')}] " - f"to [{deep_get(event, 'parameters', 'NEW_VALUE', default='')}]" + f"[{event.deep_get('actor', 'email', default='')}] " + f"from [{event.deep_get('parameters', 'OLD_VALUE', default='')}] " + f"to [{event.deep_get('parameters', 'NEW_VALUE', default='')}]" ) diff --git a/rules/gsuite_activityevent_rules/gsuite_workspace_data_export_created.py b/rules/gsuite_activityevent_rules/gsuite_workspace_data_export_created.py index 46ddc5787..91c9b717d 100644 --- a/rules/gsuite_activityevent_rules/gsuite_workspace_data_export_created.py +++ b/rules/gsuite_activityevent_rules/gsuite_workspace_data_export_created.py @@ -1,6 +1,3 @@ -from panther_base_helpers import deep_get - - def rule(event): return event.get("name", "").startswith("CUSTOMER_TAKEOUT_") @@ -9,5 +6,5 @@ def title(event): return ( f"GSuite Workspace Data Export " f"[{event.get('name', '')}] " - f"performed by [{deep_get(event, 'actor', 'email', default='')}]" + f"performed by [{event.deep_get('actor', 'email', default='')}]" ) diff --git a/rules/gsuite_activityevent_rules/gsuite_workspace_gmail_default_routing_rule.py b/rules/gsuite_activityevent_rules/gsuite_workspace_gmail_default_routing_rule.py index 93ca7562d..e6d6c0d94 100644 --- a/rules/gsuite_activityevent_rules/gsuite_workspace_gmail_default_routing_rule.py +++ b/rules/gsuite_activityevent_rules/gsuite_workspace_gmail_default_routing_rule.py @@ -1,12 +1,9 @@ -from panther_base_helpers import deep_get - - def rule(event): if all( [ (event.get("type", "") == "EMAIL_SETTINGS"), (event.get("name", "").endswith("_GMAIL_SETTING")), - (deep_get(event, "parameters", "SETTING_NAME", default="") == "MESSAGE_SECURITY_RULE"), + (event.deep_get("parameters", "SETTING_NAME", default="") == "MESSAGE_SECURITY_RULE"), ] ): return True @@ -21,5 +18,5 @@ def title(event): return ( f"GSuite Gmail Default Routing Rule Was " f"[{change_type}] " - f"by [{deep_get(event, 'actor', 'email', default='')}]" + f"by [{event.deep_get('actor', 'email', default='')}]" ) diff --git a/rules/gsuite_activityevent_rules/gsuite_workspace_gmail_enhanced_predelivery_scanning.py b/rules/gsuite_activityevent_rules/gsuite_workspace_gmail_enhanced_predelivery_scanning.py index ade01e8d1..278561275 100644 --- a/rules/gsuite_activityevent_rules/gsuite_workspace_gmail_enhanced_predelivery_scanning.py +++ b/rules/gsuite_activityevent_rules/gsuite_workspace_gmail_enhanced_predelivery_scanning.py @@ -1,18 +1,15 @@ -from panther_base_helpers import deep_get - - def rule(event): # the shape of the items in parameters can change a bit ( like NEW_VALUE can be an array ) # when the applicationName is something other than admin - if deep_get(event, "id", "applicationName", default="").lower() != "admin": + if event.deep_get("id", "applicationName", default="").lower() != "admin": return False if all( [ (event.get("name", "") == "CHANGE_APPLICATION_SETTING"), - (deep_get(event, "parameters", "APPLICATION_NAME", default="").lower() == "gmail"), - (deep_get(event, "parameters", "NEW_VALUE", default="").lower() == "true"), + (event.deep_get("parameters", "APPLICATION_NAME", default="").lower() == "gmail"), + (event.deep_get("parameters", "NEW_VALUE", default="").lower() == "true"), ( - deep_get(event, "parameters", "SETTING_NAME", default="") + event.deep_get("parameters", "SETTING_NAME", default="") == "DelayedDeliverySettingsProto disable_delayed_delivery_for_suspicious_email" ), ] @@ -24,6 +21,6 @@ def rule(event): def title(event): return ( f"GSuite Gmail Enhanced Pre-Delivery Scanning was disabled " - f"for [{deep_get(event, 'parameters', 'ORG_UNIT_NAME', default='')}] " - f"by [{deep_get(event, 'actor', 'email', default='')}]" + f"for [{event.deep_get('parameters', 'ORG_UNIT_NAME', default='')}] " + f"by [{event.deep_get('actor', 'email', default='')}]" ) diff --git a/rules/gsuite_activityevent_rules/gsuite_workspace_gmail_security_sandbox_disabled.py b/rules/gsuite_activityevent_rules/gsuite_workspace_gmail_security_sandbox_disabled.py index 75f57ed24..7f881be1e 100644 --- a/rules/gsuite_activityevent_rules/gsuite_workspace_gmail_security_sandbox_disabled.py +++ b/rules/gsuite_activityevent_rules/gsuite_workspace_gmail_security_sandbox_disabled.py @@ -1,16 +1,13 @@ -from panther_base_helpers import deep_get - - def rule(event): - if deep_get(event, "id", "applicationName", default="").lower() != "admin": + if event.deep_get("id", "applicationName", default="").lower() != "admin": return False if all( [ (event.get("name", "") == "CHANGE_APPLICATION_SETTING"), - (deep_get(event, "parameters", "APPLICATION_NAME", default="").lower() == "gmail"), - (deep_get(event, "parameters", "NEW_VALUE", default="").lower() == "false"), + (event.deep_get("parameters", "APPLICATION_NAME", default="").lower() == "gmail"), + (event.deep_get("parameters", "NEW_VALUE", default="").lower() == "false"), ( - deep_get(event, "parameters", "SETTING_NAME", default="") + event.deep_get("parameters", "SETTING_NAME", default="") == "AttachmentDeepScanningSettingsProto deep_scanning_enabled" ), ] @@ -22,6 +19,6 @@ def rule(event): def title(event): return ( f"GSuite Gmail Security Sandbox was disabled " - f"for [{deep_get(event, 'parameters', 'ORG_UNIT_NAME', default='')}] " - f"by [{deep_get(event, 'actor', 'email', default='')}]" + f"for [{event.deep_get('parameters', 'ORG_UNIT_NAME', default='')}] " + f"by [{event.deep_get('actor', 'email', default='')}]" ) diff --git a/rules/gsuite_activityevent_rules/gsuite_workspace_password_enforce_strong_disabled.py b/rules/gsuite_activityevent_rules/gsuite_workspace_password_enforce_strong_disabled.py index 1dbda3981..43c9e59e2 100644 --- a/rules/gsuite_activityevent_rules/gsuite_workspace_password_enforce_strong_disabled.py +++ b/rules/gsuite_activityevent_rules/gsuite_workspace_password_enforce_strong_disabled.py @@ -1,16 +1,13 @@ -from panther_base_helpers import deep_get - - def rule(event): - if deep_get(event, "id", "applicationName", default="").lower() != "admin": + if event.deep_get("id", "applicationName", default="").lower() != "admin": return False if all( [ (event.get("name", "") == "CHANGE_APPLICATION_SETTING"), (event.get("type", "") == "APPLICATION_SETTINGS"), - (deep_get(event, "parameters", "NEW_VALUE", default="").lower() == "off"), + (event.deep_get("parameters", "NEW_VALUE", default="").lower() == "off"), ( - deep_get(event, "parameters", "SETTING_NAME", default="") + event.deep_get("parameters", "SETTING_NAME", default="") == "Password Management - Enforce strong password" ), ] @@ -22,5 +19,5 @@ def rule(event): def title(event): return ( f"GSuite Workspace Strong Password Enforcement Has Been Disabled " - f"By [{deep_get(event, 'actor', 'email', default='')}]" + f"By [{event.deep_get('actor', 'email', default='')}]" ) diff --git a/rules/gsuite_activityevent_rules/gsuite_workspace_password_reuse_enabled.py b/rules/gsuite_activityevent_rules/gsuite_workspace_password_reuse_enabled.py index c0afefb91..f70f13650 100644 --- a/rules/gsuite_activityevent_rules/gsuite_workspace_password_reuse_enabled.py +++ b/rules/gsuite_activityevent_rules/gsuite_workspace_password_reuse_enabled.py @@ -1,16 +1,13 @@ -from panther_base_helpers import deep_get - - def rule(event): - if deep_get(event, "id", "applicationName", default="").lower() != "admin": + if event.deep_get("id", "applicationName", default="").lower() != "admin": return False if all( [ (event.get("name", "") == "CHANGE_APPLICATION_SETTING"), (event.get("type", "") == "APPLICATION_SETTINGS"), - (deep_get(event, "parameters", "NEW_VALUE", default="").lower() == "true"), + (event.deep_get("parameters", "NEW_VALUE", default="").lower() == "true"), ( - deep_get(event, "parameters", "SETTING_NAME", default="") + event.deep_get("parameters", "SETTING_NAME", default="") == "Password Management - Enable password reuse" ), ] @@ -22,5 +19,5 @@ def rule(event): def title(event): return ( f"GSuite Workspace Password Reuse Has Been Enabled " - f"By [{deep_get(event, 'actor', 'email', default='')}]" + f"By [{event.deep_get('actor', 'email', default='')}]" ) diff --git a/rules/gsuite_activityevent_rules/gsuite_workspace_trusted_domains_allowlist.py b/rules/gsuite_activityevent_rules/gsuite_workspace_trusted_domains_allowlist.py index 46f8f592c..27b5d573d 100644 --- a/rules/gsuite_activityevent_rules/gsuite_workspace_trusted_domains_allowlist.py +++ b/rules/gsuite_activityevent_rules/gsuite_workspace_trusted_domains_allowlist.py @@ -1,6 +1,3 @@ -from panther_base_helpers import deep_get - - def rule(event): return event.get("type") == "DOMAIN_SETTINGS" and event.get("name", "").endswith( "_TRUSTED_DOMAINS" @@ -11,6 +8,6 @@ def title(event): return ( f"GSuite Workspace Trusted Domains Modified " f"[{event.get('name', '')}] " - f"with [{deep_get(event, 'parameters', 'DOMAIN_NAME', default='')}] " - f"performed by [{deep_get(event, 'actor', 'email', default='')}]" + f"with [{event.deep_get('parameters', 'DOMAIN_NAME', default='')}] " + f"performed by [{event.deep_get('actor', 'email', default='')}]" ) diff --git a/rules/gsuite_reports_rules/gsuite_drive_external_share.py b/rules/gsuite_reports_rules/gsuite_drive_external_share.py index 03992ecdd..0004c8ebb 100644 --- a/rules/gsuite_reports_rules/gsuite_drive_external_share.py +++ b/rules/gsuite_reports_rules/gsuite_drive_external_share.py @@ -1,6 +1,6 @@ import datetime -from panther_base_helpers import deep_get, pattern_match, pattern_match_list +from panther_base_helpers import pattern_match, pattern_match_list COMPANY_DOMAIN = "your-company-name.com" EXCEPTION_PATTERNS = { @@ -63,9 +63,9 @@ def _check_acl_change_event(actor_email, acl_change_event): def rule(event): - application_name = deep_get(event, "id", "applicationName") + application_name = event.deep_get("id", "applicationName") events = event.get("events") - actor_email = deep_get(event, "actor", "email", default="EMAIL_UNKNOWN") + actor_email = event.deep_get("actor", "email", default="EMAIL_UNKNOWN") if application_name == "drive" and events and "acl_change" in set(e["type"] for e in events): # If any of the events in this record are a dangerous file share, alert: @@ -77,7 +77,7 @@ def rule(event): def title(event): events = event.get("events", []) - actor_email = deep_get(event, "actor", "email", default="EMAIL_UNKNOWN") + actor_email = event.deep_get("actor", "email", default="EMAIL_UNKNOWN") matching_events = [ _check_acl_change_event(actor_email, acl_change_event) for acl_change_event in events diff --git a/rules/gsuite_reports_rules/gsuite_drive_overly_visible.py b/rules/gsuite_reports_rules/gsuite_drive_overly_visible.py index 4c26b69d1..b45cb0ac3 100644 --- a/rules/gsuite_reports_rules/gsuite_drive_overly_visible.py +++ b/rules/gsuite_reports_rules/gsuite_drive_overly_visible.py @@ -1,4 +1,3 @@ -from panther_base_helpers import deep_get from panther_base_helpers import gsuite_details_lookup as details_lookup from panther_base_helpers import gsuite_parameter_lookup as param_lookup @@ -16,7 +15,7 @@ def rule(event): - if deep_get(event, "id", "applicationName") != "drive": + if event.deep_get("id", "applicationName") != "drive": return False details = details_lookup("access", RESOURCE_CHANGE_EVENTS, event) @@ -27,9 +26,9 @@ def rule(event): def dedup(event): - user = deep_get(event, "actor", "email") + user = event.deep_get("actor", "email") if user is None: - user = deep_get(event, "actor", "profileId", default="") + user = event.deep_get("actor", "profileId", default="") return user @@ -37,9 +36,9 @@ def title(event): details = details_lookup("access", RESOURCE_CHANGE_EVENTS, event) doc_title = param_lookup(details.get("parameters", {}), "doc_title") share_settings = param_lookup(details.get("parameters", {}), "visibility") - user = deep_get(event, "actor", "email") + user = event.deep_get("actor", "email") if user is None: - user = deep_get(event, "actor", "profileId", default="") + user = event.deep_get("actor", "profileId", default="") return ( f"User [{user}]" f" modified a document [{doc_title}] that has overly permissive share" diff --git a/rules/gsuite_reports_rules/gsuite_drive_visibility_change.py b/rules/gsuite_reports_rules/gsuite_drive_visibility_change.py index 1103fef58..75bf1902b 100644 --- a/rules/gsuite_reports_rules/gsuite_drive_visibility_change.py +++ b/rules/gsuite_reports_rules/gsuite_drive_visibility_change.py @@ -1,7 +1,6 @@ import json from unittest.mock import MagicMock -from panther_base_helpers import deep_get from panther_base_helpers import gsuite_parameter_lookup as param_lookup # Add any domain name(s) that you expect to share documents with in the ALLOWED_DOMAINS set @@ -67,7 +66,7 @@ def user_is_external(target_user): def rule(event): # pylint: disable=too-complex global ALLOWED_DOMAINS # pylint: disable=global-statement - if deep_get(event, "id", "applicationName") != "drive": + if event.deep_get("id", "applicationName") != "drive": return False # Events that have the types in INHERITANCE_EVENTS are @@ -75,7 +74,7 @@ def rule(event): # a change in the parent folder's permission. We ignore # these events to prevent every folder change from # generating multiple alerts. - if deep_get(event, "events", "name") in INHERITANCE_EVENTS: + if event.deep_get("events", "name") in INHERITANCE_EVENTS: return False log = event.get("p_row_id") @@ -167,7 +166,7 @@ def alert_context(event): def dedup(event): - return deep_get(event, "actor", "email", default="") + return event.deep_get("actor", "email", default="") def title(event): @@ -195,7 +194,7 @@ def title(event): # alert_access_scope = ALERT_DETAILS[log]["ACCESS_SCOPE"][0].replace("can_", "") return ( - f"User [{deep_get(event, 'actor', 'email', default='')}] made documents " + f"User [{event.deep_get('actor', 'email', default='')}] made documents " f"externally visible" ) diff --git a/rules/mongodb_rules/mongodb_atlas_api_key_created.py b/rules/mongodb_rules/mongodb_atlas_api_key_created.py index 5a8d6ff33..96ec06ae9 100644 --- a/rules/mongodb_rules/mongodb_atlas_api_key_created.py +++ b/rules/mongodb_rules/mongodb_atlas_api_key_created.py @@ -1,24 +1,23 @@ -from panther_base_helpers import deep_get, deep_walk from panther_mongodb_helpers import mongodb_alert_context def rule(event): - return deep_get(event, "eventTypeName", default="") == "API_KEY_ACCESS_LIST_ENTRY_ADDED" + return event.deep_get("eventTypeName", default="") == "API_KEY_ACCESS_LIST_ENTRY_ADDED" def title(event): - user = deep_get(event, "username", default="") - public_key = deep_get(event, "targetPublicKey", default="") + user = event.deep_get("username", default="") + public_key = event.deep_get("targetPublicKey", default="") return f"MongoDB Atlas: [{user}] updated the allowed access list for API Key [{public_key}]" def alert_context(event): context = mongodb_alert_context(event) - links = deep_walk(event, "links", "href", return_val="first", default="") + links = event.deep_walk("links", "href", return_val="first", default="") extra_context = { "links": links, - "event_type_name": deep_get(event, "eventTypeName", default=""), - "target_public_key": deep_get(event, "targetPublicKey", default=""), + "event_type_name": event.deep_get("eventTypeName", default=""), + "target_public_key": event.deep_get("targetPublicKey", default=""), } context.update(extra_context) diff --git a/rules/mongodb_rules/mongodb_external_user_invited.py b/rules/mongodb_rules/mongodb_external_user_invited.py index f4c9de06c..37d3490ad 100644 --- a/rules/mongodb_rules/mongodb_external_user_invited.py +++ b/rules/mongodb_rules/mongodb_external_user_invited.py @@ -1,7 +1,6 @@ import json from unittest.mock import MagicMock -from panther_base_helpers import deep_get from panther_mongodb_helpers import mongodb_alert_context # Set domains allowed to join the organization ie. company.com @@ -12,8 +11,8 @@ def rule(event): global ALLOWED_DOMAINS # pylint: disable=global-statement if isinstance(ALLOWED_DOMAINS, MagicMock): ALLOWED_DOMAINS = json.loads(ALLOWED_DOMAINS()) # pylint: disable=not-callable - if deep_get(event, "eventTypeName", default="") == "INVITED_TO_ORG": - target_user = deep_get(event, "targetUsername", default="") + if event.deep_get("eventTypeName", default="") == "INVITED_TO_ORG": + target_user = event.deep_get("targetUsername", default="") target_domain = target_user.split("@")[-1] return target_domain not in ALLOWED_DOMAINS return False diff --git a/rules/netskope_rules/netskope_unauthorized_api_calls.py b/rules/netskope_rules/netskope_unauthorized_api_calls.py index 9f3e96e12..f803996e6 100644 --- a/rules/netskope_rules/netskope_unauthorized_api_calls.py +++ b/rules/netskope_rules/netskope_unauthorized_api_calls.py @@ -1,8 +1,5 @@ -from panther_base_helpers import deep_walk - - def rule(event): - data_values = deep_walk(event, "supporting_data", "data_values") + data_values = event.deep_walk("supporting_data", "data_values") if data_values and data_values[0] == 403: return True return False diff --git a/rules/notion_rules/notion_page_view_impossible_travel.py b/rules/notion_rules/notion_page_view_impossible_travel.py index 08c4b22fe..758e2525a 100644 --- a/rules/notion_rules/notion_page_view_impossible_travel.py +++ b/rules/notion_rules/notion_page_view_impossible_travel.py @@ -20,7 +20,7 @@ def gen_key(event): The data_model needs to answer to "actor_user" """ - rule_name = deep_get(event, "p_source_label") + rule_name = event.get("p_source_label") actor = event.udm("actor_user") if None in [rule_name, actor]: return None @@ -43,7 +43,7 @@ def rule(event): if event.deep_get("event", "type") != "page.viewed": return False - p_event_datetime = resolve_timestamp_string(deep_get(event, "p_event_time")) + p_event_datetime = resolve_timestamp_string(event.deep_get("p_event_time")) if p_event_datetime is None: # we couldn't go from p_event_time to a datetime object # we need to do this in order to make later time comparisons generic @@ -153,7 +153,7 @@ def rule(event): def title(event): # - log_source = deep_get(event, "p_source_label", default="") + log_source = event.deep_get("p_source_label", default="") old_city = deep_get(EVENT_CITY_TRACKING, "previous", "city", default="") new_city = deep_get(EVENT_CITY_TRACKING, "current", "city", default="") speed = deep_get(EVENT_CITY_TRACKING, "speed", default="") diff --git a/rules/notion_rules/notion_workspace_settings_enforce_saml_sso_config_updated.py b/rules/notion_rules/notion_workspace_settings_enforce_saml_sso_config_updated.py index 786733df0..da87502c3 100644 --- a/rules/notion_rules/notion_workspace_settings_enforce_saml_sso_config_updated.py +++ b/rules/notion_rules/notion_workspace_settings_enforce_saml_sso_config_updated.py @@ -1,5 +1,4 @@ from global_filter_notion import filter_include_event -from panther_base_helpers import deep_get from panther_notion_helpers import notion_alert_context @@ -15,8 +14,7 @@ def rule(event): def title(event): user = event.deep_get("event", "actor", "person", "email", default="") workspace_id = event.deep_get("event", "workspace_id", default="") - state = deep_get( - event, + state = event.deep_get( "event", "workspace.settings.enforce_saml_sso_config_updated", "state", @@ -36,8 +34,7 @@ def title(event): def severity(event): - state = deep_get( - event, + state = event.deep_get( "event", "workspace.settings.enforce_saml_sso_config_updated", "state", diff --git a/rules/notion_rules/notion_workspace_settings_public_homepage_added.py b/rules/notion_rules/notion_workspace_settings_public_homepage_added.py index 5799e041a..91c4f56e9 100644 --- a/rules/notion_rules/notion_workspace_settings_public_homepage_added.py +++ b/rules/notion_rules/notion_workspace_settings_public_homepage_added.py @@ -1,5 +1,4 @@ from global_filter_notion import filter_include_event -from panther_base_helpers import deep_get from panther_notion_helpers import notion_alert_context @@ -14,8 +13,7 @@ def rule(event): def title(event): actor = event.deep_get("event", "actor", "person", "email", default="") wkspc_id = event.deep_get("event", "workspace_id", default="") - db_id = deep_get( - event, + db_id = event.deep_get( "event", "workspace.settings.public_homepage_added", "new_public_page", @@ -28,8 +26,7 @@ def title(event): def alert_context(event): context = notion_alert_context(event) workspace_id = event.deep_get("event", "workspace_id", default="") - db_id = deep_get( - event, + db_id = event.deep_get( "event", "workspace.settings.public_homepage_added", "new_public_page", diff --git a/rules/okta_rules/okta_admin_role_assigned.py b/rules/okta_rules/okta_admin_role_assigned.py index a4ba3a087..4d21017e0 100644 --- a/rules/okta_rules/okta_admin_role_assigned.py +++ b/rules/okta_rules/okta_admin_role_assigned.py @@ -1,6 +1,6 @@ import re -from panther_base_helpers import deep_get, okta_alert_context +from panther_base_helpers import okta_alert_context ADMIN_PATTERN = re.compile(r"[aA]dministrator") @@ -8,30 +8,30 @@ def rule(event): return ( event.get("eventType", None) == "user.account.privilege.grant" - and deep_get(event, "outcome", "result") == "SUCCESS" + and event.deep_get("outcome", "result") == "SUCCESS" and bool( ADMIN_PATTERN.search( - deep_get(event, "debugContext", "debugData", "privilegeGranted", default="") + event.deep_get("debugContext", "debugData", "privilegeGranted", default="") ) ) ) def dedup(event): - return deep_get(event, "debugContext", "debugData", "requestId", default="") + return event.deep_get("debugContext", "debugData", "requestId", default="") def title(event): target = event.get("target", [{}]) display_name = target[0].get("displayName", "MISSING DISPLAY NAME") if target else "" alternate_id = target[0].get("alternateId", "MISSING ALTERNATE ID") if target else "" - privilege = deep_get( - event, "debugContext", "debugData", "privilegeGranted", default="" + privilege = event.deep_get( + "debugContext", "debugData", "privilegeGranted", default="" ) return ( - f"{deep_get(event, 'actor', 'displayName')} " - f"<{deep_get(event, 'actor', 'alternateId')}> granted " + f"{event.deep_get('actor', 'displayName')} " + f"<{event.deep_get('actor', 'alternateId')}> granted " f"[{privilege}] privileges to {display_name} <{alternate_id}>" ) @@ -41,8 +41,8 @@ def alert_context(event): def severity(event): - if "Super administrator" in deep_get( - event, "debugContext", "debugData", "privilegeGranted", default="" + if "Super administrator" in event.deep_get( + "debugContext", "debugData", "privilegeGranted", default="" ): return "HIGH" return "INFO" diff --git a/rules/okta_rules/okta_anonymizing_vpn_login.py b/rules/okta_rules/okta_anonymizing_vpn_login.py index 51094fd8d..48cc62ca2 100644 --- a/rules/okta_rules/okta_anonymizing_vpn_login.py +++ b/rules/okta_rules/okta_anonymizing_vpn_login.py @@ -1,18 +1,18 @@ -from panther_base_helpers import deep_get, okta_alert_context +from panther_base_helpers import okta_alert_context def rule(event): - return event.get("eventType") == "user.session.start" and deep_get( - event, "securityContext", "isProxy", default=False + return event.get("eventType") == "user.session.start" and event.deep_get( + "securityContext", "isProxy", default=False ) def title(event): return ( - f"{deep_get(event, 'actor', 'displayName', default='')} " - f"<{deep_get(event, 'actor', 'alternateId', default='alternateId-not-found')}> " + f"{event.deep_get('actor', 'displayName', default='')} " + f"<{event.deep_get('actor', 'alternateId', default='alternateId-not-found')}> " f"attempted to sign-in from anonymizing VPN with domain " - f"[{deep_get(event, 'securityContext', 'domain', default='')}]" + f"[{event.deep_get('securityContext', 'domain', default='')}]" ) diff --git a/rules/okta_rules/okta_api_key_created.py b/rules/okta_rules/okta_api_key_created.py index 7f997f037..a4532ed01 100644 --- a/rules/okta_rules/okta_api_key_created.py +++ b/rules/okta_rules/okta_api_key_created.py @@ -1,10 +1,10 @@ -from panther_base_helpers import deep_get, okta_alert_context +from panther_base_helpers import okta_alert_context def rule(event): return ( event.get("eventType", None) == "system.api_token.create" - and deep_get(event, "outcome", "result") == "SUCCESS" + and event.deep_get("outcome", "result") == "SUCCESS" ) @@ -13,7 +13,7 @@ def title(event): key_name = target[0].get("displayName", "MISSING DISPLAY NAME") if target else "MISSING TARGET" return ( - f"{deep_get(event, 'actor', 'displayName')} <{deep_get(event, 'actor', 'alternateId')}>" + f"{event.deep_get('actor', 'displayName')} <{event.deep_get('actor', 'alternateId')}>" f"created a new API key - <{key_name}>" ) diff --git a/rules/okta_rules/okta_api_key_revoked.py b/rules/okta_rules/okta_api_key_revoked.py index 9a04cd35b..a24d47ef0 100644 --- a/rules/okta_rules/okta_api_key_revoked.py +++ b/rules/okta_rules/okta_api_key_revoked.py @@ -1,10 +1,10 @@ -from panther_base_helpers import deep_get, okta_alert_context +from panther_base_helpers import okta_alert_context def rule(event): return ( event.get("eventType", None) == "system.api_token.revoke" - and deep_get(event, "outcome", "result") == "SUCCESS" + and event.deep_get("outcome", "result") == "SUCCESS" ) @@ -13,7 +13,7 @@ def title(event): key_name = target[0].get("displayName", "MISSING DISPLAY NAME") if target else "MISSING TARGET" return ( - f"{deep_get(event, 'actor', 'displayName')} <{deep_get(event, 'actor', 'alternateId')}>" + f"{event.deep_get('actor', 'displayName')} <{event.deep_get('actor', 'alternateId')}>" f"revoked API key - <{key_name}>" ) diff --git a/rules/okta_rules/okta_app_unauthorized_access_attempt.py b/rules/okta_rules/okta_app_unauthorized_access_attempt.py index f47c0595a..57c8d9c04 100644 --- a/rules/okta_rules/okta_app_unauthorized_access_attempt.py +++ b/rules/okta_rules/okta_app_unauthorized_access_attempt.py @@ -1,4 +1,4 @@ -from panther_base_helpers import deep_get, okta_alert_context +from panther_base_helpers import okta_alert_context def rule(event): @@ -7,7 +7,7 @@ def rule(event): def title(event): return ( - f"[{deep_get(event, 'actor', 'alternateId', default = '')}] " + f"[{event.deep_get('actor', 'alternateId', default = '')}] " f"attempted unauthorized access to " f"[{event.get('target', [{}])[0].get('alternateId','')}]" ) diff --git a/rules/okta_rules/okta_brute_force_logins.py b/rules/okta_rules/okta_brute_force_logins.py index c4a8e9ffe..9074cf605 100644 --- a/rules/okta_rules/okta_brute_force_logins.py +++ b/rules/okta_rules/okta_brute_force_logins.py @@ -1,9 +1,9 @@ -from panther_base_helpers import deep_get, okta_alert_context +from panther_base_helpers import okta_alert_context def rule(event): return ( - deep_get(event, "outcome", "result") == "FAILURE" + event.deep_get("outcome", "result") == "FAILURE" and event.get("eventType") == "user.session.start" ) @@ -11,8 +11,8 @@ def rule(event): def title(event): return ( f"Suspected brute force Okta logins to account " - f"{deep_get(event, 'actor', 'alternateId', default='')}, due to " - f"[{deep_get(event, 'outcome', 'reason', default='')}]" + f"{event.deep_get('actor', 'alternateId', default='')}, due to " + f"[{event.deep_get('outcome', 'reason', default='')}]" ) diff --git a/rules/okta_rules/okta_geo_improbable_access.py b/rules/okta_rules/okta_geo_improbable_access.py index e37a3c527..aba0fa727 100644 --- a/rules/okta_rules/okta_geo_improbable_access.py +++ b/rules/okta_rules/okta_geo_improbable_access.py @@ -13,14 +13,14 @@ def rule(event): # Only evaluate successful logins if ( event.get("eventType") != "user.session.start" - or deep_get(event, "outcome", "result") == "FAILURE" + or event.deep_get("outcome", "result") == "FAILURE" ): return False new_login_stats = { - "city": deep_get(event, "client", "geographicalContext", "city"), - "lon": deep_get(event, "client", "geographicalContext", "geolocation", "lon"), - "lat": deep_get(event, "client", "geographicalContext", "geolocation", "lat"), + "city": event.deep_get("client", "geographicalContext", "city"), + "lon": event.deep_get("client", "geographicalContext", "geolocation", "lon"), + "lat": event.deep_get("client", "geographicalContext", "geolocation", "lat"), } # Bail out if we have a None value in set as it causes false positives if None in new_login_stats.values(): @@ -58,7 +58,7 @@ def rule(event): def gen_key(event): - return f"Okta.Login.GeographicallyImprobable{deep_get(event, 'actor', 'alternateId')}" + return f"Okta.Login.GeographicallyImprobable{event.deep_get('actor', 'alternateId')}" # Taken from stack overflow user Michael0x2a: https://stackoverflow.com/a/19412565/6645635 @@ -87,9 +87,9 @@ def store_login_info(key, event): [ dumps( { - "city": deep_get(event, "client", "geographicalContext", "city"), - "lon": deep_get(event, "client", "geographicalContext", "geolocation", "lon"), - "lat": deep_get(event, "client", "geographicalContext", "geolocation", "lat"), + "city": event.deep_get("client", "geographicalContext", "city"), + "lon": event.deep_get("client", "geographicalContext", "geolocation", "lon"), + "lat": event.deep_get("client", "geographicalContext", "geolocation", "lat"), "time": event.get("p_event_time"), } ) @@ -107,14 +107,14 @@ def title(event): EVENT_CITY_TRACKING.get(event.get("p_row_id")), "new_city", default="" ) return ( - f"Geographically improbable login for user [{deep_get(event, 'actor', 'alternateId')}] " + f"Geographically improbable login for user [{event.deep_get('actor', 'alternateId')}] " f"from [{old_city}] to [{new_city}]" ) def dedup(event): # (Optional) Return a string which will de-duplicate similar alerts. - return deep_get(event, "actor", "alternateId") + return event.deep_get("actor", "alternateId") def alert_context(event): diff --git a/rules/okta_rules/okta_idp_create_modify.py b/rules/okta_rules/okta_idp_create_modify.py index d62f22aa0..93902cfdd 100644 --- a/rules/okta_rules/okta_idp_create_modify.py +++ b/rules/okta_rules/okta_idp_create_modify.py @@ -1,4 +1,4 @@ -from panther_base_helpers import deep_get, deep_walk, okta_alert_context +from panther_base_helpers import okta_alert_context def rule(event): @@ -7,12 +7,12 @@ def rule(event): def title(event): action = event.get("eventType").split(".")[-1] - target = deep_walk( - event, "target", "displayName", default="", return_val="first" + target = event.deep_walk( + "target", "displayName", default="", return_val="first" ) return ( - f"{deep_get(event, 'actor', 'displayName', default='')} " - f"<{deep_get(event, 'actor', 'alternateId', default='alternateId-not-found')}> " + f"{event.deep_get('actor', 'displayName', default='')} " + f"<{event.deep_get('actor', 'alternateId', default='alternateId-not-found')}> " f"{action}d Identity Provider [{target}]" ) diff --git a/rules/okta_rules/okta_idp_signin.py b/rules/okta_rules/okta_idp_signin.py index 7676b0c3b..d9de91002 100644 --- a/rules/okta_rules/okta_idp_signin.py +++ b/rules/okta_rules/okta_idp_signin.py @@ -1,4 +1,4 @@ -from panther_base_helpers import deep_get, deep_walk, okta_alert_context +from panther_base_helpers import okta_alert_context def rule(event): @@ -6,12 +6,12 @@ def rule(event): def title(event): - target = deep_walk( - event, "target", "displayName", default="displayName-not-found", return_val="first" + target = event.deep_walk( + "target", "displayName", default="displayName-not-found", return_val="first" ) return ( - f"{deep_get(event, 'actor', 'displayName', default='')} " - f"<{deep_get(event, 'actor', 'alternateId', default='alternateId-not-found')}> " + f"{event.deep_get('actor', 'displayName', default='')} " + f"<{event.deep_get('actor', 'alternateId', default='alternateId-not-found')}> " f"signed in via 3rd party Identity Provider to {target}" ) diff --git a/rules/okta_rules/okta_new_behavior_accessing_admin_console.py b/rules/okta_rules/okta_new_behavior_accessing_admin_console.py index e82004e86..40def84b8 100644 --- a/rules/okta_rules/okta_new_behavior_accessing_admin_console.py +++ b/rules/okta_rules/okta_new_behavior_accessing_admin_console.py @@ -1,24 +1,24 @@ -from panther_base_helpers import deep_get, deep_walk, okta_alert_context +from panther_base_helpers import okta_alert_context def rule(event): if event.get("eventtype") != "policy.evaluate_sign_on": return False - if "Okta Admin Console" not in deep_walk(event, "target", "displayName", default=""): + if "Okta Admin Console" not in event.deep_walk("target", "displayName", default=""): return False - behaviors = deep_get(event, "debugContext", "debugData", "behaviors") + behaviors = event.deep_get("debugContext", "debugData", "behaviors") if behaviors: return "New Device=POSITIVE" in behaviors and "New IP=POSITIVE" in behaviors return ( - deep_get( - event, "debugContext", "debugData", "logOnlySecurityData", "behaviors", "New Device" + event.deep_get( + "debugContext", "debugData", "logOnlySecurityData", "behaviors", "New Device" ) == "POSITIVE" - and deep_get( - event, "debugContext", "debugData", "logOnlySecurityData", "behaviors", "New IP" + and event.deep_get( + "debugContext", "debugData", "logOnlySecurityData", "behaviors", "New IP" ) == "POSITIVE" ) @@ -26,11 +26,11 @@ def rule(event): def title(event): return ( - f"{deep_get(event, 'actor', 'displayName', default='')} " - f"<{deep_get(event, 'actor', 'alternateId', default='alternateId-not-found')}> " + f"{event.deep_get('actor', 'displayName', default='')} " + f"<{event.deep_get('actor', 'alternateId', default='alternateId-not-found')}> " f"accessed Okta Admin Console using new behaviors: " - f"New IP: {deep_get(event, 'client', 'ipAddress', default='')} " - f"New Device: {deep_get(event, 'device', 'name', default='')}" + f"New IP: {event.deep_get('client', 'ipAddress', default='')} " + f"New Device: {event.deep_get('device', 'name', default='')}" ) diff --git a/rules/okta_rules/okta_org2org_creation_modification.py b/rules/okta_rules/okta_org2org_creation_modification.py index 41bf07a70..0605bad09 100644 --- a/rules/okta_rules/okta_org2org_creation_modification.py +++ b/rules/okta_rules/okta_org2org_creation_modification.py @@ -1,4 +1,4 @@ -from panther_base_helpers import deep_get, deep_walk, okta_alert_context +from panther_base_helpers import okta_alert_context APP_LIFECYCLE_EVENTS = ( "application.lifecycle.update", @@ -11,17 +11,17 @@ def rule(event): if event.get("eventType") not in APP_LIFECYCLE_EVENTS: return False - return "Org2Org" in deep_walk(event, "target", "displayName", default="", return_val="first") + return "Org2Org" in event.deep_walk("target", "displayName", default="", return_val="first") def title(event): action = event.get("eventType").split(".")[-1] - target = deep_walk( - event, "target", "alternateId", default="", return_val="first" + target = event.deep_walk( + "target", "alternateId", default="", return_val="first" ) return ( - f"{deep_get(event, 'actor', 'displayName', default='')} " - f"<{deep_get(event, 'actor', 'alternateId', default='alternateId-not-found')}> " + f"{event.deep_get('actor', 'displayName', default='')} " + f"<{event.deep_get('actor', 'alternateId', default='alternateId-not-found')}> " f"{action}d Org2Org app [{target}]" ) diff --git a/rules/okta_rules/okta_password_accessed.py b/rules/okta_rules/okta_password_accessed.py index cfcc315cc..e3b4ef1d1 100644 --- a/rules/okta_rules/okta_password_accessed.py +++ b/rules/okta_rules/okta_password_accessed.py @@ -1,4 +1,4 @@ -from panther_base_helpers import deep_get, get_val_from_list +from panther_base_helpers import get_val_from_list # pylint: disable=global-variable-undefined @@ -16,13 +16,13 @@ def rule(event): event.get("target", [{}]), "alternateId", "type", "AppInstance" ) - if deep_get(event, "actor", "alternateId") not in TARGET_USERS: + if event.deep_get("actor", "alternateId") not in TARGET_USERS: return True return False def dedup(event): - dedup_str = deep_get(event, "actor", "alternateId") + dedup_str = event.deep_get("actor", "alternateId") if TARGET_USERS: dedup_str += ":" + str(TARGET_USERS) @@ -33,7 +33,7 @@ def dedup(event): def title(event): return ( - f"A user {deep_get(event, 'actor', 'alternateId')} accessed another user's " + f"A user {event.deep_get('actor', 'alternateId')} accessed another user's " f"{TARGET_USERS} " f"{TARGET_APP_NAMES} password" ) diff --git a/rules/okta_rules/okta_password_extraction_via_scim.py b/rules/okta_rules/okta_password_extraction_via_scim.py index 2f5984c04..b15d77c02 100644 --- a/rules/okta_rules/okta_password_extraction_via_scim.py +++ b/rules/okta_rules/okta_password_extraction_via_scim.py @@ -1,21 +1,21 @@ -from panther_base_helpers import deep_get, deep_walk, okta_alert_context +from panther_base_helpers import okta_alert_context def rule(event): return event.get( "eventType" - ) == "application.lifecycle.update" and "Pushing user passwords" in deep_get( - event, "outcome", "reason", default="" + ) == "application.lifecycle.update" and "Pushing user passwords" in event.deep_get( + "outcome", "reason", default="" ) def title(event): - target = deep_walk( - event, "target", "alternateId", default="", return_val="first" + target = event.deep_walk( + "target", "alternateId", default="", return_val="first" ) return ( - f"{deep_get(event, 'actor', 'displayName', default='')} " - f"<{deep_get(event, 'actor', 'alternateId', default='alternateId-not-found')}> " + f"{event.deep_get('actor', 'displayName', default='')} " + f"<{event.deep_get('actor', 'alternateId', default='alternateId-not-found')}> " f"extracted cleartext user passwords via SCIM app [{target}]" ) diff --git a/rules/okta_rules/okta_phishing_attempt_blocked_by_fastpass.py b/rules/okta_rules/okta_phishing_attempt_blocked_by_fastpass.py index d9ebe3b67..57834e399 100644 --- a/rules/okta_rules/okta_phishing_attempt_blocked_by_fastpass.py +++ b/rules/okta_rules/okta_phishing_attempt_blocked_by_fastpass.py @@ -1,18 +1,18 @@ -from panther_base_helpers import deep_get, okta_alert_context +from panther_base_helpers import okta_alert_context def rule(event): return ( event.get("eventType") == "user.authentication.auth_via_mfa" - and deep_get(event, "outcome", "result") == "FAILURE" - and deep_get(event, "outcome", "reason") == "FastPass declined phishing attempt" + and event.deep_get("outcome", "result") == "FAILURE" + and event.deep_get("outcome", "reason") == "FastPass declined phishing attempt" ) def title(event): return ( - f"{deep_get(event, 'actor', 'displayName', default='')} " - f"<{deep_get(event, 'actor', 'alternateId', default='alternateId-not-found')}> " + f"{event.deep_get('actor', 'displayName', default='')} " + f"<{event.deep_get('actor', 'alternateId', default='alternateId-not-found')}> " f"FastPass declined phishing attempt" ) diff --git a/rules/okta_rules/okta_potentially_stolen_session.py b/rules/okta_rules/okta_potentially_stolen_session.py index 1e052b274..b2eb15d78 100644 --- a/rules/okta_rules/okta_potentially_stolen_session.py +++ b/rules/okta_rules/okta_potentially_stolen_session.py @@ -2,7 +2,7 @@ from datetime import timedelta from difflib import SequenceMatcher -from panther_base_helpers import deep_get, okta_alert_context +from panther_base_helpers import okta_alert_context from panther_detection_helpers.caching import get_string_set, put_string_set FUZZ_RATIO_MIN = 0.95 @@ -17,15 +17,15 @@ def rule(event): # ensure previous session info is avaialable in the alert_context for investigation global PREVIOUS_SESSION - session_id = deep_get(event, "authenticationContext", "externalSessionId", default="unknown") - dt_hash = deep_get(event, "debugContext", "debugData", "dtHash", default="unknown") + session_id = event.deep_get("authenticationContext", "externalSessionId", default="unknown") + dt_hash = event.deep_get("debugContext", "debugData", "dtHash", default="unknown") # Some events by Okta admins may appear to have changed IPs # and user agents due to internal Okta behavior: # https://support.okta.com/help/s/article/okta-integrations-showing-as-rawuseragent-with-okta-ips # As such, we ignore certain client ids known to originate from Okta: # https://developer.okta.com/docs/api/openapi/okta-myaccount/myaccount/tag/OktaApplications/ - if deep_get(event, "client", "id") in [ + if event.deep_get("client", "id") in [ "okta.b58d5b75-07d4-5f25-bf59-368a1261a405" # Admin Console ]: return False @@ -50,18 +50,18 @@ def rule(event): put_string_set( key, [ - str(deep_get(event, "securityContext", "asNumber")), - deep_get(event, "client", "ipAddress"), + str(event.deep_get("securityContext", "asNumber")), + event.deep_get("client", "ipAddress"), # clearly label the user agent string so we can find it during the comparison - "user_agent:" + deep_get(event, "client", "userAgent", "rawUserAgent"), - deep_get(event, "client", "userAgent", "browser"), - deep_get(event, "client", "userAgent", "os"), + "user_agent:" + event.deep_get("client", "userAgent", "rawUserAgent"), + event.deep_get("client", "userAgent", "browser"), + event.deep_get("client", "userAgent", "os"), event.get("p_event_time"), "sign_on_mode:" - + deep_get(event, "debugContext", "debugData", "signOnMode", default="unknown"), + + event.deep_get("debugContext", "debugData", "signOnMode", default="unknown"), "threat_suspected:" - + deep_get( - event, "debugContext", "debugData", "threat_suspected", default="unknown" + + event.deep_get( + "debugContext", "debugData", "threat_suspected", default="unknown" ), ], epoch_seconds=event.event_time_epoch() + SESSION_TIMEOUT, @@ -79,13 +79,13 @@ def rule(event): diff_ratio = SequenceMatcher( None, - deep_get(event, "client", "userAgent", "rawUserAgent", default="ua_not_found"), + event.deep_get("client", "userAgent", "rawUserAgent", default="ua_not_found"), prev_ua, ).ratio() # is this session being used from a new IP and a different browser if ( - str(deep_get(event, "client", "ipAddress", default="ip_not_found")) + str(event.deep_get("client", "ipAddress", default="ip_not_found")) not in PREVIOUS_SESSION and diff_ratio < FUZZ_RATIO_MIN ): @@ -99,7 +99,7 @@ def rule(event): def title(event): return ( f"Potentially Stolen Okta Session - " - f"{deep_get(event, 'actor', 'displayName', default='Unknown_user')}" + f"{event.deep_get('actor', 'displayName', default='Unknown_user')}" ) diff --git a/rules/okta_rules/okta_support_reset.py b/rules/okta_rules/okta_support_reset.py index 64aff6c39..a3737e201 100644 --- a/rules/okta_rules/okta_support_reset.py +++ b/rules/okta_rules/okta_support_reset.py @@ -1,4 +1,4 @@ -from panther_base_helpers import deep_get, okta_alert_context +from panther_base_helpers import okta_alert_context OKTA_SUPPORT_RESET_EVENTS = [ "user.account.reset_password", @@ -12,10 +12,10 @@ def rule(event): if event.get("eventType") not in OKTA_SUPPORT_RESET_EVENTS: return False return ( - deep_get(event, "actor", "alternateId") == "system@okta.com" - and deep_get(event, "transaction", "id") == "unknown" - and deep_get(event, "userAgent", "rawUserAgent") is None - and deep_get(event, "client", "geographicalContext", "country") is None + event.deep_get("actor", "alternateId") == "system@okta.com" + and event.deep_get("transaction", "id") == "unknown" + and event.deep_get("userAgent", "rawUserAgent") is None + and event.deep_get("client", "geographicalContext", "country") is None ) diff --git a/rules/okta_rules/okta_threatinsight_security_threat_detected.py b/rules/okta_rules/okta_threatinsight_security_threat_detected.py index 11644629d..a0abf16aa 100644 --- a/rules/okta_rules/okta_threatinsight_security_threat_detected.py +++ b/rules/okta_rules/okta_threatinsight_security_threat_detected.py @@ -1,4 +1,4 @@ -from panther_base_helpers import deep_get, okta_alert_context +from panther_base_helpers import okta_alert_context def severity_from_threat_string(threat_detection): @@ -30,7 +30,7 @@ def title(event): def severity(event): - outcome = deep_get(event, "outcome", "result", default="") + outcome = event.deep_get("outcome", "result", default="") if outcome == "DENY": return "INFO" threat_detection = ( diff --git a/rules/onepassword_rules/onepassword_lut_sensitive_item_access.py b/rules/onepassword_rules/onepassword_lut_sensitive_item_access.py index 09f74faba..7090a1391 100644 --- a/rules/onepassword_rules/onepassword_lut_sensitive_item_access.py +++ b/rules/onepassword_rules/onepassword_lut_sensitive_item_access.py @@ -8,28 +8,26 @@ The steps detailed in that document are required for this rule to function as intended. """ -from panther_base_helpers import deep_get - # Add the human-readable names of 1Password items you want to monitor SENSITIVE_ITEM_WATCHLIST = ["demo_item"] def rule(event): return ( - deep_get(event, "p_enrichment", "1Password Translation", "item_uuid", "title") + event.deep_get("p_enrichment", "1Password Translation", "item_uuid", "title") in SENSITIVE_ITEM_WATCHLIST ) def title(event): - return f"A Sensitive 1Password Item was Accessed by user {deep_get(event, 'user', 'name')}" + return f"A Sensitive 1Password Item was Accessed by user {event.deep_get('user', 'name')}" def alert_context(event): context = { - "user": deep_get(event, "user", "name"), - "item_name": deep_get(event, "p_enrichment", "1Password Translation", "item_uuid", "title"), - "client": deep_get(event, "client", "app_name"), + "user": event.deep_get("user", "name"), + "item_name": event.deep_get("p_enrichment", "1Password Translation", "item_uuid", "title"), + "client": event.deep_get("client", "app_name"), "ip_address": event.udm("source_ip"), "event_time": event.get("timestamp"), } diff --git a/rules/onepassword_rules/onepassword_sensitive_item_access.py b/rules/onepassword_rules/onepassword_sensitive_item_access.py index cfee63ed5..1767d9b8a 100644 --- a/rules/onepassword_rules/onepassword_sensitive_item_access.py +++ b/rules/onepassword_rules/onepassword_sensitive_item_access.py @@ -8,8 +8,6 @@ BETA - Sensitive 1Password Item Accessed (onepassword_lut_sensitive_item_access.py) """ -from panther_base_helpers import deep_get - SENSITIVE_ITEM_WATCHLIST = {"ecd1d435c26440dc930ddfbbef201a11": "demo_item"} @@ -18,14 +16,14 @@ def rule(event): def title(event): - return f"A Sensitive 1Password Item was Accessed by user {deep_get(event, 'user', 'name')}" + return f"A Sensitive 1Password Item was Accessed by user {event.deep_get('user', 'name')}" def alert_context(event): context = { - "user": deep_get(event, "user", "name"), - "item_name": deep_get(event, "p_enrichment", "1Password Translation", "item_uuid", "title"), - "client": deep_get(event, "client", "app_name"), + "user": event.deep_get("user", "name"), + "item_name": event.deep_get("p_enrichment", "1Password Translation", "item_uuid", "title"), + "client": event.deep_get("client", "app_name"), "ip_address": event.udm("source_ip"), "event_time": event.get("timestamp"), } diff --git a/rules/onepassword_rules/onepassword_unusual_client.py b/rules/onepassword_rules/onepassword_unusual_client.py index 4e273f56e..27aad2763 100644 --- a/rules/onepassword_rules/onepassword_unusual_client.py +++ b/rules/onepassword_rules/onepassword_unusual_client.py @@ -9,8 +9,6 @@ If this differs from your orginization's needs this rule can be edited to suit your environment """ -from panther_base_helpers import deep_get - def rule(event): client_allowlist = [ @@ -24,20 +22,20 @@ def rule(event): "1Password for Android", ] - return deep_get(event, "client", "app_name") not in client_allowlist + return event.deep_get("client", "app_name") not in client_allowlist def title(event): - return f"Unusual 1Password client - {deep_get(event, 'client', 'app_name')} detected" + return f"Unusual 1Password client - {event.deep_get('client', 'app_name')} detected" def alert_context(event): context = {} - context["user"] = deep_get(event, "target_user", "name", default="UNKNOWN_USER") + context["user"] = event.deep_get("target_user", "name", default="UNKNOWN_USER") context["user_email"] = event.udm("actor_user") context["ip_address"] = event.udm("source_ip") - context["client"] = deep_get(event, "client", "app_name", default="UNKNOWN_CLIENT") - context["OS"] = deep_get(event, "client", "os_name", default="UNKNOWN_OS") + context["client"] = event.deep_get("client", "app_name", default="UNKNOWN_CLIENT") + context["OS"] = event.deep_get("client", "os_name", default="UNKNOWN_OS") context["login_result"] = event.get("category") context["time_seen"] = event.get("timestamp") diff --git a/rules/osquery_rules/osquery_linux_aws_commands.py b/rules/osquery_rules/osquery_linux_aws_commands.py index d22d7b474..4ac7366ae 100644 --- a/rules/osquery_rules/osquery_linux_aws_commands.py +++ b/rules/osquery_rules/osquery_linux_aws_commands.py @@ -1,7 +1,5 @@ import shlex -from panther_base_helpers import deep_get - PLATFORM_IGNORE_LIST = {"darwin"} @@ -10,11 +8,11 @@ def rule(event): if ( event.get("action") != "added" or "shell_history" not in event.get("name") - or deep_get(event, "decorations", "platform") in PLATFORM_IGNORE_LIST + or event.deep_get("decorations", "platform") in PLATFORM_IGNORE_LIST ): return False - command = deep_get(event, "columns", "command") + command = event.deep_get("columns", "command") if not command: return False try: @@ -31,6 +29,6 @@ def rule(event): def title(event): return ( - f"User [{deep_get(event, 'columns', 'username', default='')}] issued an" + f"User [{event.deep_get('columns', 'username', default='')}] issued an" f" aws-cli command on [{event.get('hostIdentifier', '')}]" ) diff --git a/rules/osquery_rules/osquery_linux_logins_non_office.py b/rules/osquery_rules/osquery_linux_logins_non_office.py index 71ce4270b..c473f8fb6 100644 --- a/rules/osquery_rules/osquery_linux_logins_non_office.py +++ b/rules/osquery_rules/osquery_linux_logins_non_office.py @@ -1,7 +1,5 @@ import ipaddress -from panther_base_helpers import deep_get - # This is only an example network, but you can set it to whatever you'd like OFFICE_NETWORKS = [ ipaddress.ip_network("192.168.1.100/32"), @@ -25,7 +23,7 @@ def rule(event): if "logged_in_users" in event.get("name"): # Only pay attention to users and not system-level accounts - if deep_get(event, "columns", "type") != "user": + if event.deep_get("columns", "type") != "user": return False elif "last" in event.get("name"): pass @@ -33,12 +31,12 @@ def rule(event): # A query we don't care about return False - host_ip = deep_get(event, "columns", "host") + host_ip = event.deep_get("columns", "host") return _login_from_non_office_network(host_ip) def title(event): - user = deep_get(event, "columns", "user", default=deep_get(event, "columns", "username")) + user = event.deep_get("columns", "user", default=event.deep_get("columns", "username")) return ( f"User [{user if user else ''}" diff --git a/rules/osquery_rules/osquery_mac_application_firewall.py b/rules/osquery_rules/osquery_mac_application_firewall.py index 2a42c5f53..c7c30d55c 100644 --- a/rules/osquery_rules/osquery_mac_application_firewall.py +++ b/rules/osquery_rules/osquery_mac_application_firewall.py @@ -1,5 +1,3 @@ -from panther_base_helpers import deep_get - QUERIES = {"pack_incident-response_alf", "pack/mac-cis/ApplicationFirewall"} @@ -14,10 +12,10 @@ def rule(event): # 0 If the firewall is disabled # 1 If the firewall is enabled with exceptions # 2 If the firewall is configured to block all incoming connections - int(deep_get(event, "columns", "global_state")) == 0 + int(event.deep_get("columns", "global_state")) == 0 or # Stealth mode is a best practice to avoid responding to unsolicited probes - int(deep_get(event, "columns", "stealth_enabled")) == 0 + int(event.deep_get("columns", "stealth_enabled")) == 0 ) diff --git a/rules/osquery_rules/osquery_mac_enable_auto_update.py b/rules/osquery_rules/osquery_mac_enable_auto_update.py index 2abe92757..3b41a1a1f 100644 --- a/rules/osquery_rules/osquery_mac_enable_auto_update.py +++ b/rules/osquery_rules/osquery_mac_enable_auto_update.py @@ -1,13 +1,10 @@ -from panther_base_helpers import deep_get - - def rule(event): return ( "SoftwareUpdate" in event.get("name", []) and event.get("action") == "added" - and deep_get(event, "columns", "domain") == "com.apple.SoftwareUpdate" - and deep_get(event, "columns", "key") == "AutomaticCheckEnabled" + and event.deep_get("columns", "domain") == "com.apple.SoftwareUpdate" + and event.deep_get("columns", "key") == "AutomaticCheckEnabled" and # Send an alert if not set to "true" - deep_get(event, "columns", "value") == "false" + event.deep_get("columns", "value") == "false" ) diff --git a/rules/osquery_rules/osquery_mac_osx_attacks_keyboard_events.py b/rules/osquery_rules/osquery_mac_osx_attacks_keyboard_events.py index b5fe9b42e..9fe7592eb 100644 --- a/rules/osquery_rules/osquery_mac_osx_attacks_keyboard_events.py +++ b/rules/osquery_rules/osquery_mac_osx_attacks_keyboard_events.py @@ -1,7 +1,5 @@ from fnmatch import fnmatch -from panther_base_helpers import deep_get - # sip protects against writing malware into the paths below. # additional apps can be added to this list based on your environments. # @@ -24,11 +22,11 @@ def rule(event): if event.get("action") != "added": return False - process_path = deep_get(event, "columns", "path", default="") + process_path = event.deep_get("columns", "path", default="") if process_path == "": return False - if deep_get(event, "columns", "name") in APPROVED_APPLICATION_NAMES: + if event.deep_get("columns", "name") in APPROVED_APPLICATION_NAMES: return False # Alert if the process is running outside any of the approved paths diff --git a/rules/osquery_rules/osquery_outdated.py b/rules/osquery_rules/osquery_outdated.py index 7e9005acf..d4f7cdce5 100644 --- a/rules/osquery_rules/osquery_outdated.py +++ b/rules/osquery_rules/osquery_outdated.py @@ -1,15 +1,13 @@ -from panther_base_helpers import deep_get - LATEST_VERSION = "5.10.2" def rule(event): return ( event.get("name") == "pack_it-compliance_osquery_info" - and deep_get(event, "columns", "version") != LATEST_VERSION + and event.deep_get("columns", "version") != LATEST_VERSION and event.get("action") == "added" ) def title(event): - return f"Osquery Version {deep_get(event, 'columns', 'version')} is Outdated" + return f"Osquery Version {event.deep_get('columns', 'version')} is Outdated" diff --git a/rules/osquery_rules/osquery_outdated_macos.py b/rules/osquery_rules/osquery_outdated_macos.py index e6e780bdf..b68937edc 100644 --- a/rules/osquery_rules/osquery_outdated_macos.py +++ b/rules/osquery_rules/osquery_outdated_macos.py @@ -1,5 +1,3 @@ -from panther_base_helpers import deep_get - SUPPORTED_VERSIONS = [ "10.15.1", "10.15.2", @@ -10,7 +8,7 @@ def rule(event): return ( event.get("name") == "pack_vuln-management_os_version" - and deep_get(event, "columns", "platform") == "darwin" - and deep_get(event, "columns", "version") not in SUPPORTED_VERSIONS + and event.deep_get("columns", "platform") == "darwin" + and event.deep_get("columns", "version") not in SUPPORTED_VERSIONS and event.get("action") == "added" ) diff --git a/rules/osquery_rules/osquery_ssh_listener.py b/rules/osquery_rules/osquery_ssh_listener.py index a5c49c681..9b5f5dad1 100644 --- a/rules/osquery_rules/osquery_ssh_listener.py +++ b/rules/osquery_rules/osquery_ssh_listener.py @@ -1,9 +1,6 @@ -from panther_base_helpers import deep_get - - def rule(event): return ( event.get("name") == "pack_incident-response_listening_ports" - and deep_get(event, "columns", "port") == "22" + and event.deep_get("columns", "port") == "22" and event.get("action") == "added" ) diff --git a/rules/osquery_rules/osquery_suspicious_cron.py b/rules/osquery_rules/osquery_suspicious_cron.py index 8f56638e7..1a9f02650 100644 --- a/rules/osquery_rules/osquery_suspicious_cron.py +++ b/rules/osquery_rules/osquery_suspicious_cron.py @@ -1,8 +1,6 @@ import shlex from fnmatch import fnmatch -from panther_base_helpers import deep_get - SUSPICIOUS_CRON_CMD_ARGS = { # Running in unexpected locations "/tmp/*", # nosec @@ -37,7 +35,7 @@ def rule(event): if "crontab" not in event.get("name"): return False - command = deep_get(event, "columns", "command") + command = event.deep_get("columns", "command") if not command: return False diff --git a/rules/panther_audit_rules/panther_detection_deleted.py b/rules/panther_audit_rules/panther_detection_deleted.py index 57452e95e..e6889538b 100644 --- a/rules/panther_audit_rules/panther_detection_deleted.py +++ b/rules/panther_audit_rules/panther_detection_deleted.py @@ -1,5 +1,3 @@ -from panther_base_helpers import deep_get - PANTHER_DETECTION_DELETE_ACTIONS = [ "DELETE_DATA_MODEL", "DELETE_DETECTION", @@ -22,9 +20,9 @@ def title(event): def alert_context(event): - detections_list = deep_get(event, "actionParams", "dynamic", "input", "detections") + detections_list = event.deep_get("actionParams", "dynamic", "input", "detections") if detections_list is None: - detections_list = deep_get(event, "actionParams", "input", "detections", default=[]) + detections_list = event.deep_get("actionParams", "input", "detections", default=[]) return { "deleted_detections_list": [x.get("id") for x in detections_list], "user": event.udm("actor_user"), diff --git a/rules/panther_audit_rules/panther_sensitive_role_created.py b/rules/panther_audit_rules/panther_sensitive_role_created.py index 682788310..e54735172 100644 --- a/rules/panther_audit_rules/panther_sensitive_role_created.py +++ b/rules/panther_audit_rules/panther_sensitive_role_created.py @@ -1,5 +1,4 @@ import panther_event_type_helpers as event_type -from panther_base_helpers import deep_get PANTHER_ADMIN_PERMISSIONS = [ "UserModify", @@ -17,9 +16,9 @@ def rule(event): if event.udm("event_type") not in PANTHER_ROLE_ACTIONS: return False - permissions = deep_get(event, "actionParams", "dynamic", "input", "permissions") + permissions = event.deep_get("actionParams", "dynamic", "input", "permissions") if permissions is None: - deep_get(event, "actionParams", "input", "permissions", default="") + event.deep_get("actionParams", "input", "permissions", default="") role_permissions = set(permissions) return ( @@ -29,9 +28,9 @@ def rule(event): def title(event): - role_name = deep_get(event, "actionParams", "dynamic", "input", "name") + role_name = event.deep_get("actionParams", "dynamic", "input", "name") if role_name is None: - role_name = deep_get(event, "actionParams", "input", "name", default="") + role_name = event.deep_get("actionParams", "input", "name", default="") return ( f"Role with Admin Permissions created by {event.udm('actor_user')}" f"Role Name: {role_name}" @@ -41,6 +40,6 @@ def title(event): def alert_context(event): return { "user": event.udm("actor_user"), - "role_name": deep_get(event, "actionParams", "name"), + "role_name": event.deep_get("actionParams", "name"), "ip": event.udm("source_ip"), } diff --git a/rules/panther_audit_rules/panther_sensitive_role_created.yml b/rules/panther_audit_rules/panther_sensitive_role_created.yml index 68979bf87..602c2dddf 100644 --- a/rules/panther_audit_rules/panther_sensitive_role_created.yml +++ b/rules/panther_audit_rules/panther_sensitive_role_created.yml @@ -175,7 +175,7 @@ Tests: "p_log_type": "Panther.Audit", "p_parse_time": "2023-02-09 21:46:53.858602089", "p_row_id": "b29dff36ad73cb77a5d7a3a816c39c2a", - "p_rule_error": '''NoneType'' object is not iterable: Panther.Sensitive.Role.py, line 20, in rule role_permissions = set(deep_get(event, "actionParams", "input", "permissions"))', + "p_rule_error": '''NoneType'' object is not iterable: Panther.Sensitive.Role.py, line 20, in rule role_permissions = set(event.deep_get("actionParams", "input", "permissions"))', "p_rule_id": "Panther.Sensitive.Role", "p_rule_reports": { "MITRE ATT&CK": ["TA0003:T1098"] }, "p_rule_severity": "HIGH", diff --git a/rules/panther_audit_rules/panther_user_modified.py b/rules/panther_audit_rules/panther_user_modified.py index 3c0d191a1..a343d911b 100644 --- a/rules/panther_audit_rules/panther_user_modified.py +++ b/rules/panther_audit_rules/panther_user_modified.py @@ -1,5 +1,4 @@ import panther_event_type_helpers as event_type -from panther_base_helpers import deep_get PANTHER_USER_ACTIONS = [ event_type.USER_ACCOUNT_MODIFIED, @@ -13,18 +12,18 @@ def rule(event): def title(event): - change_target = deep_get(event, "actionParams", "dynamic", "input", "email") + change_target = event.deep_get("actionParams", "dynamic", "input", "email") if change_target is None: - change_target = deep_get(event, "actionParams", "input", "email") + change_target = event.deep_get("actionParams", "input", "email") if change_target is None: - change_target = deep_get(event, "actionParams", "email", default="") + change_target = event.deep_get("actionParams", "email", default="") return f"The user account " f"{change_target} " f"was modified by {event.udm('actor_user')}" def alert_context(event): - change_target = deep_get(event, "actionParams", "dynamic", "input", "email") + change_target = event.deep_get("actionParams", "dynamic", "input", "email") if change_target is None: - change_target = deep_get(event, "actionParams", "input", "email", default="") + change_target = event.deep_get("actionParams", "input", "email", default="") return { "user": event.udm("actor_user"), "change_target": change_target, diff --git a/rules/sentinelone_rules/sentinelone_alert_passthrough.py b/rules/sentinelone_rules/sentinelone_alert_passthrough.py index 8ae2fe0cf..78bedda3e 100644 --- a/rules/sentinelone_rules/sentinelone_alert_passthrough.py +++ b/rules/sentinelone_rules/sentinelone_alert_passthrough.py @@ -1,5 +1,3 @@ -from panther_base_helpers import deep_get - SENTINELONE_SEVERITY = { "E_LOW": "LOW", "E_MEDIUM": "MEDIUM", @@ -16,8 +14,8 @@ def rule(event): def title(event): return ( "SentinelOne " - f"[{SENTINELONE_SEVERITY.get(deep_get(event,'data', 'severity', default=''))}] " - f"Alert - [{deep_get(event, 'data', 'rulename')}]" + f"[{SENTINELONE_SEVERITY.get(event.deep_get('data', 'severity', default=''))}] " + f"Alert - [{event.deep_get('data', 'rulename')}]" ) @@ -26,7 +24,7 @@ def dedup(event): def severity(event): - return SENTINELONE_SEVERITY.get(deep_get(event, "data", "severity", default=""), "MEDIUM") + return SENTINELONE_SEVERITY.get(event.deep_get("data", "severity", default=""), "MEDIUM") def alert_context(event): diff --git a/rules/sentinelone_rules/sentinelone_threats.py b/rules/sentinelone_rules/sentinelone_threats.py index d42792d44..0bc3aa875 100644 --- a/rules/sentinelone_rules/sentinelone_threats.py +++ b/rules/sentinelone_rules/sentinelone_threats.py @@ -1,5 +1,3 @@ -from panther_base_helpers import deep_get - NEW_THREAT_ACTIVITYTYPES = [ 19, # New Malicious Threat Not Mitigated 4108, # New Malicious Threat Not Mitigated @@ -14,9 +12,9 @@ def rule(event): def title(event): return ( - f"SentinelOne - [{deep_get(event, 'data', 'confidencelevel', default='')}] level " - f"[{deep_get(event, 'data', 'threatclassification' ,default='')}] threat detected from " - f"[{deep_get(event, 'data', 'threatclassificationsource', default= '')}]." + f"SentinelOne - [{event.deep_get('data', 'confidencelevel', default='')}] level " + f"[{event.deep_get('data', 'threatclassification' ,default='')}] threat detected from " + f"[{event.deep_get('data', 'threatclassificationsource', default= '')}]." ) @@ -25,7 +23,7 @@ def dedup(event): def severity(event): - if deep_get(event, "data", "confidencelevel", default="") == "malicious": + if event.deep_get("data", "confidencelevel", default="") == "malicious": return "CRITICAL" return "HIGH" diff --git a/rules/slack_rules/slack_app_access_expanded.py b/rules/slack_rules/slack_app_access_expanded.py index 0003f5ddb..c93d9dd01 100644 --- a/rules/slack_rules/slack_app_access_expanded.py +++ b/rules/slack_rules/slack_app_access_expanded.py @@ -1,4 +1,4 @@ -from panther_base_helpers import deep_get, slack_alert_context +from panther_base_helpers import slack_alert_context ACCESS_EXPANDED_ACTIONS = [ "app_scopes_expanded", @@ -14,8 +14,8 @@ def rule(event): def title(event): return ( - f"Slack App [{deep_get(event, 'entity', 'app', 'name')}] " - f"Access Expanded by [{deep_get(event, 'actor', 'user', 'name')}]" + f"Slack App [{event.deep_get('entity', 'app', 'name')}] " + f"Access Expanded by [{event.deep_get('actor', 'user', 'name')}]" ) @@ -23,8 +23,8 @@ def alert_context(event): context = slack_alert_context(event) # Diff previous and new scopes - new_scopes = deep_get(event, "details", "new_scopes", default=[]) - prv_scopes = deep_get(event, "details", "previous_scopes", default=[]) + new_scopes = event.deep_get("details", "new_scopes", default=[]) + prv_scopes = event.deep_get("details", "previous_scopes", default=[]) context["scopes_added"] = [x for x in new_scopes if x not in prv_scopes] context["scoped_removed"] = [x for x in prv_scopes if x not in new_scopes] @@ -35,14 +35,14 @@ def alert_context(event): def severity(event): # Used to escalate to High/Critical if the app is granted admin privileges # May want to escalate to "Critical" depending on security posture - if "admin" in deep_get(event, "entity", "app", "scopes", default=[]): + if "admin" in event.deep_get("entity", "app", "scopes", default=[]): return "High" # Fallback method in case the admin scope is not directly mentioned in entity for whatever - if "admin" in deep_get(event, "details", "new_scope", default=[]): + if "admin" in event.deep_get("details", "new_scope", default=[]): return "High" - if "admin" in deep_get(event, "details", "bot_scopes", default=[]): + if "admin" in event.deep_get("details", "bot_scopes", default=[]): return "High" return "Medium" diff --git a/rules/slack_rules/slack_app_added.py b/rules/slack_rules/slack_app_added.py index ad006ffe8..d57357ff6 100644 --- a/rules/slack_rules/slack_app_added.py +++ b/rules/slack_rules/slack_app_added.py @@ -1,4 +1,4 @@ -from panther_base_helpers import deep_get, slack_alert_context +from panther_base_helpers import slack_alert_context APP_ADDED_ACTIONS = [ "app_approved", @@ -13,14 +13,14 @@ def rule(event): def title(event): return ( - f"Slack App [{deep_get(event, 'entity', 'app', 'name')}] " - f"Added by [{deep_get(event, 'actor', 'user', 'name')}]" + f"Slack App [{event.deep_get('entity', 'app', 'name')}] " + f"Added by [{event.deep_get('actor', 'user', 'name')}]" ) def alert_context(event): context = slack_alert_context(event) - context["scopes"] = deep_get(event, "entity", "scopes") + context["scopes"] = event.deep_get("entity", "scopes") return context @@ -28,14 +28,14 @@ def alert_context(event): def severity(event): # Used to escalate to High/Critical if the app is granted admin privileges # May want to escalate to "Critical" depending on security posture - if "admin" in deep_get(event, "entity", "app", "scopes", default=[]): + if "admin" in event.deep_get("entity", "app", "scopes", default=[]): return "High" # Fallback method in case the admin scope is not directly mentioned in entity for whatever - if "admin" in deep_get(event, "details", "new_scope", default=[]): + if "admin" in event.deep_get("details", "new_scope", default=[]): return "High" - if "admin" in deep_get(event, "details", "bot_scopes", default=[]): + if "admin" in event.deep_get("details", "bot_scopes", default=[]): return "High" return "Medium" diff --git a/rules/slack_rules/slack_app_removed.py b/rules/slack_rules/slack_app_removed.py index effe84cad..7583404f9 100644 --- a/rules/slack_rules/slack_app_removed.py +++ b/rules/slack_rules/slack_app_removed.py @@ -1,4 +1,4 @@ -from panther_base_helpers import deep_get, slack_alert_context +from panther_base_helpers import slack_alert_context APP_REMOVED_ACTIONS = [ "app_restricted", @@ -13,8 +13,8 @@ def rule(event): def title(event): return ( - f"Slack App [{deep_get(event, 'entity', 'app', 'name')}] " - f"Removed by [{deep_get(event, 'actor', 'user', 'name')}]" + f"Slack App [{event.deep_get('entity', 'app', 'name')}] " + f"Removed by [{event.deep_get('actor', 'user', 'name')}]" ) diff --git a/rules/slack_rules/slack_application_dos.py b/rules/slack_rules/slack_application_dos.py index 54add00f0..ca37d82a2 100644 --- a/rules/slack_rules/slack_application_dos.py +++ b/rules/slack_rules/slack_application_dos.py @@ -1,4 +1,4 @@ -from panther_base_helpers import deep_get, slack_alert_context +from panther_base_helpers import slack_alert_context DENIAL_OF_SERVICE_ACTIONS = [ "bulk_session_reset_by_admin", @@ -16,7 +16,7 @@ def rule(event): def dedup(event): - return f"Slack.AuditLogs.ApplicationDoS{deep_get(event, 'entity', 'user', 'name')}" + return f"Slack.AuditLogs.ApplicationDoS{event.deep_get('entity', 'user', 'name')}" def alert_context(event): diff --git a/rules/slack_rules/slack_legal_hold_policy_modified.py b/rules/slack_rules/slack_legal_hold_policy_modified.py index 26fc66eb3..afb4f401f 100644 --- a/rules/slack_rules/slack_legal_hold_policy_modified.py +++ b/rules/slack_rules/slack_legal_hold_policy_modified.py @@ -1,4 +1,4 @@ -from panther_base_helpers import deep_get, slack_alert_context +from panther_base_helpers import slack_alert_context LEGAL_HOLD_POLICY_ACTIONS = { "legal_hold_policy_entities_deleted": "Slack Legal Hold Policy Entities Deleted", @@ -17,7 +17,7 @@ def title(event): if event.get("action") == "legal_hold_policy_updated": return ( f"Slack Legal Hold Updated " - f"[{deep_get(event, 'details', 'old_legal_hold_policy', 'name')}]" + f"[{event.deep_get('details', 'old_legal_hold_policy', 'name')}]" ) if event.get("action") in LEGAL_HOLD_POLICY_ACTIONS: return LEGAL_HOLD_POLICY_ACTIONS.get(event.get("action")) diff --git a/rules/slack_rules/slack_privilege_changed_to_user.py b/rules/slack_rules/slack_privilege_changed_to_user.py index 8cb636417..44e52a976 100644 --- a/rules/slack_rules/slack_privilege_changed_to_user.py +++ b/rules/slack_rules/slack_privilege_changed_to_user.py @@ -1,4 +1,4 @@ -from panther_base_helpers import deep_get, slack_alert_context +from panther_base_helpers import slack_alert_context def rule(event): @@ -6,8 +6,8 @@ def rule(event): def title(event): - username = deep_get(event, "entity", "user", "name", default="") - email = deep_get(event, "entity", "user", "email", default="") + username = event.deep_get("entity", "user", "name", default="") + email = event.deep_get("entity", "user", "email", default="") return f"Slack {username}'s ({email}) role changed to User" diff --git a/rules/slack_rules/slack_user_privilege_escalation.py b/rules/slack_rules/slack_user_privilege_escalation.py index a810df427..09ae231b4 100644 --- a/rules/slack_rules/slack_user_privilege_escalation.py +++ b/rules/slack_rules/slack_user_privilege_escalation.py @@ -1,4 +1,4 @@ -from panther_base_helpers import deep_get, slack_alert_context +from panther_base_helpers import slack_alert_context USER_PRIV_ESC_ACTIONS = { "owner_transferred": "Slack Owner Transferred", @@ -14,11 +14,11 @@ def rule(event): def title(event): # This is the user taking the action. - actor_username = deep_get(event, "actor", "user", "name", default="") - actor_email = deep_get(event, "actor", "user", "email", default="") + actor_username = event.deep_get("actor", "user", "name", default="") + actor_email = event.deep_get("actor", "user", "email", default="") # This is the user the action is taken on. - entity_username = deep_get(event, "entity", "user", "name", default="") - entity_email = deep_get(event, "entity", "user", "email", default="") + entity_username = event.deep_get("entity", "user", "name", default="") + entity_email = event.deep_get("entity", "user", "email", default="") action = event.get("action") if action == "owner_transferred": return f"{USER_PRIV_ESC_ACTIONS[action]} from {actor_username} ({actor_email})" diff --git a/rules/standard_rules/impossible_travel_login.py b/rules/standard_rules/impossible_travel_login.py index 1850307c3..7233af78b 100644 --- a/rules/standard_rules/impossible_travel_login.py +++ b/rules/standard_rules/impossible_travel_login.py @@ -19,7 +19,7 @@ def gen_key(event): The data_model needs to answer to "actor_user" """ - rule_name = deep_get(event, "p_source_label") + rule_name = event.get("p_source_label") actor = event.udm("actor_user") if None in [rule_name, actor]: return None @@ -45,7 +45,7 @@ def rule(event): if event.udm("event_type") != event_type.SUCCESSFUL_LOGIN: return False - p_event_datetime = resolve_timestamp_string(deep_get(event, "p_event_time")) + p_event_datetime = resolve_timestamp_string(event.deep_get("p_event_time")) if p_event_datetime is None: # we couldn't go from p_event_time to a datetime object # we need to do this in order to make later time comparisons generic @@ -165,7 +165,7 @@ def rule(event): def title(event): # - log_source = deep_get(event, "p_source_label", default="") + log_source = event.deep_get("p_source_label", default="") old_city = deep_get(EVENT_CITY_TRACKING, "previous", "city", default="") new_city = deep_get(EVENT_CITY_TRACKING, "current", "city", default="") speed = deep_get(EVENT_CITY_TRACKING, "speed", default="") diff --git a/rules/tailscale_rules/tailscale_https_disabled.py b/rules/tailscale_rules/tailscale_https_disabled.py index a3361e569..67074d6e4 100644 --- a/rules/tailscale_rules/tailscale_https_disabled.py +++ b/rules/tailscale_rules/tailscale_https_disabled.py @@ -1,14 +1,13 @@ from global_filter_tailscale import filter_include_event -from panther_base_helpers import deep_get from panther_tailscale_helpers import is_tailscale_admin_console_event, tailscale_alert_context def rule(event): if not filter_include_event(event): return False - action = deep_get(event, "event", "action", default="") - target_property = deep_get( - event, "event", "target", "property", default="" + action = event.deep_get("event", "action", default="") + target_property = event.deep_get( + "event", "target", "property", default="" ) return all( [ @@ -20,8 +19,8 @@ def rule(event): def title(event): - user = deep_get(event, "event", "actor", "loginName", default="") - target_id = deep_get(event, "event", "target", "id", default="") + user = event.deep_get("event", "actor", "loginName", default="") + target_id = event.deep_get("event", "target", "id", default="") return ( f"Tailscale user [{user}] disabled HTTPS for " f"[{target_id}] in your organization’s tenant." diff --git a/rules/tailscale_rules/tailscale_machine_approval_requirements_disabled.py b/rules/tailscale_rules/tailscale_machine_approval_requirements_disabled.py index 64d390f29..6ec015bcf 100644 --- a/rules/tailscale_rules/tailscale_machine_approval_requirements_disabled.py +++ b/rules/tailscale_rules/tailscale_machine_approval_requirements_disabled.py @@ -1,14 +1,13 @@ from global_filter_tailscale import filter_include_event -from panther_base_helpers import deep_get from panther_tailscale_helpers import is_tailscale_admin_console_event, tailscale_alert_context def rule(event): if not filter_include_event(event): return False - action = deep_get(event, "event", "action", default="") - target_property = deep_get( - event, "event", "target", "property", default="" + action = event.deep_get("event", "action", default="") + target_property = event.deep_get( + "event", "target", "property", default="" ) return all( [ @@ -20,7 +19,7 @@ def rule(event): def title(event): - user = deep_get(event, "event", "actor", "loginName", default="") + user = event.deep_get("event", "actor", "loginName", default="") return ( f"Tailscale user [{user}] disabled device approval requirements " f"for new devices accessing your organization’s network." diff --git a/rules/tailscale_rules/tailscale_magicdns_disabled.py b/rules/tailscale_rules/tailscale_magicdns_disabled.py index ad29e9aaf..4ee598b6d 100644 --- a/rules/tailscale_rules/tailscale_magicdns_disabled.py +++ b/rules/tailscale_rules/tailscale_magicdns_disabled.py @@ -1,14 +1,13 @@ from global_filter_tailscale import filter_include_event -from panther_base_helpers import deep_get from panther_tailscale_helpers import is_tailscale_admin_console_event, tailscale_alert_context def rule(event): if not filter_include_event(event): return False - action = deep_get(event, "event", "action", default="") - target_property = deep_get( - event, "event", "target", "property", default="" + action = event.deep_get("event", "action", default="") + target_property = event.deep_get( + "event", "target", "property", default="" ) return all( [ @@ -20,8 +19,8 @@ def rule(event): def title(event): - user = deep_get(event, "event", "actor", "loginName", default="") - target_id = deep_get(event, "event", "target", "id", default="") + user = event.deep_get("event", "actor", "loginName", default="") + target_id = event.deep_get("event", "target", "id", default="") return ( f"Tailscale user [{user}] disabled Magic DNS for " f"[{target_id}] in your organization’s tenant." diff --git a/rules/tines_rules/tines_actions_disabled_changes.py b/rules/tines_rules/tines_actions_disabled_changes.py index bc19bb6d5..860ede58f 100644 --- a/rules/tines_rules/tines_actions_disabled_changes.py +++ b/rules/tines_rules/tines_actions_disabled_changes.py @@ -1,5 +1,4 @@ from global_filter_tines import filter_include_event -from panther_base_helpers import deep_get from panther_tines_helpers import tines_alert_context ACTIONS = ["ActionsDisabledChange"] @@ -8,13 +7,13 @@ def rule(event): if not filter_include_event(event): return False - action = deep_get(event, "operation_name", default="") + action = event.deep_get("operation_name", default="") return action in ACTIONS def title(event): - action = deep_get(event, "operation_name", default="") - actor = deep_get(event, "user_email", default="") + action = event.deep_get("operation_name", default="") + actor = event.deep_get("user_email", default="") return f"Tines: {action} " f"by {actor}" diff --git a/rules/tines_rules/tines_custom_ca.py b/rules/tines_rules/tines_custom_ca.py index bdd2ead46..f9397ef87 100644 --- a/rules/tines_rules/tines_custom_ca.py +++ b/rules/tines_rules/tines_custom_ca.py @@ -1,5 +1,4 @@ from global_filter_tines import filter_include_event -from panther_base_helpers import deep_get from panther_tines_helpers import tines_alert_context ACTIONS = [ @@ -10,13 +9,13 @@ def rule(event): if not filter_include_event(event): return False - action = deep_get(event, "operation_name", default="") + action = event.deep_get("operation_name", default="") return action in ACTIONS def title(event): - action = deep_get(event, "operation_name", default="") - return f"Tines: [{action}] " f"by [{deep_get(event, 'user_email', default='')}]" + action = event.deep_get("operation_name", default="") + return f"Tines: [{action}] " f"by [{event.deep_get('user_email', default='')}]" def alert_context(event): @@ -25,7 +24,7 @@ def alert_context(event): def dedup(event): return ( - f"{deep_get(event, 'user_id', default='')}" + f"{event.deep_get('user_id', default='')}" "_" - f"{deep_get(event, 'operation_name', default='')}" + f"{event.deep_get('operation_name', default='')}" ) diff --git a/rules/tines_rules/tines_enqueued_retrying_job_deletion.py b/rules/tines_rules/tines_enqueued_retrying_job_deletion.py index 083dd3896..21f43d0b7 100644 --- a/rules/tines_rules/tines_enqueued_retrying_job_deletion.py +++ b/rules/tines_rules/tines_enqueued_retrying_job_deletion.py @@ -1,5 +1,4 @@ from global_filter_tines import filter_include_event -from panther_base_helpers import deep_get from panther_tines_helpers import tines_alert_context @@ -7,16 +6,16 @@ def rule(event): if not filter_include_event(event): return False - return deep_get(event, "operation_name", default="") in [ + return event.deep_get("operation_name", default="") in [ "JobsQueuedDeletion", "JobsRetryingDeletion", ] def title(event): - operation = deep_get(event, "operation_name", default="") - user = deep_get(event, "user_email", default="") - tines_instance = deep_get(event, "p_source_label", default="") + operation = event.deep_get("operation_name", default="") + user = event.deep_get("user_email", default="") + tines_instance = event.deep_get("p_source_label", default="") return f"Tines [{operation}] performed by [{user}] on [{tines_instance}]." diff --git a/rules/tines_rules/tines_global_resource_destruction.py b/rules/tines_rules/tines_global_resource_destruction.py index e60e23e33..0049d8b37 100644 --- a/rules/tines_rules/tines_global_resource_destruction.py +++ b/rules/tines_rules/tines_global_resource_destruction.py @@ -1,5 +1,4 @@ from global_filter_tines import filter_include_event -from panther_base_helpers import deep_get from panther_tines_helpers import tines_alert_context @@ -8,15 +7,15 @@ def rule(event): return False return ( - deep_get(event, "operation_name", default="") + event.deep_get("operation_name", default="") == "GlobalResourceDestruction" ) def title(event): - operation = deep_get(event, "operation_name", default="") - user = deep_get(event, "user_email", default="") - tines_instance = deep_get(event, "p_source_label", default="") + operation = event.deep_get("operation_name", default="") + user = event.deep_get("user_email", default="") + tines_instance = event.deep_get("p_source_label", default="") return f"Tines [{operation}] performed by [{user}] on [{tines_instance}]." diff --git a/rules/tines_rules/tines_sso_settings.py b/rules/tines_rules/tines_sso_settings.py index c3f19168b..382a7df37 100644 --- a/rules/tines_rules/tines_sso_settings.py +++ b/rules/tines_rules/tines_sso_settings.py @@ -1,5 +1,4 @@ from global_filter_tines import filter_include_event -from panther_base_helpers import deep_get from panther_tines_helpers import tines_alert_context ACTIONS = [ @@ -12,15 +11,15 @@ def rule(event): if not filter_include_event(event): return False - action = deep_get(event, "operation_name", default="") + action = event.deep_get("operation_name", default="") return action in ACTIONS def title(event): - action = deep_get(event, "operation_name", default="") + action = event.deep_get("operation_name", default="") return ( f"Tines: [{action}] Setting " - f"changed by [{deep_get(event, 'user_email', default='')}]" + f"changed by [{event.deep_get('user_email', default='')}]" ) @@ -30,7 +29,7 @@ def alert_context(event): def dedup(event): return ( - f"{deep_get(event, 'user_id', default='')}" + f"{event.deep_get('user_id', default='')}" "_" - f"{deep_get(event, 'operation_name', default='')}" + f"{event.deep_get('operation_name', default='')}" ) diff --git a/rules/tines_rules/tines_story_items_destruction.py b/rules/tines_rules/tines_story_items_destruction.py index 73685ab45..386982898 100644 --- a/rules/tines_rules/tines_story_items_destruction.py +++ b/rules/tines_rules/tines_story_items_destruction.py @@ -1,5 +1,4 @@ from global_filter_tines import filter_include_event -from panther_base_helpers import deep_get from panther_tines_helpers import tines_alert_context @@ -8,14 +7,14 @@ def rule(event): return False return ( - deep_get(event, "operation_name", default="") == "StoryItemsDestruction" + event.deep_get("operation_name", default="") == "StoryItemsDestruction" ) def title(event): - operation = deep_get(event, "operation_name", default="") - user = deep_get(event, "user_email", default="") - tines_instance = deep_get(event, "p_source_label", default="") + operation = event.deep_get("operation_name", default="") + user = event.deep_get("user_email", default="") + tines_instance = event.deep_get("p_source_label", default="") return f"Tines [{operation}] performed by [{user}] on [{tines_instance}]." diff --git a/rules/tines_rules/tines_story_jobs_clearance.py b/rules/tines_rules/tines_story_jobs_clearance.py index 3c93ba39d..6b12ca339 100644 --- a/rules/tines_rules/tines_story_jobs_clearance.py +++ b/rules/tines_rules/tines_story_jobs_clearance.py @@ -1,5 +1,4 @@ from global_filter_tines import filter_include_event -from panther_base_helpers import deep_get from panther_tines_helpers import tines_alert_context @@ -7,13 +6,13 @@ def rule(event): if not filter_include_event(event): return False - return deep_get(event, "operation_name", default="") == "StoryJobsClearance" + return event.deep_get("operation_name", default="") == "StoryJobsClearance" def title(event): - operation = deep_get(event, "operation_name", default="") - user = deep_get(event, "user_email", default="") - tines_instance = deep_get(event, "p_source_label", default="") + operation = event.deep_get("operation_name", default="") + user = event.deep_get("user_email", default="") + tines_instance = event.deep_get("p_source_label", default="") return f"Tines: [{operation}] performed by [{user}] on [{tines_instance}]." diff --git a/rules/tines_rules/tines_team_destruction.py b/rules/tines_rules/tines_team_destruction.py index 7eb30e71e..6cb19346a 100644 --- a/rules/tines_rules/tines_team_destruction.py +++ b/rules/tines_rules/tines_team_destruction.py @@ -1,5 +1,4 @@ from global_filter_tines import filter_include_event -from panther_base_helpers import deep_get from panther_tines_helpers import tines_alert_context @@ -7,13 +6,13 @@ def rule(event): if not filter_include_event(event): return False - return deep_get(event, "operation_name", default="") == "TeamDestruction" + return event.deep_get("operation_name", default="") == "TeamDestruction" def title(event): - operation = deep_get(event, "operation_name", default="") - user = deep_get(event, "user_email", default="") - tines_instance = deep_get(event, "p_source_label", default="") + operation = event.deep_get("operation_name", default="") + user = event.deep_get("user_email", default="") + tines_instance = event.deep_get("p_source_label", default="") return f"Tines [{operation}] performed by [{user}] on [{tines_instance}]." diff --git a/rules/tines_rules/tines_tenant_authtoken.py b/rules/tines_rules/tines_tenant_authtoken.py index 87606bd17..25b6f3978 100644 --- a/rules/tines_rules/tines_tenant_authtoken.py +++ b/rules/tines_rules/tines_tenant_authtoken.py @@ -1,5 +1,4 @@ from global_filter_tines import filter_include_event -from panther_base_helpers import deep_get from panther_tines_helpers import tines_alert_context ACTIONS = [ @@ -14,30 +13,30 @@ def rule(event): if not filter_include_event(event): return False - action = deep_get(event, "operation_name", default="") - is_tenant_token = deep_get(event, "inputs", "inputs", "isServiceToken", default=False) + action = event.deep_get("operation_name", default="") + is_tenant_token = event.deep_get("inputs", "inputs", "isServiceToken", default=False) return all([action in ACTIONS, is_tenant_token]) def title(event): - action = deep_get(event, "operation_name", default="") + action = event.deep_get("operation_name", default="") return ( f"Tines: Tenant [{action}] " - f"by [{deep_get(event, 'user_email', default='')}]" + f"by [{event.deep_get('user_email', default='')}]" ) def alert_context(event): a_c = tines_alert_context(event) - a_c["token_name"] = deep_get(event, "inputs", "inputs", "name", default="") + a_c["token_name"] = event.deep_get("inputs", "inputs", "name", default="") return a_c def dedup(event): return ( - f"{deep_get(event, 'user_id', default='')}" + f"{event.deep_get('user_id', default='')}" "_" - f"{deep_get(event, 'operation_name', default='')}" + f"{event.deep_get('operation_name', default='')}" "_" - f"{deep_get(event, 'inputs', 'inputs', 'name', default='')}" + f"{event.deep_get('inputs', 'inputs', 'name', default='')}" ) diff --git a/templates/example_rule.py b/templates/example_rule.py index 8584fb385..efc28cfcd 100644 --- a/templates/example_rule.py +++ b/templates/example_rule.py @@ -1,4 +1,4 @@ -from panther_base_helpers import deep_get, pattern_match +from panther_base_helpers import pattern_match ## Required @@ -6,7 +6,7 @@ # The logic to determine if an alert should send. # return True = Alert, False = Do not Alert def rule(event): - return event.get("field") == "value" and deep_get(event, "field", "nestedValue") + return event.get("field") == "value" and event.deep_get("field", "nestedValue") ## Optional Functions From 272f36bcf9d2fd7d8a119a4464faa809335a27a1 Mon Sep 17 00:00:00 2001 From: Ben Airey Date: Wed, 2 Oct 2024 12:58:04 -0500 Subject: [PATCH 2/4] fixed global helper unit tests --- global_helpers/global_helpers_test.py | 101 +++++++++++++------------- 1 file changed, 51 insertions(+), 50 deletions(-) diff --git a/global_helpers/global_helpers_test.py b/global_helpers/global_helpers_test.py index dba629cb5..3e4d93088 100755 --- a/global_helpers/global_helpers_test.py +++ b/global_helpers/global_helpers_test.py @@ -10,6 +10,7 @@ import sys import unittest +from panther_core.enriched_event import PantherEvent from panther_core.immutable import ImmutableCaseInsensitiveDict, ImmutableList # pipenv run does the right thing, but IDE based debuggers may fail to import @@ -38,7 +39,7 @@ class TestEksPantherObjRef(unittest.TestCase): def setUp(self): # pylint: disable=C0301 - self.event = ImmutableCaseInsensitiveDict( + self.event = PantherEvent( { "annotations": { "authorization.k8s.io/decision": "allow", @@ -110,7 +111,7 @@ def test_all_missing_event(self): del temp_event["sourceIPs"] del temp_event["verb"] del temp_event["p_source_label"] - temp_event = ImmutableCaseInsensitiveDict(temp_event) + temp_event = PantherEvent(temp_event) response = p_b_h.eks_panther_obj_ref(temp_event) self.assertEqual(response.get("actor", ""), "") self.assertEqual(response.get("object", ""), "") @@ -124,7 +125,7 @@ def test_all_missing_event(self): def test_missing_subresource_event(self): temp_event = self.event.to_dict() del temp_event["objectRef"]["subresource"] - temp_event = ImmutableCaseInsensitiveDict(temp_event) + temp_event = PantherEvent(temp_event) response = p_b_h.eks_panther_obj_ref(temp_event) self.assertEqual(response.get("resource", ""), "pods") @@ -203,12 +204,12 @@ def test_additional_details_str_list_json(self): class TestTorExitNodes(unittest.TestCase): def setUp(self): - self.event = ImmutableCaseInsensitiveDict( + self.event = PantherEvent( {"p_enrichment": {"tor_exit_nodes": {"foo": {"ip": "1.2.3.4"}, "p_match": "1.2.3.4"}}} ) # match against array field - self.event_list = ImmutableCaseInsensitiveDict( + self.event_list = PantherEvent( { "p_enrichment": { "tor_exit_nodes": { @@ -223,7 +224,7 @@ def setUp(self): def test_ip_address_not_found(self): """Should not find anything""" - tor_exit_nodes = p_tor_h.TorExitNodes({}) + tor_exit_nodes = p_tor_h.TorExitNodes(PantherEvent({})) ip_address = tor_exit_nodes.ip_address("foo") self.assertEqual(ip_address, None) self.assertEqual(tor_exit_nodes.has_exit_nodes(), False) @@ -284,7 +285,7 @@ def test_context(self): class TestGreyNoiseBasic(unittest.TestCase): def setUp(self): - self.event = ImmutableCaseInsensitiveDict( + self.event = PantherEvent( { "p_enrichment": { "greynoise_noise_basic": { @@ -306,7 +307,7 @@ def test_greynoise_object(self): # Ensure that noise.lut_matches is None if there is no enrichment # some users want to test if any greynoise enrichment exists self.assertIsNotNone(noise.lut_matches) - noise_none = p_greynoise_h.GetGreyNoiseObject({}) + noise_none = p_greynoise_h.GetGreyNoiseObject(PantherEvent({})) self.assertIsNone(noise_none.lut_matches) def test_greynoise_severity(self): @@ -316,12 +317,12 @@ def test_greynoise_severity(self): def test_subscription_level(self): """Should be basic""" - noise = p_greynoise_h.GreyNoiseBasic({}) + noise = p_greynoise_h.GreyNoiseBasic(PantherEvent({})) self.assertEqual(noise.subscription_level(), "basic") def test_ip_address_not_found(self): """Should not find anything""" - noise = p_greynoise_h.GreyNoiseBasic({}) + noise = p_greynoise_h.GreyNoiseBasic(PantherEvent({})) ip_address = noise.ip_address("foo") self.assertEqual(ip_address, None) @@ -367,7 +368,7 @@ def test_context(self): # pylint: disable=too-many-public-methods class TestGreyNoiseAdvanced(unittest.TestCase): def setUp(self): - self.event = ImmutableCaseInsensitiveDict( + self.event = PantherEvent( { "p_enrichment": { "greynoise_noise_advanced": { @@ -409,7 +410,7 @@ def setUp(self): } ) - self.event_list = ImmutableCaseInsensitiveDict( + self.event_list = PantherEvent( { "p_enrichment": { "greynoise_noise_advanced": { @@ -495,12 +496,12 @@ def test_greynoise_severity_list(self): def test_subscription_level(self): """Should be advanced""" - noise = p_greynoise_h.GreyNoiseAdvanced({}) + noise = p_greynoise_h.GreyNoiseAdvanced(PantherEvent({})) self.assertEqual(noise.subscription_level(), "advanced") def test_ip_address_not_found(self): """Should not find anything""" - noise = p_greynoise_h.GreyNoiseAdvanced({}) + noise = p_greynoise_h.GreyNoiseAdvanced(PantherEvent({})) ip_address = noise.ip_address("foo") self.assertEqual(ip_address, None) @@ -712,7 +713,7 @@ def test_context(self): class TestRIOTBasic(unittest.TestCase): def setUp(self): - self.event = ImmutableCaseInsensitiveDict( + self.event = PantherEvent( { "p_enrichment": { "greynoise_riot_basic": { @@ -734,7 +735,7 @@ def test_greynoise_object(self): def test_subscription_level(self): """Should be basic""" - riot = p_greynoise_h.GreyNoiseRIOTBasic({}) + riot = p_greynoise_h.GreyNoiseRIOTBasic(PantherEvent({})) self.assertEqual(riot.subscription_level(), "basic") def test_greynoise_severity(self): @@ -789,7 +790,7 @@ def test_context(self): class TestRIOTAdvanced(unittest.TestCase): def setUp(self): - self.event = ImmutableCaseInsensitiveDict( + self.event = PantherEvent( { "p_enrichment": { "greynoise_riot_advanced": { @@ -812,7 +813,7 @@ def setUp(self): ) # for testing array matches - self.event_list = ImmutableCaseInsensitiveDict( + self.event_list = PantherEvent( { "p_enrichment": { "greynoise_riot_advanced": { @@ -856,7 +857,7 @@ def test_greynoise_object(self): def test_subscription_level(self): """Should be advanced""" - riot = p_greynoise_h.GreyNoiseRIOTAdvanced({}) + riot = p_greynoise_h.GreyNoiseRIOTAdvanced(PantherEvent({})) self.assertEqual(riot.subscription_level(), "advanced") def test_greynoise_severity(self): @@ -962,7 +963,7 @@ def test_context(self): class TestIpInfoHelpersLocation(unittest.TestCase): def setUp(self): self.match_field = "clientIp" - self.event = ImmutableCaseInsensitiveDict( + self.event = PantherEvent( { "p_enrichment": { p_i_h.IPINFO_LOCATION_LUT_NAME: { @@ -1035,7 +1036,7 @@ def test_context(self): class TestIpInfoHelpersASN(unittest.TestCase): def setUp(self): self.match_field = "clientIp" - self.event = ImmutableCaseInsensitiveDict( + self.event = PantherEvent( { "p_enrichment": { p_i_h.IPINFO_ASN_LUT_NAME: { @@ -1120,7 +1121,7 @@ def test_is_entirely_different_type(self): class TestGetCrowdstrikeField(unittest.TestCase): def setUp(self): - self.input = ImmutableCaseInsensitiveDict( + self.input = PantherEvent( { "cid": "something", "aid": "else", @@ -1152,7 +1153,7 @@ def test_input_key_can_be_found_in_unknown(self): def test_precedence(self): temp_event = self.input.to_dict() temp_event["event"]["field"] = "found" - temp_event = ImmutableCaseInsensitiveDict(temp_event) + temp_event = PantherEvent(temp_event) response = p_b_h.get_crowdstrike_field(temp_event, "field") self.assertEqual(response, "found") @@ -1160,7 +1161,7 @@ def test_precedence(self): class TestIpInfoHelpersPrivacy(unittest.TestCase): def setUp(self): self.match_field = "clientIp" - self.event = ImmutableCaseInsensitiveDict( + self.event = PantherEvent( { "p_enrichment": { p_i_h.IPINFO_PRIVACY_LUT_NAME: { @@ -1221,7 +1222,7 @@ def test_context(self): class TestGeoInfoFromIP(unittest.TestCase): def setUp(self): self.match_field = "clientIp" - self.event = ImmutableCaseInsensitiveDict( + self.event = PantherEvent( { "p_enrichment": { p_i_h.IPINFO_ASN_LUT_NAME: { @@ -1267,7 +1268,7 @@ def test_geoinfo(self): self.assertEqual(expected, geoinfo) def test_ipinfo_not_enabled_exception(self): - event = ImmutableCaseInsensitiveDict({"p_enrichment": {}}) + event = PantherEvent({"p_enrichment": {}}) with self.assertRaises(p_i_h.PantherIPInfoException) as exc: p_i_h.geoinfo_from_ip(event, "fake_field") @@ -1523,7 +1524,7 @@ def test_deep_walk_manual(self): class TestCloudflareHelpers(unittest.TestCase): def setUp(self): - self.event = ImmutableCaseInsensitiveDict( + self.event = PantherEvent( { "Source": "firewallrules", "ClientIP": "12.12.12.12", @@ -1635,7 +1636,7 @@ def test_http_context_helper(self): class TestAsanaHelpers(unittest.TestCase): def setUp(self): - self.event = ImmutableCaseInsensitiveDict( + self.event = PantherEvent( { "actor": { "actor_type": "user", @@ -1670,13 +1671,13 @@ def test_alert_context(self): # Remove the user's email attribute tmp_event = self.event.to_dict() tmp_event["actor"].pop("email") - tmp_event = ImmutableCaseInsensitiveDict(tmp_event) + tmp_event = PantherEvent(tmp_event) returns = p_a_h.asana_alert_context(tmp_event) self.assertEqual(returns.get("actor", ""), "") self.assertEqual(returns.get("resource_type", ""), "task") tmp_event = tmp_event.to_dict() tmp_event["resource"] = {"resource_type": "story", "resource_subtype": "added_to_project"} - tmp_event = ImmutableCaseInsensitiveDict(tmp_event) + tmp_event = PantherEvent(tmp_event) returns = p_a_h.asana_alert_context(tmp_event) self.assertEqual(returns.get("resource_type", ""), "story__added_to_project") # resource with no resource subtype @@ -1687,14 +1688,14 @@ def test_alert_context(self): "name": "Users Name", "resource_type": "user", } - tmp_event = ImmutableCaseInsensitiveDict(tmp_event) + tmp_event = PantherEvent(tmp_event) returns = p_a_h.asana_alert_context(tmp_event) self.assertEqual(returns.get("resource_type", ""), "user") self.assertEqual(returns.get("resource_name", ""), "Users Name") self.assertEqual(returns.get("resource_gid", ""), "1111111111111111") def test_safe_ac_missing_entries(self): - returns = p_a_h.asana_alert_context(ImmutableCaseInsensitiveDict({})) + returns = p_a_h.asana_alert_context(PantherEvent({})) self.assertEqual(returns.get("actor"), "") self.assertEqual(returns.get("event_type"), "") self.assertEqual(returns.get("resource_type"), "") @@ -1702,12 +1703,12 @@ def test_safe_ac_missing_entries(self): self.assertEqual(returns.get("resource_gid"), "") tmp_event = self.event.to_dict() tmp_event["resource"]["resource_type"] = None - tmp_event = ImmutableCaseInsensitiveDict(tmp_event) + tmp_event = PantherEvent(tmp_event) returns = p_a_h.asana_alert_context(tmp_event) self.assertEqual(returns.get("resource_type"), "") def test_external_admin(self): - event = ImmutableCaseInsensitiveDict( + event = PantherEvent( { "actor": {"actor_type": "external_administrator"}, "context": {"context_type": "api"}, @@ -1731,7 +1732,7 @@ def test_external_admin(self): class TestSnykHelpers(unittest.TestCase): def setUp(self): - self.event = ImmutableCaseInsensitiveDict( + self.event = PantherEvent( { "content": {"url": "/api/v1/user/me"}, "created": "2022-12-27 16:50:46.959", @@ -1769,7 +1770,7 @@ def test_alert_context(self): class TestTinesHelpers(unittest.TestCase): def setUp(self): - self.event = ImmutableCaseInsensitiveDict( + self.event = PantherEvent( { "created_at": "2023-05-01 01:02:03", "id": 7206820, @@ -1814,7 +1815,7 @@ def test_alert_context(self): class TestAuth0Helpers(unittest.TestCase): def setUp(self): - self.event = ImmutableCaseInsensitiveDict( + self.event = PantherEvent( { "data": { "client_id": "1HXWWGKk1Zj3JF8GvMrnCSirccDs4qvr", @@ -1870,8 +1871,8 @@ def test_alert_context(self): ) self.assertEqual(returns.get("action", ""), "Create a role") self.assertEqual(auth0_config_event, True) - returns = p_auth0_h.auth0_alert_context(ImmutableCaseInsensitiveDict({})) - auth0_config_event = p_auth0_h.is_auth0_config_event({}) + returns = p_auth0_h.auth0_alert_context(PantherEvent({})) + auth0_config_event = p_auth0_h.is_auth0_config_event(PantherEvent({})) self.assertEqual(returns.get("actor", ""), "") self.assertEqual(returns.get("action", ""), "") self.assertEqual(auth0_config_event, False) @@ -1879,7 +1880,7 @@ def test_alert_context(self): class TestTailscaleHelpers(unittest.TestCase): def setUp(self): - self.event = ImmutableCaseInsensitiveDict( + self.event = PantherEvent( { "event": { "action": "CREATE", @@ -1912,8 +1913,8 @@ def test_alert_context(self): ) self.assertEqual(returns.get("action", ""), "CREATE") self.assertEqual(tailscale_admin_console_event, True) - returns = p_tscale_h.tailscale_alert_context(ImmutableCaseInsensitiveDict({})) - tailscale_admin_console_event = p_tscale_h.is_tailscale_admin_console_event({}) + returns = p_tscale_h.tailscale_alert_context(PantherEvent({})) + tailscale_admin_console_event = p_tscale_h.is_tailscale_admin_console_event(PantherEvent({})) self.assertEqual(returns.get("actor", ""), "") self.assertEqual(returns.get("action", ""), "") self.assertEqual(tailscale_admin_console_event, False) @@ -1987,7 +1988,7 @@ def test_distances(self): class TestNotionHelpers(unittest.TestCase): def setUp(self): - self.event = ImmutableCaseInsensitiveDict( + self.event = PantherEvent( { "event": { "id": "...", @@ -2019,7 +2020,7 @@ def test_alert_context(self): }, ) self.assertEqual(returns.get("action", ""), "workspace.content_exported") - returns = p_notion_h.notion_alert_context(ImmutableCaseInsensitiveDict({})) + returns = p_notion_h.notion_alert_context(PantherEvent({})) self.assertEqual(returns.get("actor", ""), "") self.assertEqual(returns.get("action", ""), "") @@ -2027,10 +2028,10 @@ def test_alert_context(self): class TestLookupTableHelpers(unittest.TestCase): # pylint: disable=protected-access def setUp(self): - self.simple_event_no_pmatch = ImmutableCaseInsensitiveDict( + self.simple_event_no_pmatch = PantherEvent( {"p_enrichment": {"tor_exit_nodes": {"foo": {"ip": "1.2.3.4"}}}} ) - self.simple_event = ImmutableCaseInsensitiveDict( + self.simple_event = PantherEvent( { "p_enrichment": { "tor_exit_nodes": { @@ -2051,7 +2052,7 @@ def setUp(self): } ) # match against array field - self.list_event = ImmutableCaseInsensitiveDict( + self.list_event = PantherEvent( { "p_enrichment": { "tor_exit_nodes": { @@ -2109,7 +2110,7 @@ def test_enrichments_by_pmatch(self): class TestAzureSigninHelpers(unittest.TestCase): def setUp(self): # pylint: disable=line-too-long - self.event_noninteractive = ImmutableCaseInsensitiveDict( + self.event_noninteractive = PantherEvent( { "Level": 4, "callerIpAddress": "12.12.12.12", @@ -2213,7 +2214,7 @@ def setUp(self): "time": "2023-07-24 07:13:50.894", } ) - self.event_signin = ImmutableCaseInsensitiveDict( + self.event_signin = PantherEvent( { "Level": 4, "callerIpAddress": "12.12.12.12", @@ -2353,7 +2354,7 @@ def test_alert_context(self): "resourceId": "b0d1813f-efb7-4d74-b573-50f2931a6837", }, ) - returns = p_asi_h.azure_signin_alert_context({}) + returns = p_asi_h.azure_signin_alert_context(PantherEvent({})) self.assertEqual( returns, { From 917e9054aca530c56c39858b2fd9dad988897d6c Mon Sep 17 00:00:00 2001 From: Ben Airey Date: Wed, 2 Oct 2024 13:04:24 -0500 Subject: [PATCH 3/4] replace single-layer deep_get with get --- global_helpers/global_filter_azuresignin.py | 2 +- global_helpers/global_filter_github.py | 2 +- global_helpers/global_filter_notion.py | 2 +- global_helpers/global_filter_snyk.py | 2 +- global_helpers/global_filter_tines.py | 2 +- global_helpers/panther_azuresignin_helpers.py | 6 +++--- global_helpers/panther_sublime_helpers.py | 2 +- rules/appomni_rules/appomni_alert_passthrough.py | 2 +- rules/auth0_rules/auth0_cic_credential_stuffing.py | 2 +- rules/auth0_rules/auth0_custom_role_created.py | 2 +- rules/auth0_rules/auth0_integration_installed.py | 2 +- rules/auth0_rules/auth0_mfa_factor_setting_enabled.py | 2 +- rules/auth0_rules/auth0_mfa_policy_disabled.py | 2 +- .../auth0_rules/auth0_mfa_risk_assessment_disabled.py | 2 +- rules/auth0_rules/auth0_mfa_risk_assessment_enabled.py | 2 +- rules/auth0_rules/auth0_post_login_action_flow.py | 2 +- rules/auth0_rules/auth0_user_invitation_created.py | 2 +- rules/auth0_rules/auth0_user_joined_tenant.py | 2 +- .../aws_cloudtrail_useraccesskeyauth.py | 2 +- .../aws_iam_compromised_key_quarantine.py | 2 +- rules/aws_cloudtrail_rules/aws_rds_snapshot_shared.py | 2 +- .../aws_cloudtrail_rules/aws_s3_activity_greynoise.py | 2 +- .../crowdstrike_macos_add_trusted_cert.py | 4 ++-- .../crowdstrike_macos_osascript_administrator.py | 4 ++-- .../crowdstrike_macos_plutil_usage.py | 4 ++-- ...p_access_attempts_violating_vpc_service_controls.py | 2 +- .../gcp_workforce_pool_created_or_updated.py | 2 +- ...gitlab_production_password_reset_multiple_emails.py | 4 ++-- rules/mongodb_rules/mongodb_2fa_disabled.py | 4 ++-- .../mongodb_access_allowed_from_anywhere.py | 10 +++++----- rules/mongodb_rules/mongodb_alerting_disabled.py | 8 ++++---- rules/mongodb_rules/mongodb_atlas_api_key_created.py | 10 +++++----- rules/mongodb_rules/mongodb_external_user_invited.py | 4 ++-- .../mongodb_external_user_invited_no_config.py | 6 +++--- .../mongodb_identity_provider_activity.py | 2 +- rules/mongodb_rules/mongodb_logging_toggled.py | 4 ++-- .../mongodb_org_membership_restriction_disabled.py | 4 ++-- rules/mongodb_rules/mongodb_user_created_or_deleted.py | 2 +- rules/mongodb_rules/mongodb_user_roles_changed.py | 2 +- .../notion_rules/notion_page_view_impossible_travel.py | 4 ++-- rules/okta_rules/okta_login_signal.py | 2 +- rules/snyk_rules/snyk_misc_settings.py | 4 ++-- rules/snyk_rules/snyk_org_settings.py | 4 ++-- rules/snyk_rules/snyk_ou_change.py | 6 +++--- rules/snyk_rules/snyk_project_settings.py | 6 +++--- rules/snyk_rules/snyk_role_change.py | 8 ++++---- rules/snyk_rules/snyk_svcacct_change.py | 6 +++--- rules/snyk_rules/snyk_system_externalaccess.py | 4 ++-- rules/snyk_rules/snyk_system_policysetting.py | 2 +- rules/snyk_rules/snyk_system_sso.py | 2 +- rules/snyk_rules/snyk_user_mgmt.py | 8 ++++---- rules/standard_rules/impossible_travel_login.py | 4 ++-- rules/tines_rules/tines_actions_disabled_changes.py | 6 +++--- rules/tines_rules/tines_custom_ca.py | 4 ++-- .../tines_enqueued_retrying_job_deletion.py | 8 ++++---- rules/tines_rules/tines_global_resource_destruction.py | 8 ++++---- rules/tines_rules/tines_sso_settings.py | 4 ++-- rules/tines_rules/tines_story_items_destruction.py | 8 ++++---- rules/tines_rules/tines_story_jobs_clearance.py | 8 ++++---- rules/tines_rules/tines_team_destruction.py | 8 ++++---- rules/tines_rules/tines_tenant_authtoken.py | 4 ++-- 61 files changed, 121 insertions(+), 121 deletions(-) diff --git a/global_helpers/global_filter_azuresignin.py b/global_helpers/global_filter_azuresignin.py index 60354bd8c..644bb018d 100644 --- a/global_helpers/global_filter_azuresignin.py +++ b/global_helpers/global_filter_azuresignin.py @@ -14,7 +14,7 @@ def filter_include_event(event) -> bool: # pylint: disable=unused-argument # # # example: event['tenantId'] # # if tenantId were missing, we want default behavior to be to alert on this event. - # tenant_id = event.deep_get("tenantId", default="") + # tenant_id = event.get("tenantId", "") # return event_origin in ["333333eb-a222-33cc-9baf-4a1111111111", ""] # return True diff --git a/global_helpers/global_filter_github.py b/global_helpers/global_filter_github.py index e89da5fbf..df5a6d7ff 100644 --- a/global_helpers/global_filter_github.py +++ b/global_helpers/global_filter_github.py @@ -16,7 +16,7 @@ def filter_include_event(event) -> bool: # pylint: disable=unused-argument # # # not all github enterprise events have org # # example: enterprise.self_hosted_runner_online - # org = event.deep_get("org", default="") + # org = event.get("org", "") # return org in ["my-prod-org", ""] # return True diff --git a/global_helpers/global_filter_notion.py b/global_helpers/global_filter_notion.py index 7961e0225..1985ae648 100644 --- a/global_helpers/global_filter_notion.py +++ b/global_helpers/global_filter_notion.py @@ -14,7 +14,7 @@ def filter_include_event(event) -> bool: # pylint: disable=unused-argument # # # example: workspace_id # # if we don't know the workspace_id, we want default behavior to be to alert on this event. - # workspace_id = event.deep_get("workspace_id", default="") + # workspace_id = event.get("workspace_id", "") # return workspace_id in ["ea65b016-6abc-4dcf-808b-e000099999999", ""] # return True diff --git a/global_helpers/global_filter_snyk.py b/global_helpers/global_filter_snyk.py index 4d96346f7..7192f313a 100644 --- a/global_helpers/global_filter_snyk.py +++ b/global_helpers/global_filter_snyk.py @@ -13,7 +13,7 @@ def filter_include_event(event) -> bool: # pylint: disable=unused-argument # # # not all snyk audit events have orgId & projectId # # example: group.user.add, sometimes api.access - # org = event.deep_get("orgId", default="") + # org = event.get("orgId", "") # return org in ["21111111-a222-4eee-8ddd-a99999999999", ""] # return True diff --git a/global_helpers/global_filter_tines.py b/global_helpers/global_filter_tines.py index fd0d63ca4..c2b411239 100644 --- a/global_helpers/global_filter_tines.py +++ b/global_helpers/global_filter_tines.py @@ -11,7 +11,7 @@ def filter_include_event(event) -> bool: # pylint: disable=unused-argument # 1. the specific tenant_id mentioned. # 2. events where tenant_id is undefined # - # tenant_id = event.deep_get("tenant_id", default="") + # tenant_id = event.get("tenant_id", "") # return tenant_id in ["1234", ""] # return True diff --git a/global_helpers/panther_azuresignin_helpers.py b/global_helpers/panther_azuresignin_helpers.py index 16dca71bd..3058f63fc 100644 --- a/global_helpers/panther_azuresignin_helpers.py +++ b/global_helpers/panther_azuresignin_helpers.py @@ -1,5 +1,5 @@ def actor_user(event): - category = event.deep_get("category", default="") + category = event.get("category", "") if category in {"ServicePrincipalSignInLogs"}: return event.deep_get("properties", "servicePrincipalName") if category in {"SignInLogs", "NonInteractiveUserSignInLogs"}: @@ -8,7 +8,7 @@ def actor_user(event): def is_sign_in_event(event): - return event.deep_get("operationName", default="") == "Sign-in activity" + return event.get("operationName", "") == "Sign-in activity" def azure_signin_alert_context(event) -> dict: @@ -16,7 +16,7 @@ def azure_signin_alert_context(event) -> dict: if ac_actor_user is None: ac_actor_user = "" a_c = {} - a_c["tenantId"] = event.deep_get("tenantId", default="") + a_c["tenantId"] = event.get("tenantId", "") a_c["source_ip"] = event.deep_get("properties", "ipAddress", default="") a_c["actor_user"] = ac_actor_user a_c["resourceDisplayName"] = event.deep_get( diff --git a/global_helpers/panther_sublime_helpers.py b/global_helpers/panther_sublime_helpers.py index 677b650f2..fbc271ca0 100644 --- a/global_helpers/panther_sublime_helpers.py +++ b/global_helpers/panther_sublime_helpers.py @@ -1,6 +1,6 @@ def sublime_alert_context(event) -> dict: context = {} - context["events_type"] = event.get("type", default="") + context["events_type"] = event.get("type", "") context["users_emails"] = event.deep_get( "created_by", "email_address", default="" ) diff --git a/rules/appomni_rules/appomni_alert_passthrough.py b/rules/appomni_rules/appomni_alert_passthrough.py index 15299ce50..93ecafa2d 100644 --- a/rules/appomni_rules/appomni_alert_passthrough.py +++ b/rules/appomni_rules/appomni_alert_passthrough.py @@ -33,4 +33,4 @@ def dedup(event): def alert_context(event): # 'Threat' and 'related' data to be included in the alert sent to the alert destination - return {"threat": event.deep_get("rule", "threat"), "related": event.deep_get("related")} + return {"threat": event.deep_get("rule", "threat"), "related": event.get("related")} diff --git a/rules/auth0_rules/auth0_cic_credential_stuffing.py b/rules/auth0_rules/auth0_cic_credential_stuffing.py index 585f787e9..b508246c3 100644 --- a/rules/auth0_rules/auth0_cic_credential_stuffing.py +++ b/rules/auth0_rules/auth0_cic_credential_stuffing.py @@ -16,7 +16,7 @@ def title(event): user = event.deep_get( "data", "details", "request", "auth", "user", "email", default="" ) - p_source_label = event.deep_get("p_source_label", default="") + p_source_label = event.get("p_source_label", "") return ( f"Auth0 User [{user}] had a suspicious [{event_type}] event in " f"your organization's tenant [{p_source_label}]." diff --git a/rules/auth0_rules/auth0_custom_role_created.py b/rules/auth0_rules/auth0_custom_role_created.py index 584678f7a..4befbfa4b 100644 --- a/rules/auth0_rules/auth0_custom_role_created.py +++ b/rules/auth0_rules/auth0_custom_role_created.py @@ -30,7 +30,7 @@ def title(event): else: role_type = "custom" - p_source_label = event.deep_get("p_source_label", default="") + p_source_label = event.get("p_source_label", "") return ( f"Auth0 User [{user}] created a " f"role [{request_body_name}] with [{role_type}] " diff --git a/rules/auth0_rules/auth0_integration_installed.py b/rules/auth0_rules/auth0_integration_installed.py index 7bd823127..bacc26fcd 100644 --- a/rules/auth0_rules/auth0_integration_installed.py +++ b/rules/auth0_rules/auth0_integration_installed.py @@ -22,7 +22,7 @@ def title(event): user = event.deep_get( "data", "details", "request", "auth", "user", "email", default="" ) - p_source_label = event.deep_get("p_source_label", default="") + p_source_label = event.get("p_source_label", "") return ( f"Auth0 User [{user}] installed an integration from the actions library for " f"your organization's tenant [{p_source_label}]." diff --git a/rules/auth0_rules/auth0_mfa_factor_setting_enabled.py b/rules/auth0_rules/auth0_mfa_factor_setting_enabled.py index 9f7b501a4..696226f20 100644 --- a/rules/auth0_rules/auth0_mfa_factor_setting_enabled.py +++ b/rules/auth0_rules/auth0_mfa_factor_setting_enabled.py @@ -21,7 +21,7 @@ def title(event): "data", "details", "request", "auth", "user", "email", default="" ) path = event.deep_get("data", "details", "request", "path", default="") - p_source_label = event.deep_get("p_source_label", default="") + p_source_label = event.get("p_source_label", "") return ( f"Auth0 User [{user}] enabled mfa factor settings for [{path}] " f"in your organization’s tenant [{p_source_label}]." diff --git a/rules/auth0_rules/auth0_mfa_policy_disabled.py b/rules/auth0_rules/auth0_mfa_policy_disabled.py index d11794796..2bbf31ea2 100644 --- a/rules/auth0_rules/auth0_mfa_policy_disabled.py +++ b/rules/auth0_rules/auth0_mfa_policy_disabled.py @@ -24,7 +24,7 @@ def title(event): user = event.deep_get( "data", "details", "request", "auth", "user", "email", default="" ) - p_source_label = event.deep_get("p_source_label", default="") + p_source_label = event.get("p_source_label", "") return ( f"Auth0 User [{user}] set mfa requirement settings to 'Never' for your " f"organization's tenant [{p_source_label}]." diff --git a/rules/auth0_rules/auth0_mfa_risk_assessment_disabled.py b/rules/auth0_rules/auth0_mfa_risk_assessment_disabled.py index 5a3bac941..8645145c7 100644 --- a/rules/auth0_rules/auth0_mfa_risk_assessment_disabled.py +++ b/rules/auth0_rules/auth0_mfa_risk_assessment_disabled.py @@ -26,7 +26,7 @@ def title(event): user = event.deep_get( "data", "details", "request", "auth", "user", "email", default="" ) - p_source_label = event.deep_get("p_source_label", default="") + p_source_label = event.get("p_source_label", "") return ( f"Auth0 User [{user}] disabled mfa risk assessment settings for your " f"organization’s tenant [{p_source_label}]." diff --git a/rules/auth0_rules/auth0_mfa_risk_assessment_enabled.py b/rules/auth0_rules/auth0_mfa_risk_assessment_enabled.py index 3a8bb0ba8..c40403448 100644 --- a/rules/auth0_rules/auth0_mfa_risk_assessment_enabled.py +++ b/rules/auth0_rules/auth0_mfa_risk_assessment_enabled.py @@ -26,7 +26,7 @@ def title(event): user = event.deep_get( "data", "details", "request", "auth", "user", "email", default="" ) - p_source_label = event.deep_get("p_source_label", default="") + p_source_label = event.get("p_source_label", "") return ( f"Auth0 User [{user}] enabled mfa risk assessment settings for your " f"organization’s tenant [{p_source_label}]." diff --git a/rules/auth0_rules/auth0_post_login_action_flow.py b/rules/auth0_rules/auth0_post_login_action_flow.py index 9c6d9d24c..75b61b075 100644 --- a/rules/auth0_rules/auth0_post_login_action_flow.py +++ b/rules/auth0_rules/auth0_post_login_action_flow.py @@ -25,7 +25,7 @@ def title(event): user = event.deep_get( "data", "details", "request", "auth", "user", "email", default="" ) - p_source_label = event.deep_get("p_source_label", default="") + p_source_label = event.get("p_source_label", "") request_bindings = event.deep_get("data", "details", "request", "body", "bindings", default=[]) response_bindings = event.deep_get( "data", "details", "response", "body", "bindings", default=[] diff --git a/rules/auth0_rules/auth0_user_invitation_created.py b/rules/auth0_rules/auth0_user_invitation_created.py index 110fd5a8d..bdb7c40e0 100644 --- a/rules/auth0_rules/auth0_user_invitation_created.py +++ b/rules/auth0_rules/auth0_user_invitation_created.py @@ -28,7 +28,7 @@ def title(event): inviter = event.deep_get( "data", "details", "request", "auth", "user", "email", default="" ) - source = event.deep_get("p_source_label", default="") + source = event.get("p_source_label", "") return f"Auth0 User [{inviter}] invited [{invitee}] to {inv_type} [{source}]]" diff --git a/rules/auth0_rules/auth0_user_joined_tenant.py b/rules/auth0_rules/auth0_user_joined_tenant.py index 8d7776442..4926889a4 100644 --- a/rules/auth0_rules/auth0_user_joined_tenant.py +++ b/rules/auth0_rules/auth0_user_joined_tenant.py @@ -30,7 +30,7 @@ def title(event): user = event.deep_get( "data", "details", "request", "auth", "user", "email", default="" ) - p_source_label = event.deep_get("p_source_label", default="") + p_source_label = event.get("p_source_label", "") return ( f"Auth0 User [{user}] has accepted an invitation to join your " f"organization's tenant [{p_source_label}]." diff --git a/rules/aws_cloudtrail_rules/aws_cloudtrail_useraccesskeyauth.py b/rules/aws_cloudtrail_rules/aws_cloudtrail_useraccesskeyauth.py index 335f6f184..30f9e3c7b 100644 --- a/rules/aws_cloudtrail_rules/aws_cloudtrail_useraccesskeyauth.py +++ b/rules/aws_cloudtrail_rules/aws_cloudtrail_useraccesskeyauth.py @@ -14,7 +14,7 @@ def title(event): def alert_context(event): return { - "ip_accessKeyId": event.get("sourceIpAddress", default="{not found}") + "ip_accessKeyId": event.get("sourceIpAddress", "{not found}") + ":" + event.deep_get("userIdentity", "accessKeyId", default="{not found}") } diff --git a/rules/aws_cloudtrail_rules/aws_iam_compromised_key_quarantine.py b/rules/aws_cloudtrail_rules/aws_iam_compromised_key_quarantine.py index 74f8b92ff..49bf8e4ac 100644 --- a/rules/aws_cloudtrail_rules/aws_iam_compromised_key_quarantine.py +++ b/rules/aws_cloudtrail_rules/aws_iam_compromised_key_quarantine.py @@ -19,6 +19,6 @@ def rule(event): def title(event): - account_id = event.deep_get("recipientAccountId", default="") + account_id = event.get("recipientAccountId", "") user_name = event.deep_get("requestParameters", "userName", default="") return f"Compromised Key quarantined for [{user_name}] in AWS Account [{account_id}]" diff --git a/rules/aws_cloudtrail_rules/aws_rds_snapshot_shared.py b/rules/aws_cloudtrail_rules/aws_rds_snapshot_shared.py index 3729e2e95..b76853904 100644 --- a/rules/aws_cloudtrail_rules/aws_rds_snapshot_shared.py +++ b/rules/aws_cloudtrail_rules/aws_rds_snapshot_shared.py @@ -21,7 +21,7 @@ def rule(event): def title(event): - account_id = event.get("recipientAccountId", default="") + account_id = event.get("recipientAccountId", "") rds_instance_id = event.deep_get( "responseElements", "dBInstanceIdentifier", default="" ) diff --git a/rules/aws_cloudtrail_rules/aws_s3_activity_greynoise.py b/rules/aws_cloudtrail_rules/aws_s3_activity_greynoise.py index 3ee15a472..514bcc238 100644 --- a/rules/aws_cloudtrail_rules/aws_s3_activity_greynoise.py +++ b/rules/aws_cloudtrail_rules/aws_s3_activity_greynoise.py @@ -68,7 +68,7 @@ def rule(event): def title(event): # Group by ip-arn combinations - ip = event.deep_get("sourceIPAddress") + ip = event.get("sourceIPAddress") arn = event.deep_get("userIdentity", "arn") return f"GreyNoise malicious S3 events detected by {ip} from {arn}" diff --git a/rules/crowdstrike_rules/crowdstrike_macos_add_trusted_cert.py b/rules/crowdstrike_rules/crowdstrike_macos_add_trusted_cert.py index a7f1559da..8dfda439a 100644 --- a/rules/crowdstrike_rules/crowdstrike_macos_add_trusted_cert.py +++ b/rules/crowdstrike_rules/crowdstrike_macos_add_trusted_cert.py @@ -2,8 +2,8 @@ def rule(event): - event_platform = event.deep_get("event_platform", default="") - fdr_event_type = event.deep_get("fdr_event_type", default="") + event_platform = event.get("event_platform", "") + fdr_event_type = event.get("fdr_event_type", "") image_filename = event.deep_get("event", "ImageFileName", default="") command_line = event.deep_get("event", "CommandLine", default="") return all( diff --git a/rules/crowdstrike_rules/crowdstrike_macos_osascript_administrator.py b/rules/crowdstrike_rules/crowdstrike_macos_osascript_administrator.py index 9a33eac98..c8a2b03a9 100644 --- a/rules/crowdstrike_rules/crowdstrike_macos_osascript_administrator.py +++ b/rules/crowdstrike_rules/crowdstrike_macos_osascript_administrator.py @@ -2,8 +2,8 @@ def rule(event): - event_platform = event.deep_get("event_platform", default="") - event_simplename = event.deep_get("event_simplename", default="") + event_platform = event.get("event_platform", "") + event_simplename = event.get("event_simplename", "") image_filename = event.deep_get("event", "ImageFileName", default="") command_line = event.deep_get("event", "CommandLine", default="") return all( diff --git a/rules/crowdstrike_rules/crowdstrike_macos_plutil_usage.py b/rules/crowdstrike_rules/crowdstrike_macos_plutil_usage.py index ba272f888..e49f2e312 100644 --- a/rules/crowdstrike_rules/crowdstrike_macos_plutil_usage.py +++ b/rules/crowdstrike_rules/crowdstrike_macos_plutil_usage.py @@ -9,8 +9,8 @@ def rule(event): ): return False - event_platform = event.deep_get("event_platform", default="") - fdr_event_type = event.deep_get("fdr_event_type", default="") + event_platform = event.get("event_platform", "") + fdr_event_type = event.get("fdr_event_type", "") image_filename = event.deep_get("event", "ImageFileName", default="") return all( diff --git a/rules/gcp_audit_rules/gcp_access_attempts_violating_vpc_service_controls.py b/rules/gcp_audit_rules/gcp_access_attempts_violating_vpc_service_controls.py index 763c00b7d..87027352c 100644 --- a/rules/gcp_audit_rules/gcp_access_attempts_violating_vpc_service_controls.py +++ b/rules/gcp_audit_rules/gcp_access_attempts_violating_vpc_service_controls.py @@ -1,5 +1,5 @@ def rule(event): - severity = event.deep_get("severity", default="") + severity = event.get("severity", "") status_code = event.deep_get("protoPayload", "status", "code", default="") violation_types = event.deep_walk( "protoPayload", "status", "details", "violations", "type", default=[] diff --git a/rules/gcp_audit_rules/gcp_workforce_pool_created_or_updated.py b/rules/gcp_audit_rules/gcp_workforce_pool_created_or_updated.py index 77df5fba9..654003ad6 100644 --- a/rules/gcp_audit_rules/gcp_workforce_pool_created_or_updated.py +++ b/rules/gcp_audit_rules/gcp_workforce_pool_created_or_updated.py @@ -16,7 +16,7 @@ def title(event): "protoPayload", "request", "workforcePool", "name", default="" ).split("/")[-1] - resource = organization_id = event.deep_get("logName", default="").split( + resource = organization_id = event.get("logName", "").split( "/" ) diff --git a/rules/gitlab_rules/gitlab_production_password_reset_multiple_emails.py b/rules/gitlab_rules/gitlab_production_password_reset_multiple_emails.py index e1f22a484..44669fea1 100644 --- a/rules/gitlab_rules/gitlab_production_password_reset_multiple_emails.py +++ b/rules/gitlab_rules/gitlab_production_password_reset_multiple_emails.py @@ -3,12 +3,12 @@ def rule(event): - path = event.get("path", default="") + path = event.get("path", "") if path != "/users/password": return False - params = event.get("params", default=[]) + params = event.get("params", []) for param in params: if param.get("key") == "user": email = deep_get(param, "value", "email", default=[]) diff --git a/rules/mongodb_rules/mongodb_2fa_disabled.py b/rules/mongodb_rules/mongodb_2fa_disabled.py index 0f2240653..e81da94a4 100644 --- a/rules/mongodb_rules/mongodb_2fa_disabled.py +++ b/rules/mongodb_rules/mongodb_2fa_disabled.py @@ -2,11 +2,11 @@ def rule(event): - return event.deep_get("eventTypeName", default="") == "ORG_TWO_FACTOR_AUTH_OPTIONAL" + return event.get("eventTypeName", "") == "ORG_TWO_FACTOR_AUTH_OPTIONAL" def title(event): - user = event.deep_get("username", default="") + user = event.get("username", "") return f"MongoDB Atlas: [{user}] has disabled 2FA" diff --git a/rules/mongodb_rules/mongodb_access_allowed_from_anywhere.py b/rules/mongodb_rules/mongodb_access_allowed_from_anywhere.py index 8e7bbe53c..aed2699ea 100644 --- a/rules/mongodb_rules/mongodb_access_allowed_from_anywhere.py +++ b/rules/mongodb_rules/mongodb_access_allowed_from_anywhere.py @@ -3,20 +3,20 @@ def rule(event): if ( - event.deep_get("eventTypeName", default="") == "NETWORK_PERMISSION_ENTRY_ADDED" - and event.deep_get("whitelistEntry", default="") == "0.0.0.0/0" + event.get("eventTypeName", "") == "NETWORK_PERMISSION_ENTRY_ADDED" + and event.get("whitelistEntry", "") == "0.0.0.0/0" ): return True return False def title(event): - user = event.deep_get("username", default="") - group_id = event.deep_get("groupId", default="") + user = event.get("username", "") + group_id = event.get("groupId", "") return f"MongoDB: [{user}] has allowed access to group [{group_id}] from anywhere" def alert_context(event): context = mongodb_alert_context(event) - context["groupId"] = event.deep_get("groupId", default="") + context["groupId"] = event.get("groupId", "") return context diff --git a/rules/mongodb_rules/mongodb_alerting_disabled.py b/rules/mongodb_rules/mongodb_alerting_disabled.py index cf873eefd..7b74b323e 100644 --- a/rules/mongodb_rules/mongodb_alerting_disabled.py +++ b/rules/mongodb_rules/mongodb_alerting_disabled.py @@ -2,19 +2,19 @@ def rule(event): - return event.deep_get("eventTypeName", default="") in [ + return event.get("eventTypeName", "") in [ "ALERT_CONFIG_DISABLED_AUDIT", "ALERT_CONFIG_DELETED_AUDIT", ] def title(event): - user = event.deep_get("username", default="") - alert_id = event.deep_get("alertConfigId", default="") + user = event.get("username", "") + alert_id = event.get("alertConfigId", "") return f"MongoDB: [{user}] has disabled or deleted security alert [{alert_id}]" def alert_context(event): context = mongodb_alert_context(event) - context["alertConfigId"] = event.deep_get("alertConfigId", default="") + context["alertConfigId"] = event.get("alertConfigId", "") return context diff --git a/rules/mongodb_rules/mongodb_atlas_api_key_created.py b/rules/mongodb_rules/mongodb_atlas_api_key_created.py index 96ec06ae9..981fc2a17 100644 --- a/rules/mongodb_rules/mongodb_atlas_api_key_created.py +++ b/rules/mongodb_rules/mongodb_atlas_api_key_created.py @@ -2,12 +2,12 @@ def rule(event): - return event.deep_get("eventTypeName", default="") == "API_KEY_ACCESS_LIST_ENTRY_ADDED" + return event.get("eventTypeName", "") == "API_KEY_ACCESS_LIST_ENTRY_ADDED" def title(event): - user = event.deep_get("username", default="") - public_key = event.deep_get("targetPublicKey", default="") + user = event.get("username", "") + public_key = event.get("targetPublicKey", "") return f"MongoDB Atlas: [{user}] updated the allowed access list for API Key [{public_key}]" @@ -16,8 +16,8 @@ def alert_context(event): links = event.deep_walk("links", "href", return_val="first", default="") extra_context = { "links": links, - "event_type_name": event.deep_get("eventTypeName", default=""), - "target_public_key": event.deep_get("targetPublicKey", default=""), + "event_type_name": event.get("eventTypeName", ""), + "target_public_key": event.get("targetPublicKey", ""), } context.update(extra_context) diff --git a/rules/mongodb_rules/mongodb_external_user_invited.py b/rules/mongodb_rules/mongodb_external_user_invited.py index 37d3490ad..de43af6df 100644 --- a/rules/mongodb_rules/mongodb_external_user_invited.py +++ b/rules/mongodb_rules/mongodb_external_user_invited.py @@ -11,8 +11,8 @@ def rule(event): global ALLOWED_DOMAINS # pylint: disable=global-statement if isinstance(ALLOWED_DOMAINS, MagicMock): ALLOWED_DOMAINS = json.loads(ALLOWED_DOMAINS()) # pylint: disable=not-callable - if event.deep_get("eventTypeName", default="") == "INVITED_TO_ORG": - target_user = event.deep_get("targetUsername", default="") + if event.get("eventTypeName", "") == "INVITED_TO_ORG": + target_user = event.get("targetUsername", "") target_domain = target_user.split("@")[-1] return target_domain not in ALLOWED_DOMAINS return False diff --git a/rules/mongodb_rules/mongodb_external_user_invited_no_config.py b/rules/mongodb_rules/mongodb_external_user_invited_no_config.py index c84ebd315..345295695 100644 --- a/rules/mongodb_rules/mongodb_external_user_invited_no_config.py +++ b/rules/mongodb_rules/mongodb_external_user_invited_no_config.py @@ -2,11 +2,11 @@ def rule(event): - if event.deep_get("eventTypeName", default="") != "INVITED_TO_ORG": + if event.get("eventTypeName", "") != "INVITED_TO_ORG": return False - user_who_sent_an_invitation = event.deep_get("username", default="") - user_who_was_invited = event.deep_get("targetUsername", default="") + user_who_sent_an_invitation = event.get("username", "") + user_who_was_invited = event.get("targetUsername", "") domain = user_who_sent_an_invitation.split("@")[-1] email_domains_are_different = not user_who_was_invited.endswith(domain) diff --git a/rules/mongodb_rules/mongodb_identity_provider_activity.py b/rules/mongodb_rules/mongodb_identity_provider_activity.py index 62e39c16d..be48207c6 100644 --- a/rules/mongodb_rules/mongodb_identity_provider_activity.py +++ b/rules/mongodb_rules/mongodb_identity_provider_activity.py @@ -16,7 +16,7 @@ def rule(event): "OIDC_IDENTITY_PROVIDER_ENABLED", "OIDC_IDENTITY_PROVIDER_DISABLED", } - return event.deep_get("eventTypeName") in important_event_types + return event.get("eventTypeName") in important_event_types def title(event): diff --git a/rules/mongodb_rules/mongodb_logging_toggled.py b/rules/mongodb_rules/mongodb_logging_toggled.py index 18d6c1ba6..ebd390214 100644 --- a/rules/mongodb_rules/mongodb_logging_toggled.py +++ b/rules/mongodb_rules/mongodb_logging_toggled.py @@ -2,11 +2,11 @@ def rule(event): - return event.deep_get("eventTypeName", default="") == "AUDIT_LOG_CONFIGURATION_UPDATED" + return event.get("eventTypeName", "") == "AUDIT_LOG_CONFIGURATION_UPDATED" def title(event): - user = event.deep_get("username", default="") + user = event.get("username", "") return f"MongoDB: [{user}] has changed logging configuration." diff --git a/rules/mongodb_rules/mongodb_org_membership_restriction_disabled.py b/rules/mongodb_rules/mongodb_org_membership_restriction_disabled.py index 987fc2128..4434bfe27 100644 --- a/rules/mongodb_rules/mongodb_org_membership_restriction_disabled.py +++ b/rules/mongodb_rules/mongodb_org_membership_restriction_disabled.py @@ -2,11 +2,11 @@ def rule(event): - return event.deep_get("eventTypeName", default="") == "ORG_PUBLIC_API_ACCESS_LIST_NOT_REQUIRED" + return event.get("eventTypeName", "") == "ORG_PUBLIC_API_ACCESS_LIST_NOT_REQUIRED" def title(event): - user = event.deep_get("username", default="") + user = event.get("username", "") return f"MongoDB: [{user}] has disabled IP access list for the Atlas Administration API" diff --git a/rules/mongodb_rules/mongodb_user_created_or_deleted.py b/rules/mongodb_rules/mongodb_user_created_or_deleted.py index ebe6e90c4..d3f476b14 100644 --- a/rules/mongodb_rules/mongodb_user_created_or_deleted.py +++ b/rules/mongodb_rules/mongodb_user_created_or_deleted.py @@ -2,7 +2,7 @@ def rule(event): - return event.deep_get("eventTypeName", default="") in ("JOINED_ORG", "REMOVED_FROM_ORG") + return event.get("eventTypeName", "") in ("JOINED_ORG", "REMOVED_FROM_ORG") def title(event): diff --git a/rules/mongodb_rules/mongodb_user_roles_changed.py b/rules/mongodb_rules/mongodb_user_roles_changed.py index 4add72f50..226b1271c 100644 --- a/rules/mongodb_rules/mongodb_user_roles_changed.py +++ b/rules/mongodb_rules/mongodb_user_roles_changed.py @@ -2,7 +2,7 @@ def rule(event): - return event.deep_get("eventTypeName") == "USER_ROLES_CHANGED_AUDIT" + return event.get("eventTypeName") == "USER_ROLES_CHANGED_AUDIT" def title(event): diff --git a/rules/notion_rules/notion_page_view_impossible_travel.py b/rules/notion_rules/notion_page_view_impossible_travel.py index 758e2525a..7bb4ea4c3 100644 --- a/rules/notion_rules/notion_page_view_impossible_travel.py +++ b/rules/notion_rules/notion_page_view_impossible_travel.py @@ -43,7 +43,7 @@ def rule(event): if event.deep_get("event", "type") != "page.viewed": return False - p_event_datetime = resolve_timestamp_string(event.deep_get("p_event_time")) + p_event_datetime = resolve_timestamp_string(event.get("p_event_time")) if p_event_datetime is None: # we couldn't go from p_event_time to a datetime object # we need to do this in order to make later time comparisons generic @@ -153,7 +153,7 @@ def rule(event): def title(event): # - log_source = event.deep_get("p_source_label", default="") + log_source = event.get("p_source_label", "") old_city = deep_get(EVENT_CITY_TRACKING, "previous", "city", default="") new_city = deep_get(EVENT_CITY_TRACKING, "current", "city", default="") speed = deep_get(EVENT_CITY_TRACKING, "speed", default="") diff --git a/rules/okta_rules/okta_login_signal.py b/rules/okta_rules/okta_login_signal.py index e7e9ab343..5ac6a2e48 100644 --- a/rules/okta_rules/okta_login_signal.py +++ b/rules/okta_rules/okta_login_signal.py @@ -1,6 +1,6 @@ def rule(event): return ( - event.deep_get("eventType") == "user.session.start" + event.get("eventType") == "user.session.start" and event.deep_get("outcome", "result") == "SUCCESS" ) diff --git a/rules/snyk_rules/snyk_misc_settings.py b/rules/snyk_rules/snyk_misc_settings.py index 5fead94f4..33994e18f 100644 --- a/rules/snyk_rules/snyk_misc_settings.py +++ b/rules/snyk_rules/snyk_misc_settings.py @@ -10,14 +10,14 @@ def rule(event): if not filter_include_event(event): return False - action = event.deep_get("event", default="") + action = event.get("event", "") return action in ACTIONS def title(event): group_or_org = "" operation = "" - action = event.deep_get("event", default="") + action = event.get("event", "") if "." in action: group_or_org = action.split(".")[0].title() operation = ".".join(action.split(".")[1:]).title() diff --git a/rules/snyk_rules/snyk_org_settings.py b/rules/snyk_rules/snyk_org_settings.py index e4d972f1a..01dded114 100644 --- a/rules/snyk_rules/snyk_org_settings.py +++ b/rules/snyk_rules/snyk_org_settings.py @@ -17,14 +17,14 @@ def rule(event): if not filter_include_event(event): return False - action = event.deep_get("event", default="") + action = event.get("event", "") return action in ACTIONS def title(event): group_or_org = "" operation = "" - action = event.deep_get("event", default="") + action = event.get("event", "") if "." in action: group_or_org = action.split(".")[0].title() operation = ".".join(action.split(".")[1:]).title() diff --git a/rules/snyk_rules/snyk_ou_change.py b/rules/snyk_rules/snyk_ou_change.py index af7111e67..10c993992 100644 --- a/rules/snyk_rules/snyk_ou_change.py +++ b/rules/snyk_rules/snyk_ou_change.py @@ -20,13 +20,13 @@ def rule(event): if not filter_include_event(event): return False - action = event.deep_get("event", default="") + action = event.get("event", "") return action in ACTIONS def title(event): group_or_org = "" - action = event.deep_get("event", default="") + action = event.get("event", "") if "." in action: group_or_org = action.split(".")[0].title() return ( @@ -50,7 +50,7 @@ def dedup(event): def severity(event): - action = event.deep_get("event", default="") + action = event.get("event", "") if action.endswith((".remove", ".delete")): return "HIGH" if action.endswith((".edit")): diff --git a/rules/snyk_rules/snyk_project_settings.py b/rules/snyk_rules/snyk_project_settings.py index 5b2cff1d6..495ddfe59 100644 --- a/rules/snyk_rules/snyk_project_settings.py +++ b/rules/snyk_rules/snyk_project_settings.py @@ -34,14 +34,14 @@ def rule(event): return False if event.deep_get("content", "after", "description") == "No new Code Analysis issues found": return False - action = event.deep_get("event", default="") + action = event.get("event", "") return action in ACTIONS def title(event): group_or_org = "" operation = "" - action = event.deep_get("event", default="") + action = event.get("event", "") if "." in action: group_or_org = action.split(".")[0].title() operation = ".".join(action.split(".")[1:]).title() @@ -69,7 +69,7 @@ def dedup(event): def severity(event): - action = event.deep_get("event", default="") + action = event.get("event", "") if action == "org.project.fix_pr.manual_open": return "INFO" return "LOW" diff --git a/rules/snyk_rules/snyk_role_change.py b/rules/snyk_rules/snyk_role_change.py index b345077c0..e5bca399a 100644 --- a/rules/snyk_rules/snyk_role_change.py +++ b/rules/snyk_rules/snyk_role_change.py @@ -18,14 +18,14 @@ def rule(event): if not filter_include_event(event): return False - action = event.deep_get("event", default="") + action = event.get("event", "") return action in ACTIONS def title(event): group_or_org = "" crud_operation = "" - action = event.deep_get("event", default="") + action = event.get("event", "") if "." in action: group_or_org = action.split(".")[0].title() crud_operation = action.split(".")[-1].title() @@ -39,7 +39,7 @@ def title(event): def alert_context(event): a_c = snyk_alert_context(event) role = event.deep_get("content", "after", "role", default=None) - if not role and "afterRoleName" in event.deep_get("content", default={}): + if not role and "afterRoleName" in event.get("content", {}): role = event.deep_get("content", "afterRoleName", default=None) if role: a_c["role_permission"] = role @@ -57,7 +57,7 @@ def dedup(event): def severity(event): role = event.deep_get("content", "after", "role", default=None) - if not role and "afterRoleName" in event.deep_get("content", default={}): + if not role and "afterRoleName" in event.get("content", {}): role = event.deep_get("content", "afterRoleName", default=None) if role == "ADMIN": return "CRITICAL" diff --git a/rules/snyk_rules/snyk_svcacct_change.py b/rules/snyk_rules/snyk_svcacct_change.py index d301009f6..904bbf028 100644 --- a/rules/snyk_rules/snyk_svcacct_change.py +++ b/rules/snyk_rules/snyk_svcacct_change.py @@ -15,14 +15,14 @@ def rule(event): if not filter_include_event(event): return False - action = event.deep_get("event", default="") + action = event.get("event", "") return action in ACTIONS def title(event): group_or_org = "" crud_operation = "" - action = event.deep_get("event", default="") + action = event.get("event", "") if "." in action: group_or_org = action.split(".")[0].title() crud_operation = action.split(".")[-1].title() @@ -53,7 +53,7 @@ def dedup(event): def severity(event): - action = event.deep_get("event", default="") + action = event.get("event", "") role = event.deep_get("content", "role", "role", default=None) if not role: role = event.deep_get("content", "role", default=None) diff --git a/rules/snyk_rules/snyk_system_externalaccess.py b/rules/snyk_rules/snyk_system_externalaccess.py index d2dc43aa9..f375be05e 100644 --- a/rules/snyk_rules/snyk_system_externalaccess.py +++ b/rules/snyk_rules/snyk_system_externalaccess.py @@ -10,13 +10,13 @@ def rule(event): if not filter_include_event(event): return False - action = event.deep_get("event", default="") + action = event.get("event", "") return action in ACTIONS def title(event): current_setting = event.deep_get("content", "after", "isEnabled", default=False) - action = event.deep_get("event", default="") + action = event.get("event", "") if "." in action: action = action.split(".")[0].title() return ( diff --git a/rules/snyk_rules/snyk_system_policysetting.py b/rules/snyk_rules/snyk_system_policysetting.py index b5844c1f8..6ff512d59 100644 --- a/rules/snyk_rules/snyk_system_policysetting.py +++ b/rules/snyk_rules/snyk_system_policysetting.py @@ -13,7 +13,7 @@ def rule(event): if not filter_include_event(event): return False - action = event.deep_get("event", default="") + action = event.get("event", "") return action in ACTIONS diff --git a/rules/snyk_rules/snyk_system_sso.py b/rules/snyk_rules/snyk_system_sso.py index 41bd7aded..07590bdbc 100644 --- a/rules/snyk_rules/snyk_system_sso.py +++ b/rules/snyk_rules/snyk_system_sso.py @@ -12,7 +12,7 @@ def rule(event): if not filter_include_event(event): return False - action = event.deep_get("event", default="") + action = event.get("event", "") return action in ACTIONS diff --git a/rules/snyk_rules/snyk_user_mgmt.py b/rules/snyk_rules/snyk_user_mgmt.py index f2201bf7b..debcceb0e 100644 --- a/rules/snyk_rules/snyk_user_mgmt.py +++ b/rules/snyk_rules/snyk_user_mgmt.py @@ -25,13 +25,13 @@ def rule(event): if not filter_include_event(event): return False - action = event.deep_get("event", default="") + action = event.get("event", "") # for org.user.add/group.user.add via SAML/SCIM # the attributes .userId and .content.publicUserId # have the same value if action.endswith(".user.add"): target_user = event.deep_get("content", "userPublicId", default="") - actor = event.deep_get("userId", default="") + actor = event.get("userId", "") if target_user == actor: return False return action in ACTIONS @@ -40,7 +40,7 @@ def rule(event): def title(event): group_or_org = "" operation = "" - action = event.deep_get("event", default="") + action = event.get("event", "") if "." in action: group_or_org = action.split(".")[0].title() operation = ".".join(action.split(".")[2:]).title() @@ -66,7 +66,7 @@ def dedup(event): def severity(event): role = event.deep_get("content", "after", "role", default=None) - if not role and "afterRoleName" in event.deep_get("content", default={}): + if not role and "afterRoleName" in event.get("content", {}): role = event.deep_get("content", "afterRoleName", default=None) if role == "ADMIN": return "CRITICAL" diff --git a/rules/standard_rules/impossible_travel_login.py b/rules/standard_rules/impossible_travel_login.py index 7233af78b..f5b2694e2 100644 --- a/rules/standard_rules/impossible_travel_login.py +++ b/rules/standard_rules/impossible_travel_login.py @@ -45,7 +45,7 @@ def rule(event): if event.udm("event_type") != event_type.SUCCESSFUL_LOGIN: return False - p_event_datetime = resolve_timestamp_string(event.deep_get("p_event_time")) + p_event_datetime = resolve_timestamp_string(event.get("p_event_time")) if p_event_datetime is None: # we couldn't go from p_event_time to a datetime object # we need to do this in order to make later time comparisons generic @@ -165,7 +165,7 @@ def rule(event): def title(event): # - log_source = event.deep_get("p_source_label", default="") + log_source = event.get("p_source_label", "") old_city = deep_get(EVENT_CITY_TRACKING, "previous", "city", default="") new_city = deep_get(EVENT_CITY_TRACKING, "current", "city", default="") speed = deep_get(EVENT_CITY_TRACKING, "speed", default="") diff --git a/rules/tines_rules/tines_actions_disabled_changes.py b/rules/tines_rules/tines_actions_disabled_changes.py index 860ede58f..9f991216a 100644 --- a/rules/tines_rules/tines_actions_disabled_changes.py +++ b/rules/tines_rules/tines_actions_disabled_changes.py @@ -7,13 +7,13 @@ def rule(event): if not filter_include_event(event): return False - action = event.deep_get("operation_name", default="") + action = event.get("operation_name", "") return action in ACTIONS def title(event): - action = event.deep_get("operation_name", default="") - actor = event.deep_get("user_email", default="") + action = event.get("operation_name", "") + actor = event.get("user_email", "") return f"Tines: {action} " f"by {actor}" diff --git a/rules/tines_rules/tines_custom_ca.py b/rules/tines_rules/tines_custom_ca.py index f9397ef87..d1abfaaeb 100644 --- a/rules/tines_rules/tines_custom_ca.py +++ b/rules/tines_rules/tines_custom_ca.py @@ -9,12 +9,12 @@ def rule(event): if not filter_include_event(event): return False - action = event.deep_get("operation_name", default="") + action = event.get("operation_name", "") return action in ACTIONS def title(event): - action = event.deep_get("operation_name", default="") + action = event.get("operation_name", "") return f"Tines: [{action}] " f"by [{event.deep_get('user_email', default='')}]" diff --git a/rules/tines_rules/tines_enqueued_retrying_job_deletion.py b/rules/tines_rules/tines_enqueued_retrying_job_deletion.py index 21f43d0b7..53ba39058 100644 --- a/rules/tines_rules/tines_enqueued_retrying_job_deletion.py +++ b/rules/tines_rules/tines_enqueued_retrying_job_deletion.py @@ -6,16 +6,16 @@ def rule(event): if not filter_include_event(event): return False - return event.deep_get("operation_name", default="") in [ + return event.get("operation_name", "") in [ "JobsQueuedDeletion", "JobsRetryingDeletion", ] def title(event): - operation = event.deep_get("operation_name", default="") - user = event.deep_get("user_email", default="") - tines_instance = event.deep_get("p_source_label", default="") + operation = event.get("operation_name", "") + user = event.get("user_email", "") + tines_instance = event.get("p_source_label", "") return f"Tines [{operation}] performed by [{user}] on [{tines_instance}]." diff --git a/rules/tines_rules/tines_global_resource_destruction.py b/rules/tines_rules/tines_global_resource_destruction.py index 0049d8b37..53a179338 100644 --- a/rules/tines_rules/tines_global_resource_destruction.py +++ b/rules/tines_rules/tines_global_resource_destruction.py @@ -7,15 +7,15 @@ def rule(event): return False return ( - event.deep_get("operation_name", default="") + event.get("operation_name", "") == "GlobalResourceDestruction" ) def title(event): - operation = event.deep_get("operation_name", default="") - user = event.deep_get("user_email", default="") - tines_instance = event.deep_get("p_source_label", default="") + operation = event.get("operation_name", "") + user = event.get("user_email", "") + tines_instance = event.get("p_source_label", "") return f"Tines [{operation}] performed by [{user}] on [{tines_instance}]." diff --git a/rules/tines_rules/tines_sso_settings.py b/rules/tines_rules/tines_sso_settings.py index 382a7df37..d24e928e7 100644 --- a/rules/tines_rules/tines_sso_settings.py +++ b/rules/tines_rules/tines_sso_settings.py @@ -11,12 +11,12 @@ def rule(event): if not filter_include_event(event): return False - action = event.deep_get("operation_name", default="") + action = event.get("operation_name", "") return action in ACTIONS def title(event): - action = event.deep_get("operation_name", default="") + action = event.get("operation_name", "") return ( f"Tines: [{action}] Setting " f"changed by [{event.deep_get('user_email', default='')}]" diff --git a/rules/tines_rules/tines_story_items_destruction.py b/rules/tines_rules/tines_story_items_destruction.py index 386982898..ca12acb53 100644 --- a/rules/tines_rules/tines_story_items_destruction.py +++ b/rules/tines_rules/tines_story_items_destruction.py @@ -7,14 +7,14 @@ def rule(event): return False return ( - event.deep_get("operation_name", default="") == "StoryItemsDestruction" + event.get("operation_name", "") == "StoryItemsDestruction" ) def title(event): - operation = event.deep_get("operation_name", default="") - user = event.deep_get("user_email", default="") - tines_instance = event.deep_get("p_source_label", default="") + operation = event.get("operation_name", "") + user = event.get("user_email", "") + tines_instance = event.get("p_source_label", "") return f"Tines [{operation}] performed by [{user}] on [{tines_instance}]." diff --git a/rules/tines_rules/tines_story_jobs_clearance.py b/rules/tines_rules/tines_story_jobs_clearance.py index 6b12ca339..f794cc69b 100644 --- a/rules/tines_rules/tines_story_jobs_clearance.py +++ b/rules/tines_rules/tines_story_jobs_clearance.py @@ -6,13 +6,13 @@ def rule(event): if not filter_include_event(event): return False - return event.deep_get("operation_name", default="") == "StoryJobsClearance" + return event.get("operation_name", "") == "StoryJobsClearance" def title(event): - operation = event.deep_get("operation_name", default="") - user = event.deep_get("user_email", default="") - tines_instance = event.deep_get("p_source_label", default="") + operation = event.get("operation_name", "") + user = event.get("user_email", "") + tines_instance = event.get("p_source_label", "") return f"Tines: [{operation}] performed by [{user}] on [{tines_instance}]." diff --git a/rules/tines_rules/tines_team_destruction.py b/rules/tines_rules/tines_team_destruction.py index 6cb19346a..f8098c9b0 100644 --- a/rules/tines_rules/tines_team_destruction.py +++ b/rules/tines_rules/tines_team_destruction.py @@ -6,13 +6,13 @@ def rule(event): if not filter_include_event(event): return False - return event.deep_get("operation_name", default="") == "TeamDestruction" + return event.get("operation_name", "") == "TeamDestruction" def title(event): - operation = event.deep_get("operation_name", default="") - user = event.deep_get("user_email", default="") - tines_instance = event.deep_get("p_source_label", default="") + operation = event.get("operation_name", "") + user = event.get("user_email", "") + tines_instance = event.get("p_source_label", "") return f"Tines [{operation}] performed by [{user}] on [{tines_instance}]." diff --git a/rules/tines_rules/tines_tenant_authtoken.py b/rules/tines_rules/tines_tenant_authtoken.py index 25b6f3978..0a326d890 100644 --- a/rules/tines_rules/tines_tenant_authtoken.py +++ b/rules/tines_rules/tines_tenant_authtoken.py @@ -13,13 +13,13 @@ def rule(event): if not filter_include_event(event): return False - action = event.deep_get("operation_name", default="") + action = event.get("operation_name", "") is_tenant_token = event.deep_get("inputs", "inputs", "isServiceToken", default=False) return all([action in ACTIONS, is_tenant_token]) def title(event): - action = event.deep_get("operation_name", default="") + action = event.get("operation_name", "") return ( f"Tines: Tenant [{action}] " f"by [{event.deep_get('user_email', default='')}]" From ee484ed14d771ea76df195cd25b73e5f29cc63a9 Mon Sep 17 00:00:00 2001 From: akozlovets098 Date: Thu, 3 Oct 2024 12:45:48 +0300 Subject: [PATCH 4/4] THREAT-397 lint fix --- global_helpers/global_helpers_test.py | 4 +++- .../aws_authentication_from_crowdstrike_unmanaged_device.py | 2 +- rules/aws_cloudtrail_rules/aws_console_login_without_mfa.py | 4 ++-- ...ssions_granted_to_create_or_manage_service_account_key.py | 2 -- .../gcp_audit_rules/gcp_workforce_pool_created_or_updated.py | 4 +--- rules/tines_rules/tines_global_resource_destruction.py | 5 +---- rules/tines_rules/tines_story_items_destruction.py | 4 +--- 7 files changed, 9 insertions(+), 16 deletions(-) diff --git a/global_helpers/global_helpers_test.py b/global_helpers/global_helpers_test.py index 3e4d93088..f26321396 100755 --- a/global_helpers/global_helpers_test.py +++ b/global_helpers/global_helpers_test.py @@ -1914,7 +1914,9 @@ def test_alert_context(self): self.assertEqual(returns.get("action", ""), "CREATE") self.assertEqual(tailscale_admin_console_event, True) returns = p_tscale_h.tailscale_alert_context(PantherEvent({})) - tailscale_admin_console_event = p_tscale_h.is_tailscale_admin_console_event(PantherEvent({})) + tailscale_admin_console_event = p_tscale_h.is_tailscale_admin_console_event( + PantherEvent({}) + ) self.assertEqual(returns.get("actor", ""), "") self.assertEqual(returns.get("action", ""), "") self.assertEqual(tailscale_admin_console_event, False) diff --git a/queries/crowdstrike_queries/aws_authentication_from_crowdstrike_unmanaged_device.py b/queries/crowdstrike_queries/aws_authentication_from_crowdstrike_unmanaged_device.py index d51347589..9095a199e 100644 --- a/queries/crowdstrike_queries/aws_authentication_from_crowdstrike_unmanaged_device.py +++ b/queries/crowdstrike_queries/aws_authentication_from_crowdstrike_unmanaged_device.py @@ -1,4 +1,4 @@ -from panther_base_helpers import aws_rule_context, deep_get +from panther_base_helpers import aws_rule_context def rule(_): diff --git a/rules/aws_cloudtrail_rules/aws_console_login_without_mfa.py b/rules/aws_cloudtrail_rules/aws_console_login_without_mfa.py index d4dd811c9..d73e99168 100644 --- a/rules/aws_cloudtrail_rules/aws_console_login_without_mfa.py +++ b/rules/aws_cloudtrail_rules/aws_console_login_without_mfa.py @@ -82,8 +82,8 @@ def title(event): if event.deep_get("userIdentity", "type") == "Root": user_string = "the root user" else: - user = event.deep_get("userIdentity", "userName") or deep_get( - event, "userIdentity", "sessionContext", "sessionIssuer", "userName" + user = event.deep_get("userIdentity", "userName") or event.deep_get( + "userIdentity", "sessionContext", "sessionIssuer", "userName" ) type_ = event.deep_get( "userIdentity", "sessionContext", "sessionIssuer", "type", default="user" diff --git a/rules/gcp_audit_rules/gcp_permissions_granted_to_create_or_manage_service_account_key.py b/rules/gcp_audit_rules/gcp_permissions_granted_to_create_or_manage_service_account_key.py index d475b8f4a..5c5abff85 100644 --- a/rules/gcp_audit_rules/gcp_permissions_granted_to_create_or_manage_service_account_key.py +++ b/rules/gcp_audit_rules/gcp_permissions_granted_to_create_or_manage_service_account_key.py @@ -1,5 +1,3 @@ -from panther_base_helpers import deep_walk - SERVICE_ACCOUNT_MANAGE_ROLES = [ "roles/iam.serviceAccountTokenCreator", "roles/iam.serviceAccountUser", diff --git a/rules/gcp_audit_rules/gcp_workforce_pool_created_or_updated.py b/rules/gcp_audit_rules/gcp_workforce_pool_created_or_updated.py index 654003ad6..342aaf198 100644 --- a/rules/gcp_audit_rules/gcp_workforce_pool_created_or_updated.py +++ b/rules/gcp_audit_rules/gcp_workforce_pool_created_or_updated.py @@ -16,9 +16,7 @@ def title(event): "protoPayload", "request", "workforcePool", "name", default="" ).split("/")[-1] - resource = organization_id = event.get("logName", "").split( - "/" - ) + resource = organization_id = event.get("logName", "").split("/") organization_id = resource[resource.index("organizations") + 1] diff --git a/rules/tines_rules/tines_global_resource_destruction.py b/rules/tines_rules/tines_global_resource_destruction.py index 53a179338..2e74b0a0a 100644 --- a/rules/tines_rules/tines_global_resource_destruction.py +++ b/rules/tines_rules/tines_global_resource_destruction.py @@ -6,10 +6,7 @@ def rule(event): if not filter_include_event(event): return False - return ( - event.get("operation_name", "") - == "GlobalResourceDestruction" - ) + return event.get("operation_name", "") == "GlobalResourceDestruction" def title(event): diff --git a/rules/tines_rules/tines_story_items_destruction.py b/rules/tines_rules/tines_story_items_destruction.py index ca12acb53..432254564 100644 --- a/rules/tines_rules/tines_story_items_destruction.py +++ b/rules/tines_rules/tines_story_items_destruction.py @@ -6,9 +6,7 @@ def rule(event): if not filter_include_event(event): return False - return ( - event.get("operation_name", "") == "StoryItemsDestruction" - ) + return event.get("operation_name", "") == "StoryItemsDestruction" def title(event):