mirror of
https://github.com/MISP/misp-galaxy.git
synced 2024-11-22 23:07:19 +00:00
111 lines
5.7 KiB
Python
111 lines
5.7 KiB
Python
#!/usr/bin/python
|
|
|
|
import json
|
|
import os
|
|
|
|
import validators
|
|
|
|
pathClusters = '../../clusters'
|
|
pathSite = './site/docs'
|
|
|
|
galaxies_fnames = []
|
|
files_to_ignore = [] # if you want to skip a specific cluster in the generation
|
|
|
|
for f in os.listdir(pathClusters):
|
|
if '.json' in f and f not in files_to_ignore:
|
|
galaxies_fnames.append(f)
|
|
|
|
galaxies_fnames.sort()
|
|
|
|
index_output = ""
|
|
index_output += """
|
|
# MISP Galaxy
|
|
|
|
The MISP galaxy offers a streamlined approach for representing large entities, known as clusters, which can be linked to MISP events or attributes. Each cluster consists of one or more elements, represented as key-value pairs. MISP galaxy comes with a default knowledge base, encompassing areas like Threat Actors, Tools, Ransomware, and ATT&CK matrices. However, users have the flexibility to modify, update, replace, or share these elements according to their needs.
|
|
|
|
Clusters and vocabularies within MISP galaxy can be utilized in their original form or as a foundational knowledge base. The distribution settings for each cluster can be adjusted, allowing for either restricted or wide dissemination.
|
|
|
|
Additionally, MISP galaxies enable the representation of existing standards like the MITRE ATT&CK™ framework, as well as custom matrices.
|
|
|
|
The aim is to provide a core set of clusters for organizations embarking on analysis, which can be further tailored to include localized, private information or additional, shareable data.
|
|
|
|
Clusters serve as an open and freely accessible knowledge base, which can be utilized and expanded within [MISP](https://www.misp-project.org/) or other threat intelligence platforms.
|
|
|
|
## Publicly available clusters
|
|
|
|
"""
|
|
|
|
galaxy_output = {}
|
|
|
|
for f in galaxies_fnames:
|
|
with open(os.path.join(pathClusters, f)) as fr:
|
|
cluster = json.load(fr)
|
|
cluster_filename = f.split('.')[0]
|
|
index_output += f'- [{cluster["name"]}](./{cluster_filename}/index.md)\n'
|
|
galaxy_output[cluster_filename] = "---\n"
|
|
galaxy_output[cluster_filename] += f'title: {cluster["name"]}\n'
|
|
meta_description = cluster["description"].replace("\"", "-")
|
|
galaxy_output[cluster_filename] += f'description: {meta_description}\n'
|
|
galaxy_output[cluster_filename] += "---\n"
|
|
galaxy_output[cluster_filename] += f'# {cluster["name"]}\n'
|
|
galaxy_output[cluster_filename] += f'{cluster["description"]}\n'
|
|
for value in cluster["values"]:
|
|
galaxy_output[cluster_filename] += f'## {value["value"]}\n'
|
|
galaxy_output[cluster_filename] += f'\n'
|
|
if 'description' in value:
|
|
galaxy_output[cluster_filename] += f'{value["description"]}\n'
|
|
|
|
if 'meta' in value:
|
|
if 'synonyms' in value['meta']:
|
|
if value['meta']['synonyms']: # some cluster have an empty list of synomyms
|
|
galaxy_output[cluster_filename] += f'\n'
|
|
galaxy_output[cluster_filename] += f'??? info "Synonyms"\n'
|
|
galaxy_output[cluster_filename] += f'\n'
|
|
galaxy_output[cluster_filename] += f' "synonyms" in the meta part typically refer to alternate names or labels that are associated with a particular {cluster["name"]}.\n\n'
|
|
galaxy_output[cluster_filename] += f' | Known Synonyms |\n'
|
|
galaxy_output[cluster_filename] += f' |---------------------|\n'
|
|
for synonym in sorted(value['meta']['synonyms']):
|
|
galaxy_output[cluster_filename] += f' | `{synonym}` |\n'
|
|
|
|
if 'uuid' in value:
|
|
galaxy_output[cluster_filename] += f'\n'
|
|
galaxy_output[cluster_filename] += f'??? tip "Internal MISP references"\n'
|
|
galaxy_output[cluster_filename] += f'\n'
|
|
galaxy_output[cluster_filename] += f' UUID `{value["uuid"]}` which can be used as unique global reference for `{value["value"]}` in MISP communities and other software using the MISP galaxy\n'
|
|
galaxy_output[cluster_filename] += f'\n'
|
|
|
|
if 'meta' in value:
|
|
if 'refs' in value['meta']:
|
|
galaxy_output[cluster_filename] += f'\n'
|
|
galaxy_output[cluster_filename] += f'??? info "External references"\n'
|
|
galaxy_output[cluster_filename] += f'\n'
|
|
|
|
for ref in value["meta"]["refs"]:
|
|
if validators.url(ref): # some ref are not actual URL (TODO: check galaxy cluster sources)
|
|
galaxy_output[cluster_filename] += f' - [{ref}]({ref}) - :material-archive: :material-arrow-right: [webarchive](https://web.archive.org/web/*/{ref})\n'
|
|
else:
|
|
galaxy_output[cluster_filename] += f' - {ref}\n'
|
|
|
|
galaxy_output[cluster_filename] += f'\n'
|
|
excluded_meta = ['synonyms', 'refs']
|
|
galaxy_output[cluster_filename] += f'\n'
|
|
galaxy_output[cluster_filename] += f'??? info "Associated metadata"\n'
|
|
galaxy_output[cluster_filename] += f'\n'
|
|
galaxy_output[cluster_filename] += f' |Metadata key |Value|\n'
|
|
galaxy_output[cluster_filename] += f' |---------------------|-----|\n'
|
|
for meta in sorted(value['meta']):
|
|
if meta in excluded_meta:
|
|
continue
|
|
galaxy_output[cluster_filename] += f' | `{meta}` |{value["meta"][meta]}|\n'
|
|
|
|
|
|
with open(os.path.join(pathSite, 'index.md'), "w") as index:
|
|
index.write(index_output)
|
|
|
|
for f in galaxies_fnames:
|
|
cluster_filename = f.split('.')[0]
|
|
pathSiteCluster = os.path.join(pathSite, cluster_filename)
|
|
if not os.path.exists(pathSiteCluster):
|
|
os.mkdir(pathSiteCluster)
|
|
with open(os.path.join(pathSiteCluster, 'index.md'), "w") as index:
|
|
index.write(galaxy_output[cluster_filename])
|