@@ -94,13 +94,30 @@ def _convert_stix_groups_to_dict(stix_attack_data):
9494 :return: list with dictionaries containing all groups from the input stix_attack_data
9595 """
9696 attack_data = []
97- for stix_tech in stix_attack_data :
98- tech = json .loads (stix_tech .serialize (), object_hook = _date_hook )
97+ for stix_group in stix_attack_data :
98+ group = json .loads (stix_group .serialize (), object_hook = _date_hook )
9999
100100 # Add group_id as key, because it's hard to get from STIX:
101- tech ['group_id' ] = get_attack_id (stix_tech )
101+ group ['group_id' ] = get_attack_id (stix_group )
102102
103- attack_data .append (tech )
103+ attack_data .append (group )
104+
105+ return attack_data
106+
107+ def _convert_stix_campaigns_to_dict (stix_attack_data ):
108+ """
109+ Convert the STIX list with Campaign to a dictionary for easier use in python and also include the campaign_id.
110+ :param stix_attack_data: the MITRE ATT&CK STIX dataset with campaigns
111+ :return: list with dictionaries containing all campaigns from the input stix_attack_data
112+ """
113+ attack_data = []
114+ for stix_campaign in stix_attack_data :
115+ campaign = json .loads (stix_campaign .serialize (), object_hook = _date_hook )
116+
117+ # Add campaign_id as key, because it's hard to get from STIX:
118+ campaign ['campaign_id' ] = get_attack_id (stix_campaign )
119+
120+ attack_data .append (campaign )
104121
105122 return attack_data
106123
@@ -191,6 +208,43 @@ def load_attack_data(data_type):
191208 })
192209
193210 attack_data = all_group_use
211+ elif data_type == DATA_TYPE_CUSTOM_TECH_IN_CAMPAIGN :
212+ # First we need to know which technique references (STIX Object type 'attack-pattern') we have for all
213+ # campaigns. This results in a dict: {campaign_id: Cxxxx, technique_ref/attack-pattern_ref: ...}
214+ campaigns = load_attack_data (DATA_TYPE_STIX_ALL_CAMPAIGNS )
215+ relationships = load_attack_data (DATA_TYPE_STIX_ALL_RELATIONSHIPS )
216+ all_campaigns_relationships = []
217+ for c in campaigns :
218+ for r in relationships :
219+ if c ['id' ] == r ['source_ref' ] and r ['relationship_type' ] == 'uses' and \
220+ r ['target_ref' ].startswith ('attack-pattern--' ):
221+ # more information on the campaign can be added. Only the minimal required data is added.
222+ all_campaigns_relationships .append (
223+ {
224+ 'campaign_id' : get_attack_id (c ),
225+ 'name' : c ['name' ],
226+ 'technique_ref' : r ['target_ref' ],
227+ 'x_mitre_domains' : c ['x_mitre_domains' ] if 'x_mitre_domains' in c .keys () else ['enterprise-attack' ]
228+ })
229+
230+ # Now we start resolving this part of the dict created above: 'technique_ref/attack-pattern_ref'.
231+ # and we add some more data to the final result.
232+ all_campaigns_use = []
233+ techniques = load_attack_data (DATA_TYPE_STIX_ALL_TECH )
234+ for cr in all_campaigns_relationships :
235+ for t in techniques :
236+ if t ['id' ] == cr ['technique_ref' ]:
237+ all_campaigns_use .append (
238+ {
239+ 'campaign_id' : cr ['campaign_id' ],
240+ 'name' : cr ['name' ],
241+ 'technique_id' : get_attack_id (t ),
242+ 'x_mitre_platforms' : t .get ('x_mitre_platforms' , None ),
243+ 'x_mitre_domains' : cr ['x_mitre_domains' ],
244+ 'matrix' : t ['external_references' ][0 ]['source_name' ]
245+ })
246+
247+ attack_data = all_campaigns_use
194248
195249 elif data_type == DATA_TYPE_STIX_ALL_TECH :
196250 stix_attack_data = mitre .get_techniques ()
@@ -216,6 +270,10 @@ def load_attack_data(data_type):
216270 # Combine groups from all matrices together:
217271 attack_data = _convert_stix_groups_to_dict (groups_enterprise + groups_ics + groups_mobile )
218272
273+ elif data_type == DATA_TYPE_STIX_ALL_CAMPAIGNS :
274+ campaigns = mitre .get_campaigns ()
275+ attack_data = _convert_stix_campaigns_to_dict (campaigns )
276+
219277 elif data_type == DATA_TYPE_STIX_ALL_SOFTWARE :
220278 attack_data = mitre .get_software ()
221279 elif data_type == DATA_TYPE_CUSTOM_TECH_BY_SOFTWARE :
@@ -283,6 +341,42 @@ def load_attack_data(data_type):
283341 })
284342 attack_data = all_group_use
285343
344+ elif data_type == DATA_TYPE_CUSTOM_SOFTWARE_IN_CAMPAIGN :
345+ # First we need to know which software references (STIX Object type 'malware' or 'tool') we have for all
346+ # campaigns. This results in a dict: {campaign_id: Cxxxx, software_ref/malware-tool_ref: ...}
347+ campaigns = load_attack_data (DATA_TYPE_STIX_ALL_CAMPAIGNS )
348+ relationships = load_attack_data (DATA_TYPE_STIX_ALL_RELATIONSHIPS )
349+ all_campaigns_relationships = []
350+ for campaign in campaigns :
351+ for r in relationships :
352+ if campaign ['id' ] == r ['source_ref' ] and r ['relationship_type' ] == 'uses' and \
353+ (r ['target_ref' ].startswith ('tool--' ) or r ['target_ref' ].startswith ('malware--' )):
354+ all_campaigns_relationships .append (
355+ {
356+ 'campaign_id' : get_attack_id (campaign ),
357+ 'name' : campaign ['name' ],
358+ 'software_ref' : r ['target_ref' ],
359+ 'x_mitre_domains' : campaign ['x_mitre_domains' ]
360+ })
361+
362+ # Now we start resolving this part of the dict created above: 'software_ref/malware-tool_ref'.
363+ # and we add some more data to the final result.
364+ all_campaign_use = []
365+ software = load_attack_data (DATA_TYPE_STIX_ALL_SOFTWARE )
366+ for campaign in all_campaigns_relationships :
367+ for s in software :
368+ if s ['id' ] == campaign ['software_ref' ]:
369+ all_campaign_use .append (
370+ {
371+ 'campaign_id' : campaign ['campaign_id' ],
372+ 'name' : campaign ['name' ],
373+ 'software_id' : get_attack_id (s ),
374+ 'x_mitre_platforms' : s .get ('x_mitre_platforms' , None ),
375+ 'x_mitre_domains' : campaign ['x_mitre_domains' ],
376+ 'matrix' : s ['external_references' ][0 ]['source_name' ]
377+ })
378+ attack_data = all_campaign_use
379+
286380 elif data_type == DATA_TYPE_STIX_ALL_ENTERPRISE_MITIGATIONS :
287381 attack_data = mitre .get_enterprise_mitigations ()
288382 attack_data = mitre .remove_revoked_deprecated (attack_data )
@@ -983,3 +1077,19 @@ def check_platform(arg_platforms, filename=None, domain=None):
9831077
9841078 return False
9851079 return True
1080+
1081+
1082+ def merge_group_dict (dict1 , dict2 ):
1083+ """
1084+ Merge the techniques from dict2 with the techniques in dict1.
1085+ :param dict1 The first dictionary
1086+ :param dict2 The other dictionary
1087+ """
1088+ for group_name , values in dict2 .items ():
1089+ if group_name not in dict1 .keys ():
1090+ dict1 [group_name ] = values
1091+ else :
1092+ for technique in values ['techniques' ]:
1093+ if technique not in dict1 [group_name ]['techniques' ]:
1094+ dict1 [group_name ]['techniques' ].add (technique )
1095+ dict1 [group_name ]['weight' ][technique ] = 1
0 commit comments