Skip to content

Commit 3813a08

Browse files
[FR] Add support for BBR rules to the rule loader (#2968)
--------- Co-authored-by: eric-forte-elastic <[email protected]>
1 parent 77b43d1 commit 3813a08

6 files changed

+29
-29
lines changed

detection_rules/packaging.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
from .misc import JS_LICENSE, cached, load_current_package_version
2222
from .navigator import NavigatorBuilder, Navigator
2323
from .rule import TOMLRule, QueryRuleData, ThreatMapping
24-
from .rule_loader import DeprecatedCollection, RuleCollection, DEFAULT_RULES_DIR
24+
from .rule_loader import DeprecatedCollection, RuleCollection, DEFAULT_RULES_DIR, DEFAULT_BBR_DIR
2525
from .schemas import definitions
2626
from .utils import Ndjson, get_path, get_etc_path, load_etc_dump
2727
from .version_lock import default_version_lock
@@ -466,13 +466,19 @@ def create_bulk_index_body(self) -> Tuple[Ndjson, Ndjson]:
466466
status = 'unmodified'
467467

468468
bulk_upload_docs.append(create)
469+
470+
try:
471+
relative_path = str(rule.path.resolve().relative_to(DEFAULT_RULES_DIR))
472+
except ValueError:
473+
relative_path = str(rule.path.resolve().relative_to(DEFAULT_BBR_DIR))
474+
469475
rule_doc = dict(hash=rule.contents.sha256(),
470476
source='repo',
471477
datetime_uploaded=now,
472478
status=status,
473479
package_version=self.name,
474480
flat_mitre=ThreatMapping.flatten(rule.contents.data.threat).to_dict(),
475-
relative_path=str(rule.path.resolve().relative_to(DEFAULT_RULES_DIR)))
481+
relative_path=relative_path)
476482
rule_doc.update(**rule.contents.to_api_format())
477483
bulk_upload_docs.append(rule_doc)
478484
importable_rules_docs.append(rule_doc)

detection_rules/rule_loader.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ def default(cls) -> 'RuleCollection':
349349
if cls.__default is None:
350350
collection = RuleCollection()
351351
collection.load_directory(DEFAULT_RULES_DIR)
352+
collection.load_directory(DEFAULT_BBR_DIR)
352353
collection.freeze()
353354
cls.__default = collection
354355

rules_building_block/command_and_control_non_standard_http_port.toml

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ integration = ["endpoint"]
44
maturity = "production"
55
min_stack_comments = "New fields added: required_fields, related_integrations, setup"
66
min_stack_version = "8.3.0"
7-
updated_date = "2023/07/10"
7+
updated_date = "2023/07/26"
88

99
[rule]
1010
author = ["Elastic"]
@@ -37,18 +37,12 @@ network where process.name : ("http", "https")
3737

3838
[[rule.threat]]
3939
framework = "MITRE ATT&CK"
40+
4041
[[rule.threat.technique]]
4142
id = "T1571"
4243
name = "Non-Standard Port"
4344
reference = "https://attack.mitre.org/techniques/T1571/"
4445

45-
46-
[rule.threat.tactic]
47-
id = "TA0011"
48-
name = "Command and Control"
49-
reference = "https://attack.mitre.org/tactics/TA0011/"
50-
[[rule.threat]]
51-
framework = "MITRE ATT&CK"
5246
[[rule.threat.technique]]
5347
id = "T1071"
5448
name = "Application Layer Protocol"
@@ -58,14 +52,6 @@ id = "T1071.001"
5852
name = "Web Protocols"
5953
reference = "https://attack.mitre.org/techniques/T1071/001/"
6054

61-
62-
63-
[rule.threat.tactic]
64-
id = "TA0011"
65-
name = "Command and Control"
66-
reference = "https://attack.mitre.org/tactics/TA0011/"
67-
[[rule.threat]]
68-
framework = "MITRE ATT&CK"
6955
[[rule.threat.technique]]
7056
id = "T1573"
7157
name = "Encrypted Channel"
@@ -75,7 +61,7 @@ id = "T1573.001"
7561
name = "Symmetric Cryptography"
7662
reference = "https://attack.mitre.org/techniques/T1573/001/"
7763
[[rule.threat.technique.subtechnique]]
78-
id = "T1573.001"
64+
id = "T1573.002"
7965
name = "Asymmetric Cryptography"
8066
reference = "https://attack.mitre.org/techniques/T1573/002/"
8167

rules_building_block/discovery_posh_generic.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ integration = ["windows"]
44
maturity = "production"
55
min_stack_comments = "New fields added: required_fields, related_integrations, setup"
66
min_stack_version = "8.3.0"
7-
updated_date = "2023/07/06"
7+
updated_date = "2023/07/26"
88

99

1010
[rule]
@@ -40,7 +40,7 @@ reg add "hklm\\SOFTWARE\\Policies\\Microsoft\\Windows\\PowerShell\\ScriptBlockLo
4040
risk_score = 21
4141
rule_id = "1e0a3f7c-21e7-4bb1-98c7-2036612fb1be"
4242
severity = "low"
43-
tags = ["Domain: Endpoint", "OS: Windows", "Use Case: Threat Detection", "Tactic: Collection", "Data Source: PowerShell Logs", "Rule Type: BBR"]
43+
tags = ["Domain: Endpoint", "OS: Windows", "Use Case: Threat Detection", "Tactic: Collection", "Tactic: Discovery", "Data Source: PowerShell Logs", "Rule Type: BBR"]
4444
timestamp_override = "event.ingested"
4545
type = "query"
4646
building_block_type = "default"

rules_building_block/discovery_windows_system_information_discovery.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ integration = ["windows", "endpoint"]
44
maturity = "production"
55
min_stack_comments = "New fields added: required_fields, related_integrations, setup"
66
min_stack_version = "8.3.0"
7-
updated_date = "2023/07/06"
7+
updated_date = "2023/07/26"
88

99
[rule]
1010
author = ["Elastic"]
@@ -50,7 +50,7 @@ process.parent.executable : (
5050
framework = "MITRE ATT&CK"
5151
[[rule.threat.technique]]
5252
id = "T1082"
53-
name = "System Service Discovery"
53+
name = "System Information Discovery"
5454
reference = "https://attack.mitre.org/techniques/T1082/"
5555

5656
[rule.threat.tactic]

tests/test_all_rules.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -499,9 +499,10 @@ def test_non_bbr_in_correct_dir(self):
499499
for rule in self.all_rules:
500500
if rule.path.parent.name == 'rules_building_block':
501501
self.assertIn(rule, self.bbr, f'{self.rule_str(rule)} should be in the {proper_directory}')
502-
# Is the rule of type BBR
503-
self.assertEqual(rule.contents.data.building_block_type, None,
504-
f'{self.rule_str(rule)} should not have building_block_type or be in {proper_directory}')
502+
else:
503+
# Is the rule of type BBR and not in the correct directory
504+
self.assertEqual(rule.contents.data.building_block_type, None,
505+
f'{self.rule_str(rule)} should be in {proper_directory}')
505506

506507

507508
class TestRuleMetadata(BaseRuleTest):
@@ -530,9 +531,15 @@ def test_deprecated_rules(self):
530531
rules_path = get_path('rules')
531532
deprecated_path = get_path("rules", "_deprecated")
532533

533-
misplaced_rules = [r for r in self.all_rules
534-
if r.path.relative_to(rules_path).parts[-2] == '_deprecated' and # noqa: W504
535-
r.contents.metadata.maturity != 'deprecated']
534+
misplaced_rules = []
535+
for r in self.all_rules:
536+
if "rules_building_block" in str(r.path):
537+
if r.contents.metadata.maturity == "deprecated":
538+
misplaced_rules.append(r)
539+
elif r.path.relative_to(rules_path).parts[-2] == "_deprecated" \
540+
and r.contents.metadata.maturity != "deprecated":
541+
misplaced_rules.append(r)
542+
536543
misplaced = '\n'.join(f'{self.rule_str(r)} {r.contents.metadata.maturity}' for r in misplaced_rules)
537544
err_str = f'The following rules are stored in {deprecated_path} but are not marked as deprecated:\n{misplaced}'
538545
self.assertListEqual(misplaced_rules, [], err_str)

0 commit comments

Comments
 (0)