From eaf87f264d5b468aaf3950ae9aa80f725bbe032f Mon Sep 17 00:00:00 2001 From: pyth0n1c Date: Mon, 15 Jul 2024 16:23:05 -0700 Subject: [PATCH 1/2] improve output of risk severity field. it is now calculated using the risk score --- contentctl/objects/detection_tags.py | 36 +++++++++++-------- contentctl/objects/enums.py | 14 ++++---- .../templates/savedsearches_detections.j2 | 2 +- 3 files changed, 30 insertions(+), 22 deletions(-) diff --git a/contentctl/objects/detection_tags.py b/contentctl/objects/detection_tags.py index 87667c29..855f6127 100644 --- a/contentctl/objects/detection_tags.py +++ b/contentctl/objects/detection_tags.py @@ -11,7 +11,7 @@ from contentctl.objects.mitre_attack_enrichment import MitreAttackEnrichment from contentctl.objects.constants import * from contentctl.objects.observable import Observable -from contentctl.objects.enums import Cis18Value, AssetType, SecurityDomain, RiskSeverity, KillChainPhase, NistCategory, RiskLevel, SecurityContentProductName +from contentctl.objects.enums import Cis18Value, AssetType, SecurityDomain, RiskSeverity, KillChainPhase, NistCategory, SecurityContentProductName from contentctl.objects.atomic import AtomicTest @@ -30,6 +30,23 @@ class DetectionTags(BaseModel): def risk_score(self)->int: return round((self.confidence * self.impact)/100) + @computed_field + @property + def severity(self)->RiskSeverity: + if 0 <= self.risk_score <= 20: + return RiskSeverity.INFO + elif 20 < self.risk_score <= 40: + return RiskSeverity.LOW + elif 40 < self.risk_score <= 60: + return RiskSeverity.MEDIUM + elif 60 < self.risk_score <= 80: + return RiskSeverity.HIGH + elif 80 < self.risk_score <= 100: + return RiskSeverity.CRITICAL + else: + raise Exception(f"Error getting severity - risk_score must be between 0-100, but was actually {self.risk_score}") + + mitre_attack_id: List[Annotated[str, Field(pattern="^T[0-9]{4}(.[0-9]{3})?$")]] = [] nist: list[NistCategory] = [] @@ -40,17 +57,6 @@ def risk_score(self)->int: security_domain: SecurityDomain = Field(...) - @computed_field - @property - def risk_severity(self)->RiskSeverity: - if self.risk_score >= 80: - return RiskSeverity('high') - elif (self.risk_score >= 50 and self.risk_score <= 79): - return RiskSeverity('medium') - else: - return RiskSeverity('low') - - cve: List[Annotated[str, "^CVE-[1|2][0-9]{3}-[0-9]+$"]] = [] atomic_guid: List[AtomicTest] = [] @@ -62,8 +68,8 @@ def risk_severity(self)->RiskSeverity: confidence_id: Optional[PositiveInt] = Field(None,ge=1,le=3) impact_id: Optional[PositiveInt] = Field(None,ge=1,le=5) # context_ids: list = None - risk_level_id: Optional[NonNegativeInt] = Field(None,le=4) - risk_level: Optional[RiskLevel] = None + + #observable_str: str = None evidence_str: Optional[str] = None @@ -137,7 +143,7 @@ def serialize_model(self): "message": self.message, "risk_score": self.risk_score, "security_domain": self.security_domain, - "risk_severity": self.risk_severity, + "risk_severity": self.severity, "mitre_attack_id": self.mitre_attack_id, "mitre_attack_enrichments": self.mitre_attack_enrichments } diff --git a/contentctl/objects/enums.py b/contentctl/objects/enums.py index e7016033..cd8c1bbe 100644 --- a/contentctl/objects/enums.py +++ b/contentctl/objects/enums.py @@ -408,14 +408,16 @@ class NistCategory(str, enum.Enum): RC_IM = "RC.IM" RC_CO = "RC.CO" -class RiskLevel(str,enum.Enum): +class RiskSeverity(str,enum.Enum): + # Levels taken from the following documentation link + # https://docs.splunk.com/Documentation/ES/7.3.2/User/RiskScoring + # 20 - Info (0-20 for us) + # 40 - Low (21-40 for us) + # 60 - Medium (41-60 for us) + # 80 - High (61-80 for us) + # 100 - Critical (81 - 100 for us) INFO = "Info" LOW = "Low" MEDIUM = "Medium" HIGH = "High" CRITICAL = "Critical" - -class RiskSeverity(str,enum.Enum): - LOW = "low" - MEDIUM = "medium" - HIGH = "high" diff --git a/contentctl/output/templates/savedsearches_detections.j2 b/contentctl/output/templates/savedsearches_detections.j2 index 92db3833..37edf13f 100644 --- a/contentctl/output/templates/savedsearches_detections.j2 +++ b/contentctl/output/templates/savedsearches_detections.j2 @@ -80,7 +80,7 @@ action.notable.param.nes_fields = {{ detection.nes_fields }} action.notable.param.rule_description = {{ detection.deployment.alert_action.notable.rule_description | custom_jinja2_enrichment_filter(detection) | escapeNewlines()}} action.notable.param.rule_title = {% if detection.type | lower == "correlation" %}RBA: {{ detection.deployment.alert_action.notable.rule_title | custom_jinja2_enrichment_filter(detection) }}{% else %}{{ detection.deployment.alert_action.notable.rule_title | custom_jinja2_enrichment_filter(detection) }}{% endif +%} action.notable.param.security_domain = {{ detection.tags.security_domain.value }} -action.notable.param.severity = high +action.notable.param.severity = {{ detection.tags.severity.value }} {% endif %} {% if detection.deployment.alert_action.email %} action.email.subject.alert = {{ detection.deployment.alert_action.email.subject | custom_jinja2_enrichment_filter(detection) | escapeNewlines() }} From 307d8f1b34557ae4eccf6161df6a48261237d5f1 Mon Sep 17 00:00:00 2001 From: pyth0n1c Date: Fri, 30 Aug 2024 12:43:43 -0700 Subject: [PATCH 2/2] removed dupliocate risk functionality in detection_Tags --- contentctl/objects/detection_tags.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/contentctl/objects/detection_tags.py b/contentctl/objects/detection_tags.py index c9de6ff0..3de1019a 100644 --- a/contentctl/objects/detection_tags.py +++ b/contentctl/objects/detection_tags.py @@ -77,17 +77,6 @@ def severity(self)->RiskSeverity: required_fields: list[str] = Field(min_length=1) throttling: Optional[Throttling] = None security_domain: SecurityDomain = Field(...) - - @computed_field - @property - def risk_severity(self) -> RiskSeverity: - if self.risk_score >= 80: - return RiskSeverity('high') - elif (self.risk_score >= 50 and self.risk_score <= 79): - return RiskSeverity('medium') - else: - return RiskSeverity('low') - cve: List[CVE_TYPE] = [] atomic_guid: List[AtomicTest] = [] drilldown_search: Optional[str] = None