def main(): alpha_package = STIXPackage() alpha_package.stix_header = STIXHeader() alpha_package.stix_header.title = "Report on Adversary Alpha's Campaign against the Industrial Control Sector" alpha_package.stix_header.package_intents = "Campaign Characterization" alpha_package.stix_header.handling = Marking() alpha_marking = MarkingSpecification() alpha_marking.controlled_structure = "../../../../node()" alpha_tlp_marking = TLPMarkingStructure() alpha_tlp_marking.color = "AMBER" alpha_marking.marking_structures.append(alpha_tlp_marking) alpha_package.stix_header.handling.add_marking(alpha_marking) rat_package = STIXPackage() rat_package.stix_header = STIXHeader() rat_package.stix_header.title = "Indicators for Malware DrownedRat" rat_package.stix_header.package_intents = "Indicators - Malware Artifacts" rat_package.stix_header.handling = Marking() rat_marking = MarkingSpecification() rat_marking.controlled_structure = "../../../../node()" rat_tlp_marking = TLPMarkingStructure() rat_tlp_marking.color = "RED" alpha_marking.marking_structures.append(rat_tlp_marking) rat_package.stix_header.handling.add_marking(rat_marking) stix_package = STIXPackage() info_src = InformationSource() info_src.identity = Identity(name="Government Sharing Program - GSP") stix_package.stix_header = STIXHeader(information_source=info_src) stix_package.related_packages.append(alpha_package) stix_package.related_packages.append(rat_package) print 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 _get_tlp_marking_structure(self, feed): tlp_marking_structure = TLPMarkingStructure() tlp_marking_structure.color = feed.tlp marking_specification = MarkingSpecification() marking_specification.marking_structures = tlp_marking_structure marking_specification.controlled_structure = '../../../../descendant-or-self::node() | ../../../../descendant-or-self::node()/@*' return marking_specification
def _make_marking_specification_statement(self, key, value, controlled_structure=None): simple_marking_structres = SimpleMarkingStructure() statement = '%s: %s' % (key, value) simple_marking_structres.statement = statement marking_specification = MarkingSpecification() marking_specification.marking_structures = simple_marking_structres marking_specification.controlled_structure = controlled_structure return marking_specification
def main(): mydata = loaddata() ''' Your Namespace ''' # NAMESPACE = {sanitizer(mydata["NSXURL"]) : (mydata["NS"])} # set_id_namespace(NAMESPACE) NAMESPACE = Namespace(sanitizer(mydata['NSXURL']), sanitizer(mydata['NS'])) set_id_namespace(NAMESPACE) # new ids will be prefixed by "myNS" wrapper = STIXPackage() info_src = InformationSource() info_src.identity = Identity(name=sanitizer(mydata["Identity"])) marking_specification = MarkingSpecification() marking_specification.controlled_structure = "//node() | //@*" tlp = TLPMarkingStructure() tlp.color = sanitizer(mydata["TLP_COLOR"]) marking_specification.marking_structures.append(tlp) handling = Marking() handling.add_marking(marking_specification) timestamp = datetime.datetime.fromtimestamp( time.time()).strftime('%Y-%m-%d %H:%M:%S') MyTITLE = sanitizer(mydata["Title"]) SHORT = timestamp DESCRIPTION = sanitizer(mydata["Description"]) wrapper.stix_header = STIXHeader(information_source=info_src, title=MyTITLE, description=DESCRIPTION, short_description=SHORT) wrapper.stix_header.handling = handling indiDom = Indicator() indiDom.title = MyTITLE indiDom.add_indicator_type("IP Watchlist") for key in mydata["IOC"].keys(): myip = Address(address_value=sanitizer(key), category=Address.CAT_IPV4) myip.condition = "Equals" obsu = Observable(myip) #if mydata[key].size: for idx, mydata["IOC"][key] in enumerate(mydata["IOC"][key]): ioc = File() ioc.add_hash(sanitizer(mydata["IOC"][key])) myip.add_related(ioc, "Downloaded") indiDom.add_observable(obsu) wrapper.add_indicator(indiDom) print(wrapper.to_xml())
def setTLP(target, distribution): marking_specification = MarkingSpecification() marking_specification.controlled_structure = "../../../descendant-or-self::node()" tlp = TLPMarkingStructure() colour = TLP_mapping.get(distribution, None) if colour is None: return target tlp.color = colour marking_specification.marking_structures.append(tlp) handling = Marking() handling.add_marking(marking_specification) target.handling = handling
def _marking(): """Define the TLP marking and the inheritance.""" marking_specification = MarkingSpecification() tlp = TLPMarkingStructure() tlp.color = SETTINGS['stix']['tlp'] marking_specification.marking_structures.append(tlp) marking_specification.controlled_structure = SETTINGS[ 'stix']['controlled_structure'] simple = SimpleMarkingStructure() simple.statement = SETTINGS['stix']['statement'] marking_specification.marking_structures.append(simple) handling = Marking() handling.add_marking(marking_specification) return handling
def marking(): """Define the TLP marking and the inheritence.""" marking_specification = MarkingSpecification() marking_specification.controlled_structure = "../../../../descendant"\ "-or-self::node() | ../../../../descendant-or-self::node()/@*" simple = SimpleMarkingStructure() simple.statement = HNDL_ST marking_specification.marking_structures.append(simple) tlp = TLPMarkingStructure() tlp.color = "WHITE" marking_specification.marking_structures.append(tlp) handling = Marking() handling.add_marking(marking_specification) return handling
def to_stix_tlp(obj): from stix.data_marking import Marking, MarkingSpecification from stix.extensions.marking.tlp import TLPMarkingStructure marking_specification = MarkingSpecification() marking_specification.controlled_structure = "//node() | //@*" tlp = TLPMarkingStructure() tlp.color = obj.tlp marking_specification.marking_structures.append(tlp) handling = Marking() handling.add_marking(marking_specification) return handling
def convert(self, stix_id_prefix='', published_only=True, **kw_arg): self.parse(**kw_arg) stix_packages = [] for event in self.events: if published_only: if not event.published: continue # id generator package_id = self.get_misp_pacakge_id(stix_id_prefix, event) stix_package = STIXPackage(timestamp=event.dt, id_=package_id) stix_header = STIXHeader() # set identity information identity = Identity(name=self.identity_name) information_source = InformationSource(identity=identity) stix_header.information_source = information_source tlp = None for tag in event.tags: if tag.tlp is not None: tlp = tag.tlp break if tlp is not None: # TLP for Generic format tlp_marking_structure = TLPMarkingStructure() tlp_marking_structure.color = tlp marking_specification = MarkingSpecification() marking_specification.marking_structures = tlp_marking_structure marking_specification.controlled_structure = '../../../../descendant-or-self::node() | ../../../../descendant-or-self::node()/@*' marking = Marking() marking.add_marking(marking_specification) stix_header.handling = marking stix_header.title = event.info stix_header.description = event.info stix_header.short_description = event.info for attribute in event.attributes: stix_package.add_indicator(attribute.convert()) stix_package.stix_header = stix_header stix_packages.append(stix_package) return stix_packages
def 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 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 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 stix(json): """ Created a stix file based on a json file that is being handed over """ # Create a new STIXPackage stix_package = STIXPackage() # Create a new STIXHeader stix_header = STIXHeader() # Add Information Source. This is where we will add the tool information. stix_header.information_source = InformationSource() # Create a ToolInformation object. Use the initialization parameters # to set the tool and vendor names. # # Note: This is an instance of cybox.common.ToolInformation and NOT # stix.common.ToolInformation. tool = ToolInformation( tool_name="viper2stix", tool_vendor="The Viper group http://viper.li - developed by Alexander Jaeger https://github.com/deralexxx/viper2stix" ) #Adding your identity to the header identity = Identity() identity.name = Config.get('stix', 'producer_name') stix_header.information_source.identity=identity # Set the Information Source "tools" section to a # cybox.common.ToolInformationList which contains our tool that we # created above. stix_header.information_source.tools = ToolInformationList(tool) stix_header.title = Config.get('stix', 'title') # Set the produced time to now stix_header.information_source.time = Time() stix_header.information_source.time.produced_time = datetime.now() marking_specification = MarkingSpecification() marking_specification.controlled_structure = "../../../descendant-or-self::node()" tlp = TLPMarkingStructure() tlp.color = Config.get('stix', 'TLP') marking_specification.marking_structures.append(tlp) handling = Marking() handling.add_marking(marking_specification) # Set the header description stix_header.description = Config.get('stix', 'description') # Set the STIXPackage header stix_package.stix_header = stix_header stix_package.stix_header.handling = handling try: pp = pprint.PrettyPrinter(indent=5) pp.pprint(json['default']) #for key, value in json['default'].iteritems(): # print key, value for item in json['default']: #logger.debug("item %s", item) indicator = Indicator() indicator.title = "File Hash" indicator.description = ( "An indicator containing a File observable with an associated hash" ) # Create a CyboX File Object f = File() sha_value = item['sha256'] if sha_value is not None: sha256 = Hash() sha256.simple_hash_value = sha_value h = Hash(sha256, Hash.TYPE_SHA256) f.add_hash(h) sha1_value = item['sha1'] if sha_value is not None: sha1 = Hash() sha1.simple_hash_value = sha1_value h = Hash(sha1, Hash.TYPE_SHA1) f.add_hash(h) sha512_value = item['sha512'] if sha_value is not None: sha512 = Hash() sha512.simple_hash_value = sha512_value h = Hash(sha512, Hash.TYPE_SHA512) f.add_hash(h) f.add_hash(item['md5']) #adding the md5 hash to the title as well stix_header.title+=' '+item['md5'] #print(item['type']) f.size_in_bytes=item['size'] f.file_format=item['type'] f.file_name = item['name'] indicator.description = "File hash served by a Viper instance" indicator.add_object(f) stix_package.add_indicator(indicator) except Exception, e: logger.error('Error: %s',format(e)) return False
def index2stix(local_index, orig_stix): #============= # Build package metadata #============= new_stix = STIXPackage() new_stix.stix_header = STIXHeader() new_stix.stix_header.title = "TG3390 - Enrichment" new_stix.stix_header.description = "Enrichment stix file to the Dell SecureWorks Counter Threat Unit(TM) (CTU) researchers investigated activities associated with Threat Group-3390[1] (TG-3390) - http://www.secureworks.com/cyber-threat-intelligence/threats/threat-group-3390-targets-organizations-for-cyberespionage/" marking_specification = MarkingSpecification() marking_specification.controlled_structure = "../../../../descendant-or-self::node()" tlp = TLPMarkingStructure() tlp.color = "WHITE" marking_specification.marking_structures.append(tlp) handling = Marking() handling.add_marking(marking_specification) new_stix.stix_header.handling = handling enrich_IPs = Indicator(title="Suspected TG3390 IP Addresses obtained through automated enrichment") enrich_IPs.add_indicator_type("IP Watchlist") enrich_IPs.confidence = "Low" related_IPs = Indicator(title="Related indicator wrapper for source of enrichment") related_IPs.add_indicator_type("IP Watchlist") related_IPs.confidence = "Medium" enrich_Domains = Indicator(title="Suspected TG3390 Domains obtained through automated enrichment") enrich_Domains.add_indicator_type("Domain Watchlist") enrich_Domains.confidence = "Low" related_Domains = Indicator(title="Related indicator wrapper for source of enrichment") related_Domains.add_indicator_type("Domain Watchlist") related_Domains.confidence = "Medium" # START with the ones that already have ids: #if verbose: #print_chain(local_index) new_ref_created = True while new_ref_created: new_ref_created = False for ind_type in local_index: for obs in local_index[ind_type]: id_tobe_referenced = local_index[ind_type][obs][0] #print id_tobe_referenced[:10] if id_tobe_referenced[:10] != '{{no_ref}}': ref_obs = Observable() ref_obs.id_ = id_tobe_referenced.replace("{{no_ref}}","") ref_obs.description = 'Source of enrichment for: ' create_ref_obs = False for entry in local_index[ind_type][obs]: if type(entry) is list: if len(entry)>0: for item in entry: ref, child_ind_type = get_ref_from_obs(item, local_index) #print item if ref == '{{no_ref}}' or ref == '': create_ref_obs = True new_ref_created = True #print 'Create new, complete, observable for ' + item #print child_ind_type #Create the new observable for item and add as object to appropriate Indicator if child_ind_type == 'DomainName': append_ind = enrich_Domains related_ind = related_Domains new_obj = DomainName() new_obj.value = item #enrich_Domains.add_object(domain_obj) elif child_ind_type == 'Address': append_ind = enrich_IPs related_ind = related_IPs new_obj = Address() new_obj.category = "ipv4-addr" new_obj.address_value = item #enrich_IPs.add_object(ipv4_obj) else: print 'Unsupported indicator type: ' + child_ind_type new_obs = Observable(new_obj) new_obs_ref = new_obs.id_ append_ind.add_observable(new_obs) ref = new_obs_ref #local_index[item][0] = ref set_obs_ref(item, new_obs_ref, local_index) #print 'Adding ref to: ' + ref_obs.id_ + ' of ' + ref ref_obs.description = str(ref_obs.description) + ref.replace("{{no_ref}}","") + ', ' if create_ref_obs: #Add the new ref obs to Related Indicators related_ind.add_observable(ref_obs) #print related_ind.to_xml() create_ref_obs = False related_ind1 = RelatedIndicator(related_IPs, relationship='Source of enrichment for IPs') related_ind2 = RelatedIndicator(related_Domains, relationship='Source of enrichment for Domains') enrich_IPs.related_indicators.append(related_ind1) enrich_Domains.related_indicators.append(related_ind2) new_stix.add_indicator(enrich_IPs) new_stix.add_indicator(enrich_Domains) #new_stix_json = json.loads(new_stix.to_json()) #new_stix_xml = new_stix.to_xml() #if verbose: #print new_stix.to_xml() return new_stix
def csv2stix(outFormat,inFile): #============= # Build package metadata #============= stix_package = STIXPackage() stix_package.stix_header = STIXHeader() stix_package.stix_header.title = "TG3390" stix_package.stix_header.description = "Dell SecureWorks Counter Threat Unit(TM) (CTU) researchers investigated activities associated with Threat Group-3390[1] (TG-3390) - http://www.secureworks.com/cyber-threat-intelligence/threats/threat-group-3390-targets-organizations-for-cyberespionage/" marking_specification = MarkingSpecification() marking_specification.controlled_structure = "../../../../descendant-or-self::node()" tlp = TLPMarkingStructure() tlp.color = "WHITE" marking_specification.marking_structures.append(tlp) handling = Marking() handling.add_marking(marking_specification) stix_package.stix_header.handling = handling #============= # Build package structure #============= ta_tg3390 = ThreatActor(title="TG3390") ta_tg3390.identity = Identity(name="TG3390") attack_pattern = AttackPattern() attack_pattern.description = ("Infrastructure Building") ttp_infrastructure = TTP(title="Infrastructure Building") ttp_infrastructure.behavior = Behavior() ttp_infrastructure.behavior.add_attack_pattern(attack_pattern) ttp_infrastructure.add_intended_effect("Unauthorized Access") infra_domainInd = Indicator(title="Domains associated with TG3390 Infrastructure") infra_domainInd.add_indicator_type("Domain Watchlist") infra_domainInd.confidence = "High" infra_domainInd.add_indicated_ttp(TTP(idref=ttp_infrastructure.id_)) infra_IPInd = Indicator(title="[H] IP Addresses associated with TG3390 Infrastructure") infra_IPInd.add_indicator_type("IP Watchlist") infra_IPInd.confidence = "High" infra_IPInd.add_indicated_ttp(TTP(idref=ttp_infrastructure.id_)) infra_IPInd_M = Indicator(title="[M] IP Addresses associated with TG3390 Infrastructure") infra_IPInd_M.add_indicator_type("IP Watchlist") infra_IPInd_M.confidence = "Medium" infra_IPInd_M.add_indicated_ttp(TTP(idref=ttp_infrastructure.id_)) httpBrowserObj = MalwareInstance() httpBrowserObj.add_name("HTTP Browser") ttp_httpB = TTP(title="HTTP Browser") ttp_httpB.behavior = Behavior() ttp_httpB.behavior.add_malware_instance(httpBrowserObj) ttp_httpB.add_intended_effect("Theft - Intellectual Property") httpB_hashInd = Indicator(title="File hashes for HTTP Browser") httpB_hashInd.add_indicator_type("File Hash Watchlist") httpB_hashInd.confidence = "High" httpB_hashInd.add_indicated_ttp(TTP(idref=ttp_httpB.id_)) httpBrowserDropperObj = MalwareInstance() httpBrowserDropperObj.add_name("HTTP Browser Dropper") ttp_httpBDpr = TTP(title="HTTP Browser Dropper") ttp_httpBDpr.behavior = Behavior() ttp_httpBDpr.behavior.add_malware_instance(httpBrowserDropperObj) ttp_httpBDpr.add_intended_effect("Theft - Intellectual Property") httpBDpr_hashInd = Indicator(title="File hashes for HTTP Browser Dropper") httpBDpr_hashInd.add_indicator_type("File Hash Watchlist") httpBDpr_hashInd.confidence = "High" httpBDpr_hashInd.add_indicated_ttp(TTP(idref=ttp_httpBDpr.id_)) plugXObj = MalwareInstance() plugXObj.add_name("PlugX Dropper") ttp_plugX = TTP(title="PlugX Dropper") ttp_plugX.behavior = Behavior() ttp_plugX.behavior.add_malware_instance(plugXObj) ttp_plugX.add_intended_effect("Theft - Intellectual Property") plugX_hashInd = Indicator(title="File hashes for PlugX Dropper") plugX_hashInd.add_indicator_type("File Hash Watchlist") plugX_hashInd.confidence = "High" plugX_hashInd.add_indicated_ttp(TTP(idref=ttp_plugX.id_)) #============= # Process content in to structure #============= ip_rules = [] ip_rules_M = [] domain_rules = [] with open(inFile, 'rb') as f: reader = csv.reader(f) for row in reader: obs = row[0] obsType = row[1] description = row[2] confidence = row[3] #print obs,obsType,description,confidence if description == 'TG-3390 infrastructure': if obsType == 'Domain name': domain_obj = DomainName() domain_obj.value = obs #domain_obj.title = description infra_domainInd.add_object(domain_obj) domain_rule = generate_snort([obs], 'DomainName', str(infra_domainInd.id_).split(':',1)[1].split('-',1)[1]) domain_rules.append(domain_rule) elif obsType == 'IP address': ipv4_obj = Address() ipv4_obj.category = "ipv4-addr" ipv4_obj.address_value = obs ipv4_obj.title = description ind_ref = str(infra_IPInd.id_).split(':',1)[1].split('-',1)[1] if confidence == "High": infra_IPInd.add_object(ipv4_obj) ip_rules.append(obs) else: infra_IPInd_M.add_object(ipv4_obj) ip_rules_M.append(obs) else: print "TTP Infra: obsType is wrong" elif description == 'HttpBrowser RAT dropper': file_obj = File() file_obj.add_hash(Hash(obs)) file_obj.title = description httpBDpr_hashInd.add_observable(file_obj) elif description == 'HttpBrowser RAT': file_obj = File() file_obj.add_hash(Hash(obs)) file_obj.title = description httpB_hashInd.add_observable(file_obj) elif description == 'PlugX RAT dropper': file_obj = File() file_obj.add_hash(Hash(obs)) file_obj.title = description plugX_hashInd.add_observable(file_obj) else: print "TTP not found" #print ip_rules ip_rule = generate_snort(ip_rules, 'Address', str(infra_IPInd.id_).split(':',1)[1].split('-',1)[1]) ip_rule_M = generate_snort(ip_rules_M, 'Address', str(infra_IPInd_M.id_).split(':',1)[1].split('-',1)[1]) ip_tm = SnortTestMechanism() ip_tm.rules = [ip_rule] ip_tm.efficacy = "High" ip_tm.producer = InformationSource(identity=Identity(name="Auto")) infra_IPInd.test_mechanisms = [ip_tm] ip_M_tm = SnortTestMechanism() ip_M_tm.rules = [ip_rule_M] ip_M_tm.efficacy = "Medium" ip_M_tm.producer = InformationSource(identity=Identity(name="Auto")) infra_IPInd_M.test_mechanisms = [ip_M_tm] domain_tm = SnortTestMechanism() domain_tm.rules = domain_rules domain_tm.efficacy = "High" domain_tm.producer = InformationSource(identity=Identity(name="Auto")) infra_domainInd.test_mechanisms = [domain_tm] #============= # Add the composed content to the structure #============= stix_package.add_indicator(infra_domainInd) stix_package.add_indicator(infra_IPInd) stix_package.add_indicator(infra_IPInd_M) stix_package.add_indicator(httpBDpr_hashInd) stix_package.add_indicator(httpB_hashInd) stix_package.add_indicator(plugX_hashInd) stix_package.add_ttp(ttp_infrastructure) stix_package.add_ttp(ttp_httpB) stix_package.add_ttp(ttp_httpBDpr) stix_package.add_ttp(ttp_plugX) """ if outFormat =='dict': print stix_package.to_dict() if outFormat =='json': parsed = stix_package.to_json() jsonpkg = json.loads(parsed) pprint.pprint(jsonpkg) if outFormat =='stix': print stix_package.to_xml() """ #if verbose: #print stix_package.to_xml() #pprint(stix_package.to_json()) return stix_package
def add_ais_marking(stix_package, proprietary, consent, color, **kwargs): """ This utility functions aids in the creation of an AIS marking and appends it to the provided STIX package. Args: stix_package: A stix.core.STIXPackage object. proprietary: True if marking uses IsProprietary, False for NotProprietary. consent: A string with one of the following values: "EVERYONE", "NONE" or "USG". color: A string that corresponds to TLP values: "WHITE", "GREEN" or "AMBER". **kwargs: Six required keyword arguments that are used to create a CIQ identity object. These are: country_name_code, country_name_code_type, admin_area_name_code, admin_area_name_code_type, organisation_name, industry_type. Raises: ValueError: When keyword arguments are missing. User did not supply correct values for: proprietary, color and consent. Note: The following line is required to register the AIS extension:: >>> import stix.extensions.marking.ais Any Markings under STIX Header will be removed. Please follow the guidelines for `AIS`_. The industry_type keyword argument accepts: a list of string based on defined sectors, a pipe-delimited string of sectors, or a single sector. .. _AIS: https://www.us-cert.gov/ais """ from stix.common import InformationSource from stix.extensions.identity.ciq_identity_3_0 import ( CIQIdentity3_0Instance, STIXCIQIdentity3_0, PartyName, Address, Country, NameElement, OrganisationInfo, AdministrativeArea) from stix.core.stix_header import STIXHeader from stix.data_marking import MarkingSpecification, Marking args = ('country_name_code', 'country_name_code_type', 'industry_type', 'admin_area_name_code', 'admin_area_name_code_type', 'organisation_name') diff = set(args) - set(kwargs.keys()) if diff: msg = 'All keyword arguments must be provided. Missing: {0}' raise ValueError(msg.format(tuple(diff))) party_name = PartyName() party_name.add_organisation_name(kwargs['organisation_name']) country = Country() country_name = NameElement() country_name.name_code = kwargs['country_name_code'] country_name.name_code_type = kwargs['country_name_code_type'] country.add_name_element(country_name) admin_area = AdministrativeArea() admin_area_name = NameElement() admin_area_name.name_code = kwargs['admin_area_name_code'] admin_area_name.name_code_type = kwargs['admin_area_name_code_type'] admin_area.add_name_element(admin_area_name) address = Address() address.country = country address.administrative_area = admin_area org_info = OrganisationInfo() org_info.industry_type = _validate_and_create_industry_type(kwargs['industry_type']) id_spec = STIXCIQIdentity3_0() id_spec.party_name = party_name id_spec.add_address(address) id_spec.organisation_info = org_info identity = CIQIdentity3_0Instance() identity.specification = id_spec if proprietary is True: proprietary_obj = IsProprietary() consent = 'EVERYONE' elif proprietary is False: proprietary_obj = NotProprietary() else: raise ValueError('proprietary expected True or False.') proprietary_obj.ais_consent = AISConsentType(consent=consent) proprietary_obj.tlp_marking = TLPMarkingType(color=color) ais_marking = AISMarkingStructure() if isinstance(proprietary_obj, IsProprietary): ais_marking.is_proprietary = proprietary_obj else: ais_marking.not_proprietary = proprietary_obj marking_spec = MarkingSpecification() marking_spec.controlled_structure = '//node() | //@*' marking_spec.marking_structures.append(ais_marking) marking_spec.information_source = InformationSource() marking_spec.information_source.identity = identity if not stix_package.stix_header: stix_package.stix_header = STIXHeader() # Removes any other Markings if present. stix_package.stix_header.handling = Marking() stix_package.stix_header.handling.add_marking(marking_spec)
def create_cybox_object(self, jdict, whitelist, config): listObservables = [] NS = cybox.utils.Namespace("cert.siemens.com", "siemens_cert") cybox.utils.set_id_namespace(NS) """ store information about malware binary that was analyzed """ if 'target' in jdict and 'category' in jdict['target'] and jdict['target']['category'] == 'file': log.debug("handling File information ...") main_file_object = self.__create_cybox_main_file(jdict['target']['file']) file_md5 = jdict['target']['file']['md5'] elif 'target' in jdict and 'category' in jdict['target'] and jdict['target']['category'] == 'url': log.warning("Not a file analysis report! URL reports not handled") return else: log.error("No target information in report ... skipping") return """ try to find email that dropped this attachment """ if config["attachemail"] or config["referenceemail"]: log.info("handling email attack vector information ...") email_object_properties, email_observables_list, email_stix_path_tuple_list = self.__check_malware_mailing_list(file_md5, log, config) if email_object_properties and len(email_object_properties)>0: for email_object in email_object_properties: main_file_object.add_related(email_object, "Contained_Within", inline=False) else: log.warning("failed linking mail object (no objects to link)") email_stix_path_tuple_list = [] else: email_object = None email_observables = [] email_stix_path_tuple_list = [] """ store extended information about malware file """ if 'static' in jdict: log.debug("handling extended File information ...") win_executable_extension = self.__create_cybox_win_executable(jdict['target']['file'], jdict['static']) if win_executable_extension: main_file_object.add_related(win_executable_extension, "Characterized_By", inline=False) win_executable_extension = [win_executable_extension] else: log.warning("No extended File information found") win_executable_extension = [] """ store domains connected to """ if 'network' in jdict and 'domains' in jdict['network']: log.debug("handling Domain information ...") domains, addresses = self.__create_cybox_domains(jdict['network']['domains'], whitelist) for dom in domains: main_file_object.add_related(dom, 'Connected_To', inline=False) else: domains = [] addresses = [] """ store http session information """ if 'network' in jdict and 'http' in jdict['network']: log.debug("handling HTTP information ...") http_requests = self.__create_cybox_https(jdict['network']['http'], whitelist) for session in http_requests: main_file_object.add_related(session, 'Connected_To', inline=False) else: http_requests = [] """ store dns queries information about the malware """ if 'network' in jdict and 'dns' in jdict['network']: log.debug("handling DNS information ...") queries = self.__create_cybox_dns_queries(jdict['network']['dns'], whitelist) for query in queries: main_file_object.add_related(query, 'Connected_To', inline=False) else: queries = [] """ store information about dropped files """ if 'dropped' in jdict: log.debug('handling dropped files ...') dropped = self.__create_cybox_dropped_files(jdict['dropped'], jdict['target']['file']['sha256']) for drop in dropped: main_file_object.add_related(drop, 'Dropped', inline=False) else: dropped = [] """ store virustotal information """ if 'virustotal' in jdict and 'positives' in jdict['virustotal']: log.debug('handling virustotal information ...') vtInformationTools = self.__create_stix_virustotal(jdict['virustotal'], log, config) vtFound = True else: vtInformationTools = [] vtFound = False """ create observables """ if config["attachemail"] and len(email_observables)>0: obs = Observables([main_file_object]+email_observables+win_executable_extension+domains+addresses+http_requests+dropped+queries) else: obs = Observables([main_file_object]+win_executable_extension+domains+addresses+http_requests+dropped+queries) """ generate stix id with siemens namespace """ if config: stix_id_generator = stix.utils.IDGenerator(namespace={config["xmlns"]: config["namespace"]}) else: stix_id_generator = stix.utils.IDGenerator(namespace={"cert.siemens.com": "siemens_cert"}) """ create stix package """ stix_id = stix_id_generator.create_id() stix_package = STIXPackage(observables=obs, id_=stix_id) stix_header = STIXHeader() stix_header.title = "Analysis report: %s" % (str(main_file_object.file_name).decode('utf8', errors='xmlcharrefreplace')) if 'info' in jdict and 'started' in jdict['info']: sandbox_report_date = dateparser.parse(jdict['info']['started']+' CET').isoformat() else: sandbox_report_date = datetime.datetime.now(pytz.timezone('Europe/Berlin')).isoformat() stix_header.description = 'Summarized analysis results for file "%s" with MD5 hash "%s" created on %s.' % (str(main_file_object.file_name).decode('utf8', errors='xmlcharrefreplace'), main_file_object.hashes.md5, sandbox_report_date) stix_header.add_package_intent("Malware Characterization") """ create markings """ spec = MarkingSpecification() spec.idref = stix_id spec.controlled_structure = "//node()" tlpmark = TLPMarkingStructure() if config: if not vtFound: tlpmark.color = config["color"] else: tlpmark.color = "GREEN" elif vtFound: tlpmark.color = "GREEN" else: tlpmark.color = "AMBER" spec.marking_structure = [tlpmark] """ attach to header """ stix_header.handling = Marking([spec]) stix_information_source = InformationSource() stix_information_source.time = Time(produced_time=sandbox_report_date) stix_information_source.tools = ToolInformationList([ToolInformation(tool_name="SIEMENS-ANALYSIS-TOOL-ID-12", tool_vendor="ANALYSIS-ID: %s" % (jdict['info']['id']))]+vtInformationTools) stix_header.information_source = stix_information_source stix_package.stix_header = stix_header """ write result xml file """ xml_file_name = "stix-%s-malware-report.xml" % (file_md5) xml_report_file_path = os.path.join(self.reports_path, xml_file_name) fp = open(xml_report_file_path, 'w') if config: fp.write(stix_package.to_xml(ns_dict={config["xmlns"]: config["namespace"]})) else: fp.write(stix_package.to_xml(ns_dict={'cert.siemens.com': 'siemens_cert'})) fp.close() if config["copytoshare"]: self.__copy_xml_to_ti_share(xml_report_file_path, xml_file_name, config) for item in email_stix_path_tuple_list: self.__copy_xml_to_ti_share(item[0], item[1], config, "email") else: log.warning("copy to TI share is disabled: %s" % (config["copytoshare"])) return
def gen_stix_observable_sample(config, target=None, datatype=None, title='random test data', description='random test data', package_intents='Indicators - Watchlist', tlp_color='WHITE'): '''generate sample stix data comprised of indicator_count indicators of type datatype''' # setup the xmlns... xmlns_url = config['edge']['sites'][target]['stix']['xmlns_url'] xmlns_name = config['edge']['sites'][target]['stix']['xmlns_name'] set_stix_id_namespace({xmlns_url: xmlns_name}) set_cybox_id_namespace(Namespace(xmlns_url, xmlns_name)) # construct a stix package... stix_package = STIXPackage() stix_header = STIXHeader() stix_header.title = title stix_header.description = description stix_header.package_intents = package_intents marking = MarkingSpecification() marking.controlled_structure = '../../../../descendant-or-self::node()' tlp_marking = TLPMarkingStructure() tlp_marking.color = tlp_color marking.marking_structures.append(tlp_marking) stix_package.stix_header = stix_header stix_package.stix_header.handling = Marking() stix_package.stix_header.handling.add_marking(marking) # ...and stuff it full of random sample data :-) if datatype == 'ip': addr = Address(address_value=datagen.generate_random_ip_address(), category='ipv4-addr') addr.condition = 'Equals' stix_package.add_observable(Observable(addr)) elif datatype == 'domain': domain = DomainName() domain.type_ = 'FQDN' domain.value = datagen.generate_random_domain(config) domain.condition = 'Equals' stix_package.add_observable(Observable(domain)) elif datatype == 'filehash': file_object = File() file_object.file_name = str(uuid.uuid4()) + '.exe' hashes = datagen.generate_random_hashes() for hash in hashes.keys(): file_object.add_hash(Hash(hashes[hash], type_=hash.upper())) for i in file_object.hashes: i.simple_hash_value.condition = "Equals" stix_package.add_observable(Observable(file_object)) elif datatype == 'email': try: msg = datagen.get_random_spam_msg(config) email = EmailMessage() email.header = EmailHeader() header_map = {'Subject': 'subject', 'To': 'to', 'Cc': 'cc', 'Bcc': 'bcc', 'From': 'from_', 'Sender': 'sender', 'Date': 'date', 'Message-ID': 'message_id', 'Reply-To': 'reply_to', 'In-Reply-To': 'in_reply_to', 'Content-Type': 'content_type', 'Errors-To': 'errors_to', 'Precedence': 'precedence', 'Boundary': 'boundary', 'MIME-Version': 'mime_version', 'X-Mailer': 'x_mailer', 'User-Agent': 'user_agent', 'X-Originating-IP': 'x_originating_ip', 'X-Priority': 'x_priority'} # TODO handle received_lines for key in header_map.keys(): val = msg.get(key, None) if val: email.header.__setattr__(header_map[key], val) email.header.__getattribute__(header_map[key]).condition = \ 'Equals' # TODO handle email bodies (it's mostly all there except for # handling weird text encoding problems that were making # libcybox stacktrace) # body = get_email_payload(random_spam_msg) # if body: # email.raw_body = body stix_package.add_observable(Observable(email)) except: return(None) observable_id = stix_package.observables.observables[0].id_ return(observable_id, stix_package)
def main(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 = raw_input("Insert Title Ioc:") # La description strutturiamola come segue # <IOC PRODUCER> - <Descrizione della minaccia/campagna> - <URL (if any)> DESCRIPTION = raw_input("Insert Decription:") # La sorgente che ha generato l'IoC con riferimento a Cyber Saiyan Community IDENTITY = raw_input("Insert User Identity:") # File degli IoC IOCFILE = raw_input("Add IoC Source File:") # Prefisso STIX output files STIX 1.2 e STIX 2 OUTFILEPREFIX = "package" # Short Description - UNUSED #SHORT = "Emotet" ###################################################################### VERBOSE = 0 # UTF8 encode TITLE = TITLE.encode('utf8') DESCRIPTION = DESCRIPTION.encode('utf8') IDENTITY = IDENTITY.encode('utf8') print "\nStix File generation in progress...." #print (TITLE) #"TITLE: " + TITLE #print (DESCRIPTION) #"DESCRIPTION: " + DESCRIPTION #print (IDENTITY) #"IDENTITY: " + IDENTITY #print (IOCFILE) #"IOC FILE: " + IOCFILE #print "---------------------" ######################## # Commond data timestamp = datetime.datetime.fromtimestamp( time.time()).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) # 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.MarkingDefinition(definition_type="tlp", definition={"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 ioc = loaddata(IOCFILE) if (VERBOSE): print "Reading IoC file " + IOCFILE + "..." 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: # STIX 1.2 filei = File() filei.add_hash(Hash(ioc)) obsi = Observable(filei) indicatorHASH.add_observable(obsi) if (VERBOSE): print "SHA256: " + ioc notfound = 0 # STIX 2 pattern_sha256.append("[file:hashes.'SHA-256' = '" + ioc + "'] OR ") #md5 p = re.compile(r"^[0-9a-f]{32}$", re.IGNORECASE) m = p.match(ioc) if m and notfound: # STIX 1.2 filej = File() filej.add_hash(Hash(ioc)) obsj = Observable(filej) indicatorHASH.add_observable(obsj) if (VERBOSE): print "MD5: " + ioc notfound = 0 # STIX 2 pattern_md5.append("[file:hashes.'MD5' = '" + ioc + "'] OR ") #sha1 p = re.compile(r"^[0-9a-f]{40}$", re.IGNORECASE) m = p.match(ioc) if m and notfound: # STIX 1.2 filek = File() filek.add_hash(Hash(ioc)) obsk = Observable(filek) indicatorHASH.add_observable(obsk) if (VERBOSE): print "SHA1: " + ioc notfound = 0 # STIX 2 pattern_sha1.append("[file:hashes.'SHA1' = '" + ioc + "'] OR ") #domains if validators.domain(ioc) and notfound: # 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 notfound = 0 # STIX 2 pattern_domain.append("[domain-name:value = '" + ioc + "'] OR ") #url if validators.url(ioc) and notfound: # 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 notfound = 0 # STIX 2 pattern_url.append("[url:value = '" + ioc + "'] OR ") #ip if validators.ipv4(ioc) and notfound: # STIX 1.2 ip = Address() ip.address_value = ioc obsu = Observable(ip) indiIP.add_observable(obsu) if (VERBOSE): print "IP: " + ioc notfound = 0 # STIX 2 pattern_ip.append("[ipv4-addr:value = '" + ioc + "'] OR ") #email if validators.email(ioc) and notfound: # STIX 1.2 email = EmailAddress() email.address_value = ioc obsu = Observable(email) indiEMAIL.add_observable(obsu) if (VERBOSE): print "Email: " + ioc notfound = 0 # STIX 2 pattern_email.append("[email-message:from_ref.value = '" + ioc + "'] 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 bundle = stix2.Bundle(objects=bundle_objects) ######################## # save to STIX 1.2 file print print "Writing STIX 1.2 package: " + OUTFILEPREFIX + ".stix" f = open(OUTFILEPREFIX + ".stix", "w") f.write(wrapper.to_xml()) f.close() ######################## # save to STIX 2 file print "Writing STIX 2 package: " + OUTFILEPREFIX + ".stix2" g = open(OUTFILEPREFIX + ".stix2", "w") sys.stdout = g print bundle
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 main(): ###################################################################### # MODIFICARE LE VARIABILI SEGUENTI # Il title e' ID univoco della minaccia (es. Cobalt / Danabot / APT28) MyTITLE = "Gootkit" # La description strutturiamola come segue # <IOC PRODUCER> - <Descrizione della minaccia/campagna> - <URL (if any)> DESCRIPTION = "D3Lab - Malspam Gootkit con dropper da 450+ MB - https://www.d3lab.net/malspam-gootkit-con-dropper-da-450-mb/" # La sorgente che ha generato l'IoC con riferimento a Cyber Saiyan Community IDENTITY = "D3Lab via Cyber Saiyan Community" # ###################################################################### # read IoC files file_sha256 = "CS-sha256.txt" sha256 = loaddata(file_sha256) file_md5 = "CS-md5.txt" md5 = loaddata(file_md5) file_sha1 = "CS-sha1.txt" sha1 = loaddata(file_sha1) file_domains = "CS-domain.txt" domains = loaddata(file_domains) file_urls = "CS-url.txt" urls = loaddata(file_urls) file_ips = "CS-ipv4.txt" ips = loaddata(file_ips) file_emails = "CS-email.txt" emails = loaddata(file_emails) # 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") print "Reading IoC sha256 file..." p = re.compile(r"^[0-9a-f]{64}$", re.IGNORECASE) for idx, sha256 in enumerate(sha256): m = p.match(sha256) if m: filei = File() filei.add_hash(Hash(sha256)) obsi = Observable(filei) indicatorHASH.add_observable(obsi) else: print " Malformed sha256: " + sha256 print print "Reading IoC md5 file..." p = re.compile(r"^[0-9a-f]{32}$", re.IGNORECASE) for idx, md5 in enumerate(md5): m = p.match(md5) if m: filej = File() filej.add_hash(Hash(md5)) obsj = Observable(filej) indicatorHASH.add_observable(obsj) else: print " Malformed md5: " + md5 print print "Reading IoC sha1 file..." p = re.compile(r"^[0-9a-f]{40}$", re.IGNORECASE) for idx, sha1 in enumerate(sha1): m = p.match(sha1) if m: filek = File() filek.add_hash(Hash(sha1)) obsk = Observable(filek) indicatorHASH.add_observable(obsk) else: print " Malformed sha1: " + sha1 print # DOMAIN indicators indiDOMAIN = Indicator() indiDOMAIN.title = MyTITLE + " - DOMAIN" indiDOMAIN.add_indicator_type("Domain Watchlist") print "Reading IoC domains file..." for idu, domains in enumerate(domains): if validators.domain(domains): url = URI() url.value = domains url.type_ = URI.TYPE_DOMAIN url.condition = "Equals" obsu = Observable(url) indiDOMAIN.add_observable(obsu) else: print " Malformed domain: " + domains print # URL indicators indiURL = Indicator() indiURL.title = MyTITLE + " - URL" indiURL.add_indicator_type("URL Watchlist") print "Reading IoC url file..." for idu, urls in enumerate(urls): if validators.url(urls): url = URI() url.value = urls url.type_ = URI.TYPE_URL url.condition = "Equals" obsu = Observable(url) indiURL.add_observable(obsu) else: print " Malformed url: " + urls print # IP indicators indiIP = Indicator() indiIP.title = MyTITLE + " - IP" indiIP.add_indicator_type("IP Watchlist") print "Reading IoC IP file..." for idu, ips in enumerate(ips): if validators.ipv4(ips): ip = Address() ip.address_value = ips obsu = Observable(ip) indiIP.add_observable(obsu) else: print " Malformed IP: " + ips print # EMAIL indicators indiEMAIL = Indicator() indiEMAIL.title = MyTITLE + " - EMAIL" indiEMAIL.add_indicator_type("Malicious E-mail") print "Reading IoC email file..." for idu, emails in enumerate(emails): if validators.email(emails): email = EmailAddress() email.address_value = emails obsu = Observable(email) indiEMAIL.add_observable(obsu) else: print " Malformed email: " + emails print # add all indicators 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 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)