def generate_layer(self, match): """ Generate a layer :param match: the pattern to match :return: layer object with annotated techniques """ typeChecker(type(self).__name__, match, str, "match") raw_data, matched_obj = self.get_matrix_data(match) if matched_obj['type'] not in ["course-of-action", 'tool', 'malware', 'intrusion-set', 'x-mitre-data-source', 'x-mitre-data-component']: print(f"Warning: The input match {match} corresponds with an ATT&CK Technique, which is not supported. " f"Please provide a group, software, or mitigation instead.") raise StixObjectIsNotValid a_id = get_attack_id(matched_obj) processed_listing = self.generate_technique_data(raw_data) raw_layer = dict(name=f"{matched_obj['name']} ({matched_obj['id']})", domain=self.domain + '-attack') raw_layer['techniques'] = processed_listing output_layer = Layer(raw_layer) if matched_obj['type'] != 'x-mitre-data-component': name = matched_obj['name'] else: name = self.source_mapping[matched_obj['id']] output_layer.description = f"{self.domain.capitalize() if len(self.domain) > 3 else self.domain.upper()} " \ f"techniques used by {name}, ATT&CK {matched_obj['type']} {a_id}" return output_layer
def generate_layer(self, obj_type): """ Generate a layer :param obj_type: the type of object data to compute over (group, software, or mitigation) :return: layer object with annotated techniques """ typeChecker(type(self).__name__, obj_type, str, "type") categoryChecker( type(self).__name__, obj_type, ["group", "software", "mitigation", "datasource"], "type") initial_list = self.get_matrix_template() updated_list = self.update_template(obj_type, initial_list) if obj_type == "group": p_name = "groups" r_type = "using" elif obj_type == "software": p_name = "software" r_type = "using" elif obj_type == "datasource": p_name = "data sources" r_type = "detecting" else: # mitigation case p_name = "mitigations" r_type = "mitigating" desc = f"Overview of techniques used by {p_name}. Score is the number of {p_name} " \ f"{r_type} the technique, and comment lists the {r_type} {p_name}" raw_layer = dict(name=f"{p_name} overview", domain='enterprise-attack', description=desc) raw_layer['techniques'] = updated_list output_layer = Layer(raw_layer) return output_layer
def score(self, score): try: typeChecker(type(self).__name__, score, int, "score") self.__score = score except BadType: typeChecker(type(self).__name__, score, float, "score") self.__score = int(score)
def navigator(self, navigator): typeChecker(type(self).__name__, navigator, str, "navigator") if not navigator.startswith('4.'): print(f'[WARNING] - unrecognized navigator version {navigator}. Defaulting to the 4.X schema, ' f'this may result in unexpected behavior.') navigator = defaults['navigator'] self.__navigator = navigator
def techniqueID(self, techniqueID): typeChecker(type(self).__name__, techniqueID, str, "techniqueID") if not techniqueID.startswith('T'): handler( type(self).__name__, '{} not a valid value for techniqueID'.format(techniqueID)) raise BadInput else: self.__techniqueID = techniqueID
def domain(self, domain): typeChecker(type(self).__name__, domain, str, "domain") dom = domain if dom.startswith('mitre'): dom = dom.split('-')[-1] + '-attack' categoryChecker(type(self).__name__, dom, ["enterprise-attack", "mobile-attack", "ics-attack"], "domain") self.__domain = domain
def layer(self, layer): typeChecker(type(self).__name__, layer, str, "layer") try: categoryChecker(type(self).__name__, layer, ["3.0", "4.0", "4.1", "4.2", "4.3"], "layer version") except BadInput: print(f'[WARNING] - unrecognized layer version {layer}. Defaulting to the 4.3 schema, this may result in ' f'unexpected behavior.') if layer in ["3.0", "4.0", "4.1", "4.2"]: print(f'[NOTICE] - Forcibly upgrading version from {layer} to 4.3.') layer = "4.3" self.__layer = layer
def links(self, links): typeChecker(type(self).__name__, links, list, "links") if not handle_object_placement(self.__links, links, Link): self.__links = [] entry = "" try: for entry in links: if "divider" in entry: self.__links.append(Link(entry["divider"])) else: self.__links.append(Link(entry['label'], entry['url'])) except KeyError as e: handler(type(self).__name__, 'Link {} is missing parameters: ' '{}. Unable to load.' .format(entry, e))
def legendItems(self, legendItems): typeChecker(type(self).__name__, legendItems, list, "legendItems") self.__legendItems = [] for entry in legendItems: ret = handle_object_placement(self.__legendItems, entry, LegendItem, list=True) if ret: self.__legendItems = ret else: try: loadChecker(type(self).__name__, entry, ['label', 'color'], "legendItem") temp = LegendItem(entry['label'], entry['color']) self.__legendItems.append(temp) except MissingParameters as e: handler(type(self).__name__, 'Legend Item {} is missing parameters: ' '{}. Skipping.' .format(entry, e))
def versions(self, versions): ret = handle_object_placement(self.__versions, versions, Versions) if ret: self.__versions = ret else: typeChecker(type(self).__name__, versions, dict, "version") attack = UNSETVALUE if 'attack' in versions: attack = versions['attack'] try: loadChecker(type(self).__name__, versions, ['layer', 'navigator'], "versions") self.__versions = Versions(versions['layer'], attack, versions['navigator']) except MissingParameters as e: handler(type(self).__name__, 'versions {} is missing parameters: ' '{}. Skipping.' .format(versions, e))
def metadata(self, metadata): typeChecker(type(self).__name__, metadata, list, "metadata") if not handle_object_placement(self.__metadata, metadata, Metadata): self.__metadata = [] entry = "" try: for entry in metadata: if "divider" in entry: self.__metadata.append(MetaDiv(entry["divider"])) else: self.__metadata.append( Metadata(entry['name'], entry['value'])) except KeyError as e: handler( type(self).__name__, 'Metadata {} is missing parameters: ' '{}. Unable to load.'.format(entry, e))
def techniques(self, techniques): typeChecker(type(self).__name__, techniques, list, "techniques") self.__techniques = [] for entry in techniques: ret = handle_object_placement(self.__techniques, entry, Technique, list=True) if ret: self.__techniques = ret else: try: loadChecker(type(self).__name__, entry, ['techniqueID'], "technique") temp = Technique(entry['techniqueID']) temp._loader(entry) self.__techniques.append(temp) except MissingParameters as e: handler(type(self).__name__, 'Technique {} is missing parameters: ' '{}. Skipping.' .format(entry, e))
def metadata(self, metadata): typeChecker(type(self).__name__, metadata, list, "metadata") self.__metadata = [] for entry in metadata: ret = handle_object_placement(self.__metadata, entry, Metadata, list=True) if ret: self.__metadata = ret else: try: if "divider" in entry: self.__metadata.append(MetaDiv(entry["divider"])) else: loadChecker(type(self).__name__, entry, ['name', 'value'], "metadata") self.__metadata.append(Metadata(entry['name'], entry['value'])) except MissingParameters as e: handler( type(self).__name__, 'Metadata {} is missing parameters: {}. Skipping.'.format(entry, e) )
def generate_layers(self, layers_type): """ Generate and return a collection of layers for all objects of a given type :param layers_type: the type of object to generate layers for (group, software, mitigation or datasource) :return: dictionary of generated layer objects, referenced by STIX-ID """ typeChecker(type(self).__name__, layers_type, str, "type") categoryChecker( type(self).__name__, layers_type, ["group", "software", "mitigation", "datasource"], "type") produced = dict() object_listing = remove_revoked_depreciated( self.usage_handle.source_handle.query(self.mapping[layers_type])) for entry in tqdm(object_listing, desc=f"building {layers_type} matrices"): try: produced[entry['id']] = self.usage_handle.generate_layer( get_attack_id(entry)) except datastore.DataSourceError as e: print( f"WARNING - unable to generate layer for {(entry['id'], entry['name'])}. " f"Specifically, generator encountered {e}. Continuing...") return produced
def description(self, description): typeChecker(type(self).__name__, description, str, "description") self.__description = description
def state(self, state): typeChecker(type(self).__name__, state, bool, "state") self.__value = state
def name(self, name): typeChecker(type(self).__name__, name, str, "name") self.__name = name
def showName(self, showName): typeChecker(type(self).__name__, showName, bool, "showName") self.__showName = showName
def version(self, version): typeChecker(type(self).__name__, version, str, "version") categoryChecker(type(self).__name__, version, ["3.0", "4.0", "4.1", "4.2", "4.3"], "version") if self.__versions is UNSETVALUE: self.__versions = Versions() self.__versions.layer = version
def selectSubtechniquesWithParent(self, selectSubtechniquesWithParent): typeChecker(type(self).__name__, selectSubtechniquesWithParent, bool, "selectSubtechniquesWithParent") self.__selectSubtechniquesWithParent = selectSubtechniquesWithParent
def showAggregateScores(self, showAggregateScores): typeChecker( type(self).__name__, showAggregateScores, bool, "showAggregateScores") self.__showAggregateScores = showAggregateScores
def tacticRowBackground(self, tacticRowBackground): typeChecker(type(self).__name__, tacticRowBackground, str, "tacticRowBackground") self.__tacticRowBackground = tacticRowBackground
def selectTechniquesAcrossTactics(self, selectTechniquesAcrossTactics): typeChecker(type(self).__name__, selectTechniquesAcrossTactics, bool, "selectTechniqueAcrossTactics") self.__selectTechniquesAcrossTactics = selectTechniquesAcrossTactics
def countUnscored(self, countUnscored): typeChecker(type(self).__name__, countUnscored, bool, "countUnscored") self.__countUnscored = countUnscored
def showTacticRowBackground(self, showTacticRowBackground): typeChecker(type(self).__name__, showTacticRowBackground, bool, "showTacticRowBackground") self.__showTacticRowBackground = showTacticRowBackground
def layout(self, layout): typeChecker(type(self).__name__, layout, str, "layout") categoryChecker( type(self).__name__, layout, ["side", "flat", "mini"], "layout") self.__layout = layout
def hideDisabled(self, hideDisabled): typeChecker(type(self).__name__, hideDisabled, bool, "hideDisabled") self.__hideDisabled = hideDisabled
def sorting(self, sorting): typeChecker(type(self).__name__, sorting, int, "sorting") categoryChecker(type(self).__name__, sorting, [0, 1, 2, 3], "sorting") self.__sorting = sorting
def showID(self, showID): typeChecker(type(self).__name__, showID, bool, "showID") self.__showID = showID
def maxValue(self, maxValue): typeChecker(type(self).__name__, maxValue, int, "maxValue") self.__maxValue = maxValue self._compute_curve()