def main(args): if len(args) < 4: sys.exit("Invalid parameters") baseURL = args[1] if not baseURL: baseURL = 'https://www.misp-project.org' orgname = args[2] orgname = re.sub('[\W]+', '', orgname.replace(" ", "_")) NS_DICT[baseURL] = orgname try: idgen.set_id_namespace(Namespace(baseURL, orgname)) except TypeError: idgen.set_id_namespace(Namespace(baseURL, orgname, "MISP")) stix_package = STIXPackage() stix_header = STIXHeader() stix_header.title = "Export from {} MISP".format(args[2]) stix_header.package_intents = "Threat Report" stix_package.stix_header = stix_header stix_package.version = "1.1.1" stix_package.timestamp = datetime.datetime.now() if args[3] == 'json': stix_string = stix_package.to_json()[:-1] stix_string += ', "related_packages": [' else: stix_string = stix_package.to_xml(auto_namespace=False, ns_dict=NS_DICT, schemaloc_dict=SCHEMALOC_DICT) stix_string = stix_string.decode().replace("</stix:STIX_Package>\n", "") print(stix_string)
def generateMainPackage(events): stix_package = STIXPackage() stix_header = STIXHeader() stix_header.title = "Export from " + namespace[1] + " MISP" stix_header.package_intents = "Threat Report" stix_package.stix_header = stix_header return stix_package
def test_stix_header(self): header = STIXHeader() header.title = UNICODE_STR header.description = UNICODE_STR header.short_description = UNICODE_STR header2 = round_trip(header) self._test_equal(header, header2)
def test_to_xml_utf16_encoded(self): encoding = 'utf-16' s = STIXHeader() s.title = UNICODE_STR xml = s.to_xml(encoding=encoding) print(xml) self.assertTrue(UNICODE_STR in xml.decode(encoding))
def stix_pkg(config, src, endpoint, payload, title='random test data', description='random test data', package_intents='Indicators - Watchlist', tlp_color='WHITE', dest=None): '''package observables''' # setup the xmlns... xmlns_url = config['edge']['sites'][dest]['stix']['xmlns_url'] xmlns_name = config['edge']['sites'][dest]['stix']['xmlns_name'] set_stix_id_namespace({xmlns_url: xmlns_name}) set_cybox_id_namespace(Namespace(xmlns_url, xmlns_name)) # construct a stix package... stix_package = STIXPackage() stix_header = STIXHeader() stix_header.title = title stix_header.description = description stix_header.package_intents = package_intents marking = MarkingSpecification() marking.controlled_structure = '../../../../descendant-or-self::node()' tlp_marking = TLPMarkingStructure() tlp_marking.color = tlp_color marking.marking_structures.append(tlp_marking) stix_package.stix_header = stix_header stix_package.stix_header.handling = Marking() stix_package.stix_header.handling.add_marking(marking) if isinstance(payload, Observable): stix_package.add_observable(payload) elif isinstance(payload, Indicator): stix_package.add_indicator(payload) elif isinstance(payload, Incident): stix_package.add_incident(payload) return(stix_package)
def generateMainPackage(events): stix_package = STIXPackage() stix_header = STIXHeader() stix_header.title="Export from " + namespace[1] + " MISP" stix_header.package_intents="Threat Report" stix_package.stix_header = stix_header return stix_package
def _add_header(self, stix_package, title, desc): stix_header = STIXHeader() stix_header.title = title stix_header.description = desc stix_header.information_source = InformationSource() stix_header.information_source.time = CyboxTime() stix_header.information_source.time.produced_time = datetime.now().isoformat() stix_package.stix_header = stix_header
def _add_header(self, stix_package, title, desc): stix_header = STIXHeader() stix_header.title = title stix_header.description = desc stix_header.information_source = InformationSource() stix_header.information_source.time = CyboxTime() stix_header.information_source.time.produced_time = datetime.now() stix_package.stix_header = stix_header
def main(): # get args parser = argparse.ArgumentParser( description="Parse an input JSON file and output STIX XML ", formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument("infile",help="input file") parser.add_argument("--outfile","-o", help="output file") args = parser.parse_args() # We assume the input file is a flat JSON file # format 'bot_name':[list,of,ips] content = json.load(open(args.infile)) # Set up STIX document stix_package = STIXPackage() stix_header = STIXHeader() stix_header.title = "C2 Server IP Addresses" stix_header.add_package_intent (PackageIntent.TERM_INDICATORS_WATCHLIST) stix_package.stix_header = stix_header # Create Indicator and TTP for each item in JSON document for item in content: # Create TTP for C2 server ttp = TTP() ttp.title = item stix_package.add_ttp(ttp) # Create Indicator for C2 IP addresses indicator = Indicator() indicator.title = "IP addresses for known C2 channel" indicator.description = "Bot connecting to control server" # Add IPs for C2 node addr = Address(address_value=content[item], category=Address.CAT_IPV4) addr.address_value.condition= "Equals" indicator.add_object(addr) # Relate Indicator and TTP indicator.add_indicated_ttp(TTP(idref=ttp.id_)) # Add Indicator to STIX PAckage stix_package.add_indicator(indicator) # Output to given file # The context manager is just to make the output look nicer by ignoring # warnings from to_xml() with warnings.catch_warnings(): warnings.simplefilter("ignore") stix_out = stix_package.to_xml() if args.outfile: fd = open(args.outfile,'w') fd.write(stix_out) else: print stix_out
def _export_multi_json(): from stix.core import STIXPackage, STIXHeader if jsonPattern is None: if streamFlag: #stream fullFileName = "cifStream" else: fullFileName = myJsonFile xmlFileName = outputFile else: fullFileName = jsonPath + myJsonFile + '.json' fileName = "stix_" + str(myJsonFile) xmlFileName = stixPath + fileName + '.xml' if testMode: print "-----------------File Name: -------- " + fullFileName print "xmlFileName: " + xmlFileName global log_string log_string = log_string + "\n\n" + str(datetime.datetime.now().time()) + ": fullFileName: " + fullFileName + "\n" log_string = log_string + str(datetime.datetime.now().time()) + ": xmlFileName: " + xmlFileName + "\n" wholeJson = _prepare_json(fullFileName) stix_package = STIXPackage() stix_header = STIXHeader() stix_header.description = "Search result from CIF with search parameter " + str(mySearchParam) stix_header.title = "Indicators from search by " + str(mySearchParam) stix_package.stix_header = stix_header stix_header.package_intent = "Purpose: mitigation" for x in wholeJson: indicatorIns = _export_from_json_to_xml(json.loads(x)) stix_package.add_indicator(indicatorIns) if streamFlag is False: f = open(xmlFileName, 'w') try: f.write(stix_package.to_xml()) finally: f.close() #if testMode: # print stix_package.to_xml() log_string = log_string + str(datetime.datetime.now().time()) + ": -------------- STIX----------- \n\n" + stix_package.to_xml() return stix_package.to_xml()
def generateEventPackage(event): package_name = namespace[1] + ':STIXPackage-' + event["Event"]["uuid"] stix_package = STIXPackage(id_=package_name) stix_header = STIXHeader() stix_header.title="MISP event #" + event["Event"]["id"] + " uuid: " + event["Event"]["uuid"] stix_header.package_intents="Threat Report" stix_package.stix_header = stix_header objects = generateSTIXObjects(event) incident = objects[0] ttps = objects[1] stix_package.add_incident(incident) for ttp in ttps: stix_package.add_ttp(ttp) return stix_package
def generateEventPackage(event): package_name = namespace[1] + ':STIXPackage-' + event["Event"]["uuid"] timestamp = getDateFromTimestamp(int(event["Event"]["timestamp"])) stix_package = STIXPackage(id_=package_name, timestamp=timestamp) stix_header = STIXHeader() stix_header.title=event["Event"]["info"] + " (MISP Event #" + event["Event"]["id"] + ")" stix_header.package_intents="Threat Report" stix_package.stix_header = stix_header objects = generateSTIXObjects(event) incident = objects[0] ttps = objects[1] stix_package.add_incident(incident) for ttp in ttps: stix_package.add_ttp(ttp) return stix_package
def generateEventPackage(event): package_name = namespace[1] + ":STIXPackage-" + event["Event"]["uuid"] timestamp = getDateFromTimestamp(int(event["Event"]["timestamp"])) stix_package = STIXPackage(id_=package_name, timestamp=timestamp) stix_header = STIXHeader() stix_header.title = event["Event"]["info"] + " (MISP Event #" + event["Event"]["id"] + ")" stix_header.package_intents = "Threat Report" stix_package.stix_header = stix_header objects = generateSTIXObjects(event) incident = objects[0] ttps = objects[1] stix_package.add_incident(incident) for ttp in ttps: stix_package.add_ttp(ttp) return stix_package
def generateEventPackage(self): package_name = "{}:STIXPackage-{}".format(namespace[1], self.misp_event.uuid) # timestamp = self.get_date_from_timestamp(int(str(self.misp_event.timestamp))) timestamp = self.misp_event.timestamp stix_package = STIXPackage(id_=package_name, timestamp=timestamp) stix_package.version = "1.1.1" stix_header = STIXHeader() stix_header.title = "Export from {} MISP".format(self.namespace_prefix) stix_header.package_intents = "Threat Report" stix_package.stix_header = stix_header incident = self.generate_stix_objects() stix_package.add_incident(incident) for ttp in self.ttps: stix_package.add_ttp(ttp) self.stix_package = stix_package
def test_utf16_roundtrip(self): sh = STIXHeader() sh.title = UNICODE_STR sp = STIXPackage() sp.stix_header = sh # serialize as utf-16 xml16 = sp.to_xml(encoding='utf-16') # deserialize as utf-16 sp2 = STIXPackage.from_xml(StringIO(xml16), encoding='utf-16') sh2 = sp2.stix_header # check that the titles align self.assertEqual(sh.title, sh2.title)
def test_utf16_roundtrip(self): sh = STIXHeader() sh.title = UNICODE_STR sp = STIXPackage() sp.stix_header = sh # serialize as utf-16 xml16 = sp.to_xml(encoding="utf-16") # deserialize as utf-16 sp2 = STIXPackage.from_xml(StringIO(xml16), encoding="utf-16") sh2 = sp2.stix_header # check that the titles align self.assertEqual(sh.title, sh2.title)
def genData_STIXHeader(data): from stix.core import STIXHeader #from stix.common.vocabs import PackageIntent objHdr = STIXHeader() objHdr.title = data['source']['stix.core.stix_header.STIXHeader.title'] objHdr.description = data['source'][ 'stix.core.stix_header.STIXHeader.description'] objHdr.package_intents = data['source'][ 'stix.core.stix_header.STIXHeader.package_intents'] objHdr.profiles = data['source'][ 'stix.core.stix_header.STIXHeader.profiles'] ### Define/Used outside this function # objHdr.handling = handling # objHdr.information_source = information_source return (objHdr)
def main(args): if len(args) < 4: sys.exit("Invalid parameters") baseURL = args[1] if not baseURL: baseURL = 'https://www.misp-project.org' orgname = args[2] namespace = [baseURL, orgname.replace(" ", "_")] namespace[1] = re.sub('[\W]+', '', namespace[1]) NS_DICT[namespace[0]] = namespace[1] try: idgen.set_id_namespace({baseURL: namespace[1]}) except ValueError: # Some weird stix error that sometimes occurs if the stars # align and Mixbox is being mean to us # Glory to STIX, peace and good xmlns be upon it try: idgen.set_id_namespace(Namespace(baseURL, namespace[1])) except TypeError: # Ok this only occurs if the script is being run under py3 # and if we're running a REALLY weird version of stix # May as well catch it idgen.set_id_namespace(Namespace(baseURL, namespace[1], "MISP")) stix_package = STIXPackage() stix_header = STIXHeader() stix_header.title = "Export from {} MISP".format(orgname) stix_header.package_intents = "Threat Report" stix_package.stix_header = stix_header stix_package.version = "1.1.1" stix_package.timestamp = datetime.datetime.now() if args[3] == 'json': stix_string = stix_package.to_json()[:-1] stix_string += ', "related_packages": [' else: stix_string = stix_package.to_xml(auto_namespace=False, ns_dict=NS_DICT, schemaloc_dict=SCHEMALOC_DICT) stix_string = stix_string.decode() stix_string = stix_string.replace("</stix:STIX_Package>\n", "") print(stix_string)
def gen_stix_indicator_sample( config, target=None, datatype=None, title="random test data", description="random test data", package_intents="Indicators - Watchlist", tlp_color="WHITE", observables_list=None, ): """generate sample stix data comprised of indicator_count indicators of type datatype""" # setup the xmlns... xmlns_url = config["edge"]["sites"][target]["stix"]["xmlns_url"] xmlns_name = config["edge"]["sites"][target]["stix"]["xmlns_name"] set_stix_id_namespace({xmlns_url: xmlns_name}) set_cybox_id_namespace(Namespace(xmlns_url, xmlns_name)) # construct a stix package... stix_package = STIXPackage() stix_header = STIXHeader() stix_header.title = title stix_header.description = description stix_header.package_intents = package_intents marking = MarkingSpecification() marking.controlled_structure = "../../../../descendant-or-self::node()" tlp_marking = TLPMarkingStructure() tlp_marking.color = tlp_color marking.marking_structures.append(tlp_marking) stix_package.stix_header = stix_header stix_package.stix_header.handling = Marking() stix_package.stix_header.handling.add_marking(marking) indicator_ = Indicator() indicator_.title = str(uuid.uuid4()) + "_sample_indicator" indicator_.confidence = "Unknown" indicator_.add_indicator_type("Malware Artifacts") observable_composition_ = ObservableComposition() observable_composition_.operator = indicator_.observable_composition_operator for observable_id in observables_list: observable_ = Observable() observable_.idref = observable_id observable_composition_.add(observable_) indicator_.observable = Observable() indicator_.observable.observable_composition = observable_composition_ stix_package.add_indicator(indicator_) return stix_package
def convert(self, stix_id_prefix='', published_only=True, **kw_arg): self.parse(**kw_arg) stix_packages = [] for event in self.events: if published_only: if not event.published: continue # id generator package_id = self.get_misp_pacakge_id(stix_id_prefix, event) stix_package = STIXPackage(timestamp=event.dt, id_=package_id) stix_header = STIXHeader() # set identity information identity = Identity(name=self.identity_name) information_source = InformationSource(identity=identity) stix_header.information_source = information_source tlp = None for tag in event.tags: if tag.tlp is not None: tlp = tag.tlp break if tlp is not None: # TLP for Generic format tlp_marking_structure = TLPMarkingStructure() tlp_marking_structure.color = tlp marking_specification = MarkingSpecification() marking_specification.marking_structures = tlp_marking_structure marking_specification.controlled_structure = '../../../../descendant-or-self::node() | ../../../../descendant-or-self::node()/@*' marking = Marking() marking.add_marking(marking_specification) stix_header.handling = marking stix_header.title = event.info stix_header.description = event.info stix_header.short_description = event.info for attribute in event.attributes: stix_package.add_indicator(attribute.convert()) stix_package.stix_header = stix_header stix_packages.append(stix_package) return stix_packages
def set_stix_header(self, threat_name, threat_descr, threat_source=None, reference=None): # Create a STIX Package hdr = STIXHeader() hdr.title = threat_name hdr.add_description(threat_descr) hdr.information_source = InformationSource() if threat_source is not None: hdr.information_source.description = threat_source if reference is not None: hdr.information_source.references = fields.TypedField(reference, References) # Set the produced time to now hdr.information_source.time = Time() hdr.information_source.time.produced_time = datetime.utcnow() self._pkg.stix_header = hdr
def wrap_maec(maec_package, file_name=None): """Wrap a MAEC Package in a STIX TTP/Package. Return the newly created STIX Package. Args: maec_package: the ``maec.package.package.Package`` instance to wrap in STIX. file_name: the name of the input file from which the MAEC Package originated, to be used in the Title of the STIX TTP that wraps the MAEC Package. Optional. Returns: A ``stix.STIXPackage`` instance with a single TTP that wraps the input MAEC Package. """ # Set the namespace to be used in the STIX Package stix.utils.set_id_namespace( {"https://github.com/MAECProject/maec-to-stix": "MAECtoSTIX"}) # Create the STIX MAEC Instance maec_malware_instance = MAECInstance() maec_malware_instance.maec = maec_package # Create the STIX TTP that includes the MAEC Instance ttp = TTP() ttp.behavior = Behavior() ttp.behavior.add_malware_instance(maec_malware_instance) # Create the STIX Package and add the TTP to it stix_package = STIXPackage() stix_package.add_ttp(ttp) # Create the STIX Header and add it to the Package stix_header = STIXHeader() if file_name: stix_header.title = "STIX TTP wrapper around MAEC file: " + str( file_name) stix_header.add_package_intent("Malware Characterization") # Add the Information Source to the STIX Header tool_info = ToolInformation() stix_header.information_source = InformationSource() tool_info.name = "MAEC to STIX" tool_info.version = str(maec_to_stix.__version__) stix_header.information_source.tools = ToolInformationList(tool_info) stix_package.stix_header = stix_header return stix_package
def gen_stix_indicator_sample(config, target=None, datatype=None, title='random test data', description='random test data', package_intents='Indicators - Watchlist', tlp_color='WHITE', observables_list=None): '''generate sample stix data comprised of indicator_count indicators of type datatype''' # setup the xmlns... xmlns_url = config['edge']['sites'][target]['stix']['xmlns_url'] xmlns_name = config['edge']['sites'][target]['stix']['xmlns_name'] set_stix_id_namespace({xmlns_url: xmlns_name}) set_cybox_id_namespace(Namespace(xmlns_url, xmlns_name)) # construct a stix package... stix_package = STIXPackage() stix_header = STIXHeader() stix_header.title = title stix_header.description = description stix_header.package_intents = package_intents marking = MarkingSpecification() marking.controlled_structure = '../../../../descendant-or-self::node()' tlp_marking = TLPMarkingStructure() tlp_marking.color = tlp_color marking.marking_structures.append(tlp_marking) stix_package.stix_header = stix_header stix_package.stix_header.handling = Marking() stix_package.stix_header.handling.add_marking(marking) indicator_ = Indicator() indicator_.title = str(uuid.uuid4()) + '_sample_indicator' indicator_.confidence = 'Unknown' indicator_.add_indicator_type('Malware Artifacts') observable_composition_ = ObservableComposition() observable_composition_.operator = \ indicator_.observable_composition_operator for observable_id in observables_list: observable_ = Observable() observable_.idref = observable_id observable_composition_.add(observable_) indicator_.observable = Observable() indicator_.observable.observable_composition = observable_composition_ stix_package.add_indicator(indicator_) return (stix_package)
def wrap_maec(maec_package, file_name=None): """Wrap a MAEC Package in a STIX TTP/Package. Return the newly created STIX Package. Args: maec_package: the ``maec.package.package.Package`` instance to wrap in STIX. file_name: the name of the input file from which the MAEC Package originated, to be used in the Title of the STIX TTP that wraps the MAEC Package. Optional. Returns: A ``stix.STIXPackage`` instance with a single TTP that wraps the input MAEC Package. """ # Set the namespace to be used in the STIX Package stix.utils.set_id_namespace({"https://github.com/MAECProject/maec-to-stix":"MAECtoSTIX"}) # Create the STIX MAEC Instance maec_malware_instance = MAECInstance() maec_malware_instance.maec = maec_package # Create the STIX TTP that includes the MAEC Instance ttp = TTP() ttp.behavior = Behavior() ttp.behavior.add_malware_instance(maec_malware_instance) # Create the STIX Package and add the TTP to it stix_package = STIXPackage() stix_package.add_ttp(ttp) # Create the STIX Header and add it to the Package stix_header = STIXHeader() if file_name: stix_header.title = "STIX TTP wrapper around MAEC file: " + str(file_name) stix_header.add_package_intent("Malware Characterization") # Add the Information Source to the STIX Header tool_info = ToolInformation() stix_header.information_source = InformationSource() tool_info.name = "MAEC to STIX" tool_info.version = str(maec_to_stix.__version__) stix_header.information_source.tools = ToolInformationList(tool_info) stix_package.stix_header = stix_header return stix_package
def gen_stix_indicator_sample(config, target=None, datatype=None, title='random test data', description='random test data', package_intents='Indicators - Watchlist', tlp_color='WHITE', observables_list=None): '''generate sample stix data comprised of indicator_count indicators of type datatype''' # setup the xmlns... xmlns_url = config['edge']['sites'][target]['stix']['xmlns_url'] xmlns_name = config['edge']['sites'][target]['stix']['xmlns_name'] set_stix_id_namespace({xmlns_url: xmlns_name}) set_cybox_id_namespace(Namespace(xmlns_url, xmlns_name)) # construct a stix package... stix_package = STIXPackage() stix_header = STIXHeader() stix_header.title = title stix_header.description = description stix_header.package_intents = package_intents marking = MarkingSpecification() marking.controlled_structure = '../../../../descendant-or-self::node()' tlp_marking = TLPMarkingStructure() tlp_marking.color = tlp_color marking.marking_structures.append(tlp_marking) stix_package.stix_header = stix_header stix_package.stix_header.handling = Marking() stix_package.stix_header.handling.add_marking(marking) indicator_ = Indicator() indicator_.title = str(uuid.uuid4()) + '_sample_indicator' indicator_.confidence = 'Unknown' indicator_.add_indicator_type('Malware Artifacts') observable_composition_ = ObservableComposition() observable_composition_.operator = \ indicator_.observable_composition_operator for observable_id in observables_list: observable_ = Observable() observable_.idref = observable_id observable_composition_.add(observable_) indicator_.observable = Observable() indicator_.observable.observable_composition = observable_composition_ stix_package.add_indicator(indicator_) return(stix_package)
def _create_stix_package(self): """Create and return a STIX Package with the basic information populated. Returns: A ``stix.STIXPackage`` object with a STIX Header that describes the intent of the package in terms of capturing malware artifacts, along with some associated metadata. """ stix_package = STIXPackage() stix_header = STIXHeader() stix_header.add_package_intent("Indicators - Malware Artifacts") if self.file_name: stix_header.title = "STIX Indicators extracted from MAEC file: " + str(self.file_name) # Add the Information Source to the STIX Header tool_info = ToolInformation() stix_header.information_source = InformationSource() tool_info.name = "MAEC to STIX" tool_info.version = str(__version__) stix_header.information_source.tools = ToolInformationList(tool_info) stix_package.stix_header = stix_header return stix_package
def main(args): if len(sys.argv) < 4: sys.exit("Invalid parameters") namespace = [sys.argv[1], sys.argv[2].replace(" ", "_")] namespace[1] = re.sub('[\W]+', '', namespace[1]) NS_DICT[namespace[0]] = namespace[1] stix.utils.idgen.set_id_namespace({namespace[0]: namespace[1]}) stix_package = STIXPackage() stix_header = STIXHeader() stix_header.title = "Export from " + sys.argv[2] + " MISP" stix_header.package_intents = "Threat Report" stix_package.stix_header = stix_header if sys.argv[3] == 'json': stix_string = stix_package.to_json()[:-1] stix_string += ', "related_packages": [' else: stix_string = stix_package.to_xml(auto_namespace=False, ns_dict=NS_DICT, schemaloc_dict=SCHEMALOC_DICT) stix_string = stix_string.replace("</stix:STIX_Package>\n", "") print(stix_string)
def alta_informacion(request): #""" #When in GET method return all the Content Blocks. #When in POST method, given a content binding id, a title, description and content we create a Content Block. #""" logger = logging.getLogger('TAXIIApplication.rest.views.alta_informacion') logger.debug('Entering alta_informacion') logger.debug(request.method) if request.method == 'GET': content = ContentBlock.objects.all() serializer = ContentBlockSerializer(content, many=True) return Response(serializer.data) elif request.method == 'POST': cont = request.DATA.get('content') c = StringIO.StringIO(cont) logger.debug(request.DATA.get('content_binding')) observables_obj = cybox_core_binding.parse(c) observables = Observables.from_obj(observables_obj) logger.debug(str(observables)) stix_package = STIXPackage() stix_header = STIXHeader() stix_header.description = request.DATA.get('description') stix_header.title = request.DATA.get('title') stix_package.stix_header = stix_header stix_package.add_observable(observables) content_binding = ContentBindingId.objects.get(id=1) cb = ContentBlock(title=request.DATA.get('title'), description=request.DATA.get('description') ,content_binding=content_binding, content=stix_package.to_xml()) cb.save() df = DataFeed.objects.get(name='default') df.content_blocks.add(cb) return Response(status=status.HTTP_201_CREATED)
def _create_stix_package(self): """Create and return a STIX Package with the basic information populated. Returns: A ``stix.STIXPackage`` object with a STIX Header that describes the intent of the package in terms of capturing malware artifacts, along with some associated metadata. """ stix_package = STIXPackage() stix_header = STIXHeader() stix_header.add_package_intent("Indicators - Malware Artifacts") if self.file_name: stix_header.title = "STIX Indicators extracted from MAEC file: " + str( self.file_name) # Add the Information Source to the STIX Header tool_info = ToolInformation() stix_header.information_source = InformationSource() tool_info.name = "MAEC to STIX" tool_info.version = str(__version__) stix_header.information_source.tools = ToolInformationList(tool_info) stix_package.stix_header = stix_header return stix_package
def stix_pkg(config, src, endpoint, payload, title='random test data', description='random test data', package_intents='Indicators - Watchlist', tlp_color='WHITE', dest=None): '''package observables''' # setup the xmlns... xmlns_url = config['edge']['sites'][dest]['stix']['xmlns_url'] xmlns_name = config['edge']['sites'][dest]['stix']['xmlns_name'] set_stix_id_namespace({xmlns_url: xmlns_name}) set_cybox_id_namespace(Namespace(xmlns_url, xmlns_name)) # construct a stix package... stix_package = STIXPackage() stix_header = STIXHeader() stix_header.title = title stix_header.description = description stix_header.package_intents = package_intents marking = MarkingSpecification() marking.controlled_structure = '../../../../descendant-or-self::node()' tlp_marking = TLPMarkingStructure() tlp_marking.color = tlp_color marking.marking_structures.append(tlp_marking) stix_package.stix_header = stix_header stix_package.stix_header.handling = Marking() stix_package.stix_header.handling.add_marking(marking) if isinstance(payload, Observable): stix_package.add_observable(payload) elif isinstance(payload, Indicator): stix_package.add_indicator(payload) elif isinstance(payload, Incident): stix_package.add_incident(payload) return (stix_package)
def test_to_xml_default_encoded(self): s = STIXHeader() s.title = UNICODE_STR xml = s.to_xml() self.assertTrue(UNICODE_STR in xml.decode('utf-8'))
def create_cybox_object(self, jdict, whitelist, config): listObservables = [] NS = cybox.utils.Namespace("cert.siemens.com", "siemens_cert") cybox.utils.set_id_namespace(NS) """ store information about malware binary that was analyzed """ if 'target' in jdict and 'category' in jdict['target'] and jdict['target']['category'] == 'file': log.debug("handling File information ...") main_file_object = self.__create_cybox_main_file(jdict['target']['file']) file_md5 = jdict['target']['file']['md5'] elif 'target' in jdict and 'category' in jdict['target'] and jdict['target']['category'] == 'url': log.warning("Not a file analysis report! URL reports not handled") return else: log.error("No target information in report ... skipping") return """ try to find email that dropped this attachment """ if config["attachemail"] or config["referenceemail"]: log.info("handling email attack vector information ...") email_object_properties, email_observables_list, email_stix_path_tuple_list = self.__check_malware_mailing_list(file_md5, log, config) if email_object_properties and len(email_object_properties)>0: for email_object in email_object_properties: main_file_object.add_related(email_object, "Contained_Within", inline=False) else: log.warning("failed linking mail object (no objects to link)") email_stix_path_tuple_list = [] else: email_object = None email_observables = [] email_stix_path_tuple_list = [] """ store extended information about malware file """ if 'static' in jdict: log.debug("handling extended File information ...") win_executable_extension = self.__create_cybox_win_executable(jdict['target']['file'], jdict['static']) if win_executable_extension: main_file_object.add_related(win_executable_extension, "Characterized_By", inline=False) win_executable_extension = [win_executable_extension] else: log.warning("No extended File information found") win_executable_extension = [] """ store domains connected to """ if 'network' in jdict and 'domains' in jdict['network']: log.debug("handling Domain information ...") domains, addresses = self.__create_cybox_domains(jdict['network']['domains'], whitelist) for dom in domains: main_file_object.add_related(dom, 'Connected_To', inline=False) else: domains = [] addresses = [] """ store http session information """ if 'network' in jdict and 'http' in jdict['network']: log.debug("handling HTTP information ...") http_requests = self.__create_cybox_https(jdict['network']['http'], whitelist) for session in http_requests: main_file_object.add_related(session, 'Connected_To', inline=False) else: http_requests = [] """ store dns queries information about the malware """ if 'network' in jdict and 'dns' in jdict['network']: log.debug("handling DNS information ...") queries = self.__create_cybox_dns_queries(jdict['network']['dns'], whitelist) for query in queries: main_file_object.add_related(query, 'Connected_To', inline=False) else: queries = [] """ store information about dropped files """ if 'dropped' in jdict: log.debug('handling dropped files ...') dropped = self.__create_cybox_dropped_files(jdict['dropped'], jdict['target']['file']['sha256']) for drop in dropped: main_file_object.add_related(drop, 'Dropped', inline=False) else: dropped = [] """ store virustotal information """ if 'virustotal' in jdict and 'positives' in jdict['virustotal']: log.debug('handling virustotal information ...') vtInformationTools = self.__create_stix_virustotal(jdict['virustotal'], log, config) vtFound = True else: vtInformationTools = [] vtFound = False """ create observables """ if config["attachemail"] and len(email_observables)>0: obs = Observables([main_file_object]+email_observables+win_executable_extension+domains+addresses+http_requests+dropped+queries) else: obs = Observables([main_file_object]+win_executable_extension+domains+addresses+http_requests+dropped+queries) """ generate stix id with siemens namespace """ if config: stix_id_generator = stix.utils.IDGenerator(namespace={config["xmlns"]: config["namespace"]}) else: stix_id_generator = stix.utils.IDGenerator(namespace={"cert.siemens.com": "siemens_cert"}) """ create stix package """ stix_id = stix_id_generator.create_id() stix_package = STIXPackage(observables=obs, id_=stix_id) stix_header = STIXHeader() stix_header.title = "Analysis report: %s" % (str(main_file_object.file_name).decode('utf8', errors='xmlcharrefreplace')) if 'info' in jdict and 'started' in jdict['info']: sandbox_report_date = dateparser.parse(jdict['info']['started']+' CET').isoformat() else: sandbox_report_date = datetime.datetime.now(pytz.timezone('Europe/Berlin')).isoformat() stix_header.description = 'Summarized analysis results for file "%s" with MD5 hash "%s" created on %s.' % (str(main_file_object.file_name).decode('utf8', errors='xmlcharrefreplace'), main_file_object.hashes.md5, sandbox_report_date) stix_header.add_package_intent("Malware Characterization") """ create markings """ spec = MarkingSpecification() spec.idref = stix_id spec.controlled_structure = "//node()" tlpmark = TLPMarkingStructure() if config: if not vtFound: tlpmark.color = config["color"] else: tlpmark.color = "GREEN" elif vtFound: tlpmark.color = "GREEN" else: tlpmark.color = "AMBER" spec.marking_structure = [tlpmark] """ attach to header """ stix_header.handling = Marking([spec]) stix_information_source = InformationSource() stix_information_source.time = Time(produced_time=sandbox_report_date) stix_information_source.tools = ToolInformationList([ToolInformation(tool_name="SIEMENS-ANALYSIS-TOOL-ID-12", tool_vendor="ANALYSIS-ID: %s" % (jdict['info']['id']))]+vtInformationTools) stix_header.information_source = stix_information_source stix_package.stix_header = stix_header """ write result xml file """ xml_file_name = "stix-%s-malware-report.xml" % (file_md5) xml_report_file_path = os.path.join(self.reports_path, xml_file_name) fp = open(xml_report_file_path, 'w') if config: fp.write(stix_package.to_xml(ns_dict={config["xmlns"]: config["namespace"]})) else: fp.write(stix_package.to_xml(ns_dict={'cert.siemens.com': 'siemens_cert'})) fp.close() if config["copytoshare"]: self.__copy_xml_to_ti_share(xml_report_file_path, xml_file_name, config) for item in email_stix_path_tuple_list: self.__copy_xml_to_ti_share(item[0], item[1], config, "email") else: log.warning("copy to TI share is disabled: %s" % (config["copytoshare"])) return
def genStixDoc( outputDir_, targetFileSha1_, targetFileSha256_, targetFileSha512_, targetFileSsdeep_, targetFileMd5_, targetFileSize_, targetFileName_, ipv4Addresses_, hostNames_): """ Generate Stix document from the input values. The doc structure is the file object along with the related network items: addresses, domain names. Output is written to files, which are then wrapped with taxii and uploaded using a separate script. """ parsedTargetFileName = reFileName(targetFileName_)[1] parsedTargetFilePrefix = reFileName(targetFileName_)[0] stix.utils.set_id_namespace({"http://www.equifax.com/cuckoo2Stix" : "cuckoo2Stix"}) NS = cybox.utils.Namespace("http://www.equifax.com/cuckoo2Stix", "cuckoo2Stix") cybox.utils.set_id_namespace(NS) stix_package = STIXPackage() stix_header = STIXHeader() stix_header.title = 'File: ' + parsedTargetFileName + ' with the associated hashes, network indicators' stix_header.description = 'File: ' + parsedTargetFileName + ' with the associated hashes, network indicators' stix_package.stix_header = stix_header # Create the ttp malware_instance = MalwareInstance() malware_instance.add_name(parsedTargetFileName) malware_instance.description = targetFileSha1_ ttp = TTP(title='TTP: ' + parsedTargetFileName) ttp.behavior = Behavior() ttp.behavior.add_malware_instance(malware_instance) stix_package.add_ttp(ttp) # Create the indicator for the ipv4 addresses ipv4Object = Address(ipv4Addresses_, Address.CAT_IPV4) ipv4Object.condition = 'Equals' ipv4Indicator = Indicator() ipv4Indicator.title = parsedTargetFileName + ': ipv4 addresses' ipv4Indicator.add_indicator_type('IP Watchlist') ipv4Indicator.add_indicated_ttp(RelatedTTP(TTP(idref=ttp.id_), relationship='Indicates Malware')) ipv4Indicator.observable = ipv4Object ipv4Indicator.confidence = 'Low' # Create the indicator for the domain names domainNameObject = DomainName() domainNameObject.value = hostNames_ domainNameObject.condition = 'Equals' domainNameIndicator = Indicator() domainNameIndicator.title = parsedTargetFileName + ': domain names' domainNameIndicator.add_indicator_type('Domain Watchlist') domainNameIndicator.add_indicated_ttp(RelatedTTP(TTP(idref=ttp.id_), relationship='Indicates Malware')) domainNameIndicator.observable = domainNameObject domainNameIndicator.confidence = 'Low' # Create the indicator for the file fileObject = File() fileObject.file_name = parsedTargetFileName fileObject.file_name.condition = 'Equals' fileObject.size_in_bytes = targetFileSize_ fileObject.size_in_bytes.condition = 'Equals' fileObject.add_hash(Hash(targetFileSha1_, type_='SHA1', exact=True)) fileObject.add_hash(Hash(targetFileSha256_, type_='SHA256', exact=True)) fileObject.add_hash(Hash(targetFileSha512_, type_='SHA512', exact=True)) fileObject.add_hash(Hash(targetFileSsdeep_, type_='SSDEEP', exact=True)) fileObject.add_hash(Hash(targetFileMd5_, type_='MD5', exact=True)) fileIndicator = Indicator() fileIndicator.title = parsedTargetFileName + ': hashes' fileIndicator.description = parsedTargetFilePrefix fileIndicator.add_indicator_type('File Hash Watchlist') fileIndicator.add_indicated_ttp(RelatedTTP(TTP(idref=ttp.id_), relationship="Indicates Malware")) fileIndicator.observable = fileObject fileIndicator.confidence = 'Low' stix_package.indicators = [fileIndicator, ipv4Indicator, domainNameIndicator] stagedStixDoc = stix_package.to_xml() stagedStixDoc = fixAddressObject(stagedStixDoc) stagedStixDoc = fixDomainObject(stagedStixDoc) today = datetime.datetime.now() now = today.strftime('%Y-%m-%d_%H%M%S') if not os.path.exists(outputDir_): os.makedirs(outputDir_) with open (outputDir_ + '/' + now + '-' + targetFileSha1_ + '.stix.xml', 'a') as myfile: myfile.write(stagedStixDoc) _l.debug('Wrote file: ' + now + '-' + targetFileSha1_ + '.stix.xml') return
def adptr_dict2STIX(srcObj, data): sTxt = "Called... " sndMSG(sTxt, 'INFO', 'adptr_dict2STIX()') stixObj = None ### Input Check if srcObj == None or data == None: #TODO: Needs error msg: Missing srcData Object return (False) ### Generate NameSpace id tags STIX_NAMESPACE = {"http://hailataxii.com": "opensource"} OBS_NAMESPACE = Namespace("http://hailataxii.com", "opensource") stix_set_id_namespace(STIX_NAMESPACE) obs_set_id_namespace(OBS_NAMESPACE) ### Building STIX Wrapper stix_package = STIXPackage() objIndicator = Indicator() ### Bulid Object Data for sKey in data: objIndicator = Indicator() listOBS = [] ### Parsing IP Address sAddr = data[sKey]['attrib']['ipAddr'] if len(sAddr) > 0: objAddr = Address() objAddr.is_source = True objAddr.address_value = sAddr objAddr.address_value.condition = 'Equals' if isIPv4(sAddr): objAddr.category = 'ipv4-addr' elif isIPv6(sAddr): objAddr.category = 'ipv6-addr' else: continue obsAddr = Observable(objAddr) objAddr = None obsAddr.sighting_count = 1 obsAddr.title = 'IP: ' + sAddr sDscrpt = 'IPv4' + ': ' + sAddr + " | " sDscrpt += "isSource: True | " obsAddr.description = "<![CDATA[" + sDscrpt + "]]>" listOBS.append(obsAddr) obsAddr = None objIndicator.add_indicator_type("IP Watchlist") ### Parsing Domain sDomain = data[sKey]['attrib']['domain'] if len(sDomain) > 0: objDomain = DomainName() objDomain.value = sDomain objDomain.value.condition = 'Equals' if isFQDN(sDomain): objDomain.type = 'FQDN' elif isTLD(sDomain): objDomain.type = 'TLD' else: continue obsDomain = Observable(objDomain) objDomain = None obsDomain.sighting_count = 1 obsDomain.title = 'Domain: ' + sDomain sDscrpt = 'Domain: ' + sDomain + " | " sDscrpt += "isFQDN: True | " obsDomain.description = "<![CDATA[" + sDscrpt + "]]>" listOBS.append(obsDomain) obsDomain = None objIndicator.add_indicator_type("Domain Watchlist") #Parser URI sURI = data[sKey]['attrib']['URI'] if len(sURI) > 0: objURI = URI() objURI.value = sURI objURI.value.condition = 'Equals' objURI.type_ = URI.TYPE_URL obsURI = Observable(objURI) objURI = None obsURI.sighting_count = 1 obsURI.title = 'URI: ' + sURI sDscrpt = 'URI: ' + sURI + " | " sDscrpt += "Type: URL | " obsURI.description = "<![CDATA[" + sDscrpt + "]]>" listOBS.append(obsURI) obsURI = None objIndicator.add_indicator_type("URL Watchlist") #Parser File Hash sHash = data[sKey]['attrib']['hash'] if len(sHash) > 0: objFile = File() sFileName = data[sKey]['attrib']['fileName'] if len(sFileName) > 0: objFile.file_name = sFileName objFile.file_format = sFileName.split('.')[1] objFile.add_hash(Hash(sHash, exact=True)) obsFile = Observable(objFile) objFile = None obsFile.sighting_count = 1 obsFile.title = 'File: ' + sFileName sDscrpt = 'FileName: ' + sFileName + " | " sDscrpt += "FileHash: " + sHash + " | " obsFile.description = "<![CDATA[" + sDscrpt + "]]>" listOBS.append(obsFile) obsFile = None objIndicator.add_indicator_type("File Hash Watchlist") ### Add Generated observable to Indicator objIndicator.observables = listOBS objIndicator.observable_composition_operator = 'OR' #Parsing Producer sProducer = srcObj.Domain if len(sProducer) > 0: objIndicator.set_producer_identity(sProducer) objIndicator.set_produced_time(data[sKey]['attrib']['dateVF']) objIndicator.set_received_time(data[sKey]['dateDL']) ### Old Title / Description Generator #objIndicator.title = data[sKey]['attrib']['title']; #objIndicator.description = "<![CDATA[" + data[sKey]['attrib']['dscrpt'] + "]]>"; ### Generate Indicator Title based on availbe data sTitle = 'ZeuS Tracker (' + data[sKey]['attrib'][ 'status'] + ')| ' + data[sKey]['attrib']['title'] if len(sAddr) > 0: sAddLine = "This IP address has been identified as malicious" if len(sDomain) > 0: sAddLine = "This domain has been identified as malicious" if len(sAddLine) > 0: sTitle = sTitle + " | " + sAddLine if len(srcObj.Domain) > 0: sTitle = sTitle + " by " + srcObj.Domain else: sTitle = sTitle + "." if len(sTitle) > 0: objIndicator.title = sTitle #Generate Indicator Description based on availbe data sDscrpt = "" if len(sAddr) > 0: sAddLine = "This IP address " + sAddr if len(sDomain) > 0: sAddLine = "This domain " + sDomain if len(sAddr) > 0 and len(sDomain) > 0: sAddLine = "This domain " + sDomain + " (" + sAddr + ")" if len(sAddLine) > 0: sDscrpt = sDscrpt + sAddLine sDscrpt = sDscrpt + " has been identified as malicious" if len(srcObj.Domain) > 0: sDscrpt = sDscrpt + " by " + srcObj.Domain else: sDscrpt = sDscrpt + "." sDscrpt = sDscrpt + ". For more detailed infomation about this indicator go to [CAUTION!!Read-URL-Before-Click] [" + data[ sKey]['attrib']['link'] + "]." if len(sDscrpt) > 0: objIndicator.description = "<![CDATA[" + sDscrpt + "]]>" #Parse TTP objMalware = MalwareInstance() objMalware.add_name("ZeuS") objMalware.add_name("Zbot") objMalware.add_name("Zeus") objMalware.add_type("Remote Access Trojan") objMalware.short_description = "Zeus, ZeuS, or Zbot is Trojan horse computer malware effects Microsoft Windows operating system" objMalware.description = "Zeus, ZeuS, or Zbot is Trojan horse computer malware that runs on computers running under versions of the Microsoft Windows operating system. While it is capable of being used to carry out many malicious and criminal tasks, it is often used to steal banking information by man-in-the-browser keystroke logging and form grabbing. It is also used to install the CryptoLocker ransomware.[1] Zeus is spread mainly through drive-by downloads and phishing schemes. (2014(http://en.wikipedia.org/wiki/Zeus_%28Trojan_horse%29))" objTTP = TTP(title="ZeuS") objTTP.behavior = Behavior() objTTP.behavior.add_malware_instance(objMalware) objIndicator.add_indicated_ttp(objTTP) #objIndicator.add_indicated_ttp(TTP(idref=objTTP.id_)) #stix_package.add_ttp(objTTP) stix_package.add_indicator(objIndicator) objIndicator = None ### STIX Package Meta Data stix_header = STIXHeader() stix_header.title = srcObj.pkgTitle stix_header.description = "<![CDATA[" + srcObj.pkgDscrpt + "]]>" ### Understanding markings http://stixproject.github.io/idioms/features/data-markings/ marking_specification = MarkingSpecification() classLevel = SimpleMarkingStructure() classLevel.statement = "Unclassified (Public)" marking_specification.marking_structures.append(classLevel) objTOU = TermsOfUseMarkingStructure() sTOU = open('tou.txt').read() objTOU.terms_of_use = sProducer + " | " + sTOU marking_specification.marking_structures.append(objTOU) tlp = TLPMarkingStructure() tlp.color = "WHITE" marking_specification.marking_structures.append(tlp) marking_specification.controlled_structure = "//node()" handling = Marking() handling.add_marking(marking_specification) stix_header.handling = handling stix_package.stix_header = stix_header stix_header = None ### Generate STIX XML File locSTIXFile = 'STIX_' + srcObj.fileName.split('.')[0] + '.xml' sndFile(stix_package.to_xml(), locSTIXFile) return (stix_package)
def main(): # get args parser = argparse.ArgumentParser ( description = "Parse a given CSV and output STIX XML" , formatter_class=argparse.ArgumentDefaultsHelpFormatter ) parser.add_argument("--infile","-f", help="input CSV", default = "in.csv") args = parser.parse_args() # setup header contain_pkg = STIXPackage() stix_header = STIXHeader() stix_header.title = "Indicators" stix_header.add_package_intent ("Indicators") # XXX add Information_Source and Handling contain_pkg.stix_header = stix_header # create kill chain with three options (pre, post, unknown), relate as needed pre = KillChainPhase(phase_id="stix:KillChainPhase-1a3c67f7-5623-4621-8d67-74963d1c5fee", name="Pre-infection indicator", ordinality=1) post = KillChainPhase(phase_id="stix:KillChainPhase-d5459305-1a27-4f50-9875-23793d75e4fe", name="Post-infection indicator", ordinality=2) chain = KillChain(id_="stix:KillChain-3fbfebf2-25a7-47b9-ad8b-3f65e56e402d", name="Degenerate Cyber Kill Chain" ) chain.definer = "U5" chain.kill_chain_phases = [pre, post] contain_pkg.ttps.kill_chains.append(chain) # read input data fd = open (args.infile, "rb") infile = csv.DictReader(fd) for row in infile: # create indicator for each row error = False ind = Indicator() ind.add_alternative_id(row['ControlGroupID']) ind.title = "Indicator with ID " + row['IndicatorID'] ind.description = row['Notes'] ind.producer = InformationSource() ind.producer.description = row['Reference'] # XXX unknown purpose for 'Malware' field - omitted # if the field denotes a specific malware family, we might relate as 'Malware TTP' to the indicator # set chain phase if 'Pre' in row['Infection Type']: ind.kill_chain_phases.append(KillChainPhaseReference(phase_id="stix:KillChainPhase-1a3c67f7-5623-4621-8d67-74963d1c5fee",kill_chain_id="stix:KillChain-3fbfebf2-25a7-47b9-ad8b-3f65e56e402d")) elif 'Post' in row['Infection Type']: ind.kill_chain_phases.append(KillChainPhaseReference(phase_id="stix:KillChainPhase-1a3c67f7-5623-4621-8d67-74963d1c5fee",kill_chain_id="stix:KillChain-3fbfebf2-25a7-47b9-ad8b-3f65e56e402d")) ind_type = row['Indicator Type'] if 'IP' in ind_type: ind.add_indicator_type( "IP Watchlist") ind_obj = SocketAddress() ind_obj.ip_address = row['Indicator'] ind_obj.ip_address.condition= "Equals" if row['indValue']: port = Port() # pull port out, since it's in form "TCP Port 42" port.port_value = row['indValue'].split()[-1] port.layer4_protocol = row['indValue'].split()[0] port.port_value.condition= "Equals" ind_obj.port = port elif 'Domain' in ind_type: ind.add_indicator_type ("Domain Watchlist") ind_obj = DomainName() ind_obj.value = row['Indicator'] ind_obj.value.condition= "Equals" elif 'Email' in ind_type: # parse out which part of the email is being # i.e. "Sender: attach | Subject: whatever" tag = row['Indicator'].split(':')[0] val = row['Indicator'].split(':')[1] ind.add_indicator_type ("Malicious E-mail") ind_obj = EmailMessage() if "Subject" in tag: ind_obj.subject = val ind_obj.subject.condition= "Equals" elif "Sender" in tag: ind_obj.sender = val ind_obj.sender.condition= "Equals" elif "Attachment" in tag: # make inline File to store filename file_obj = File() file_obj.id_ = cybox.utils.create_id(prefix="File") file_obj.file_name = val file_obj.file_name.condition = "Equals" ind_obj.add_related(file_obj, "Contains") attach = Attachments() attach.append(file_obj.id_) ind_obj.attachments = attach elif 'User Agent' in ind_type: ind.add_indicator_type( VocabString(row['Indicator Type'])) fields = HTTPRequestHeaderFields() fields.user_agent = row['Indicator'] fields.user_agent.condition = "Equals" header = HTTPRequestHeader() header.parsed_header = fields thing = HTTPRequestResponse() thing.http_client_request = HTTPClientRequest() thing.http_client_request.http_request_header = header ind_obj = HTTPSession() ind_obj.http_request_response = [thing] elif 'URI' in ind_type: ind.add_indicator_type( VocabString(row['Indicator Type'])) thing = HTTPRequestResponse() thing.http_client_request = HTTPClientRequest() thing.http_client_request.http_request_line = HTTPRequestLine() thing.http_client_request.http_request_line.http_method = row['Indicator'].split()[0] thing.http_client_request.http_request_line.http_method.condition = "Equals" thing.http_client_request.http_request_line.value = row['Indicator'].split()[1] thing.http_client_request.http_request_line.value.condition = "Equals" ind_obj = HTTPSession() ind_obj.http_request_response = [thing] elif 'File' in ind_type: ind.add_indicator_type( VocabString(row['Indicator Type'])) ind_obj = File() ind_obj.file_name = row['Indicator'] ind_obj.file_name.condition = "Equals" digest = Hash() # XXX assumes that hash digests are stored in this field in real data digest.simple_hash_value = row['indValue'].strip() digest.simple_hash_value.condition = "Equals" digest.type_.condition = "Equals" ind_obj.add_hash(digest) elif 'Registry' in ind_type: ind.add_indicator_type( VocabString(row['Indicator Type'])) ind_obj = WinRegistryKey() keys = RegistryValues() key = RegistryValue() key.name = row['Indicator'] key.name.condition = "Equals" key.data = row['indValue'] key.data.condition = "Equals" keys.append(key) ind_obj.values = keys elif 'Mutex' in ind_type: ind.add_indicator_type (VocabString(row['Indicator Type'])) ind_obj = Mutex() ind_obj.name = row['Indicator'] ind_obj.name.condition= "Equals" else: print "ERR type not supported: " + ind_type + " <- will be omitted from output" error = True # finalize indicator if not error: ind.add_object(ind_obj) contain_pkg.add_indicator(ind) # DONE looping print contain_pkg.to_xml()
def adptr_dict2STIX(srcObj, data): sTxt = "Called... " sndMSG(sTxt, 'INFO', 'adptr_dict2STIX()') stixObj = None ### Input Check if srcObj == None or data == None: #TODO: Needs error msg: Missing srcData Object return (False) ### Generate NameSpace id tags STIX_NAMESPACE = {"http://hailataxii.com": "opensource"} OBS_NAMESPACE = Namespace("http://hailataxii.com", "opensource") stix_set_id_namespace(STIX_NAMESPACE) obs_set_id_namespace(OBS_NAMESPACE) ### Building STIX Wrapper stix_package = STIXPackage() objIndicator = Indicator() ### Bulid Object Data for sKey in data: objIndicator = Indicator() listOBS = [] ### Parsing Domain sDomain = data[sKey]['attrib']['domain'] if len(sDomain) > 0: objDomain = DomainName() objDomain.value = sDomain objDomain.value.condition = 'Equals' if isFQDN(sDomain): objDomain.type = 'FQDN' elif isTLD(sDomain): objDomain.type = 'TLD' else: continue obsDomain = Observable(objDomain) objDomain = None obsDomain.sighting_count = 1 obsDomain.title = 'Domain: ' + sDomain sDscrpt = 'Domain: ' + sDomain + " | " sDscrpt += "isFQDN: True | " obsDomain.description = "<![CDATA[" + sDscrpt + "]]>" listOBS.append(obsDomain) obsDomain = None objIndicator.add_indicator_type("Domain Watchlist") ### Add Generated observable to Indicator objIndicator.observable_composition_operator = 'OR' objIndicator.observables = listOBS #Parsing Producer infoSrc = InformationSource(identity=Identity(name=srcObj.Domain)) infoSrc.add_contributing_source(data[sKey]['attrib']['ref']) if len(srcObj.Domain) > 0: objIndicator.producer = infoSrc if data[sKey]['attrib']['lstDateVF']: objIndicator.set_produced_time( data[sKey]['attrib']['lstDateVF'][0]) objIndicator.set_received_time(data[sKey]['dateDL']) ### Generate Indicator Title based on availbe data lstContainng = [] lstIs = [] sTitle = 'This domain ' + data[sKey]['attrib'][ 'domain'] + ' has been identified as malicious' if len(data[sKey]['attrib']['ref']): sTitle += ' by ' + data[sKey]['attrib']['ref'] if len(data[sKey]['attrib']['type']) > 0: sTitle += ', via this vector [' + data[sKey]['attrib'][ 'type'] + '].' else: sTitle += '.' objIndicator.title = sTitle ### Generate Indicator Description based on availbe data sDscrpt = 'Lehigh.edu site has added this domain ' + data[sKey][ 'attrib']['domain'] sDscrpt += ' to recommend block list.' sDscrpt += ' This site has been identified as malicious' sDscrpt += ' by ' + data[sKey]['attrib']['ref'] sDscrpt += ' and was still attive on the following dates ' + str( data[sKey]['attrib']['lstDateVF']) + "." objIndicator.description = "<![CDATA[" + sDscrpt + "]]>" #Parse TTP objMalware = MalwareInstance() objMalware.add_type("Remote Access Trojan") ttpTitle = data[sKey]['attrib']['type'] objTTP = TTP(title=ttpTitle) objTTP.behavior = Behavior() objTTP.behavior.add_malware_instance(objMalware) objIndicator.add_indicated_ttp(objTTP) #objIndicator.add_indicated_ttp(TTP(idref=objTTP.id_)) #stix_package.add_ttp(objTTP) stix_package.add_indicator(objIndicator) objIndicator = None ### STIX Package Meta Data stix_header = STIXHeader() stix_header.title = srcObj.pkgTitle stix_header.description = "<![CDATA[" + srcObj.pkgDscrpt + "]]>" ### Understanding markings http://stixproject.github.io/idioms/features/data-markings/ marking_specification = MarkingSpecification() classLevel = SimpleMarkingStructure() classLevel.statement = "Unclassified (Public)" marking_specification.marking_structures.append(classLevel) tlp = TLPMarkingStructure() tlp.color = "WHITE" marking_specification.marking_structures.append(tlp) marking_specification.controlled_structure = "//node()" objTOU = TermsOfUseMarkingStructure() sTOU = open('tou.txt').read() objTOU.terms_of_use = srcObj.Domain + " | " + sTOU marking_specification.marking_structures.append(objTOU) handling = Marking() handling.add_marking(marking_specification) stix_header.handling = handling stix_package.stix_header = stix_header stix_header = None ### Generate STIX XML File locSTIXFile = 'STIX_' + srcObj.fileName.split('.')[0] + '.xml' sndFile(stix_package.to_xml(), locSTIXFile) return (stix_package)
def adptr_dict2STIX(srcObj, data): sTxt = "Called... " sndMSG(sTxt, 'INFO', 'adptr_dict2STIX()') stixObj = None ### Input Check if srcObj == None or data == None: #TODO: Needs error msg: Missing srcData Object return (False) ### Generate NameSpace id tags STIX_NAMESPACE = {"http://hailataxii.com": "opensource"} OBS_NAMESPACE = Namespace("http://hailataxii.com", "opensource") stix_set_id_namespace(STIX_NAMESPACE) obs_set_id_namespace(OBS_NAMESPACE) ### Building STIX Wrapper stix_package = STIXPackage() objIndicator = Indicator() ### Bulid Object Data for sKey in data: objIndicator = Indicator() listOBS = [] oObsSrcData = genObsSrcData(srcObj, data[sKey]) ### Parsing IP Address sAddr = sKey if len(sAddr) > 0: objAddr = Address() objAddr.is_source = True objAddr.address_value = sAddr objAddr.address_value.condition = 'InclusiveBetween' objAddr.category = 'ipv4-net' obsAddr = Observable(objAddr) objAddr = None obsAddr.sighting_count = int(data[sKey]['attrib']['Attacks']) oObsSrcData.sighting_count = int(data[sKey]['attrib']['Attacks']) obsAddr.observable_source.append(oObsSrcData) sTitle = 'NETWORK_range: ' + sAddr obsAddr.title = sTitle sDscpt = 'ipv4-net' + ': ' + sAddr + " | " sDscpt += "is_source: True | " sDscpt += "Attack_Count: " + data[sKey]['attrib']['Attacks'] + " | " sDscpt += "Attack_DateRange: " + data[sKey]['attrib'][ 'dateRange'] + " | " obsAddr.description = sDscpt listOBS.append(obsAddr) obsAddr = None ### Parsing Registrar Information if data[sKey]['attrib']['email']: objEmail = EmailAddress() objEmail.address_value = data[sKey]['attrib']['email'] objEmail.address_value.condition = 'Equals' objEmail.category = 'e-mail' objWhoisReg = WhoisRegistrar() if len(data[sKey]['attrib']['Name']) > 1: objWhoisReg.name = data[sKey]['attrib']['Name'] objWhoisReg.email_address = objEmail objEmail = None objWhois = WhoisEntry() objWhois.registrar_info = objWhoisReg obsWhois = Observable(objWhois) #print obsWhois.id_ objWhois = None obsWhois.sighting_count = 1 sTitle = 'REGISTRAR_email: ' + data[sKey]['attrib']['email'] if len(data[sKey]['attrib']['Name']) > 0: sTitle += " | REGISTRAR_name: " + data[sKey]['attrib'][ 'Name'] + " | " obsWhois.title = sTitle obsWhois.description = sTitle listOBS.append(obsWhois) obsWhois = None sDscrpt = None sCntry_code = None sCntry_name = None sRgstra_email = None sRgstra_name = None if len(data[sKey]['attrib']['Country']) > 0: sCntry_code = data[sKey]['attrib']['Country'] if sCntry_code in dictCC2CN: sCntry_name = dictCC2CN[sCntry_code] if 'email' in data[sKey]['attrib']: sRgstra_email = data[sKey]['attrib']['email'] if len(data[sKey]['attrib']['Name']) > 0: sRgstra_name = data[sKey]['attrib']['Name'] sDscrpt = "This IP block appears to have " if sCntry_code: sDscrpt += "originated in " + sCntry_code if sCntry_name: sDscrpt += "(" + sCntry_name + ")" if sCntry_code and (sRgstra_email or sRgstra_name): sDscrpt += " and is " if sRgstra_email: sDscrpt += "register to " + sRgstra_email if sRgstra_email and sRgstra_name: sDscrpt += " of " + sRgstra_name elif sRgstra_name: sDscrpt += "register to " + sRgstra_name sDscrpt += "." if sCntry_code or sRgstra_email or sRgstra_name: objIndicator.description = "<![CDATA[" + sDscrpt + "]]>" objIndicator.title = sAddr.replace('##comma##', ' - ') + " | " + srcObj.pkgTitle ### Add Generated observable to Indicator objIndicator.add_indicator_type("IP Watchlist") objIndicator.observable_composition_operator = 'OR' objIndicator.observables = listOBS #Parsing Producer sProducer = srcObj.Domain if len(sProducer) > 0: objIndicator.set_producer_identity(sProducer) objIndicator.set_produced_time(data[sKey]['attrib']['dateVF']) objIndicator.set_received_time(data[sKey]['dateDL']) stix_package.add_indicator(objIndicator) objIndicator = None ### STIX Package Meta Data stix_header = STIXHeader() stix_header.title = srcObj.pkgTitle stix_header.description = "<![CDATA[" + srcObj.pkgDscrpt + "]]>" ### Understanding markings http://stixproject.github.io/idioms/features/data-markings/ marking_specification = MarkingSpecification() classLevel = SimpleMarkingStructure() classLevel.statement = "Unclassified (Public)" marking_specification.marking_structures.append(classLevel) objTOU = TermsOfUseMarkingStructure() #sTOU = open('tou.txt').read() objTOU.terms_of_use = sProducer + " | " + srcObj.srcTOU marking_specification.marking_structures.append(objTOU) tlp = TLPMarkingStructure() tlp.color = "WHITE" marking_specification.marking_structures.append(tlp) marking_specification.controlled_structure = "//node()" handling = Marking() handling.add_marking(marking_specification) stix_header.handling = handling stix_package.stix_header = stix_header stix_header = None ### Generate STIX XML File locSTIXFile = 'STIX_' + srcObj.fileName.split('.')[0] + '.xml' sndFile(stix_package.to_xml(), locSTIXFile) return (stix_package)
def stix_header(title): if title: stix_hdr = STIXHeader() stix_hdr.title = title return stix_hdr return None
def adptr_dict2STIX(srcObj, data): sTxt = "Called... " sndMSG(sTxt, 'INFO', 'adptr_dict2STIX()') stixObj = None ### Input Check if srcObj == None or data == None: #TODO: Needs error msg: Missing srcData Object return (False) ### Generate NameSpace id tags STIX_NAMESPACE = {"http://hailataxii.com": "opensource"} OBS_NAMESPACE = Namespace("http://hailataxii.com", "opensource") stix_set_id_namespace(STIX_NAMESPACE) obs_set_id_namespace(OBS_NAMESPACE) ### Building STIX Wrapper stix_package = STIXPackage() objIndicator = Indicator() ### Bulid Object Data for sKey in data: objIndicator = Indicator() # if 'indicator' in data[sKey]['meta']['IDs']: # objIndicator.id_ = data[sKey]['meta']['IDs'].key # else: # data[sKey]['meta']['IDs'].update({objIndicator.id_:'indicator'}) listOBS = [] ### Parsing IP Address sAddr = data[sKey]['attrib']['IP Address'] if sAddr: objAddr = Address() objAddr.is_source = True objAddr.address_value = sAddr objAddr.address_value.condition = 'Equals' if isIPv4(sAddr): objAddr.category = 'ipv4-addr' elif isIPv6(sAddr): objAddr.category = 'ipv6-addr' else: continue obsAddr = Observable(objAddr) # if 'address"' in data[sKey]['meta']['IDs']: # obsAddr.id_ = data[sKey]['meta']['IDs'].key # else: # data[sKey]['meta']['IDs'].update({objIndicator.id_:'address'}) objAddr = None obsAddr.sighting_count = 1 obsAddr.title = 'IP: ' + sAddr sDscrpt = 'IPv4' + ': ' + sAddr + " | " sDscrpt += "isSource: True | " obsAddr.description = "<![CDATA[" + sDscrpt + "]]>" listOBS.append(obsAddr) obsAddr = None objIndicator.add_indicator_type("IP Watchlist") ### Parsing Domain sDomain = data[sKey]['attrib']['Hostname'] if sDomain: objDomain = DomainName() objDomain.value = sDomain objDomain.value.condition = 'Equals' if isFQDN(sDomain): objDomain.type = 'FQDN' elif isTLD(sDomain): objDomain.type = 'TLD' else: continue obsDomain = Observable(objDomain) # if 'domain' in data[sKey]['meta']['IDs']: # obsDomain.id_ = data[sKey]['meta']['IDs'].key # else: # data[sKey]['meta']['IDs'].update({obsDomain.id_:'domain'}) objDomain = None obsDomain.sighting_count = 1 obsDomain.title = 'Domain: ' + sDomain sDscrpt = 'Domain: ' + sDomain + " | " sDscrpt += "isFQDN: True | " obsDomain.description = "<![CDATA[" + sDscrpt + "]]>" listOBS.append(obsDomain) obsDomain = None objIndicator.add_indicator_type("Domain Watchlist") ### Parsing Port Number sPortList = data[sKey]['attrib']['Ports'] for item in sPortList: if sPortList[item]: objPort = Port() sPort = sPortList[item] objPort.port_value = int(sPort) objPort.port_value.condition = 'Equals' objPort.layer4_protocol = 'TCP' obsPort = Observable(objPort) objPort = None obsPort.sighting_count = 1 obsPort.title = 'Port: ' + str(sPort) sDscrpt = 'PortNumber: ' + str(sPort) + " | " sDscrpt += "Protocol: TCP | " obsPort.description = "<![CDATA[" + sDscrpt + "]]>" listOBS.append(obsPort) ### Add Generated observable to Indicator objIndicator.observable_composition_operator = 'OR' objIndicator.observables = listOBS #Parsing Producer infoSrc = InformationSource(identity=Identity(name=srcObj.Domain)) #infoSrc.add_contributing_source(data[sKey]['attrib']['ref']) objIndicator.producer = infoSrc # if data[sKey]['attrib']['lstDateVF']: # objIndicator.set_produced_time(data[sKey]['attrib']['lstDateVF'][0]); objIndicator.set_received_time(data[sKey]['meta']['dateDL']) ### Generate Indicator Title based on availbe data lstContainng = [] lstIs = [] sTitle = ' This' if data[sKey]['attrib']['Hostname']: sTitle += ' domain ' + data[sKey]['attrib']['Hostname'] else: sTitle += ' ipAddress ' + sKey sTitle += ' has been identified as a TOR network "Exit Point" router' objIndicator.title = sTitle ### Generate Indicator Description based on availbe data sDscrpt = ' torstatus.blutmagie.de has identified this' if data[sKey]['attrib']['Hostname']: sDscrpt += ' domain ' + data[sKey]['attrib']['Hostname'] else: sDscrpt += ' ipAddress ' + sKey # sDscrpt += ' with a router name of "' + data[sKey]['attrib']['Router Name'] + '"' # if data[sKey]['attrib']['Ports']['ORPort']: # sDscrpt += ' using ORPort: ' + str(data[sKey]['attrib']['Ports']['ORPort']) # if data[sKey]['attrib']['Ports']['DirPort']: # sDscrpt += ' and DirPort: ' + str(data[sKey]['attrib']['Ports']['DirPort']) sDscrpt += ' as a TOR network "Exit Point" router' if data[sKey]['attrib']['Country Code']: sCntry_code = data[sKey]['attrib']['Country Code'] if sCntry_code in dictCC2CN: sCntry_name = dictCC2CN[sCntry_code] sDscrpt += ', which appears to be located in ' + sCntry_name sDscrpt += '. \n\n RawData: ' + str(data[sKey]['attrib']) objIndicator.description = "<![CDATA[" + sDscrpt + "]]>" #Parse TTP # objMalware = MalwareInstance() # objMalware.add_type("Remote Access Trojan") # ttpTitle = data[sKey]['attrib']['type'] # objTTP = TTP(title=ttpTitle) # objTTP.behavior = Behavior() # objTTP.behavior.add_malware_instance(objMalware) # objIndicator.add_indicated_ttp(objTTP) #objIndicator.add_indicated_ttp(TTP(idref=objTTP.id_)) #stix_package.add_ttp(objTTP) stix_package.add_indicator(objIndicator) objIndicator = None ### STIX Package Meta Data stix_header = STIXHeader() stix_header.title = srcObj.pkgTitle stix_header.description = "<![CDATA[" + srcObj.pkgDscrpt + "]]>" ### Understanding markings http://stixproject.github.io/idioms/features/data-markings/ marking_specification = MarkingSpecification() classLevel = SimpleMarkingStructure() classLevel.statement = "Unclassified (Public)" marking_specification.marking_structures.append(classLevel) tlp = TLPMarkingStructure() tlp.color = "WHITE" marking_specification.marking_structures.append(tlp) marking_specification.controlled_structure = "//node()" objTOU = TermsOfUseMarkingStructure() sTOU = open('tou.txt').read() objTOU.terms_of_use = srcObj.Domain + " | " + sTOU marking_specification.marking_structures.append(objTOU) handling = Marking() handling.add_marking(marking_specification) stix_header.handling = handling stix_package.stix_header = stix_header stix_header = None ### Generate STIX XML File locSTIXFile = 'STIX_' + srcObj.fileName.split('.')[0] + '.xml' sndFile(stix_package.to_xml(), locSTIXFile) # locDataFile = 'db_' + srcObj.fileName.split('.')[0] + '.json' # sndFile_Dict2JSON(data,locDataFile); # data = None return (stix_package)
def adptr_dict2STIX(srcObj, data): sTxt = "Called... " sndMSG(sTxt, 'INFO', 'adptr_dict2STIX()') stixObj = None ### Input Check if srcObj == None or data == None: #TODO: Needs error msg: Missing srcData Object return (False) ### Generate NameSpace id tags STIX_NAMESPACE = {"http://hailataxii.com": "opensource"} OBS_NAMESPACE = Namespace("http://hailataxii.com", "opensource") stix_set_id_namespace(STIX_NAMESPACE) obs_set_id_namespace(OBS_NAMESPACE) ### Building STIX Wrapper stix_package = STIXPackage() objIndicator = Indicator() ### Bulid Object Data for sKey in data: objIndicator = Indicator() listOBS = [] ### Parsing IP Address sAddr = data[sKey]['attrib']['ipAddr'] if len(sAddr) > 0: objAddr = Address() objAddr.is_destination = True objAddr.address_value = sAddr objAddr.address_value.condition = 'Equals' if isIPv4(sAddr): objAddr.category = objAddr.CAT_IPV4 elif isIPv6(sAddr): objAddr.category = objAddr.CAT_IPV6 else: continue obsAddr = Observable(objAddr) objAddr = None obsAddr.sighting_count = 1 obsAddr.title = 'IP: ' + sAddr sDscrpt = 'IPv4' + ': ' + sAddr + " | " sDscrpt += "isDestination: True | " obsAddr.description = "<![CDATA[" + sDscrpt + "]]>" listOBS.append(obsAddr) obsAddr = None objIndicator.add_indicator_type("IP Watchlist") ### Parsing Domain sDomain = data[sKey]['attrib']['domain'] if len(sDomain) > 0: objDomain = DomainName() objDomain.value = sDomain objDomain.value.condition = 'Equals' if isFQDN(sDomain): objDomain.type = 'FQDN' elif isTLD(sDomain): objDomain.type = 'TLD' else: continue obsDomain = Observable(objDomain) objDomain = None obsDomain.sighting_count = 1 obsDomain.title = 'Domain: ' + sDomain sDscrpt = 'Domain: ' + sDomain + " | " sDscrpt += "isFQDN: True | " obsDomain.description = "<![CDATA[" + sDscrpt + "]]>" listOBS.append(obsDomain) obsDomain = None objIndicator.add_indicator_type("Domain Watchlist") #Parser URI sURI = data[sKey]['attrib']['title'] if len(sURI) > 0: objURI = URI() objURI.value = sURI objURI.value.condition = 'Equals' objURI.type_ = URI.TYPE_URL obsURI = Observable(objURI) objURI = None obsURI.sighting_count = 1 obsURI.title = 'URI: ' + sURI sDscrpt = 'URI: ' + sURI + " | " sDscrpt += "Type: URL | " obsURI.description = "<![CDATA[" + sDscrpt + "]]>" listOBS.append(obsURI) obsURI = None objIndicator.add_indicator_type("URL Watchlist") ### Add Generated observable to Indicator objIndicator.observables = listOBS objIndicator.observable_composition_operator = 'OR' #Parsing Producer sProducer = srcObj.Domain if len(sProducer) > 0: objIndicator.set_producer_identity(sProducer) objIndicator.set_produced_time(data[sKey]['attrib']['dateVF']) objIndicator.set_received_time(data[sKey]['dateDL']) ### Generate Indicator Title based on availbe data sTitle = 'C2C Site: ' + sURI objIndicator.title = sTitle #Generate Indicator Description based on availbe data sDscrpt = "" if len(sAddr) > 0: sAddLine = "This IP address " + sAddr if len(sDomain) > 0: sAddLine = "This domain " + sDomain if len(sAddr) > 0 and len(sDomain) > 0: sAddLine = "This domain " + sDomain + " (" + sAddr + ")" if len(sAddLine) > 0: sDscrpt += sAddLine sDscrpt = sDscrpt + " has been identified as a command and control site for " + data[ sKey]['attrib']['dscrpt'] + ' malware' if len(srcObj.Domain) > 0: sDscrpt = sDscrpt + " by " + srcObj.Domain else: sDscrpt = sDscrpt + "." sDscrpt = sDscrpt + ". For more detailed infomation about this indicator go to [CAUTION!!Read-URL-Before-Click] [" + data[ sKey]['attrib']['link'] + "]." if len(sDscrpt) > 0: objIndicator.description = "<![CDATA[" + sDscrpt + "]]>" pass #Parse TTP sType = data[sKey]['attrib']['dscrpt'] if len(sType) > 0: objMalware = MalwareInstance() objMalware.add_name(sType) objMalware.add_type("Remote Access Trojan") objMalware.short_description = "" objMalware.description = "" objTTP = TTP(title=sType) objTTP.behavior = Behavior() objTTP.behavior.add_malware_instance(objMalware) objIndicator.add_indicated_ttp(objTTP) stix_package.add_indicator(objIndicator) objIndicator = None ### STIX Package Meta Data stix_header = STIXHeader() stix_header.title = srcObj.pkgTitle stix_header.description = "<![CDATA[" + srcObj.pkgDscrpt + "]]>" ### Understanding markings http://stixproject.github.io/idioms/features/data-markings/ marking_specification = MarkingSpecification() classLevel = SimpleMarkingStructure() classLevel.statement = "Unclassified (Public)" marking_specification.marking_structures.append(classLevel) tlp = TLPMarkingStructure() tlp.color = "WHITE" marking_specification.marking_structures.append(tlp) marking_specification.controlled_structure = "//node()" objTOU = TermsOfUseMarkingStructure() sTOU = open('tou.txt').read() objTOU.terms_of_use = sProducer + " | " + sTOU marking_specification.marking_structures.append(objTOU) handling = Marking() handling.add_marking(marking_specification) stix_header.handling = handling stix_package.stix_header = stix_header stix_header = None ### Generate STIX XML File locSTIXFile = 'STIX_' + srcObj.fileName.split('.')[0] + '.xml' sndFile(stix_package.to_xml(), locSTIXFile) return (stix_package)
def test_to_xml_default_encoded(self): s = STIXHeader() s.title = UNICODE_STR xml = s.to_xml() self.assertTrue(UNICODE_STR in xml.decode("utf-8"))
def test_to_xml_no_encoding(self): s = STIXHeader() s.title = UNICODE_STR xml = s.to_xml(encoding=None) self.assertTrue(isinstance(xml, unicode)) self.assertTrue(UNICODE_STR in xml)
def adptr_dict2STIX(srcObj, data): sTxt = "Called... " sndMSG(sTxt, 'INFO', 'adptr_dict2STIX()') stixObj = None ### Input Check if srcObj == None or data == None: #TODO: Needs error msg: Missing srcData Object return (False) ### Generate NameSpace id tags STIX_NAMESPACE = {"http://hailataxii.com": "opensource"} OBS_NAMESPACE = Namespace("http://hailataxii.com", "opensource") stix_set_id_namespace(STIX_NAMESPACE) obs_set_id_namespace(OBS_NAMESPACE) ### Building STIX Wrapper stix_package = STIXPackage() objIndicator = Indicator() ### Bulid Object Data for sKey in data: objIndicator = Indicator() listOBS = [] oObsSrcData = genObsSrcData(srcObj, data[sKey]) ### Parsing IP Address sAddr = data[sKey]['attrib']['ip'] if len(sAddr) > 0: objAddr = Address() objAddr.is_destination = True objAddr.address_value = sAddr objAddr.address_value.condition = 'Equals' if isIPv4(sAddr): objAddr.type = 'ipv4-addr' elif isIPv6(sAddr): objAddr.type = 'ipv6-addr' else: continue obsAddr = Observable(objAddr) objAddr = None obsAddr.sighting_count = 1 oObsSrcData.sighting_count = 1 obsAddr.observable_source.append(oObsSrcData) sTitle = 'IP: ' + sAddr obsAddr.title = sTitle sDscpt = 'ipv4-addr' + ': ' + sAddr + " | " sDscpt += "is_destination: True | " if data[sKey]['attrib']['first']: sDscpt += "firstSeen: " + data[sKey]['attrib']['first'] + " | " if data[sKey]['attrib']['last']: sDscpt += "lastSeen: " + data[sKey]['attrib']['last'] + " | " obsAddr.description = "<![CDATA[" + sDscpt + "]]>" listOBS.append(obsAddr) obsAddr = None ### Parsing Network Address sAddr = data[sKey]['attrib']['inetnum'] if sAddr: objAddr = Address() objAddr.is_destination = True sAddrNet = sAddr.split("-") objAddr.address_value = sAddrNet[0].strip( ) + "##comma##" + sAddrNet[1].strip() objAddr.address_value.condition = 'InclusiveBetween' objAddr.category = 'ipv4-net' obsAddr = Observable(objAddr) objAddr = None obsAddr.sighting_count = 1 oObsSrcData.sighting_count = 1 obsAddr.observable_source.append(oObsSrcData) sTitle = 'NETWORK_range: ' + sAddr obsAddr.title = sTitle sDscpt = 'ipv4-net' + ': ' + sAddr + " | " if data[sKey]['attrib']['netname']: sDscpt += 'netName' + ': ' + data[sKey]['attrib'][ 'netname'] + " | " obsAddr.description = "<![CDATA[" + sDscpt + "]]>" listOBS.append(obsAddr) obsAddr = None ### Parsing Email Address sEMAIL = data[sKey]['attrib']['email'] if sEMAIL: objEmail = EmailAddress() #objEmail.is_source = True objEmail.address_value = sEMAIL objEmail.address_value.condition = 'Equals' objEmail.category = 'e-mail' obsEmail = Observable(objEmail) objEmail = None obsEmail.sighting_count = 1 oObsSrcData.sighting_count = 1 if len(data[sKey]['attrib']['source']) > 0: oObsSrcData.name = data[sKey]['attrib']['source'] obsEmail.observable_source.append(oObsSrcData) sTitle = 'REGISTRAR_email: ' + sEMAIL obsEmail.title = sTitle sDscrpt = 'REGISTRAR_email: ' + sEMAIL if data[sKey]['attrib']['descr']: sDscrpt += " | REGISTRAR_name: " + data[sKey]['attrib'][ 'descr'] + " | " obsEmail.description = "<![CDATA[" + sDscrpt + "]]>" listOBS.append(obsEmail) obsEmail = None ### Parsing Domain sDomain = data[sKey]['attrib']['domain'] if len(sDomain) > 0: objDomain = DomainName() objDomain.value = sDomain objDomain.value.condition = 'Equals' objDomain.is_destination = True if isFQDN(sDomain): objDomain.type = 'FQDN' elif isTLD(sDomain): objDomain.type = 'TLD' else: continue obsDomain = Observable(objDomain) objDomain = None obsDomain.sighting_count = 1 oObsSrcData.sighting_count = 1 obsDomain.observable_source.append(oObsSrcData) obsDomain.title = 'Domain: ' + sDomain sDscpt = 'Domain: ' + sDomain + " | " sDscpt += "isDestination: True | " if data[sKey]['attrib']['first']: sDscpt += "firstSeen: " + data[sKey]['attrib']['first'] + " | " if data[sKey]['attrib']['last']: sDscpt += "lastSeen: " + data[sKey]['attrib']['last'] + " | " #if obsDomain.description = "<![CDATA[" + sDscpt + "]]>" listOBS.append(obsDomain) obsDomain = None objIndicator.add_indicator_type("Domain Watchlist") #Parser URI sURI = data[sKey]['attrib']['url'] if len(sURI) > 0: objURI = URI() objURI.value = sURI objURI.value.condition = 'Equals' objURI.type_ = URI.TYPE_URL obsURI = Observable(objURI) objURI = None obsURI.sighting_count = 1 oObsSrcData.sighting_count = 1 obsURI.observable_source.append(oObsSrcData) obsURI.title = 'URI: ' + sURI sDscpt = 'URI: ' + sURI + " | " sDscpt += "Type: URL | " obsURI.description = "<![CDATA[" + sDscpt + "]]>" listOBS.append(obsURI) obsURI = None objIndicator.add_indicator_type("URL Watchlist") sDscrpt = None sCntry_code = None sCntry_name = None sRgstra_email = None sRgstra_name = None # add Phishing Email Target # add Phishing email Details phishtank_ID if data[sKey]['attrib']['country']: sCntry_code = data[sKey]['attrib']['country'] if sCntry_code in dictCC2CN: sCntry_name = dictCC2CN[sCntry_code] if data[sKey]['attrib']['email'] > 0: sRgstra_email = data[sKey]['attrib']['email'] if data[sKey]['attrib']['descr']: sRgstra_name = data[sKey]['attrib']['descr'] sDscrpt = " clean-mx.de has identified this " if isIPv4(data[sKey]['attrib']['domain']): sDscrpt += "ip address " + data[sKey]['attrib']['domain'] + " " else: sDscrpt += "domain " + data[sKey]['attrib']['domain'] + " " sDscrpt += "as malicious " if data[sKey]['attrib']['target']: sDscrpt += "and uses phishing email(s) targeting " + data[sKey][ 'attrib']['target'] + " users with " else: sDscrpt += "and sent out " sDscrpt += "email containg this url <-Do Not Connect-> {" + data[sKey][ 'attrib']['url'] + "} <-Do Not Connect-> link. " if data[sKey]['attrib']['phishtank']: sDscrpt += "For more detail on the specific phisihing email use this phishtank ID [" + data[ sKey]['attrib']['phishtank'] + "]. " if sCntry_code: sDscrpt += " This url appears to originated in " + sCntry_code if sCntry_name: sDscrpt += " (" + sCntry_name + ")" if sCntry_code and (sRgstra_email or sRgstra_name): sDscrpt += " and is " if sRgstra_email: sDscrpt += "register to " + sRgstra_email if sRgstra_email and sRgstra_name: sDscrpt += " of " + sRgstra_name elif sRgstra_name: sDscrpt += "register to " + sRgstra_name sDscrpt += "." if sCntry_code or sRgstra_email or sRgstra_name: objIndicator.description = "<![CDATA[" + sDscrpt + "]]>" sTitle = 'Phishing ID:' + sKey + " " if data[sKey]['attrib']["target"]: sTitle += "Target: " + data[sKey]['attrib']["target"] + " " if data[sKey]['attrib']["url"]: sTitle += "URL: " + data[sKey]['attrib']["url"] + " " objIndicator.title = sTitle ### Add Generated observable to Indicator objIndicator.add_indicator_type("IP Watchlist") objIndicator.observable_composition_operator = 'OR' objIndicator.observables = listOBS #Parsing Producer sProducer = srcObj.Domain if len(sProducer) > 0: objIndicator.set_producer_identity(sProducer) objIndicator.set_produced_time(data[sKey]['attrib']['first']) objIndicator.set_received_time(data[sKey]['dateDL']) stix_package.add_indicator(objIndicator) objIndicator = None ### STIX Package Meta Data stix_header = STIXHeader() stix_header.title = srcObj.pkgTitle stix_header.description = "<![CDATA[" + srcObj.pkgDscrpt + "]]>" ### Understanding markings http://stixproject.github.io/idioms/features/data-markings/ marking_specification = MarkingSpecification() classLevel = SimpleMarkingStructure() classLevel.statement = "Unclassified (Public)" marking_specification.marking_structures.append(classLevel) objTOU = TermsOfUseMarkingStructure() #sTOU = open('tou.txt').read() objTOU.terms_of_use = sProducer + " | " + srcObj.srcTOU marking_specification.marking_structures.append(objTOU) tlp = TLPMarkingStructure() tlp.color = "WHITE" marking_specification.marking_structures.append(tlp) marking_specification.controlled_structure = "//node()" handling = Marking() handling.add_marking(marking_specification) stix_header.handling = handling stix_package.stix_header = stix_header stix_header = None ### Generate STIX XML File locSTIXFile = 'STIX_' + srcObj.fileName.split('.')[0] + '.xml' sndFile(stix_package.to_xml(), locSTIXFile) return (stix_package)
def gen_stix_observable_sample(config, target=None, datatype=None, title='random test data', description='random test data', package_intents='Indicators - Watchlist', tlp_color='WHITE'): '''generate sample stix data comprised of indicator_count indicators of type datatype''' # setup the xmlns... xmlns_url = config['edge']['sites'][target]['stix']['xmlns_url'] xmlns_name = config['edge']['sites'][target]['stix']['xmlns_name'] set_stix_id_namespace({xmlns_url: xmlns_name}) set_cybox_id_namespace(Namespace(xmlns_url, xmlns_name)) # construct a stix package... stix_package = STIXPackage() stix_header = STIXHeader() stix_header.title = title stix_header.description = description stix_header.package_intents = package_intents marking = MarkingSpecification() marking.controlled_structure = '../../../../descendant-or-self::node()' tlp_marking = TLPMarkingStructure() tlp_marking.color = tlp_color marking.marking_structures.append(tlp_marking) stix_package.stix_header = stix_header stix_package.stix_header.handling = Marking() stix_package.stix_header.handling.add_marking(marking) # ...and stuff it full of random sample data :-) if datatype == 'ip': addr = Address(address_value=datagen.generate_random_ip_address(), category='ipv4-addr') addr.condition = 'Equals' stix_package.add_observable(Observable(addr)) elif datatype == 'domain': domain = DomainName() domain.type_ = 'FQDN' domain.value = datagen.generate_random_domain(config) domain.condition = 'Equals' stix_package.add_observable(Observable(domain)) elif datatype == 'filehash': file_object = File() file_object.file_name = str(uuid.uuid4()) + '.exe' hashes = datagen.generate_random_hashes() for hash in hashes.keys(): file_object.add_hash(Hash(hashes[hash], type_=hash.upper())) for i in file_object.hashes: i.simple_hash_value.condition = "Equals" stix_package.add_observable(Observable(file_object)) elif datatype == 'email': try: msg = datagen.get_random_spam_msg(config) email = EmailMessage() email.header = EmailHeader() header_map = { 'Subject': 'subject', 'To': 'to', 'Cc': 'cc', 'Bcc': 'bcc', 'From': 'from_', 'Sender': 'sender', 'Date': 'date', 'Message-ID': 'message_id', 'Reply-To': 'reply_to', 'In-Reply-To': 'in_reply_to', 'Content-Type': 'content_type', 'Errors-To': 'errors_to', 'Precedence': 'precedence', 'Boundary': 'boundary', 'MIME-Version': 'mime_version', 'X-Mailer': 'x_mailer', 'User-Agent': 'user_agent', 'X-Originating-IP': 'x_originating_ip', 'X-Priority': 'x_priority' } # TODO handle received_lines for key in header_map.keys(): val = msg.get(key, None) if val: email.header.__setattr__(header_map[key], val) email.header.__getattribute__(header_map[key]).condition = \ 'Equals' # TODO handle email bodies (it's mostly all there except for # handling weird text encoding problems that were making # libcybox stacktrace) # body = get_email_payload(random_spam_msg) # if body: # email.raw_body = body stix_package.add_observable(Observable(email)) except: return (None) observable_id = stix_package.observables.observables[0].id_ return (observable_id, stix_package)
def stix_framing(*args): import datetime, re from stix.core import STIXPackage, STIXHeader from cybox.utils import Namespace # As python3 is forced anyway, mixbox is used and we don't need to try to import idgen from stix.utils from mixbox import idgen from stix import __version__ as STIXVER NS_DICT = { "http://cybox.mitre.org/common-2": 'cyboxCommon', "http://cybox.mitre.org/cybox-2": 'cybox', "http://cybox.mitre.org/default_vocabularies-2": 'cyboxVocabs', "http://cybox.mitre.org/objects#AccountObject-2": 'AccountObj', "http://cybox.mitre.org/objects#ASObject-1": 'ASObj', "http://cybox.mitre.org/objects#AddressObject-2": 'AddressObj', "http://cybox.mitre.org/objects#PortObject-2": 'PortObj', "http://cybox.mitre.org/objects#DomainNameObject-1": 'DomainNameObj', "http://cybox.mitre.org/objects#EmailMessageObject-2": 'EmailMessageObj', "http://cybox.mitre.org/objects#FileObject-2": 'FileObj', "http://cybox.mitre.org/objects#HTTPSessionObject-2": 'HTTPSessionObj', "http://cybox.mitre.org/objects#HostnameObject-1": 'HostnameObj', "http://cybox.mitre.org/objects#MutexObject-2": 'MutexObj', "http://cybox.mitre.org/objects#PipeObject-2": 'PipeObj', "http://cybox.mitre.org/objects#URIObject-2": 'URIObj', "http://cybox.mitre.org/objects#WinRegistryKeyObject-2": 'WinRegistryKeyObj', 'http://cybox.mitre.org/objects#WinServiceObject-2': 'WinServiceObj', "http://cybox.mitre.org/objects#NetworkConnectionObject-2": 'NetworkConnectionObj', "http://cybox.mitre.org/objects#NetworkSocketObject-2": 'NetworkSocketObj', "http://cybox.mitre.org/objects#SocketAddressObject-1": 'SocketAddressObj', "http://cybox.mitre.org/objects#SystemObject-2": 'SystemObj', "http://cybox.mitre.org/objects#ProcessObject-2": 'ProcessObj', "http://cybox.mitre.org/objects#X509CertificateObject-2": 'X509CertificateObj', "http://cybox.mitre.org/objects#WhoisObject-2": 'WhoisObj', "http://cybox.mitre.org/objects#WinExecutableFileObject-2": 'WinExecutableFileObj', "http://data-marking.mitre.org/Marking-1": 'marking', "http://data-marking.mitre.org/extensions/MarkingStructure#TLP-1": 'tlpMarking', "http://stix.mitre.org/ExploitTarget-1": 'et', "http://stix.mitre.org/Incident-1": 'incident', "http://stix.mitre.org/Indicator-2": 'indicator', "http://stix.mitre.org/TTP-1": 'ttp', "http://stix.mitre.org/ThreatActor-1": 'ta', "http://stix.mitre.org/common-1": 'stixCommon', "http://stix.mitre.org/default_vocabularies-1": 'stixVocabs', "http://stix.mitre.org/extensions/Identity#CIQIdentity3.0-1": 'ciqIdentity', "http://stix.mitre.org/extensions/TestMechanism#Snort-1": 'snortTM', "http://stix.mitre.org/stix-1": 'stix', "http://www.w3.org/2001/XMLSchema-instance": 'xsi', "urn:oasis:names:tc:ciq:xal:3": 'xal', "urn:oasis:names:tc:ciq:xnl:3": 'xnl', "urn:oasis:names:tc:ciq:xpil:3": 'xpil', } SCHEMALOC_DICT = { 'http://cybox.mitre.org/common-2': 'http://cybox.mitre.org/XMLSchema/common/2.1/cybox_common.xsd', 'http://cybox.mitre.org/cybox-2': 'http://cybox.mitre.org/XMLSchema/core/2.1/cybox_core.xsd', 'http://cybox.mitre.org/default_vocabularies-2': 'http://cybox.mitre.org/XMLSchema/default_vocabularies/2.1/cybox_default_vocabularies.xsd', 'http://cybox.mitre.org/objects#AccountObject-2': ' http://cybox.mitre.org/XMLSchema/objects/Account/2.1/Account_Object.xsd', 'http://cybox.mitre.org/objects#ASObject-1': 'http://cybox.mitre.org/XMLSchema/objects/AS/1.0/AS_Object.xsd', 'http://cybox.mitre.org/objects#AddressObject-2': 'http://cybox.mitre.org/XMLSchema/objects/Address/2.1/Address_Object.xsd', 'http://cybox.mitre.org/objects#PortObject-2': 'http://cybox.mitre.org/XMLSchema/objects/Port/2.1/Port_Object.xsd', 'http://cybox.mitre.org/objects#DomainNameObject-1': 'http://cybox.mitre.org/XMLSchema/objects/Domain_Name/1.0/Domain_Name_Object.xsd', 'http://cybox.mitre.org/objects#EmailMessageObject-2': 'http://cybox.mitre.org/XMLSchema/objects/Email_Message/2.1/Email_Message_Object.xsd', 'http://cybox.mitre.org/objects#FileObject-2': 'http://cybox.mitre.org/XMLSchema/objects/File/2.1/File_Object.xsd', 'http://cybox.mitre.org/objects#HTTPSessionObject-2': 'http://cybox.mitre.org/XMLSchema/objects/HTTP_Session/2.1/HTTP_Session_Object.xsd', 'http://cybox.mitre.org/objects#HostnameObject-1': 'http://cybox.mitre.org/XMLSchema/objects/Hostname/1.0/Hostname_Object.xsd', 'http://cybox.mitre.org/objects#MutexObject-2': 'http://cybox.mitre.org/XMLSchema/objects/Mutex/2.1/Mutex_Object.xsd', 'http://cybox.mitre.org/objects#PipeObject-2': 'http://cybox.mitre.org/XMLSchema/objects/Pipe/2.1/Pipe_Object.xsd', 'http://cybox.mitre.org/objects#URIObject-2': 'http://cybox.mitre.org/XMLSchema/objects/URI/2.1/URI_Object.xsd', 'http://cybox.mitre.org/objects#WinServiceObject-2': 'http://cybox.mitre.org/XMLSchema/objects/Win_Service/2.1/Win_Service_Object.xsd', 'http://cybox.mitre.org/objects#WinRegistryKeyObject-2': 'http://cybox.mitre.org/XMLSchema/objects/Win_Registry_Key/2.1/Win_Registry_Key_Object.xsd', 'http://cybox.mitre.org/objects#NetworkConnectionObject-2': 'http://cybox.mitre.org/XMLSchema/objects/Network_Connection/2.0.1/Network_Connection_Object.xsd', 'http://cybox.mitre.org/objects#NetworkSocketObject-2': 'https://cybox.mitre.org/XMLSchema/objects/Network_Socket/2.1/Network_Socket_Object.xsd', 'http://cybox.mitre.org/objects#SystemObject-2': 'http://cybox.mitre.org/XMLSchema/objects/System/2.1/System_Object.xsd', 'http://cybox.mitre.org/objects#SocketAddressObject-1': 'http://cybox.mitre.org/XMLSchema/objects/Socket_Address/1.1/Socket_Address_Object.xsd', 'http://cybox.mitre.org/objects#ProcessObject-2': 'https://cybox.mitre.org/XMLSchema/objects/Process/2.1/Process_Object.xsd', 'http://cybox.mitre.org/objects#X509CertificateObject-2': 'http://cybox.mitre.org/XMLSchema/objects/X509_Certificate/2.1/X509_Certificate_Object.xsd', 'http://cybox.mitre.org/objects#WhoisObject-2': 'http://cybox.mitre.org/XMLSchema/objects/Whois/2.1/Whois_Object.xsd', 'http://cybox.mitre.org/objects#WinExecutableFileObject-2': 'http://cybox.mitre.org/XMLSchema/objects/Win_Executable_File/2.1/Win_Executable_File_Object.xsd', 'http://data-marking.mitre.org/Marking-1': 'http://stix.mitre.org/XMLSchema/data_marking/1.1.1/data_marking.xsd', 'http://data-marking.mitre.org/extensions/MarkingStructure#TLP-1': 'http://stix.mitre.org/XMLSchema/extensions/marking/tlp/1.1.1/tlp_marking.xsd', 'http://stix.mitre.org/ExploitTarget-1': 'http://stix.mitre.org/XMLSchema/exploit_target/1.1.1/exploit_target.xsd', 'http://stix.mitre.org/Incident-1': 'http://stix.mitre.org/XMLSchema/incident/1.1.1/incident.xsd', 'http://stix.mitre.org/Indicator-2': 'http://stix.mitre.org/XMLSchema/indicator/2.1.1/indicator.xsd', 'http://stix.mitre.org/TTP-1': 'http://stix.mitre.org/XMLSchema/ttp/1.1.1/ttp.xsd', 'http://stix.mitre.org/ThreatActor-1': 'http://stix.mitre.org/XMLSchema/threat_actor/1.1.1/threat_actor.xsd', 'http://stix.mitre.org/common-1': 'http://stix.mitre.org/XMLSchema/common/1.1.1/stix_common.xsd', 'http://stix.mitre.org/default_vocabularies-1': 'http://stix.mitre.org/XMLSchema/default_vocabularies/1.1.1/stix_default_vocabularies.xsd', 'http://stix.mitre.org/extensions/Identity#CIQIdentity3.0-1': 'http://stix.mitre.org/XMLSchema/extensions/identity/ciq_3.0/1.1.1/ciq_3.0_identity.xsd', 'http://stix.mitre.org/extensions/TestMechanism#Snort-1': 'http://stix.mitre.org/XMLSchema/extensions/test_mechanism/snort/1.1.1/snort_test_mechanism.xsd', 'http://stix.mitre.org/stix-1': 'http://stix.mitre.org/XMLSchema/core/1.1.1/stix_core.xsd', 'urn:oasis:names:tc:ciq:xal:3': 'http://stix.mitre.org/XMLSchema/external/oasis_ciq_3.0/xAL.xsd', 'urn:oasis:names:tc:ciq:xnl:3': 'http://stix.mitre.org/XMLSchema/external/oasis_ciq_3.0/xNL.xsd', 'urn:oasis:names:tc:ciq:xpil:3': 'http://stix.mitre.org/XMLSchema/external/oasis_ciq_3.0/xPIL.xsd', } baseurl, orgname, return_type = args if not baseurl: baseurl = 'https://www.misp-project.org' real_orgname = args[1] orgname = re.sub('[\W]+', '', orgname.replace(" ", "_")) NS_DICT[baseurl] = orgname try: idgen.set_id_namespace(Namespace(baseurl, orgname)) except TypeError: idgen.set_id_namespace(Namespace(baseurl, orgname, "MISP")) stix_package = STIXPackage() stix_header = STIXHeader() stix_header.title = "Export from {} MISP".format(real_orgname) stix_header.package_intents = "Threat Report" stix_package.stix_header = stix_header stix_package.version = "1.1.1" stix_package.timestamp = datetime.datetime.now() return stix_json_framing( stix_package) if return_type == 'json' else stix_xml_framing( stix_package, NS_DICT, SCHEMALOC_DICT)
def gen_stix_observable_sample(config, target=None, datatype=None, title='random test data', description='random test data', package_intents='Indicators - Watchlist', tlp_color='WHITE'): '''generate sample stix data comprised of indicator_count indicators of type datatype''' # setup the xmlns... xmlns_url = config['edge']['sites'][target]['stix']['xmlns_url'] xmlns_name = config['edge']['sites'][target]['stix']['xmlns_name'] set_stix_id_namespace({xmlns_url: xmlns_name}) set_cybox_id_namespace(Namespace(xmlns_url, xmlns_name)) # construct a stix package... stix_package = STIXPackage() stix_header = STIXHeader() stix_header.title = title stix_header.description = description stix_header.package_intents = package_intents marking = MarkingSpecification() marking.controlled_structure = '../../../../descendant-or-self::node()' tlp_marking = TLPMarkingStructure() tlp_marking.color = tlp_color marking.marking_structures.append(tlp_marking) stix_package.stix_header = stix_header stix_package.stix_header.handling = Marking() stix_package.stix_header.handling.add_marking(marking) # ...and stuff it full of random sample data :-) if datatype == 'ip': addr = Address(address_value=datagen.generate_random_ip_address(), category='ipv4-addr') addr.condition = 'Equals' stix_package.add_observable(Observable(addr)) elif datatype == 'domain': domain = DomainName() domain.type_ = 'FQDN' domain.value = datagen.generate_random_domain(config) domain.condition = 'Equals' stix_package.add_observable(Observable(domain)) elif datatype == 'filehash': file_object = File() file_object.file_name = str(uuid.uuid4()) + '.exe' hashes = datagen.generate_random_hashes() for hash in hashes.keys(): file_object.add_hash(Hash(hashes[hash], type_=hash.upper())) for i in file_object.hashes: i.simple_hash_value.condition = "Equals" stix_package.add_observable(Observable(file_object)) elif datatype == 'email': try: msg = datagen.get_random_spam_msg(config) email = EmailMessage() email.header = EmailHeader() header_map = {'Subject': 'subject', 'To': 'to', 'Cc': 'cc', 'Bcc': 'bcc', 'From': 'from_', 'Sender': 'sender', 'Date': 'date', 'Message-ID': 'message_id', 'Reply-To': 'reply_to', 'In-Reply-To': 'in_reply_to', 'Content-Type': 'content_type', 'Errors-To': 'errors_to', 'Precedence': 'precedence', 'Boundary': 'boundary', 'MIME-Version': 'mime_version', 'X-Mailer': 'x_mailer', 'User-Agent': 'user_agent', 'X-Originating-IP': 'x_originating_ip', 'X-Priority': 'x_priority'} # TODO handle received_lines for key in header_map.keys(): val = msg.get(key, None) if val: email.header.__setattr__(header_map[key], val) email.header.__getattribute__(header_map[key]).condition = \ 'Equals' # TODO handle email bodies (it's mostly all there except for # handling weird text encoding problems that were making # libcybox stacktrace) # body = get_email_payload(random_spam_msg) # if body: # email.raw_body = body stix_package.add_observable(Observable(email)) except: return(None) observable_id = stix_package.observables.observables[0].id_ return(observable_id, stix_package)
def stix(json): """ Created a stix file based on a json file that is being handed over """ # Create a new STIXPackage stix_package = STIXPackage() # Create a new STIXHeader stix_header = STIXHeader() # Add Information Source. This is where we will add the tool information. stix_header.information_source = InformationSource() # Create a ToolInformation object. Use the initialization parameters # to set the tool and vendor names. # # Note: This is an instance of cybox.common.ToolInformation and NOT # stix.common.ToolInformation. tool = ToolInformation( tool_name="viper2stix", tool_vendor="The Viper group http://viper.li - developed by Alexander Jaeger https://github.com/deralexxx/viper2stix" ) #Adding your identity to the header identity = Identity() identity.name = Config.get('stix', 'producer_name') stix_header.information_source.identity=identity # Set the Information Source "tools" section to a # cybox.common.ToolInformationList which contains our tool that we # created above. stix_header.information_source.tools = ToolInformationList(tool) stix_header.title = Config.get('stix', 'title') # Set the produced time to now stix_header.information_source.time = Time() stix_header.information_source.time.produced_time = datetime.now() marking_specification = MarkingSpecification() marking_specification.controlled_structure = "../../../descendant-or-self::node()" tlp = TLPMarkingStructure() tlp.color = Config.get('stix', 'TLP') marking_specification.marking_structures.append(tlp) handling = Marking() handling.add_marking(marking_specification) # Set the header description stix_header.description = Config.get('stix', 'description') # Set the STIXPackage header stix_package.stix_header = stix_header stix_package.stix_header.handling = handling try: pp = pprint.PrettyPrinter(indent=5) pp.pprint(json['default']) #for key, value in json['default'].iteritems(): # print key, value for item in json['default']: #logger.debug("item %s", item) indicator = Indicator() indicator.title = "File Hash" indicator.description = ( "An indicator containing a File observable with an associated hash" ) # Create a CyboX File Object f = File() sha_value = item['sha256'] if sha_value is not None: sha256 = Hash() sha256.simple_hash_value = sha_value h = Hash(sha256, Hash.TYPE_SHA256) f.add_hash(h) sha1_value = item['sha1'] if sha_value is not None: sha1 = Hash() sha1.simple_hash_value = sha1_value h = Hash(sha1, Hash.TYPE_SHA1) f.add_hash(h) sha512_value = item['sha512'] if sha_value is not None: sha512 = Hash() sha512.simple_hash_value = sha512_value h = Hash(sha512, Hash.TYPE_SHA512) f.add_hash(h) f.add_hash(item['md5']) #adding the md5 hash to the title as well stix_header.title+=' '+item['md5'] #print(item['type']) f.size_in_bytes=item['size'] f.file_format=item['type'] f.file_name = item['name'] indicator.description = "File hash served by a Viper instance" indicator.add_object(f) stix_package.add_indicator(indicator) except Exception, e: logger.error('Error: %s',format(e)) return False
def gen_stix_observable_sample( config, target=None, datatype=None, title="random test data", description="random test data", package_intents="Indicators - Watchlist", tlp_color="WHITE", ): """generate sample stix data comprised of indicator_count indicators of type datatype""" # setup the xmlns... xmlns_url = config["edge"]["sites"][target]["stix"]["xmlns_url"] xmlns_name = config["edge"]["sites"][target]["stix"]["xmlns_name"] set_stix_id_namespace({xmlns_url: xmlns_name}) set_cybox_id_namespace(Namespace(xmlns_url, xmlns_name)) # construct a stix package... stix_package = STIXPackage() stix_header = STIXHeader() stix_header.title = title stix_header.description = description stix_header.package_intents = package_intents marking = MarkingSpecification() marking.controlled_structure = "../../../../descendant-or-self::node()" tlp_marking = TLPMarkingStructure() tlp_marking.color = tlp_color marking.marking_structures.append(tlp_marking) stix_package.stix_header = stix_header stix_package.stix_header.handling = Marking() stix_package.stix_header.handling.add_marking(marking) # ...and stuff it full of random sample data :-) if datatype == "ip": addr = Address(address_value=datagen_.generate_random_ip_address(), category="ipv4-addr") addr.condition = "Equals" stix_package.add_observable(Observable(addr)) elif datatype == "domain": domain = DomainName() domain.type_ = "FQDN" domain.value = datagen_.generate_random_domain(config) domain.condition = "Equals" stix_package.add_observable(Observable(domain)) elif datatype == "filehash": file_object = File() file_object.file_name = str(uuid.uuid4()) + ".exe" hashes = datagen_.generate_random_hashes() for hash in hashes.keys(): file_object.add_hash(Hash(hashes[hash], type_=hash.upper())) for i in file_object.hashes: i.simple_hash_value.condition = "Equals" stix_package.add_observable(Observable(file_object)) elif datatype == "email": try: msg = datagen_.get_random_spam_msg(config) email = EmailMessage() email.header = EmailHeader() header_map = { "Subject": "subject", "To": "to", "Cc": "cc", "Bcc": "bcc", "From": "from_", "Sender": "sender", "Date": "date", "Message-ID": "message_id", "Reply-To": "reply_to", "In-Reply-To": "in_reply_to", "Content-Type": "content_type", "Errors-To": "errors_to", "Precedence": "precedence", "Boundary": "boundary", "MIME-Version": "mime_version", "X-Mailer": "x_mailer", "User-Agent": "user_agent", "X-Originating-IP": "x_originating_ip", "X-Priority": "x_priority", } # TODO handle received_lines for key in header_map.keys(): val = msg.get(key, None) if val: email.header.__setattr__(header_map[key], val) email.header.__getattribute__(header_map[key]).condition = "Equals" # TODO handle email bodies (it's mostly all there except for # handling weird text encoding problems that were making # libcybox stacktrace) # body = get_email_payload(random_spam_msg) # if body: # email.raw_body = body stix_package.add_observable(Observable(email)) except: return None observable_id = stix_package.observables.observables[0].id_ return (observable_id, stix_package)
def main(): # get args parser = argparse.ArgumentParser ( description = "Parse a given CSV from Shadowserver and output STIX XML to stdout" , formatter_class=argparse.ArgumentDefaultsHelpFormatter ) parser.add_argument("--infile","-f", help="input CSV with bot data", default = "bots.csv") args = parser.parse_args() # setup stix document stix_package = STIXPackage() stix_header = STIXHeader() stix_header.title = "Bot Server IP addresses" stix_header.description = "IP addresses connecting to bot control servers at a given port" stix_header.add_package_intent ("Indicators - Watchlist") # add marking mark = Marking() markspec = MarkingSpecification() markstruct = SimpleMarkingStructure() markstruct.statement = "Usage of this information, including integration into security mechanisms implies agreement with the Shadowserver Terms of Service available at https://www.shadowserver.org/wiki/pmwiki.php/Shadowserver/TermsOfService" markspec.marking_structures.append(markstruct) mark.add_marking(markspec) stix_header.handling = mark # include author info stix_header.information_source = InformationSource() stix_header.information_source.time = Time() stix_header.information_source.time.produced_time =datetime.now(tzutc()) stix_header.information_source.tools = ToolInformationList() stix_header.information_source.tools.append("ShadowBotnetIP-STIXParser") stix_header.information_source.identity = Identity() stix_header.information_source.identity.name = "MITRE STIX Team" stix_header.information_source.add_role(VocabString("Format Transformer")) src = InformationSource() src.description = "https://www.shadowserver.org/wiki/pmwiki.php/Services/Botnet-CCIP" srcident = Identity() srcident.name = "shadowserver.org" src.identity = srcident src.add_role(VocabString("Originating Publisher")) stix_header.information_source.add_contributing_source(src) stix_package.stix_header = stix_header # add TTP for overall indicators bot_ttp = TTP() bot_ttp.title = 'Botnet C2' bot_ttp.resources = Resource() bot_ttp.resources.infrastructure = Infrastructure() bot_ttp.resources.infrastructure.title = 'Botnet C2' stix_package.add_ttp(bot_ttp) # read input data fd = open (args.infile, "rb") infile = csv.DictReader(fd) for row in infile: # split indicators out, may be 1..n with positional storage, same port and channel, inconsistent delims domain = row['Domain'].split() country = row['Country'].split() region = row['Region'].split('|') state = row['State'].split('|') asn = row['ASN'].split() asname = row['AS Name'].split() asdesc = row['AS Description'].split('|') index = 0 for ip in row['IP Address'].split(): indicator = Indicator() indicator.title = "IP indicator for " + row['Channel'] indicator.description = "Bot connecting to control server" # point to overall TTP indicator.add_indicated_ttp(TTP(idref=bot_ttp.id_)) # add our IP and port sock = SocketAddress() sock.ip_address = ip # add sighting sight = Sighting() sight.timestamp = "" obs = Observable(item=sock.ip_address) obsref = Observable(idref=obs.id_) sight.related_observables.append(obsref) indicator.sightings.append(sight) stix_package.add_observable(obs) # add pattern for indicator sock_pattern = SocketAddress() sock_pattern.ip_address = ip port = Port() port.port_value = row['Port'] sock_pattern.port = port sock_pattern.ip_address.condition= "Equals" sock_pattern.port.port_value.condition= "Equals" indicator.add_object(sock_pattern) stix_package.add_indicator(indicator) # add domain domain_obj = DomainName() domain_obj.value = domain[index] domain_obj.add_related(sock.ip_address,"Resolved_To", inline=False) stix_package.add_observable(domain_obj) # add whois obs whois_obj = WhoisEntry() registrar = WhoisRegistrar() registrar.name = asname[index] registrar.address = state[index] + region[index] + country[index] whois_obj.registrar_info = registrar whois_obj.add_related(sock.ip_address,"Characterizes", inline=False) stix_package.add_observable(whois_obj) # add ASN obj asn_obj = AutonomousSystem() asn_obj.name = asname[index] asn_obj.number = asn[index] asn_obj.handle = "AS" + str(asn[index]) asn_obj.add_related(sock.ip_address,"Contains", inline=False) stix_package.add_observable(asn_obj) # iterate index = index + 1 print stix_package.to_xml()
def adptr_dict2STIX(srcObj, data): sTxt = "Called... " sndMSG(sTxt, 'INFO', 'adptr_dict2STIX()') ### Input Check if srcObj is None or data is None: # TODO: Needs error msg: Missing srcData Object return False ### Generate NameSpace id tags STIX_NAMESPACE = {"http://hailataxii.com": "opensource"} OBS_NAMESPACE = Namespace("http://hailataxii.com", "opensource") stix_set_id_namespace(STIX_NAMESPACE) obs_set_id_namespace(OBS_NAMESPACE) ### Building STIX Wrapper stix_package = STIXPackage() ### Bulid Object Data for sKey in data: objIndicator = Indicator() listOBS = [] ### Parsing IP Address sAddr = data[sKey]['attrib']['ipAddr'] if sAddr: objAddr = Address() objAddr.is_source = True objAddr.address_value = sAddr objAddr.address_value.condition = 'Equals' if isIPv4(sAddr): objAddr.category = 'ipv4-addr' elif isIPv6(sAddr): objAddr.category = 'ipv6-addr' else: continue obsAddr = Observable(objAddr) obsAddr.sighting_count = 1 obsAddr.title = 'IP: ' + sAddr sDscrpt = 'IPv4' + ': ' + sAddr + " | " sDscrpt += "isSource: True | " obsAddr.description = "<![CDATA[" + sDscrpt + "]]>" listOBS.append(obsAddr) objIndicator.add_indicator_type("IP Watchlist") ### Parsing Domain sDomain = data[sKey]['attrib']['domain'] if sDomain: objDomain = DomainName() objDomain.value = sDomain objDomain.value.condition = 'Equals' if isFQDN(sDomain): objDomain.type = 'FQDN' elif isTLD(sDomain): objDomain.type = 'TLD' else: continue obsDomain = Observable(objDomain) obsDomain.sighting_count = 1 obsDomain.title = 'Domain: ' + sDomain sDscrpt = 'Domain: ' + sDomain + " | " sDscrpt += "isFQDN: True | " obsDomain.description = "<![CDATA[" + sDscrpt + "]]>" listOBS.append(obsDomain) objIndicator.add_indicator_type("Domain Watchlist") # Parser File Hash # sHash = data[sKey]['attrib']['hash']; # if len(sHash) > 0: # objFile = File() # sFileName = data[sKey]['attrib']['fileName'] # if len(sFileName) > 0: # objFile.file_name = sFileName # objFile.file_format = sFileName.split('.')[1] # objFile.add_hash(Hash(sHash, exact=True)) # obsFile = Observable(objFile) # objFile = None; # obsFile.sighting_count = 1 # obsFile.title = 'File: ' + sFileName # sDscrpt = 'FileName: ' + sFileName + " | " # sDscrpt += "FileHash: " + sHash + " | " # obsFile.description = "<![CDATA[" + sDscrpt + "]]>" # listOBS.append(obsFile) # obsFile = None; # objIndicator.add_indicator_type("File Hash Watchlist") ### Add Generated observable to Indicator objIndicator.observables = listOBS objIndicator.observable_composition_operator = 'OR' #Parsing Producer sProducer = srcObj.Domain if len(srcObj.Domain) > 0: objIndicator.set_producer_identity(srcObj.Domain) if data[sKey]['attrib']['dateVF']: objIndicator.set_produced_time(data[sKey]['attrib']['dateVF']) objIndicator.set_received_time(data[sKey]['dateDL']) ### Old Title / Description Generator #objIndicator.title = data[sKey]['attrib']['title']; #objIndicator.description = "<![CDATA[" + data[sKey]['attrib']['dscrpt'] + "]]>"; ### Generate Indicator Title based on availbe data sTitle = 'Feodo Tracker: ' if sAddr: sAddLine = "This IP address has been identified as malicious" if sDomain: sAddLine = "This domain has been identified as malicious" if len(sAddLine) > 0: sTitle += " | " + sAddLine if len(srcObj.Domain) > 0: sTitle += " by " + srcObj.Domain else: sTitle += "." if len(sTitle) > 0: objIndicator.title = sTitle #Generate Indicator Description based on availbe data sDscrpt = "" if sAddr: sAddLine = "This IP address " + sAddr if sDomain: sAddLine = "This domain " + sDomain if sAddr and sDomain: sAddLine = "This domain " + sDomain + " (" + sAddr + ")" if len(sAddLine) > 0: sDscrpt += sAddLine sDscrpt += " has been identified as malicious" if len(srcObj.Domain) > 0: sDscrpt += " by " + srcObj.Domain else: sDscrpt += "." sDscrpt = sDscrpt + ". For more detailed infomation about this indicator go to [CAUTION!!Read-URL-Before-Click] [" + \ data[sKey]['attrib']['link'] + "]." if len(sDscrpt) > 0: objIndicator.description = "<![CDATA[" + sDscrpt + "]]>" #Parse TTP objMalware = MalwareInstance() objMalware.add_name("Cridex") objMalware.add_name("Bugat") objMalware.add_name("Dridex") objMalware.add_type("Remote Access Trojan") objMalware.short_description = "Feodo (also known as Cridex or Bugat) is a Trojan used to commit ebanking fraud and steal sensitive information from the victims computer, such as credit card details or credentials" sDscrpt = "Feodo (also known as Cridex or Bugat) is a Trojan used to commit ebanking fraud and steal sensitive information from the victims computer, such as credit card details or credentials. At the moment, Feodo Tracker is tracking four versions of Feodo, and they are labeled by Feodo Tracker as version A, version B, version C and version D:\n" sDscrpt += "\n" sDscrpt += " Version A: Hosted on compromised webservers running an nginx proxy on port 8080 TCP forwarding all botnet traffic to a tier 2 proxy node. Botnet traffic usually directly hits these hosts on port 8080 TCP without using a domain name.\n" sDscrpt += " Version B: Hosted on servers rented and operated by cybercriminals for the exclusive purpose of hosting a Feodo botnet controller. Usually taking advantage of a domain name within ccTLD .ru. Botnet traffic usually hits these domain names using port 80 TCP.\n" sDscrpt += " Version C: Successor of Feodo, completely different code. Hosted on the same botnet infrastructure as Version A (compromised webservers, nginx on port 8080 TCP or port 7779 TCP, no domain names) but using a different URL structure. This Version is also known as Geodo.\n" sDscrpt += " Version D: Successor of Cridex. This version is also known as Dridex\n" objMalware.description = "<![CDATA[" + sDscrpt + "]]>" objTTP = TTP(title="Feodo") objTTP.behavior = Behavior() objTTP.behavior.add_malware_instance(objMalware) objIndicator.add_indicated_ttp(objTTP) #objIndicator.add_indicated_ttp(TTP(idref=objTTP.id_)) #stix_package.add_ttp(objTTP) stix_package.add_indicator(objIndicator) ### STIX Package Meta Data stix_header = STIXHeader() stix_header.title = srcObj.pkgTitle stix_header.description = "<![CDATA[" + srcObj.pkgDscrpt + "]]>" ### Understanding markings http://stixproject.github.io/idioms/features/data-markings/ marking_specification = MarkingSpecification() classLevel = SimpleMarkingStructure() classLevel.statement = "Unclassified (Public)" marking_specification.marking_structures.append(classLevel) objTOU = TermsOfUseMarkingStructure() sTOU = open('tou.txt').read() objTOU.terms_of_use = srcObj.Domain + " | " + sTOU marking_specification.marking_structures.append(objTOU) tlp = TLPMarkingStructure() tlp.color = "WHITE" marking_specification.marking_structures.append(tlp) marking_specification.controlled_structure = "//node()" handling = Marking() handling.add_marking(marking_specification) stix_header.handling = handling stix_package.stix_header = stix_header ### Generate STIX XML File locSTIXFile = 'STIX_' + srcObj.fileName.split('.')[0] + '.xml' sndFile(stix_package.to_xml(), locSTIXFile) return stix_package