@@ -181,7 +181,12 @@ def techniquesToDf(src, domain):
181
181
"techniques" : pd .DataFrame (technique_rows ).sort_values ("name" ),
182
182
}
183
183
# add relationships
184
- dataframes .update (relationshipsToDf (src , relatedType = "technique" ))
184
+ codex = relationshipsToDf (src , relatedType = "technique" )
185
+ dataframes .update (codex )
186
+ # add relationship references
187
+ group_listing = [x for x in dataframes ["techniques" ]["ID" ]]
188
+ for y in [x for x in codex if x != 'citations' ]:
189
+ dataframes ["techniques" ][f"relationship citations ({ y } )" ] = _get_relationship_citations (group_listing , codex [y ])
185
190
# add/merge citations
186
191
if not citations .empty :
187
192
if "citations" in dataframes : # append to existing citations from references
@@ -307,7 +312,12 @@ def softwareToDf(src, domain):
307
312
"software" : pd .DataFrame (software_rows ).sort_values ("name" ),
308
313
}
309
314
# add relationships
310
- dataframes .update (relationshipsToDf (src , relatedType = "software" ))
315
+ codex = relationshipsToDf (src , relatedType = "software" )
316
+ dataframes .update (codex )
317
+ # add relationship references
318
+ group_listing = [x for x in dataframes ["software" ]["ID" ]]
319
+ for y in [x for x in codex if x != 'citations' ]:
320
+ dataframes ["software" ][f"relationship citations ({ y } )" ] = _get_relationship_citations (group_listing , codex [y ])
311
321
# add/merge citations
312
322
if not citations .empty :
313
323
if "citations" in dataframes : # append to existing citations from references
@@ -355,7 +365,12 @@ def groupsToDf(src, domain):
355
365
"groups" : pd .DataFrame (group_rows ).sort_values ("name" ),
356
366
}
357
367
# add relationships
358
- dataframes .update (relationshipsToDf (src , relatedType = "group" ))
368
+ codex = relationshipsToDf (src , relatedType = "group" )
369
+ dataframes .update (codex )
370
+ # add relationship references
371
+ group_listing = [x for x in dataframes ["groups" ]["ID" ]]
372
+ for y in [x for x in codex if x != 'citations' ]:
373
+ dataframes ["groups" ][f"relationship citations ({ y } )" ] = _get_relationship_citations (group_listing , codex [y ])
359
374
# add/merge citations
360
375
if not citations .empty :
361
376
if "citations" in dataframes : # append to existing citations from references
@@ -387,7 +402,12 @@ def mitigationsToDf(src, domain):
387
402
"mitigations" : pd .DataFrame (mitigation_rows ).sort_values ("name" ),
388
403
}
389
404
# add relationships
390
- dataframes .update (relationshipsToDf (src , relatedType = "mitigation" ))
405
+ codex = relationshipsToDf (src , relatedType = "mitigation" )
406
+ dataframes .update (codex )
407
+ # add relationship references
408
+ group_listing = [x for x in dataframes ["mitigations" ]["ID" ]]
409
+ for y in [x for x in codex if x != 'citations' ]:
410
+ dataframes ["mitigations" ][f"relationship citations ({ y } )" ] = _get_relationship_citations (group_listing , codex [y ])
391
411
# add/merge citations
392
412
if not citations .empty :
393
413
if "citations" in dataframes : # append to existing citations from references
@@ -718,7 +738,7 @@ def add_side(label, sdo):
718
738
relationships = pd .DataFrame (relationship_rows ).sort_values (
719
739
["mapping type" , "source type" , "target type" , "source name" , "target name" ])
720
740
721
- if not relatedType : # return all relationships and citrations
741
+ if not relatedType : # return all relationships and citations
722
742
dataframes = {
723
743
"relationships" : relationships ,
724
744
}
@@ -748,7 +768,7 @@ def add_side(label, sdo):
748
768
'associated mitigations' if relatedType == 'technique' else 'techniques addressed' ] = relatedMitigations
749
769
750
770
if not citations .empty :
751
- # fitler citations by ones actually used
771
+ # filter citations by ones actually used
752
772
# build master list of used citations
753
773
usedCitations = set ()
754
774
for dfname in dataframes :
@@ -762,4 +782,24 @@ def add_side(label, sdo):
762
782
763
783
dataframes ["citations" ] = citations .sort_values ("reference" )
764
784
765
- return dataframes
785
+ return dataframes
786
+
787
+
788
+ def _get_relationship_citations (object_listing , relationship_df ):
789
+ """
790
+ Extract citations for each _object_ in the listing from the relationship dataframe. This allows us to include
791
+ citations from relationships for each ATT&CK object type.
792
+ :param object_listing: List of all _object ids_ for the given ATT&CK object type
793
+ :param relationship_df: Dataframe of relationships
794
+ :return: Array of strings, with each string being placed relative to the object listing, and containing all
795
+ relevant citations
796
+ """
797
+ new_citations = []
798
+ for y in object_listing :
799
+ mask = relationship_df .values == y
800
+ filtered = relationship_df .loc [mask ]
801
+ temp = set ()
802
+ for description in filter (lambda x : x == x , filtered ["mapping description" ].tolist ()):
803
+ [temp .add (x ) for x in re .findall (r"\(Citation: (.*?)\)" , description )]
804
+ new_citations .append ("," .join ([f"(Citation: { z } )" for z in temp ]))
805
+ return new_citations
0 commit comments