txt2stix 1.0.2__py3-none-any.whl → 1.0.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- txt2stix/attack_flow.py +28 -11
- txt2stix/txt2stix.py +2 -2
- {txt2stix-1.0.2.dist-info → txt2stix-1.0.4.dist-info}/METADATA +1 -1
- {txt2stix-1.0.2.dist-info → txt2stix-1.0.4.dist-info}/RECORD +7 -7
- {txt2stix-1.0.2.dist-info → txt2stix-1.0.4.dist-info}/WHEEL +0 -0
- {txt2stix-1.0.2.dist-info → txt2stix-1.0.4.dist-info}/entry_points.txt +0 -0
- {txt2stix-1.0.2.dist-info → txt2stix-1.0.4.dist-info}/licenses/LICENSE +0 -0
txt2stix/attack_flow.py
CHANGED
@@ -21,14 +21,14 @@ def parse_flow(report, flow: AttackFlowList, techniques, tactics):
|
|
21
21
|
for i, item in enumerate(flow.items):
|
22
22
|
try:
|
23
23
|
technique = techniques[item.attack_technique_id]
|
24
|
-
tactic_id = technique[
|
24
|
+
tactic_id = technique["possible_tactics"][
|
25
|
+
flow.tactic_mapping[item.attack_technique_id]
|
26
|
+
]
|
25
27
|
technique_obj = technique["stix_obj"]
|
26
28
|
tactic_obj = tactics[technique["domain"]][tactic_id]
|
27
29
|
action_obj = AttackAction(
|
28
30
|
**{
|
29
|
-
"id": flow_id(
|
30
|
-
report["id"], item.attack_technique_id, tactic_id
|
31
|
-
),
|
31
|
+
"id": flow_id(report["id"], item.attack_technique_id, tactic_id),
|
32
32
|
"effect_refs": [f"attack-action--{str(uuid.uuid4())}"],
|
33
33
|
"technique_id": item.attack_technique_id,
|
34
34
|
"technique_ref": technique_obj["id"],
|
@@ -149,14 +149,21 @@ def get_techniques_from_extracted_objects(objects: dict, tactics: dict):
|
|
149
149
|
|
150
150
|
def create_navigator_layer(report, summary, flow: AttackFlowList, techniques):
|
151
151
|
domains = {}
|
152
|
+
comments = {item.attack_technique_id: item.description for item in flow.items}
|
152
153
|
for technique in techniques.values():
|
153
154
|
domain_techniques = domains.setdefault(technique["domain"], [])
|
154
155
|
technique_id = technique["id"]
|
155
156
|
if technique_id not in flow.tactic_mapping:
|
156
157
|
continue
|
157
|
-
|
158
|
-
|
158
|
+
technique_item = dict(
|
159
|
+
techniqueID=technique_id,
|
160
|
+
tactic=flow.tactic_mapping[technique_id],
|
161
|
+
score=100,
|
162
|
+
showSubtechniques=True,
|
159
163
|
)
|
164
|
+
if comment := comments.get(technique_id):
|
165
|
+
technique_item["comment"] = comment
|
166
|
+
domain_techniques.append(technique_item)
|
160
167
|
|
161
168
|
retval = []
|
162
169
|
|
@@ -174,7 +181,13 @@ def create_navigator_layer(report, summary, flow: AttackFlowList, techniques):
|
|
174
181
|
"maxValue": 100,
|
175
182
|
},
|
176
183
|
"legendItems": [],
|
177
|
-
"metadata": [],
|
184
|
+
"metadata": [{"name": "report_id", "value": report.id}],
|
185
|
+
"links": [
|
186
|
+
{
|
187
|
+
"label": "Generated using txt2stix",
|
188
|
+
"url": "https://github.com/muchdogesec/txt2stix/",
|
189
|
+
}
|
190
|
+
],
|
178
191
|
"layout": {"layout": "side"},
|
179
192
|
}
|
180
193
|
)
|
@@ -191,10 +204,12 @@ def extract_attack_flow_and_navigator(
|
|
191
204
|
ex: BaseAIExtractor = ai_settings_relationships
|
192
205
|
tactics = get_all_tactics()
|
193
206
|
techniques = get_techniques_from_extracted_objects(bundler.bundle.objects, tactics)
|
207
|
+
if not techniques:
|
208
|
+
return None, None
|
209
|
+
|
194
210
|
logged_techniques = [
|
195
|
-
|
196
|
-
|
197
|
-
]
|
211
|
+
{k: v for k, v in t.items() if k != "stix_obj"} for t in techniques.values()
|
212
|
+
]
|
198
213
|
logging.debug(f"parsed techniques: {json.dumps(logged_techniques, indent=4)}")
|
199
214
|
|
200
215
|
flow = ex.extract_attack_flow(preprocessed_text, techniques)
|
@@ -204,5 +219,7 @@ def extract_attack_flow_and_navigator(
|
|
204
219
|
bundler.flow_objects = parse_flow(bundler.report, flow, techniques, tactics)
|
205
220
|
|
206
221
|
if ai_create_attack_navigator_layer:
|
207
|
-
navigator = create_navigator_layer(
|
222
|
+
navigator = create_navigator_layer(
|
223
|
+
bundler.report, bundler.summary, flow, techniques
|
224
|
+
)
|
208
225
|
return flow, navigator
|
txt2stix/txt2stix.py
CHANGED
@@ -440,11 +440,11 @@ def main():
|
|
440
440
|
output_path = output_dir/f"{bundler.bundle.id}.json"
|
441
441
|
output_path.write_text(out)
|
442
442
|
logger.info(f"Wrote bundle output to `{output_path}`")
|
443
|
-
data_path = output_dir/"data.json"
|
443
|
+
data_path = output_dir/f"data--{args.report_id}.json"
|
444
444
|
data_path.write_text(data.model_dump_json(indent=4))
|
445
445
|
logger.info(f"Wrote data output to `{data_path}`")
|
446
446
|
for nav_layer in data.navigator_layer or []:
|
447
|
-
nav_path = output_dir/f"navigator-{nav_layer['domain']}.json"
|
447
|
+
nav_path = output_dir/f"navigator-{nav_layer['domain']}----{args.report_id}.json"
|
448
448
|
nav_path.write_text(json.dumps(nav_layer, indent=4))
|
449
449
|
logger.info(f"Wrote navigator output to `{nav_path}`")
|
450
450
|
except argparse.ArgumentError as e:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: txt2stix
|
3
|
-
Version: 1.0.
|
3
|
+
Version: 1.0.4
|
4
4
|
Summary: txt2stix is a Python script that is designed to identify and extract IoCs and TTPs from text files, identify the relationships between them, convert them to STIX 2.1 objects, and output as a STIX 2.1 bundle.
|
5
5
|
Project-URL: Homepage, https://github.com/muchdogesec/txt2stix
|
6
6
|
Project-URL: Issues, https://github.com/muchdogesec/txt2stix/issues
|
@@ -1,5 +1,5 @@
|
|
1
1
|
txt2stix/__init__.py,sha256=Sm_VT913IFuAZ6dJEdVz3baPwC5VYtHySVfBAOUG92w,803
|
2
|
-
txt2stix/attack_flow.py,sha256=
|
2
|
+
txt2stix/attack_flow.py,sha256=WnhihbY_ltWOXrmzigTHIwj1pzSIQqKpu2sPe2M465k,8489
|
3
3
|
txt2stix/bundler.py,sha256=kqUNW9_jktuMyWSkoAa-ydZY-L5gzSSkthb7OdhUiKo,16854
|
4
4
|
txt2stix/common.py,sha256=ISnGNKqJPE1EcfhL-x_4G18mcwt1urmorkW-ru9kV-0,585
|
5
5
|
txt2stix/extractions.py,sha256=_tlsqYHhfAoV-PJzxRHysrX47uxCsMlSg7PQWxww1u0,2171
|
@@ -7,7 +7,7 @@ txt2stix/indicator.py,sha256=c6S0xx0K8JM-PT_Qd1PlN_ZlDXdnEwiRS8529iUp3yg,30774
|
|
7
7
|
txt2stix/lookups.py,sha256=h42YVtYUkWZm6ZPv2h5hHDHDzDs3yBqrT_T7pj2MDZI,2301
|
8
8
|
txt2stix/retriever.py,sha256=auKlk6JlRE9en-oiQ5KICMW0IwmU8R558o0K5UmEQZc,5550
|
9
9
|
txt2stix/stix.py,sha256=9nXD9a2dCY4uaatl-mlIA1k3srwQBhGW-tUSho3iYe0,30
|
10
|
-
txt2stix/txt2stix.py,sha256=
|
10
|
+
txt2stix/txt2stix.py,sha256=9i03BOYz34G_qaf5oTUm3YhDLDeqaPkik3dDyEjpFAE,18208
|
11
11
|
txt2stix/utils.py,sha256=n6mh4t9ZRJ7iT4Jvp9ai_dfCXjgXNcRtF_zXO7nkpnk,3304
|
12
12
|
txt2stix/ai_extractor/__init__.py,sha256=5Tf6Co9THzytBdFEVhD-7vvT05TT3nSpltnAV1sfdoM,349
|
13
13
|
txt2stix/ai_extractor/anthropic.py,sha256=mdz-8CB-BSCEqnK5l35DRZURVPUf508ef2b48XMxmuk,441
|
@@ -112,8 +112,8 @@ txt2stix/includes/lookups/threat_actor.txt,sha256=QfDO9maQuqKBgW_Sdd7VGv1SHZ9Ra-
|
|
112
112
|
txt2stix/includes/lookups/tld.txt,sha256=-MEgJea2NMG_KDsnc4BVvI8eRk5Dm93L-t8SGYx5wMo,8598
|
113
113
|
txt2stix/includes/lookups/tool.txt,sha256=HGKG6JpUE26w6ezzSxOjBkp15UpSaB7N-mZ_NU_3G7A,6
|
114
114
|
txt2stix/includes/tests/test_cases.yaml,sha256=QD1FdIunpPkOpsn6wJRqs2vil_hv8OSVaqUp4a96aZg,22247
|
115
|
-
txt2stix-1.0.
|
116
|
-
txt2stix-1.0.
|
117
|
-
txt2stix-1.0.
|
118
|
-
txt2stix-1.0.
|
119
|
-
txt2stix-1.0.
|
115
|
+
txt2stix-1.0.4.dist-info/METADATA,sha256=dyi1Sej16Pl7EBTkcWNnYkoeU-d9R4mIwKSd2sF1Kec,14887
|
116
|
+
txt2stix-1.0.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
117
|
+
txt2stix-1.0.4.dist-info/entry_points.txt,sha256=x6QPtt65hWeomw4IpJ_wQUesBl1M4WOLODbhOKyWMFg,55
|
118
|
+
txt2stix-1.0.4.dist-info/licenses/LICENSE,sha256=BK8Ppqlc4pdgnNzIxnxde0taoQ1BgicdyqmBvMiNYgY,11364
|
119
|
+
txt2stix-1.0.4.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|