Skip to content

Commit

Permalink
Merge pull request #14 from frack113/clean
Browse files Browse the repository at this point in the history
Multiple Updates - Migration to v2 Specification - First Batch
  • Loading branch information
nasbench authored Aug 10, 2024
2 parents f520af7 + 6b14fd1 commit 2122060
Show file tree
Hide file tree
Showing 18 changed files with 516 additions and 537 deletions.
47 changes: 7 additions & 40 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,52 +3,19 @@
![Coverage Badge](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/frack113/b27ee1cbe964fb1a299cc20c3403f8c8/raw/pySigma-validators-sigmaHQ.json)
![Status](https://img.shields.io/badge/Status-pre--release-orange)

# Purpose
# 🌟 Purpose

Create all validators specific to the requirements of the SigmaHQ rules repository

# Validators

| Name | Description|
| --- | ---|
| sigmahq_categorie_eventid | Checks if rule use Eventid with a windows category that |
| sigmahq_date_existence | Checks if rule has a data. |
| sigmahq_description_existence | Checks if rule has a description. |
| sigmahq_description_length | Checks if rule has a description. |
| sigmahq_falsepositives_banned_word | Checks if rule falsepositive start with a banned word. |
| sigmahq_falsepositives_capital | Checks if rule falsepositive start with a capital. |
| sigmahq_falsepositives_typo_word | Checks if rule falsepositive start with a common typo error. |
| sigmahq_field_duplicate_value | Check uniques value in field list. |
| sigmahq_field_user | Check a User field use a localized name. |
| sigmahq_field_with_space | Check field do not have a space. |
| sigmahq_fieldname_cast | Check field name have a cast error. |
| sigmahq_filename | Check rule filename match SigmaHQ standard. |
| sigmahq_filename_prefix | Check rule filename match SigmaHQ prefix standard. |
| sigmahq_invalid_all_modifier | Check All modifier used with a single value. |
| sigmahq_invalid_field_source | Check field Source use with Eventlog. |
| sigmahq_invalid_fieldname | Check field name do not exist in the logsource. |
| sigmahq_level_existence | Checks if rule has a level. |
| sigmahq_link_description | Checks if rule description use a link instead of references. |
| sigmahq_logsource_known | Checks if rule has known logsource. |
| sigmahq_noasterixofselection_condition | Check use '1/all of ' without asterix |
| sigmahq_ofselection_condition | Check use 'All/X of ' with only one selection |
| sigmahq_ofthem_condition | Check use ' of them' with only one selection |
| sigmahq_sigmac | Checks if rule use a selection name that break sigmac. |
| sigmahq_space_fieldname | Check field name have a space. |
| sigmahq_status_deprecated | Checks if rule has a status DEPRECATED. |
| sigmahq_status_existence | Checks if rule has a status. |
| sigmahq_status_unsupported | Checks if rule has a status UNSUPPORTED. |
| sigmahq_title_case | Checks if rule title use capitalization. |
| sigmahq_title_end | Checks if rule title end with a dot(.). |
| sigmahq_title_length | Checks if rule has a title too long. |
| sigmahq_title_start | Checks if rule title start with Detects. |


# Data
# 🏗️ Validators

TBD

# 🧬 Data

All the data value are in the config.py

# Maintainer
# 📜 Maintainer

This pipelines is currently maintained by:
* [François Hubaut](https://github.com/frack113)
310 changes: 166 additions & 144 deletions poetry.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "pySigma-validators-sigmahq"
version = "0.7.1"
version = "0.8.0"
description = "pySigma SigmaHQ validators"
authors = ["François Hubaut <[email protected]>"]
license = "LGPL-2.1-only"
Expand Down
2 changes: 1 addition & 1 deletion sigma/validators/sigmahq/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import re

from sigma.validators.base import SigmaRuleValidator
from .config import ConfigHq
from .config import ConfigHQ

validators = {
re.sub("([A-Z]+)", "_\\1", name.replace("Validator", ""))[
Expand Down
24 changes: 15 additions & 9 deletions sigma/validators/sigmahq/condition.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@

@dataclass
class SigmahqOfthemConditionIssue(SigmaValidationIssue):
description: ClassVar[str] = "Rule contains ' of them' with only 1 selection"
description: ClassVar[str] = (
"Rule uses the ' of them' keyword in the condition with only one selection in the detection section"
)
severity: ClassVar[SigmaValidationIssueSeverity] = SigmaValidationIssueSeverity.LOW


class SigmahqOfthemConditionValidator(SigmaRuleValidator):
"""Check use ' of them' with only one selection"""
"""Check use of the ' of them' keyword with only a single selection in the detection section"""

re_all_of_them: ClassVar[Pattern] = re.compile("\\s+of\\s+them")

Expand All @@ -43,13 +45,15 @@ def validate(self, rule: SigmaRule) -> List[SigmaValidationIssue]:

@dataclass
class SigmahqOfselectionConditionIssue(SigmaValidationIssue):
description: ClassVar[str] = "Rule contains 'All/X of ' with only 1 selection"
description: ClassVar[str] = (
"Rule uses the 'All/X of ' format in the condition with only one selection in the detection section"
)
severity: ClassVar[SigmaValidationIssueSeverity] = SigmaValidationIssueSeverity.LOW
selection: str


class SigmahqOfselectionConditionValidator(SigmaRuleValidator):
"""Check use 'All/X of ' with only one selection"""
"""Check use of the 'All/X of ' format with only one selection in the detection section"""

re_x_of_them: ClassVar[Pattern] = re.compile("[\\d+|all]\\s+of\\s+([^\\s]+)")

Expand Down Expand Up @@ -79,16 +83,18 @@ def validate(self, rule: SigmaRule) -> List[SigmaValidationIssue]:


@dataclass
class SigmahqNoasterixofselectionConditionIssue(SigmaValidationIssue):
description: ClassVar[str] = "Rule contains '1/all of ' without asterix"
class SigmahqMissingAsteriskConditionIssue(SigmaValidationIssue):
description: ClassVar[str] = (
"Rule uses a '1/all of ' keyword in the condition without an asterisk"
)
severity: ClassVar[SigmaValidationIssueSeverity] = (
SigmaValidationIssueSeverity.MEDIUM
)
selection: str


class SigmahqNoasterixofselectionConditionValidator(SigmaRuleValidator):
"""Check use '1/all of ' without asterix"""
class SigmahqMissingAsteriskConditionValidator(SigmaRuleValidator):
"""Check the use of the '1/all of ' keyword without an asterisk in the condition"""

re_x_of_them: ClassVar[Pattern] = re.compile("\\s+of\\s+([^\\s\\)]+)")

Expand All @@ -103,5 +109,5 @@ def validate(self, rule: SigmaRule) -> List[SigmaValidationIssue]:
if name == "them":
continue
if not name.endswith("*"):
return [SigmahqNoasterixofselectionConditionIssue(rule, name)]
return [SigmahqMissingAsteriskConditionIssue(rule, name)]
return []
72 changes: 43 additions & 29 deletions sigma/validators/sigmahq/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -1145,6 +1145,7 @@
"ProcessId",
"TargetFilename",
"User",
"UtcTime",
],
},
"win_file_delete": {
Expand Down Expand Up @@ -1331,6 +1332,8 @@
"CurrentDirectory",
"Description",
"FileVersion",
"GrandparentCommandLine",
"GrandParentImage",
"Hashes",
"Image",
"IntegrityLevel",
Expand All @@ -1347,8 +1350,7 @@
"Product",
"TerminalSessionId",
"User",
"GrandParentImage",
"GrandparentCommandLine",
"UtcTime",
],
},
"win_process_access": {
Expand Down Expand Up @@ -1563,39 +1565,51 @@
}


class ConfigHq:
title_lengh = 110
class ConfigHQ:
title_max_length = 120
allowed_lowercase_words = [
"the",
"a",
"an",
"and",
"as",
"at",
"by",
"for",
"from",
"in",
"with",
"via",
"on",
"to",
"without",
"new",
"of",
"through",
"from",
"by",
"as",
"a",
"on",
"or",
"at",
"and",
"an",
"over",
"new",
"the",
"through",
"to",
"via",
"with",
"without",
]
sigmahq_fp_banned_word = [
"none",
"pentest",
"penetration test",
"red team",
"offensive security tool",
]
sigmahq_fp_banned_word = ["none", "pentest", "penetration"]
sigmahq_fp_typo_word = ["unkown", "ligitimate", "legitim ", "legitimeate"]
sigmahq_link_in_description = ["http://", "https://", "internal research"]
sigmahq_fp_typo_word = [
"unkown",
"ligitimate",
"legitim ",
"legitimeate",
"legitimat",
]
sigmahq_link_in_description = ["http://", "https://"]
sigmahq_logsource_cast: Dict[SigmaLogSource, List[str]] = {}
sigmahq_logsource_unicast: Dict[SigmaLogSource, List[str]] = {}
sigmahq_logsource_list: Dict[SigmaLogSource, str] = {}
sigmahq_logsource_prefix: Dict[SigmaLogSource, str] = {}
sigmahq_product_prefix: Dict[str, str] = {}
windows_categorie_no_eventid = [
windows_category_no_eventid = [
"clipboard_capture",
"create_remote_thread",
"create_stream_hash",
Expand Down Expand Up @@ -1625,7 +1639,7 @@ class ConfigHq:
"sysmon_error",
"sysmon_status",
]
windows_categorie_provider_name = {
windows_category_provider_name = {
"clipboard_capture": ["Microsoft-Windows-Sysmon"],
"create_remote_thread": ["Microsoft-Windows-Sysmon"],
"create_stream_hash": ["Microsoft-Windows-Sysmon"],
Expand All @@ -1642,13 +1656,13 @@ class ConfigHq:
],
"pipe_created": ["Microsoft-Windows-Sysmon"],
"process_access": [
"Microsoft-Windows-Sysmon",
"Microsoft-Windows-Kernel-Audit-API-Calls",
"Microsoft-Windows-Sysmon",
],
"process_creation": [
"Microsoft-Windows-Sysmon",
"Microsoft-Windows-Security-Auditing",
"Microsoft-Windows-Kernel-Process",
"Microsoft-Windows-Security-Auditing",
"Microsoft-Windows-Sysmon",
"SystemTraceProvider-Process",
],
"process_tampering": ["Microsoft-Windows-Sysmon"],
Expand Down Expand Up @@ -1681,10 +1695,10 @@ def __init__(self) -> None:
if v["log"]["product"] == "windows":
field.extend(
[
"EventID",
"Provider_Name",
"Channel",
"Computer",
"EventID",
"Provider_Name",
"Security_UserID",
]
)
Expand Down
45 changes: 14 additions & 31 deletions sigma/validators/sigmahq/detection.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,28 @@
SigmaDetectionItemValidator,
SigmaDetectionItem,
)
from .config import ConfigHq
from .config import ConfigHQ

config = ConfigHq()
config = ConfigHQ()


@dataclass
class SigmahqCategorieEventidIssue(SigmaValidationIssue):
description: ClassVar[str] = "Rule use a windows categorie that don't need EventId"
class SigmahqCategoryEventIdIssue(SigmaValidationIssue):
description: ClassVar[str] = (
"Rule uses a windows logsource category that doesn't require the use of an EventID field"
)
severity: ClassVar[SigmaValidationIssueSeverity] = (
SigmaValidationIssueSeverity.MEDIUM
)


class SigmahqCategorieEventidValidator(SigmaDetectionItemValidator):
"""Checks if a rule uses an EventID field with a windows category logsource that is already included."""
class SigmahqCategoryEventIdValidator(SigmaDetectionItemValidator):
"""Checks if a rule uses an EventID field with a windows category logsource that doesn't require it."""

def validate(self, rule: SigmaRule) -> List[SigmaValidationIssue]:
if (
rule.logsource.product == "windows"
and rule.logsource.category in ConfigHq.windows_categorie_no_eventid
and rule.logsource.category in ConfigHQ.windows_category_no_eventid
):
return super().validate(rule)
else:
Expand All @@ -38,28 +40,28 @@ def validate_detection_item(
self, detection_item: SigmaDetectionItem
) -> List[SigmaValidationIssue]:
if detection_item.field is not None and detection_item.field == "EventID":
return [SigmahqCategorieEventidIssue(self.rule)]
return [SigmahqCategoryEventIdIssue(self.rule)]
else:
return []


@dataclass
class SigmahqCategoriProvidernameIssue(SigmaValidationIssue):
description: ClassVar[str] = (
"Rule use a windows category logsource that doesn't need a Provider_Name field"
"Rule uses a windows logsource category that doesn't require the use of the Provider_Name field"
)
severity: ClassVar[SigmaValidationIssueSeverity] = (
SigmaValidationIssueSeverity.MEDIUM
)


class SigmahqCategoriProvidernameValidator(SigmaDetectionItemValidator):
"""Checks if a rule uses a Provider_Name field with a windows category logsource that is already included."""
"""Checks if a rule uses a Provider_Name field with a windows category logsource that doesn't require it."""

def validate(self, rule: SigmaRule) -> List[SigmaValidationIssue]:
if (
rule.logsource.product == "windows"
and rule.logsource.category in ConfigHq.windows_categorie_provider_name
and rule.logsource.category in ConfigHQ.windows_category_provider_name
):
return super().validate(rule)
else:
Expand All @@ -72,29 +74,10 @@ def validate_detection_item(
for v in detection_item.value:
if (
v
in ConfigHq.windows_categorie_provider_name[
in ConfigHQ.windows_category_provider_name[
self.rule.logsource.category
]
):
return [SigmahqCategoriProvidernameIssue(self.rule)]

return []


@dataclass
class SigmahqSigmacIssue(SigmaValidationIssue):
description: ClassVar[str] = "Rule use a selection name that break sigmac"
severity: ClassVar[SigmaValidationIssueSeverity] = (
SigmaValidationIssueSeverity.MEDIUM
)
selection: str


class SigmahqSigmacValidator(SigmaRuleValidator):
"""Checks if rule use a selection name that break sigmac."""

def validate(self, rule: SigmaRule) -> List[SigmaValidationIssue]:
for k in rule.detection.detections.keys():
if k.startswith("or") or k.startswith("and") or k.startswith("not"):
return [SigmahqSigmacIssue(rule, k)]
return []
Loading

0 comments on commit 2122060

Please sign in to comment.