def from_dict(cls, dict_repr, return_obj=None): if not dict_repr: return None if not return_obj: return_obj = cls() identity_dict = dict_repr.get('identity') time_dict = dict_repr.get('time') tools_list = dict_repr.get('tools') if identity_dict: xsi_type = identity_dict.get('xsi:type') if xsi_type: type_name = xsi_type.split(":")[1] if type_name == CIQIdentity3_0Instance._XML_TYPE: return_obj.identity = CIQIdentity3_0Instance.from_dict(identity_dict) else: raise TypeError('No known class for xsi:type: %s' % (xsi_type)) else: return_obj.identity = Identity.from_dict(identity_dict) if time_dict: return_obj.time = Time.from_dict(time_dict) if tools_list: return_obj.tools = ToolInformationList.from_list(tools_list) return return_obj
def from_dict(cls, dict_repr, return_obj=None): if not dict_repr: return None if not return_obj: return_obj = cls() identity_dict = dict_repr.get('identity') time_dict = dict_repr.get('time') tools_list = dict_repr.get('tools') if identity_dict: xsi_type = identity_dict.get('xsi:type') if xsi_type: type_name = xsi_type.split(":")[1] if type_name == CIQIdentity3_0Instance._XML_TYPE: return_obj.identity = CIQIdentity3_0Instance.from_dict( identity_dict) else: raise TypeError('No known class for xsi:type: %s' % (xsi_type)) else: return_obj.identity = Identity.from_dict(identity_dict) if time_dict: return_obj.time = Time.from_dict(time_dict) if tools_list: return_obj.tools = ToolInformationList.from_list(tools_list) return return_obj
def main(): # 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="python-stix", tool_vendor="The MITRE Corporation") # 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) # Set the header description stix_header.description = "Example" # Set the STIXPackage header stix_package.stix_header = stix_header # Print the XML! print(stix_package.to_xml()) # Print the dictionary! pprint(stix_package.to_dict())
def _create_observables(self, msg): o = Observables(self.__parse_email_message(msg)) t = ToolInformation() t.name = os.path.basename(__file__) t.description = StructuredText("Email to CybOX conversion script") t.vendor = "The MITRE Corporation" t.version = __version__ t_list = ToolInformationList() t_list.append(t) m = MeasureSource() m.tools = t_list o.observable_package_source = m return o
def from_obj(mal_dev_obj): if not mal_dev_obj: return None mal_dev_env_ = MalwareDevelopmentEnvironment() mal_dev_env_.tools = ToolInformationList.from_obj(mal_dev_obj.get_Tools()) if mal_dev_obj.get_Debugging_File(): mal_dev_env_.debugging_file = [File.from_obj(x) for x in mal_dev_obj.get_Debugging_File()] return mal_dev_env_
def from_dict(mal_dev_dict): if not mal_dev_dict: return None mal_dev_env_ = MalwareDevelopmentEnvironment() mal_dev_env_.tools = ToolInformationList.from_list(mal_dev_dict['tools']) if mal_dev_dict.get('debugging_file'): mal_dev_env_.debugging_file = [File.from_dict(x) for x in mal_dev_dict['debugging_file']] return mal_dev_env_
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 04" stix_package.stix_header = stix_header print(stix_package.to_xml()) print(stix_package.to_dict())
def from_dict(measure_source_dict): if not measure_source_dict: return None measure_source_ = MeasureSource() measure_source_.class_ = measure_source_dict.get('class') measure_source_.source_type = measure_source_dict.get('source_type') measure_source_.name = measure_source_dict.get('name') measure_source_.information_source_type = VocabString.from_dict(measure_source_dict.get('information_source_type')) measure_source_.tool_type = VocabString.from_dict(measure_source_dict.get('tool_type')) measure_source_.description = StructuredText.from_dict(measure_source_dict.get('description')) measure_source_.contributors = Personnel.from_list(measure_source_dict.get('contributors')) measure_source_.time = Time.from_dict(measure_source_dict.get('time')) measure_source_.tools = ToolInformationList.from_list(measure_source_dict.get('tools')) measure_source_.platform = None #TODO: add support measure_source_.system = ObjectProperties.from_dict(measure_source_dict.get('system')) measure_source_.instance = ObjectProperties.from_dict(measure_source_dict.get('instance')) return measure_source_
def from_obj(measure_source_obj): if not measure_source_obj: return None measure_source_ = MeasureSource() measure_source_.class_ = measure_source_obj.get_class() measure_source_.source_type = measure_source_obj.get_source_type() measure_source_.name = measure_source_obj.get_name() measure_source_.information_source_type = VocabString.from_obj(measure_source_obj.get_Information_Source_Type()) measure_source_.tool_type = VocabString.from_obj(measure_source_obj.get_Tool_Type()) measure_source_.description = StructuredText.from_obj(measure_source_obj.get_Description()) measure_source_.contributors = Personnel.from_obj(measure_source_obj.get_Contributors()) measure_source_.time = Time.from_obj(measure_source_obj.get_Time()) measure_source_.tools = ToolInformationList.from_obj(measure_source_obj.get_Tools()) measure_source_.platform = None #TODO: add support measure_source_.system = ObjectProperties.from_obj(measure_source_obj.get_System()) measure_source_.instance = ObjectProperties.from_obj(measure_source_obj.get_Instance()) return measure_source_
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 execute(self, device_info, data_dir_path, simple_output=False, html_output=False): """ :param device_info: DeviceInfo :param data_dir_path: string """ extracted_data_dir_path = os.path.join(data_dir_path, EXTRACTED_DATA_DIR_NAME) try: os.makedirs(extracted_data_dir_path) except OSError as exception: if exception.errno != errno.EEXIST: raise self.extractor.execute(extracted_data_dir_path, self.param_values) set_id_method(IDGenerator.METHOD_INT if simple_output else IDGenerator.METHOD_UUID) inspected_objects, source_objects = self.inspector.execute(device_info, extracted_data_dir_path) inspected_observables = Observables(inspected_objects) source_observables = Observables(source_objects) tool_info = ToolInformation() tool_info.name = 'Android Inspector' tool_info.version = '1.0' measure_source = MeasureSource() measure_source.tool_type = ToolType.TERM_DIGITAL_FORENSICS measure_source.tools = ToolInformationList([tool_info]) measure_source.time = Time(produced_time=datetime.now().isoformat()) inspected_observables.observable_package_source = measure_source source_observables.observable_package_source = measure_source write_observables_xml_file(inspected_observables, os.path.join(data_dir_path, INSPECTED_DATA_FILE_NAME), simple_output) write_observables_xml_file(source_observables, os.path.join(data_dir_path, SOURCE_DATA_FILE_NAME), simple_output) if html_output: generate_html_files(data_dir_path)
def from_obj(cls, obj, return_obj=None): if not obj: return None if not return_obj: return_obj = cls() if obj.get_Identity(): identity_obj = obj.get_Identity() if isinstance(identity_obj, ciq_identity_binding.CIQIdentity3_0InstanceType): return_obj.identity = CIQIdentity3_0Instance.from_obj(identity_obj) elif type(identity_obj) == stix_common_binding.IdentityType: return_obj.identity = Identity.from_obj(identity_obj) if obj.get_Time(): return_obj.time = Time.from_obj(obj.get_Time()) if obj.get_Tools(): return_obj.tools = ToolInformationList.from_obj(obj.get_Tools()) return return_obj
def _create_stix_package(self): """Create and return a STIX Package with the basic information populated. Returns: A ``stix.STIXPackage`` object with a STIX Header that describes the intent of the package in terms of capturing malware artifacts, along with some associated metadata. """ stix_package = STIXPackage() stix_header = STIXHeader() stix_header.add_package_intent("Indicators - Malware Artifacts") if self.file_name: stix_header.title = "STIX Indicators extracted from MAEC file: " + str( self.file_name) # Add the Information Source to the STIX Header tool_info = ToolInformation() stix_header.information_source = InformationSource() tool_info.name = "MAEC to STIX" tool_info.version = str(__version__) stix_header.information_source.tools = ToolInformationList(tool_info) stix_package.stix_header = stix_header return stix_package
def from_obj(cls, obj, return_obj=None): if not obj: return None if not return_obj: return_obj = cls() if obj.get_Identity(): identity_obj = obj.get_Identity() if isinstance(identity_obj, ciq_identity_binding.CIQIdentity3_0InstanceType): return_obj.identity = CIQIdentity3_0Instance.from_obj( identity_obj) elif type(identity_obj) == stix_common_binding.IdentityType: return_obj.identity = Identity.from_obj(identity_obj) if obj.get_Time(): return_obj.time = Time.from_obj(obj.get_Time()) if obj.get_Tools(): return_obj.tools = ToolInformationList.from_obj(obj.get_Tools()) return return_obj
def _observable_to_indicator_stix(observable): """Translate a CybOX Observable into a STIX Indicator. Args: observable: Observable object that will be translated Returns: Indicator object with STIX utility and CybOX tags """ # Build STIX tool content tool = ToolInformation(tool_name='OpenIOC to STIX Utility') tool.version = version.__version__ # Build Indicator.producer contents producer = InformationSource() producer.tools = ToolInformationList(tool) # Build Indicator indicator = Indicator(title="CybOX-represented Indicator Created from OpenIOC File") indicator.producer = producer indicator.add_observable(observable) return indicator
def transform(self, event): stix_package = STIXPackage() self._add_header(stix_package, "Unauthorized traffic to honeypot", "Describes one or more honeypot incidents") incident = Incident( id_="%s:%s-%s" % (CONPOT_NAMESPACE, 'incident', event['session_id'])) initial_time = StixTime() initial_time.initial_compromise = event['timestamp'].isoformat() incident.time = initial_time incident.title = "Conpot Event" incident.short_description = "Traffic to Conpot ICS honeypot" incident.add_category( VocabString(value='Scans/Probes/Attempted Access')) tool_list = ToolInformationList() tool_list.append( ToolInformation.from_dict({ 'name': "Conpot", 'vendor': "Conpot Team", 'version': conpot.__version__, 'description': textwrap.dedent( 'Conpot is a low interactive server side Industrial Control Systems ' 'honeypot designed to be easy to deploy, modify and extend.' ) })) incident.reporter = InformationSource(tools=tool_list) incident.add_discovery_method("Monitoring Service") incident.confidence = "High" # Victim Targeting by Sector ciq_identity = CIQIdentity3_0Instance() #identity_spec = STIXCIQIdentity3_0() #identity_spec.organisation_info = OrganisationInfo(industry_type="Electricity, Industrial Control Systems") #ciq_identity.specification = identity_spec ttp = TTP( title= "Victim Targeting: Electricity Sector and Industrial Control System Sector" ) ttp.victim_targeting = VictimTargeting() ttp.victim_targeting.identity = ciq_identity incident.leveraged_ttps.append(ttp) indicator = Indicator(title="Conpot Event") indicator.description = "Conpot network event" indicator.confidence = "High" source_port = Port.from_dict({ 'port_value': event['remote'][1], 'layer4_protocol': 'tcp' }) dest_port = Port.from_dict({ 'port_value': self.protocol_to_port_mapping[event['data_type']], 'layer4_protocol': 'tcp' }) source_ip = Address.from_dict({ 'address_value': event['remote'][0], 'category': Address.CAT_IPV4 }) dest_ip = Address.from_dict({ 'address_value': event['public_ip'], 'category': Address.CAT_IPV4 }) source_address = SocketAddress.from_dict({ 'ip_address': source_ip.to_dict(), 'port': source_port.to_dict() }) dest_address = SocketAddress.from_dict({ 'ip_address': dest_ip.to_dict(), 'port': dest_port.to_dict() }) network_connection = NetworkConnection.from_dict({ 'source_socket_address': source_address.to_dict(), 'destination_socket_address': dest_address.to_dict(), 'layer3_protocol': "IPv4", 'layer4_protocol': "TCP", 'layer7_protocol': event['data_type'], 'source_tcp_state': "ESTABLISHED", 'destination_tcp_state': "ESTABLISHED", }) indicator.add_observable(Observable(network_connection)) artifact = Artifact() artifact.data = json.dumps(event['data']) artifact.packaging.append(ZlibCompression()) artifact.packaging.append(Base64Encoding()) indicator.add_observable(Observable(artifact)) incident.related_indicators.append(indicator) stix_package.add_incident(incident) stix_package_xml = stix_package.to_xml() return stix_package_xml
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 == RelationshipTypes.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 transform(self, event): self._set_namespace(self.config['contact_domain'], self.config['contact_name']) stix_package = STIXPackage() self._add_header(stix_package, "Unauthorized traffic to honeypot", "Describes one or more honeypot incidents") incident = Incident(id_="%s:%s-%s" % (self.config['contact_name'], 'incident', event['session_id'])) initial_time = StixTime() initial_time.initial_compromise = event['timestamp'].isoformat() incident.time = initial_time incident.title = "Conpot Event" incident.short_description = "Traffic to Conpot ICS honeypot" incident.add_category(VocabString(value='Scans/Probes/Attempted Access')) tool_list = ToolInformationList() tool_list.append(ToolInformation.from_dict({ 'name': "Conpot", 'vendor': "Conpot Team", 'version': conpot.__version__, 'description': textwrap.dedent('Conpot is a low interactive server side Industrial Control Systems ' 'honeypot designed to be easy to deploy, modify and extend.') })) incident.reporter = InformationSource(tools=tool_list) incident.add_discovery_method("Monitoring Service") incident.confidence = "High" # Victim Targeting by Sector ciq_identity = CIQIdentity3_0Instance() #identity_spec = STIXCIQIdentity3_0() #identity_spec.organisation_info = OrganisationInfo(industry_type="Electricity, Industrial Control Systems") #ciq_identity.specification = identity_spec ttp = TTP(title="Victim Targeting: Electricity Sector and Industrial Control System Sector") ttp.victim_targeting = VictimTargeting() ttp.victim_targeting.identity = ciq_identity incident.leveraged_ttps.append(ttp) indicator = Indicator(title="Conpot Event") indicator.description = "Conpot network event" indicator.confidence = "High" source_port = Port.from_dict({'port_value': event['remote'][1], 'layer4_protocol': 'tcp'}) dest_port = Port.from_dict({'port_value': self.protocol_to_port_mapping[event['data_type']], 'layer4_protocol': 'tcp'}) source_ip = Address.from_dict({'address_value': event['remote'][0], 'category': Address.CAT_IPV4}) dest_ip = Address.from_dict({'address_value': event['public_ip'], 'category': Address.CAT_IPV4}) source_address = SocketAddress.from_dict({'ip_address': source_ip.to_dict(), 'port': source_port.to_dict()}) dest_address = SocketAddress.from_dict({'ip_address': dest_ip.to_dict(), 'port': dest_port.to_dict()}) network_connection = NetworkConnection.from_dict( {'source_socket_address': source_address.to_dict(), 'destination_socket_address': dest_address.to_dict(), 'layer3_protocol': u"IPv4", 'layer4_protocol': u"TCP", 'layer7_protocol': event['data_type'], 'source_tcp_state': u"ESTABLISHED", 'destination_tcp_state': u"ESTABLISHED", } ) indicator.add_observable(Observable(network_connection)) artifact = Artifact() artifact.data = json.dumps(event['data']) artifact.packaging.append(ZlibCompression()) artifact.packaging.append(Base64Encoding()) indicator.add_observable(Observable(artifact)) incident.related_indicators.append(indicator) stix_package.add_incident(incident) stix_package_xml = stix_package.to_xml() return stix_package_xml
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 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 == RelationshipTypes.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