def main(): # Create a CyboX File Object f = File() # This automatically detects that it's an MD5 hash based on the length f.add_hash("4EC0027BEF4D7E1786A04D021FA8A67F") # Create an Indicator with the File Hash Object created above. indicator = Indicator() indicator.title = "File Hash Example" indicator.description = ( "An indicator containing a File observable with an associated hash" ) indicator.set_producer_identity("The MITRE Corporation") indicator.set_produced_time(utils.dates.now()) # Add The File Object to the Indicator. This will promote the CybOX Object # to a CybOX Observable internally. indicator.add_object(f) # Create a STIX Package stix_package = STIXPackage() # Create the STIX Header and add a description. stix_header = STIXHeader() stix_header.description = "File Hash Indicator Example" stix_package.stix_header = stix_header # Add our Indicator object. The add() method will inspect the input and # append it to the `stix_package.indicators` collection. stix_package.add(indicator) # Print the XML! print(stix_package.to_xml())
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 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 stix_xml(bldata): # Create the STIX Package and Header objects stix_package = STIXPackage() stix_header = STIXHeader() # Set the description stix_header.description = "RiskIQ Blacklist Data - STIX Format" # Set the namespace NAMESPACE = {"http://www.riskiq.com" : "RiskIQ"} set_id_namespace(NAMESPACE) # Set the produced time to now stix_header.information_source = InformationSource() stix_header.information_source.time = Time() stix_header.information_source.time.produced_time = datetime.now() # Create the STIX Package stix_package = STIXPackage() # Build document stix_package.stix_header = stix_header # Build the Package Intent stix_header.package_intents.append(PackageIntent.TERM_INDICATORS) # Build the indicator indicator = Indicator() indicator.title = "List of Malicious URLs detected by RiskIQ - Malware, Phishing, and Spam" indicator.add_indicator_type("URL Watchlist") for datum in bldata: url = URI() url.value = "" url.value = datum['url'] url.type_ = URI.TYPE_URL url.condition = "Equals" indicator.add_observable(url) stix_package.add_indicator(indicator) return stix_package.to_xml()
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 main(): f = File() f.add_hash("4EC0027BEF4D7E1786A04D021FA8A67F") indicator = Indicator() indicator.title = "File Hash Example" indicator.description = "An indicator containing a File observable with an associated hash" indicator.set_producer_identity("The MITRE Corporation") indicator.set_produced_time(datetime.now(tzutc())) indicator.add_object(f) party_name = PartyName(name_lines=["Foo", "Bar"], person_names=["John Smith", "Jill Smith"], organisation_names=["Foo Inc.", "Bar Corp."]) ident_spec = STIXCIQIdentity3_0(party_name=party_name) ident_spec.add_electronic_address_identifier("*****@*****.**") ident_spec.add_free_text_line("Demonstrating Free Text!") ident_spec.add_contact_number("555-555-5555") ident_spec.add_contact_number("555-555-5556") identity = CIQIdentity3_0Instance(specification=ident_spec) indicator.set_producer_identity(identity) stix_package = STIXPackage() stix_header = STIXHeader() stix_header.description = "Example" stix_package.stix_header = stix_header stix_package.add_indicator(indicator) xml = stix_package.to_xml() print(xml)
def main(): infilename = '' outfilename = '' #Get the command-line arguments args = sys.argv[1:] if len(args) < 4: usage() sys.exit(1) for i in range(0,len(args)): if args[i] == '-i': infilename = args[i+1] elif args[i] == '-o': outfilename = args[i+1] if os.path.isfile(infilename): try: # Perform the translation using the methods from the OpenIOC to CybOX Script openioc_indicators = openioc.parse(infilename) observables_obj = openioc_to_cybox.generate_cybox(openioc_indicators, infilename, True) observables_cls = Observables.from_obj(observables_obj) # Set the namespace to be used in the STIX Package stix.utils.set_id_namespace({"https://github.com/STIXProject/openioc-to-stix":"openiocToSTIX"}) # Wrap the created Observables in a STIX Package/Indicator stix_package = STIXPackage() # Add the OpenIOC namespace input_namespaces = {"http://openioc.org/":"openioc"} stix_package.__input_namespaces__ = input_namespaces for observable in observables_cls.observables: indicator_dict = {} producer_dict = {} producer_dict['tools'] = [{'name':'OpenIOC to STIX Utility', 'version':str(__VERSION__)}] indicator_dict['producer'] = producer_dict indicator_dict['title'] = "CybOX-represented Indicator Created from OpenIOC File" indicator = Indicator.from_dict(indicator_dict) indicator.add_observable(observables_cls.observables[0]) stix_package.add_indicator(indicator) # Create and write the STIX Header stix_header = STIXHeader() stix_header.package_intent = "Indicators - Malware Artifacts" stix_header.description = "CybOX-represented Indicators Translated from OpenIOC File" stix_package.stix_header = stix_header # Write the generated STIX Package as XML to the output file outfile = open(outfilename, 'w') # Ignore any warnings - temporary fix for no schemaLocation w/ namespace with warnings.catch_warnings(): warnings.simplefilter("ignore") outfile.write(stix_package.to_xml()) warnings.resetwarnings() outfile.flush() outfile.close() except Exception, err: print('\nError: %s\n' % str(err)) traceback.print_exc()
def to_stix(infile): """Converts the `infile` OpenIOC xml document into a STIX Package. Args: infile: OpenIOC xml filename to translate Returns: stix.core.STIXPackage object """ observables = to_cybox(infile) # Build Indicators from the Observable objects indicators = [_observable_to_indicator_stix(o) for o in observables] # Wrap the created Observables in a STIX Package/Indicator stix_package = STIXPackage() # Set the Indicators collection stix_package.indicators = indicators # Create and write the STIX Header. Warning: these fields have been # deprecated in STIX v1.2! stix_header = STIXHeader() stix_header.package_intent = PackageIntent.TERM_INDICATORS_MALWARE_ARTIFACTS stix_header.description = "CybOX-represented Indicators Translated from OpenIOC File" stix_package.stix_header = stix_header 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 main(): # Create our CybOX Simple Hash Value shv = Hash() shv.simple_hash_value = "4EC0027BEF4D7E1786A04D021FA8A67F" # Create a CybOX File Object and add the Hash we created above. f = File() h = Hash(shv, Hash.TYPE_MD5) f.add_hash(h) # Create the STIX Package stix_package = STIXPackage() # Create the STIX Header and add a description. stix_header = STIXHeader() stix_header.description = "Simple File Hash Observable Example" stix_package.stix_header = stix_header # Add the File Hash Observable to the STIX Package. The add() method will # inspect the input and add it to the top-level stix_package.observables # collection. stix_package.add(f) # Print the XML! print(stix_package.to_xml())
def buildSTIX(ident,confid,restconfid, effect, resteffect,typeIncident,resttype,asset,restasset,hashPkg): # IMPLEMENTATION WORKAROUND - # restConfid --> header.description # resteffect --> breach.description # resttype --> reporter.description # restasset --> reporter.identity.name # setup stix document stix_package = STIXPackage() stix_header = STIXHeader() stix_header.description = restconfid # "Example description" stix_package.stix_header = stix_header # add incident and confidence breach = Incident(id_=ident) breach.description = resteffect # "Intrusion into enterprise network" breach.confidence = Confidence() breach.confidence.value=confid breach._binding_class.xml_type = typeIncident # stamp with reporter breach.reporter = InformationSource() breach.reporter.description = resttype #"The person who reported it" breach.reporter.time = Time() breach.reporter.time.produced_time = datetime.strptime("2014-03-11","%Y-%m-%d") # when they submitted it breach.reporter.identity = Identity() breach.reporter.identity.name = restasset # "Sample Investigations, LLC" # set incident-specific timestamps breach.time = incidentTime() breach.title = "Breach of CyberTech Dynamics" breach.time.initial_compromise = datetime.strptime("2012-01-30", "%Y-%m-%d") breach.time.incident_discovery = datetime.strptime("2012-05-10", "%Y-%m-%d") breach.time.restoration_achieved = datetime.strptime("2012-08-10", "%Y-%m-%d") breach.time.incident_reported = datetime.strptime("2012-12-10", "%Y-%m-%d") # add the impact #impact = ImpactAssessment() #impact.add_effect("Unintended Access") #breach.impact_assessment = impact affected_asset = AffectedAsset() affected_asset.description = "Database server at hr-data1.example.com" affected_asset.type_ = asset breach.affected_assets = affected_asset #print("asset type: %s"%(breach.affected_assets[0].type_)) # add the victim breach.add_victim (hashPkg) # add the impact impact = ImpactAssessment() impact.add_effect(effect) breach.impact_assessment = impact stix_package.add_incident(breach) #print("hey, I've got an incident! list size=%s"%(len(stix_package._incidents))) # Print the XML! #print(stix_package.to_xml()) return stix_package
def init_stix(self): stix_package = STIXPackage() stix_header = STIXHeader() info_source = InformationSource() info_source.description = 'HAR file analysis of visit to malicious URL' stix_header.information_source = info_source 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() 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 build_stix( input_dict ): # setup stix document stix_package = STIXPackage() stix_header = STIXHeader() stix_header.description = "Incident report for " + input_dict['organization'] stix_header.add_package_intent ("Incident") # Add handling requirements if needed if input_dict['sensitive'] == "True": mark = SimpleMarkingStructure() mark.statement = "Sensitive" mark_spec = MarkingSpecification() mark_spec.marking_structures.append(mark) stix_header.handling = Marking(mark_spec) stix_package.stix_header = stix_header # add incident and confidence incident = Incident() incident.description = input_dict['description'] incident.confidence = input_dict['confidence'] # add incident reporter incident.reporter = InformationSource() incident.reporter.description = "Person who reported the incident" incident.reporter.time = Time() incident.reporter.time.produced_time = datetime.strptime(input_dict['timestamp'], "%Y-%m-%d") # when they submitted it incident.reporter.identity = Identity() incident.reporter.identity.name = input_dict['submitter'] # incident time is a complex object with support for a bunch of different "when stuff happened" items incident.time = incidentTime() incident.title = "Breach of " + input_dict['organization'] incident.time.incident_discovery = datetime.strptime(input_dict['timestamp'], "%Y-%m-%d") # when they submitted it # add the impact impact = ImpactAssessment() impact.add_effect(input_dict['damage']) incident.impact_assessment = impact #Add the thing that was stolen jewels = AffectedAsset() jewels.type_ = input_dict['asset'] incident.add_affected_asset (jewels) # add the victim incident.add_victim (input_dict['organization']) stix_package.add_incident(incident) return stix_package
def export_stix(iocs): """ Export the tagged items in STIX format. BROKE! """ observables_doc = None stix_package = STIXPackage() stix_header = STIXHeader() stix_header.description = filename stix_package.stix_header = stix_header for ioc in iocs['md5']: observable = cybox_helper.create_file_hash_observable('', value) observables.append(observable) stix_package.add_observable(observable) indicators.append(value) if t == 'ipv4': if not value in indicators: observable = cybox_helper.create_ipv4_observable(value) observables.append(observable) stix_package.add_observable(observable) indicators.append(value) elif t == 'domain': if not value in indicators: observable = cybox_helper.create_domain_name_observable(value) observables.append(observable) stix_package.add_observable(observable) indicators.append(value) elif t == 'url': if not value in indicators: observable = cybox_helper.create_url_observable(value) observables.append(observable) stix_package.add_observable(observable) indicators.append(value) elif t == 'email': if not value in indicators: observable = cybox_helper.create_email_address_observable(value) observables.append(observable) stix_package.add_observable(observable) indicators.append(value) if len(observables) > 0: if not filename.endswith('.xml'): filename = "%s.xml" % filename #add .xml extension if missing # end if with open(filename, "wb") as f: stix_xml = stix_package.to_xml() f.write(stix_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 main(): stix_package = STIXPackage() stix_header = STIXHeader() # Add tool information stix_header.information_source = InformationSource() stix_header.information_source.tools = ToolInformationList() stix_header.information_source.tools.append(ToolInformation("python-stix ex_04.py", "The MITRE Corporation")) stix_header.description = "Example " stix_package.stix_header = stix_header print(stix_package.to_xml()) print(stix_package.to_dict())
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 main(): infilename = '' outfilename = '' #Get the command-line arguments args = sys.argv[1:] if len(args) < 4: usage() sys.exit(1) for i in range(0,len(args)): if args[i] == '-i': infilename = args[i+1] elif args[i] == '-o': outfilename = args[i+1] if os.path.isfile(infilename): try: # Perform the translation using the methods from the OpenIOC to CybOX Script openioc_indicators = openioc.parse(infilename) observables_obj = openioc_to_cybox.generate_cybox(openioc_indicators, infilename, True) observables_cls = Observables.from_obj(observables_obj) # Wrap the created Observables in a STIX Package/Indicator stix_package = STIXPackage() for observable in observables_cls.observables: indicator_dict = {} producer_dict = {} producer_dict['tools'] = [{'name':'OpenIOC to STIX Utility', 'version':str(__VERSION__)}] indicator_dict['producer'] = producer_dict indicator_dict['title'] = "CybOX-represented Indicator Created from OpenIOC File" indicator = Indicator.from_dict(indicator_dict) indicator.add_observable(observables_cls.observables[0]) stix_package.add_indicator(indicator) # Create and write the STIX Header stix_header = STIXHeader() stix_header.package_intent = "Indicators - Malware Artifacts" stix_header.description = "CybOX-represented Indicators Translated from OpenIOC File" stix_package.stix_header = stix_header # Write the generated STIX Package as XML to the output file outfile = open(outfilename, 'w') outfile.write(stix_package.to_xml()) outfile.flush() outfile.close() except Exception, err: print('\nError: %s\n' % str(err)) traceback.print_exc()
def stix(self): """Output data as STIX. STIX is highly subjective and difficult to format without getting more data from the user. Passive DNS results are formtted into a STIX watchlist with descriptions and other details about the record. :return: STIX formatted watchlist """ if python3: raise RuntimeError("STIX is not supported when using Python 3 due to dependency libraries.") stix_package = STIXPackage() stix_header = STIXHeader() stix_header.description = "Passive DNS resolutions associated" \ " with %s during the time periods of " \ " %s - %s" % (self.queryValue, self.firstSeen, self.lastSeen) stix_package.stix_header = stix_header for record in self._records: indicator = Indicator( title="Observed from %s - %s" % ( record.firstSeen, record.lastSeen ), short_description="Resolution observed by %s." % ( ','.join(record.source) ), description="Passive DNS data collected and aggregated from" \ " PassiveTotal services." ) if is_ip(record.resolve): indicator.add_indicator_type('IP Watchlist') ioc = Address( address_value=record.resolve, category=Address.CAT_IPV4 ) else: indicator.add_indicator_type('Domain Watchlist') ioc = DomainName(value=record.resolve) ioc.condition = "Equals" indicator.add_observable(ioc) stix_package.add_indicator(indicator) output = stix_package.to_xml() return output
def main(): shv = Hash() shv.simple_hash_value = "4EC0027BEF4D7E1786A04D021FA8A67F" f = File() h = Hash(shv, Hash.TYPE_MD5) f.add_hash(h) stix_package = STIXPackage() stix_header = STIXHeader() stix_header.description = "Example 03" stix_package.stix_header = stix_header stix_package.add_observable(f) print(stix_package.to_xml())
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 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 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 build_stix( ): # setup stix document stix_package = STIXPackage() stix_header = STIXHeader() stix_header.description = "Sample breach report" stix_header.add_package_intent ("Incident") stix_package.stix_header = stix_header # add incident and confidence breach = Incident() breach.description = "Intrusion into enterprise network" breach.confidence = "High" # stamp with reporter breach.reporter = InformationSource() breach.reporter.description = "The person who reported it" breach.reporter.time = Time() breach.reporter.time.produced_time = datetime.strptime("2014-03-11","%Y-%m-%d") # when they submitted it breach.reporter.identity = Identity() breach.reporter.identity.name = "Sample Investigations, LLC" # set incident-specific timestamps breach.time = incidentTime() breach.title = "Breach of Cyber Tech Dynamics" breach.time.initial_compromise = datetime.strptime("2012-01-30", "%Y-%m-%d") breach.time.incident_discovery = datetime.strptime("2012-05-10", "%Y-%m-%d") breach.time.restoration_achieved = datetime.strptime("2012-08-10", "%Y-%m-%d") breach.time.incident_reported = datetime.strptime("2012-12-10", "%Y-%m-%d") # add the impact impact = ImpactAssessment() impact.add_effect("Unintended Access") breach.impact_assessment = impact # add the victim breach.add_victim ("Cyber Tech Dynamics") stix_package.add_incident(breach) 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 build_stix( ): # setup stix document stix_package = STIXPackage() stix_header = STIXHeader() stix_header.description = "Sample breach report" stix_header.add_package_intent ("Incident") stix_package.stix_header = stix_header # add incident and confidence breach = Incident() breach.description = "Intrusion into enterprise network" breach.confidence = "High" # stamp with reporter breach.reporter = InformationSource() breach.reporter.description = "The person who reported it" breach.reporter.time = Time() breach.reporter.time.produced_time = datetime.strptime("2014-03-11","%Y-%m-%d") # when they submitted it breach.reporter.identity = Identity() breach.reporter.identity.name = "Sample Investigations, LLC" # incident time is a complex object with support for a bunch of different "when stuff happened" items breach.time = incidentTime() breach.title = "Breach of Canary Corp" breach.time.incident_discovery = datetime.strptime("2013-01-13", "%Y-%m-%d") # when they submitted it # add the impact impact = ImpactAssessment() impact.add_effect("Financial Loss") breach.impact_assessment = impact # add the victim breach.add_victim ("Canary Corp") stix_package.add_incident(breach) return stix_package
def main(): f = File() # This automatically detects that it's an MD5 hash based on the length f.add_hash("4EC0027BEF4D7E1786A04D021FA8A67F") indicator = Indicator() indicator.title = "File Hash Example" indicator.description = "An indicator containing a File observable with an associated hash" indicator.set_producer_identity("The MITRE Corporation") indicator.set_produced_time(datetime.now(tzutc())) indicator.add_object(f) stix_package = STIXPackage() stix_header = STIXHeader() stix_header.description = "Example " stix_package.stix_header = stix_header stix_package.add_indicator(indicator) print(stix_package.to_xml())
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 to_stix(obj, items_to_convert=[], loaded=False, bin_fmt="raw"): """ Converts a CRITs object to a STIX document. The resulting document includes standardized representations of all related objects noted within items_to_convert. :param items_to_convert: The list of items to convert to STIX/CybOX :type items_to_convert: Either a list of CRITs objects OR a list of {'_type': CRITS_TYPE, '_id': CRITS_ID} dicts :param loaded: Set to True if you've passed a list of CRITs objects as the value for items_to_convert, else leave False. :type loaded: bool :param bin_fmt: Specifies the format for Sample data encoding. Options: None (don't include binary data in STIX output), "raw" (include binary data as is), "base64" (base64 encode binary data) :returns: A dict indicating which items mapped to STIX indicators, ['stix_indicators'] which items mapped to STIX observables, ['stix_observables'] which items are included in the resulting STIX doc, ['final_objects'] and the STIX doc itself ['stix_obj']. """ from cybox.common import Time, ToolInformationList, ToolInformation from stix.common import StructuredText, InformationSource from stix.core import STIXPackage, STIXHeader from stix.common.identity import Identity # These lists are used to determine which CRITs objects # go in which part of the STIX document. ind_list = ['Indicator'] obs_list = [ 'Certificate', 'Domain', 'Email', 'IP', 'PCAP', 'RawData', 'Sample' ] actor_list = ['Actor'] # Store message stix_msg = { 'stix_incidents': [], 'stix_indicators': [], 'stix_observables': [], 'stix_actors': [], 'final_objects': [] } if not loaded: # if we have a list of object metadata, load it before processing items_to_convert = [ class_from_id(item['_type'], item['_id']) for item in items_to_convert ] # add self to the list of items to STIXify if obj not in items_to_convert: items_to_convert.append(obj) # add any email attachments attachments = [] for obj in items_to_convert: if obj._meta['crits_type'] == 'Email': for rel in obj.relationships: if rel.relationship == 'Contains': atch = class_from_id('Sample', rel.object_id) if atch not in items_to_convert: attachments.append(atch) items_to_convert.extend(attachments) # grab ObjectId of items refObjs = {key.id: 0 for key in items_to_convert} relationships = {} stix = [] from stix.indicator import Indicator as S_Ind for obj in items_to_convert: obj_type = obj._meta['crits_type'] if obj_type == class_from_type('Event')._meta['crits_type']: stx, release = to_stix_incident(obj) stix_msg['stix_incidents'].append(stx) elif obj_type in ind_list: # convert to STIX indicators stx, releas = to_stix_indicator(obj) stix_msg['stix_indicators'].append(stx) refObjs[obj.id] = S_Ind(idref=stx.id_) elif obj_type in obs_list: # convert to CybOX observable if obj_type == class_from_type('Sample')._meta['crits_type']: stx, releas = to_cybox_observable(obj, bin_fmt=bin_fmt) else: stx, releas = to_cybox_observable(obj) # wrap in stix Indicator ind = S_Ind() for ob in stx: ind.add_observable(ob) ind.title = "CRITs %s Top-Level Object" % obj_type ind.description = ("This is simply a CRITs %s top-level " "object, not actually an Indicator. " "The Observable is wrapped in an Indicator" " to facilitate documentation of the " "relationship." % obj_type) ind.confidence = 'None' stx = ind stix_msg['stix_indicators'].append(stx) refObjs[obj.id] = S_Ind(idref=stx.id_) elif obj_type in actor_list: # convert to STIX actor stx, releas = to_stix_actor(obj) stix_msg['stix_actors'].append(stx) # get relationships from CRITs objects for rel in obj.relationships: if rel.object_id in refObjs: relationships.setdefault(stx.id_, {}) relationships[stx.id_][rel.object_id] = ( rel.relationship, rel.rel_confidence.capitalize(), rel.rel_type) stix_msg['final_objects'].append(obj) stix.append(stx) # set relationships on STIX objects for stix_obj in stix: for rel in relationships.get(stix_obj.id_, {}): if isinstance(refObjs.get(rel), S_Ind): # if is STIX Indicator stix_obj.related_indicators.append(refObjs[rel]) rel_meta = relationships.get(stix_obj.id_)[rel] stix_obj.related_indicators[-1].relationship = rel_meta[0] stix_obj.related_indicators[-1].confidence = rel_meta[1] # Add any Email Attachments to CybOX EmailMessage Objects if isinstance(stix_obj, S_Ind): if 'EmailMessage' in stix_obj.observable.object_.id_: if rel_meta[0] == 'Contains' and rel_meta[ 2] == 'Sample': email = stix_obj.observable.object_.properties email.attachments.append(refObjs[rel].idref) tool_list = ToolInformationList() tool = ToolInformation("CRITs", "MITRE") tool.version = settings.CRITS_VERSION tool_list.append(tool) i_s = InformationSource(time=Time(produced_time=datetime.now()), identity=Identity(name=settings.COMPANY_NAME), tools=tool_list) if obj._meta['crits_type'] == "Event": stix_desc = obj.description() stix_int = obj.event_type() stix_title = obj.title() else: stix_desc = "STIX from %s" % settings.COMPANY_NAME stix_int = "Collective Threat Intelligence" stix_title = "Threat Intelligence Sharing" header = STIXHeader(information_source=i_s, description=StructuredText(value=stix_desc), package_intents=[stix_int], title=stix_title) stix_msg['stix_obj'] = STIXPackage(incidents=stix_msg['stix_incidents'], indicators=stix_msg['stix_indicators'], threat_actors=stix_msg['stix_actors'], stix_header=header, id_=uuid.uuid4()) return stix_msg
def create_stix_file(): # List of indicators to be deduped hostnames = [] ips = [] urls = [] md5s = [] sha1s = [] # Set namespace NAMESPACE = {PRODUCER_URL: PRODUCER_NAME} set_id_namespace(NAMESPACE) # JSON load the POSTed request data try: data_recv = request.data data = json.loads(data_recv) except: return make_response( jsonify({'Error': "Unable to decode json object"}), 400) # Parse the JSON object try: # Get MD5 of sample malware_sample = data['alert']['explanation']['malware-detected'][ 'malware'] count = 0 sample_hash = "" try: for entry in malware_sample: if "md5sum" in malware_sample[count]: sample_hash = malware_sample[count]['md5sum'] count += 1 except: if "md5sum" in malware_sample: sample_hash = malware_sample['md5sum'] # If all else fails if sample_hash == "": sample_hash = "Unknown" # Indicators # Domains domain_indicator = Indicator() domain_indicator.title = "Malware Artifacts - Domain" domain_indicator.type = "Malware Artifacts" domain_indicator.description = ( "Domains derived from sandboxed malware sample. MD5 Hash: " + sample_hash) domain_indicator.short_description = ("Domainss from " + sample_hash) domain_indicator.set_producer_identity(PRODUCER_NAME) domain_indicator.set_produced_time(utils.dates.now()) domain_indicator.indicator_types.append("Domain Watchlist") # IPs ip_indicator = Indicator() ip_indicator.title = "Malware Artifacts - IP" ip_indicator.description = ( "IPs derived from sandboxed malware sample. MD5 Hash: " + sample_hash) ip_indicator.short_description = ("IPs from " + sample_hash) ip_indicator.set_producer_identity(PRODUCER_NAME) ip_indicator.set_produced_time(utils.dates.now()) ip_indicator.indicator_types.append("IP Watchlist") # URLs url_indicator = Indicator() url_indicator.title = "Malware Artifacts - URL" url_indicator.description = ( "URLs derived from sandboxed malware sample. MD5 Hash: " + sample_hash) url_indicator.short_description = ("URLs from " + sample_hash) url_indicator.set_producer_identity(PRODUCER_NAME) url_indicator.set_produced_time(utils.dates.now()) url_indicator.indicator_types.append("URL Watchlist") # Hashs hash_indicator = Indicator() hash_indicator.title = "Malware Artifacts - File Hash" hash_indicator.description = ( "File hashes derived from sandboxed malware sample. MD5 Hash: " + sample_hash) hash_indicator.short_description = ("Hash from " + sample_hash) hash_indicator.set_producer_identity(PRODUCER_NAME) hash_indicator.set_produced_time(utils.dates.now()) hash_indicator.indicator_types.append("File Hash Watchlist") # Create a STIX Package stix_package = STIXPackage() # Create the STIX Header and add a description. stix_header = STIXHeader({"Indicators - Malware Artifacts"}) stix_header.description = PRODUCER_NAME + ": FireEye Sample ID " + str( data['alert']['id']) stix_package.stix_header = stix_header if "network" in data['alert']['explanation']['os-changes']: # Add indicators for network for entry in data['alert']['explanation']['os-changes']['network']: if "hostname" in entry: hostnames.append(entry['hostname']) if "ipaddress" in entry: ips.append(entry['ipaddress']) if "http_request" in entry: domain = re.search('~~Host:\s(.*?)~~', entry['http_request']) url = re.search('^.*\s(.*?)\sHTTP', entry['http_request']) if domain: domain_name = domain.group(1) if url: url_string = url.group(1) urls.append(domain_name + url_string) # Add indicators for files for entry in data['alert']['explanation']['os-changes']['network']: if "md5sum" in entry['processinfo']: filename = re.search('([\w-]+\..*)', entry['processinfo']['imagepath']) if filename: md5s.append((filename.group(1), entry['processinfo']['md5sum'])) if "process" in data['alert']['explanation']['os-changes']: # Add indicators from process for entry in data['alert']['explanation']['os-changes']['process']: if "md5sum" in entry: filename = re.search('([\w-]+\..*)', entry['value']) if filename: md5s.append((filename.group(1), entry['md5sum'])) if "sha1sum" in entry: filename = re.search('([\w-]+\..*)', entry['value']) if filename: sha1s.append((filename.group(1), entry['sha1sum'])) # Dedupe lists for hostname in set(hostnames): hostname_observable = create_domain_name_observable(hostname) domain_indicator.add_observable(hostname_observable) for ip in set(ips): ip_observable = create_ipv4_observable(ip) ip_indicator.add_observable(ip_observable) for url in set(urls): url_observable = create_url_observable(url) url_indicator.add_observable(url_observable) for hash in set(md5s): hash_observable = create_file_hash_observable(hash[0], hash[1]) hash_indicator.add_observable(hash_observable) for hash in set(sha1s): hash_observable = create_file_hash_observable(hash[0], hash[1]) hash_indicator.add_observable(hash_observable) # Add those to the package stix_package.add(domain_indicator) stix_package.add(ip_indicator) stix_package.add(url_indicator) stix_package.add(hash_indicator) # Save to file save_as = SAVE_DIRECTORY + "/fireeye_" + str( data['alert']['id']) + ".xml" f = open(save_as, 'w') f.write(stix_package.to_xml()) f.close # Return success response return make_response( jsonify({'Success': "STIX document succesfully generated"}), 200) # Unable to parse object except: return make_response(jsonify({'Error': "Unable to parse JSON object"}), 400)
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()') ### 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
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 main(): # define constants TI_REQUEST_URL = "https://api.intelgraph.idefense.com/rest/threatindicator/v0" # iDefense API Key # To avoid hard-coding creds, I'm using environment variables if os.environ.get('IDEF_TOKEN') is None: print( "error: please store your iDefense IntelGraph API key in the IDEF_TOKEN environment" ) sys.exit(1) API_KEY = os.environ.get('IDEF_TOKEN') API_SECRET = '' # TODO: use command-line parameter timestr = datetime.datetime.utcnow() - datetime.timedelta(days=1) LAST_IMPORT = timestr.strftime("%Y-%m-%dT%H:%M:%S") + ".000Z" HEADERS = { "Content-Type": "application/json", "auth-token": API_KEY, "X-Api-Key-Proof": API_SECRET } print(HEADERS) page = 1 more_data = True count = 0 # Set namespace NAMESPACE = Namespace("https://intelgraph.idefense.com", "idefense") set_id_namespace(NAMESPACE) # Create STIX Package stix_package = STIXPackage() stix_header = STIXHeader() stix_header.description = "iDefense Threat Indicators Feed" stix_package.stix_header = stix_header ttps = {} malware = {} try: while more_data: request_payload = { "start_date": LAST_IMPORT, "page_size": 200, "page": page } r = requests.post(TI_REQUEST_URL, headers=HEADERS, data=json.dumps(request_payload)) print(r) response = [] if r.status_code == requests.codes.ok: try: # Read in response as json response = r.json() except (ValueError, KeyError): print("Response couldn't be decoded :(") more_data = False continue more_data = response.get('more', 'False') print("Page %d ==> %s (%s)" % (page, response['more'], response['total_size'])) page += 1 # Iterate the response for indicatorD in response['results']: count += 1 # Indicator value such as the value of the IP/Domain/URL indicator = indicatorD.get('key') print(indicator, indicatorD.get('type')) if indicatorD.get('last_seen_as') is None: last_seen_as = 'UNKNOWN' else: last_seen_as = ''.join(indicatorD.get('last_seen_as')) # Identify TTP if last_seen_as not in ttps: ttps[last_seen_as] = TTP(title=last_seen_as) stix_package.add_ttp(ttps[last_seen_as]) # Identify malware source if 'files' in indicatorD: for hashD in indicatorD['files']: md5 = hashD.get('key') # Malware Family classification of the hash if available if hashD.get('malware_family') is None: malware_family = "Unknown" else: malware_family = ''.join( hashD.get('malware_family')) if md5 not in malware: malware[md5] = add_malware( md5, malware_family, hashD.get('uuid')) if indicatorD.get('type') == "url": # Create indicator indicator = Indicator( id_="indicator-{0}".format(indicatorD.get('uuid')), title=''.join(indicatorD.get('malware_family')), timestamp=indicatorD.get('last_seen')) indicator.add_indicator_type("URL Watchlist") # Populate URL url = URI() url.value = indicatorD.get('key') url.type_ = URI.TYPE_URL url.value.condition = "Equals" indicator.add_observable(url) elif indicatorD.get('type') == "domain": # Populate domain name indicator = Indicator( id_="indicator-{0}".format(indicatorD.get('uuid')), title=''.join(indicatorD.get('malware_family')), timestamp=indicatorD.get('last_seen')) indicator.add_indicator_type("Domain Watchlist") domain = DomainName() domain.value = indicatorD.get('key') domain.value.condition = "Equals" indicator.add_observable(domain) elif indicatorD.get('type') == "ip": # Create indicator indicator = Indicator( id_="indicator-{0}".format(indicatorD.get('uuid')), title=indicatorD.get('malware_family'), timestamp=indicatorD.get('last_seen')) indicator.add_indicator_type("IP Watchlist") # Populate IP address addr = Address(address_value=indicatorD.get('key'), category=Address.CAT_IPV4) addr.condition = "Equals" indicator.add_observable(addr) # Link TTP indicator.add_indicated_ttp( TTP(idref=ttps[last_seen_as].id_)) # Indicate confidence score indicator.confidence = Confidence( value=VocabString(indicatorD.get('confidence'))) # Add related indicator to malware indicator.add_related_indicator(malware[md5]) # Add to package stix_package.add_indicator(indicator) else: print("API request couldn't be fulfilled due status code: %d" % r.status_code) more_data = False except requests.exceptions.ConnectionError as e: print("Check your network connection\n %s" % str(e)) except requests.exceptions.HTTPError as e: print("Bad HTTP response\n %s" % str(e)) except Exception as e: print("Uncaught exception\n %s" % str(e)) # Output to XML with open('stix-1.2.1.xml', 'wb') as f: f.write(stix_package.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() # 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 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 doCuckoo(results): malfilename = "" # memstrings = [] print "json dumps %s" % (json.dumps(results['target'])) try: fileitems = results['target']['file'] malfilename = fileitems['name'] malfilesize = fileitems['size'] malmd5 = fileitems['md5'] malsha1 = fileitems['sha1'] malsha256 = fileitems['sha256'] malsha512 = fileitems['sha512'] malssdeep = fileitems['ssdeep'] malfiletype = fileitems["type"] # MD54K - From Chris Hudel malmd54k = doMD54K(fileitems['path']) # memfile = fileitems['path'][0:len(fileitems['path']) - 64] + "../analyses/" + str(results['info']['id']) + "/memory.dmp" # memstrings = doStrings(stringscmd(memfile)) except: fileitems = [] pass staticitems = results['static'] # info = results['info'] # Suspicious PE imports iocimports = [] try: for imports in staticitems['pe_imports']: for item in imports['imports']: if item['name'] in suspiciousimports: iocimports.append(item['name']) except: pass #rsrcentries = [] # PE sectionis badpesections = [] try: for sections in staticitems['pe_sections']: if sections['name'] not in goodpesections: badpesection = [ sections['name'], sections['size_of_data'], str(sections['entropy']) ] badpesections.append(badpesection) except: pass # PE Exports iocexports = [] try: for exportfunc in staticitems['pe_exports']: iocexports.append(exportfunc['name']) except: pass # PE Version Info versioninfo = dict.fromkeys(['LegalCopyright', 'InternalName', 'FileVersion', 'CompanyName', 'PrivateBuild', \ 'LegalTrademarks', 'Comments', 'ProductName', 'SpecialBuild', 'ProductVersion', \ 'FileDescription', 'OriginalFilename']) if 'pe_versioninfo' in staticitems: for item in staticitems['pe_versioninfo']: if item['name'] in versioninfo: versioninfo[item['name']] = item['value'] # Dropped files droppedfiles = [] try: for droppedfile in results['dropped']: droppedfiles.append([droppedfile['name'], droppedfile['size'], droppedfile['md5'], droppedfile['sha1'], \ droppedfile['sha256'], droppedfile['sha512']]) except: pass # Hosts contacted. This will exclude # localhost, broadcast and any other 'noise' # as indicated by excludedips hosts = [] try: for host in results['network']['hosts']: if host not in excludedips: hosts.append(host) except: pass # Mutexes mutexes = [] try: for mutex in results['behavior']['summary']['mutexes']: mutexes.append(mutex) except: pass # Processes processes = [] try: for process in results['behavior']['processes']: processes.append([ process['process_name'], process['process_id'], process['parent_id'] ]) except: pass # grab the string results # currently these are simple # regexes for IPv4 addresses and # emails strings = doStrings(results['strings']) # Registry Keys # This uses modified cuckoo source code to only # pull the Registry keys created, instead # of those created OR just opened regkeys = results['behavior']['summary']['keys'] # Create our metadata dictionary for getting the # metadata values int the IOC metadata = {'malfilename':malfilename, 'malmd5':malmd5, 'malsha1':malsha1, 'malsha256':malsha256, 'malsha512':malsha512, \ 'malmd54k':malmd54k, 'malfilesize':malfilesize, 'malssdeep':malssdeep, 'malfiletype':malfiletype, \ 'iocexports':iocexports, 'iocimports':iocimports, 'badpesections':badpesections, 'versioninfo':versioninfo} dynamicindicators = { "droppedfiles": droppedfiles, "processes": processes, "regkeys": regkeys, 'mutexes': mutexes, 'hosts': hosts } stix_package = STIXPackage() stix_header = STIXHeader() desc = "IOCAware Auto-Generated IOC Document" if len(malfilename) > 0: desc += " " + malfilename stix_header.description = desc stix_header.information_source = InformationSource() stix_header.information_source.time = Time() stix_header.information_source.time.produced_time = datetime.now() stix_package.stix_header = stix_header #wfe = createMetaData(stix_package, metadata) #addStrings(stix_package, wfe, strings) createMetaData(stix_package, metadata, strings) createDynamicIndicators(stix_package, dynamicindicators) filename = IOCLOCATION + "/iocaware_stix_" + str(uuid.uuid4()) + ".xml" stixfile = open(filename, "w") stixfile.write(stix_package.to_xml())
def test_to_xml_no_encoding(self): s = STIXHeader() s.title = UNICODE_STR xml = s.to_xml(encoding=None) self.assertTrue(isinstance(xml, text_type)) self.assertTrue(UNICODE_STR in xml)
def main(argv): ###################################################################### # Se non impostati da command line vengono utilizzati i seguenti valori per TITLE, DESCRIPTION, IDENTITY # Il title e' ID univoco della minaccia (es. Cobalt / Danabot / APT28) TITLE = "Test" # La description strutturiamola come segue # <IOC PRODUCER> - <Descrizione della minaccia/campagna> - <URL (if any)> DESCRIPTION = "Cyber Saiyan - Test - https://infosharing.cybersaiyan.it" # La sorgente che ha generato l'IoC con riferimento a Cyber Saiyan Community IDENTITY = "Cyber Saiyan Community" # File degli IoC IOCFILE = "CS-ioc.txt" # Prefisso STIX output files STIX 1.2 e STIX 2 OUTFILEPREFIX = "package" # Short Description - UNUSED SHORT = "unused" ###################################################################### VERBOSE = 0 # Parse ARGV[] try: opts, args = getopt.getopt(argv, "ht:d:i:f:o:v") except getopt.GetoptError: print( "CS_build_stix-from_files.py [-t TITLE] [-d DESCRIPTION] [-i IDENTITY] [-f IOC_FILE] [-o STIX_FILES_PREFIX]") sys.exit(2) for opt, arg in opts: if opt == "-h": print( "CS_build_stix-from_files.py [-t TITLE] [-d DESCRIPTION] [-i IDENTITY] [-f IOC_FILE] [-o STIX_FILES_PREFIX]") sys.exit() elif opt == "-t": TITLE = arg elif opt == "-d": DESCRIPTION = arg elif opt == "-i": IDENTITY = arg elif opt == "-f": IOCFILE = arg elif opt == "-o": OUTFILEPREFIX = arg elif opt == "-v": VERBOSE = 1 print("---------------------") print("TITLE: " + TITLE) print("DESCRIPTION: " + DESCRIPTION) print("IDENTITY: " + IDENTITY) print("IOC FILE: " + IOCFILE) print("---------------------") ######################## # Commond data timestamp = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S") ######################## # Build STIX 1.2 file info_src = InformationSource() info_src.identity = Identity(name=IDENTITY) NAMESPACE = Namespace("https://infosharing.cybersaiyan.it", "CYBERSAIYAN") set_id_namespace(NAMESPACE) wrapper = STIXPackage() marking_specification = MarkingSpecification() marking_specification.controlled_structure = "//node() | //@*" tlp = TLPMarkingStructure() tlp.color = "white" marking_specification.marking_structures.append(tlp) handling = Marking() handling.add_marking(marking_specification) wrapper.stix_header = STIXHeader(information_source=info_src, title=TITLE, description=DESCRIPTION, short_description=SHORT) wrapper.stix_header.handling = handling # HASH indicators indicatorHASH = Indicator() indicatorHASH.title = TITLE + " - HASH" indicatorHASH.add_indicator_type("File Hash Watchlist") # DOMAIN indicators indiDOMAIN = Indicator() indiDOMAIN.title = TITLE + " - DOMAIN" indiDOMAIN.add_indicator_type("Domain Watchlist") # URL indicators indiURL = Indicator() indiURL.title = TITLE + " - URL" indiURL.add_indicator_type("URL Watchlist") # IP indicators indiIP = Indicator() indiIP.title = TITLE + " - IP" indiIP.add_indicator_type("IP Watchlist") # EMAIL indicators indiEMAIL = Indicator() indiEMAIL.title = TITLE + " - EMAIL" indiEMAIL.add_indicator_type("Malicious E-mail") ######################## # Build STIX 2 file pattern_sha256 = [] pattern_md5 = [] pattern_sha1 = [] pattern_domain = [] pattern_url = [] pattern_ip = [] pattern_email = [] # Marking marking_def_white = stix2.TLP_WHITE # campagna # [TODO] aggiungere tutti i campi dello STIX 1.2 (es. IDENTITY) campaign_MAIN = stix2.Campaign( created=timestamp, modified=timestamp, name=TITLE, description=DESCRIPTION, first_seen=timestamp, objective="TBD" ) ######################## # Read IoC file loaddata(IOCFILE) if (VERBOSE): print("Reading IoC file " + IOCFILE + "...") ioccount = 0 # sha256 for ioc in listSHA256: # STIX 1.2 filei = File() filei.add_hash(Hash(ioc)) obsi = Observable(filei) indicatorHASH.add_observable(obsi) if (VERBOSE): print("SHA256: " + ioc) ioccount += 1 # STIX 2 pattern_sha256.append("[file:hashes.'SHA-256' = '" + ioc + "'] OR ") # md5 for ioc in listMD5: # STIX 1.2 filej = File() filej.add_hash(Hash(ioc)) obsj = Observable(filej) indicatorHASH.add_observable(obsj) if (VERBOSE): print("MD5: " + ioc) ioccount += 1 # STIX 2 pattern_md5.append("[file:hashes.'MD5' = '" + ioc + "'] OR ") # sha1 for ioc in listSHA1: # STIX 1.2 filek = File() filek.add_hash(Hash(ioc)) obsk = Observable(filek) indicatorHASH.add_observable(obsk) if (VERBOSE): print("SHA1: " + ioc) ioccount += 1 # STIX 2 pattern_sha1.append("[file:hashes.'SHA1' = '" + ioc + "'] OR ") # domains for ioc in listDOMAIN: # STIX 1.2 url = URI() url.value = ioc url.type_ = URI.TYPE_DOMAIN url.condition = "Equals" obsu = Observable(url) indiDOMAIN.add_observable(obsu) if (VERBOSE): print("DOMAIN: " + ioc) ioccount += 1 # STIX 2 pattern_domain.append("[domain-name:value = '" + ioc + "'] OR ") # url for ioc in listURL: # STIX 1.2 url = URI() url.value = ioc url.type_ = URI.TYPE_URL url.condition = "Equals" obsu = Observable(url) indiURL.add_observable(obsu) if (VERBOSE): print("URL: " + ioc) ioccount += 1 # STIX 2 pattern_url.append("[url:value = '" + ioc + "'] OR ") # ip for ioc in listIP: # STIX 1.2 ip = Address() ip.address_value = ioc obsu = Observable(ip) indiIP.add_observable(obsu) if (VERBOSE): print("IP: " + ioc) ioccount += 1 # STIX 2 pattern_ip.append("[ipv4-addr:value = '" + ioc + "'] OR ") # email for ioc in listEMAIL: # STIX 1.2 email = EmailAddress() email.address_value = ioc obsu = Observable(email) indiEMAIL.add_observable(obsu) if (VERBOSE): print("Email: " + ioc) ioccount += 1 # STIX 2 pattern_email.append("[email-message:from_ref.value = '" + ioc + "'] OR ") # subject for ioc in listSUBJECT: # STIX 1.2 emailsubject = EmailMessage() emailsubject.subject = ioc obsu = Observable(emailsubject) indiEMAIL.add_observable(obsu) if (VERBOSE): print("Subject: " + ioc) ioccount += 1 # STIX 2 (http://docs.oasis-open.org/cti/stix/v2.0/stix-v2.0-part5-stix-patterning.html) # Replace all quotes in a subject string with escaped quotes pattern_email.append("[email-message:subject = '" + ioc.replace("'", "\\'") + "'] OR ") ######################## # add all indicators to STIX 1.2 wrapper.add_indicator(indicatorHASH) wrapper.add_indicator(indiDOMAIN) wrapper.add_indicator(indiURL) wrapper.add_indicator(indiIP) wrapper.add_indicator(indiEMAIL) ######################## # prepare for STIX 2 bundle_objects = [campaign_MAIN, marking_def_white] if len(pattern_sha256) != 0: stix2_sha256 = "".join(pattern_sha256) stix2_sha256 = stix2_sha256[:-4] indicator_SHA256 = stix2.Indicator( name=TITLE + " - SHA256", created=timestamp, modified=timestamp, description=DESCRIPTION, labels=["malicious-activity"], pattern=stix2_sha256, object_marking_refs=[marking_def_white] ) relationship_indicator_SHA256 = stix2.Relationship(indicator_SHA256, "indicates", campaign_MAIN) bundle_objects.append(indicator_SHA256) bundle_objects.append(relationship_indicator_SHA256) if len(pattern_md5) != 0: stix2_md5 = "".join(pattern_md5) stix2_md5 = stix2_md5[:-4] indicator_MD5 = stix2.Indicator( name=TITLE + " - MD5", created=timestamp, modified=timestamp, description=DESCRIPTION, labels=["malicious-activity"], pattern=stix2_md5, object_marking_refs=[marking_def_white] ) relationship_indicator_MD5 = stix2.Relationship(indicator_MD5, "indicates", campaign_MAIN) bundle_objects.append(indicator_MD5) bundle_objects.append(relationship_indicator_MD5) if len(pattern_sha1) != 0: stix2_sha1 = "".join(pattern_sha1) stix2_sha1 = stix2_sha1[:-4] indicator_SHA1 = stix2.Indicator( name=TITLE + " - SHA1", created=timestamp, modified=timestamp, description=DESCRIPTION, labels=["malicious-activity"], pattern=stix2_sha1, object_marking_refs=[marking_def_white] ) relationship_indicator_SHA1 = stix2.Relationship(indicator_SHA1, "indicates", campaign_MAIN) bundle_objects.append(indicator_SHA1) bundle_objects.append(relationship_indicator_SHA1) if len(pattern_domain) != 0: stix2_domain = "".join(pattern_domain) stix2_domain = stix2_domain[:-4] indicator_DOMAINS = stix2.Indicator( name=TITLE + " - DOMAINS", created=timestamp, modified=timestamp, description=DESCRIPTION, labels=["malicious-activity"], pattern=stix2_domain, object_marking_refs=[marking_def_white] ) relationship_indicator_DOMAINS = stix2.Relationship(indicator_DOMAINS, "indicates", campaign_MAIN) bundle_objects.append(indicator_DOMAINS) bundle_objects.append(relationship_indicator_DOMAINS) if len(pattern_url) != 0: stix2_url = "".join(pattern_url) stix2_url = stix2_url[:-4] indicator_URLS = stix2.Indicator( name=TITLE + " - URL", created=timestamp, modified=timestamp, description=DESCRIPTION, labels=["malicious-activity"], pattern=stix2_url, object_marking_refs=[marking_def_white] ) relationship_indicator_URLS = stix2.Relationship(indicator_URLS, "indicates", campaign_MAIN) bundle_objects.append(indicator_URLS) bundle_objects.append(relationship_indicator_URLS) if len(pattern_ip) != 0: stix2_ip = "".join(pattern_ip) stix2_ip = stix2_ip[:-4] indicator_IPS = stix2.Indicator( name=TITLE + " - IPS", created=timestamp, modified=timestamp, description=DESCRIPTION, labels=["malicious-activity"], pattern=stix2_ip, object_marking_refs=[marking_def_white] ) relationship_indicator_IPS = stix2.Relationship(indicator_IPS, "indicates", campaign_MAIN) bundle_objects.append(indicator_IPS) bundle_objects.append(relationship_indicator_IPS) if len(pattern_email) != 0: stix2_email = "".join(pattern_email) stix2_email = stix2_email[:-4] indicator_EMAILS = stix2.Indicator( name=TITLE + " - EMAILS", created=timestamp, modified=timestamp, description=DESCRIPTION, labels=["malicious-activity"], pattern=stix2_email, object_marking_refs=[marking_def_white] ) relationship_indicator_EMAILS = stix2.Relationship(indicator_EMAILS, "indicates", campaign_MAIN) bundle_objects.append(indicator_EMAILS) bundle_objects.append(relationship_indicator_EMAILS) # creo il bunble STIX 2 bundlestix2 = stix2.Bundle(objects=bundle_objects) if (ioccount > 0): ######################## # save to STIX 1.2 file print("Writing STIX 1.2 package: " + OUTFILEPREFIX + ".stix") f = open(OUTFILEPREFIX + ".stix", "wb") f.write(wrapper.to_xml()) f.close() ######################## # save to STIX 2 file print("Writing STIX 2 package: " + OUTFILEPREFIX + ".stix2") g = open(OUTFILEPREFIX + ".stix2", "w") g.write(str(bundlestix2)) g.close() else: print("No IoC found")
def to_stix(self, username=None): """ Converts a CRITs event to a STIX document. The resulting document includes all related emails, samples, and indicators converted to CybOX Observable objects. Returns the STIX document and releasability constraints. (NOTE: the following statement is untrue until the releasability checking is finished, which includes setting releasability on all CRITs objects.) Raises UnreleasableEventError if the releasability on the relationships and the event do not share any common releasability sources. """ from crits.emails.email import Email from crits.samples.sample import Sample from crits.indicators.indicator import Indicator from cybox.common import Time, ToolInformationList, ToolInformation from cybox.core import Observables from stix.common import StructuredText from stix.core import STIXPackage, STIXHeader from stix.common import InformationSource from stix.common.identity import Identity stix_indicators = [] stix_observables = [] final_objects = [] # create a list of sources to send as part of the results. # list should be limited to the sources this user is allowed to use. # this list should be used along with the list of objects to set the # appropriate source's 'released' key to True for each object. final_sources = [] user_source_list = user_sources(username) for f in self.releasability: if f.name in user_source_list: final_sources.append(f.name) final_sources = set(final_sources) # TODO: eventually we can use class_from_id instead of the if block # but only once we support all CRITs types. for r in self.relationships: obj = None if r.rel_type == Email._meta['crits_type']: obj = Email.objects(id=r.object_id, source__name__in=user_source_list).first() if obj: ind, releas = obj.to_cybox() stix_observables.append(ind[0]) elif r.rel_type == Sample._meta['crits_type']: obj = Sample.objects(id=r.object_id, source__name__in=user_source_list).first() if obj: ind, releas = obj.to_cybox() for i in ind: stix_observables.append(i) elif r.rel_type == Indicator._meta['crits_type']: #NOTE: Currently this will raise an exception if there # are multiple indicators with the same value. # Should be fixed automatically once we transition # indicators to be related based on ObjectId rather # than value. obj = Indicator.objects(id=r.object_id, source__name__in=user_source_list).first() if obj: ind, releas = obj.to_stix_indicator() stix_indicators.append(ind) else: continue #Create a releasability list that is the intersection of # each related item's releasability with the event's # releasability. If the resulting set is empty, raise exception #TODO: Set releasability on all objects so that we actually # get results here instead of always raising an exception. if obj: releas_sources = set([rel.name for rel in releas]) final_sources = final_sources.intersection(releas_sources) #TODO: uncomment the following lines when objects have # releasability set. #if not final_sources: # raise UnreleasableEventError(r.value) # add to the final_objects list to send as part of the results final_objects.append(obj) tool_list = ToolInformationList() tool = ToolInformation("CRITs", "MITRE") tool.version = settings.CRITS_VERSION tool_list.append(tool) i_s = InformationSource( time=Time(produced_time= datetime.datetime.now()), identity = Identity(name=settings.COMPANY_NAME), tools = tool_list ) description = StructuredText(value=self.description) header = STIXHeader(information_source=i_s, description=description, package_intent=self.event_type, title=self.title) return (STIXPackage(indicators=stix_indicators, observables=Observables(stix_observables), stix_header=header, id_=self.event_id), final_sources, final_objects)
def main(): # Create a CybOX File Object with a contained hash f = File() f.add_hash("4EC0027BEF4D7E1786A04D021FA8A67F") # Create an Indicator with the File Hash Object created above. indicator = Indicator() indicator.title = "File Hash Example" indicator.description = ( "An indicator containing a File observable with an associated hash") indicator.set_producer_identity("The MITRE Corporation") indicator.set_produced_time(utils.dates.now()) # Add The File Object to the Indicator. This will promote the CybOX Object # to a CybOX Observable internally. indicator.add_object(f) # Build our STIX CIQ Identity object party_name = stix_ciq.PartyName(name_lines=("Foo", "Bar"), person_names=("John Smith", "Jill Smith"), organisation_names=("Foo Inc.", "Bar Corp.")) ident_spec = stix_ciq.STIXCIQIdentity3_0(party_name=party_name) ident_spec.add_electronic_address_identifier("*****@*****.**") ident_spec.add_free_text_line("Demonstrating Free Text!") ident_spec.add_contact_number("555-555-5555") ident_spec.add_contact_number("555-555-5556") # Build and add a CIQ Address addr = stix_ciq.Address(free_text_address='1234 Example Lane.', country='USA', administrative_area='An Admin Area') ident_spec.add_address(addr) # Build and add a nationality nationality = stix_ciq.Country("Norway") ident_spec.add_nationality(nationality) identity = stix_ciq.CIQIdentity3_0Instance(specification=ident_spec) # Set the Indicator producer identity to our CIQ Identity indicator.set_producer_identity(identity) # Build our STIX Package stix_package = STIXPackage() # Build a STIX Header and add a description stix_header = STIXHeader() stix_header.description = "STIX CIQ Identity Extension Example" # Set the STIX Header on our STIX Package stix_package.stix_header = stix_header # Add our Indicator object. The add() method will inspect the input and # append it to the `stix_package.indicators` collection. stix_package.add(indicator) # Print the XML! print(stix_package.to_xml()) # Print a dictionary! pprint(stix_package.to_dict())
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 main(): ###################################################################### # MODIFICARE LE VARIABILI SEGUENTI # Il title e' ID univoco della minaccia (es. Cobalt / Danabot / APT28) MyTITLE = "GandCrab" # La description strutturiamola come segue # <IOC PRODUCER> - <Descrizione della minaccia/campagna> - <URL (if any)> DESCRIPTION = "CERT-PA - Nuova campagna di Cyber-Estorsione basata su ransomware GandCrab - https://www.cert-pa.it/notizie/nuova-campagna-di-cyber-estorsione-basata-su-ransomware-gandcrab/" # La sorgente che ha generato l'IoC con riferimento a Cyber Saiyan Community IDENTITY = "CERT-PA via Cyber Saiyan Community" # ###################################################################### # Build STIX file info_src = InformationSource() info_src.identity = Identity(name=IDENTITY) NAMESPACE = Namespace("https://infosharing.cybersaiyan.it", "CYBERSAIYAN") set_id_namespace(NAMESPACE) timestamp = datetime.datetime.fromtimestamp(time.time()).strftime('%Y-%m-%d %H:%M:%S') SHORT = timestamp wrapper = STIXPackage() marking_specification = MarkingSpecification() marking_specification.controlled_structure = "//node() | //@*" tlp = TLPMarkingStructure() tlp.color = "WHITE" marking_specification.marking_structures.append(tlp) handling = Marking() handling.add_marking(marking_specification) wrapper.stix_header = STIXHeader(information_source=info_src, title=MyTITLE.encode(encoding='UTF-8', errors='replace'), description=DESCRIPTION.encode(encoding='UTF-8', errors='replace'), short_description=SHORT.encode(encoding='UTF-8', errors='replace')) wrapper.stix_header.handling = handling # HASH indicators indicatorHASH = Indicator() indicatorHASH.title = MyTITLE + " - HASH" indicatorHASH.add_indicator_type("File Hash Watchlist") # DOMAIN indicators indiDOMAIN = Indicator() indiDOMAIN.title = MyTITLE + " - DOMAIN" indiDOMAIN.add_indicator_type("Domain Watchlist") # URL indicators indiURL = Indicator() indiURL.title = MyTITLE + " - URL" indiURL.add_indicator_type("URL Watchlist") # IP indicators indiIP = Indicator() indiIP.title = MyTITLE + " - IP" indiIP.add_indicator_type("IP Watchlist") # EMAIL indicators indiEMAIL = Indicator() indiEMAIL.title = MyTITLE + " - EMAIL" indiEMAIL.add_indicator_type("Malicious E-mail") # Read IoC file file_ioc = "CS-ioc.txt" ioc = loaddata(file_ioc) print "Reading IoC file..." for idx, ioc in enumerate(ioc): notfound = 1 # sha256 p = re.compile(r"^[0-9a-f]{64}$", re.IGNORECASE) m = p.match(ioc) if m and notfound: filei = File() filei.add_hash(Hash(ioc)) obsi = Observable(filei) indicatorHASH.add_observable(obsi) print "SHA256: " + ioc notfound = 0 #md5 p = re.compile(r"^[0-9a-f]{32}$", re.IGNORECASE) m = p.match(ioc) if m and notfound: filej = File() filej.add_hash(Hash(ioc)) obsj = Observable(filej) indicatorHASH.add_observable(obsj) print "MD5: " + ioc notfound = 0 #sha1 p = re.compile(r"^[0-9a-f]{40}$", re.IGNORECASE) m = p.match(ioc) if m and notfound: filek = File() filek.add_hash(Hash(ioc)) obsk = Observable(filek) indicatorHASH.add_observable(obsk) print "SHA1: " + ioc notfound = 0 #domains if validators.domain(ioc) and notfound: url = URI() url.value = ioc url.type_ = URI.TYPE_DOMAIN url.condition = "Equals" obsu = Observable(url) indiDOMAIN.add_observable(obsu) print "DOMAIN: " + ioc notfound = 0 #url if validators.url(ioc) and notfound: url = URI() url.value = ioc url.type_ = URI.TYPE_URL url.condition = "Equals" obsu = Observable(url) indiURL.add_observable(obsu) print "URL: " + ioc notfound = 0 #ip if validators.ipv4(ioc) and notfound: ip = Address() ip.address_value = ioc obsu = Observable(ip) indiIP.add_observable(obsu) print "IP: " + ioc notfound = 0 # add all indicators to STIX wrapper.add_indicator(indicatorHASH) wrapper.add_indicator(indiDOMAIN) wrapper.add_indicator(indiURL) wrapper.add_indicator(indiIP) wrapper.add_indicator(indiEMAIL) # print STIX file to stdout print "Writing STIX package: package.stix" f = open ("package.stix", "w") f.write (wrapper.to_xml()) f.close () print
def main(iocs=iocs): stix_header = STIXHeader(title=iocs['title'], description=iocs['desc'], package_intents=["Indicators - Watchlist"]) stix_package = STIXPackage(stix_header=stix_header) # add indicator - file hash if iocs.get('hash'): indicator_file_hash = Indicator(title="Malicious File") indicator_file_hash.add_indicator_type("File Hash Watchlist") for file_hash in iocs['hash']: file_object = File() file_object.add_hash(Hash(file_hash)) file_object.hashes[0].simple_hash_value.condition = "Equals" file_object.hashes[0].type_.condition = "Equals" indicator_file_hash.add_observable(file_object) stix_package.add_indicator(indicator_file_hash) # add indicator - file name if iocs.get('fname'): indicator_filename = Indicator(title="Malicious File Name") for file in iocs['fname']: file_object = File() file_object.file_name = file indicator_filename.add_observable(file_object) stix_package.add_indicator(indicator_filename) # add indicator - ip address if iocs.get('ips'): indicator_ip = Indicator(title="Malicious IP Address") indicator_ip.add_indicator_type("IP Watchlist") for ip in iocs['ips']: addr = Address(address_value=ip, category=Address.CAT_IPV4) addr.condition = "Equals" indicator_ip.add_observable(addr) stix_package.add_indicator(indicator_ip) # add indicator - domains if iocs.get('domains'): indicator_domains = Indicator(title="Malicious Domains") indicator_domains.add_indicator_type("Domain Watchlist") for domain in iocs['domains']: domain_name = DomainName() domain_name.value = domain indicator_domains.add_observable(domain_name) stix_package.add_indicator(indicator_domains) # add indicator - url if iocs.get('urls'): indicator_url = Indicator(title='Malicious URL') indicator_url.add_indicator_type("URL Watchlist") for _url in iocs['urls']: url = URI() url.value = _url url.type_ = URI.TYPE_URL url.value.condition = "Equals" # url.value.condition = "Contains" indicator_url.add_observable(url) stix_package.add_indicator(indicator_url) # add indicator - email subject if iocs.get('subject'): indicator_email_subject = Indicator(title='Malicious E-mail Subject') indicator_email_subject.add_indicator_type("Malicious E-mail") for subject in iocs['subject']: email_subject_object = EmailMessage() email_subject_object.header = EmailHeader() email_subject_object.header.subject = subject email_subject_object.header.subject.condition = "StartsWith" indicator_email_subject.add_observable(email_subject_object) stix_package.add_indicator(indicator_email_subject) # add indicator - email sender if iocs.get('senders'): indicator_email_sender = Indicator(title='Malicious E-mail Sender') indicator_email_sender.add_indicator_type("Malicious E-mail") for sender in iocs['senders']: email_sender_object = EmailMessage() email_sender_object.header = EmailHeader() email_sender_object.header.sender = sender email_sender_object.header.sender.condition = "Equals" indicator_email_sender.add_observable(email_sender_object) stix_package.add_indicator(indicator_email_sender) # print(stix_package.to_xml(encoding=None)) # print(type(stix_package.to_xml(encoding=None))) return stix_package.to_xml(encoding=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() 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 test_to_xml_utf16_encoded(self): encoding = 'utf-16' s = STIXHeader() s.title = UNICODE_STR xml = s.to_xml(encoding=encoding) self.assertTrue(UNICODE_STR in xml.decode(encoding))
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_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 test_duplicate_package_intent(self): # Recreate https://github.com/STIXProject/python-stix/issues/63 hdr = STIXHeader(package_intents=["Indicators - Watchlist"]) self.assertEqual(1, len(hdr.package_intents))
def convert_bundle(bundle_obj): global _ID_OBJECT_MAPPING global _EXPLICIT_OBJECT_USED global _ID_NAMESPACE global _VICTIM_TARGET_TTPS global _KILL_CHAINS global CONTAINER _ID_OBJECT_MAPPING = {} _EXPLICIT_OBJECT_USED = {} _VICTIM_TARGET_TTPS = [] _KILL_CHAINS = {} if get_option_value("use_namespace"): option_value = get_option_value("use_namespace").split(" ") _ID_NAMESPACE = option_value[0] set_default_namespace(*option_value) CONTAINER = stixmarx.new() pkg = CONTAINER.package pkg.id_ = convert_id20(bundle_obj["id"]) for identity in (v for v in bundle_obj["objects"] if v["type"] == "identity"): debug("Found '%s'", 0, identity["id"]) i1x = convert_identity(identity) record_id_object_mapping(identity["id"], i1x, used=False) for marking_definition in (v for v in bundle_obj["objects"] if v["type"] == "marking-definition"): debug("Found '%s'", 0, marking_definition["id"]) m1x = convert_marking_definition(marking_definition) if not pkg.stix_header: pkg.stix_header = STIXHeader(handling=Marking()) pkg.stix_header.handling.add_marking(m1x) for o in bundle_obj["objects"]: if o["type"] == "attack-pattern": pkg.add_ttp(convert_attack_pattern(o)) elif o["type"] == "campaign": pkg.add_campaign(convert_campaign(o)) elif o["type"] == 'course-of-action': pkg.add_course_of_action(convert_coa(o)) elif o["type"] == "indicator": pkg.add_indicator(convert_indicator(o)) elif o["type"] == "intrusion-set": error( "Cannot convert STIX 2.0 content that contains intrusion-sets", 524) return None elif o["type"] == "malware": pkg.add_ttp(convert_malware(o)) elif o["type"] == "observed-data": pkg.add_observable(convert_observed_data(o)) elif o["type"] == "report": pkg.add_report(convert_report(o)) elif o["type"] == "threat-actor": pkg.add_threat_actor(convert_threat_actor(o)) elif o["type"] == "tool": pkg.add_ttp(convert_tool(o)) elif o["type"] == "vulnerability": pkg.add_exploit_target(convert_vulnerability(o)) # second passes for o in bundle_obj["objects"]: if o["type"] == "relationship": process_relationships(o) for o in bundle_obj["objects"]: if "created_by_ref" in o: process_created_by_ref(o) if "external_references" in o: create_references(o) for o in bundle_obj["objects"]: if o["type"] == "sighting": process_sighting(o) for k, v in _KILL_CHAINS.items(): pkg.ttps.kill_chains.append(v["kill_chain"]) CONTAINER.flush() CONTAINER = None return pkg
c = pycurl.Curl() c.setopt(c.URL, dataquery) c.setopt(c.HTTPHEADER, ['Accept: application/xml']) c.setopt(c.VERBOSE, 0) c.setopt(pycurl.SSL_VERIFYPEER, 0) c.setopt(pycurl.SSL_VERIFYHOST, 0) c.setopt(c.USERPWD, user_pass) c.setopt(c.WRITEDATA, buffer) c.perform() c.close() response = buffer.getvalue().decode("utf-8") response = response.strip('OK:') response = response.strip('\r\n') stxf = File() stix_package = STIXPackage() stix_header = STIXHeader() stix_header.description = "Malicious File Hash Indicator" stix_package.stix_header = stix_header indicator = Indicator() indicator.title = "File Observable" indicator.description = ( "An indicator containing a File observable with an associated hash") root = ElementTree.fromstring(response) for child in root: for child2 in child: for child3 in child2: for filenames in child3.iter('fileJoined.filename'): indicator.add_short_description(filenames.text) for hashes in child3.iter('fileJoined.md5'): stxf.add_hash(hashes.text)
def main(): # "hardcoded" values ns = "urn:example.com:marks_malware_metadata_mart" ns_alias = "m4" # Set the STIX ID Namespace stix_namespace = {ns: ns_alias} stix_sin(stix_namespace) # Set the CybOX ID Namespace cybox_namespace = Namespace(ns, ns_alias) cybox_sin(cybox_namespace) ttp_id = 'ttp-d539bb85-9363-4814-83c8-fa9975045686' ttp_timestamp = '2014-09-30T15:56:27.000000+00:00' # Fake database values md5_hash = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' object_id = 'File-927731f2-cc2c-421c-a40e-dc6f4a6c75a4' observable_id = 'Observable-45e3e64c-8438-441e-bc49-51e417466e29' confidence = 'High' confidence_timestamp = '2014-09-29T14:32:00.000000' indicator_id = 'Indicator-54baefc1-4742-4b40-ba83-afd51115015b' indicator_timestamp = '2014-09-29T14:32:00.000000' # Code to create the STIX Package sp = STIXPackage() sp.stix_header = STIXHeader() sp.stix_header.title = "File Hash Reputation for %s" % md5_hash sp.stix_header.add_package_intent("Indicators - Malware Artifacts") sp.stix_header.information_source = InformationSource() sp.stix_header.information_source.identity = Identity() sp.stix_header.information_source.identity.name = "Mark's Malware Metadata Mart" file_hash = Hash(hash_value=md5_hash, type_='MD5', exact=True) file_hash.type_.condition = "Equals" file_obj = File() file_obj.id_ = (ns_alias + ':' + object_id) file_obj.add_hash(file_hash) indicator = Indicator(title="File Hash Reputation", id_=(ns_alias + ':' + indicator_id), timestamp=indicator_timestamp) indicator.indicator_type = "File Hash Reputation" indicator.add_observable(file_obj) indicator.observables[0].id_ = ns_alias + ':' + observable_id ttp = TTP() ttp.id_ = ns_alias + ':' + ttp_id ttp.timestamp = ttp_timestamp ttp.title = "Malicious File" indicator.add_indicated_ttp(TTP(idref=ttp.id_, timestamp=ttp.timestamp)) indicator.indicated_ttps[0].confidence = confidence indicator.indicated_ttps[0].confidence.timestamp = confidence_timestamp sp.add_indicator(indicator) sp.add_ttp(ttp) stix_xml = sp.to_xml() poll_response = tm11.PollResponse(message_id=generate_message_id(), in_response_to="1234", collection_name='file_hash_reputation') cb = tm11.ContentBlock(content_binding=CB_STIX_XML_111, content=stix_xml) poll_response.content_blocks.append(cb) print poll_response.to_xml(pretty_print=True)
def buildSTIX(ident, confid, restconfid, effect, resteffect, typeIncident, resttype, asset, restasset, hashPkg): # IMPLEMENTATION WORKAROUND - # restConfid --> header.description # resteffect --> breach.description # resttype --> reporter.description # restasset --> reporter.identity.name # setup stix document stix_package = STIXPackage() stix_header = STIXHeader() stix_header.description = restconfid # "Example description" stix_package.stix_header = stix_header # add incident and confidence breach = Incident(id_=ident) breach.description = resteffect # "Intrusion into enterprise network" breach.confidence = Confidence() breach.confidence.value = confid breach._binding_class.xml_type = typeIncident # stamp with reporter breach.reporter = InformationSource() breach.reporter.description = resttype #"The person who reported it" breach.reporter.time = Time() breach.reporter.time.produced_time = datetime.strptime( "2014-03-11", "%Y-%m-%d") # when they submitted it breach.reporter.identity = Identity() breach.reporter.identity.name = restasset # "Sample Investigations, LLC" # set incident-specific timestamps breach.time = incidentTime() breach.title = "Breach of CyberTech Dynamics" breach.time.initial_compromise = datetime.strptime("2012-01-30", "%Y-%m-%d") breach.time.incident_discovery = datetime.strptime("2012-05-10", "%Y-%m-%d") breach.time.restoration_achieved = datetime.strptime( "2012-08-10", "%Y-%m-%d") breach.time.incident_reported = datetime.strptime("2012-12-10", "%Y-%m-%d") # add the impact #impact = ImpactAssessment() #impact.add_effect("Unintended Access") #breach.impact_assessment = impact affected_asset = AffectedAsset() affected_asset.description = "Database server at hr-data1.example.com" affected_asset.type_ = asset breach.affected_assets = affected_asset #print("asset type: %s"%(breach.affected_assets[0].type_)) # add the victim breach.add_victim(hashPkg) # add the impact impact = ImpactAssessment() impact.add_effect(effect) breach.impact_assessment = impact stix_package.add_incident(breach) #print("hey, I've got an incident! list size=%s"%(len(stix_package._incidents))) # Print the XML! #print(stix_package.to_xml()) return stix_package
def generate_stix_file(input_file, list_type, delimiter, list_name, tc_name, tmp_dir, validate, verbose): # observable limit per generated stix file OBSERVABLES_PER_STIX_FILE = 3000 if verbose: logging.info("=====================") logging.info("== GENERATING STIX ==") logging.info("=====================") # download or open input file if validators.url(input_file): res = requests.get(input_file) items = res.text.split(delimiter) else: # exit if input file doesn't exist if not os.path.isfile(input_file): logging.error("Supplied input file '{}' doesn't exist".format(input_file)) sys.exit("Error: Supplied input file '{}' doesn't exist".format(input_file)) else: with open(input_file, 'r') as f: items = f.read().split(delimiter) logging.info("Successfully parsed input file at {}".format(input_file)) # slice input into batches for batch_num, index in enumerate(range(0, len(items), OBSERVABLES_PER_STIX_FILE), 1): # slice handles out of bounds indices gracefully batch_items = items[index:index + OBSERVABLES_PER_STIX_FILE] # create the STIX Package package = STIXPackage() # create the STIX Header and add a description header = STIXHeader() package.stix_header = header reporttime = datetime.datetime.utcnow().strftime('%m/%d/%Y %H:%M:%S %Z') # create indicator for each item in the batch for item in batch_items: item = item.strip() # basic filtering of empty items and comments if not item or item.startswith(('#', '//', '--')): continue if list_type == 'ip': indicator_obj = Address() # attempt to parse as an ip address try: parsed_ip = ipaddress.ip_address(item) if parsed_ip.version == 4: indicator_obj.category = Address.CAT_IPV4 elif parsed_ip.version == 6: indicator_obj.category = Address.CAT_IPV6 else: logging.warning("Unknown IP Address version type: {} - skipping".format(parsed_ip.version)) continue except ValueError: # if ip address parsing fails then attempt to parse as an ip network try: parsed_ip = ipaddress.ip_network(item, strict=False) indicator_obj.category = Address.CAT_CIDR except ValueError: logging.warning("IP Address {} is neither an IPv4, IPv6, nor CIDR - skipping".format(item)) continue indicator_obj.address_value = str(parsed_ip) indicator_obj.condition = "Equals" indicator_type = "IP Watchlist" # customizable components below indicator_title = "IP: {}" indicator_description = "IP {} reported from {}" elif list_type == 'domain': # validate domain if validate and not validators.domain(item): logging.warning("Invalid domain: {} - skipping".format(item)) continue indicator_obj = DomainName() indicator_obj.value = item indicator_type = "Domain Watchlist" # customizable components below indicator_title = "Domain: {}" indicator_description = "Domain {} reported from {}" elif list_type == 'url': # validate url if validate and not validators.url(item): logging.warning("Invalid url: {} - skipping".format(item)) continue indicator_obj = URI() indicator_obj.value = item indicator_obj.type_ = URI.TYPE_URL indicator_obj.condition = "Equals" indicator_type = "URL Watchlist" # customizable components below indicator_title = "URL: {}" indicator_description = "URL {} reported from {}" else: # invalid input type logging.error("invalid input type encountered") raise Exception('Error: invalid input type encountered') # create a basic Indicator object from the item indicator = Indicator() indicator.title = indicator_title.format(str(item)) indicator.description = indicator_description.format(str(item), list_name) indicator.add_indicator_type(indicator_type) indicator.set_producer_identity(list_name) indicator.set_produced_time(str(reporttime)) indicator.add_observable(indicator_obj) # add the indicator to the stix package package.add_indicator(indicator) # save each batch in a separate stix file with the filename ending ..._part_N.stix collection_filename = "{}_part_{}.stix".format(strip_non_alphanum(tc_name), batch_num) with open(os.path.join(tmp_dir, collection_filename), 'wb') as f: f.write(package.to_xml()) logging.info("Successfully created stix file {}".format(collection_filename)) # clear cybox cache to prevent an Out of Memory error # https://cybox.readthedocs.io/en/stable/api/cybox/core/object.html#cybox.core.object.Object cache_clear() return
def main(): url = 'https://isc.sans.edu/api/topips/records/100' ua = 'ISC2Stix/1.0 (https://blog.rootshell.be/)' headers = {'User-Agent': ua} try: req = urllib2.Request(url, None, headers) res = urllib2.urlopen(req) except urllib2.HTTPError, e: print "HTTPError: " + str(e.code) except urllib2.URLError, e: print "URLError: " + str(e.reason) doc = xmltodict.parse(res.read()) # Create the STIX Package package = STIXPackage() # Create the STIX Header and add a description. header = STIXHeader() #header.title = "SANS ISC Top-100 Malicious IP Addresses" #header.description = "Source: " + url package.stix_header = header for entry in doc['topips']['ipaddress']: bytes = entry['source'].split('.') indicator = Indicator() indicator.title = "SANS ISC Malicious IP" indicator.add_indicator_type("IP Watchlist") ip = Address() ip.address_value = "%d.%d.%d.%d" % (int(bytes[0]), int( bytes[1]), int(bytes[2]), int(bytes[3])) ip.category = 'ipv4-addr' ip.condition = 'Equals' indicator.add_observable(ip) package.add_indicator(indicator)
def main(): ###################################################################### # MODIFICARE LE VARIABILI SEGUENTI MyTITLE = "APT28 / Fancy Bear" DESCRIPTION = "Emanuele De Lucia - APT28 / Fancy Bear still targeting military institutions - https://www.emanueledelucia.net/apt28-targeting-military-institutions/" sha256 = [] md5 = [ '43D7FFD611932CF51D7150B176ECFC29', '549726B8BFB1919A343AC764D48FDC81' ] sha1 = [] domains = ['beatguitar.com'] urls = [ 'https://beatguitar.com/aadv/gJNn/X2/ep/VQOA/3.SMPTE292M/?ct=+lMQKtXi0kf+3MVk38U=', 'https://beatguitar.com/n2qqSy/HPSe0/SY/yAsFy8/mSaYZP/lw.sip/?n=VxL0BnijNmtTnSFIcoQ=' ] ips = ['185.99.133.72'] emails = [] ###################################################################### # Costruzione STIX file NAMESPACE = Namespace("https://infosharing.cybersaiyan.it", "CYBERSAIYAN") set_id_namespace(NAMESPACE) timestamp = datetime.datetime.fromtimestamp( time.time()).strftime('%Y-%m-%d %H:%M:%S') SHORT = timestamp wrapper = STIXPackage() info_src = InformationSource() info_src.identity = Identity(name="CyberSaiyan Community") marking_specification = MarkingSpecification() marking_specification.controlled_structure = "//node() | //@*" tlp = TLPMarkingStructure() tlp.color = "WHITE" marking_specification.marking_structures.append(tlp) handling = Marking() handling.add_marking(marking_specification) wrapper.stix_header = STIXHeader(information_source=info_src, title=MyTITLE, description=DESCRIPTION, short_description=SHORT) wrapper.stix_header.handling = handling # HASH indicators indicatorHASH = Indicator() indicatorHASH.title = MyTITLE + " - HASH" indicatorHASH.add_indicator_type("File Hash Watchlist") for idx, sha256 in enumerate(sha256): filei = File() filei.add_hash(Hash(sha256)) obsi = Observable(filei) indicatorHASH.add_observable(obsi) for idx, md5 in enumerate(md5): filej = File() filej.add_hash(Hash(md5)) obsj = Observable(filej) indicatorHASH.add_observable(obsj) for idx, sha1 in enumerate(sha1): filek = File() filek.add_hash(Hash(sha1)) obsk = Observable(filek) indicatorHASH.add_observable(obsk) # DOMAIN indicators indiDOMAIN = Indicator() indiDOMAIN.title = MyTITLE + " - DOMAIN" indiDOMAIN.add_indicator_type("Domain Watchlist") for idu, domains in enumerate(domains): url = URI() url.value = domains url.type_ = URI.TYPE_DOMAIN url.condition = "Equals" obsu = Observable(url) indiDOMAIN.add_observable(obsu) # URL indicators indiURL = Indicator() indiURL.title = MyTITLE + " - URL" indiURL.add_indicator_type("URL Watchlist") for idu, urls in enumerate(urls): url = URI() url.value = urls url.type_ = URI.TYPE_URL url.condition = "Equals" obsu = Observable(url) indiURL.add_observable(obsu) # IP indicators indiIP = Indicator() indiIP.title = MyTITLE + " - IP" indiIP.add_indicator_type("IP Watchlist") for idu, ips in enumerate(ips): ip = Address() ip.address_value = ips obsu = Observable(ip) indiIP.add_observable(obsu) # EMAIL indicators indiEMAIL = Indicator() indiEMAIL.title = MyTITLE + " - EMAIL" indiEMAIL.add_indicator_type("Malicious E-mail") for idu, emails in enumerate(emails): email = EmailAddress() email.address_value = emails obsu = Observable(email) indiEMAIL.add_observable(obsu) # add all indicators wrapper.add_indicator(indicatorHASH) wrapper.add_indicator(indiDOMAIN) wrapper.add_indicator(indiURL) wrapper.add_indicator(indiIP) wrapper.add_indicator(indiEMAIL) print(wrapper.to_xml())
def transform(addsec_data): # # Parse the Addition Security protobuf object, which contains a STIX report representation # as_report = addsec_cti_pb2.Report() as_report.ParseFromString(addsec_data) # # Create a new STIX package & report container # stix_package = STIXPackage() stix_package.stix_header = STIXHeader() stix_package.stix_header.description = "Addition Security Report" stix_report = Report() # # Addition Security includes various identification information re: the entity of the report. # We are going to convert it into three CybOX objects: Product, Device, and Custom # cybox_product = Product() cybox_product.product = "MobileAwareness" cybox_product.vendor = "Addition Security" cybox_device = Device() cybox_device.device_type = "Mobile Device" cybox_custom_sourceapp = Custom() cybox_custom_sourceapp.custom_name = "addsec:sourceApplication" cybox_custom_sourceapp.custom_properties = CustomProperties() p = Property() p.name = "organizationId" p.value = as_report.organizationId.encode( 'hex') # NOTE: this is binary bytes cybox_custom_sourceapp.custom_properties.append(p) p = Property() p.name = "application" p.value = as_report.applicationId # NOTE: bundleId/packageId of hosting app cybox_custom_sourceapp.custom_properties.append(p) p = Property() p.name = "instanceId" p.value = as_report.systemId.encode('hex') # NOTE: this is binary bytes cybox_custom_sourceapp.custom_properties.append(p) stix_report.add_observable(cybox_product) stix_report.add_observable(cybox_device) stix_report.add_observable(cybox_custom_sourceapp) # # Enumerate the Addition Security reported sightings # for as_sighting in as_report.observations: # # Addition Security lets customers transit custom messages over the reporting channel; these # messages show up as a "Customer Message" indicator with string-based payload. Since these # messages are both proprietary in nature and potentially unrelated to STIX, we are going to # filter them out from this processing. # if as_sighting.observationType == 8: continue # 8: CustomerData # # Sightings are used to report device information as well; let's expel device-related # sightings and re-route their data into the CybOX device object (instead of including # as an indicator w/ sighting) # if as_sighting.testId == 1 or as_sighting.testId == 2: # addsec_to_cybox_device(cybox_device, as_sighting) continue # Ditto for reported product information as well if as_sighting.testId == 8: # 8: SDKVersionInfo addsec_to_cybox_product(cybox_product, as_sighting) continue # # Compose a STIX-appropriate indicator value from the Addition Security indicator ID & SubID # indicator_id = "addsec:asma-%d-%d" % (as_sighting.testId, as_sighting.testSubId) stix_indicator = Indicator(id_=indicator_id) stix_indicator.title = addsec_title_lookup(as_sighting.testId, as_sighting.testSubId) # # Create a sighting for this indicator # stix_sighting = Sighting() stix_indicator.sightings = stix_sighting stix_sighting.timestamp = datetime.datetime.fromtimestamp( as_sighting.timestamp) if as_sighting.confidence > 0: stix_sighting.confidence = addsec_to_stix_confidence( as_sighting.confidence) # # Enumerate the observables for this sighting # for as_observable in as_sighting.datas: cybox_obj = addsec_to_cybox(as_observable.dataType, as_observable.data) if not cybox_obj is None: stix_sighting.related_observables.append( RelatedObservable(Observable(cybox_obj))) # # Finally, add this indicator (w/ sightings & related observables) to the top level report # stix_report.add_indicator(stix_indicator) # # Finalize the STIX report and output the XML # stix_package.reports = stix_report return stix_package.to_xml()