From 7362dd2f8b10e4b8c353d6e18e2bdf3994b494d8 Mon Sep 17 00:00:00 2001 From: ben-githubs <38414634+ben-githubs@users.noreply.github.com> Date: Fri, 17 Jan 2025 11:22:10 -0600 Subject: [PATCH] Snowflake Brute Force Tuning (#1477) --- .../snowflake_stream_brute_force_by_ip.py | 15 ++++++- .../snowflake_stream_brute_force_by_ip.yml | 39 +++++++++++++++++++ ...nowflake_stream_brute_force_by_username.py | 15 ++++++- ...owflake_stream_brute_force_by_username.yml | 39 +++++++++++++++++++ 4 files changed, 106 insertions(+), 2 deletions(-) diff --git a/rules/snowflake_rules/snowflake_stream_brute_force_by_ip.py b/rules/snowflake_rules/snowflake_stream_brute_force_by_ip.py index 75891247c..bcb3804cf 100644 --- a/rules/snowflake_rules/snowflake_stream_brute_force_by_ip.py +++ b/rules/snowflake_rules/snowflake_stream_brute_force_by_ip.py @@ -1,7 +1,12 @@ def rule(event): # Return true for any login attempt; Let Panther's dedup and threshold handle the brute force # detection. - return event.get("EVENT_TYPE") == "LOGIN" and event.get("IS_SUCCESS") == "NO" + return ( + event.get("EVENT_TYPE") == "LOGIN" + and event.get("IS_SUCCESS") == "NO" + and event.get("ERROR_MESSAGE") != "OVERFLOW_FAILURE_EVENTS_ELIDED" + # ^^ OVERFLOW_FAILURE_EVENTS_ELIDED are placeholder logs -> no point in alerting + ) def title(event): @@ -12,6 +17,14 @@ def title(event): ) +def severity(event): + # If the error appears to be caused by an automation issue, downgrade to INFO + common_errors = {"JWT_TOKEN_INVALID_PUBLIC_KEY_FINGERPRINT_MISMATCH"} + if event.get("ERROR_MESSAGE") in common_errors: + return "INFO" + return "DEFAULT" + + def dedup(event): return event.get("CLIENT_IP", "") + event.get( "REPORTED_CLIENT_TYPE", "" diff --git a/rules/snowflake_rules/snowflake_stream_brute_force_by_ip.yml b/rules/snowflake_rules/snowflake_stream_brute_force_by_ip.yml index bc9557fb0..55ef8cc70 100644 --- a/rules/snowflake_rules/snowflake_stream_brute_force_by_ip.yml +++ b/rules/snowflake_rules/snowflake_stream_brute_force_by_ip.yml @@ -54,3 +54,42 @@ Tests: "REPORTED_CLIENT_VERSION": "1.11.1", "USER_NAME": "luthor@lexcorp.com" } + - Name: Unsuccessful Login due to Invalid JWT Fingerprint + ExpectedResult: true + Log: + { + "p_event_time": "2024-10-08 14:38:46.061000000", + "p_log_type": "Snowflake.LoginHistory", + "p_source_label": "Snowflake Prod", + "CLIENT_IP": "1.2.3.4", + "ERROR_CODE": 394304, + "ERROR_MESSAGE": "JWT_TOKEN_INVALID_PUBLIC_KEY_FINGERPRINT_MISMATCH", + "EVENT_ID": "393754014361778", + "EVENT_TIMESTAMP": "2024-10-08 14:38:46.061000000", + "EVENT_TYPE": "LOGIN", + "FIRST_AUTHENTICATION_FACTOR": "PASSWORD", + "IS_SUCCESS": "NO", + "RELATED_EVENT_ID": "0", + "REPORTED_CLIENT_TYPE": "OTHER", + "REPORTED_CLIENT_VERSION": "1.11.1", + "USER_NAME": "luthor@lexcorp.com" + } + - Name: Overflow Failure + ExpectedResult: false + Log: + { + "p_event_time": "2024-11-15 00:12:24.288000000", + "p_log_type": "Snowflake.LoginHistory", + "p_parse_time": "2024-11-15 02:46:25.862374468", + "CLIENT_IP": "0.0.0.0", + "ERROR_CODE": 390156, + "ERROR_MESSAGE": "OVERFLOW_FAILURE_EVENTS_ELIDED", + "EVENT_ID": "16592193114297018", + "EVENT_TIMESTAMP": "2024-11-15 00:12:24.288000000", + "EVENT_TYPE": "LOGIN", + "IS_SUCCESS": "NO", + "RELATED_EVENT_ID": "0", + "REPORTED_CLIENT_TYPE": "OTHER", + "REPORTED_CLIENT_VERSION": "0", + "USER_NAME": "luthor@lexcorp.com" + } diff --git a/rules/snowflake_rules/snowflake_stream_brute_force_by_username.py b/rules/snowflake_rules/snowflake_stream_brute_force_by_username.py index b9cc76dce..28e5c538e 100644 --- a/rules/snowflake_rules/snowflake_stream_brute_force_by_username.py +++ b/rules/snowflake_rules/snowflake_stream_brute_force_by_username.py @@ -1,7 +1,12 @@ def rule(event): # Return true for any login attempt; Let Panther's dedup and threshold handle the brute force # detection. - return event.get("EVENT_TYPE") == "LOGIN" and event.get("IS_SUCCESS") == "NO" + return ( + event.get("EVENT_TYPE") == "LOGIN" + and event.get("IS_SUCCESS") == "NO" + and event.get("ERROR_MESSAGE") != "OVERFLOW_FAILURE_EVENTS_ELIDED" + # ^^ OVERFLOW_FAILURE_EVENTS_ELIDED are placeholder logs -> no point in alerting + ) def title(event): @@ -10,6 +15,14 @@ def title(event): ) +def severity(event): + # If the error appears to be caused by an automation issue, downgrade to INFO + common_errors = {"JWT_TOKEN_INVALID_PUBLIC_KEY_FINGERPRINT_MISMATCH"} + if event.get("ERROR_MESSAGE") in common_errors: + return "INFO" + return "DEFAULT" + + def dedup(event): return event.get("USER_NAME", "") + event.get( "REPORTED_CLIENT_TYPE", "" diff --git a/rules/snowflake_rules/snowflake_stream_brute_force_by_username.yml b/rules/snowflake_rules/snowflake_stream_brute_force_by_username.yml index 80fe931bb..e68c8cc83 100644 --- a/rules/snowflake_rules/snowflake_stream_brute_force_by_username.yml +++ b/rules/snowflake_rules/snowflake_stream_brute_force_by_username.yml @@ -54,3 +54,42 @@ Tests: "REPORTED_CLIENT_VERSION": "1.11.1", "USER_NAME": "luthor@lexcorp.com" } + - Name: Unsuccessful Login due to Invalid JWT Fingerprint + ExpectedResult: true + Log: + { + "p_event_time": "2024-10-08 14:38:46.061000000", + "p_log_type": "Snowflake.LoginHistory", + "p_source_label": "Snowflake Prod", + "CLIENT_IP": "1.2.3.4", + "ERROR_CODE": 394304, + "ERROR_MESSAGE": "JWT_TOKEN_INVALID_PUBLIC_KEY_FINGERPRINT_MISMATCH", + "EVENT_ID": "393754014361778", + "EVENT_TIMESTAMP": "2024-10-08 14:38:46.061000000", + "EVENT_TYPE": "LOGIN", + "FIRST_AUTHENTICATION_FACTOR": "PASSWORD", + "IS_SUCCESS": "NO", + "RELATED_EVENT_ID": "0", + "REPORTED_CLIENT_TYPE": "OTHER", + "REPORTED_CLIENT_VERSION": "1.11.1", + "USER_NAME": "luthor@lexcorp.com" + } + - Name: Overflow Failure + ExpectedResult: false + Log: + { + "p_event_time": "2024-11-15 00:12:24.288000000", + "p_log_type": "Snowflake.LoginHistory", + "p_parse_time": "2024-11-15 02:46:25.862374468", + "CLIENT_IP": "0.0.0.0", + "ERROR_CODE": 390156, + "ERROR_MESSAGE": "OVERFLOW_FAILURE_EVENTS_ELIDED", + "EVENT_ID": "16592193114297018", + "EVENT_TIMESTAMP": "2024-11-15 00:12:24.288000000", + "EVENT_TYPE": "LOGIN", + "IS_SUCCESS": "NO", + "RELATED_EVENT_ID": "0", + "REPORTED_CLIENT_TYPE": "OTHER", + "REPORTED_CLIENT_VERSION": "0", + "USER_NAME": "luthor@lexcorp.com" + }