mirror of
https://github.com/MISP/misp-galaxy.git
synced 2024-11-30 02:37:17 +00:00
Merge pull request #972 from cvandeplas/main
chg: [MITRE] Split Matrix view based on OS and more metadata
This commit is contained in:
commit
71f219c9ea
4 changed files with 3258 additions and 1427 deletions
10
.vscode/launch.json
vendored
10
.vscode/launch.json
vendored
|
@ -1,6 +1,15 @@
|
||||||
{
|
{
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "gen_mitre",
|
||||||
|
"type": "debugpy",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${file}",
|
||||||
|
"console": "integratedTerminal",
|
||||||
|
"args": "-p ../../MITRE-ATTACK",
|
||||||
|
"cwd": "${fileDirname}"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "gen_interpol_dwvat",
|
"name": "gen_interpol_dwvat",
|
||||||
"type": "debugpy",
|
"type": "debugpy",
|
||||||
|
@ -9,7 +18,6 @@
|
||||||
"console": "integratedTerminal",
|
"console": "integratedTerminal",
|
||||||
"args": "-p ../../DW-VA-Taxonomy",
|
"args": "-p ../../DW-VA-Taxonomy",
|
||||||
"cwd": "${fileDirname}"
|
"cwd": "${fileDirname}"
|
||||||
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Python Debugger: Current File",
|
"name": "Python Debugger: Current File",
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -2,9 +2,55 @@
|
||||||
"description": "ATT&CK Tactic",
|
"description": "ATT&CK Tactic",
|
||||||
"icon": "map",
|
"icon": "map",
|
||||||
"kill_chain_order": {
|
"kill_chain_order": {
|
||||||
"mitre-attack": [
|
"attack-Azure-AD": [
|
||||||
"reconnaissance",
|
"initial-access",
|
||||||
"resource-development",
|
"execution",
|
||||||
|
"persistence",
|
||||||
|
"privilege-escalation",
|
||||||
|
"defense-evasion",
|
||||||
|
"credential-access",
|
||||||
|
"discovery",
|
||||||
|
"lateral-movement",
|
||||||
|
"impact"
|
||||||
|
],
|
||||||
|
"attack-Containers": [
|
||||||
|
"initial-access",
|
||||||
|
"execution",
|
||||||
|
"persistence",
|
||||||
|
"privilege-escalation",
|
||||||
|
"defense-evasion",
|
||||||
|
"credential-access",
|
||||||
|
"discovery",
|
||||||
|
"lateral-movement",
|
||||||
|
"impact"
|
||||||
|
],
|
||||||
|
"attack-Google-Workspace": [
|
||||||
|
"initial-access",
|
||||||
|
"execution",
|
||||||
|
"persistence",
|
||||||
|
"privilege-escalation",
|
||||||
|
"defense-evasion",
|
||||||
|
"credential-access",
|
||||||
|
"discovery",
|
||||||
|
"lateral-movement",
|
||||||
|
"collection",
|
||||||
|
"exfiltration",
|
||||||
|
"impact"
|
||||||
|
],
|
||||||
|
"attack-IaaS": [
|
||||||
|
"initial-access",
|
||||||
|
"execution",
|
||||||
|
"persistence",
|
||||||
|
"privilege-escalation",
|
||||||
|
"defense-evasion",
|
||||||
|
"credential-access",
|
||||||
|
"discovery",
|
||||||
|
"lateral-movement",
|
||||||
|
"collection",
|
||||||
|
"exfiltration",
|
||||||
|
"impact"
|
||||||
|
],
|
||||||
|
"attack-Linux": [
|
||||||
"initial-access",
|
"initial-access",
|
||||||
"execution",
|
"execution",
|
||||||
"persistence",
|
"persistence",
|
||||||
|
@ -18,7 +64,79 @@
|
||||||
"exfiltration",
|
"exfiltration",
|
||||||
"impact"
|
"impact"
|
||||||
],
|
],
|
||||||
"mitre-mobile-attack": [
|
"attack-Network": [
|
||||||
|
"initial-access",
|
||||||
|
"execution",
|
||||||
|
"persistence",
|
||||||
|
"privilege-escalation",
|
||||||
|
"defense-evasion",
|
||||||
|
"credential-access",
|
||||||
|
"discovery",
|
||||||
|
"lateral-movement",
|
||||||
|
"collection",
|
||||||
|
"command-and-control",
|
||||||
|
"exfiltration",
|
||||||
|
"impact"
|
||||||
|
],
|
||||||
|
"attack-Office-365": [
|
||||||
|
"initial-access",
|
||||||
|
"execution",
|
||||||
|
"persistence",
|
||||||
|
"privilege-escalation",
|
||||||
|
"defense-evasion",
|
||||||
|
"credential-access",
|
||||||
|
"discovery",
|
||||||
|
"lateral-movement",
|
||||||
|
"collection",
|
||||||
|
"exfiltration",
|
||||||
|
"impact"
|
||||||
|
],
|
||||||
|
"attack-PRE": [
|
||||||
|
"reconnaissance",
|
||||||
|
"resource-development"
|
||||||
|
],
|
||||||
|
"attack-SaaS": [
|
||||||
|
"initial-access",
|
||||||
|
"execution",
|
||||||
|
"persistence",
|
||||||
|
"privilege-escalation",
|
||||||
|
"defense-evasion",
|
||||||
|
"credential-access",
|
||||||
|
"discovery",
|
||||||
|
"lateral-movement",
|
||||||
|
"collection",
|
||||||
|
"exfiltration",
|
||||||
|
"impact"
|
||||||
|
],
|
||||||
|
"attack-Windows": [
|
||||||
|
"initial-access",
|
||||||
|
"execution",
|
||||||
|
"persistence",
|
||||||
|
"privilege-escalation",
|
||||||
|
"defense-evasion",
|
||||||
|
"credential-access",
|
||||||
|
"discovery",
|
||||||
|
"lateral-movement",
|
||||||
|
"collection",
|
||||||
|
"command-and-control",
|
||||||
|
"exfiltration",
|
||||||
|
"impact"
|
||||||
|
],
|
||||||
|
"attack-macOS": [
|
||||||
|
"initial-access",
|
||||||
|
"execution",
|
||||||
|
"persistence",
|
||||||
|
"privilege-escalation",
|
||||||
|
"defense-evasion",
|
||||||
|
"credential-access",
|
||||||
|
"discovery",
|
||||||
|
"lateral-movement",
|
||||||
|
"collection",
|
||||||
|
"command-and-control",
|
||||||
|
"exfiltration",
|
||||||
|
"impact"
|
||||||
|
],
|
||||||
|
"mobile-attack-Android": [
|
||||||
"initial-access",
|
"initial-access",
|
||||||
"execution",
|
"execution",
|
||||||
"persistence",
|
"persistence",
|
||||||
|
@ -34,7 +152,23 @@
|
||||||
"network-effects",
|
"network-effects",
|
||||||
"remote-service-effects"
|
"remote-service-effects"
|
||||||
],
|
],
|
||||||
"mitre-pre-attack": [
|
"mobile-attack-iOS": [
|
||||||
|
"initial-access",
|
||||||
|
"execution",
|
||||||
|
"persistence",
|
||||||
|
"privilege-escalation",
|
||||||
|
"defense-evasion",
|
||||||
|
"credential-access",
|
||||||
|
"discovery",
|
||||||
|
"lateral-movement",
|
||||||
|
"collection",
|
||||||
|
"command-and-control",
|
||||||
|
"exfiltration",
|
||||||
|
"impact",
|
||||||
|
"network-effects",
|
||||||
|
"remote-service-effects"
|
||||||
|
],
|
||||||
|
"pre-attack": [
|
||||||
"priority-definition-planning",
|
"priority-definition-planning",
|
||||||
"priority-definition-direction",
|
"priority-definition-direction",
|
||||||
"target-selection",
|
"target-selection",
|
||||||
|
@ -49,12 +183,14 @@
|
||||||
"persona-development",
|
"persona-development",
|
||||||
"build-capabilities",
|
"build-capabilities",
|
||||||
"test-capabilities",
|
"test-capabilities",
|
||||||
"stage-capabilities"
|
"stage-capabilities",
|
||||||
|
"launch",
|
||||||
|
"compromise"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"name": "Attack Pattern",
|
"name": "Attack Pattern",
|
||||||
"namespace": "mitre-attack",
|
"namespace": "mitre-attack",
|
||||||
"type": "mitre-attack-pattern",
|
"type": "mitre-attack-pattern",
|
||||||
"uuid": "c4e851fa-775f-11e7-8163-b774922098cd",
|
"uuid": "c4e851fa-775f-11e7-8163-b774922098cd",
|
||||||
"version": 9
|
"version": 10
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,62 @@ types = {'data-source': 'x-mitre-data-source',
|
||||||
}
|
}
|
||||||
mitre_sources = ['mitre-attack', 'mitre-ics-attack', 'mitre-pre-attack', 'mitre-mobile-attack']
|
mitre_sources = ['mitre-attack', 'mitre-ics-attack', 'mitre-pre-attack', 'mitre-mobile-attack']
|
||||||
|
|
||||||
|
|
||||||
|
kill_chain_order_sort_order = {
|
||||||
|
"attack": [
|
||||||
|
"reconnaissance",
|
||||||
|
"resource-development",
|
||||||
|
"initial-access",
|
||||||
|
"execution",
|
||||||
|
"persistence",
|
||||||
|
"privilege-escalation",
|
||||||
|
"defense-evasion",
|
||||||
|
"credential-access",
|
||||||
|
"discovery",
|
||||||
|
"lateral-movement",
|
||||||
|
"collection",
|
||||||
|
"command-and-control",
|
||||||
|
"exfiltration",
|
||||||
|
"impact"
|
||||||
|
],
|
||||||
|
"mobile-attack": [
|
||||||
|
"initial-access",
|
||||||
|
"execution",
|
||||||
|
"persistence",
|
||||||
|
"privilege-escalation",
|
||||||
|
"defense-evasion",
|
||||||
|
"credential-access",
|
||||||
|
"discovery",
|
||||||
|
"lateral-movement",
|
||||||
|
"collection",
|
||||||
|
"command-and-control",
|
||||||
|
"exfiltration",
|
||||||
|
"impact",
|
||||||
|
"network-effects",
|
||||||
|
"remote-service-effects"
|
||||||
|
],
|
||||||
|
"pre-attack": [
|
||||||
|
"priority-definition-planning",
|
||||||
|
"priority-definition-direction",
|
||||||
|
"target-selection",
|
||||||
|
"technical-information-gathering",
|
||||||
|
"people-information-gathering",
|
||||||
|
"organizational-information-gathering",
|
||||||
|
"technical-weakness-identification",
|
||||||
|
"people-weakness-identification",
|
||||||
|
"organizational-weakness-identification",
|
||||||
|
"adversary-opsec",
|
||||||
|
"establish-&-maintain-infrastructure",
|
||||||
|
"persona-development",
|
||||||
|
"build-capabilities",
|
||||||
|
"test-capabilities",
|
||||||
|
"stage-capabilities",
|
||||||
|
"launch", # added manually
|
||||||
|
"compromise" # added manually
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
all_data = {} # variable that will contain everything
|
all_data = {} # variable that will contain everything
|
||||||
|
|
||||||
# read in the non-MITRE data
|
# read in the non-MITRE data
|
||||||
|
@ -90,6 +146,12 @@ for domain in domains:
|
||||||
if item['type'] not in types.values():
|
if item['type'] not in types.values():
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# skip deprecated and/or revoked
|
||||||
|
# if 'revoked' in item and item['revoked']:
|
||||||
|
# continue
|
||||||
|
# if 'x_mitre_deprecated' in item and item['x_mitre_deprecated']:
|
||||||
|
# continue
|
||||||
|
|
||||||
# print(json.dumps(item, indent=2, sort_keys=True, ensure_ascii=False))
|
# print(json.dumps(item, indent=2, sort_keys=True, ensure_ascii=False))
|
||||||
try:
|
try:
|
||||||
# build the new data structure
|
# build the new data structure
|
||||||
|
@ -97,6 +159,7 @@ for domain in domains:
|
||||||
uuid = re.search('--(.*)$', item['id']).group(0)[2:]
|
uuid = re.search('--(.*)$', item['id']).group(0)[2:]
|
||||||
# item exist already in the all_data set
|
# item exist already in the all_data set
|
||||||
update = False
|
update = False
|
||||||
|
|
||||||
if uuid in all_data_uuid:
|
if uuid in all_data_uuid:
|
||||||
value = all_data_uuid[uuid]
|
value = all_data_uuid[uuid]
|
||||||
|
|
||||||
|
@ -130,12 +193,28 @@ for domain in domains:
|
||||||
if 'kill_chain_phases' in item: # many (but not all) attack-patterns have this
|
if 'kill_chain_phases' in item: # many (but not all) attack-patterns have this
|
||||||
value['meta']['kill_chain'] = []
|
value['meta']['kill_chain'] = []
|
||||||
for killchain in item['kill_chain_phases']:
|
for killchain in item['kill_chain_phases']:
|
||||||
value['meta']['kill_chain'].append(killchain['kill_chain_name'] + ':' + killchain['phase_name'])
|
kill_chain_name = killchain['kill_chain_name'][6:]
|
||||||
|
phase_name = killchain['phase_name']
|
||||||
|
if 'x_mitre_platforms' in item:
|
||||||
|
for platform in item['x_mitre_platforms']:
|
||||||
|
platform = platform.replace(' ', '-')
|
||||||
|
value['meta']['kill_chain'].append(f"{kill_chain_name}-{platform}:{phase_name}")
|
||||||
|
else:
|
||||||
|
value['meta']['kill_chain'].append(f"{kill_chain_name}:{phase_name}")
|
||||||
if 'x_mitre_data_sources' in item:
|
if 'x_mitre_data_sources' in item:
|
||||||
value['meta']['mitre_data_sources'] = item['x_mitre_data_sources']
|
value['meta']['mitre_data_sources'] = item['x_mitre_data_sources']
|
||||||
if 'x_mitre_platforms' in item:
|
if 'x_mitre_platforms' in item:
|
||||||
value['meta']['mitre_platforms'] = item['x_mitre_platforms']
|
value['meta']['mitre_platforms'] = item['x_mitre_platforms']
|
||||||
# TODO add the other x_mitre elements dynamically
|
# TODO add the other x_mitre elements dynamically
|
||||||
|
# x_mitre_fields = [key for key in item.keys() if key.startswith('x_mitre')]
|
||||||
|
# skip_x_mitre_fields = ['x_mitre_aliases', 'x_mitre_version', 'x_mitre_old_attack_id', 'mitre_attack_spec_version']
|
||||||
|
# for skip_field in skip_x_mitre_fields:
|
||||||
|
# try:
|
||||||
|
# x_mitre_fields.remove(skip_field)
|
||||||
|
# except ValueError:
|
||||||
|
# pass
|
||||||
|
# for x_mitre_field in x_mitre_fields:
|
||||||
|
# value['meta'][x_mitre_field[2:]] = item[x_mitre_field]
|
||||||
|
|
||||||
# relationships will be build separately afterwards
|
# relationships will be build separately afterwards
|
||||||
value['type'] = item['type'] # remove this before dump to json
|
value['type'] = item['type'] # remove this before dump to json
|
||||||
|
@ -144,7 +223,7 @@ for domain in domains:
|
||||||
# FIXME if 'x_mitre_deprecated' , 'revoked'
|
# FIXME if 'x_mitre_deprecated' , 'revoked'
|
||||||
all_data_uuid[uuid] = value
|
all_data_uuid[uuid] = value
|
||||||
|
|
||||||
except Exception as e:
|
except Exception:
|
||||||
print(json.dumps(item, sort_keys=True, indent=2))
|
print(json.dumps(item, sort_keys=True, indent=2))
|
||||||
import traceback
|
import traceback
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
@ -208,6 +287,8 @@ for domain in domains:
|
||||||
|
|
||||||
# dump all_data to their respective file
|
# dump all_data to their respective file
|
||||||
for t, meta_t in types.items():
|
for t, meta_t in types.items():
|
||||||
|
kill_chain_order = {}
|
||||||
|
|
||||||
fname = os.path.join(misp_dir, 'clusters', 'mitre-{}.json'.format(t))
|
fname = os.path.join(misp_dir, 'clusters', 'mitre-{}.json'.format(t))
|
||||||
if not os.path.exists(fname):
|
if not os.path.exists(fname):
|
||||||
exit("File {} does not exist, this is unexpected.".format(fname))
|
exit("File {} does not exist, this is unexpected.".format(fname))
|
||||||
|
@ -222,6 +303,11 @@ for t, meta_t in types.items():
|
||||||
item_2 = item.copy()
|
item_2 = item.copy()
|
||||||
item_2.pop('type', None)
|
item_2.pop('type', None)
|
||||||
file_data['values'].append(item_2)
|
file_data['values'].append(item_2)
|
||||||
|
for kill_chains in item['meta'].get('kill_chain', []):
|
||||||
|
kill_chain_name, kill_chain_phase = kill_chains.split(':')
|
||||||
|
if kill_chain_name not in kill_chain_order:
|
||||||
|
kill_chain_order[kill_chain_name] = set()
|
||||||
|
kill_chain_order[kill_chain_name].add(kill_chain_phase)
|
||||||
|
|
||||||
# FIXME the sort algo needs to be further improved, potentially with a recursive deep sort
|
# FIXME the sort algo needs to be further improved, potentially with a recursive deep sort
|
||||||
file_data['values'] = sorted(file_data['values'], key=lambda x: sorted(x['value']))
|
file_data['values'] = sorted(file_data['values'], key=lambda x: sorted(x['value']))
|
||||||
|
@ -238,4 +324,36 @@ for t, meta_t in types.items():
|
||||||
json.dump(file_data, f, indent=2, sort_keys=True, ensure_ascii=False)
|
json.dump(file_data, f, indent=2, sort_keys=True, ensure_ascii=False)
|
||||||
f.write('\n') # only needed for the beauty and to be compliant with jq_all_the_things
|
f.write('\n') # only needed for the beauty and to be compliant with jq_all_the_things
|
||||||
|
|
||||||
|
# rebuild the galaxies file with kill_chains
|
||||||
|
# OK, this is really inefficient, but just the easiest way to get it done now
|
||||||
|
fname_galaxy = os.path.join(misp_dir, 'galaxies', 'mitre-{}.json'.format(t))
|
||||||
|
if not os.path.exists(fname_galaxy):
|
||||||
|
exit("File {} does not exist, this is unexpected.".format(fname_galaxy))
|
||||||
|
with open(fname_galaxy) as f_galaxy:
|
||||||
|
file_data_galaxy = json.load(f_galaxy)
|
||||||
|
|
||||||
|
# sort the kill chain order in the right way, using the kill_chain_order_sort_order
|
||||||
|
kill_chain_order_sorted = {}
|
||||||
|
for kill_chain_name, kill_chain_phases in kill_chain_order.items():
|
||||||
|
for kill_chain_order_sort_order_key in kill_chain_order_sort_order.keys():
|
||||||
|
if kill_chain_name.startswith(kill_chain_order_sort_order_key):
|
||||||
|
try:
|
||||||
|
kill_chain_order_sorted[kill_chain_name] = sorted(
|
||||||
|
list(kill_chain_phases),
|
||||||
|
key=kill_chain_order_sort_order[kill_chain_order_sort_order_key].index)
|
||||||
|
except ValueError as e:
|
||||||
|
print("ERROR:")
|
||||||
|
print(f"- Kill chain: {kill_chain_name}")
|
||||||
|
print(f"- Kill chain phases: {kill_chain_phases}")
|
||||||
|
print(f"- Kill chain order sort order: {kill_chain_order_sort_order[kill_chain_order_sort_order_key]}")
|
||||||
|
exit(f"ERROR: kill_chain_order_sort_order does not contain a key for {kill_chain_name} - {e}. Please add it manually in the code.")
|
||||||
|
|
||||||
|
if kill_chain_order_sorted:
|
||||||
|
file_data_galaxy['kill_chain_order'] = dict(sorted(kill_chain_order_sorted.items()))
|
||||||
|
file_data_galaxy['version'] += 1
|
||||||
|
with open(fname_galaxy, 'w') as f_galaxy:
|
||||||
|
json.dump(file_data_galaxy, f_galaxy, indent=2, sort_keys=True, ensure_ascii=False)
|
||||||
|
f_galaxy.write('\n') # only needed for the beauty and to be compliant with jq_all_the_things
|
||||||
|
|
||||||
|
|
||||||
print("All done, please don't forget to ./jq_all_the_things.sh, commit, and then ./validate_all.sh.")
|
print("All done, please don't forget to ./jq_all_the_things.sh, commit, and then ./validate_all.sh.")
|
||||||
|
|
Loading…
Reference in a new issue