Skip to content

Commit 97d8ae4

Browse files
committed
✨ feat: add SigmahqSelectionAlphabeticalOrderValidator
1 parent 6ba5bfe commit 97d8ae4

2 files changed

Lines changed: 165 additions & 0 deletions

File tree

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
from dataclasses import dataclass
2+
from typing import ClassVar, List
3+
4+
from sigma.correlations import SigmaCorrelationRule
5+
from sigma.rule import SigmaRule
6+
from sigma.validators.base import (
7+
SigmaRuleValidator,
8+
SigmaValidationIssue,
9+
SigmaValidationIssueSeverity,
10+
)
11+
12+
13+
@dataclass
14+
class SigmahqSelectionAlphabeticalOrderIssue(SigmaValidationIssue):
15+
description: ClassVar[str] = "Selection list is not in alphabetical order."
16+
severity: ClassVar[SigmaValidationIssueSeverity] = SigmaValidationIssueSeverity.LOW
17+
field: str
18+
selection: str
19+
values: List[str]
20+
21+
22+
class SigmahqSelectionAlphabeticalOrderValidator(SigmaRuleValidator):
23+
"""Checks if any multi-item selection list is sorted alphabetically."""
24+
25+
def validate(self, rule: SigmaRule | SigmaCorrelationRule) -> List[SigmaValidationIssue]:
26+
if isinstance(rule, SigmaCorrelationRule):
27+
return []
28+
29+
issues: List[SigmaValidationIssue] = []
30+
for sel_name, detection in rule.detection.detections.items():
31+
for item in detection.detection_items:
32+
if hasattr(item, "field") and item.field and hasattr(item, "value"):
33+
if isinstance(item.value, list) and len(item.value) >= 2:
34+
values = [str(v) for v in item.value]
35+
if values != sorted(values):
36+
issues.append(
37+
SigmahqSelectionAlphabeticalOrderIssue(
38+
[rule], sel_name, item.field, values
39+
)
40+
)
41+
return issues
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import pytest
2+
from sigma.rule import SigmaRule
3+
from sigma.validators.sigmahq.selection_order import SigmahqSelectionAlphabeticalOrderValidator
4+
5+
pytestmark = pytest.mark.sigmahq
6+
7+
test_cases = [
8+
(
9+
"Alphabetical order - no issue",
10+
{
11+
"title": "Test Rule",
12+
"description": "Detects test",
13+
"status": "experimental",
14+
"logsource": {"product": "windows", "category": "process_creation"},
15+
"detection": {
16+
"selection": {
17+
"Image|endswith": ["cmd.exe", "powershell.exe", "pwsh.exe"]
18+
},
19+
"condition": "selection"
20+
},
21+
"level": "medium",
22+
"falsepositives": ["Unknown"],
23+
"author": "Test",
24+
"date": "2024-01-01",
25+
},
26+
[],
27+
),
28+
(
29+
"Non-alphabetical order - issue",
30+
{
31+
"title": "Test Rule",
32+
"description": "Detects test",
33+
"status": "experimental",
34+
"logsource": {"product": "windows", "category": "process_creation"},
35+
"detection": {
36+
"selection": {
37+
"Image|endswith": ["zombie.exe", "cmd.exe", "powershell.exe"]
38+
},
39+
"condition": "selection"
40+
},
41+
"level": "medium",
42+
"falsepositives": ["Unknown"],
43+
"author": "Test",
44+
"date": "2024-01-01",
45+
},
46+
["*zombie.exe*", "*cmd.exe*", "*powershell.exe*"],
47+
),
48+
(
49+
"Two items not in order - issue",
50+
{
51+
"title": "Test Rule",
52+
"description": "Detects test",
53+
"status": "experimental",
54+
"logsource": {"product": "windows", "category": "process_creation"},
55+
"detection": {
56+
"selection": {
57+
"Image|endswith": ["z.exe", "a.exe"]
58+
},
59+
"condition": "selection"
60+
},
61+
"level": "medium",
62+
"falsepositives": ["Unknown"],
63+
"author": "Test",
64+
"date": "2024-01-01",
65+
},
66+
["*z.exe*", "*a.exe*"],
67+
),
68+
(
69+
"Single item - no issue",
70+
{
71+
"title": "Test Rule",
72+
"description": "Detects test",
73+
"status": "experimental",
74+
"logsource": {"product": "windows", "category": "process_creation"},
75+
"detection": {
76+
"selection": {
77+
"Image|endswith": "cmd.exe"
78+
},
79+
"condition": "selection"
80+
},
81+
"level": "medium",
82+
"falsepositives": ["Unknown"],
83+
"author": "Test",
84+
"date": "2024-01-01",
85+
},
86+
[],
87+
),
88+
(
89+
"Mixed - some alphabetical some not",
90+
{
91+
"title": "Test Rule",
92+
"description": "Detects test",
93+
"status": "experimental",
94+
"logsource": {"product": "windows", "category": "process_creation"},
95+
"detection": {
96+
"selection1": {
97+
"Image|endswith": ["a.exe", "b.exe", "c.exe"]
98+
},
99+
"selection2": {
100+
"Image|contains": ["zombie", "cmd", "powershell"]
101+
},
102+
"condition": "1 of selection*"
103+
},
104+
"level": "medium",
105+
"falsepositives": ["Unknown"],
106+
"author": "Test",
107+
"date": "2024-01-01",
108+
},
109+
["*zombie*", "*cmd*", "*powershell*"],
110+
),
111+
]
112+
113+
114+
@pytest.mark.parametrize("name,rule_dict,expected_values", test_cases)
115+
def test_sigmahq_selection_alphabetical_order_validator(name, rule_dict, expected_values):
116+
rule = SigmaRule.from_dict(rule_dict)
117+
validator = SigmahqSelectionAlphabeticalOrderValidator()
118+
issues = validator.validate(rule)
119+
120+
if expected_values:
121+
assert len(issues) == 1
122+
assert issues[0].values == expected_values
123+
else:
124+
assert len(issues) == 0

0 commit comments

Comments
 (0)