From a519c40f46efd1f6a9fac29a5608ae33b1dc254b Mon Sep 17 00:00:00 2001 From: Ariel Ropek Date: Wed, 13 Dec 2023 11:18:40 -0700 Subject: [PATCH] new and improved Notion rules for demo --- .../notion_rules/notion_page_shared_to_web.py | 8 +- .../notion_scim_token_generated.py | 6 +- .../notion_sharing_settings_updated.py | 32 +++++++ .../notion_sharing_settings_updated.yml | 69 ++++++++++++++ .../notion_teamspace_owner_added.py | 26 ++++++ .../notion_teamspace_owner_added.yml | 90 +++++++++++++++++++ .../notion_workspace_audit_log_exported.py | 6 +- .../notion_workspace_audit_log_exported.yml | 2 +- 8 files changed, 225 insertions(+), 14 deletions(-) create mode 100644 rules/notion_rules/notion_sharing_settings_updated.py create mode 100644 rules/notion_rules/notion_sharing_settings_updated.yml create mode 100644 rules/notion_rules/notion_teamspace_owner_added.py create mode 100644 rules/notion_rules/notion_teamspace_owner_added.yml diff --git a/rules/notion_rules/notion_page_shared_to_web.py b/rules/notion_rules/notion_page_shared_to_web.py index 842a44eab..a9e6373a6 100644 --- a/rules/notion_rules/notion_page_shared_to_web.py +++ b/rules/notion_rules/notion_page_shared_to_web.py @@ -16,12 +16,12 @@ def rule(event): def title(event): user = event.deep_get("event", "actor", "person", "email", default="") - page_id = event.deep_get("event", "details", "target", "page_id", default="") - return f"Notion User [{user}] changed the status of page [{page_id}] to public." + page_name = event.deep_get("event", "details", "page_name", default="") + return f"Notion User [{user}] changed the status of page [{page_name}] to public." def alert_context(event): context = notion_alert_context(event) - page_id = event.deep_get("event", "details", "target", "page_id", default="") - context["page_id"] = page_id + page_name = event.deep_get("event", "details", "page_name", default="") + context["page_name"] = page_name return context diff --git a/rules/notion_rules/notion_scim_token_generated.py b/rules/notion_rules/notion_scim_token_generated.py index 15d166c02..58402495d 100644 --- a/rules/notion_rules/notion_scim_token_generated.py +++ b/rules/notion_rules/notion_scim_token_generated.py @@ -12,11 +12,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="") - token_id = event.deep_get("event", "workspace", "scim_token_generated", default="{}") - return ( - f"Notion User [{user}] generated a SCIM token " - f"[{token_id}] for workspace id [{workspace_id}]." - ) + return f"Notion User [{user}] generated a SCIM token for workspace id [{workspace_id}]." def alert_context(event): diff --git a/rules/notion_rules/notion_sharing_settings_updated.py b/rules/notion_rules/notion_sharing_settings_updated.py new file mode 100644 index 000000000..d192ece20 --- /dev/null +++ b/rules/notion_rules/notion_sharing_settings_updated.py @@ -0,0 +1,32 @@ +from panther_notion_helpers import notion_alert_context + +EVENTS = ( + "teamspace.settings.allow_public_page_sharing_setting_updated", + "teamspace.settings.allow_guests_setting_updated", + "teamspace.settings.allow_content_export_setting_updated", + "workspace.settings.allow_public_page_sharing_setting_updated", + "workspace.settings.allow_guests_setting_updated", + "workspace.settings.allow_content_export_setting_updated", +) + + +def rule(event): + return all( + [ + event.deep_get("event", "type", default="") in EVENTS, + event.deep_get("event", "details", "state", default="") == "enabled", + ] + ) + + +def title(event): + actor = event.deep_get("event", "actor", "person", "email", default="NO_ACTOR_FOUND") + action = event.deep_get("event", "type", default="NO.EVENT.FOUND").split(".")[2] + teamspace = event.deep_get("event", "details", "target", "name", default=None) + if teamspace: + return f"[{actor}] enabled [{action}] for [{teamspace}] Teamspace" + return f"[{actor}] enabled [{action}] for Workspace" + + +def alert_context(event): + return notion_alert_context(event) diff --git a/rules/notion_rules/notion_sharing_settings_updated.yml b/rules/notion_rules/notion_sharing_settings_updated.yml new file mode 100644 index 000000000..a5b893ee4 --- /dev/null +++ b/rules/notion_rules/notion_sharing_settings_updated.yml @@ -0,0 +1,69 @@ +AnalysisType: rule +Filename: notion_sharing_settings_updated.py +RuleID: "Notion.SharingSettingsUpdated" +DisplayName: "Notion Sharing Settings Updated" +Enabled: true +LogTypes: + - Notion.AuditLogs +Tags: + - Notion + - Data Exfiltration +Description: A Notion User enabled sharing for a Workspace or Teamspace. +Severity: Medium +DedupPeriodMinutes: 60 +Threshold: 1 +Runbook: Possible Data Exfiltration. Follow up with the Notion User to determine if this was done for a valid business reason. +Tests: + - ExpectedResult: true + Log: + { + "event": { + "actor": { + "id": "c16137bb-5078-4eac-b026-5cbd2f9a027a", + "object": "user", + "person": { + "email": "aaron@example.com" + }, + "type": "person" + }, + "details": { + "state": "enabled", + }, + "id": "91b29a4b-4978-40e1-ab56-40221f801ce5", + "ip_address": "11.22.33.44", + "platform": "web", + "timestamp": "2023-12-13 16:39:06.860000000", + "type": "workspace.settings.allow_guests_setting_updated", + "workspace_id": "ea65b016-6abc-4dcf-808b-e119617b55d1" + }, + } + Name: Sharing Enabled + - ExpectedResult: false + Log: + { + "event": { + "actor": { + "id": "c16137bb-5078-4eac-b026-5cbd2f9a027a", + "object": "user", + "person": { + "email": "aaron@example.com" + }, + "type": "person" + }, + "details": { + "state": "disabled", + "target": { + "id": "a70a4074-5cac-4fc5-8e59-109df81e5a93", + "name": "R&D", + "object": "teamspace" + } + }, + "id": "91b29a4b-4978-40e1-ab56-40221f801ce5", + "ip_address": "11.22.33.44", + "platform": "web", + "timestamp": "2023-12-13 16:39:06.860000000", + "type": "teamspace.settings.allow_guests_setting_updated", + "workspace_id": "ea65b016-6abc-4dcf-808b-e119617b55d1" + }, + } + Name: Sharing Disabled diff --git a/rules/notion_rules/notion_teamspace_owner_added.py b/rules/notion_rules/notion_teamspace_owner_added.py new file mode 100644 index 000000000..510028495 --- /dev/null +++ b/rules/notion_rules/notion_teamspace_owner_added.py @@ -0,0 +1,26 @@ +from panther_notion_helpers import notion_alert_context + + +def rule(event): + added = ( + event.deep_get("event", "type", default="") == "teamspace.permissions.member_added" + and event.deep_get("event", "details", "role", default="") == "owner" + ) + updated = ( + event.deep_get("event", "type", default="") == "teamspace.permissions.member_role_updated" + and event.deep_get("event", "details", "new_role", default="") == "owner" + ) + return added or updated + + +def title(event): + actor = event.deep_get("event", "actor", "person", "email", default="NO_ACTOR_FOUND") + member = event.deep_get( + "event", "details", "member", "person", "email", default="NO_MEMBER_FOUND" + ) + teamspace = event.deep_get("event", "details", "target", "name", default="NO_TEAMSPACE_FOUND") + return f"[{actor}] added [{member}] as owner of [{teamspace}] Teamspace" + + +def alert_context(event): + return notion_alert_context(event) diff --git a/rules/notion_rules/notion_teamspace_owner_added.yml b/rules/notion_rules/notion_teamspace_owner_added.yml new file mode 100644 index 000000000..9acbb9514 --- /dev/null +++ b/rules/notion_rules/notion_teamspace_owner_added.yml @@ -0,0 +1,90 @@ +AnalysisType: rule +Filename: notion_teamspace_owner_added.py +RuleID: "Notion.TeamspaceOwnerAdded" +DisplayName: "Notion Teamspace Owner Added" +Enabled: true +LogTypes: + - Notion.AuditLogs +Tags: + - Notion + - Privilege Escalation +Description: A Notion User was added as a Teamspace owner. +Severity: Medium +DedupPeriodMinutes: 60 +Threshold: 1 +Runbook: Possible Privilege Escalation. Follow up with the Notion User to determine if this was done for a valid business reason. +Tests: + - ExpectedResult: false + Log: + { + "event": { + "actor": { + "id": "c16137bb-5078-4eac-b026-5cbd2f9a027a", + "object": "user", + "person": { + "email": "bill@example.com" + }, + "type": "person" + }, + "details": { + "member": { + "id": "c16137bb-5078-4eac-b026-5cbd2f9a027a", + "object": "user", + "person": { + "email": "bob@example.com" + }, + "type": "person" + }, + "role": "member", + "target": { + "id": "b8db234d-71eb-49e2-a5ed-7935ca764920", + "name": "General", + "object": "teamspace" + } + }, + "id": "eed75a56-ca1b-453b-afd8-73789bc19398", + "ip_address": "11.22.33.44", + "platform": "web", + "timestamp": "2023-12-13 16:20:14.966000000", + "type": "teamspace.permissions.member_added", + "workspace_id": "ea65b016-6abc-4dcf-808b-e119617b55d1" + } + } + Name: Member Added + - ExpectedResult: true + Log: + { + "event": { + "actor": { + "id": "c16137bb-5078-4eac-b026-5cbd2f9a027a", + "object": "user", + "person": { + "email": "malicious.insider@example.com" + }, + "type": "person" + }, + "details": { + "member": { + "id": "c16137bb-5078-4eac-b026-5cbd2f9a027a", + "object": "user", + "person": { + "email": "bad.dude@example.com" + }, + "type": "person" + }, + "new_role": "owner", + "target": { + "id": "b8db234d-71eb-49e2-a5ed-7935ca764920", + "name": "General", + "object": "teamspace" + } + }, + "id": "6019b995-0158-4430-8263-89ad7905bd1d", + "ip_address": "11.22.33.44", + "platform": "web", + "timestamp": "2023-12-13 16:38:04.264000000", + "type": "teamspace.permissions.member_role_updated", + "workspace_id": "ea65b016-6abc-4dcf-808b-e119617b55d1" + } + } + Name: Owner Added diff --git a/rules/notion_rules/notion_workspace_audit_log_exported.py b/rules/notion_rules/notion_workspace_audit_log_exported.py index 196a6da8d..5cde6de6a 100644 --- a/rules/notion_rules/notion_workspace_audit_log_exported.py +++ b/rules/notion_rules/notion_workspace_audit_log_exported.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 @@ -13,10 +12,9 @@ def rule(event): def title(event): user = event.deep_get("event", "actor", "person", "email", default="") workspace_id = event.deep_get("event", "workspace_id", default="") - duration_in_days = deep_get( - event, + duration_in_days = event.deep_get( "event", - "workspace.audit_log_exported", + "details", "duration_in_days", default="", ) diff --git a/rules/notion_rules/notion_workspace_audit_log_exported.yml b/rules/notion_rules/notion_workspace_audit_log_exported.yml index f18a3a767..d85b97582 100644 --- a/rules/notion_rules/notion_workspace_audit_log_exported.yml +++ b/rules/notion_rules/notion_workspace_audit_log_exported.yml @@ -56,7 +56,7 @@ Tests: "ip_address": "...", "platform": "web", "type": "workspace.audit_log_exported", - "workspace.audit_log_exported": { + "details": { "duration_in_days": 30 } }