-
Notifications
You must be signed in to change notification settings - Fork 176
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add initial Correlation Rules (#1260)
* GitHub advanced security change not followed by repo archived * StopInstance FOLLOWED BY ModifyInstanceAttributes (correlation rule) * GCP run.services.create Privilege Escalation - correlation rule * GCP run.services.create Privilege Escalation - linter fix * Add gcp_cloud_run_service_created.py changes Signed-off-by: egibs <20933572+egibs@users.noreply.github.com> * updated to follow CR style guide/best practices * instance_ids as lists for comparison * added unit tests to correlation rules * updated packs --------- Signed-off-by: egibs <20933572+egibs@users.noreply.github.com> Co-authored-by: akozlovets098 <an.kozlovets@gmail.com> Co-authored-by: Ariel Ropek <ariel.ropek@panther.com> Co-authored-by: Ben Airey <benjaminjohnairey@gmail.com> Co-authored-by: Ariel Ropek <79653153+arielkr256@users.noreply.github.com>
- Loading branch information
1 parent
dd05da4
commit e68dabf
Showing
15 changed files
with
962 additions
and
1 deletion.
There are no files selected for viewing
48 changes: 48 additions & 0 deletions
48
correlation_rules/aws_cloudtrail_stopinstance_followed_by_modifyinstanceattributes.yml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
AnalysisType: correlation_rule | ||
RuleID: "AWS.EC2.StopInstance.FOLLOWED.BY.ModifyInstanceAttributes" | ||
DisplayName: "StopInstance FOLLOWED BY ModifyInstanceAttributes" | ||
Enabled: true | ||
Severity: High | ||
Description: Identifies when StopInstance and ModifyInstanceAttributes CloudTrail events occur in a short period of time. Since EC2 startup scripts cannot be modified without first stopping the instance, StopInstances should be a signal. | ||
Reference: https://unit42.paloaltonetworks.com/malicious-operations-of-exposed-iam-keys-cryptojacking/ | ||
Reports: | ||
MITRE ATT&CK: | ||
- TA0002:T1059 | ||
Detection: | ||
- Sequence: | ||
- ID: StopInstance | ||
RuleID: AWS.EC2.StopInstances | ||
- ID: StartupScriptChange | ||
RuleID: AWS.EC2.Startup.Script.Change | ||
Transitions: | ||
- ID: StopInstance FOLLOWED BY StartupScriptChange | ||
From: StopInstance | ||
To: StartupScriptChange | ||
Match: | ||
- On: p_alert_context.instance_ids | ||
LookbackWindowMinutes: 90 | ||
Schedule: | ||
RateMinutes: 60 | ||
TimeoutMinutes: 1 | ||
Tests: | ||
- Name: Instance Stopped, Followed By Script Change | ||
ExpectedResult: true | ||
RuleOutputs: | ||
- ID: StopInstance | ||
Matches: | ||
p_alert_context.instance_ids: | ||
'i-abcdef0123456789a': | ||
- "2024-06-01T10:00:01Z" | ||
- ID: StartupScriptChange | ||
Matches: | ||
p_alert_context.instance_ids: | ||
'i-abcdef0123456789a': | ||
- "2024-06-01T10:01:01Z" | ||
- Name: Instance Stopped, Not Followed By Script Change | ||
ExpectedResult: false | ||
RuleOutputs: | ||
- ID: StopInstance | ||
Matches: | ||
p_alert_context.instance_ids: | ||
'i-abcdef0123456789a': | ||
- "2024-06-01T10:00:01Z" |
72 changes: 72 additions & 0 deletions
72
correlation_rules/gcp_cloud_run_service_create_followed_by_set_iam_policy.yml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
AnalysisType: correlation_rule | ||
RuleID: "GCP.Cloud.Run.Service.Created.FOLLOWED.BY.Set.IAM.Policy" | ||
DisplayName: "GCP Cloud Run Service Created FOLLOWED BY Set IAM Policy" | ||
Enabled: true | ||
Severity: High | ||
Description: Detects run.services.create method for privilege escalation in GCP. The exploit creates a new Cloud Run | ||
Service that, when invoked, returns the Service Account's access token by accessing the metadata API of the server | ||
it is running on. | ||
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 | ||
Detection: | ||
- Sequence: | ||
- ID: ServiceCreated | ||
RuleID: GCP.Cloud.Run.Service.Created | ||
- ID: SetIAMPolicy | ||
RuleID: GCP.Cloud.Run.Set.IAM.Policy | ||
Transitions: | ||
- ID: ServiceCreated FOLLOWED BY SetIAMPolicy | ||
From: ServiceCreated | ||
To: SetIAMPolicy | ||
Match: | ||
- On: p_alert_context.caller_ip | ||
LookbackWindowMinutes: 90 | ||
Schedule: | ||
RateMinutes: 60 | ||
TimeoutMinutes: 1 | ||
Tests: | ||
- Name: GCP Service Run, Followed By IAM Policy Change From Same IP | ||
ExpectedResult: true | ||
RuleOutputs: | ||
- ID: ServiceCreated | ||
Matches: | ||
p_alert_context.caller_ip: | ||
1.1.1.1: | ||
- "2024-06-01T10:00:00Z" | ||
- ID: SetIAMPolicy | ||
Matches: | ||
p_alert_context.caller_ip: | ||
1.1.1.1: | ||
- "2024-06-01T10:00:01Z" | ||
- Name: GCP Service Run, Not Followed By IAM Policy Change | ||
ExpectedResult: false | ||
RuleOutputs: | ||
- ID: ServiceCreated | ||
Matches: | ||
p_alert_context.caller_ip: | ||
1.1.1.1: | ||
- "2024-06-01T10:00:00Z" | ||
- Name: IAM Policy Change, Not Preceeded By GCP Service Run | ||
ExpectedResult: false | ||
RuleOutputs: | ||
- ID: SetIAMPolicy | ||
Matches: | ||
p_alert_context.caller_ip: | ||
1.1.1.1: | ||
- "2024-06-01T10:00:01Z" | ||
- Name: GCP Service Run, Followed By IAM Policy Change From Different IP | ||
ExpectedResult: false | ||
RuleOutputs: | ||
- ID: ServiceCreated | ||
Matches: | ||
p_alert_context.caller_ip: | ||
1.1.1.1: | ||
- "2024-06-01T10:00:00Z" | ||
- ID: SetIAMPolicy | ||
Matches: | ||
p_alert_context.caller_ip: | ||
2.2.2.2: | ||
- "2024-06-01T10:00:01Z" |
59 changes: 59 additions & 0 deletions
59
correlation_rules/github_advanced_security_change_not_followed_by_repo_archived.yml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
AnalysisType: correlation_rule | ||
RuleID: "GitHub.Advanced.Security.Change.NOT.FOLLOWED.BY.Repo.Archived" | ||
DisplayName: "GitHub Advanced Security Change NOT FOLLOWED BY Repo Archived" | ||
Enabled: true | ||
Severity: Critical | ||
Description: Identifies when advances security change was made not to archive a repo. Eliminates false positives in the Advances Security Change Rule when the repo is archived. | ||
Reference: https://docs.github.com/en/code-security/getting-started/auditing-security-alerts | ||
Detection: | ||
- Sequence: | ||
- ID: GHASChange | ||
RuleID: GitHub.Advanced.Security.Change | ||
- ID: RepoArchived | ||
RuleID: Github.Repo.Archived | ||
Absence: true | ||
Transitions: | ||
- ID: GHASChange NOT FOLLOWED BY RepoArchived | ||
From: GHASChange | ||
To: RepoArchived | ||
Match: | ||
- On: p_alert_context.repo | ||
LookbackWindowMinutes: 15 | ||
Schedule: | ||
RateMinutes: 10 | ||
TimeoutMinutes: 1 | ||
Tests: | ||
- Name: Security Change on Repo, Followed By Same Repo Archived | ||
ExpectedResult: false | ||
RuleOutputs: | ||
- ID: GHASChange | ||
Matches: | ||
p_alert_context.repo: | ||
my-org/example-repo: | ||
- "2024-06-01T10:00:00Z" | ||
- ID: RepoArchived | ||
Matches: | ||
p_alert_context.repo: | ||
my-org/example-repo: | ||
- "2024-06-01T10:00:01Z" | ||
- Name: Security Change on Repo, Followed By Different Repo Archived | ||
ExpectedResult: true | ||
RuleOutputs: | ||
- ID: GHASChange | ||
Matches: | ||
p_alert_context.repo: | ||
my-org/example-repo: | ||
- "2024-06-01T10:00:00Z" | ||
- ID: RepoArchived | ||
Matches: | ||
p_alert_context.repo: | ||
my-org/other-repo: | ||
- "2024-06-01T10:00:01Z" | ||
- Name: Security Change on Repo, Not Followed By Repo Archived | ||
ExpectedResult: true | ||
RuleOutputs: | ||
- ID: GHASChange | ||
Matches: | ||
p_alert_context.repo: | ||
my-org/example-repo: | ||
- "2024-06-01T10:00:00Z" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
from panther_base_helpers import aws_rule_context | ||
|
||
|
||
def rule(event): | ||
return all( | ||
[ | ||
not event.get("errorCode"), | ||
not event.get("errorMessage"), | ||
event.get("eventName") == "StopInstances", | ||
] | ||
) | ||
|
||
|
||
def title(event): | ||
instances = [ | ||
instance["instanceId"] | ||
for instance in event.deep_get("requestParameters", "instancesSet", "items", default=[]) | ||
] | ||
account = event.get("recipientAccountId") | ||
return f"EC2 instances {instances} stopped in account {account}." | ||
|
||
|
||
def alert_context(event): | ||
context = aws_rule_context(event) | ||
context["instance_ids"] = [ | ||
instance["instanceId"] | ||
for instance in event.deep_get("requestParameters", "instancesSet", "items", default=[]) | ||
] | ||
return context |
Oops, something went wrong.