Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

using caching module in detections instead of globals #888

Merged
merged 7 commits into from
Oct 13, 2023
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ lint: lint-pylint lint-fmt
lint-pylint:
pipenv run bandit -r $(dirs) --skip B101 # allow assert statements in tests
pipenv run pylint $(dirs) \
--disable=missing-docstring,duplicate-code,import-error,fixme,consider-iterating-dictionary,global-variable-not-assigned \
--disable=missing-docstring,duplicate-code,import-error,fixme,consider-iterating-dictionary,global-variable-not-assigned,broad-exception-raised \
--load-plugins=pylint.extensions.mccabe,pylint_print \
--max-line-length=100

Expand Down
6 changes: 3 additions & 3 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ url = "https://pypi.org/simple"
verify_ssl = true

[dev-packages]
bandit = "~=1.7"
bandit = "==1.7.5"
black = "~=22.8"
click = "~=8.1"
decorator = "~=5.1"
isort = "~=5.10.0"
isort = "==5.12.0"
mypy = "~=0.950"
pylint = "~=2.15.0"
pylint = "==2.17.6"
pylint-print = "~=1.0.0"
moto = ">=4.1"

Expand Down
20 changes: 10 additions & 10 deletions Pipfile.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion data_models/asana_data_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@


def get_event_type(event):

logged_event_type = event.get("event_type", {})
# Since this is a safe dict get if the event type is not mapped
# there is an implicit return of None
Expand Down
1 change: 1 addition & 0 deletions global_helpers/panther_iocs.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@
"shscrypto.net",
}


# IOC Helper functions:
def ioc_match(indicators: list, known_iocs: set) -> list:
"""Matches a set of indicators against known Indicators of Compromise
Expand Down
1 change: 1 addition & 0 deletions global_helpers/panther_lookuptable_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
ENRICHMENT_KEY = "p_enrichment"
IGNORE_ENRICHMENTS = "p_any_"


# pylint: disable=too-few-public-methods
class LookupTableMatches:
def __init__(self):
Expand Down
2 changes: 1 addition & 1 deletion rules/aws_cloudtrail_rules/abnormally_high_event_volume.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from json import dumps, loads
from statistics import mean

from panther_oss_helpers import get_string_set, put_string_set
from panther_detection_helpers.caching import get_string_set, put_string_set

# AVERAGE_THRESHOLD defines the factor by which the log count must exceed the rolling_ledger average
AVERAGE_THRESHOLD = 10
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@


def rule(event):

if (
event.get("eventSource") != "signin.amazonaws.com"
and event.get("eventName") != "ConsoleLogin"
Expand All @@ -18,7 +17,6 @@ def rule(event):


def title(event):

arn = deep_get(event, "userIdenity", "arn", default="No ARN")
username = deep_get(event, "userIdentity", "userName", default="No Username")

Expand Down
3 changes: 2 additions & 1 deletion rules/aws_cloudtrail_rules/aws_console_login_without_mfa.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@

from panther_base_helpers import aws_rule_context, deep_get
from panther_default import lookup_aws_account_name
from panther_oss_helpers import check_account_age
from panther_detection_helpers.caching import check_account_age

# Set to True for environments that permit direct role assumption via external IDP
ROLES_VIA_EXTERNAL_IDP = False


# pylint: disable=R0911,R0912,R1260
def rule(event):
if event.get("eventName") != "ConsoleLogin":
Expand Down
1 change: 0 additions & 1 deletion rules/aws_cloudtrail_rules/aws_ec2_monitoring.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@


def rule(event):

# Disqualify any eventSource that is not ec2
if event.get("eventSource", "") != "ec2.amazonaws.com":
return False
Expand Down
1 change: 0 additions & 1 deletion rules/aws_cloudtrail_rules/aws_s3_activity_greynoise.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ 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):
# Only Greynoise advanced provides AS organization info
Expand Down
1 change: 1 addition & 0 deletions rules/aws_eks_rules/system_namespace_public_ip.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
# which are run as Lambdas and originate from public IPs
AMZ_PUBLICS = {"eks:addon-manager", "eks:node-manager"}


# Alert if
# the username starts ( with system: or eks: )
# and
Expand Down
1 change: 0 additions & 1 deletion rules/crowdstrike_rules/crowdstrike_base64_encoded_args.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ def rule(event):
# Define a regular expression pattern to match Base64 encoded strings

if event.get("event_platform") == "Win":

base64_pattern = re.compile(
r"^(\W|)(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?(\W|)$"
)
Expand Down
3 changes: 1 addition & 2 deletions rules/github_rules/github_repo_initial_access.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from global_filter_github import filter_include_event
from panther_oss_helpers import get_string_set, put_string_set
from panther_detection_helpers.caching import get_string_set, put_string_set

CODE_ACCESS_ACTIONS = [
"git.clone",
Expand All @@ -16,7 +16,6 @@ def rule(event):
return False

if event.get("action") in CODE_ACCESS_ACTIONS and not event.get("repository_public"):

# Compute unique entry for this user + repo
key = get_key(event)
previous_access = get_string_set(key)
Expand Down
3 changes: 2 additions & 1 deletion rules/indicator_creation_rules/new_aws_account_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
from datetime import timedelta

import panther_event_type_helpers as event_type
from panther_oss_helpers import put_string_set, resolve_timestamp_string
from panther_detection_helpers.caching import put_string_set
from panther_oss_helpers import resolve_timestamp_string

# Days an account is considered new
TTL = timedelta(days=3)
Expand Down
3 changes: 2 additions & 1 deletion rules/indicator_creation_rules/new_user_account_logging.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from datetime import timedelta

import panther_event_type_helpers as event_type
from panther_oss_helpers import put_string_set, resolve_timestamp_string
from panther_detection_helpers.caching import put_string_set
from panther_oss_helpers import resolve_timestamp_string

# Days an account is considered new
TTL = timedelta(days=3)
Expand Down
1 change: 0 additions & 1 deletion rules/okta_rules/okta_api_key_created.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ def rule(event):


def title(event):

target = event.get("target", [{}])
key_name = target[0].get("displayName", "MISSING DISPLAY NAME") if target else "MISSING TARGET"

Expand Down
6 changes: 5 additions & 1 deletion rules/okta_rules/okta_geo_improbable_access.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
from math import asin, cos, radians, sin, sqrt

from panther_base_helpers import deep_get, okta_alert_context
from panther_oss_helpers import get_string_set, put_string_set, set_key_expiration
from panther_detection_helpers.caching import (
get_string_set,
put_string_set,
set_key_expiration,
)

PANTHER_TIME_FORMAT = "%Y-%m-%d %H:%M:%S.%f"
EVENT_CITY_TRACKING = {}
Expand Down
2 changes: 1 addition & 1 deletion rules/onelogin_rules/onelogin_active_login_activity.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import time

from panther_base_helpers import is_ip_in_network
from panther_oss_helpers import (
from panther_detection_helpers.caching import (
add_to_string_set,
get_string_set,
put_string_set,
Expand Down
1 change: 0 additions & 1 deletion rules/onelogin_rules/onelogin_high_risk_failed_login.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
def rule(event):

# check risk associated with this event
if event.get("risk_score", 0) > 50:
# a failed authentication attempt with high risk
Expand Down
3 changes: 1 addition & 2 deletions rules/onelogin_rules/onelogin_high_risk_login.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import time

from panther_oss_helpers import (
from panther_detection_helpers.caching import (
get_counter,
increment_counter,
reset_counter,
Expand All @@ -11,7 +11,6 @@


def rule(event):

# Filter events down to successful and failed login events
if not event.get("user_id") or str(event.get("event_type_id")) not in ["5", "6"]:
return False
Expand Down
1 change: 0 additions & 1 deletion rules/onelogin_rules/onelogin_password_accessed.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
def rule(event):

# Filter events; event type 240 is actor_user revealed user's app password
if (
str(event.get("event_type_id")) != "240"
Expand Down
1 change: 0 additions & 1 deletion rules/onelogin_rules/onelogin_password_changed.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
def rule(event):

# check that this is a password change event;
# event id 11 is actor_user changed password for user
# Normally, admin's may change a user's password (event id 211)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
def rule(event):

# verify this is a auth factor being removed
# event id 24 is otp device deregistration
# event id 172 is a user deleted an authentication factor
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
def rule(event):

# filter events; event type 17 is a user deleted
return str(event.get("event_type_id")) == "17"

Expand Down
2 changes: 1 addition & 1 deletion rules/onelogin_rules/onelogin_unusual_login.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import json

import requests
from panther_oss_helpers import get_string_set, put_string_set
from panther_detection_helpers.caching import get_string_set, put_string_set

FINGERPRINT_THRESHOLD = 3
EVENT_LOGIN_INFO = {}
Expand Down
1 change: 0 additions & 1 deletion rules/onelogin_rules/onelogin_user_account_locked.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
def rule(event):

# check for a user locked event
# event 531 and 553 are user lock events via api
# event 551 is user suspended via api
Expand Down
1 change: 0 additions & 1 deletion rules/onelogin_rules/onelogin_user_assumed.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
def rule(event):

# check that this is a user assumption event; event id 3
return str(event.get("event_type_id")) == "3" and event.get(
"actor_user_id", "UNKNOWN_USER"
Expand Down
6 changes: 5 additions & 1 deletion rules/slack_rules/slack_application_dos.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@
from json import dumps

from panther_base_helpers import deep_get, slack_alert_context
from panther_oss_helpers import get_string_set, put_string_set, set_key_expiration
from panther_detection_helpers.caching import (
get_string_set,
put_string_set,
set_key_expiration,
)

DENIAL_OF_SERVICE_ACTIONS = [
"bulk_session_reset_by_admin",
Expand Down
8 changes: 2 additions & 6 deletions rules/standard_rules/impossible_travel_login.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,9 @@

import panther_event_type_helpers as event_type
from panther_base_helpers import deep_get
from panther_detection_helpers.caching import get_string_set, put_string_set
from panther_lookuptable_helpers import LookupTableMatches
from panther_oss_helpers import (
get_string_set,
km_between_ipinfo_loc,
put_string_set,
resolve_timestamp_string,
)
from panther_oss_helpers import km_between_ipinfo_loc, resolve_timestamp_string

# pylint: disable=global-variable-undefined

Expand Down
8 changes: 2 additions & 6 deletions rules/standard_rules/unusual_login_deprecated.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,8 @@
import logging

import panther_event_type_helpers as event_type
from panther_oss_helpers import (
add_parse_delay,
geoinfo_from_ip,
get_string_set,
put_string_set,
)
from panther_detection_helpers.caching import get_string_set, put_string_set
from panther_oss_helpers import add_parse_delay, geoinfo_from_ip

# number of unique geolocation city:region combinations retained in the
# panther-kv-table in Dynamo to suppress alerts
Expand Down