@@ -88,16 +88,17 @@ def generate_domain_markdown(domain, techniques_no_sub, tactics, side_nav_data,
8888 md_file .write (subs )
8989
9090 # Create the markdown for techniques in the STIX
91+ datasource_of = util .relationshipgetters .get_datasource_of ()
9192 for technique in techniques_no_sub [domain ]:
9293 if "revoked" not in technique or technique ["revoked" ] is False :
93- generate_technique_md (technique , domain , side_nav_data , tactics [domain ], notes )
94+ generate_technique_md (technique , domain , side_nav_data , tactics [domain ], notes , datasource_of )
9495
9596 return True
9697
9798 return False
9899
99100
100- def generate_technique_md (technique , domain , side_nav_data , tactic_list , notes ):
101+ def generate_technique_md (technique , domain , side_nav_data , tactic_list , notes , datasource_of ):
101102 """Generetes markdown data for given technique."""
102103 attack_id = util .buildhelpers .get_attack_id (technique )
103104
@@ -117,7 +118,7 @@ def generate_technique_md(technique, domain, side_nav_data, tactic_list, notes):
117118 technique_dict ["subtechniques" ] = get_subtechniques (technique )
118119
119120 # Generate data for technique
120- technique_dict = generate_data_for_md (technique_dict , technique , tactic_list )
121+ technique_dict = generate_data_for_md (technique_dict = technique_dict , technique = technique , tactic_list = tactic_list , datasource_of = datasource_of )
121122
122123 subs = techniques_config .technique_md .substitute (technique_dict )
123124 path = technique_dict ["attack_id" ]
@@ -143,7 +144,7 @@ def generate_technique_md(technique, domain, side_nav_data, tactic_list, notes):
143144 sub_tech_dict ["parent_name" ] = technique .get ("name" )
144145 sub_tech_dict ["subtechniques" ] = technique_dict ["subtechniques" ]
145146
146- sub_tech_dict = generate_data_for_md (sub_tech_dict , subtechnique ["object" ], tactic_list , True )
147+ sub_tech_dict = generate_data_for_md (technique_dict = sub_tech_dict , technique = subtechnique ["object" ], tactic_list = tactic_list , is_sub_technique = True , datasource_of = datasource_of )
147148
148149 if sub_tech_dict .get ("sub_number" ):
149150 subs = techniques_config .sub_technique_md .substitute (sub_tech_dict )
@@ -158,7 +159,7 @@ def generate_technique_md(technique, domain, side_nav_data, tactic_list, notes):
158159 md_file .write (subs )
159160
160161
161- def generate_data_for_md (technique_dict , technique , tactic_list , is_sub_technique = False ):
162+ def generate_data_for_md (technique_dict , technique , tactic_list , is_sub_technique = False , datasource_of = None ):
162163 """Given a technique or subtechnique, fill technique dictionary to create markdown file."""
163164 technique_dict ["name" ] = technique .get ("name" )
164165
@@ -266,10 +267,10 @@ def generate_data_for_md(technique_dict, technique, tactic_list, is_sub_techniqu
266267 technique_dict ["eff_perms" ] = ", " .join (technique ["x_mitre_effective_permissions" ])
267268
268269 # Get data sources and components
269- # (
270- # technique_dict["datasources"],
271- # technique_dict["show_descriptions"],
272- # ) = get_datasources_and_components_of_technique(technique, reference_list)
270+ (
271+ technique_dict ["datasources" ],
272+ technique_dict ["show_descriptions" ],
273+ ) = get_datasources_and_components_of_technique (technique , reference_list , datasource_of )
273274
274275 # Get if technique supports remote
275276 if technique .get ("x_mitre_remote_support" ):
@@ -341,9 +342,11 @@ def generate_data_for_md(technique_dict, technique, tactic_list, is_sub_techniqu
341342
342343
343344def get_mitigations_table_data (technique , reference_list ):
344- """Given a technique a reference list, find mitigations that mitigate
345- technique and return list with mitigation data. Also modifies the
346- reference list if it finds a reference that is not on the list
345+ """Given a technique and a reference list, return mitigation data.
346+
347+ Find mitigations that mitigate the technique and return a list with mitigation
348+ data. Also modifies the reference list if it finds a reference that is not
349+ on the list.
347350 """
348351 mitigation_data = []
349352
@@ -373,9 +376,11 @@ def get_mitigations_table_data(technique, reference_list):
373376
374377
375378def get_assets_table_data (technique , reference_list ):
376- """Given a technique a reference list, find assets that are targeted by the
377- technique and return list with asset data. Also modifies the
378- reference list if it finds a reference that is not on the list
379+ """Return asset data for a technique.
380+
381+ Given a technique and a reference list, find assets targeted by the
382+ technique and return a list with asset data. Also modify the reference
383+ list if a relationship reference is not present in the list.
379384 """
380385 asset_data = []
381386
@@ -407,9 +412,10 @@ def get_assets_table_data(technique, reference_list):
407412
408413
409414def get_examples_table_data (technique , reference_list ):
410- """Given a technique object, find examples in malware using technique,
411- tools using technique and groups using technique. Return list with
412- example data
415+ """Return example data for a technique.
416+
417+ Find malware, tools, groups, and campaigns that use the technique and
418+ return a list with example data.
413419 """
414420 # Creating map to avoid repeating the code multiple times
415421 examples_map = [
@@ -451,7 +457,7 @@ def get_examples_table_data(technique, reference_list):
451457
452458
453459def get_path_from_type (object ):
454- """Given an object, return the path """
460+ """Return the path for an object. """
455461 path_map = {"intrusion-set" : "groups" , "malware" : "software" , "tool" : "software" , "campaign" : "campaigns" }
456462 return path_map [object .get ("type" )]
457463
@@ -528,7 +534,7 @@ def get_technique_side_nav_data(techniques, tactics):
528534
529535
530536def get_techniques_list (techniques ):
531- """This method is used to generate a list of techniques."""
537+ """Generate a list of techniques."""
532538 technique_list = {}
533539
534540 for technique in techniques :
@@ -584,9 +590,10 @@ def get_subtechniques(technique):
584590 return sorted (subtechs , key = lambda k : k ["id" ])
585591
586592
587- def get_datasources_and_components_of_technique (technique , reference_list ):
588- """Given a technique object, find data sources and components
589- detecting the technique. Returns list with the following structure
593+ def get_datasources_and_components_of_technique (technique , reference_list , datasource_of ):
594+ """Return data sources and components that detect a technique.
595+
596+ Returns a list with the following structure:
590597
591598 For each data source:
592599 Data Source ATT&CK ID
@@ -598,20 +605,22 @@ def get_datasources_and_components_of_technique(technique, reference_list):
598605 datasource_and_components = []
599606
600607 datacomponents_of_technique = util .relationshipgetters .get_datacomponents_detecting_technique ().get (technique ["id" ])
601- datasource_of = util .relationshipgetters .get_datasource_of ()
602608
603609 show_descriptions = False
604610
605611 if datacomponents_of_technique :
606612 datasources_data = {}
607613 for datacomponent in datacomponents_of_technique :
608614 datasource = datasource_of .get (datacomponent ["object" ]["id" ])
615+ # If datasource lookup failed, skip this datacomponent
616+ if not datasource :
617+ continue
609618 datasource_attack_id = util .buildhelpers .get_attack_id (datasource )
610619 if datasource_attack_id :
611620 if not datasources_data .get (datasource_attack_id ):
612621 datasources_data [datasource_attack_id ] = {}
613622 datasources_data [datasource_attack_id ]["attack_id" ] = datasource_attack_id
614- datasources_data [datasource_attack_id ]["name" ] = datasource [ "name" ]
623+ datasources_data [datasource_attack_id ]["name" ] = datasource . get ( "name" )
615624 datasources_data [datasource_attack_id ]["datacomponents" ] = []
616625
617626 datacomponent_data = {}
0 commit comments