Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit4a1d3e3

Browse files
author
oleksandr.volha
committed
resolve conflicts
2 parents69f8f6c +8d06469 commit4a1d3e3

File tree

41 files changed

+3654
-120
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+3654
-120
lines changed

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
fromtypingimportOptional
22

33

4-
classNotImplementedException(BaseException):
5-
...
6-
7-
84
classBasePlatformException(BaseException):
95
...
106

@@ -88,5 +84,9 @@ class InvalidJSONStructure(InvalidRuleStructure):
8884
rule_type:str="JSON"
8985

9086

87+
classInvalidTOMLStructure(InvalidRuleStructure):
88+
rule_type:str="TOML"
89+
90+
9191
classInvalidXMLStructure(InvalidRuleStructure):
9292
rule_type:str="XML"

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@ class FunctionRenderException(BaseRenderException):
1414

1515
classUnsupportedRenderMethod(BaseRenderException):
1616
def__init__(self,platform_name:str,method:str):
17-
message=f"Cannot translate.{platform_name} backend does not support{method}."
17+
message=f'Cannot translate.{platform_name} backend does not support"{method}".'
1818
super().__init__(message)

‎uncoder-core/app/translator/core/mapping.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ def prepare_mapping(self) -> dict[str, SourceMapping]:
116116
default_mapping=SourceMapping(source_id=DEFAULT_MAPPING_NAME)
117117
formapping_dictinself._loader.load_platform_mappings(self._platform_dir):
118118
log_source_signature=self.prepare_log_source_signature(mapping=mapping_dict)
119-
if (source_id:=mapping_dict["source"])==DEFAULT_MAPPING_NAME:
119+
if (source_id:=mapping_dict.get("source"))==DEFAULT_MAPPING_NAME:
120120
default_mapping.log_source_signature=log_source_signature
121121
ifself.skip_load_default_mappings:
122122
continue

‎uncoder-core/app/translator/core/mitre.py‎

Lines changed: 114 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,90 @@
33
importssl
44
importurllib.request
55
fromjsonimportJSONDecodeError
6-
fromtypingimportOptional
6+
fromtypingimportOptional,Union
77
fromurllib.errorimportHTTPError
88

99
fromapp.translator.core.models.query_containerimportMitreInfoContainer,MitreTacticContainer,MitreTechniqueContainer
1010
fromapp.translator.tools.singleton_metaimportSingletonMeta
1111
fromconstimportROOT_PROJECT_PATH
1212

1313

14+
classTrieNode:
15+
def__init__(self):
16+
self.children= {}
17+
self.is_end_of_word=False
18+
self.result=None
19+
20+
21+
classTrie:
22+
"""
23+
Trie (prefix tree) data structure for storing and searching Mitre ATT&CK Techniques and Tactics strings.
24+
25+
This class handles the insertion and searching of strings related to Mitre ATT&CK Techniques and Tactics, even when
26+
the strings have variations in spacing, case, or underscores. By normalizing the text—converting it to lowercase and
27+
removing spaces and underscores—different variations of the same logical string are treated as equivalent.
28+
29+
It means strings 'CredentialAccess', 'credential Access', and 'credential_access' will be processed identically,
30+
leading to the same result.
31+
"""
32+
33+
def__init__(self):
34+
self.root=TrieNode()
35+
36+
defnormalize_text(self,text:str)->str:
37+
returntext.replace(" ","").lower().replace("_","").lower()
38+
39+
definsert(self,text:str,result:Union[MitreTacticContainer,MitreTechniqueContainer])->None:
40+
node=self.root
41+
normalized_text=self.normalize_text(text)
42+
43+
forcharinnormalized_text:
44+
ifcharnotinnode.children:
45+
node.children[char]=TrieNode()
46+
node=node.children[char]
47+
48+
node.is_end_of_word=True
49+
node.result=result
50+
51+
52+
classTacticsTrie(Trie):
53+
def__init__(self):
54+
self.root=TrieNode()
55+
56+
defsearch(self,text:str)->Optional[MitreTacticContainer]:
57+
node:TrieNode=self.root
58+
normalized_text=self.normalize_text(text)
59+
60+
forcharinnormalized_text:
61+
ifcharnotinnode.children:
62+
return
63+
node=node.children[char]
64+
65+
ifnode.is_end_of_word:
66+
returnnode.result
67+
68+
69+
classTechniquesTrie(Trie):
70+
defsearch(self,text:str)->Optional[MitreTechniqueContainer]:
71+
node:TrieNode=self.root
72+
normalized_text=self.normalize_text(text)
73+
74+
forcharinnormalized_text:
75+
ifcharnotinnode.children:
76+
return
77+
node=node.children[char]
78+
79+
ifnode.is_end_of_word:
80+
returnnode.result
81+
82+
1483
classMitreConfig(metaclass=SingletonMeta):
1584
config_url:str="https://raw.githubusercontent.com/mitre/cti/master/enterprise-attack/enterprise-attack.json"
1685
mitre_source_types:tuple= ("mitre-attack",)
1786

1887
def__init__(self,server:bool=False):
19-
self.tactics= {}
20-
self.techniques= {}
88+
self.tactics:TacticsTrie=TacticsTrie()
89+
self.techniques:TechniquesTrie=TechniquesTrie()
2190
ifnotserver:
2291
self.__load_mitre_configs_from_files()
2392

@@ -44,7 +113,6 @@ def update_mitre_config(self) -> None: # noqa: PLR0912
44113
return
45114

46115
tactic_map= {}
47-
technique_map= {}
48116

49117
# Map the tactics
50118
forentryinmitre_json["objects"]:
@@ -53,11 +121,12 @@ def update_mitre_config(self) -> None: # noqa: PLR0912
53121
forrefinentry["external_references"]:
54122
ifref["source_name"]=="mitre-attack":
55123
tactic_map[entry["x_mitre_shortname"]]=entry["name"]
56-
self.tactics[entry["name"].replace(" ","_").lower()]= {
57-
"external_id":ref["external_id"],
58-
"url":ref["url"],
59-
"tactic":entry["name"],
60-
}
124+
125+
tactic_data=MitreTacticContainer(
126+
external_id=ref["external_id"],url=ref["url"],name=entry["name"]
127+
)
128+
self.tactics.insert(entry["name"],tactic_data)
129+
61130
break
62131

63132
# Map the techniques
@@ -68,19 +137,15 @@ def update_mitre_config(self) -> None: # noqa: PLR0912
68137
continue
69138
forrefinentry["external_references"]:
70139
ifref["source_name"]inself.mitre_source_types:
71-
technique_map[ref["external_id"]]=entry["name"]
72140
sub_tactics= []
73-
# Get Mitre Tactics (Kill-Chains)
74141
fortacticinentry["kill_chain_phases"]:
75142
iftactic["kill_chain_name"]inself.mitre_source_types:
76-
# Map the short phase_name to tactic name
77143
sub_tactics.append(tactic_map[tactic["phase_name"]])
78-
self.techniques[ref["external_id"].lower()]= {
79-
"technique_id":ref["external_id"],
80-
"technique":entry["name"],
81-
"url":ref["url"],
82-
"tactic":sub_tactics,
83-
}
144+
145+
technique_data=MitreTechniqueContainer(
146+
technique_id=ref["external_id"],name=entry["name"],url=ref["url"],tactic=sub_tactics
147+
)
148+
self.techniques.insert(ref["external_id"],technique_data)
84149
break
85150

86151
# Map the sub-techniques
@@ -92,58 +157,60 @@ def update_mitre_config(self) -> None: # noqa: PLR0912
92157
ifref["source_name"]inself.mitre_source_types:
93158
sub_technique_id=ref["external_id"]
94159
sub_technique_name=entry["name"]
95-
parent_technique_name=technique_map[sub_technique_id.split(".")[0]]
96-
parent_tactics=self.techniques.get(sub_technique_id.split(".")[0].lower(), {}).get(
97-
"tactic", []
98-
)
99-
sub_technique_name=f"{parent_technique_name} :{sub_technique_name}"
100-
self.techniques[ref["external_id"].lower()]= {
101-
"technique_id":ref["external_id"],
102-
"technique":sub_technique_name,
103-
"url":ref["url"],
104-
"tactic":parent_tactics,
105-
}
160+
ifparent_technique:=self.techniques.search(sub_technique_id.split(".")[0]):
161+
sub_technique_name=f"{parent_technique.name} :{sub_technique_name}"
162+
sub_technique_data=MitreTechniqueContainer(
163+
technique_id=ref["external_id"],
164+
name=sub_technique_name,
165+
url=ref["url"],
166+
tactic=parent_technique.tactic,
167+
)
168+
self.techniques.insert(sub_technique_id,sub_technique_data)
106169
break
107170

108171
def__load_mitre_configs_from_files(self)->None:
109172
try:
110173
withopen(os.path.join(ROOT_PROJECT_PATH,"app/dictionaries/tactics.json"))asfile:
111-
self.tactics=json.load(file)
174+
loaded=json.load(file)
175+
176+
fortactic_name,tactic_datainloaded.items():
177+
tactic=MitreTacticContainer(
178+
external_id=tactic_data["external_id"],url=tactic_data["url"],name=tactic_data["tactic"]
179+
)
180+
self.tactics.insert(tactic_name,tactic)
112181
exceptJSONDecodeError:
113-
self.tactics= {}
182+
print("Unable to load MITRE Tactics")
114183

115184
try:
116185
withopen(os.path.join(ROOT_PROJECT_PATH,"app/dictionaries/techniques.json"))asfile:
117-
self.techniques=json.load(file)
186+
loaded=json.load(file)
187+
fortechnique_id,technique_datainloaded.items():
188+
technique=MitreTechniqueContainer(
189+
technique_id=technique_data["technique_id"],
190+
name=technique_data["technique"],
191+
url=technique_data["url"],
192+
tactic=technique_data.get("tactic", []),
193+
)
194+
self.techniques.insert(technique_id,technique)
118195
exceptJSONDecodeError:
119-
self.techniques= {}
196+
print("Unable to load MITRE Techniques")
120197

121198
defget_tactic(self,tactic:str)->Optional[MitreTacticContainer]:
122-
tactic=tactic.replace(".","_")
123-
iftactic_found:=self.tactics.get(tactic):
124-
returnMitreTacticContainer(
125-
external_id=tactic_found["external_id"],url=tactic_found["url"],name=tactic_found["tactic"]
126-
)
199+
returnself.tactics.search(tactic)
127200

128201
defget_technique(self,technique_id:str)->Optional[MitreTechniqueContainer]:
129-
iftechnique_found:=self.techniques.get(technique_id):
130-
returnMitreTechniqueContainer(
131-
technique_id=technique_found["technique_id"],
132-
name=technique_found["technique"],
133-
url=technique_found["url"],
134-
tactic=technique_found["tactic"],
135-
)
202+
returnself.techniques.search(technique_id)
136203

137204
defget_mitre_info(
138205
self,tactics:Optional[list[str]]=None,techniques:Optional[list[str]]=None
139206
)->MitreInfoContainer:
140207
tactics_list= []
141208
techniques_list= []
142209
fortacticintacticsor []:
143-
iftactic_found:=self.get_tactic(tactic=tactic.lower()):
210+
iftactic_found:=self.tactics.search(tactic):
144211
tactics_list.append(tactic_found)
145212
fortechniqueintechniquesor []:
146-
iftechnique_found:=self.get_technique(technique_id=technique.lower()):
213+
iftechnique_found:=self.techniques.search(technique):
147214
techniques_list.append(technique_found)
148215
returnMitreInfoContainer(
149216
tactics=sorted(tactics_list,key=lambdax:x.name),

‎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
importjson
22
fromtypingimportUnion
33

4+
importtoml
45
importxmltodict
56
importyaml
67

7-
fromapp.translator.core.exceptions.coreimportInvalidJSONStructure,InvalidXMLStructure,InvalidYamlStructure
8+
fromapp.translator.core.exceptions.coreimport (
9+
InvalidJSONStructure,
10+
InvalidTOMLStructure,
11+
InvalidXMLStructure,
12+
InvalidYamlStructure,
13+
)
814
fromapp.translator.core.mitreimportMitreConfig,MitreInfoContainer
915

1016

@@ -50,3 +56,14 @@ def load_rule(text: Union[str, bytes]) -> dict:
5056
returnxmltodict.parse(text)
5157
exceptExceptionaserr:
5258
raiseInvalidXMLStructure(error=str(err))fromerr
59+
60+
61+
classTOMLRuleMixin:
62+
mitre_config:MitreConfig=MitreConfig()
63+
64+
@staticmethod
65+
defload_rule(text:str)->dict:
66+
try:
67+
returntoml.loads(text)
68+
excepttoml.TomlDecodeErroraserr:
69+
raiseInvalidTOMLStructure(error=str(err))fromerr

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

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,34 @@ class MitreInfoContainer:
3131
techniques:list[MitreTechniqueContainer]=field(default_factory=list)
3232

3333

34+
classRawMetaInfoContainer:
35+
def__init__(
36+
self,
37+
*,
38+
trigger_operator:Optional[str]=None,
39+
trigger_threshold:Optional[str]=None,
40+
query_frequency:Optional[str]=None,
41+
query_period:Optional[str]=None,
42+
from_:Optional[str]=None,
43+
interval:Optional[str]=None,
44+
)->None:
45+
self.trigger_operator=trigger_operator
46+
self.trigger_threshold=trigger_threshold
47+
self.query_frequency=query_frequency
48+
self.query_period=query_period
49+
self.from_=from_
50+
self.interval=interval
51+
52+
3453
classMetaInfoContainer:
3554
def__init__(
3655
self,
3756
*,
3857
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,
3962
title:Optional[str]=None,
4063
description:Optional[str]=None,
4164
author:Optional[list[str]]=None,
@@ -52,10 +75,16 @@ def __init__(
5275
source_mapping_ids:Optional[list[str]]=None,
5376
parsed_logsources:Optional[dict]=None,
5477
timeframe:Optional[timedelta]=None,
78+
query_period:Optional[timedelta]=None,
5579
mitre_attack:MitreInfoContainer=MitreInfoContainer(),
80+
raw_metainfo_container:Optional[RawMetaInfoContainer]=None,
5681
)->None:
5782
self.id=id_orstr(uuid.uuid4())
5883
self.title=titleor""
84+
self.index=indexor []
85+
self.language=languageor""
86+
self.risk_score=risk_score
87+
self.type_=type_or""
5988
self.description=descriptionor""
6089
self.author= [v.strip()forvinauthor]ifauthorelse []
6190
self.date=dateordatetime.now().date().strftime("%Y-%m-%d")
@@ -72,6 +101,8 @@ def __init__(
72101
self._source_mapping_ids=source_mapping_idsor [DEFAULT_MAPPING_NAME]
73102
self.parsed_logsources=parsed_logsourcesor {}
74103
self.timeframe=timeframe
104+
self.query_period=query_period
105+
self.raw_metainfo_container=raw_metainfo_container
75106

76107
@property
77108
defauthor_str(self)->str:

‎uncoder-core/app/translator/core/parser.py‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,3 @@ def get_source_mappings(
8383
source_mappings=self.mappings.get_suitable_source_mappings(field_names=field_names,log_sources=log_sources)
8484
self.tokenizer.set_field_tokens_generic_names_map(field_tokens,source_mappings,self.mappings.default_mapping)
8585
returnsource_mappings
86-

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp