Skip to content

Commit

Permalink
Merge branch 'develop' into THREAT-403-Create-rules-for-User,-Adminis…
Browse files Browse the repository at this point in the history
…trator,-and-Role-Management-based-on-test-cases
  • Loading branch information
ben-githubs authored Nov 6, 2024
2 parents 657d855 + 5132f6a commit 103f8af
Show file tree
Hide file tree
Showing 72 changed files with 1,271 additions and 81 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/check-packs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ jobs:
panther_analysis_tool check-packs || echo "errors=`cat errors.txt`" >> $GITHUB_OUTPUT
- name: Comment PR
uses: thollander/actions-comment-pull-request@e2c37e53a7d2227b61585343765f73a9ca57eda9
uses: thollander/actions-comment-pull-request@24bffb9b452ba05a4f3f77933840a6a841d1b32b
if: ${{ steps.check-packs.outputs.errors }}
with:
mode: upsert
Expand All @@ -57,7 +57,7 @@ jobs:
```
comment-tag: check-packs
- name: Delete comment
uses: thollander/actions-comment-pull-request@e2c37e53a7d2227b61585343765f73a9ca57eda9
uses: thollander/actions-comment-pull-request@24bffb9b452ba05a4f3f77933840a6a841d1b32b
if: ${{ !steps.check-packs.outputs.errors }}
with:
mode: delete
Expand Down
17 changes: 9 additions & 8 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Contributing to `panther-analysis`

Thank you for your interest in contributing to Panther's open-source ruleset! We appreciate all types of contributions, including new detection rules, feature requests, and bug reports.
Thank you for your interest in contributing to Panther's open-source ruleset! We appreciate all types of contributions, including new detection rules, feature requests, and bug reports.

## What makes a good detection?

Expand All @@ -19,18 +19,18 @@ Before submitting your pull request, make sure to:
- Write or update relevant unit tests
- Redact any sensitive information or PII from example logs
- Format, lint, and test your changes to ensure CI tests pass, using the following commands:
```bash
make fmt
make lint
make test
```
```bash
make fmt
make lint
make test
```

## Pull Request process

1. Make desired detection changes. This may include creating new detections in existing log type directories, creating new log type directories, updating existing detections, etc
2. Commit both the Python and Metadata files
3. Write a clear commit message
4. Open a [Pull Request](https://github.com/panther-labs/panther-analysis/pulls).
4. Open a [Pull Request](https://github.com/panther-labs/panther-analysis/pulls) against the `develop` branch.
5. Once your PR has been approved by code owners, if you have merge permissions, merge it. If you do not have merge permissions, leave a comment requesting a code owner merge it for you

## Code of Conduct
Expand All @@ -42,4 +42,5 @@ in all of your interactions with this project.

If you need assistance at any point, feel free to open a support ticket, or reach out to us on [Panther Community Slack](https://pnthr.io/community).

Thank you again for your contributions, and we look forward to working together!
Thank you again for your contributions, and we look forward to working together!

Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ Detection:
- ID: StopInstance FOLLOWED BY StartupScriptChange
From: StopInstance
To: StartupScriptChange
WithinTimeFrameMinutes: 90
Match:
- On: p_alert_context.instance_ids
LookbackWindowMinutes: 90
LookbackWindowMinutes: 2160
Schedule:
RateMinutes: 60
RateMinutes: 1440
TimeoutMinutes: 5
Tests:
- Name: Instance Stopped, Followed By Script Change
Expand Down
2 changes: 1 addition & 1 deletion correlation_rules/aws_console_sign-in_without_okta.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Detection:
Schedule:
RateMinutes: 1440
TimeoutMinutes: 5
LookbackWindowMinutes: 1440
LookbackWindowMinutes: 2160
Tests:
- Name: AWS Console Sign-In PRECEDED BY Okta Redirect
ExpectedResult: false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@ Detection:
- ID: User Backdoored TO User Accessed ON IP Addr
From: User Backdoored
To: User Accessed
WithinTimeFrameMinutes: 60
Match:
- On: p_alert_context.ip_accessKeyId
Schedule:
RateMinutes: 60
RateMinutes: 1440
TimeoutMinutes: 10
LookbackWindowMinutes: 90
LookbackWindowMinutes: 2160
Tests:
- Name: Access Key Created and Used from Same IP
ExpectedResult: true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Detection:
Schedule:
RateMinutes: 1440
TimeoutMinutes: 5
LookbackWindowMinutes: 1440
LookbackWindowMinutes: 2160
Tests:
- Name: AWS SSO Access Token Retrieved by Authenticated IP
ExpectedResult: false
Expand Down
5 changes: 3 additions & 2 deletions correlation_rules/aws_user_takeover_via_password_reset.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@ Detection:
- ID: Password Reset TO Login ON IP Addr
From: Password Reset
To: Login
WithinTimeFrameMinutes: 60
Match:
- On: p_alert_context.ip_and_username
Schedule:
RateMinutes: 60
RateMinutes: 1440
TimeoutMinutes: 10
LookbackWindowMinutes: 90
LookbackWindowMinutes: 2160
Tests:
- Name: Password Reset, Then Login From Same IP
ExpectedResult: true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,12 @@ Detection:
- ID: ServiceCreated FOLLOWED BY SetIAMPolicy
From: ServiceCreated
To: SetIAMPolicy
WithinTimeFrameMinutes: 90
Match:
- On: p_alert_context.caller_ip
LookbackWindowMinutes: 90
LookbackWindowMinutes: 2160
Schedule:
RateMinutes: 60
RateMinutes: 1440
TimeoutMinutes: 5
Tests:
- Name: GCP Service Run, Followed By IAM Policy Change From Same IP
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@ Detection:
- ID: GHASChange NOT FOLLOWED BY RepoArchived
From: RepoArchived
To: GHASChange
WithinTimeFrameMinutes: 60
Match:
- On: p_alert_context.repo
LookbackWindowMinutes: 90
LookbackWindowMinutes: 2160
Schedule:
RateMinutes: 60
RateMinutes: 1440
TimeoutMinutes: 10
Tests:
- Name: Security Change on Repo, Followed By Same Repo Archived
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Detection:
WithinTimeFrameMinutes: 15
Match:
- On: p_alert_context.actor_id
LookbackWindowMinutes: 1440
LookbackWindowMinutes: 2160
Schedule:
RateMinutes: 1440
TimeoutMinutes: 5
Expand Down
5 changes: 3 additions & 2 deletions correlation_rules/okta_login_without_push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,14 @@ Detection:
- ID: Okta to Push
From: Okta
To: Push
WithinTimeFrameMinutes: 60
Match:
- From: actor.alternateId
To: new.email
Schedule:
RateMinutes: 60
RateMinutes: 1440
TimeoutMinutes: 10
LookbackWindowMinutes: 90
LookbackWindowMinutes: 2160
Tests:
- Name: Okta Login, Followed By Push Authorized Login
ExpectedResult: false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Detection:
WithinTimeFrameMinutes: 15
Match:
- On: user_name
LookbackWindowMinutes: 1440
LookbackWindowMinutes: 2160
Schedule:
RateMinutes: 1440
TimeoutMinutes: 5
Expand Down
5 changes: 3 additions & 2 deletions correlation_rules/potential_compromised_okta_credentials.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,14 @@ Detection:
- ID: Match on user
From: Login Without Push Marker
To: Push Phishing
WithinTimeFrameMinutes: 60
Match:
- From: actor.alternateId
To: new.employee.email
Schedule:
RateMinutes: 60
RateMinutes: 1440
TimeoutMinutes: 10
LookbackWindowMinutes: 90
LookbackWindowMinutes: 2160
Tests:
- Name: Login Without Marker, Followed By Phishing Detection
ExpectedResult: true
Expand Down
5 changes: 3 additions & 2 deletions correlation_rules/secret_exposed_and_not_quarantined.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ Detection:
- ID: SecretFound TO SecretNotQuarantined
From: SecretFound
To: SecretNotQuarantined
WithinTimeFrameMinutes: 60
Schedule:
RateMinutes: 60
RateMinutes: 1440
TimeoutMinutes: 10
LookbackWindowMinutes: 90
LookbackWindowMinutes: 2160
Tests:
- Name: Secret Found and Quarantied
ExpectedResult: false
Expand Down
4 changes: 2 additions & 2 deletions correlation_rules/snowflake_data_exfiltration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ Detection:
Match:
- On: stage
Schedule:
RateMinutes: 720
RateMinutes: 1440
TimeoutMinutes: 15
LookbackWindowMinutes: 1440
LookbackWindowMinutes: 2160
Tests:
- Name: Data Exfiltration
ExpectedResult: true
Expand Down
47 changes: 47 additions & 0 deletions correlation_rules/snowflake_potential_brute_force_success.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
AnalysisType: correlation_rule
RuleID: "Snowflake.PotentialBruteForceSuccess"
DisplayName: "Snowflake Brute Force Login Success"
Enabled: true
Severity: High
Description: Detecting brute force activity and reporting when a user has incorrectly logged in multiple times and then had a successful login.
Detection:
- Sequence:
- ID: Multiple Failed Logins
RuleID: Snowflake.Stream.BruteForceByIp
MinMatchCount: 5
- ID: Successful Login
RuleID: Snowflake.Stream.LoginSuccess
Transitions:
- ID: Multiple Failed Logins FOLLOWED BY Successful Login
From: Multiple Failed Logins
To: Successful Login
WithinTimeFrameMinutes: 30
Match:
- On: CLIENT_IP
Schedule:
RateMinutes: 720
TimeoutMinutes: 15
LookbackWindowMinutes: 1440
Tests:
- Name: Successful Bulk Login
ExpectedResult: true
RuleOutputs:
- ID: Multiple Failed Logins
Matches:
CLIENT_IP:
"1.1.1.1": [0, 2, 3, 6, 9, 10, 11, 15]
- ID: Successful Login
Matches:
CLIENT_IP:
"1.1.1.1": [16]
- Name: Successful Login With Single Failure
ExpectedResult: false
RuleOutputs:
- ID: Multiple Failed Logins
Matches:
CLIENT_IP:
"1.1.1.1": [0]
- ID: Successful Login
Matches:
CLIENT_IP:
"1.1.1.1": [1]
4 changes: 2 additions & 2 deletions global_helpers/panther_aws_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def aws_strip_role_session_id(user_identity_arn):
return user_identity_arn


def aws_rule_context(event: dict):
def aws_rule_context(event):
return {
"eventName": event.get("eventName", "<MISSING_EVENT_NAME>"),
"eventSource": event.get("eventSource", "<MISSING_ACCOUNT_ID>"),
Expand All @@ -41,7 +41,7 @@ def aws_rule_context(event: dict):
}


def aws_guardduty_context(event: dict):
def aws_guardduty_context(event):
return {
"description": event.get("description", "<MISSING DESCRIPTION>"),
"severity": event.get("severity", "<MISSING SEVERITY>"),
Expand Down
2 changes: 1 addition & 1 deletion global_helpers/panther_box_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ def build_jwt_settings(response: dict) -> dict:

# 'additional_details' from box logs varies by event_type.
# This helper wraps the process of extracting those details.
def box_parse_additional_details(event: dict):
def box_parse_additional_details(event):
additional_details = event.get("additional_details", {})
if isinstance(additional_details, (str, bytes)):
try:
Expand Down
4 changes: 2 additions & 2 deletions global_helpers/panther_cloudflare_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def map_source_to_name(event: Any) -> str:
)


def cloudflare_fw_alert_context(event: dict = None):
def cloudflare_fw_alert_context(event=None):
keep_keys = [
"Action",
"ClientIP",
Expand All @@ -57,7 +57,7 @@ def cloudflare_fw_alert_context(event: dict = None):
return context_dict


def cloudflare_http_alert_context(event: dict = None):
def cloudflare_http_alert_context(event=None):
keep_keys = [
"BotScore",
"BotScoreSrc",
Expand Down
6 changes: 3 additions & 3 deletions global_helpers/panther_crowdstrike_fdr_helpers.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
def crowdstrike_detection_alert_context(event: dict):
def crowdstrike_detection_alert_context(event):
"""Returns common context for Crowdstrike detections"""
return {
"aid": get_crowdstrike_field(event, "aid", default=""),
Expand All @@ -13,7 +13,7 @@ def crowdstrike_detection_alert_context(event: dict):
}


def crowdstrike_process_alert_context(event: dict):
def crowdstrike_process_alert_context(event):
"""Returns common process context for Crowdstrike detections"""
return {
"aid": get_crowdstrike_field(event, "aid", default=""),
Expand All @@ -28,7 +28,7 @@ def crowdstrike_process_alert_context(event: dict):
}


def crowdstrike_network_detection_alert_context(event: dict):
def crowdstrike_network_detection_alert_context(event):
"""Returns common network context for Crowdstrike detections"""
return {
"LocalAddressIP4": get_crowdstrike_field(event, "LocalAddressIP4", default=""),
Expand Down
2 changes: 1 addition & 1 deletion global_helpers/panther_duo_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from json import JSONDecodeError


def deserialize_administrator_log_event_description(event: dict) -> dict:
def deserialize_administrator_log_event_description(event) -> dict:
"""Intelligently try and decode a field that is usually stringified json into a python dict.
This description field seems to take the form of stringified json, So this function
Expand Down
2 changes: 1 addition & 1 deletion global_helpers/panther_lookuptable_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def _lookup(self, match_field: str, *keys) -> list or str:
def p_matched(self):
return self._p_matched

def p_matches(self, event: dict, p_match: str = "") -> dict:
def p_matches(self, event, p_match: str = "") -> dict:
"""Collect enrichments by searching for a value match in the p_match field
Parameters:
Expand Down
2 changes: 1 addition & 1 deletion global_helpers/panther_okta_helpers.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
def okta_alert_context(event: dict):
def okta_alert_context(event):
"""Returns common context for automation of Okta alerts"""
return {
"event_type": event.get("eventtype", ""),
Expand Down
11 changes: 11 additions & 0 deletions global_helpers/panther_snowflake_helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
""" Global helpers for Snowflake streaming detections. """


def query_history_alert_context(event):
return {
"user": event.get("user_name", "<UNKNOWN USER>"),
"role": event.get("role_name", "<UNKNOWN ROLE>"),
"source": event.get("p_source_label", "<UNKNOWN SOURCE>"),
# Not all queries are run in a warehouse; e.g.: getting worksheet files
"warehouse": event.get("WAREHOUSE_NAME", "<NO WAREHOUSE>"),
}
5 changes: 5 additions & 0 deletions global_helpers/panther_snowflake_helpers.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
AnalysisType: global
Filename: panther_snowflake_helpers.py
GlobalID: "panther_snowflake_helpers"
Description: >
Global helpers for Snowflake streaming detections
Loading

0 comments on commit 103f8af

Please sign in to comment.