Skip to content

Commit 0e5e0ca

Browse files
authored
Merge pull request #217 from UncoderIO/gis-9099
Gis 9099 add microsoft sentinel to one vendor flow
2 parents a749460 + e25af9b commit 0e5e0ca

File tree

5 files changed

+49
-12
lines changed

5 files changed

+49
-12
lines changed

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ def __init__(
7878
parsed_logsources: Optional[dict] = None,
7979
timeframe: Optional[timedelta] = None,
8080
query_period: Optional[timedelta] = None,
81-
mitre_attack: MitreInfoContainer = MitreInfoContainer(),
81+
mitre_attack: Optional[MitreInfoContainer] = None,
8282
raw_metainfo_container: Optional[RawMetaInfoContainer] = None,
8383
) -> None:
8484
self.id = id_ or str(uuid.uuid4())
@@ -88,7 +88,7 @@ def __init__(
8888
self.risk_score = risk_score
8989
self.type_ = type_ or ""
9090
self.description = description or ""
91-
self.author = [v.strip() for v in author] if author else []
91+
self.author = [v.strip() for v in author] if author and author != [None] else []
9292
self.date = date or datetime.now().date().strftime("%Y-%m-%d")
9393
self.output_table_fields = output_table_fields or []
9494
self.query_fields = query_fields or []
@@ -98,15 +98,15 @@ def __init__(
9898
self.severity = severity or SeverityType.low
9999
self.references = references or []
100100
self.tags = tags or []
101-
self.mitre_attack = mitre_attack or None
101+
self.mitre_attack = mitre_attack or MitreInfoContainer()
102102
self.raw_mitre_attack = raw_mitre_attack or []
103103
self.status = status or "stable"
104104
self.false_positives = false_positives or []
105105
self._source_mapping_ids = source_mapping_ids or [DEFAULT_MAPPING_NAME]
106106
self.parsed_logsources = parsed_logsources or {}
107107
self.timeframe = timeframe
108108
self.query_period = query_period
109-
self.raw_metainfo_container = raw_metainfo_container
109+
self.raw_metainfo_container = raw_metainfo_container or RawMetaInfoContainer()
110110

111111
@property
112112
def author_str(self) -> str:

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,18 @@
1919

2020
PLATFORM_DETAILS = {"group_id": "sentinel", "group_name": "Microsoft Sentinel"}
2121

22+
_SENTINEL_KQL_QUERY = "sentinel-kql-query"
23+
_SENTINEL_KQL_RULE = "sentinel-kql-rule"
24+
2225
MICROSOFT_SENTINEL_QUERY_DETAILS = {
23-
"platform_id": "sentinel-kql-query",
26+
"platform_id": _SENTINEL_KQL_QUERY,
2427
"name": "Microsoft Sentinel Query",
2528
"platform_name": "Query (Kusto)",
2629
**PLATFORM_DETAILS,
2730
}
2831

2932
MICROSOFT_SENTINEL_RULE_DETAILS = {
30-
"platform_id": "sentinel-kql-rule",
33+
"platform_id": _SENTINEL_KQL_RULE,
3134
"name": "Microsoft Sentinel Rule",
3235
"platform_name": "Rule (Kusto)",
3336
"first_choice": 0,
@@ -50,6 +53,8 @@
5053
"group_id": "microsoft-defender",
5154
}
5255

56+
MICROSOFT_SENTINEL_QUERY_TYPES = {_SENTINEL_KQL_QUERY, _SENTINEL_KQL_RULE}
57+
5358
microsoft_defender_query_details = PlatformDetails(**MICROSOFT_DEFENDER_DETAILS)
5459
microsoft_sentinel_query_details = PlatformDetails(**MICROSOFT_SENTINEL_QUERY_DETAILS)
5560
microsoft_sentinel_rule_details = PlatformDetails(**MICROSOFT_SENTINEL_RULE_DETAILS)

uncoder-core/app/translator/platforms/microsoft/renders/microsoft_sentinel.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from app.translator.const import DEFAULT_VALUE_TYPE
2323
from app.translator.core.mapping import LogSourceSignature
2424
from app.translator.core.models.platform_details import PlatformDetails
25+
from app.translator.core.models.query_container import RawQueryContainer
2526
from app.translator.core.render import BaseFieldValueRender, PlatformQueryRender
2627
from app.translator.managers import render_manager
2728
from app.translator.platforms.microsoft.const import microsoft_sentinel_query_details
@@ -144,3 +145,6 @@ def generate_prefix(self, log_source_signature: LogSourceSignature, functions_pr
144145
@staticmethod
145146
def _finalize_search_query(query: str) -> str:
146147
return f"| where {query}" if query else ""
148+
149+
def generate_from_raw_query_container(self, query_container: RawQueryContainer) -> str:
150+
return query_container.query

uncoder-core/app/translator/platforms/microsoft/renders/microsoft_sentinel_rule.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
from app.translator.core.custom_types.meta_info import SeverityType
2727
from app.translator.core.mapping import SourceMapping
2828
from app.translator.core.models.platform_details import PlatformDetails
29-
from app.translator.core.models.query_container import MetaInfoContainer, MitreInfoContainer
29+
from app.translator.core.models.query_container import MetaInfoContainer, MitreInfoContainer, RawQueryContainer
3030
from app.translator.managers import render_manager
3131
from app.translator.platforms.microsoft.const import DEFAULT_MICROSOFT_SENTINEL_RULE, microsoft_sentinel_rule_details
3232
from app.translator.platforms.microsoft.mapping import MicrosoftSentinelMappings, microsoft_sentinel_rule_mappings
@@ -107,7 +107,8 @@ def finalize_query(
107107
*args, # noqa: ARG002
108108
**kwargs, # noqa: ARG002
109109
) -> str:
110-
query = super().finalize_query(prefix=prefix, query=query, functions=functions)
110+
if not kwargs.get("raw_query", False):
111+
query = super().finalize_query(prefix=prefix, query=query, functions=functions)
111112
rule = copy.deepcopy(DEFAULT_MICROSOFT_SENTINEL_RULE)
112113
rule["query"] = query
113114
rule["displayName"] = meta_info.title or _AUTOGENERATED_TEMPLATE
@@ -130,3 +131,8 @@ def finalize_query(
130131
json_rule = json.dumps(rule, indent=4, sort_keys=False)
131132
json_rule = self.wrap_with_unmapped_fields(json_rule, unmapped_fields)
132133
return self.wrap_with_not_supported_functions(json_rule, not_supported_functions)
134+
135+
def generate_from_raw_query_container(self, query_container: RawQueryContainer) -> str:
136+
return self.finalize_query(
137+
prefix="", query=query_container.query, functions="", meta_info=query_container.meta_info, raw_query=True
138+
)

uncoder-core/app/translator/translator.py

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
import logging
2-
from typing import Optional
2+
from collections import Counter
3+
from typing import Optional, Union
34

45
from app.translator.core.exceptions.core import UnsupportedPlatform
56
from app.translator.core.models.query_container import RawQueryContainer, TokenizedQueryContainer
6-
from app.translator.core.parser import QueryParser
7+
from app.translator.core.parser import PlatformQueryParser, QueryParser
78
from app.translator.core.render import QueryRender
89
from app.translator.managers import ParserManager, RenderManager, parser_manager, render_manager
910
from app.translator.platforms.elasticsearch.const import ELASTIC_QUERY_TYPES
11+
from app.translator.platforms.microsoft.const import MICROSOFT_SENTINEL_QUERY_TYPES
12+
from app.translator.platforms.roota.parsers.roota import RootAParser
13+
from app.translator.platforms.sigma.mapping import sigma_rule_mappings
1014
from app.translator.tools.decorators import handle_translation_exceptions
1115

1216

@@ -32,18 +36,36 @@ def __get_render(self, target: str) -> QueryRender:
3236

3337
@staticmethod
3438
def __is_one_vendor_translation(source: str, target: str) -> bool:
35-
vendors_query_types = [ELASTIC_QUERY_TYPES]
39+
vendors_query_types = [ELASTIC_QUERY_TYPES, MICROSOFT_SENTINEL_QUERY_TYPES]
3640
for vendor_query_types in vendors_query_types:
3741
if source in vendor_query_types and target in vendor_query_types:
3842
return True
3943

4044
return False
4145

42-
def parse_raw_query(self, text: str, source: str) -> tuple[QueryParser, RawQueryContainer]:
46+
def parse_raw_query(
47+
self, text: str, source: str
48+
) -> tuple[Union[PlatformQueryParser, RootAParser], RawQueryContainer]:
4349
parser = self.__get_parser(source)
4450
text = parser.remove_comments(text)
4551
return parser, parser.parse_raw_query(text, language=source)
4652

53+
def parse_meta_info(self, text: str, source: str) -> Union[dict, RawQueryContainer]:
54+
parser, raw_query_container = self.parse_raw_query(text=text, source=source)
55+
source_mappings = parser.get_source_mapping_ids_by_logsources(raw_query_container.query)
56+
log_sources = {"product": Counter(), "service": Counter(), "category": Counter()}
57+
sigma_source_mappings = sigma_rule_mappings.get_source_mappings_by_ids(
58+
[source_mapping.source_id for source_mapping in source_mappings], return_default=False
59+
)
60+
for sigma_source_mapping in sigma_source_mappings:
61+
if product := sigma_source_mapping.log_source_signature.log_sources.get("product"):
62+
log_sources["product"][product] += 1
63+
if service := sigma_source_mapping.log_source_signature.log_sources.get("service"):
64+
log_sources["service"][service] += 1
65+
if category := sigma_source_mapping.log_source_signature.log_sources.get("category"):
66+
log_sources["category"][category] += 1
67+
return log_sources, raw_query_container
68+
4769
@handle_translation_exceptions
4870
def __parse_incoming_data(
4971
self, text: str, source: str, target: Optional[str] = None

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