From a311ce6a1c8af74efb81f44d57ac8d63b78c9446 Mon Sep 17 00:00:00 2001 From: niclas Date: Fri, 23 Feb 2024 11:25:07 +0100 Subject: [PATCH] Add [technique] subtechnique --- tools/tidal-api/main.py | 18 ++- tools/tidal-api/models/cluster.py | 212 +++++++++++++++++++++++------- 2 files changed, 179 insertions(+), 51 deletions(-) diff --git a/tools/tidal-api/main.py b/tools/tidal-api/main.py index d402dbb..9438567 100644 --- a/tools/tidal-api/main.py +++ b/tools/tidal-api/main.py @@ -1,6 +1,13 @@ from api.api import TidalAPI from models.galaxy import Galaxy -from models.cluster import GroupCluster, SoftwareCluster, CampaignsCluster, TechniqueCluster, TacticCluster, ReferencesCluster +from models.cluster import ( + GroupCluster, + SoftwareCluster, + CampaignsCluster, + TechniqueCluster, + TacticCluster, + ReferencesCluster, +) import argparse import json import os @@ -9,6 +16,7 @@ CONFIG = "./config" GALAXY_PATH = "../../galaxies" CLUSTER_PATH = "../../clusters" + def create_galaxy(endpoint: str, version: int): api = TidalAPI() data = api.get_data(endpoint) @@ -17,7 +25,7 @@ def create_galaxy(endpoint: str, version: int): galaxy = Galaxy(**config["galaxy"], version=version) galaxy.save_to_file(f"{GALAXY_PATH}/tidal-{endpoint}.json") - + match endpoint: case "groups": cluster = GroupCluster(**config["cluster"], uuid=galaxy.uuid) @@ -44,13 +52,14 @@ def create_galaxy(endpoint: str, version: int): cluster.save_to_file(f"{CLUSTER_PATH}/tidal-{endpoint}.json") print(f"Galaxy tidal-{endpoint} created") + def main(args, galaxies): if args.all: for galaxy in galaxies: create_galaxy(galaxy, args.version) else: create_galaxy(args.type, args.version) - + if __name__ == "__main__": @@ -59,7 +68,6 @@ if __name__ == "__main__": if f.endswith(".json"): galaxies.append(f.split(".")[0]) - parser = argparse.ArgumentParser( description="Create galaxy and cluster json files from Tidal API" ) @@ -86,4 +94,4 @@ if __name__ == "__main__": if hasattr(args, "func"): args.func(args, galaxies=galaxies) else: - parser.print_help() \ No newline at end of file + parser.print_help() diff --git a/tools/tidal-api/models/cluster.py b/tools/tidal-api/models/cluster.py index 4c75a98..fca9171 100644 --- a/tools/tidal-api/models/cluster.py +++ b/tools/tidal-api/models/cluster.py @@ -1,12 +1,14 @@ from dataclasses import dataclass, field, asdict import json + @dataclass class Meta: pass + @dataclass -class GroupsMeta(): +class GroupsMeta(Meta): source: str = None group_attack_id: str = None country: str = None @@ -16,8 +18,9 @@ class GroupsMeta(): tags: list = None owner: str = None + @dataclass -class SoftwareMeta(): +class SoftwareMeta(Meta): source: str = None type: str = None software_attack_id: str = None @@ -25,23 +28,32 @@ class SoftwareMeta(): tags: list = None owner: str = None + @dataclass -class TechniqueMeta(): +class TechniqueMeta(Meta): source: str = None platforms: list = None tags: list = None owner: str = None + @dataclass -class TacticMeta(): +class SubTechniqueMeta(Meta): + source: str = None + technique_attack_id: str = None + + +@dataclass +class TacticMeta(Meta): source: str = None tactic_attack_id: str = None ordinal_position: int = None tags: list = None owner: str = None + @dataclass -class ReferencesMeta(): +class ReferencesMeta(Meta): source: str = None refs: list = None title: str = None @@ -50,8 +62,9 @@ class ReferencesMeta(): date_published: str = None owner: str = None + @dataclass -class CampaignsMeta(): +class CampaignsMeta(Meta): source: str = None campaign_attack_id: str = None first_seen: str = None @@ -59,6 +72,7 @@ class CampaignsMeta(): tags: list = None owner: str = None + @dataclass class ClusterValue: description: str = "" @@ -69,11 +83,23 @@ class ClusterValue: def return_value(self): value_dict = asdict(self) - value_dict['meta'] = {k: v for k, v in asdict(self.meta).items() if v is not None} + value_dict["meta"] = { + k: v for k, v in asdict(self.meta).items() if v is not None + } return value_dict -class Cluster(): - def __init__(self, authors: str, category: str, description: str, name: str, source: str, type: str, uuid: str): + +class Cluster: + def __init__( + self, + authors: str, + category: str, + description: str, + name: str, + source: str, + type: str, + uuid: str, + ): self.authors = authors self.category = category self.description = description @@ -85,7 +111,7 @@ class Cluster(): def add_values(self): print("This method should be implemented in the child class") - + def save_to_file(self, path): with open(path, "w") as file: file.write(json.dumps(self.__dict__(), indent=4)) @@ -104,29 +130,48 @@ class Cluster(): "uuid": self.uuid, "values": self.values, } - + + class GroupCluster(Cluster): - def __init__(self, authors: str, category: str, description: str, name: str, source: str, type: str, uuid: str): + def __init__( + self, + authors: str, + category: str, + description: str, + name: str, + source: str, + type: str, + uuid: str, + ): super().__init__(authors, category, description, name, source, type, uuid) - + def add_values(self, data): for entry in data["data"]: meta = GroupsMeta( source=entry.get("source"), group_attack_id=entry.get("group_attack_id"), - country=entry.get("country")[0].get("country_code") if entry.get("country") else None, - observed_countries=[x.get("country_code") for x in entry.get("observed_country")], - observed_motivations=[x.get("name") for x in entry.get("observed_motivation")], + country=( + entry.get("country")[0].get("country_code") + if entry.get("country") + else None + ), + observed_countries=[ + x.get("country_code") for x in entry.get("observed_country") + ], + observed_motivations=[ + x.get("name") for x in entry.get("observed_motivation") + ], target_categories=[x.get("name") for x in entry.get("observed_sector")], tags=[x.get("tag") for x in entry.get("tags")], owner=entry.get("owner_name"), ) related = [] for relation in entry.get("associated_groups"): - related.append({ - "dest-uuid": relation.get("id"), - "type": "related-to", - } + related.append( + { + "dest-uuid": relation.get("id"), + "type": "related-to", + } ) value = ClusterValue( description=entry.get("description"), @@ -139,9 +184,18 @@ class GroupCluster(Cluster): class SoftwareCluster(Cluster): - def __init__(self, authors: str, category: str, description: str, name: str, source: str, type: str, uuid: str): + def __init__( + self, + authors: str, + category: str, + description: str, + name: str, + source: str, + type: str, + uuid: str, + ): super().__init__(authors, category, description, name, source, type, uuid) - + def add_values(self, data): for entry in data["data"]: meta = SoftwareMeta( @@ -154,16 +208,18 @@ class SoftwareCluster(Cluster): ) related = [] for relation in entry.get("groups"): - related.append({ - "dest-uuid": relation.get("group_id"), - "type": "used-by", - } + related.append( + { + "dest-uuid": relation.get("group_id"), + "type": "used-by", + } ) for relation in entry.get("associated_software"): - related.append({ - "dest-uuid": relation.get("id"), - "type": "related-to", - } + related.append( + { + "dest-uuid": relation.get("id"), + "type": "related-to", + } ) value = ClusterValue( description=entry.get("description"), @@ -174,10 +230,20 @@ class SoftwareCluster(Cluster): ) self.values.append(value.return_value()) + class TechniqueCluster(Cluster): - def __init__(self, authors: str, category: str, description: str, name: str, source: str, type: str, uuid: str): + def __init__( + self, + authors: str, + category: str, + description: str, + name: str, + source: str, + type: str, + uuid: str, + ): super().__init__(authors, category, description, name, source, type, uuid) - + def add_values(self, data): for entry in data["data"]: meta = TechniqueMeta( @@ -188,10 +254,11 @@ class TechniqueCluster(Cluster): ) related = [] for relation in entry.get("tactic"): - related.append({ - "dest-uuid": relation.get("tactic_id"), - "type": "uses", - } + related.append( + { + "dest-uuid": relation.get("tactic_id"), + "type": "uses", + } ) value = ClusterValue( description=entry.get("description"), @@ -202,10 +269,42 @@ class TechniqueCluster(Cluster): ) self.values.append(value.return_value()) + for sub_technique in entry.get("sub_technique"): + meta = SubTechniqueMeta( + source=sub_technique.get("source"), + technique_attack_id=sub_technique.get("technique_attack_id"), + ) + related = [] + for relation in sub_technique.get("tactic"): + related.append( + { + "dest-uuid": relation.get("tactic_id"), + "type": "uses", + } + ) + value = ClusterValue( + description=sub_technique.get("description"), + meta=meta, + related=related, + uuid=sub_technique.get("id"), + value=sub_technique.get("name"), + ) + self.values.append(value.return_value()) + + class TacticCluster(Cluster): - def __init__(self, authors: str, category: str, description: str, name: str, source: str, type: str, uuid: str): + def __init__( + self, + authors: str, + category: str, + description: str, + name: str, + source: str, + type: str, + uuid: str, + ): super().__init__(authors, category, description, name, source, type, uuid) - + def add_values(self, data): for entry in data["data"]: meta = TacticMeta( @@ -217,10 +316,11 @@ class TacticCluster(Cluster): ) related = [] for relation in entry.get("techniques"): - related.append({ - "dest-uuid": relation.get("technique_id"), - "type": "uses", - } + related.append( + { + "dest-uuid": relation.get("technique_id"), + "type": "uses", + } ) value = ClusterValue( description=entry.get("description"), @@ -231,10 +331,20 @@ class TacticCluster(Cluster): ) self.values.append(value.return_value()) + class ReferencesCluster(Cluster): - def __init__(self, authors: str, category: str, description: str, name: str, source: str, type: str, uuid: str): + def __init__( + self, + authors: str, + category: str, + description: str, + name: str, + source: str, + type: str, + uuid: str, + ): super().__init__(authors, category, description, name, source, type, uuid) - + def add_values(self, data): for entry in data["data"]: meta = ReferencesMeta( @@ -255,8 +365,18 @@ class ReferencesCluster(Cluster): ) self.values.append(value.return_value()) + class CampaignsCluster(Cluster): - def __init__(self, authors: str, category: str, description: str, name: str, source: str, type: str, uuid: str): + def __init__( + self, + authors: str, + category: str, + description: str, + name: str, + source: str, + type: str, + uuid: str, + ): super().__init__(authors, category, description, name, source, type, uuid) def add_values(self, data): @@ -277,4 +397,4 @@ class CampaignsCluster(Cluster): uuid=entry.get("id"), value=entry.get("name"), ) - self.values.append(value.return_value()) \ No newline at end of file + self.values.append(value.return_value())