Beispiel #1
0
def generate_group_heat_map(groups,
                            overlay,
                            overlay_type,
                            stage,
                            platform,
                            software_groups,
                            search_visibility,
                            search_detection,
                            health_is_called,
                            include_all_score_objs=False):
    """
    Calls all functions that are necessary for the generation of the heat map and write a json layer to disk.
    :param groups: threat actor groups
    :param overlay: group(s), visibility or detections to overlay (group ID, group name/alias, YAML file with
    group(s), detections or visibility)
    :param overlay_type: group, visibility or detection
    :param stage: attack or pre-attack
    :param platform: one of the values from PLATFORMS constant or 'all'
    :param software_groups: specify if techniques from related software should be included
    :param search_visibility: visibility EQL search query
    :param search_detection: detection EQL search query
    :param health_is_called: boolean that specifies if detailed errors in the file will be printed
    :param include_all_score_objs: include all score objects within the score_logbook for the EQL query
    :return: returns nothing when something's wrong
    """
    overlay_dict = {}
    groups_software_dict = {}

    groups_file_type = None
    if os.path.isfile(groups):
        groups_file_type = check_file(groups,
                                      file_type=FILE_TYPE_GROUP_ADMINISTRATION,
                                      health_is_called=health_is_called)
        if not groups_file_type:
            return
    else:
        # remove whitespaces (leading and trailing), convert to lower case and put in a list
        groups = groups.split(',')
        groups = list(map(lambda x: x.strip().lower(), groups))

    # set the correct value for platform
    if groups_file_type == FILE_TYPE_GROUP_ADMINISTRATION:
        _yaml = init_yaml()
        with open(groups, 'r') as yaml_file:
            group_file = _yaml.load(yaml_file)

        platform_yaml = get_platform_from_yaml(group_file)
        if platform_yaml:
            platform = platform_yaml
    if isinstance(platform, str) and platform.lower() != 'all':
        platform = [platform]

    overlay_file_type = None
    if overlay:
        if os.path.isfile(overlay):
            expected_file_type = FILE_TYPE_GROUP_ADMINISTRATION if overlay_type == OVERLAY_TYPE_GROUP \
                else FILE_TYPE_TECHNIQUE_ADMINISTRATION \
                if overlay_type in [OVERLAY_TYPE_VISIBILITY, OVERLAY_TYPE_DETECTION] else None
            overlay_file_type = check_file(overlay,
                                           expected_file_type,
                                           health_is_called=health_is_called)
            if not overlay_file_type:
                return
        else:
            overlay = overlay.split(',')
            overlay = list(map(lambda x: x.strip().lower(), overlay))
    else:
        overlay = []

    # load the techniques (visibility or detection) from the YAML file
    all_techniques = None
    if overlay_file_type == FILE_TYPE_TECHNIQUE_ADMINISTRATION:
        # filter out visibility and/or detection objects using EQL
        if search_detection or search_visibility:
            overlay = techniques_search(
                overlay,
                search_visibility,
                search_detection,
                include_all_score_objs=include_all_score_objs)
            if not overlay:
                return None  # something went wrong in executing the search or 0 results where returned

        if overlay_type == OVERLAY_TYPE_VISIBILITY:
            overlay_dict, all_techniques = _get_visibility_techniques(overlay)
        elif overlay_type == OVERLAY_TYPE_DETECTION:
            overlay_dict, all_techniques = _get_detection_techniques(overlay)
    # we are not overlaying visibility or detection, overlay group will therefore contain information on another group
    elif len(overlay) > 0:
        overlay_dict = _get_group_techniques(overlay, stage, platform,
                                             overlay_file_type)
        if overlay_dict == -1:
            return

    groups_dict = _get_group_techniques(groups, stage, platform,
                                        groups_file_type)
    if groups_dict == -1:
        return
    if len(groups_dict) == 0:
        print('[!] Empty layer.'
              )  # the provided groups dit not result in any techniques
        return

    # check if we are doing a software group overlay
    if software_groups and overlay:
        if overlay_type not in [
                OVERLAY_TYPE_VISIBILITY, OVERLAY_TYPE_DETECTION
        ]:
            # if a group overlay is provided, get the software techniques for the overlay
            groups_software_dict = _get_software_techniques(
                overlay, stage, platform)
    elif software_groups:
        groups_software_dict = _get_software_techniques(
            groups, stage, platform)

    technique_count, max_count = _get_technique_count(groups_dict,
                                                      overlay_dict,
                                                      groups_software_dict,
                                                      overlay_type,
                                                      all_techniques)
    technique_layer = _get_technique_layer(technique_count, groups_dict,
                                           overlay_dict, groups_software_dict,
                                           overlay_file_type, overlay_type,
                                           all_techniques)

    # make a list group names for the involved groups.
    if groups == ['all']:
        groups_list = ['all']
    else:
        groups_list = _get_group_list(groups_dict, groups_file_type)
    overlay_list = _get_group_list(overlay_dict, overlay_file_type)

    desc = 'stage: ' + stage + ' | platform(s): ' + platform_to_name(platform, separator=', ') + ' | group(s): ' \
           + ', '.join(groups_list) + ' | overlay group(s): ' + ', '.join(overlay_list)

    layer = get_layer_template_groups(
        stage[0].upper() + stage[1:] + ' - ' +
        platform_to_name(platform, separator=', '), max_count, desc, stage,
        platform, overlay_type)
    layer['techniques'] = technique_layer

    json_string = simplejson.dumps(layer).replace('}, ', '},\n')

    if stage == 'pre-attack':
        filename = '_'.join(groups_list)
    elif overlay:
        filename = platform_to_name(platform) + '_' + '_'.join(
            groups_list) + '-overlay_' + '_'.join(overlay_list)
    else:
        filename = platform_to_name(platform) + '_' + '_'.join(groups_list)

    write_file(stage, filename[:255], json_string)
Beispiel #2
0
def generate_group_heat_map(groups,
                            overlay,
                            overlay_type,
                            platform,
                            software_groups,
                            search_visibility,
                            search_detection,
                            health_is_called,
                            output_filename,
                            layer_name,
                            include_all_score_objs=False):
    """
    Calls all functions that are necessary for the generation of the heat map and write a json layer to disk.
    :param groups: threat actor groups
    :param overlay: group(s), visibility or detections to overlay (group ID, group name/alias, YAML file with
    group(s), detections or visibility)
    :param overlay_type: group, visibility or detection
    :param platform: one or multiple the values from PLATFORMS constant or None (default = Windows)
    :param software_groups: specify if techniques from related software should be included
    :param search_visibility: visibility EQL search query
    :param search_detection: detection EQL search query
    :param health_is_called: boolean that specifies if detailed errors in the file will be printed
    :param output_filename: output filename defined by the user
    :param layer_name: the name of the Navigator layer
    :param include_all_score_objs: include all score objects within the score_logbook for the EQL query
    :return: returns None when something went wrong
    """
    overlay_dict = {}
    groups_software_dict = {}

    groups_file_type = None
    if groups == None:
        groups = ['all']
    elif os.path.isfile(groups[0]):
        groups = groups[0]
        groups_file_type = check_file(groups,
                                      file_type=FILE_TYPE_GROUP_ADMINISTRATION,
                                      health_is_called=health_is_called)
        if not groups_file_type:
            return None  # the groups_file_type is not of the type FILE_TYPE_GROUP_ADMINISTRATION
    elif isinstance(groups[0], str) and len(groups) == 1:
        # reached when the groups are provided via the interactive menu, or when the CLI only contained one argument
        groups = groups[0]
        groups = groups.split(',')
        groups = list(map(lambda x: x.strip().lower(), groups))
    else:  # reached when the groups are provided via CLI arguments
        groups = list(map(lambda x: x.strip().lower(), groups))

    # set the correct value for platform
    platform_yaml = None
    if groups_file_type == FILE_TYPE_GROUP_ADMINISTRATION:
        _yaml = init_yaml()
        with open(groups, 'r') as yaml_file:
            group_file = _yaml.load(yaml_file)

        platform_yaml = get_platform_from_yaml(group_file)

    if platform == None and platform_yaml != None:
        platform = platform_yaml
    elif platform == None:
        platform = ['Windows']
    elif 'all' in platform:
        platform = list(PLATFORMS.values())

    overlay_file_type = None
    if overlay:
        if os.path.isfile(overlay[0]):
            overlay = overlay[0]
            expected_file_type = FILE_TYPE_GROUP_ADMINISTRATION if overlay_type == OVERLAY_TYPE_GROUP \
                else FILE_TYPE_TECHNIQUE_ADMINISTRATION \
                if overlay_type in [OVERLAY_TYPE_VISIBILITY, OVERLAY_TYPE_DETECTION] else None
            overlay_file_type = check_file(overlay,
                                           expected_file_type,
                                           health_is_called=health_is_called)
            if not overlay_file_type:
                return None  # the overlay_file_type is not of the expected type
        elif isinstance(overlay, str):
            # reached when the overlay is provided via the interactive menu
            overlay = overlay.split(',')
            overlay = list(map(lambda x: x.strip().lower(), overlay))
        else:  # reached when the groups are provided via CLI arguments
            overlay = list(map(lambda x: x.strip().lower(), overlay))
    else:
        overlay = []

    # load the techniques (visibility or detection) from the YAML file
    all_techniques = None
    if overlay_file_type == FILE_TYPE_TECHNIQUE_ADMINISTRATION:
        # filter out visibility and/or detection objects using EQL
        if search_detection or search_visibility:
            overlay = techniques_search(
                overlay,
                search_visibility,
                search_detection,
                include_all_score_objs=include_all_score_objs)
            if not overlay:
                return None  # something went wrong in executing the search or 0 results where returned

        if overlay_type == OVERLAY_TYPE_VISIBILITY:
            overlay_dict, all_techniques = _get_visibility_techniques(overlay)
        elif overlay_type == OVERLAY_TYPE_DETECTION:
            overlay_dict, all_techniques = _get_detection_techniques(overlay)

    # we are not overlaying visibility or detection, overlay group will therefore contain information on another group
    elif len(overlay) > 0:
        overlay_dict = _get_group_techniques(overlay, platform,
                                             overlay_file_type)
        if overlay_dict == -1:
            return None  # returns None when the provided Group(s) to be overlaid, contains Groups not part of ATT&CK

    groups_dict = _get_group_techniques(groups, platform, groups_file_type)
    if groups_dict == -1:
        return None  # returns None when the provided Group contains Groups not part of ATT&CK
    if len(groups_dict) == 0:
        print('[!] Empty layer.'
              )  # the provided groups dit not result in any techniques
        return None

    # check if we are doing a software group overlay
    if software_groups and overlay:
        if overlay_type not in [
                OVERLAY_TYPE_VISIBILITY, OVERLAY_TYPE_DETECTION
        ]:
            # if a group overlay is provided, get the software techniques for the overlay
            groups_software_dict = _get_software_techniques(overlay, platform)
    elif software_groups:
        groups_software_dict = _get_software_techniques(groups, platform)

    technique_count, max_count = _get_technique_count(groups_dict,
                                                      overlay_dict,
                                                      groups_software_dict,
                                                      overlay_type,
                                                      all_techniques)
    technique_layer = _get_technique_layer(technique_count, groups_dict,
                                           overlay_dict, groups_software_dict,
                                           overlay_file_type, overlay_type,
                                           all_techniques)

    # make a list group names for the involved groups.
    if groups == ['all']:
        groups_list = ['all']
    else:
        groups_list = _get_group_list(groups_dict, groups_file_type)
    overlay_list = _get_group_list(overlay_dict, overlay_file_type)

    desc = 'stage: attack | platform(s): ' + platform_to_name(platform, separator=', ') + ' | group(s): ' \
        + ', '.join(groups_list) + ' | overlay group(s): ' + ', '.join(overlay_list)

    if not layer_name:
        layer_name = 'Attack - ' + platform_to_name(platform, separator=', ')

    layer = get_layer_template_groups(layer_name, max_count, desc, platform,
                                      overlay_type)
    layer['techniques'] = technique_layer

    json_string = simplejson.dumps(layer).replace('}, ', '},\n')

    if not output_filename:
        if overlay:
            filename = platform_to_name(platform) + '_' + '_'.join(
                groups_list) + '-overlay_' + '_'.join(overlay_list)
        else:
            filename = platform_to_name(platform) + '_' + '_'.join(groups_list)

        filename = create_output_filename('attack', filename)
        write_file(filename, json_string)
    else:
        write_file(output_filename, json_string)