Skip to content

Commit 8d06469

Browse files
authored
Merge pull request #192 from UncoderIO/gis-8502
Gis 8502
2 parents 3f24987 + 9a8bdba commit 8d06469

File tree

6 files changed

+94
-5
lines changed

6 files changed

+94
-5
lines changed

uncoder-core/app/translator/core/exceptions/core.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,5 +84,9 @@ class InvalidJSONStructure(InvalidRuleStructure):
8484
rule_type: str = "JSON"
8585

8686

87+
class InvalidTOMLStructure(InvalidRuleStructure):
88+
rule_type: str = "TOML"
89+
90+
8791
class InvalidXMLStructure(InvalidRuleStructure):
8892
rule_type: str = "XML"

uncoder-core/app/translator/core/mixins/rule.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
import json
22
from typing import Union
33

4+
import toml
45
import xmltodict
56
import yaml
67

7-
from app.translator.core.exceptions.core import InvalidJSONStructure, InvalidXMLStructure, InvalidYamlStructure
8+
from app.translator.core.exceptions.core import (
9+
InvalidJSONStructure,
10+
InvalidTOMLStructure,
11+
InvalidXMLStructure,
12+
InvalidYamlStructure,
13+
)
814
from app.translator.core.mitre import MitreConfig, MitreInfoContainer
915

1016

@@ -50,3 +56,14 @@ def load_rule(text: Union[str, bytes]) -> dict:
5056
return xmltodict.parse(text)
5157
except Exception as err:
5258
raise InvalidXMLStructure(error=str(err)) from err
59+
60+
61+
class TOMLRuleMixin:
62+
mitre_config: MitreConfig = MitreConfig()
63+
64+
@staticmethod
65+
def load_rule(text: str) -> dict:
66+
try:
67+
return toml.loads(text)
68+
except toml.TomlDecodeError as err:
69+
raise InvalidTOMLStructure(error=str(err)) from err

uncoder-core/app/translator/core/models/query_container.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,18 +39,26 @@ def __init__(
3939
trigger_threshold: Optional[str] = None,
4040
query_frequency: Optional[str] = None,
4141
query_period: Optional[str] = None,
42+
from_: Optional[str] = None,
43+
interval: Optional[str] = None,
4244
) -> None:
4345
self.trigger_operator = trigger_operator
4446
self.trigger_threshold = trigger_threshold
4547
self.query_frequency = query_frequency
4648
self.query_period = query_period
49+
self.from_ = from_
50+
self.interval = interval
4751

4852

4953
class MetaInfoContainer:
5054
def __init__(
5155
self,
5256
*,
5357
id_: Optional[str] = None,
58+
index: Optional[list[str]] = None,
59+
language: Optional[str] = None,
60+
risk_score: Optional[int] = None,
61+
type_: Optional[str] = None,
5462
title: Optional[str] = None,
5563
description: Optional[str] = None,
5664
author: Optional[list[str]] = None,
@@ -73,6 +81,10 @@ def __init__(
7381
) -> None:
7482
self.id = id_ or str(uuid.uuid4())
7583
self.title = title or ""
84+
self.index = index or []
85+
self.language = language or ""
86+
self.risk_score = risk_score
87+
self.type_ = type_ or ""
7688
self.description = description or ""
7789
self.author = [v.strip() for v in author] if author else []
7890
self.date = date or datetime.now().date().strftime("%Y-%m-%d")

uncoder-core/app/translator/platforms/elasticsearch/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
from app.translator.platforms.elasticsearch.parsers.detection_rule import ElasticSearchRuleParser # noqa: F401
1+
from app.translator.platforms.elasticsearch.parsers.detection_rule import (
2+
ElasticSearchRuleParser, # noqa: F401
3+
ElasticSearchRuleTOMLParser, # noqa: F401
4+
)
25
from app.translator.platforms.elasticsearch.parsers.elasticsearch import ElasticSearchQueryParser # noqa: F401
36
from app.translator.platforms.elasticsearch.renders.detection_rule import ElasticSearchRuleRender # noqa: F401
47
from app.translator.platforms.elasticsearch.renders.elast_alert import ElastAlertRuleRender # noqa: F401

uncoder-core/app/translator/platforms/elasticsearch/const.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
_ELASTIC_LUCENE_QUERY = "elastic-lucene-query"
77
_ELASTIC_LUCENE_RULE = "elastic-lucene-rule"
8+
_ELASTIC_LUCENE_RULE_TOML = "elastic-lucene-rule-toml"
89
_ELASTIC_KIBANA_RULE = "elastic-kibana-rule"
910
_ELASTALERT_LUCENE_RULE = "elastalert-lucene-rule"
1011
_ELASTIC_WATCHER_RULE = "elastic-watcher-rule"
@@ -50,6 +51,14 @@
5051
**PLATFORM_DETAILS,
5152
}
5253

54+
ELASTICSEARCH_RULE_TOML_DETAILS = {
55+
"platform_id": _ELASTIC_LUCENE_RULE_TOML,
56+
"name": "Elastic Rule TOML",
57+
"platform_name": "Detection Rule (Lucene) TOML",
58+
"first_choice": 0,
59+
**PLATFORM_DETAILS,
60+
}
61+
5362
KIBANA_DETAILS = {
5463
"platform_id": _ELASTIC_KIBANA_RULE,
5564
"name": "Elastic Kibana Saved Search",
@@ -78,6 +87,7 @@
7887
elasticsearch_esql_query_details = PlatformDetails(**ELASTICSEARCH_ESQL_QUERY_DETAILS)
7988
elasticsearch_esql_rule_details = PlatformDetails(**ELASTICSEARCH_ESQL_RULE_DETAILS)
8089
elasticsearch_rule_details = PlatformDetails(**ELASTICSEARCH_RULE_DETAILS)
90+
elasticsearch_rule_toml_details = PlatformDetails(**ELASTICSEARCH_RULE_TOML_DETAILS)
8191
elastalert_details = PlatformDetails(**ELASTALERT_DETAILS)
8292
kibana_rule_details = PlatformDetails(**KIBANA_DETAILS)
8393
xpack_watcher_details = PlatformDetails(**XPACK_WATCHER_DETAILS)

uncoder-core/app/translator/platforms/elasticsearch/parsers/detection_rule.py

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,13 @@
1515
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1616
-----------------------------------------------------------------
1717
"""
18+
from datetime import datetime
1819

19-
from app.translator.core.mixins.rule import JsonRuleMixin
20+
from app.translator.core.mixins.rule import JsonRuleMixin, TOMLRuleMixin
2021
from app.translator.core.models.platform_details import PlatformDetails
21-
from app.translator.core.models.query_container import MetaInfoContainer, RawQueryContainer
22+
from app.translator.core.models.query_container import MetaInfoContainer, RawMetaInfoContainer, RawQueryContainer
2223
from app.translator.managers import parser_manager
23-
from app.translator.platforms.elasticsearch.const import elasticsearch_rule_details
24+
from app.translator.platforms.elasticsearch.const import elasticsearch_rule_details, elasticsearch_rule_toml_details
2425
from app.translator.platforms.elasticsearch.parsers.elasticsearch import ElasticSearchQueryParser
2526
from app.translator.tools.utils import parse_rule_description_str
2627

@@ -53,3 +54,45 @@ def parse_raw_query(self, text: str, language: str) -> RawQueryContainer:
5354
mitre_attack=mitre_attack,
5455
),
5556
)
57+
58+
59+
@parser_manager.register
60+
class ElasticSearchRuleTOMLParser(ElasticSearchQueryParser, TOMLRuleMixin):
61+
details: PlatformDetails = elasticsearch_rule_toml_details
62+
63+
def parse_raw_query(self, text: str, language: str) -> RawQueryContainer:
64+
raw_rule = self.load_rule(text=text)
65+
rule = raw_rule.get("rule")
66+
metadata = raw_rule.get("metadata")
67+
techniques = []
68+
for threat_data in rule.get("threat", []):
69+
if threat_data.get("technique"):
70+
techniques.append(threat_data["technique"][0]["id"].lower())
71+
mitre_attack = self.mitre_config.get_mitre_info(
72+
tactics=[threat_data["tactic"]["name"].replace(" ", "_").lower() for threat_data in rule.get("threat", [])],
73+
techniques=techniques,
74+
)
75+
date = None
76+
if metadata.get("creation_date"):
77+
date = datetime.strptime(metadata.get("creation_date"), "%Y/%m/%d").strftime("%Y-%m-%d")
78+
return RawQueryContainer(
79+
query=rule["query"],
80+
language=language,
81+
meta_info=MetaInfoContainer(
82+
id_=rule.get("rule_id"),
83+
title=rule.get("name"),
84+
description=rule.get("description"),
85+
author=rule.get("author"),
86+
date=date,
87+
license_=rule.get("license"),
88+
severity=rule.get("severity"),
89+
references=rule.get("references"),
90+
tags=rule.get("tags"),
91+
mitre_attack=mitre_attack,
92+
index=rule.get("index"),
93+
language=rule.get("language"),
94+
risk_score=rule.get("risk_score"),
95+
type_=rule.get("type"),
96+
raw_metainfo_container=RawMetaInfoContainer(from_=rule.get("from"), interval=rule.get("interval")),
97+
),
98+
)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy