Added applicable_to parameter in command line arguments and interactive menu, to filter on this field while generating a layer file.

master
Ruben 2019-04-18 15:32:35 +02:00
parent 0dd76c68a1
commit 58497e41ce
3 changed files with 49 additions and 29 deletions

View File

@ -67,7 +67,10 @@ def init_menu():
parser_detection.add_argument('-fd', '--file-ds', help='path to the data source administration YAML file (used in '
'the overlay with visibility to add metadata on the '
'involved data sources)')
parser_detection.add_argument('-l', '--layer', help='generate detection layer for the ATT&CK navigator',
parser_detection.add_argument('-a', '--applicable', help='filter techniques in the layer file based on the'
'applicable_to field in the technique administration YAML'
'file', default='all')
parser_detection.add_argument('-l', '--layer', help='generate detection layer for the ATT&CK navigator',
action='store_true')
parser_detection.add_argument('-e', '--excel', help='generate an Excel sheet with all administrated techniques',
action='store_true')
@ -174,9 +177,9 @@ def menu(menu_parser):
if check_file_type(args.file_tech, FILE_TYPE_TECHNIQUE_ADMINISTRATION):
if args.layer:
generate_detection_layer(args.file_tech, args.file_ds, False)
generate_detection_layer(args.file_tech, args.file_ds, False, args.applicable)
if args.overlay and check_file_type(args.file_ds, FILE_TYPE_DATA_SOURCE_ADMINISTRATION):
generate_detection_layer(args.file_tech, args.file_ds, True)
generate_detection_layer(args.file_tech, args.file_ds, True, args.applicable)
if args.graph:
plot_detection_graph(args.file_tech)
if args.excel:

View File

@ -11,6 +11,7 @@ platform = 'Windows'
stage = 'attack'
groups_overlay = ''
overlay_type = ''
filter_applicable_to = 'all'
MENU_NAME_DATA_SOURCE_MAPPING = 'Data source mapping'
MENU_NAME_VISIBILITY_MAPPING = 'Visibility coverage mapping'
@ -250,32 +251,39 @@ def menu_detection(filename_t):
:param filename_t:
:return:
"""
global filter_applicable_to
clear()
print('Menu: %s' % MENU_NAME_DETECTION_COVERAGE_MAPPING)
print('')
print('Selected techniques YAML file: %s' % filename_t)
print('')
print('Options:')
print('1. Filter techniques in the layer file based on the applicable_to field in the technique administration YAML file: %s' % filter_applicable_to)
print('')
print('Select what you want to do:')
print('1. Generate a layer for detection coverage for the ATT&CK Navigator.')
print('2. Generate a layer for detection coverage overlayed with visibility for the ATT&CK Navigator.')
print('3. Generate a graph with detections added through time.')
print('4. Generate an Excel sheet with all administrated techniques.')
print('2. Generate a layer for detection coverage for the ATT&CK Navigator.')
print('3. Generate a layer for detection coverage overlayed with visibility for the ATT&CK Navigator.')
print('4. Generate a graph with detections added through time.')
print('5. Generate an Excel sheet with all administrated techniques.')
print('9. Back to main menu.')
choice = ask_input()
if choice == '1':
print('Writing detection coverage layer...')
generate_detection_layer(filename_t, None, False)
wait()
print('Specify your filter for the applicable_to field:')
filter_applicable_to = ask_input().lower()
elif choice == '2':
filename_ds = select_file(MENU_NAME_DETECTION_COVERAGE_MAPPING, 'data sources (used to add metadata on the involved data sources to the heat map)', FILE_TYPE_DATA_SOURCE_ADMINISTRATION, False)
print('Writing detection coverage layer with visibility as overlay...')
generate_detection_layer(filename_t, filename_ds, True)
print('Writing detection coverage layer...')
generate_detection_layer(filename_t, None, False, filter_applicable_to)
wait()
elif choice == '3':
filename_ds = select_file(MENU_NAME_DETECTION_COVERAGE_MAPPING, 'data sources (used to add metadata on the involved data sources to the heat map)', FILE_TYPE_DATA_SOURCE_ADMINISTRATION, False)
print('Writing detection coverage layer with visibility as overlay...')
generate_detection_layer(filename_t, filename_ds, True, filter_applicable_to)
wait()
elif choice == '4':
print('Drawing the graph...')
plot_detection_graph(filename_t)
wait()
elif choice == '4':
elif choice == '5':
print('Generating Excel file...')
export_techniques_list_to_excel(filename_t)
wait()

View File

@ -4,7 +4,7 @@ import xlsxwriter
# Imports for pandas and plotly are because of performance reasons in the function that uses these libraries.
def generate_detection_layer(filename_techniques, filename_data_sources, overlay):
def generate_detection_layer(filename_techniques, filename_data_sources, overlay, filter_applicable_to):
"""
Generates layer for detection coverage and optionally an overlayed version with visibility coverage.
:param filename_techniques: the filename of the yaml file containing the techniques administration
@ -12,17 +12,17 @@ def generate_detection_layer(filename_techniques, filename_data_sources, overlay
:param overlay: boolean value to specify if an overlay between detection and visibility should be generated
:return:
"""
my_techniques, name, platform = _load_detections(filename_techniques)
my_techniques, name, platform = _load_detections(filename_techniques, filter_applicable_to)
if not overlay:
mapped_techniques_detection = _map_and_colorize_techniques_for_detections(my_techniques)
layer_detection = get_layer_template_detections('Detections ' + name, 'description', 'attack', platform)
_write_layer(layer_detection, mapped_techniques_detection, 'detection', name)
layer_detection = get_layer_template_detections('Detections ' + name + ' ' + filter_applicable_to, 'description', 'attack', platform)
_write_layer(layer_detection, mapped_techniques_detection, 'detection', filter_applicable_to, name)
else:
my_data_sources = _load_data_sources(filename_data_sources)
mapped_techniques_both = _map_and_colorize_techniques_for_overlayed(my_techniques, my_data_sources)
layer_both = get_layer_template_layered('Visibility and Detection ' + name, 'description', 'attack', platform)
_write_layer(layer_both, mapped_techniques_both, 'visibility_and_detection', name)
layer_both = get_layer_template_layered('Visibility and Detection ' + name + ' ' + filter_applicable_to, 'description', 'attack', platform)
_write_layer(layer_both, mapped_techniques_both, 'visibility_and_detection', filter_applicable_to, name)
def generate_visibility_layer(filename_techniques, filename_data_sources, overlay):
@ -39,11 +39,11 @@ def generate_visibility_layer(filename_techniques, filename_data_sources, overla
if not overlay:
mapped_techniques_visibility = _map_and_colorize_techniques_for_visibility(my_techniques, my_data_sources)
layer_visibility = get_layer_template_visibility('Visibility ' + name, 'description', 'attack', platform)
_write_layer(layer_visibility, mapped_techniques_visibility, 'visibility', name)
_write_layer(layer_visibility, mapped_techniques_visibility, 'visibility', '', name)
else:
mapped_techniques_both = _map_and_colorize_techniques_for_overlayed(my_techniques, my_data_sources)
layer_both = get_layer_template_layered('Visibility and Detection ' + name, 'description', 'attack', platform)
_write_layer(layer_both, mapped_techniques_both, 'visibility_and_detection', name)
_write_layer(layer_both, mapped_techniques_both, 'visibility_and_detection', '', name)
def plot_detection_graph(filename):
@ -75,17 +75,23 @@ def plot_detection_graph(filename):
print("File written: " + output_filename)
def _load_detections(filename):
def _load_detections(filename, filter_applicable_to=''):
"""
Loads the techniques (including detection and visibility properties) from the given yaml file.
:param filename: the filename of the yaml file containing the techniques administration
:return: dictionary with techniques (incl. properties), name and platform
"""
my_techniques = {}
with open(filename, 'r') as yaml_file:
yaml_content = yaml.load(yaml_file, Loader=yaml.FullLoader)
for d in yaml_content['techniques']:
my_techniques[d['technique_id']] = d
applicable_to = True
if 'applicable_to' in d['detection'].keys():
if filter_applicable_to != 'all' and filter_applicable_to not in d['detection']['applicable_to'] and 'all' not in d['detection']['applicable_to']:
applicable_to = False
if applicable_to:
my_techniques[d['technique_id']] = d
name = yaml_content['name']
platform = yaml_content['platform']
return my_techniques, name, platform
@ -107,7 +113,7 @@ def _load_data_sources(filename):
return my_data_sources
def _write_layer(layer, mapped_techniques, filename_prefix, name):
def _write_layer(layer, mapped_techniques, filename_prefix, filename_suffix, name):
"""
Writes the json layer file to disk.
:param layer: the prepped layer dictionary
@ -119,7 +125,8 @@ def _write_layer(layer, mapped_techniques, filename_prefix, name):
layer['techniques'] = mapped_techniques
json_string = simplejson.dumps(layer).replace('}, ', '},\n')
output_filename = 'output/%s_%s.json' % (filename_prefix, normalize_name_to_filename(name))
filename_suffix = '_' + filename_suffix if filename_suffix != '' else ''
output_filename = 'output/%s_%s%s.json' % (filename_prefix, normalize_name_to_filename(name), filename_suffix)
with open(output_filename, 'w') as f:
f.write(json_string)
print("File written: " + output_filename)
@ -150,7 +157,10 @@ def _map_and_colorize_techniques_for_detections(my_techniques):
for tactic in technique['tactic']:
location = ', '.join(c['detection']['location']) if 'detection' in c.keys() else '-'
location = location if location != '' else '-'
applicable_to = ', '.join(c['detection']['applicable_to']) if 'detection' in c.keys() else '-'
if 'applicable_to' in c['detection'].keys():
applicable_to = ', '.join(c['detection']['applicable_to']) if 'detection' in c.keys() else '-'
else:
applicable_to = '-'
x = {}
x['techniqueID'] = d
x['color'] = color
@ -162,8 +172,7 @@ def _map_and_colorize_techniques_for_detections(my_techniques):
{'name': '-Comment', 'value': comment},
{'name': '-Applicable to', 'value': applicable_to}]
x['score'] = s
mapped_techniques.append(x)
mapped_techniques.append(x)
except Exception:
print('[!] Possible error in YAML file at: ' + d)
quit()