diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2078e8513..1a7f8ddf9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,7 +17,7 @@ jobs: fetch-depth: 0 token: ${{ env.GITHUB_TOKEN }} - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@010d0da01d0b5a38af31e9c3470dbfdabdecca3a # v4.0.1 + uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2 with: role-to-assume: ${{ secrets.AWS_ROLE }} aws-region: ${{ secrets.AWS_REGION }} diff --git a/Pipfile b/Pipfile index 7fc86308c..95e4f9a9f 100644 --- a/Pipfile +++ b/Pipfile @@ -19,7 +19,7 @@ wrapt = "~=1.15" [packages] policyuniverse = "==1.5.1.20230817" requests = "==2.31.0" -panther-analysis-tool = "~=0.39" +panther-analysis-tool = "~=0.40" panther-detection-helpers = "==0.2.0" [requires] diff --git a/Pipfile.lock b/Pipfile.lock index f22df0f43..4204c9c87 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "d2d43cb0e38e6667b7f9fc5f22dc91cfe095a2e0c7825c2e9105a18dbfeae942" + "sha256": "ef3121c751224143c7f27939ddd036b7a8b5a454d45de632892d1a4369805548" }, "pipfile-spec": 6, "requires": { @@ -147,19 +147,19 @@ }, "boto3": { "hashes": [ - "sha256:7c70c6ceb2706c7fad6466a5de174fe6d0d6f5f8f1e052bfaad9cbe4e53b64cd", - "sha256:e74fbad79bc921a74a9a276ef9f38e1e31153f76690fe9bc5ec790007de36572" + "sha256:9fd66f22a4cdd63165a7a19186fff9b6e3d742e83498ea3f3231bab6ae4bf0f3", + "sha256:ae1a974c728c076a49392a695102124f650f45361c654bb7c0bef1bb644c52d5" ], "markers": "python_version >= '3.8'", - "version": "==1.34.38" + "version": "==1.34.41" }, "botocore": { "hashes": [ - "sha256:773e49f5bf596191e796b2a15096ff381e61778cbe7c982b381bb9f6bfe5fef3", - "sha256:da9754a8e1798706427ede9c9c0a55263bd8e57f217c021807b2946eb4a0c2d8" + "sha256:3a6943c75a0d292ab6e008bce58ee6503776969479f991f5ad03a5d877af29ae", + "sha256:9b5827332da766da487e5a5b14b36e02528be9f2e899f909577afb7001eb441d" ], "markers": "python_version >= '3.8'", - "version": "==1.34.38" + "version": "==1.34.41" }, "certifi": { "hashes": [ @@ -668,10 +668,10 @@ }, "panther-analysis-tool": { "hashes": [ - "sha256:70bea9cbadd820ae2e77361e966320e058d5d16ebbc8d730298b0606844e934c" + "sha256:54534d08ef27e35186a7e5cfbc2eb7970132d615367372906d2065e030164718" ], "index": "pypi", - "version": "==0.39.0" + "version": "==0.40.0" }, "panther-core": { "hashes": [ @@ -715,6 +715,7 @@ "sha256:7920896195af163230635f1a5cee0958f56003ef8c421f805ec81f134f80a57c" ], "index": "pypi", + "markers": "python_version >= '3.7'", "version": "==1.5.1.20230817" }, "pygments": { @@ -738,7 +739,7 @@ "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==2.8.2" }, "pyyaml": { @@ -911,6 +912,7 @@ "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1" ], "index": "pypi", + "markers": "python_version >= '3.7'", "version": "==2.31.0" }, "rpds-py": { @@ -1079,7 +1081,7 @@ "sha256:f481f16baec5290e45aebdc2a5168ebc6d35189ae6fea7a58787613a25f6e875", "sha256:fff3573c2db359f091e1589c3d7c5fc2f86f5bdb6f24252c2d8e539d4e45f412" ], - "markers": "platform_python_implementation == 'CPython' and python_version < '3.13'", + "markers": "python_version < '3.13' and platform_python_implementation == 'CPython'", "version": "==0.2.8" }, "s3transfer": { @@ -1110,7 +1112,7 @@ "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.16.0" }, "sniffio": { @@ -1155,11 +1157,11 @@ }, "tqdm": { "hashes": [ - "sha256:d302b3c5b53d47bce91fea46679d9c3c6508cf6332229aa1e7d8653723793386", - "sha256:d88e651f9db8d8551a62556d3cff9e3034274ca5d66e93197cf2490e2dcb69c7" + "sha256:1ee4f8a893eb9bef51c6e35730cebf234d5d0b6bd112b0271e10ed7c24a02bd9", + "sha256:6cd52cdf0fef0e0f543299cfc96fec90d7b8a7e88745f411ec33eb44d5ed3531" ], "markers": "python_version >= '3.7'", - "version": "==4.66.1" + "version": "==4.66.2" }, "typing-extensions": { "hashes": [ @@ -1289,6 +1291,7 @@ "sha256:527906bec6088cb499aae31bc962864b4e77569e9d529ee51df3a93b4b8ab28a" ], "index": "pypi", + "markers": "python_version >= '3.8'", "version": "==1.7.7" }, "black": { @@ -1307,23 +1310,24 @@ "sha256:d30b212bffeb1e252b31dd269dfae69dd17e06d92b87ad26e23890f3efea366f" ], "index": "pypi", + "markers": "python_version >= '3.7'", "version": "==22.12.0" }, "boto3": { "hashes": [ - "sha256:7c70c6ceb2706c7fad6466a5de174fe6d0d6f5f8f1e052bfaad9cbe4e53b64cd", - "sha256:e74fbad79bc921a74a9a276ef9f38e1e31153f76690fe9bc5ec790007de36572" + "sha256:9fd66f22a4cdd63165a7a19186fff9b6e3d742e83498ea3f3231bab6ae4bf0f3", + "sha256:ae1a974c728c076a49392a695102124f650f45361c654bb7c0bef1bb644c52d5" ], "markers": "python_version >= '3.8'", - "version": "==1.34.38" + "version": "==1.34.41" }, "botocore": { "hashes": [ - "sha256:773e49f5bf596191e796b2a15096ff381e61778cbe7c982b381bb9f6bfe5fef3", - "sha256:da9754a8e1798706427ede9c9c0a55263bd8e57f217c021807b2946eb4a0c2d8" + "sha256:3a6943c75a0d292ab6e008bce58ee6503776969479f991f5ad03a5d877af29ae", + "sha256:9b5827332da766da487e5a5b14b36e02528be9f2e899f909577afb7001eb441d" ], "markers": "python_version >= '3.8'", - "version": "==1.34.38" + "version": "==1.34.41" }, "certifi": { "hashes": [ @@ -1539,6 +1543,7 @@ "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186" ], "index": "pypi", + "markers": "python_version >= '3.5'", "version": "==5.1.1" }, "dill": { @@ -1547,6 +1552,7 @@ "sha256:c36ca9ffb54365bdd2f8eb3eff7d2a21237f8452b57ace88b1ac615b7e815bd7" ], "index": "pypi", + "markers": "python_version >= '3.8'", "version": "==0.3.8" }, "idna": { @@ -1563,6 +1569,7 @@ "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6" ], "index": "pypi", + "markers": "python_full_version >= '3.8.0'", "version": "==5.13.2" }, "jinja2": { @@ -1720,6 +1727,7 @@ "sha256:94e3b07a403cc8078ffee94bf404ef677112d036a57ddb5e0f19c5fcf48987f5" ], "index": "pypi", + "markers": "python_version >= '3.8'", "version": "==5.0.1" }, "mypy": { @@ -1753,6 +1761,7 @@ "sha256:f5ac9a4eeb1ec0f1ccdc6f326bcdb464de5f80eb07fb38b5ddd7b0de6bc61e55" ], "index": "pypi", + "markers": "python_version >= '3.8'", "version": "==1.8.0" }, "mypy-extensions": { @@ -1808,6 +1817,7 @@ "sha256:f4fcac7ae74cfe36bc8451e931d8438e4a476c20314b1101c458ad0f05191fad" ], "index": "pypi", + "markers": "python_full_version >= '3.7.2'", "version": "==2.17.7" }, "pylint-print": { @@ -1816,6 +1826,7 @@ "sha256:a2b2599e7887b93e551db2624c523c1e6e9e58c3be8416cd98d41e4427e2669b" ], "index": "pypi", + "markers": "python_version >= '3.6'", "version": "==1.0.1" }, "python-dateutil": { @@ -1823,7 +1834,7 @@ "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==2.8.2" }, "pyyaml": { @@ -1889,15 +1900,16 @@ "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1" ], "index": "pypi", + "markers": "python_version >= '3.7'", "version": "==2.31.0" }, "responses": { "hashes": [ - "sha256:a2b43f4c08bfb9c9bd242568328c65a34b318741d3fab884ac843c5ceeb543f9", - "sha256:b127c6ca3f8df0eb9cc82fd93109a3007a86acb24871834c47b77765152ecf8c" + "sha256:01ae6a02b4f34e39bffceb0fc6786b67a25eae919c6368d05eabc8d9576c2a66", + "sha256:2f0b9c2b6437db4b528619a77e5d565e4ec2a9532162ac1a131a83529db7be1a" ], "markers": "python_version >= '3.8'", - "version": "==0.24.1" + "version": "==0.25.0" }, "rich": { "hashes": [ @@ -1920,7 +1932,7 @@ "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.16.0" }, "stevedore": { @@ -2045,6 +2057,7 @@ "sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4" ], "index": "pypi", + "markers": "python_version >= '3.6'", "version": "==1.16.0" }, "xmltodict": { diff --git a/data_models/github_data_model.py b/data_models/github_data_model.py index b6f337089..5ab24efb8 100644 --- a/data_models/github_data_model.py +++ b/data_models/github_data_model.py @@ -6,14 +6,25 @@ "team.promote_maintainer", } +CONDITIONAL_ADMIN_EVENTS = { + "team.add_repository", +} + def get_admin_role(event): action = event.get("action", "") + permission = event.get("permission", "") + if action in CONDITIONAL_ADMIN_EVENTS and permission == "admin": + return action return action if action in ADMIN_EVENTS else "" def get_event_type(event): - if event.get("action", "") in ADMIN_EVENTS: + action = event.get("action", "") + permission = event.get("permission", "") + if action in ADMIN_EVENTS: + return event_type.ADMIN_ROLE_ASSIGNED + if action in CONDITIONAL_ADMIN_EVENTS and permission == "admin": return event_type.ADMIN_ROLE_ASSIGNED if event.get("action", "") == "org.disable_two_factor_requirement": return event_type.MFA_DISABLED diff --git a/lookup_tables/tor/tor_exit_nodes.yml b/lookup_tables/tor/tor_exit_nodes.yml index 672fd65f3..705b7f5e2 100644 --- a/lookup_tables/tor/tor_exit_nodes.yml +++ b/lookup_tables/tor/tor_exit_nodes.yml @@ -211,6 +211,7 @@ LogTypeMap: - "$.protoPayload.requestMetadata.callerIP" - "$.httpRequest.remoteIP" - "$.httpRequest.serverIP" + - "$.requestMetadata.callerIP" - LogType: GCP.HTTPLoadBalancer Selectors: - "$.jsonPayload.removeIp" diff --git a/packs/auth0.yml b/packs/auth0.yml index 820572892..5ffb82d9d 100644 --- a/packs/auth0.yml +++ b/packs/auth0.yml @@ -5,6 +5,7 @@ PackDefinition: IDs: - Auth0.Custom.Role.Created - Auth0.Integration.Installed + - Auth0.MFA.Factor.Setting.Enabled - Auth0.MFA.Policy.Disabled - Auth0.MFA.Policy.Enabled - Auth0.MFA.Risk.Assessment.Disabled diff --git a/packs/aws.yml b/packs/aws.yml index 4731a9f09..240f46368 100644 --- a/packs/aws.yml +++ b/packs/aws.yml @@ -49,6 +49,7 @@ PackDefinition: # Root Activity - AWS.CloudTrail.RootAccessKeyCreated - AWS.CloudTrail.RootPasswordChanged + - AWS.Console.RootLogin - AWS.Console.RootLoginFailed - AWS.EC2.Instance.DetailedMonitoring - AWS.Root.Activity @@ -110,6 +111,7 @@ PackDefinition: - AWS.GuardDuty.MediumSeverityFinding - AWS.IAM.Policy.AdministrativePrivileges - AWS.RDS.InstanceHighAvailability + - AWS.RDS.ManualSnapshotCreated - AWS.RDS.MasterPasswordUpdated - AWS.RDS.PublicRestore - AWS.RDS.SnapshotShared diff --git a/packs/carbonblack.yml b/packs/carbonblack.yml index dbdba1d36..7a815c6ad 100644 --- a/packs/carbonblack.yml +++ b/packs/carbonblack.yml @@ -3,6 +3,7 @@ PackID: PantherManaged.CarbonBlack Description: Group of all Carbon Black detections PackDefinition: IDs: + - CarbonBlack.AlertV2.Passthrough - CarbonBlack.Audit.Admin.Grant - CarbonBlack.Audit.API.Key.Created.Retrieved - CarbonBlack.Audit.Data.Forwarder.Stopped diff --git a/packs/cloudflare.yml b/packs/cloudflare.yml index 003d30f21..332d00808 100644 --- a/packs/cloudflare.yml +++ b/packs/cloudflare.yml @@ -6,6 +6,8 @@ PackDefinition: IDs: - Cloudflare.Firewall.L7DDoS - Cloudflare.Firewall.SuspiciousEventGreyNoise + - Cloudflare.HttpRequest.BotHighVolume + - Cloudflare.HttpRequest.BotHighVolumeGreyNoise # Globals used in these rules/policies - panther_base_helpers - panther_cloudflare_helpers diff --git a/packs/gcp_audit.yml b/packs/gcp_audit.yml index bbd68c422..0a689a423 100644 --- a/packs/gcp_audit.yml +++ b/packs/gcp_audit.yml @@ -36,6 +36,8 @@ PackDefinition: - GCP.VPC.Flow.Logs.Disabled - GCP.Workforce.Pool.Created.or.Updated - GCP.Workload.Identity.Pool.Created.or.Updated + - GCP.Storage.Hmac.Keys.Create + - GCP.K8s.New.Daemonset.Deployed # Data model - Standard.GCP.AuditLog # Globals used in these rules/policies diff --git a/rules/aws_cloudtrail_rules/aws_cloudtrail_unsuccessful_mfa_attempt.yml b/rules/aws_cloudtrail_rules/aws_cloudtrail_unsuccessful_mfa_attempt.yml index 138703915..a7f7004e1 100644 --- a/rules/aws_cloudtrail_rules/aws_cloudtrail_unsuccessful_mfa_attempt.yml +++ b/rules/aws_cloudtrail_rules/aws_cloudtrail_unsuccessful_mfa_attempt.yml @@ -4,6 +4,8 @@ DisplayName: "AWS Unsuccessful MFA attempt" Enabled: false Filename: aws_cloudtrail_unsuccessful_mfa_attempt.py Reference: https://attack.mitre.org/techniques/T1621/ +Tags: + - Configuration Required # configure threshold for multiple MFA failures Reports: MITRE ATT&CK: - TA0006:T1621 diff --git a/rules/aws_cloudtrail_rules/aws_console_root_login.yml b/rules/aws_cloudtrail_rules/aws_console_root_login.yml index e5096871f..1fef21db3 100644 --- a/rules/aws_cloudtrail_rules/aws_console_root_login.yml +++ b/rules/aws_cloudtrail_rules/aws_console_root_login.yml @@ -2,7 +2,7 @@ AnalysisType: rule Filename: aws_console_root_login.py RuleID: "AWS.Console.RootLogin" DisplayName: "Root Console Login" -Enabled: false +Enabled: true DedupPeriodMinutes: 15 LogTypes: - AWS.CloudTrail diff --git a/rules/aws_cloudtrail_rules/aws_lambda_crud.yml b/rules/aws_cloudtrail_rules/aws_lambda_crud.yml index 8ca1cb70c..879053ce1 100644 --- a/rules/aws_cloudtrail_rules/aws_lambda_crud.yml +++ b/rules/aws_cloudtrail_rules/aws_lambda_crud.yml @@ -8,6 +8,7 @@ LogTypes: Tags: - AWS - Security Control + - Configuration Required Reports: CIS: - 3.12 diff --git a/rules/aws_cloudtrail_rules/aws_rds_manual_snapshot_created.yml b/rules/aws_cloudtrail_rules/aws_rds_manual_snapshot_created.yml index 54fb358aa..8fc26baff 100644 --- a/rules/aws_cloudtrail_rules/aws_rds_manual_snapshot_created.yml +++ b/rules/aws_cloudtrail_rules/aws_rds_manual_snapshot_created.yml @@ -2,7 +2,7 @@ AnalysisType: rule Filename: aws_rds_manual_snapshot_created.py RuleID: "AWS.RDS.ManualSnapshotCreated" DisplayName: "AWS RDS Manual/Public Snapshot Created" -Enabled: false +Enabled: true LogTypes: - AWS.CloudTrail Tags: diff --git a/rules/aws_cloudtrail_rules/aws_software_discovery.yml b/rules/aws_cloudtrail_rules/aws_software_discovery.yml index a2493852f..199471ef4 100644 --- a/rules/aws_cloudtrail_rules/aws_software_discovery.yml +++ b/rules/aws_cloudtrail_rules/aws_software_discovery.yml @@ -4,6 +4,8 @@ DisplayName: "AWS Software Discovery" Enabled: false Filename: aws_software_discovery.py Reference: https://attack.mitre.org/techniques/T1518/001/ +Tags: + - Configuration Required Reports: MITRE ATT&CK: - TA0007:T1518 diff --git a/rules/aws_cloudtrail_rules/aws_unused_region.yml b/rules/aws_cloudtrail_rules/aws_unused_region.yml index e3b0d873f..a38b3b996 100644 --- a/rules/aws_cloudtrail_rules/aws_unused_region.yml +++ b/rules/aws_cloudtrail_rules/aws_unused_region.yml @@ -8,6 +8,7 @@ LogTypes: Tags: - AWS - Defense Evasion:Unused/Unsupported Cloud Regions + - Configuration Required Reports: MITRE ATT&CK: - TA0005:T1535 diff --git a/rules/carbonblack_rules/cb_passthrough.yml b/rules/carbonblack_rules/cb_passthrough.yml index ec1a28024..67e239668 100644 --- a/rules/carbonblack_rules/cb_passthrough.yml +++ b/rules/carbonblack_rules/cb_passthrough.yml @@ -4,7 +4,7 @@ Description: This rule enriches and contextualizes security alerts generated by DisplayName: Carbon Black Passthrough Rule Runbook: Review the Carbon Black alert details to determine what malicious behavior was detected, and whether or not it was blocked. Use the Reference link to view the alert in the Carbon Black console and take remediating actions if necessary. Reference: https://docs.vmware.com/en/VMware-Carbon-Black-Cloud/services/carbon-black-cloud-user-guide/GUID-0B68199D-6411-45D1-AE0D-2AB9B7A28513.html -Enabled: false +Enabled: true Filename: cb_passthrough.py LogTypes: - CarbonBlack.AlertV2 diff --git a/rules/gcp_audit_rules/gcp_computeinstances_create_privilege_escalation.py b/rules/gcp_audit_rules/gcp_computeinstances_create_privilege_escalation.py new file mode 100644 index 000000000..beb37b249 --- /dev/null +++ b/rules/gcp_audit_rules/gcp_computeinstances_create_privilege_escalation.py @@ -0,0 +1,62 @@ +from gcp_base_helpers import gcp_alert_context +from panther_base_helpers import deep_get + +REQUIRED_PERMISSIONS = [ + "compute.disks.create", + "compute.instances.create", + "compute.instances.setMetadata", + "compute.instances.setServiceAccount", + "compute.subnetworks.use", + "compute.subnetworks.useExternalIp", +] + + +def rule(event): + if deep_get(event, "protoPayload", "response", "error"): + return False + + method = deep_get(event, "protoPayload", "methodName") + if not method.endswith("compute.instances.insert"): + return False + + authorization_info = deep_get(event, "protoPayload", "authorizationInfo") + if not authorization_info: + return False + + granted_permissions = {} + for auth in authorization_info: + granted_permissions[auth["permission"]] = auth["granted"] + for permission in REQUIRED_PERMISSIONS: + if not granted_permissions.get(permission): + return False + + return True + + +def title(event): + actor = deep_get( + event, "protoPayload", "authenticationInfo", "principalEmail", default="" + ) + + service_accounts = deep_get(event, "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="") + return ( + f"[GCP]: [{actor}] created a new Compute Engine instance with [{service_account_emails}] " + f"Service Account on project [{project}]" + ) + + +def alert_context(event): + context = gcp_alert_context(event) + service_accounts = deep_get(event, "protoPayload", "request", "serviceAccounts") + if not service_accounts: + service_account_emails = "" + else: + service_account_emails = [service_acc["email"] for service_acc in service_accounts] + context["serviceAccount"] = service_account_emails + return context diff --git a/rules/gcp_audit_rules/gcp_computeinstances_create_privilege_escalation.yml b/rules/gcp_audit_rules/gcp_computeinstances_create_privilege_escalation.yml new file mode 100644 index 000000000..a0b4cd0e0 --- /dev/null +++ b/rules/gcp_audit_rules/gcp_computeinstances_create_privilege_escalation.yml @@ -0,0 +1,346 @@ +AnalysisType: rule +LogTypes: + - GCP.AuditLog +Description: Detects compute.instances.create method for privilege escalation in GCP. +DisplayName: "GCP compute.instances.create Privilege Escalation" +RuleID: "GCP.compute.instances.create.Privilege.Escalation" +Enabled: true +Reference: https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/ +Runbook: Confirm this was authorized and necessary behavior. +Reports: + MITRE ATT&CK: + - TA0004:T1548 # Abuse Elevation Control Mechanism +Severity: High +Filename: gcp_computeinstances_create_privilege_escalation.py +DedupPeriodMinutes: 60 +Threshold: 1 +Tests: + - + Name: GCP compute.instances - Potential Privilege Escalation + ExpectedResult: true + Log: + { + "protoPayload": { + "at_sign_type": "type.googleapis.com/google.cloud.audit.AuditLog", + "authenticationInfo": { + "principalEmail": "some.user@company.com", + "principalSubject": "user:some.user@company.com" + }, + "authorizationInfo": [ + { + "granted": true, + "permission": "compute.instances.create", + "resource": "projects/some-project/zones/us-central1-f/instances/abc", + "resourceAttributes": { + "name": "projects/some-project/zones/us-central1-f/instances/abc", + "service": "compute", + "type": "compute.instances" + } + }, + { + "granted": true, + "permission": "compute.disks.create", + "resource": "projects/some-project/zones/us-central1-f/disks/abc", + "resourceAttributes": { + "name": "projects/some-project/zones/us-central1-f/disks/abc", + "service": "compute", + "type": "compute.disks" + } + }, + { + "granted": true, + "permission": "compute.subnetworks.use", + "resource": "projects/some-project/regions/us-central1/subnetworks/default", + "resourceAttributes": { + "name": "projects/some-project/regions/us-central1/subnetworks/default", + "service": "compute", + "type": "compute.subnetworks" + } + }, + { + "granted": true, + "permission": "compute.subnetworks.useExternalIp", + "resource": "projects/some-project/regions/us-central1/subnetworks/default", + "resourceAttributes": { + "name": "projects/some-project/regions/us-central1/subnetworks/default", + "service": "compute", + "type": "compute.subnetworks" + } + }, + { + "granted": true, + "permission": "compute.instances.setMetadata", + "resource": "projects/some-project/zones/us-central1-f/instances/abc", + "resourceAttributes": { + "name": "projects/some-project/zones/us-central1-f/instances/abc", + "service": "compute", + "type": "compute.instances" + } + }, + { + "granted": true, + "permission": "compute.instances.setServiceAccount", + "resource": "projects/some-project/zones/us-central1-f/instances/abc", + "resourceAttributes": { + "name": "projects/some-project/zones/us-central1-f/instances/abc", + "service": "compute", + "type": "compute.instances" + } + } + ], + "methodName": "v1.compute.instances.insert", + "request": { + "@type": "type.googleapis.com/compute.instances.insert", + "disks": ..., + "machineType": ..., + "name": ..., + "networkInterfaces": ..., + "serviceAccounts": [ + { + "email": "abcmail@some-project.iam.gserviceaccount.com", + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/iam" + ] + } + ] + }, + "requestMetadata": { + "callerIP": "1.2.3.4", + "callerSuppliedUserAgent": "(gzip),gzip(gfe)", + "destinationAttributes": { }, + "requestAttributes": { + "auth": { }, + "time": "2024-01-30T12:52:36.003867Z" + } + }, + "resourceLocation": ..., + "resourceName": "projects/some-project/zones/us-central1-f/instances/abc", + "response": { + "@type": "type.googleapis.com/operation", + "id": "8758546889396539388", + "insertTime": "2024-01-30T04:52:35.886-08:00", + "name": "operation-1706619154623-610293c7a6a25-934f1c35-1efebb12", + "operationType": "insert", + "progress": "0", + "selfLink": "https://www.googleapis.com/compute/v1/projects/some-project/zones/us-central1-f/operations/operation-1706619154623-610293c7a6a25-934f1c35-1efebb12", + "selfLinkWithId": "https://www.googleapis.com/compute/v1/projects/some-project/zones/us-central1-f/operations/8758546889396539388", + "startTime": "2024-01-30T04:52:35.887-08:00", + "status": "RUNNING", + "targetId": "1454427709413609468", + "targetLink": "https://www.googleapis.com/compute/v1/projects/some-project/zones/us-central1-f/instances/abc", + "user": "some.user@company.com", + "zone": "https://www.googleapis.com/compute/v1/projects/some-project/zones/us-central1-f" + }, + "serviceName": "compute.googleapis.com" + }, + "receiveTimestamp": "2024-01-30 12:52:36.642422049", + "resource": { + "labels": { + "instance_id": "1454427709413609468", + "project_id": "some-project", + "zone": "us-central1-f" + }, + "type": "gce_instance" + }, + "severity": "NOTICE", + "timestamp": "2024-01-30 12:52:34.676384000" + } + - + Name: GCP compute.instances - Error + ExpectedResult: false + Log: + { + "protoPayload": { + "at_sign_type": "type.googleapis.com/google.cloud.audit.AuditLog", + "authenticationInfo": { + "principalEmail": "some.user@company.com", + "principalSubject": "user:some.user@company.com" + }, + "authorizationInfo": [ + { + "granted": true, + "permission": "compute.instances.create", + "resource": "projects/some-project/zones/us-central1-f/instances/abc", + "resourceAttributes": { + "name": "projects/some-project/zones/us-central1-f/instances/abc", + "service": "compute", + "type": "compute.instances" + } + }, + { + "granted": true, + "permission": "compute.disks.create", + "resource": "projects/some-project/zones/us-central1-f/disks/abc", + "resourceAttributes": { + "name": "projects/some-project/zones/us-central1-f/disks/abc", + "service": "compute", + "type": "compute.disks" + } + }, + { + "granted": true, + "permission": "compute.subnetworks.use", + "resource": "projects/some-project/regions/us-central1/subnetworks/default", + "resourceAttributes": { + "name": "projects/some-project/regions/us-central1/subnetworks/default", + "service": "compute", + "type": "compute.subnetworks" + } + }, + { + "granted": true, + "permission": "compute.subnetworks.useExternalIp", + "resource": "projects/some-project/regions/us-central1/subnetworks/default", + "resourceAttributes": { + "name": "projects/some-project/regions/us-central1/subnetworks/default", + "service": "compute", + "type": "compute.subnetworks" + } + }, + { + "granted": true, + "permission": "compute.instances.setMetadata", + "resource": "projects/some-project/zones/us-central1-f/instances/abc", + "resourceAttributes": { + "name": "projects/some-project/zones/us-central1-f/instances/abc", + "service": "compute", + "type": "compute.instances" + } + }, + { + "granted": true, + "permission": "compute.instances.setServiceAccount", + "resource": "projects/some-project/zones/us-central1-f/instances/abc", + "resourceAttributes": { + "name": "projects/some-project/zones/us-central1-f/instances/abc", + "service": "compute", + "type": "compute.instances" + } + } + ], + "methodName": "v1.compute.instances.insert", + "request": { + "@type": ..., + "disks": ..., + "machineType": ..., + "name": ..., + "networkInterfaces": ..., + "serviceAccounts": [ + { + "email": "abcmail@some-project.iam.gserviceaccount.com", + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/iam" + ] + } + ] + }, + "requestMetadata": ..., + "resourceLocation": ..., + "resourceName": "projects/some-project/zones/us-central1-f/instances/abc", + "response": { + "@type": "type.googleapis.com/error", + "error": { + "code": 404, + "errors": [ + { + "domain": "global", + "message": "The resource 'abc' was not found", + "reason": "notFound" + } + ], + "message": "The resource 'abc' was not found" + } + }, + "serviceName": "compute.googleapis.com", + "status": { + "code": 5, + "message": "The resource 'abc' was not found" + } + }, + "receiveTimestamp": "2024-01-30 11:03:56.719662927", + "resource": { + "labels": { + "instance_id": "", + "project_id": "some-project", + "zone": "us-central1-f" + }, + "type": "gce_instance" + }, + "severity": "ERROR", + "timestamp": "2024-01-30 11:03:55.700872000" + } + - Name: GCP compute.instances - Not All Permissions + ExpectedResult: false + Log: + { + "protoPayload": { + "at_sign_type": "type.googleapis.com/google.cloud.audit.AuditLog", + "authenticationInfo": { + "principalEmail": "some.user@company.com", + "principalSubject": "user:some.user@company.com" + }, + "authorizationInfo": [ + { + "granted": true, + "permission": "compute.instances.create", + "resource": "projects/some-project/zones/us-central1-f/instances/abc", + "resourceAttributes": { + "name": "projects/some-project/zones/us-central1-f/instances/abc", + "service": "compute", + "type": "compute.instances" + } + }, + { + "granted": true, + "permission": "compute.disks.create", + "resource": "projects/some-project/zones/us-central1-f/disks/abc", + "resourceAttributes": { + "name": "projects/some-project/zones/us-central1-f/disks/abc", + "service": "compute", + "type": "compute.disks" + } + }, + { + "granted": true, + "permission": "compute.subnetworks.use", + "resource": "projects/some-project/regions/us-central1/subnetworks/default", + "resourceAttributes": { + "name": "projects/some-project/regions/us-central1/subnetworks/default", + "service": "compute", + "type": "compute.subnetworks" + } + }, + { + "granted": true, + "permission": "compute.subnetworks.useExternalIp", + "resource": "projects/some-project/regions/us-central1/subnetworks/default", + "resourceAttributes": { + "name": "projects/some-project/regions/us-central1/subnetworks/default", + "service": "compute", + "type": "compute.subnetworks" + } + }, + { + "granted": true, + "permission": "compute.instances.setMetadata", + "resource": "projects/some-project/zones/us-central1-f/instances/abc", + "resourceAttributes": { + "name": "projects/some-project/zones/us-central1-f/instances/abc", + "service": "compute", + "type": "compute.instances" + } + }, + ], + "methodName": "v1.compute.instances.insert", + "request": ..., + "requestMetadata": ..., + "resourceLocation": ..., + "resourceName": ..., + "response": ..., + "serviceName": ... + }, + "receiveTimestamp": ..., + "resource": ... + } diff --git a/rules/gcp_audit_rules/gcp_gcs_public.py b/rules/gcp_audit_rules/gcp_gcs_public.py index 02dabe399..28743607d 100644 --- a/rules/gcp_audit_rules/gcp_gcs_public.py +++ b/rules/gcp_audit_rules/gcp_gcs_public.py @@ -12,7 +12,7 @@ def rule(event): if not service_data: return False - # Reference: bit.ly/2WsJdZS + # Reference: https://cloud.google.com/iam/docs/policies binding_deltas = deep_get(service_data, "policyDelta", "bindingDeltas") if not binding_deltas: return False diff --git a/rules/gcp_audit_rules/gcp_iam_admin_role_assigned.yml b/rules/gcp_audit_rules/gcp_iam_admin_role_assigned.yml index 7cfcb7e17..84c0020fa 100644 --- a/rules/gcp_audit_rules/gcp_iam_admin_role_assigned.yml +++ b/rules/gcp_audit_rules/gcp_iam_admin_role_assigned.yml @@ -9,6 +9,8 @@ Tags: - GCP - Identity & Access Management - Privilege Escalation:Valid Accounts + - Configuration Required + - Deprecated Reports: MITRE ATT&CK: - TA0004:T1078 diff --git a/rules/gcp_audit_rules/gcp_storage_hmac_keys_create.yml b/rules/gcp_audit_rules/gcp_storage_hmac_keys_create.yml new file mode 100644 index 000000000..e2da538a9 --- /dev/null +++ b/rules/gcp_audit_rules/gcp_storage_hmac_keys_create.yml @@ -0,0 +1,57 @@ +AnalysisType: rule +RuleID: "GCP.Storage.Hmac.Keys.Create" +DisplayName: "GCP storage hmac keys create" +Description: "There is a feature of Cloud Storage, “interoperability”, that provides a way for Cloud Storage to interact with storage offerings from other cloud providers, like AWS S3. As part of that, there are HMAC keys that can be created for both Service Accounts and regular users. We can escalate Cloud Storage permissions by creating an HMAC key for a higher-privileged Service Account." +Enabled: true +LogTypes: + - GCP.AuditLog +Severity: High +DedupPeriodMinutes: 60 +Threshold: 1 +Reference: https://rhinosecuritylabs.com/cloud-security/privilege-escalation-google-cloud-platform-part-2/ +Reports: + MITRE ATT&CK: + - TA0004:T1548 +Detection: + - All: + - KeyPath: protoPayload.authorizationInfo[*].granted + Condition: Contains + Value: true + - KeyPath: protoPayload.authorizationInfo[*].permission + Condition: Contains + Value: storage.hmacKeys.create +Tests: + - Name: privilege-escalation + ExpectedResult: true + Log: + protoPayload: + authorizationInfo: + - granted: true + permission: storage.hmacKeys.create + methodName: v2.deploymentmanager.deployments.insert + serviceName: deploymentmanager.googleapis.com + receiveTimestamp: "2024-01-19 13:47:19.465856238" + resource: + labels: + name: test-vm-deployment + project_id: panther-threat-research + type: deployment + severity: NOTICE + timestamp: "2024-01-19 13:47:18.279921000" + - Name: fail + ExpectedResult: false + Log: + protoPayload: + authorizationInfo: + - granted: false + permission: storage.hmacKeys.create + methodName: v2.deploymentmanager.deployments.insert + serviceName: deploymentmanager.googleapis.com + receiveTimestamp: "2024-01-19 13:47:19.465856238" + resource: + labels: + name: test-vm-deployment + project_id: panther-threat-research + type: deployment + severity: NOTICE + timestamp: "2024-01-19 13:47:18.279921000" diff --git a/rules/gcp_k8s_rules/gcp_k8s_ioc_activity.yml b/rules/gcp_k8s_rules/gcp_k8s_ioc_activity.yml new file mode 100644 index 000000000..e89cccfed --- /dev/null +++ b/rules/gcp_k8s_rules/gcp_k8s_ioc_activity.yml @@ -0,0 +1,44 @@ +AnalysisType: rule +RuleID: "GCP.K8s.IOC.Activity" +DisplayName: "GCP K8s IOCActivity" +Enabled: true +LogTypes: + - GCP.AuditLog +Tags: + - GCP + - Optional +Severity: Medium +Description: This detection monitors for any kuberentes API Request originating from an Indicator of Compromise. +Detection: + - All: + - KeyPath: operation.producer + Condition: Equals + Value: k8s.io + - KeyPath: p_enrichment.tor_exit_nodes + Condition: IsNotNullOrEmpty +Reference: https://medium.com/snowflake/from-logs-to-detection-using-snowflake-and-panther-to-detect-k8s-threats-d72f70a504d7 +Tests: + - + Name: triggers + ExpectedResult: true + Log: + { + "operation": {"producer":"k8s.io"}, + "p_enrichment": { + "tor_exit_nodes": [ + "1.1.1.1" + ] + } + } + - + Name: ignore + ExpectedResult: false + Log: + { + "operation": {"producer":"chrome"}, + "p_enrichment": { + "tor_exit_nodes": [ + "1.1.1.1" + ] + } + } diff --git a/rules/gcp_k8s_rules/gcp_k8s_privileged_pod_created.py b/rules/gcp_k8s_rules/gcp_k8s_privileged_pod_created.py new file mode 100644 index 000000000..283ca7b42 --- /dev/null +++ b/rules/gcp_k8s_rules/gcp_k8s_privileged_pod_created.py @@ -0,0 +1,40 @@ +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": + return False + + if deep_get(event, "protoPayload", "methodName") != "io.k8s.core.v1.pods.create": + return False + + authorization_info = deep_walk(event, "protoPayload", "authorizationInfo") + containers_info = deep_walk(event, "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: + if ( + deep_get(security_context, "securityContext", "privileged") is True + or deep_get(security_context, "securityContext", "runAsNonRoot") is False + ): + return True + + return False + + +def title(event): + actor = deep_get( + event, "protoPayload", "authenticationInfo", "principalEmail", default="" + ) + pod_name = deep_get(event, "protoPayload", "resourceName", default="") + project_id = deep_get(event, "resource", "labels", "project_id", default="") + + return f"[GCP]: [{actor}] created a privileged pod [{pod_name}] in project [{project_id}]" + + +def alert_context(event): + context = gcp_alert_context(event) + containers_info = deep_walk(event, "protoPayload", "response", "spec", "containers") + context["pod_security_context"] = [i.get("securityContext") for i in containers_info] + return context diff --git a/rules/gcp_k8s_rules/gcp_k8s_privileged_pod_created.yml b/rules/gcp_k8s_rules/gcp_k8s_privileged_pod_created.yml new file mode 100644 index 000000000..9d85349a6 --- /dev/null +++ b/rules/gcp_k8s_rules/gcp_k8s_privileged_pod_created.yml @@ -0,0 +1,344 @@ +AnalysisType: rule +RuleID: "GCP.K8S.Privileged.Pod.Created" +DisplayName: "GCP K8S Privileged Pod Created" +Enabled: true +LogTypes: + - GCP.AuditLog +Severity: High +Filename: gcp_k8s_privileged_pod_created.py +Description: > + Alerts when a user creates privileged pod. These particular pods have full access to the host’s namespace and + devices, have the ability to exploit the kernel, have dangerous linux capabilities, and can be a powerful launching + point for further attacks. In the event of a successful container escape where a user is operating with root + privileges, the attacker retains this role on the node. +Runbook: > + Investigate the reason of creating privileged pod. Advise that it is discouraged practice. + Create ticket if appropriate. +Reference: https://www.golinuxcloud.com/kubernetes-privileged-pod-examples/ +Reports: + MITRE ATT&CK: + - TA0004:T1548 # Abuse Elevation Control Mechanism +Tests: + - + Name: Privileged Pod Created + ExpectedResult: true + Log: + { + "logName": "projects/some-project/logs/cloudaudit.googleapis.com%2Factivity", + "operation": {}, + "protoPayload": { + "at_sign_type": "type.googleapis.com/google.cloud.audit.AuditLog", + "authenticationInfo": { + "principalEmail": "john.doe@company.com" + }, + "authorizationInfo": [ + { + "granted": true, + "permission": "io.k8s.core.v1.pods.create", + "resource": "core/v1/namespaces/default/pods/test-privileged-pod" + } + ], + "methodName": "io.k8s.core.v1.pods.create", + "request": { + "@type": "core.k8s.io/v1.Pod", + "apiVersion": "v1", + "kind": "Pod", + "metadata": { + "name": "test-privileged-pod", + "namespace": "default" + }, + "spec": { + "containers": [ + { + "image": "nginx", + "imagePullPolicy": "Always", + "name": "nginx", + "resources": { }, + "securityContext": { + "privileged": true + }, + } + ], + "securityContext": { }, + }, + "status": { } + }, + "requestMetadata": { + "callerIP": "1.2.3.4", + }, + "resourceName": "core/v1/namespaces/default/pods/test-privileged-pod", + "response": { + "@type": "core.k8s.io/v1.Pod", + "apiVersion": "v1", + "kind": "Pod", + "metadata": {}, + "spec": { + "containers": [ + { + "image": "nginx", + "imagePullPolicy": "Always", + "name": "nginx", + "resources": { }, + "securityContext": { + "privileged": true + }, + } + ], + "securityContext": { }, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + }, + "status": {} + }, + "serviceName": "k8s.io", + "status": {} + }, + "receiveTimestamp": "2024-02-13 12:45:20.058795785", + "resource": { + "labels": { + "cluster_name": "some-project-cluster", + "location": "us-west1", + "project_id": "some-project" + }, + "type": "k8s_cluster" + }, + "timestamp": "2024-02-13 12:45:06.073905000" + } + - + Name: Run-As-Root Pod Created + ExpectedResult: true + Log: + { + "logName": "projects/some-project/logs/cloudaudit.googleapis.com%2Factivity", + "operation": {}, + "protoPayload": { + "at_sign_type": "type.googleapis.com/google.cloud.audit.AuditLog", + "authenticationInfo": { + "principalEmail": "john.doe@company.com" + }, + "authorizationInfo": [ + { + "granted": true, + "permission": "io.k8s.core.v1.pods.create", + "resource": "core/v1/namespaces/default/pods/test-runasroot-pod" + } + ], + "methodName": "io.k8s.core.v1.pods.create", + "request": { + "@type": "core.k8s.io/v1.Pod", + "apiVersion": "v1", + "kind": "Pod", + "metadata": {}, + "spec": { + "containers": [ + { + "image": "nginx", + "imagePullPolicy": "Always", + "name": "nginx", + "resources": { }, + "securityContext": { + "runAsNonRoot": false + }, + } + ], + }, + "status": { } + }, + "requestMetadata": { + "callerIP": "1.2.3.4", + }, + "resourceName": "core/v1/namespaces/default/pods/test-runasroot-pod", + "response": { + "@type": "core.k8s.io/v1.Pod", + "apiVersion": "v1", + "kind": "Pod", + "metadata": {}, + "spec": { + "containers": [ + { + "image": "nginx", + "imagePullPolicy": "Always", + "name": "nginx", + "resources": { }, + "securityContext": { + "runAsNonRoot": false + }, + } + ], + }, + "status": { + "phase": "Pending", + "qosClass": "BestEffort" + } + }, + "serviceName": "k8s.io", + "status": { } + }, + "receiveTimestamp": "2024-02-13 13:13:53.113465457", + "resource": { + "labels": { + "cluster_name": "some-project-cluster", + "location": "us-west1", + "project_id": "some-project" + }, + "type": "k8s_cluster" + }, + "timestamp": "2024-02-13 13:13:45.363388000" + } + - + Name: Non-Privileged Pod Created + ExpectedResult: false + Log: + { + "logName": "projects/some-project/logs/cloudaudit.googleapis.com%2Factivity", + "operation": { + "first": true, + "id": "7f8c5bec-01ff-4079-97e3-065ac34e10e8", + "last": true, + "producer": "k8s.io" + }, + "protoPayload": { + "at_sign_type": "type.googleapis.com/google.cloud.audit.AuditLog", + "authenticationInfo": { + "principalEmail": "john.doe@company.com" + }, + "authorizationInfo": [ + { + "granted": true, + "permission": "io.k8s.core.v1.pods.create", + "resource": "core/v1/namespaces/default/pods/test-non-privileged-pod" + } + ], + "methodName": "io.k8s.core.v1.pods.create", + "request": { + "@type": "core.k8s.io/v1.Pod", + "apiVersion": "v1", + "kind": "Pod", + "metadata": { + "name": "test-non-privileged-pod", + "namespace": "default" + }, + "spec": { + "containers": [ + { + "image": "nginx", + "imagePullPolicy": "Always", + "name": "nginx", + "resources": { }, + } + ], + }, + "status": { } + }, + "requestMetadata": { + "callerIP": "1.2.3.4", + }, + "resourceName": "core/v1/namespaces/default/pods/test-non-privileged-pod", + "response": { + "@type": "core.k8s.io/v1.Pod", + "apiVersion": "v1", + "kind": "Pod", + "metadata": {}, + "spec": { + "containers": [ + { + "image": "nginx", + "imagePullPolicy": "Always", + "name": "nginx", + "resources": { }, + } + ], + }, + "status": {} + }, + "serviceName": "k8s.io", + "status": { } + }, + "receiveTimestamp": "2024-02-13 13:07:54.642331675", + "resource": { + "labels": { + "cluster_name": "some-project-cluster", + "location": "us-west1", + "project_id": "some-project" + }, + "type": "k8s_cluster" + }, + "timestamp": "2024-02-13 13:07:29.505948000" + } + - Name: Error Creating Pod + ExpectedResult: false + Log: + { + "logName": "projects/some-project/logs/cloudaudit.googleapis.com%2Factivity", + "protoPayload": { + "at_sign_type": "type.googleapis.com/google.cloud.audit.AuditLog", + "authenticationInfo": { + "principalEmail": "john.doe@company.com" + }, + "authorizationInfo": [ + { + "granted": true, + "permission": "io.k8s.core.v1.pods.create", + "resource": "core/v1/namespaces/default/pods/test-privileged-pod" + } + ], + "methodName": "io.k8s.core.v1.pods.create", + "request": { + "@type": "core.k8s.io/v1.Pod", + "apiVersion": "v1", + "kind": "Pod", + "metadata": { + "name": "test-privileged-pod", + "namespace": "default" + }, + "spec": { + "containers": [ + { + "image": "nginx", + "imagePullPolicy": "Always", + "name": "nginx", + "resources": { }, + "securityContext": { + "runAsNonRoot": false + }, + } + ], + }, + "status": { } + }, + "requestMetadata": { + "callerIP": "1.2.3.4", + }, + "resourceName": "core/v1/namespaces/default/pods/test-privileged-pod", + "response": { + "@type": "core.k8s.io/v1.Status", + "apiVersion": "v1", + "code": 409, + "details": { + "kind": "pods", + "name": "test-privileged-pod" + }, + "kind": "Status", + "message": "pods \"test-privileged-pod\" already exists", + "metadata": { }, + "reason": "AlreadyExists", + "status": "Failure" + }, + "serviceName": "k8s.io", + "status": { + "code": 10, + "message": "pods \"test-privileged-pod\" already exists" + } + }, + "receiveTimestamp": "2024-02-13 13:13:33.486605432", + "resource": { + "labels": { + "cluster_name": "some-project-cluster", + "location": "us-west1", + "project_id": "some-project" + }, + "type": "k8s_cluster" + }, + "timestamp": "2024-02-13 13:13:24.079140000" + } diff --git a/rules/gcp_k8s_rules/gcp_kubernetes_new_daemonset_deployed.yml b/rules/gcp_k8s_rules/gcp_kubernetes_new_daemonset_deployed.yml new file mode 100644 index 000000000..96155e9a6 --- /dev/null +++ b/rules/gcp_k8s_rules/gcp_kubernetes_new_daemonset_deployed.yml @@ -0,0 +1,54 @@ +AnalysisType: rule +RuleID: "GCP.K8s.New.Daemonset.Deployed" +DisplayName: "GCP K8s New Daemonset Deployed" +Description: "Detects Daemonset creation in GCP Kubernetes clusters." +Enabled: true +LogTypes: + - GCP.AuditLog +Severity: Medium +DedupPeriodMinutes: 60 +Threshold: 1 +Reference: https://medium.com/snowflake/from-logs-to-detection-using-snowflake-and-panther-to-detect-k8s-threats-d72f70a504d7 +Detection: + - All: + - KeyPath: protoPayload.authorizationInfo[*].granted + Condition: Contains + Value: true + - KeyPath: protoPayload.authorizationInfo[*].permission + Condition: Contains + Value: io.k8s.apps.v1.daemonsets.create +Tests: + - Name: privilege-escalation + ExpectedResult: true + Log: + protoPayload: + authorizationInfo: + - granted: true + permission: io.k8s.apps.v1.daemonsets.create + methodName: v2.deploymentmanager.deployments.insert + serviceName: deploymentmanager.googleapis.com + receiveTimestamp: "2024-01-19 13:47:19.465856238" + resource: + labels: + name: test-vm-deployment + project_id: panther-threat-research + type: deployment + severity: NOTICE + timestamp: "2024-01-19 13:47:18.279921000" + - Name: fail + ExpectedResult: false + Log: + protoPayload: + authorizationInfo: + - granted: false + permission: io.k8s.apps.v1.daemonsets.create + methodName: v2.deploymentmanager.deployments.insert + serviceName: deploymentmanager.googleapis.com + receiveTimestamp: "2024-01-19 13:47:19.465856238" + resource: + labels: + name: test-vm-deployment + project_id: panther-threat-research + type: deployment + severity: NOTICE + timestamp: "2024-01-19 13:47:18.279921000" diff --git a/rules/gsuite_activityevent_rules/gsuite_permissions_delegated.yml b/rules/gsuite_activityevent_rules/gsuite_permissions_delegated.yml index 22337695e..3738d16da 100644 --- a/rules/gsuite_activityevent_rules/gsuite_permissions_delegated.yml +++ b/rules/gsuite_activityevent_rules/gsuite_permissions_delegated.yml @@ -7,6 +7,8 @@ LogTypes: - GSuite.ActivityEvent Tags: - GSuite + - Configuration Required + - Deprecated Severity: Low Description: > A GSuite user was granted new administrator privileges. diff --git a/rules/netskope_rules/netskope_many_deletes.yml b/rules/netskope_rules/netskope_many_deletes.yml index c89c54fe6..93dc7abdf 100644 --- a/rules/netskope_rules/netskope_many_deletes.yml +++ b/rules/netskope_rules/netskope_many_deletes.yml @@ -12,7 +12,7 @@ LogTypes: - Netskope.Audit Tags: - Netskope - - Configuration Required + - Configuration Required # configure threshold for your environment - Data Destruction Reports: MITRE ATT&CK: diff --git a/rules/netskope_rules/netskope_unauthorized_api_calls.yml b/rules/netskope_rules/netskope_unauthorized_api_calls.yml index 74758ed4f..1a1896f6b 100644 --- a/rules/netskope_rules/netskope_unauthorized_api_calls.yml +++ b/rules/netskope_rules/netskope_unauthorized_api_calls.yml @@ -12,7 +12,7 @@ LogTypes: - Netskope.Audit Tags: - Netskope - - Configuration Required + - Configuration Required # configure threshold for your environment - Brute Force Reports: MITRE ATT&CK: diff --git a/rules/notion_rules/notion_login_from_blocked_ip.yml b/rules/notion_rules/notion_login_from_blocked_ip.yml index af4e2134b..c47541ce1 100644 --- a/rules/notion_rules/notion_login_from_blocked_ip.yml +++ b/rules/notion_rules/notion_login_from_blocked_ip.yml @@ -9,6 +9,7 @@ Tags: - Notion - Network Security Monitoring - Malicious Connections + - Configuration Required Severity: Medium Description: "A user attempted to access Notion from a blocked IP address. Note: before deployinh, make sure to add Rule Filters checking if event.ip_address is in a certain CIDR range(s)." DedupPeriodMinutes: 60 diff --git a/rules/okta_rules/okta_idp_signin.yaml b/rules/okta_rules/okta_idp_signin.yaml index feade31b6..6409a618b 100644 --- a/rules/okta_rules/okta_idp_signin.yaml +++ b/rules/okta_rules/okta_idp_signin.yaml @@ -5,6 +5,8 @@ DisplayName: "Okta Identity Provider Sign-in" Enabled: false LogTypes: - Okta.SystemLog +Tags: + - Configuration Required Reports: MITRE ATT&CK: - TA0001:T1199 # Trusted Relationship diff --git a/rules/standard_rules/impossible_travel_login.py b/rules/standard_rules/impossible_travel_login.py index 9d718c741..8e4db4450 100644 --- a/rules/standard_rules/impossible_travel_login.py +++ b/rules/standard_rules/impossible_travel_login.py @@ -72,7 +72,7 @@ def rule(event): IS_PRIVATE_RELAY = all( [ deep_get(ipinfo_privacy, "relay", default=False), - deep_get(ipinfo_privacy, "service", default="") != "", + deep_get(ipinfo_privacy, "service", default="") == "Apple Private Relay", ] ) # We've found that some places, like WeWork locations,