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 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['possible_tactics'][flow.tactic_mapping[item.attack_technique_id]]
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
- domain_techniques.append(
158
- dict(techniqueID=technique_id, tactic=flow.tactic_mapping[technique_id])
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
- {k: v for k, v in t.items() if k != "stix_obj"}
196
- for t in techniques.values()
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(bundler.report, bundler.summary, flow, techniques)
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.2
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=DLDaNXB_gxuqdEb_A1VQO_nu69MG23nolTx7-JESrKI,7889
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=HYXN9dKzakoqdqJ4wSthwGdFIxOm6KTegiQlVmfp0eQ,18169
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.2.dist-info/METADATA,sha256=-qdpBMRkkfhkAvFlAK8ya9Dj8ZYnXH0rt-NJSH8bqnw,14887
116
- txt2stix-1.0.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
117
- txt2stix-1.0.2.dist-info/entry_points.txt,sha256=x6QPtt65hWeomw4IpJ_wQUesBl1M4WOLODbhOKyWMFg,55
118
- txt2stix-1.0.2.dist-info/licenses/LICENSE,sha256=BK8Ppqlc4pdgnNzIxnxde0taoQ1BgicdyqmBvMiNYgY,11364
119
- txt2stix-1.0.2.dist-info/RECORD,,
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,,