diff --git a/contentctl/objects/detection_tags.py b/contentctl/objects/detection_tags.py index 21ce44cf..3de1019a 100644 --- a/contentctl/objects/detection_tags.py +++ b/contentctl/objects/detection_tags.py @@ -23,6 +23,7 @@ from contentctl.objects.mitre_attack_enrichment import MitreAttackEnrichment from contentctl.objects.constants import ATTACK_TACTICS_KILLCHAIN_MAPPING from contentctl.objects.observable import Observable +from contentctl.objects.enums import Cis18Value, AssetType, SecurityDomain, RiskSeverity, KillChainPhase, NistCategory, SecurityContentProductName from contentctl.objects.enums import ( Cis18Value, AssetType, @@ -30,9 +31,9 @@ RiskSeverity, KillChainPhase, NistCategory, - RiskLevel, SecurityContentProductName ) + from contentctl.objects.atomic import AtomicTest from contentctl.objects.annotated_types import MITRE_ATTACK_ID_TYPE, CVE_TYPE @@ -50,6 +51,23 @@ class DetectionTags(BaseModel): @property 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[MITRE_ATTACK_ID_TYPE] = [] nist: list[NistCategory] = [] @@ -59,17 +77,6 @@ def risk_score(self) -> int: 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 @@ -78,10 +85,6 @@ def risk_severity(self) -> RiskSeverity: mitre_attack_enrichments: List[MitreAttackEnrichment] = Field([], validate_default=True) 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 @computed_field @@ -157,7 +160,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 4783107a..9cda98be 100644 --- a/contentctl/objects/enums.py +++ b/contentctl/objects/enums.py @@ -409,14 +409,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 f2885a62..f2f345aa 100644 --- a/contentctl/output/templates/savedsearches_detections.j2 +++ b/contentctl/output/templates/savedsearches_detections.j2 @@ -71,7 +71,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() }}