def pre_import_stix(file, cluster=None): from stix.core import STIXPackage pkg = STIXPackage() pkg = pkg.from_xml(file) reports = pkg.reports header = None timestamp = "" try: header = reports[0].header timestamp = reports[0].timestamp except: header = pkg.header # sc = header_to_subcluster(header) sc = {"name": header.title, "description": header.description, "firstseen": timestamp} """ campaigns= pkg.campaigns for campaign in campaigns: s = campaign_to_subcluster(campaign) if not s in sc: sc.append(s) """ # ttp = pkg.ttps obs = pkg.observables if sc: sc["node"] = [] sc = obs_to_node(obs, sc) sc["cluster"] = cluster return sc
def main(): stix_package = STIXPackage() ta = ThreatActor() ta.title = "Disco Team Threat Actor Group" ta.identity = CIQIdentity3_0Instance() identity_spec = STIXCIQIdentity3_0() identity_spec.party_name = PartyName() identity_spec.party_name.add_organisation_name(OrganisationName("Disco Tean", type_="CommonUse")) identity_spec.party_name.add_organisation_name(OrganisationName("Equipo del Discoteca", type_="UnofficialName")) identity_spec.add_language("Spanish") address = Address() address.country = Country() address.country.add_name_element("United States") address.administrative_area = AdministrativeArea() address.administrative_area.add_name_element("California") identity_spec.add_address(address) identity_spec.add_electronic_address_identifier("*****@*****.**") ta.identity.specification = identity_spec stix_package.add_threat_actor(ta) print stix_package.to_xml()
def main(): from stix.campaign import Campaign, Attribution from stix.threat_actor import ThreatActor from stix.incident import Incident from stix.core import STIXPackage from stix.ttp import TTP, VictimTargeting ttp = TTP() ttp.title = "Victim Targeting: Customer PII and Financial Data" ttp.victim_targeting = VictimTargeting() ttp.victim_targeting.add_targeted_information("Information Assets - Financial Data") actor = ThreatActor() actor.title = "People behind the intrusion" attrib = Attribution() attrib.append(actor) c = Campaign() c.attribution = [] c.attribution.append(attrib) c.title = "Compromise of ATM Machines" c.related_ttps.append(ttp) c.related_incidents.append(Incident(idref="example:incident-229ab6ba-0eb2-415b-bdf2-079e6b42f51e")) c.related_incidents.append(Incident(idref="example:incident-517cf274-038d-4ed4-a3ec-3ac18ad9db8a")) c.related_incidents.append(Incident(idref="example:incident-7d8cf96f-91cb-42d0-a1e0-bfa38ea08621")) pkg = STIXPackage() pkg.add_campaign(c) print pkg.to_xml()
def main(): from stix.coa import CourseOfAction, Objective from stix.common import Confidence from stix.core import STIXPackage from cybox.core import Observables from cybox.objects.address_object import Address pkg = STIXPackage() coa = CourseOfAction() coa.title = "Block traffic to PIVY C2 Server (10.10.10.10)" coa.stage = "Response" coa.type_ = "Perimeter Blocking" obj = Objective() obj.description = "Block communication between the PIVY agents and the C2 Server" obj.applicability_confidence = Confidence("High") coa.objective = obj coa.impact = "Low" coa.impact.description = "This IP address is not used for legitimate hosting so there should be no operational impact." coa.cost = "Low" coa.efficacy = "High" addr = Address(address_value="10.10.10.10", category=Address.CAT_IPV4) coa.parameter_observables = Observables(addr) pkg.add_course_of_action(coa) print(pkg.to_xml(encoding=None))
def main(): # Create a CyboX File Object f = File() # This automatically detects that it's an MD5 hash based on the length f.add_hash("4EC0027BEF4D7E1786A04D021FA8A67F") # Create an Indicator with the File Hash Object created above. indicator = Indicator() indicator.title = "File Hash Example" indicator.description = ( "An indicator containing a File observable with an associated hash" ) indicator.set_producer_identity("The MITRE Corporation") indicator.set_produced_time(utils.dates.now()) # Add The File Object to the Indicator. This will promote the CybOX Object # to a CybOX Observable internally. indicator.add_object(f) # Create a STIX Package stix_package = STIXPackage() # Create the STIX Header and add a description. stix_header = STIXHeader() stix_header.description = "File Hash Indicator Example" stix_package.stix_header = stix_header # Add our Indicator object. The add() method will inspect the input and # append it to the `stix_package.indicators` collection. stix_package.add(indicator) # Print the XML! print(stix_package.to_xml())
def test_user_provided_ns(self): """Test that user-provided namespaces are serialized. """ p = STIXPackage() nsinfo = nsparser.NamespaceInfo() # Collect classes nsinfo.collect(p) TEST_PREFIX = 'test' TEST_NS = 'a:unit:test' NEW_STIX_PREFIX = 'newstix' NEW_STIX_NS = "http://stix.mitre.org/stix-1" test_dict = { TEST_NS: TEST_PREFIX, NEW_STIX_NS: NEW_STIX_PREFIX } finalized = nsinfo._finalize_namespaces(ns_dict=test_dict) nsinfo.finalized_namespaces self.assertEqual(finalized.get(TEST_PREFIX), TEST_NS) self.assertEqual(finalized.get(NEW_STIX_PREFIX), NEW_STIX_NS) # Parse the exported document and make sure that the namespaces # made it through the serialization process. xml = p.to_xml(ns_dict=test_dict) e = lxml.etree.XML(xml) self.assertEqual(e.nsmap.get(TEST_PREFIX), TEST_NS) self.assertEqual(e.nsmap.get(NEW_STIX_PREFIX), NEW_STIX_NS)
def main(): rule = """ rule silent_banker : banker { meta: description = "This is just an example" thread_level = 3 in_the_wild = true strings: $a = {6A 40 68 00 30 00 00 6A 14 8D 91} $b = {8D 4D B0 2B C1 83 C0 27 99 6A 4E 59 F7 F9} $c = "UVODFRYSIHLNWPEJXQZAKCBGMT" condition: $a or $b or $c } """ stix_package = STIXPackage() indicator = Indicator(title="silent_banker", description="This is just an example") tm = YaraTestMechanism() tm.rule = rule tm.producer = InformationSource(identity=Identity(name="Yara")) tm.producer.references = ["http://plusvic.github.io/yara/"] indicator.test_mechanisms = [tm] stix_package.add_indicator(indicator) print stix_package.to_xml()
def to_stix(infile): """Converts the `infile` OpenIOC xml document into a STIX Package. Args: infile: OpenIOC xml filename to translate Returns: stix.core.STIXPackage object """ observables = to_cybox(infile) # Build Indicators from the Observable objects indicators = [_observable_to_indicator_stix(o) for o in observables] # Wrap the created Observables in a STIX Package/Indicator stix_package = STIXPackage() # Set the Indicators collection stix_package.indicators = indicators # Create and write the STIX Header. Warning: these fields have been # deprecated in STIX v1.2! stix_header = STIXHeader() stix_header.package_intent = PackageIntent.TERM_INDICATORS_MALWARE_ARTIFACTS stix_header.description = "CybOX-represented Indicators Translated from OpenIOC File" stix_package.stix_header = stix_header return stix_package
def main(): f = File() f.add_hash("4EC0027BEF4D7E1786A04D021FA8A67F") indicator = Indicator() indicator.title = "File Hash Example" indicator.description = "An indicator containing a File observable with an associated hash" indicator.set_producer_identity("The MITRE Corporation") indicator.set_produced_time(datetime.now(tzutc())) indicator.add_object(f) party_name = PartyName(name_lines=["Foo", "Bar"], person_names=["John Smith", "Jill Smith"], organisation_names=["Foo Inc.", "Bar Corp."]) ident_spec = STIXCIQIdentity3_0(party_name=party_name) ident_spec.add_electronic_address_identifier("*****@*****.**") ident_spec.add_free_text_line("Demonstrating Free Text!") ident_spec.add_contact_number("555-555-5555") ident_spec.add_contact_number("555-555-5556") identity = CIQIdentity3_0Instance(specification=ident_spec) indicator.set_producer_identity(identity) stix_package = STIXPackage() stix_header = STIXHeader() stix_header.description = "Example" stix_package.stix_header = stix_header stix_package.add_indicator(indicator) xml = stix_package.to_xml() print(xml)
def main(): # Create our CybOX Simple Hash Value shv = Hash() shv.simple_hash_value = "4EC0027BEF4D7E1786A04D021FA8A67F" # Create a CybOX File Object and add the Hash we created above. f = File() h = Hash(shv, Hash.TYPE_MD5) f.add_hash(h) # Create the STIX Package stix_package = STIXPackage() # Create the STIX Header and add a description. stix_header = STIXHeader() stix_header.description = "Simple File Hash Observable Example" stix_package.stix_header = stix_header # Add the File Hash Observable to the STIX Package. The add() method will # inspect the input and add it to the top-level stix_package.observables # collection. stix_package.add(f) # Print the XML! print(stix_package.to_xml())
def main(): pkg = STIXPackage() affected_asset = AffectedAsset() affected_asset.description = "Database server at hr-data1.example.com" affected_asset.type_ = "Database" affected_asset.type_.count_affected = 1 affected_asset.business_function_or_role = "Hosts the database for example.com" affected_asset.ownership_class = "Internally-Owned" affected_asset.management_class = "Internally-Managed" affected_asset.location_class = "Internally-Located" property_affected = PropertyAffected() property_affected.property_ = "Confidentiality" property_affected.description_of_effect = "Data was exfiltrated, has not been determined which data or how." property_affected.non_public_data_compromised = "Yes" property_affected.non_public_data_compromised.data_encrypted = False security_effect_nature = NatureOfSecurityEffect() security_effect_nature.append(property_affected) affected_asset.nature_of_security_effect = security_effect_nature affected_assets = AffectedAssets() affected_assets.append(affected_asset) incident = Incident(title="Exfiltration from hr-data1.example.com") incident.affected_assets = affected_assets pkg.add_incident(incident) print(pkg.to_xml(encoding=None))
def generateMainPackage(events): stix_package = STIXPackage() stix_header = STIXHeader() stix_header.title = "Export from " + namespace[1] + " MISP" stix_header.package_intents = "Threat Report" stix_package.stix_header = stix_header return stix_package
def buildSTIX(ident,confid,restconfid, effect, resteffect,typeIncident,resttype,asset,restasset,hashPkg): # IMPLEMENTATION WORKAROUND - # restConfid --> header.description # resteffect --> breach.description # resttype --> reporter.description # restasset --> reporter.identity.name # setup stix document stix_package = STIXPackage() stix_header = STIXHeader() stix_header.description = restconfid # "Example description" stix_package.stix_header = stix_header # add incident and confidence breach = Incident(id_=ident) breach.description = resteffect # "Intrusion into enterprise network" breach.confidence = Confidence() breach.confidence.value=confid breach._binding_class.xml_type = typeIncident # stamp with reporter breach.reporter = InformationSource() breach.reporter.description = resttype #"The person who reported it" breach.reporter.time = Time() breach.reporter.time.produced_time = datetime.strptime("2014-03-11","%Y-%m-%d") # when they submitted it breach.reporter.identity = Identity() breach.reporter.identity.name = restasset # "Sample Investigations, LLC" # set incident-specific timestamps breach.time = incidentTime() breach.title = "Breach of CyberTech Dynamics" breach.time.initial_compromise = datetime.strptime("2012-01-30", "%Y-%m-%d") breach.time.incident_discovery = datetime.strptime("2012-05-10", "%Y-%m-%d") breach.time.restoration_achieved = datetime.strptime("2012-08-10", "%Y-%m-%d") breach.time.incident_reported = datetime.strptime("2012-12-10", "%Y-%m-%d") # add the impact #impact = ImpactAssessment() #impact.add_effect("Unintended Access") #breach.impact_assessment = impact affected_asset = AffectedAsset() affected_asset.description = "Database server at hr-data1.example.com" affected_asset.type_ = asset breach.affected_assets = affected_asset #print("asset type: %s"%(breach.affected_assets[0].type_)) # add the victim breach.add_victim (hashPkg) # add the impact impact = ImpactAssessment() impact.add_effect(effect) breach.impact_assessment = impact stix_package.add_incident(breach) #print("hey, I've got an incident! list size=%s"%(len(stix_package._incidents))) # Print the XML! #print(stix_package.to_xml()) return stix_package
def init_stix(self): stix_package = STIXPackage() stix_header = STIXHeader() info_source = InformationSource() info_source.description = 'HAR file analysis of visit to malicious URL' stix_header.information_source = info_source stix_package.stix_header = stix_header return stix_package
def main(): fn = 'ex_01.xml' stix_package = STIXPackage.from_xml(fn) stix_dict = stix_package.to_dict() # parse to dictionary pprint(stix_dict) stix_package_two = STIXPackage.from_dict(stix_dict) # create python-stix object from dictionary xml = stix_package_two.to_xml() # generate xml from python-stix object print(xml)
def file_to_stix(file_): '''transform files into stix packages''' try: stix_package = STIXPackage.from_xml(file_) except UnsupportedVersionError as ex: updated = ramrod.update(file_) updated_xml = updated.document.as_stringio() stix_package = STIXPackage.from_xml(updated_xml) return stix_package
def __repr__(self): stix_package = STIXPackage() stix_header = STIXHeader() stix_package.stix_header = stix_header for d in self.data: i = self._create_indicator(d) stix_package.add_indicator(i) return stix_package.to_xml()
def pkg_builder(mailbox_cfg, mailitem): pkg = STIXPackage( id_="%s:Package-%s" % (constants.DEFAULT_STIX_ALIAS, uuid.uuid4()), indicators=data_to_indicator(mailbox_cfg, mailitem), stix_header=stix_header( title=mailitem.email_subject), ) data = pkg.to_xml(ns_dict={mailbox_cfg.stix_prefix: constants.DEFAULT_STIX_ALIAS}, include_idgen=False, include_schemalocs=False) #return StringIO(data) return data
def cvebuild(var): """Search for a CVE ID and return a STIX formatted response.""" cve = CVESearch() data = json.loads(cve.id(var)) if data: try: from stix.utils import set_id_namespace namespace = {NS: NS_PREFIX} set_id_namespace(namespace) except ImportError: from mixbox.idgen import set_id_namespace from mixbox.namespaces import Namespace namespace = Namespace(NS, NS_PREFIX, "") set_id_namespace(namespace) pkg = STIXPackage() pkg.stix_header = STIXHeader() pkg = STIXPackage() pkg.stix_header = STIXHeader() pkg.stix_header.handling = _marking() # Define the exploit target expt = ExploitTarget() expt.title = data['id'] expt.description = data['summary'] expt.information_source = InformationSource( identity=Identity(name="National Vulnerability Database")) # Add the vulnerability object to the package object expt.add_vulnerability(_vulnbuild(data)) # Add the COA object to the ET object for coa in COAS: expt.potential_coas.append( CourseOfAction( idref=coa['id'], timestamp=expt.timestamp)) # Do some TTP stuff with CAPEC objects if TTPON is True: try: for i in data['capec']: pkg.add_ttp(_buildttp(i, expt)) except KeyError: pass expt.add_weakness(_weakbuild(data)) # Add the exploit target to the package object pkg.add_exploit_target(expt) xml = pkg.to_xml() title = pkg.id_.split(':', 1)[-1] # If the function is not imported then output the xml to a file. if __name__ == '__main__': _postconstruct(xml, title) return xml else: sys.exit("[-] Error retrieving details for " + var)
def build_stix( input_dict ): # setup stix document stix_package = STIXPackage() stix_header = STIXHeader() stix_header.description = "Incident report for " + input_dict['organization'] stix_header.add_package_intent ("Incident") # Add handling requirements if needed if input_dict['sensitive'] == "True": mark = SimpleMarkingStructure() mark.statement = "Sensitive" mark_spec = MarkingSpecification() mark_spec.marking_structures.append(mark) stix_header.handling = Marking(mark_spec) stix_package.stix_header = stix_header # add incident and confidence incident = Incident() incident.description = input_dict['description'] incident.confidence = input_dict['confidence'] # add incident reporter incident.reporter = InformationSource() incident.reporter.description = "Person who reported the incident" incident.reporter.time = Time() incident.reporter.time.produced_time = datetime.strptime(input_dict['timestamp'], "%Y-%m-%d") # when they submitted it incident.reporter.identity = Identity() incident.reporter.identity.name = input_dict['submitter'] # incident time is a complex object with support for a bunch of different "when stuff happened" items incident.time = incidentTime() incident.title = "Breach of " + input_dict['organization'] incident.time.incident_discovery = datetime.strptime(input_dict['timestamp'], "%Y-%m-%d") # when they submitted it # add the impact impact = ImpactAssessment() impact.add_effect(input_dict['damage']) incident.impact_assessment = impact #Add the thing that was stolen jewels = AffectedAsset() jewels.type_ = input_dict['asset'] incident.add_affected_asset (jewels) # add the victim incident.add_victim (input_dict['organization']) stix_package.add_incident(incident) return stix_package
def main(): data = json.load(open("data.json")) stix_package = STIXPackage(stix_header=STIXHeader(title=data['title'], package_intents='Incident')) ttps = {} for info in data['ips']: if info['bot'] not in ttps: ttps[info['bot']] = TTP(title=info['bot']) stix_package.add_ttp(ttps[info['bot']]) incident = Incident(title=info['ip']) incident.time = Time() incident.time.first_malicious_action = info['first_seen'] addr = Address(address_value=info['ip'], category=Address.CAT_IPV4) observable = Observable(item=addr) stix_package.add_observable(observable) related_ttp = RelatedTTP(TTP(idref=ttps[info['bot']].id_), relationship="Used Malware") incident.leveraged_ttps.append(related_ttp) related_observable = RelatedObservable(Observable(idref=observable.id_)) incident.related_observables.append(related_observable) stix_package.add_incident(incident) print stix_package.to_xml()
def main(): stix_package = STIXPackage() addr1 = Observable(Address(address_value="198.51.100.2", category=Address.CAT_IPV4)) addr2 = Observable(Address(address_value="198.51.100.17", category=Address.CAT_IPV4)) addr3 = Observable(Address(address_value="203.0.113.19", category=Address.CAT_IPV4)) stix_package.add_observable(addr1) stix_package.add_observable(addr2) stix_package.add_observable(addr3) obs_addr1 = Observable() obs_addr2 = Observable() obs_addr3 = Observable() obs_addr1.id_ = None obs_addr2.id_ = None obs_addr3.id_ = None obs_addr1.idref = addr1.id_ obs_addr2.idref = addr2.id_ obs_addr3.idref = addr3.id_ infrastructure = Infrastructure() infrastructure.observable_characterization = Observables([obs_addr1, obs_addr2, obs_addr3]) resource = Resource() resource.infrastructure = infrastructure ttp = TTP(title="Malware C2 Channel") ttp.resources = resource stix_package.add_ttp(ttp) print stix_package.to_xml()
def main(): stix_package = STIXPackage() ttp_phishing = TTP(title="Phishing") attack_pattern = AttackPattern() attack_pattern.capec_id = "CAPEC-98" attack_pattern.description = ("Phishing") ttp_phishing.behavior = Behavior() ttp_phishing.behavior.add_attack_pattern(attack_pattern) ttp_pivy = TTP(title="Poison Ivy Variant d1c6") malware_instance = MalwareInstance() malware_instance.add_name("Poison Ivy Variant d1c6") malware_instance.add_type("Remote Access Trojan") ttp_pivy.behavior = Behavior() ttp_pivy.behavior.add_malware_instance(malware_instance) ta_bravo = ThreatActor(title="Adversary Bravo") ta_bravo.identity = Identity(name="Adversary Bravo") related_ttp_phishing = RelatedTTP(TTP(idref=ttp_phishing.id_), relationship="Leverages Attack Pattern") ta_bravo.observed_ttps.append(related_ttp_phishing) related_ttp_pivy = RelatedTTP(TTP(idref=ttp_pivy.id_), relationship="Leverages Malware") ta_bravo.observed_ttps.append(related_ttp_pivy) stix_package.add_ttp(ttp_phishing) stix_package.add_ttp(ttp_pivy) stix_package.add_threat_actor(ta_bravo) print stix_package.to_xml()
def taxii_content_block_to_stix(content_block): '''transform taxii content blocks into stix packages''' xml = StringIO(content_block.content) try: stix_package = STIXPackage.from_xml(xml) except UnsupportedVersionError as ex: updated = ramrod.update(xml) updated_xml = updated.document.as_stringio() stix_package = STIXPackage.from_xml(updated_xml) xml.close() return stix_package
def main(): pkg = STIXPackage() vuln = Vulnerability() vuln.cve_id = "CVE-2013-3893" et = ExploitTarget(title="Javascript vulnerability in MSIE 6-11") et.add_vulnerability(vuln) pkg.add_exploit_target(et) print pkg.to_xml()
def cvebuild(var): """Search for a CVE ID and return a STIX formatted response.""" cve = CVESearch() data = json.loads(cve.id(var)) if data: try: from stix.utils import set_id_namespace namespace = {NS: NS_PREFIX} set_id_namespace(namespace) except ImportError: from stix.utils import idgen from mixbox.namespaces import Namespace namespace = Namespace(NS, NS_PREFIX, "") idgen.set_id_namespace(namespace) pkg = STIXPackage() pkg.stix_header = STIXHeader() pkg = STIXPackage() pkg.stix_header = STIXHeader() pkg.stix_header.handling = marking() # Define the exploit target expt = ExploitTarget() expt.title = data['id'] expt.description = data['summary'] # Add the vulnerability object to the package object expt.add_vulnerability(vulnbuild(data)) # Do some TTP stuff with CAPEC objects try: for i in data['capec']: ttp = TTP() ttp.title = "CAPEC-" + str(i['id']) ttp.description = i['summary'] ttp.exploit_targets.append(ExploitTarget(idref=expt.id_)) pkg.add_ttp(ttp) except KeyError: pass # Do some weakness stuff if data['cwe'] != 'Unknown': weak = Weakness() weak.cwe_id = data['cwe'] expt.add_weakness(weak) # Add the exploit target to the package object pkg.add_exploit_target(expt) xml = pkg.to_xml() # If the function is not imported then output the xml to a file. if __name__ == '__main__': title = pkg.id_.split(':', 1)[-1] with open(title + ".xml", "w") as text_file: text_file.write(xml) return xml
def main(): maec_malware_instance = MAECInstance() maec_malware_instance.add_name("Poison Ivy Variant v4392-acc") maec_malware_instance.add_type("Remote Access Trojan") maec_malware_instance.maec = etree.fromstring(MAEC_XML, parser=etree.ETCompatXMLParser()) ttp = TTP(title="Poison Ivy Variant v4392-acc") ttp.behavior = Behavior() ttp.behavior.add_malware_instance(maec_malware_instance) stix_package = STIXPackage() stix_package.add_ttp(ttp) print(stix_package.to_xml(encoding=None))
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 main(): stix_package = STIXPackage() stix_header = STIXHeader() # Add tool information stix_header.information_source = InformationSource() stix_header.information_source.tools = ToolInformationList() stix_header.information_source.tools.append(ToolInformation("python-stix ex_04.py", "The MITRE Corporation")) stix_header.description = "Example " stix_package.stix_header = stix_header print(stix_package.to_xml()) print(stix_package.to_dict())
def stix_pkg(config, src, endpoint, payload, title='random test data', description='random test data', package_intents='Indicators - Watchlist', tlp_color='WHITE', dest=None): '''package observables''' # setup the xmlns... xmlns_url = config['edge']['sites'][dest]['stix']['xmlns_url'] xmlns_name = config['edge']['sites'][dest]['stix']['xmlns_name'] set_stix_id_namespace({xmlns_url: xmlns_name}) set_cybox_id_namespace(Namespace(xmlns_url, xmlns_name)) # construct a stix package... stix_package = STIXPackage() stix_header = STIXHeader() stix_header.title = title stix_header.description = description stix_header.package_intents = package_intents marking = MarkingSpecification() marking.controlled_structure = '../../../../descendant-or-self::node()' tlp_marking = TLPMarkingStructure() tlp_marking.color = tlp_color marking.marking_structures.append(tlp_marking) stix_package.stix_header = stix_header stix_package.stix_header.handling = Marking() stix_package.stix_header.handling.add_marking(marking) if isinstance(payload, Observable): stix_package.add_observable(payload) elif isinstance(payload, Indicator): stix_package.add_indicator(payload) elif isinstance(payload, Incident): stix_package.add_incident(payload) return(stix_package)
def test_deprecated_related_packages(self): i = Indicator() i.related_packages.append(STIXPackage()) self.assertEqual(len(i.related_packages), 1)
def gatherIOCs(folderPath, synConn, synackConn, ackConn, resolvedIPs, results, fullHTTPArray, udpconn, dnspacket, icmpPacket, ftpconn, sshconn, foundIPs): #print "Gather IOCs" stix_package = STIXPackage() stix_report = stixReport() # need to add indicator references to this stix_header_information_source = InformationSource() stix_header_information_source.description = "From Cuckoo sandbox IOC_STIX reporting module" stix_report.header = Header() stix_report.header.title = "A bunch of related indicators" stix_report.header.short_description = "A short description for the indicators oooooh!" stix_report.header.information_source = stix_header_information_source # IP address for susip in resolvedIPs: stix_package.add(susIP(susip)) stix_report.add_indicator(Indicator(idref=susIP(susip)._id)) # IPs found as static strings in the file for IP in foundIPs: stix_package.add(susIPfound(IP)) stix_report.add_indicator(Indicator(idref=susIPfound(IP)._id)) # TCP Connection attempt and Connection established for tcp in synConn: if tcp not in ackConn: #print "tcp: ", tcp stix_package.add(TCPConnectionAttemptFailedObj(tcp)) stix_report.add_indicator(Indicator(idref=TCPConnectionAttemptFailedObj(tcp)._id)) for tcpest in synConn: if tcpest in synackConn and tcpest in ackConn: #print "tcpest: ", tcpest stix_package.add(TCPConnectionEstablishedObj(tcpest)) stix_report.add_indicator(Indicator(idref=TCPConnectionEstablishedObj(tcpest)._id)) # Full HTTP Request for ht in fullHTTPArray: #print "ht array part: ", ht, type(ht) stix_package.add(HTTPFullObj(ht)) stix_report.add_indicator(Indicator(idref=HTTPFullObj(ht)._id)) # UDP Connection #print udpconn, type(udpconn) for udp in udpconn: if udp[0]!='53' and udp[1]!='53': # ignore DNS UDP packets (they are logged else where) #print "udp: ", udp stix_package.add(UDPRequestObj(udp)) stix_report.add_indicator(Indicator(idref=UDPRequestObj(udp)._id)) # DNS Connection for dns in dnspacket: #print "dns: ", dns stix_package.add(DNSRequestObj(dns)) stix_report.add_indicator(Indicator(idref=DNSRequestObj(dns)._id)) # ICMP Connection for icmp in icmpPacket: #print "ICMP: ", icmp if icmp[0] == 0 or icmp[0] == 8: stix_package.add(ICMPObj(icmp)) stix_report.add_indicator(Indicator(idref=ICMPObj(icmp)._id)) # FTP Connection for ftp in ftpconn: #print "FTP: ", ftp if ftp[4]=='220' or ftp[4]=='230' or ftp[4]=='250': stix_package.add(FTPObj(ftp)) stix_report.add_indicator(Indicator(idref=FTPObj(ftp)._id)) elif ftp[5]=="USER" or ftp[5]=="PASS" or ftp[5]=="STOR" or ftp[5]=="RETR": stix_package.add(FTPObj(ftp)) stix_report.add_indicator(Indicator(idref=FTPObj(ftp)._id)) # SSH Connection for ssh in sshconn: #print "SSH: ", ssh stix_package.add(SSHObj(ssh)) stix_report.add_indicator(Indicator(idref=SSHObj(ssh)._id)) stix_package.add_report(stix_report) #print results["target"] IOCStix = open(folderPath+"/"+str(results["target"]["file"]["name"])+".xml",'w') IOCStix.write(stix_package.to_xml()) IOCStix.close()
def test_deprecated_related_packages(self): t = ttp.TTP() t.related_packages.append(STIXPackage()) self.assertEqual(len(t.related_packages), 1)
def test_deprecated_related_packages(self): c = coa.CourseOfAction() c.related_packages.append(STIXPackage()) self.assertEqual(len(c.related_packages), 1)
class StixManager(object): def __init__(self, threat_name="Generic Threat", threat_descr="Generic Threat", author="Nozomi Networks Labs" , log=True): for i in ADDITIONAL_NAMESPACES: nsparser.STIX_NAMESPACES.add_namespace(i) mixbox.namespaces.register_namespace(i) self._pkg = STIXPackage() self.set_stix_header(threat_name, threat_descr) self._src_file = None self.__author = author self._lookup = set() self.__log = log def _is_ascii(self, value): return value.isascii() def load_raw_file(self, fname): with open(fname, 'r') as f: rawdata = f.readlines() for line in rawdata: ioc = line.strip() if len(ioc) > 0: res = self.add_raw_indicator(ioc) if res is True: if self.__log is True: logging.info("Auto-detected indicator: %s", ioc) else: if self.__log is True: logging.warning("Unknown indicator format: %s", ioc) self._src_file = fname return True def save_stix_file(self , file_name): try: with open(file_name, 'wb') as f: f.write(self._pkg.to_xml()) return True except Exception as e: if self.__log is True: logging.error(e) return False def set_stix_header(self, threat_name, threat_descr, threat_source=None, reference=None): # Create a STIX Package hdr = STIXHeader() hdr.title = threat_name hdr.add_description(threat_descr) hdr.information_source = InformationSource() if threat_source is not None: hdr.information_source.description = threat_source if reference is not None: hdr.information_source.references = fields.TypedField(reference, References) # Set the produced time to now hdr.information_source.time = Time() hdr.information_source.time.produced_time = datetime.utcnow() self._pkg.stix_header = hdr def add_raw_indicator(self , orig_indicator, ts=None): indicator_value = orig_indicator if not self._is_ascii(indicator_value): return False indicator_type, _ = guess_type(indicator_value) # Create a CyboX File Object if indicator_type == StixItemType.IPADDR: title = "Malicious IPv4 - %s" % indicator_value descr = "Malicious IPv4 involved with %s" % self._pkg.stix_header.title cybox = Address(indicator_value , Address.CAT_IPV4) elif indicator_type == StixItemType.DOMAIN: title = "Malicious domain - %s" % indicator_value descr = "Malicious domain involved with %s" % self._pkg.stix_header.title cybox = DomainName() cybox.value = indicator_value elif indicator_type == StixItemType.MD5: title = "Malicious MD5 - %s" % indicator_value descr = "Malicious MD5 involved with %s" % self._pkg.stix_header.title cybox = File() cybox.add_hash(indicator_value ) elif indicator_type == StixItemType.SHA256: title = "Malicious SHA256 - %s" % indicator_value descr = "Malicious SHA256 involved with %s" % self._pkg.stix_header.title cybox = File() cybox.add_hash(indicator_value ) elif indicator_type == StixItemType.SHA1: title = "Malicious SHA1 - %s" % indicator_value descr = "Malicious SHA1 involved with %s" % self._pkg.stix_header.title cybox = File() cybox.add_hash(indicator_value ) elif indicator_type == StixItemType.URL: title = "Malicious URL - %s" % indicator_value descr = "Malicious URL involved with %s" % self._pkg.stix_header.title cybox = URI() cybox.value = indicator_value cybox.type_ = URI.TYPE_URL if indicator_type == StixItemType.UNKNOWN: return False indicator = Indicator() indicator.title = title indicator.description = descr indicator.add_object(cybox) indicator.set_producer_identity(self.__author) if ts: indicator.set_produced_time(ts) else: indicator.set_produced_time(utils.dates.now()) self._add(indicator) return True def _add(self, indicator): ioc = self._parse_indicator(indicator) assert len(ioc) == 1, "Multiple observables in a single indicator not supported yet" ioc = ioc.pop() # Check for duplicates if self.is_duplicated(ioc.value): if self.__log is True: logging.warning("Skipping duplicated indicator: %s", ioc.value) return False # Update description _, type_descr = guess_type(ioc.value) indicator.title = "Malicious %s - %s" % (type_descr, ioc.value) indicator.description = "Malicious %s involved with the threat %s" % (type_descr, self._pkg.stix_header.title) # Update the lookup table self._lookup.add(ioc.value) self._pkg.add(indicator) return True def is_duplicated(self, ivalue): return ivalue in self._lookup def _parse_indicator(self, indicator): processed_indicators = set() title = indicator.title description = indicator.description timestamp = indicator.get_produced_time() if timestamp: timestamp = timestamp.value else: logging.warning("Failed to get produced time") for obj in indicator.observables: # Object attributes obj_val = None obj_type = None # Extract the object properties obj_prop = obj.to_obj().Object.Properties if isinstance(obj_prop, domain_name_object.DomainNameObjectType): obj_val = obj_prop.Value.valueOf_ obj_type = StixItemType.DOMAIN elif isinstance(obj_prop, file_object.FileObjectType): # TODO: support multiple hashes obj_hash = obj_prop.Hashes.get_Hash()[0] obj_hash_type = obj_hash.Type.valueOf_.upper() if obj_hash_type in ['SHA256', 'SHA1', 'MD5']: obj_val = obj_hash.get_Simple_Hash_Value().valueOf_ if obj_hash_type == 'SHA256': obj_type = StixItemType.SHA256 elif obj_hash_type == 'SHA1': obj_type = StixItemType.SHA1 elif obj_hash_type == 'MD5': obj_type = StixItemType.MD5 else: obj_type = StixItemType.UNKNOWN else: if self.__log is True: logging.warning("Unsupported hash type: %s" % obj_hash_type) elif isinstance(obj_prop, uri_object.URIObjectType): obj_val = obj_prop.Value.valueOf_ obj_type = StixItemType.URL elif isinstance(obj_prop, address_object.AddressObjectType): obj_val = obj_prop.Address_Value.valueOf_ obj_type = StixItemType.IPADDR else: obj_val = indicator obj_type = StixItemType.UNKNOWN # Strip-out the value obj_val = obj_val.strip() ioc = StixIndicator(obj_type, obj_val, title, description, timestamp) processed_indicators.add(ioc) # Return indicators return processed_indicators
from stix.exploit_target.vulnerability import Vulnerability # Build a Product Object that characterizes our affected software software = Product() software.product = "Foobar" software.version = "3.0" software.edition = "GOTY" # Wrap the Product Object in an Observable instance observable = Observable(software) # Attach the Product observable to the affected_sofware list of # RelatedObservable instances. This wraps our Observable in a # RelatedObservable layer. vuln = Vulnerability() vuln.affected_software.append(observable) # Create the Exploit Target et = ExploitTarget() # Attach our Vulnerability to the Exploit Target et.vulnerabilities.append(vuln) # Build a STIX Package package = STIXPackage() # Attach the Exploit Target instance to the Package package.exploit_targets.append(et) # Print! print package.to_xml()
def test_from_xml_default_encoded(self): utf8_xml = XML.encode('utf-8') sio = BytesIO(utf8_xml) sp = STIXPackage.from_xml(sio) header = sp.stix_header self.assertEqual(header.title, UNICODE_STR)
def received(s, content, collection): # Hack XML header on. package = STIXPackage.from_xml(StringIO.StringIO(content)) print("Received", package.id_)
def test_deprecated_related_packages(self): i = incident.Incident() i.related_packages.append(STIXPackage()) self.assertEqual(len(i.related_packages), 1)
def main(): data = json.load(open("data.json")) stix_package = STIXPackage(stix_header=STIXHeader( title=data['title'], package_intents='Incident')) ttps = {} for info in data['ips']: # Add TTP, unless it's already been added if info['bot'] not in ttps: ttps[info['bot']] = TTP(title=info['bot']) stix_package.add_ttp(ttps[info['bot']]) # Add indicator indicator = Indicator(title=info['ip']) addr = Address(address_value=info['ip'], category=Address.CAT_IPV4) addr.condition = "Equals" indicator.add_observable(addr) indicator.add_indicated_ttp(TTP(idref=ttps[info['bot']].id_)) stix_package.add_indicator(indicator) # Add incident incident = Incident(title=info['ip']) incident.time = Time() incident.time.first_malicious_action = info['first_seen'] addr = Address(address_value=info['ip'], category=Address.CAT_IPV4) observable = Observable(item=addr) stix_package.add_observable(observable) related_ttp = RelatedTTP(TTP(idref=ttps[info['bot']].id_), relationship="Used Malware") incident.leveraged_ttps.append(related_ttp) related_observable = RelatedObservable( Observable(idref=observable.id_)) incident.related_observables.append(related_observable) related_indicator = RelatedIndicator(Indicator(idref=indicator.id_)) incident.related_indicators.append(related_indicator) stix_package.add_incident(incident) print stix_package.to_xml()
def test_parsing_maec_fails(self): try: STIXPackage.from_xml(PythonMAECInPackageTests.XML_MAEC) except ImportError as e: self.assertTrue(all(x in str(e) for x in ("No module named", "maec")))
def test_parse_malware_maec(self): """Test parsing a MaecInstance from XML """ stix_pkg = STIXPackage.from_xml(self.XML_MAEC) mw = stix_pkg.ttps.ttp[0].behavior.malware_instances[0].to_dict() self.assertTrue('names' in mw)
print("Confidence: " + str(ind.confidence.value)) # look up ttp from list in package for ref_ttp in ind.indicated_ttps: print("TTP: " + str(pkg.find(ref_ttp.item.idref).title)) for obs in ind.observables: if obs.object_.related_objects: # attachment is inline print("Attachment ID: " + str(obs.object_.id_)) print("Attachment Filename: " + str(obs.object_.related_objects[0].properties.file_name)) print("Attachment File extension: " + str(obs.object_.related_objects[0].properties.file_extension)) print("Relationship: " + str(obs.object_.related_objects[0].relationship)) elif obs.object_.properties.header: print("Subject : " + str(obs.object_.properties.header.subject)) if obs.object_.properties.attachments: print("Attachment -> : " + str(obs.object_.properties.attachments[0].object_reference)) return 0 if __name__ == '__main__': try: fname = sys.argv[1] except: exit(1) fd = open(fname) stix_pkg = STIXPackage.from_xml(fd) parse_stix(stix_pkg)
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 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': 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
""" # Create a VocabString class for our CustomVocab-1.0 vocabular class CustomVocab(vocabs.VocabString): _namespace = 'http://customvocabs.com/vocabs-1' _XSI_TYPE = 'customVocabs:CustomVocab-1.0' _ALLOWED_VALUES = ('FOO', 'BAR') # Register our Custom Vocabulary class so parsing and serialization works vocabs.add_vocab(CustomVocab) # Parse the input document sio = StringIO(XML) package = STIXPackage.from_xml(sio) # Retrieve the first (and only) Package_Intent entry package_intent = package.stix_header.package_intents[0] # Print information about the input Package_Intent print type(package_intent), package_intent.xsi_type, package_intent # Add another Package Intent bar = CustomVocab('BAR') package.stix_header.add_package_intent(bar) schemalocs = {'http://customvocabs.com/vocabs-1': '/path/to/customVocabs.xsd'} # This will include the 'BAR' CustomVocab entry print package.to_xml(schemaloc_dict=schemalocs)
def test_from_xml_utf16_encoded(self): utf16_xml = XML.encode('utf-16') sio = BytesIO(utf16_xml) sp = STIXPackage.from_xml(sio, encoding='utf-16') header = sp.stix_header self.assertEqual(header.title, UNICODE_STR)
def stix_framing(*args): import datetime, re from stix.core import STIXPackage, STIXHeader from cybox.utils import Namespace # As python3 is forced anyway, mixbox is used and we don't need to try to import idgen from stix.utils from mixbox import idgen from stix import __version__ as STIXVER NS_DICT = { "http://cybox.mitre.org/common-2": 'cyboxCommon', "http://cybox.mitre.org/cybox-2": 'cybox', "http://cybox.mitre.org/default_vocabularies-2": 'cyboxVocabs', "http://cybox.mitre.org/objects#AccountObject-2": 'AccountObj', "http://cybox.mitre.org/objects#ArtifactObject-2": 'ArtifactObj', "http://cybox.mitre.org/objects#ASObject-1": 'ASObj', "http://cybox.mitre.org/objects#AddressObject-2": 'AddressObj', "http://cybox.mitre.org/objects#PortObject-2": 'PortObj', "http://cybox.mitre.org/objects#DomainNameObject-1": 'DomainNameObj', "http://cybox.mitre.org/objects#EmailMessageObject-2": 'EmailMessageObj', "http://cybox.mitre.org/objects#FileObject-2": 'FileObj', "http://cybox.mitre.org/objects#HTTPSessionObject-2": 'HTTPSessionObj', "http://cybox.mitre.org/objects#HostnameObject-1": 'HostnameObj', "http://cybox.mitre.org/objects#MutexObject-2": 'MutexObj', "http://cybox.mitre.org/objects#PipeObject-2": 'PipeObj', "http://cybox.mitre.org/objects#URIObject-2": 'URIObj', "http://cybox.mitre.org/objects#WinRegistryKeyObject-2": 'WinRegistryKeyObj', 'http://cybox.mitre.org/objects#WinServiceObject-2': 'WinServiceObj', "http://cybox.mitre.org/objects#NetworkConnectionObject-2": 'NetworkConnectionObj', "http://cybox.mitre.org/objects#NetworkSocketObject-2": 'NetworkSocketObj', "http://cybox.mitre.org/objects#SocketAddressObject-1": 'SocketAddressObj', "http://cybox.mitre.org/objects#SystemObject-2": 'SystemObj', "http://cybox.mitre.org/objects#ProcessObject-2": 'ProcessObj', "http://cybox.mitre.org/objects#X509CertificateObject-2": 'X509CertificateObj', "http://cybox.mitre.org/objects#WhoisObject-2": 'WhoisObj', "http://cybox.mitre.org/objects#WinExecutableFileObject-2": 'WinExecutableFileObj', "http://cybox.mitre.org/objects#UnixUserAccountObject-2": "UnixUserAccountObj", "http://cybox.mitre.org/objects#UserAccountObject-2": "UserAccountObj", "http://cybox.mitre.org/objects#WinUserAccountObject-2": "WinUserAccountObj", "http://data-marking.mitre.org/Marking-1": 'marking', "http://data-marking.mitre.org/extensions/MarkingStructure#TLP-1": 'tlpMarking', "http://stix.mitre.org/ExploitTarget-1": 'et', "http://stix.mitre.org/Incident-1": 'incident', "http://stix.mitre.org/Indicator-2": 'indicator', "http://stix.mitre.org/CourseOfAction-1": 'coa', "http://stix.mitre.org/TTP-1": 'ttp', "http://stix.mitre.org/ThreatActor-1": 'ta', "http://stix.mitre.org/common-1": 'stixCommon', "http://stix.mitre.org/default_vocabularies-1": 'stixVocabs', "http://stix.mitre.org/extensions/Identity#CIQIdentity3.0-1": 'ciqIdentity', "http://stix.mitre.org/extensions/TestMechanism#Snort-1": 'snortTM', "http://stix.mitre.org/stix-1": 'stix', "http://www.w3.org/2001/XMLSchema-instance": 'xsi', "urn:oasis:names:tc:ciq:xal:3": 'xal', "urn:oasis:names:tc:ciq:xnl:3": 'xnl', "urn:oasis:names:tc:ciq:xpil:3": 'xpil', } SCHEMALOC_DICT = { 'http://cybox.mitre.org/common-2': 'http://cybox.mitre.org/XMLSchema/common/2.1/cybox_common.xsd', 'http://cybox.mitre.org/cybox-2': 'http://cybox.mitre.org/XMLSchema/core/2.1/cybox_core.xsd', 'http://cybox.mitre.org/default_vocabularies-2': 'http://cybox.mitre.org/XMLSchema/default_vocabularies/2.1/cybox_default_vocabularies.xsd', 'http://cybox.mitre.org/objects#AccountObject-2': ' http://cybox.mitre.org/XMLSchema/objects/Account/2.1/Account_Object.xsd', 'http://cybox.mitre.org/objects#ArtifactObject-2': 'http://cybox.mitre.org/XMLSchema/objects/Artifact/2.1/Artifact_Object.xsd', 'http://cybox.mitre.org/objects#ASObject-1': 'http://cybox.mitre.org/XMLSchema/objects/AS/1.0/AS_Object.xsd', 'http://cybox.mitre.org/objects#AddressObject-2': 'http://cybox.mitre.org/XMLSchema/objects/Address/2.1/Address_Object.xsd', 'http://cybox.mitre.org/objects#PortObject-2': 'http://cybox.mitre.org/XMLSchema/objects/Port/2.1/Port_Object.xsd', 'http://cybox.mitre.org/objects#DomainNameObject-1': 'http://cybox.mitre.org/XMLSchema/objects/Domain_Name/1.0/Domain_Name_Object.xsd', 'http://cybox.mitre.org/objects#EmailMessageObject-2': 'http://cybox.mitre.org/XMLSchema/objects/Email_Message/2.1/Email_Message_Object.xsd', 'http://cybox.mitre.org/objects#FileObject-2': 'http://cybox.mitre.org/XMLSchema/objects/File/2.1/File_Object.xsd', 'http://cybox.mitre.org/objects#HTTPSessionObject-2': 'http://cybox.mitre.org/XMLSchema/objects/HTTP_Session/2.1/HTTP_Session_Object.xsd', 'http://cybox.mitre.org/objects#HostnameObject-1': 'http://cybox.mitre.org/XMLSchema/objects/Hostname/1.0/Hostname_Object.xsd', 'http://cybox.mitre.org/objects#MutexObject-2': 'http://cybox.mitre.org/XMLSchema/objects/Mutex/2.1/Mutex_Object.xsd', 'http://cybox.mitre.org/objects#PipeObject-2': 'http://cybox.mitre.org/XMLSchema/objects/Pipe/2.1/Pipe_Object.xsd', 'http://cybox.mitre.org/objects#URIObject-2': 'http://cybox.mitre.org/XMLSchema/objects/URI/2.1/URI_Object.xsd', 'http://cybox.mitre.org/objects#WinServiceObject-2': 'http://cybox.mitre.org/XMLSchema/objects/Win_Service/2.1/Win_Service_Object.xsd', 'http://cybox.mitre.org/objects#WinRegistryKeyObject-2': 'http://cybox.mitre.org/XMLSchema/objects/Win_Registry_Key/2.1/Win_Registry_Key_Object.xsd', 'http://cybox.mitre.org/objects#NetworkConnectionObject-2': 'http://cybox.mitre.org/XMLSchema/objects/Network_Connection/2.0.1/Network_Connection_Object.xsd', 'http://cybox.mitre.org/objects#NetworkSocketObject-2': 'https://cybox.mitre.org/XMLSchema/objects/Network_Socket/2.1/Network_Socket_Object.xsd', 'http://cybox.mitre.org/objects#SystemObject-2': 'http://cybox.mitre.org/XMLSchema/objects/System/2.1/System_Object.xsd', 'http://cybox.mitre.org/objects#SocketAddressObject-1': 'http://cybox.mitre.org/XMLSchema/objects/Socket_Address/1.1/Socket_Address_Object.xsd', 'http://cybox.mitre.org/objects#ProcessObject-2': 'https://cybox.mitre.org/XMLSchema/objects/Process/2.1/Process_Object.xsd', 'http://cybox.mitre.org/objects#X509CertificateObject-2': 'http://cybox.mitre.org/XMLSchema/objects/X509_Certificate/2.1/X509_Certificate_Object.xsd', 'http://cybox.mitre.org/objects#WhoisObject-2': 'http://cybox.mitre.org/XMLSchema/objects/Whois/2.1/Whois_Object.xsd', 'http://cybox.mitre.org/objects#WinExecutableFileObject-2': 'http://cybox.mitre.org/XMLSchema/objects/Win_Executable_File/2.1/Win_Executable_File_Object.xsd', 'http://cybox.mitre.org/objects#UnixUserAccountObject-2': 'http://cybox.mitre.org/XMLSchema/objects/Unix_User_Account/2.1/Unix_User_Account_Object.xsd', 'http://cybox.mitre.org/objects#UserAccountObject-2': 'http://cybox.mitre.org/XMLSchema/objects/User_Account/2.1/User_Account_Object.xsd', 'http://cybox.mitre.org/objects#WinUserAccountObject-2': 'http://cybox.mitre.org/XMLSchema/objects/Win_User_Account/2.1/Win_User_Account_Object.xsd', 'http://data-marking.mitre.org/Marking-1': 'http://stix.mitre.org/XMLSchema/data_marking/1.1.1/data_marking.xsd', 'http://data-marking.mitre.org/extensions/MarkingStructure#TLP-1': 'http://stix.mitre.org/XMLSchema/extensions/marking/tlp/1.1.1/tlp_marking.xsd', 'http://stix.mitre.org/ExploitTarget-1': 'http://stix.mitre.org/XMLSchema/exploit_target/1.1.1/exploit_target.xsd', 'http://stix.mitre.org/Incident-1': 'http://stix.mitre.org/XMLSchema/incident/1.1.1/incident.xsd', 'http://stix.mitre.org/Indicator-2': 'http://stix.mitre.org/XMLSchema/indicator/2.1.1/indicator.xsd', 'http://stix.mitre.org/CourseOfAction-1': 'http://stix.mitre.org/XMLSchema/course_of_action/1.1.1/course_of_action.xsd', 'http://stix.mitre.org/TTP-1': 'http://stix.mitre.org/XMLSchema/ttp/1.1.1/ttp.xsd', 'http://stix.mitre.org/ThreatActor-1': 'http://stix.mitre.org/XMLSchema/threat_actor/1.1.1/threat_actor.xsd', 'http://stix.mitre.org/common-1': 'http://stix.mitre.org/XMLSchema/common/1.1.1/stix_common.xsd', 'http://stix.mitre.org/default_vocabularies-1': 'http://stix.mitre.org/XMLSchema/default_vocabularies/1.1.1/stix_default_vocabularies.xsd', 'http://stix.mitre.org/extensions/Identity#CIQIdentity3.0-1': 'http://stix.mitre.org/XMLSchema/extensions/identity/ciq_3.0/1.1.1/ciq_3.0_identity.xsd', 'http://stix.mitre.org/extensions/TestMechanism#Snort-1': 'http://stix.mitre.org/XMLSchema/extensions/test_mechanism/snort/1.1.1/snort_test_mechanism.xsd', 'http://stix.mitre.org/stix-1': 'http://stix.mitre.org/XMLSchema/core/1.1.1/stix_core.xsd', 'urn:oasis:names:tc:ciq:xal:3': 'http://stix.mitre.org/XMLSchema/external/oasis_ciq_3.0/xAL.xsd', 'urn:oasis:names:tc:ciq:xnl:3': 'http://stix.mitre.org/XMLSchema/external/oasis_ciq_3.0/xNL.xsd', 'urn:oasis:names:tc:ciq:xpil:3': 'http://stix.mitre.org/XMLSchema/external/oasis_ciq_3.0/xPIL.xsd', } baseurl, orgname, return_type = args if not baseurl: baseurl = 'https://www.misp-project.org' real_orgname = args[1] orgname = re.sub('[\W]+', '', orgname.replace(" ", "_")) NS_DICT[baseurl] = orgname try: idgen.set_id_namespace(Namespace(baseurl, orgname)) except TypeError: idgen.set_id_namespace(Namespace(baseurl, orgname, "MISP")) stix_package = STIXPackage() stix_header = STIXHeader() stix_header.title = "Export from {} MISP".format(real_orgname) stix_header.package_intents = "Threat Report" stix_package.stix_header = stix_header stix_package.version = "1.1.1" stix_package.timestamp = datetime.datetime.now() return stix_json_framing( stix_package) if return_type == 'json' else stix_xml_framing( stix_package, NS_DICT, SCHEMALOC_DICT)
def _import_collection(self, client, site, collection, data_set=False): collection_name = collection.name sanitized_feed_name = cleanup_string( "%s%s" % (site.get('site'), collection_name)) feed_summary = "%s %s" % (site.get('site'), collection_name) available = collection.available collection_type = collection.type default_score = site.get('default_score') logger.info("%s,%s,%s,%s,%s" % (site.get('site'), collection_name, sanitized_feed_name, available, collection_type)) if not available: return False # # Sanity check on start date # start_date_str = site.get('start_date') if not start_date_str or len(start_date_str) == 0: start_date_str = "2019-01-01 00:00:00" # # Create a feed helper object # feed_helper = FeedHelper(site.get('output_path'), sanitized_feed_name, site.get('minutes_to_advance'), start_date_str) if not data_set: logger.info("Feed start time %s" % feed_helper.start_date) logger.info("polling Collection: {}...".format(collection.name)) # # Build up the URI for polling # if not site.get('poll_path', ''): uri = None else: uri = '' if site.get('use_https'): uri += 'https://' else: uri += 'http://' uri += site.get('site') uri += site.get('poll_path') logger.info('Poll path: {}'.format(uri)) reports = [] while True: num_times_empty_content_blocks = 0 try: try: logger.info("Polling Collection: {0}".format( collection.name)) content_blocks = client.poll( uri=uri, collection_name=collection.name, begin_date=feed_helper.start_date, end_date=feed_helper.end_date, content_bindings=BINDING_CHOICES) except Exception as e: logger.info(e.message) content_blocks = [] # # Iterate through all content_blocks # num_blocks = 0 if not data_set: logger.info("polling start_date: {}, end_date: {}".format( feed_helper.start_date, feed_helper.end_date)) for block in content_blocks: logger.debug(block.content) # # if in export mode then save off this content block # if self.export_dir: self.export_xml(collection_name, feed_helper.start_date, feed_helper.end_date, num_blocks, block.content) # # This code accounts for a case found with ThreatCentral.io where the content is url encoded. # etree.fromstring can parse this data. # try: root = etree.fromstring(block.content) content = root.find( './/{http://taxii.mitre.org/messages/taxii_xml_binding-1.1}Content' ) if content is not None and len(content) == 0 and len( list(content)) == 0: # # Content has no children. So lets make sure we parse the xml text for content and re-add # it as valid XML so we can parse # new_stix_package = etree.fromstring( root.find( "{http://taxii.mitre.org/messages/taxii_xml_binding-1.1}Content_Block/{http://taxii.mitre.org/messages/taxii_xml_binding-1.1}Content" ).text) content.append(new_stix_package) # # Since we modified the xml, we need create a new xml message string to parse # message = etree.tostring(root) # # Write the content block to disk so we can parse with python stix # file_handle, file_path = self.write_to_temp_file( message) # # Parse STIX data # stix_package = STIXPackage.from_xml(file_path) # # if it is a DATA_SET make feed_summary from the stix_header description # NOTE: this is for RecordedFuture, also note that we only do this for data_sets. # to date I have only seen RecordedFuture use data_sets # if data_set and stix_package.stix_header and stix_package.stix_header.descriptions: for desc in stix_package.stix_header.descriptions: feed_summary = "{}: {}".format( desc.value, collection_name) break # # Get the timestamp of the STIX Package so we can use this in our feed # timestamp = total_seconds(stix_package.timestamp) if not stix_package.indicators and not stix_package.observables: num_times_empty_content_blocks += 1 if num_times_empty_content_blocks > 10: break if stix_package.indicators: for indicator in stix_package.indicators: if not indicator or not indicator.observable: continue if indicator.confidence: if str(indicator.confidence.value).isdigit( ): # # Get the confidence score and use it for our score # score = int( indicator.confidence.to_dict().get( "value", default_score)) else: if str(indicator.confidence.value ).lower() == "high": score = 75 elif str(indicator.confidence.value ).lower() == "medium": score = 50 elif str(indicator.confidence.value ).lower() == "low": score = 25 else: score = default_score else: score = default_score if not indicator.timestamp: timestamp = 0 else: timestamp = int( (indicator.timestamp - datetime.datetime(1970, 1, 1).replace( tzinfo=dateutil.tz.tzutc()) ).total_seconds()) reports.extend( cybox_parse_observable( indicator.observable, indicator, timestamp, score)) # # Now lets find some data. Iterate through all observables and parse # if stix_package.observables: for observable in stix_package.observables: if not observable: continue # # Cybox observable returns a list # reports.extend( cybox_parse_observable( observable, None, timestamp, default_score)) # # Delete our temporary file # file_handle.close() num_blocks += 1 # # end for loop through content blocks # except Exception as e: # logger.info(traceback.format_exc()) logger.info(e.message) continue logger.info("content blocks read: {}".format(num_blocks)) logger.info("current number of reports: {}".format( len(reports))) if len(reports) > site.get('reports_limit'): logger.info( "We have reached the reports limit of {0}".format( site.get('reports_limit'))) break # # DEBUG CODE # # if len(reports) > 10: # break # # Attempt to advance the start time and end time # except Exception as e: logger.info(traceback.format_exc()) # # If it is just a data_set, the data is unordered, so we can just break out of the while loop # if data_set: break if feed_helper.advance(): continue else: break # # end While True # logger.info("Found {} new reports.".format(len(reports))) if not data_set: # # We only want to concatenate if we are NOT a data set, otherwise we want to refresh all the reports # logger.info("Adding existing reports...") reports = feed_helper.load_existing_feed_data() + reports logger.info("Total number of reports: {}".format(len(reports))) if site.get('reports_limit') < len(reports): logger.info("Truncating reports to length {0}".format( site.get('reports_limit'))) reports = reports[:site.get('reports_limit')] data = build_feed_data(sanitized_feed_name, "%s %s" % (site.get('site'), collection_name), feed_summary, site.get('site'), site.get('icon_link'), reports) if feed_helper.write_feed(data): feed_helper.save_details() # # Create Cb Response Feed if necessary # feed_id = None try: feeds = get_object_by_name_or_id(self.cb, Feed, name=sanitized_feed_name) if not feeds: logger.info( "Feed {} was not found, so we are going to create it". format(sanitized_feed_name)) elif len(feeds) > 1: logger.warning( "Multiple feeds found, selecting Feed id {}".format( feeds[0].id)) feed_id = feeds[0].id elif feeds: feed_id = feeds[0].id logger.info("Feed {} was found as Feed ID {}".format( sanitized_feed_name, feed_id)) except Exception as e: logger.info(e.message) if not feed_id: logger.info("Creating {} feed for the first time".format( sanitized_feed_name)) f = self.cb.create(Feed) f.feed_url = "file://" + feed_helper.path f.enabled = site.get('feeds_enable') f.use_proxy = False f.validate_server_cert = False try: f.save() except ServerError as se: if se.error_code == 500: logger.info("Could not add feed:") logger.info( " Received error code 500 from server. This is usually because the server cannot retrieve the feed." ) logger.info( " Check to ensure the Cb server has network connectivity and the credentials are correct." ) else: logger.info("Could not add feed: {0:s}".format(str(se))) except Exception as e: logger.info("Could not add feed: {0:s}".format(str(e))) else: logger.info("Feed data: {0:s}".format(str(f))) logger.info("Added feed. New feed ID is {0:d}".format(f.id)) feed_id = f.id return feed_id
def test_deprecated_warning(self): from stix.core import STIXPackage l = RelatedPackageRefs() l.append(STIXPackage())
def main(): stix_pkg = STIXPackage() # create LM-style kill chain # REF: http://stix.mitre.org/language/version{{site.current_version}}/stix_v{{site.current_version}}_lmco_killchain.xml recon = KillChainPhase( phase_id="stix:TTP-af1016d6-a744-4ed7-ac91-00fe2272185a", name="Reconnaissance", ordinality="1") weapon = KillChainPhase( phase_id="stix:TTP-445b4827-3cca-42bd-8421-f2e947133c16", name="Weaponization", ordinality="2") deliver = KillChainPhase( phase_id="stix:TTP-79a0e041-9d5f-49bb-ada4-8322622b162d", name="Delivery", ordinality="3") exploit = KillChainPhase( phase_id="stix:TTP-f706e4e7-53d8-44ef-967f-81535c9db7d0", name="Exploitation", ordinality="4") install = KillChainPhase( phase_id="stix:TTP-e1e4e3f7-be3b-4b39-b80a-a593cfd99a4f", name="Installation", ordinality="5") control = KillChainPhase( phase_id="stix:TTP-d6dc32b9-2538-4951-8733-3cb9ef1daae2", name="Command and Control", ordinality="6") action = KillChainPhase( phase_id="stix:TTP-786ca8f9-2d9a-4213-b38e-399af4a2e5d6", name="Actions on Objectives", ordinality="7") lmchain = KillChain(id_="stix:TTP-af3e707f-2fb9-49e5-8c37-14026ca0a5ff", name="LM Cyber Kill Chain") lmchain.definer = "LMCO" lmchain.kill_chain_phases = [ recon, weapon, deliver, exploit, install, control, action ] stix_pkg.ttps.kill_chains.append(lmchain) infect = KillChainPhase(name="Infect Machine") exfil = KillChainPhase(name="Exfiltrate Data") mychain = KillChain(name="Organization-specific Kill Chain") mychain.definer = "Myself" mychain.kill_chain_phases = [infect, exfil] stix_pkg.ttps.kill_chains.append(mychain) indicator = Indicator() indicator.kill_chain_phases = KillChainPhasesReference([ KillChainPhaseReference(phase_id=exfil.phase_id, kill_chain_id=mychain.id_), KillChainPhaseReference(phase_id=action.phase_id, kill_chain_id=lmchain.id_) ]) stix_pkg.add_indicator(indicator) print stix_pkg.to_xml()
def main(): mydata = loaddata() # NAMESPACE = {sanitizer(mydata["NSXURL"]) : sanitizer(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["filename"]) + ": " + sanitizer( mydata["hashes"]["md5"]) ShortDescription = timestamp DESCRIPTION = "STIX Report for: " + sanitizer( mydata["filename"]) + " - " + sanitizer(mydata["hashes"]["md5"]) wrapper.stix_header = STIXHeader(information_source=info_src, title=MyTITLE, description=DESCRIPTION, short_description=ShortDescription) wrapper.stix_header.handling = handling fileobj = File() fileobj.file_name = sanitizer(mydata["filename"]) fileobj.file_format = sanitizer(mydata["file_type"]) fileobj.size_in_bytes = sanitizer(mydata["file_size"]) fileobj.add_hash(Hash(sanitizer(mydata["hashes"]["md5"]))) fileobj.add_hash(Hash(sanitizer(mydata["hashes"]["sha1"]))) fileobj.add_hash(Hash(sanitizer(mydata["hashes"]["sha256"]))) observable = Observable(fileobj) if "URL_file_hosting" in mydata: for idx, mydata["URL_file_hosting"] in enumerate( mydata["URL_file_hosting"]): url = URI() url.value = sanitizer(mydata["URL_file_hosting"]) url.type_ = URI.TYPE_URL url.condition = "Equals" fileobj.add_related(url, "Downloaded_From") indicator = Indicator() indicator.title = MyTITLE indicator.add_indicator_type("File Hash Watchlist") indicator.add_observable(observable) wrapper.add_indicator(indicator) print(wrapper.to_xml())
from stix.core import STIXPackage from stix.incident import Incident from stix.common import InformationSource from cybox.common import Time from datetime import datetime from stix.common import Identity from stix.incident import Time as incidentTime # different type than common:Time from stix.incident import Incident, ImpactAssessment from stix.incident.impact_assessment import Effects from stix.common import References # setup stix document stix_package = STIXPackage() # add incident and confidence breach = Incident() breach.description = "Parity Wallet Hacked" breach.confidence = "High" # investigators were able to thoroughly validate the incident, Low means not yet validated # stamp with reporter breach.reporter = InformationSource() breach.reporter.description = "https://paritytech.io/blog/security-alert.html" breach.reporter.time = Time() breach.reporter.time.produced_time = datetime.strptime( "2017-11-08", "%Y-%m-%d") # when they submitted it breach.reporter.identity = Identity() breach.reporter.identity.name = "parity technologies ltd" # set incident-specific timestamps
def process_cases(misp, case_list): for case_id in case_list: LOGGER.info('Fetching case: {0}'.format(case_id)) case_url = 'https://api.xforce.ibmcloud.com/casefiles/{0}/stix'.format(case_id) response = requests.get(case_url, headers=get_api_headers()) if not response.status_code == 200: LOGGER.info('Failed to get case. Status code: {0}'.format(response.status_code)) continue LOGGER.info('Case request OK!') stix_xml = StringIO(response.text) stix_package = STIXPackage.from_xml(stix_xml) stix_xml.close() title = stix_package.stix_header.title author = stix_package.stix_header.information_source.contributing_sources[0].identity.name LOGGER.info('New case from {0}: {1}'.format(author, title)) if not stix_package.observables: LOGGER.warning('Case does not have any recorded observables. Skipping...') continue event = False event_search = misp.search_index(eventinfo=title) if not event_search == []: for result in event_search: if result['info'] == title: event = event_search[0] if event: LOGGER.warning('Event already exists. Will only update attributes.') else: event = make_new_event(misp, stix_package) if not event: LOGGER.warning('Failed to make or retrieve event.') continue observables = stix_package.observables.observables LOGGER.info('Processing {0} observables...'.format(len(observables))) for observable in observables: attribute_value = None if hasattr(observable.object_.properties, 'hashes'): if observable.object_.properties.hashes.sha256: attribute_value = str(observable.object_.properties.hashes.sha256.value).lower() attribute_category = 'Payload delivery' attribute_type = 'sha256' elif observable.object_.properties.hashes.sha1: attribute_value = str(observable.object_.properties.hashes.sha1.value).lower() attribute_category = 'Payload delivery' attribute_type = 'sha1' elif observable.object_.properties.hashes.md5: attribute_value = str(observable.object_.properties.hashes.md5.value).lower() attribute_category = 'Payload delivery' attribute_type = 'md5' elif hasattr(observable.object_.properties, 'type_'): if observable.object_.properties.type_ == 'URL': observable_value = str(observable.object_.properties.value) attribute_category = 'Network activity' if is_valid_domain(observable_value): attribute_value = observable_value if attribute_value.count('.') == 1: attribute_type = 'domain' else: attribute_type = 'hostname' elif is_valid_url(observable_value): attribute_value = observable_value attribute_category = 'Network activity' attribute_type = 'url' elif is_valid_url('https://{0}'.format(observable_value)): attribute_value = 'https://{0}'.format(observable_value) attribute_category = 'Network activity' attribute_type = 'url' elif hasattr(observable.object_.properties, 'address_value'): attribute_value = str(observable.object_.properties.address_value) attribute_category = 'Network activity' if 'scan' in title.lower(): attribute_type = 'ip-src' else: attribute_type = 'ip-dst' if not attribute_value: LOGGER.warning('Unable to determine observable type: {0}'.format(str(type(observable.object_.properties)))) continue attribute_exists = False attribute_search = misp.search(controller='attributes', value=attribute_value) if not attribute_search['Attribute'] == []: for attribute_result in attribute_search['Attribute']: if int(attribute_result['event_id']) == int(event['id']): attribute_exists = True if attribute_exists: continue attribute_json = {'category': attribute_category, 'type': attribute_type, 'value': attribute_value, 'to_ids': MISP_TO_IDS} new_attr = misp.add_attribute(event, attribute_json, pythonify=True) if MISP_PUBLISH_EVENTS: LOGGER.info('Publishing event...') misp.publish(event) LOGGER.info('Case complete!')
def main(): # NOTE: ID values will differ due to being regenerated on each script execution pkg = STIXPackage() pkg.title = "Examples of Observable Composition" # USE CASE: single obj with single condition obs = File() obs.file_name = "foo.exe" obs.file_name.condition = "Contains" pkg.add_observable(obs) # USE CASE: single obj with multiple conditions obs = File() obs.file_name = "foo" obs.file_name.condition = "Contains" obs.size_in_bytes = '1896000' obs.size_in_bytes.condition = "Equals" pkg.add_observable(obs) # USE CASE: multiple obj with individual conditions obs = EmailMessage() obs.subject = "Syria strategic plans leaked" obs.subject.condition = "Equals" file_obj = File() file_obj.file_name = "bombISIS.pdf" file_obj.file_name.condition = "Equals" obs.add_related(file_obj, "Contains") pkg.add_observable(obs) # USE CASE: multiple objects with complex condition like (A OR B) AND C # orcomp = either of a mutex or file are present orcomp = ObservableComposition() orcomp.operator = "OR" obs = Mutex() obs.name = 'foo' obs.name.condition = "Contains" orcomp.add(obs) obs = File() obs.file_name = "barfoobar" obs.file_name.condition = "Equals" orcomp.add(obs) # andcomp = the above is true AND a network connection is present andcomp = ObservableComposition() andcomp.operator = "AND" andcomp.add(orcomp) obs = NetworkConnection() sock = SocketAddress() sock.ip_address = "46.123.99.25" sock.ip_address.category = "ipv4-addr" sock.ip_address.condition = "Equals" obs.destination_socket_address = sock andcomp.add(obs) pkg.add_observable(andcomp) # USE CASE: single object, one property with multiple values obs = SocketAddress() obs.ip_address = ['10.0.0.0', '10.0.0.1', '10.0.0.2'] # comma delimiter automagically added obs.ip_address.condition = "Equals" obs.ip_address.apply_condition = "ANY" pkg.add_observable(obs) print pkg.to_xml()
def load_stix(stix): # Just save the pain and load it if the first character is a < log.debug("Loading STIX...") if sys.version_info < (3, 5): json_exception = ValueError else: json_exception = json.JSONDecodeError if isinstance(stix, STIXPackage): log.debug("Argument was already STIX package, ignoring.") # Oh cool we're ok # Who tried to load this? Honestly. return stix elif hasattr(stix, 'read'): log.debug("Argument has 'read' attribute, assuming file-like.") # It's a file! # But somehow, sometimes, reading it returns a bytes stream # and the loader dies on python 3.4. # Luckily, STIXPackage.from_json (which is mixbox.Entity.from_json) # will happily load a string. # So we're going to play dirty. data = stix.read() log.debug("Read file, type %s.", type(data)) if isinstance(data, bytes): data = data.decode() try: log.debug("Attempting to load from JSON...") # Try loading from JSON stix_package = STIXPackage.from_json(data) except json_exception: log.debug("Attempting to load from XML...") # Ok then try loading from XML # Loop zoop # Read the STIX into an Etree stix.seek(0) stix_xml = etree.fromstring(stix.read()) ns_map = stix_xml.nsmap # Remove any "marking" sections because the US-Cert is evil log.debug("Removing Marking elements...") pattern = ".//{http://data-marking.mitre.org/Marking-1}Marking" for element in stix_xml.findall(pattern): element.getparent().remove(element) log.debug("Writing cleaned XML to Tempfile") f = SpooledTemporaryFile(max_size=10 * 1024) f.write(etree.tostring(stix_xml)) f.seek(0) # Pray to anything you hold sacred ns_objmap = map(lambda x: Namespace(ns_map[x], x), ns_map) for ns in ns_objmap: log.debug("Trying to add namespace %s", ns) try: nsparser.STIX_NAMESPACES.add_namespace(ns) mixbox.namespaces.register_namespace(ns) except Exception as ex: log.exception(ex) try: log.debug("Attempting to read clean XML into STIX...") stix_package = STIXPackage.from_xml(f) except Exception as ex: # No joy. Quit. log.fatal("Could not :<") log.exception(ex) f.seek(0) with open("FAILED_STIX.xml", "wb") as g: g.write(f.read()) raise STIXLoadError("Could not load stix file. {}".format(ex)) return stix_package elif isinstance(stix, (str, bytes)): if isinstance(stix, bytes): stix = stix.decode() # It's text, we'll need to use a temporary file # Create a temporary file to load from # Y'know I should probably give it a max size before jumping to disk # idk, 10MB? Sounds reasonable. f = SpooledTemporaryFile(max_size=10 * 1024) # O I have idea for sneak # Will be very sneak # Write the (probably) XML to file f.write(stix.encode("utf-8")) # Reset the file so we can read from it f.seek(0) # AHA SNEAK DIDN'T EXPECT RECURSION DID YOU return load_stix(f)
def parse_stix(self, reference='', make_event=False, source=''): """ Parse the document. :param reference: The reference to the data. :type reference: str :param make_event: Whether or not to create an Event for this document. :type make_event: bool :param source: The source of this document. :type source: str :raises: :class:`crits.standards.parsers.STIXParserException` Until we have a way to map source strings in a STIX document to a source in CRITs, we are being safe and using the source provided as the true source. """ f = StringIO(self.data) self.package = STIXPackage.from_xml(f) f.close() if not self.package: raise STIXParserException("STIX package failure") stix_header = self.package.stix_header if stix_header and stix_header.information_source and stix_header.information_source.identity: self.information_source = stix_header.information_source.identity.name if self.information_source: info_src = "STIX Source: %s" % self.information_source if not reference: reference = '' else: reference += ", " reference += info_src if does_source_exist(source): self.source.name = source elif does_source_exist(self.information_source): self.source.name = self.information_source else: raise STIXParserException("No source to attribute data to.") self.source_instance.reference = reference self.source.instances.append(self.source_instance) if make_event: title = "STIX Document %s" % self.package.id_ event_type = "Collective Threat Intelligence" date = datetime.datetime.now() description = str(date) header = self.package.stix_header if isinstance(header, STIXHeader): if header.title: title = header.title if hasattr(header, 'package_intents'): event_type = str(header.package_intents[0]) if header.description: description = header.description if isinstance(description, StructuredText): try: description = description.to_dict() except: pass res = add_new_event(title, description, event_type, self.source.name, self.source_instance.method, self.source_instance.reference, date, self.source_instance.analyst) if res['success']: self.event = res['object'] self.imported[self.package.id_] = ('Event', res['object']) # Get relationships to the Event if self.package.incidents: incdnts = self.package.incidents for rel in getattr(incdnts[0], 'related_indicators', ()): self.event_rels[rel.item.idref] = ( rel.relationship.value, rel.confidence.value.value) else: self.failed.append((res['message'], "STIX Event", "")) if self.package.indicators: self.parse_indicators(self.package.indicators) if self.package.observables and self.package.observables.observables: self.parse_observables(self.package.observables.observables) if self.package.threat_actors: self.parse_threat_actors(self.package.threat_actors)
def main(): txt = demisto.args().get("iocXml").encode("utf-8") stx = convert_to_json(txt) if stx: stix2_to_demisto(stx) else: with tempfile.NamedTemporaryFile() as temp: temp.write(demisto.args()["iocXml"].encode("utf-8")) temp.flush() stix_package = STIXPackage.from_xml(temp.name) data = list() # type: list i = 0 stix_id = stix_package.id_ if stix_package.indicators: for ind in stix_package.indicators: ind_id = ind.id_ for obs in ind.observables: if hasattr(obs.object_.properties, "hashes"): # File object for digest in obs.object_.properties.hashes: if hasattr(digest, "simple_hash_value"): if isinstance(digest.simple_hash_value.value, list): for hash in digest.simple_hash_value.value: create_new_ioc(data, i, ind.timestamp, stix_id, ind_id) data[i]["indicator_type"] = "File" data[i]["value"] = hash i = i + 1 else: create_new_ioc(data, i, ind.timestamp, stix_id, ind_id) data[i]["indicator_type"] = "File" data[i][ "value"] = digest.simple_hash_value.value.strip( ) i = i + 1 elif hasattr(obs.object_.properties, "category"): # Address object category = obs.object_.properties.category if category.startswith("ip"): for ip in obs.object_.properties.address_value.values: create_new_ioc(data, i, ind.timestamp, stix_id, ind_id) data[i]["indicator_type"] = "IP" data[i]["value"] = ip i = i + 1 elif hasattr(obs.object_.properties, "type_"): if obs.object_.properties.type_ == "URL": # URI object create_new_ioc(data, i, ind.timestamp, stix_id, ind_id) data[i]["indicator_type"] = "URL" data[i][ "value"] = obs.object_.properties.value.value i = i + 1 elif hasattr(obs.object_.properties.value, "values"): for url in obs.object_.properties.value.values: # URI object create_new_ioc(data, i, ind.timestamp, stix_id, ind_id) data[i]["indicator_type"] = "URL" data[i]["value"] = url i = i + 1 json_data = json.dumps(data) demisto.results(json_data)
def test_deprecated_related_packages(self): t = ta.ThreatActor() t.related_packages.append(STIXPackage()) self.assertEqual(len(t.related_packages), 1)
for message in sliced_search(misp, args.start, args.end, args.day_slice, args.time_wait, datasrc_dict, allowed_attribute_set, args.quiet, attribute_status_dict, stix_export_file, yara_export_file, snort_export_file, bool(args.mail)): if args.verbose and message is not None: print message if isinstance(sock, socket.socket) and message is not None: sock.send(message) if isinstance(sock, socket.socket): sock.close() if args.stix_export_path: stix_package = STIXPackage() stix_header = STIXHeader() stix_header.description = "MISP checkioc STIX export" stix_package.stix_header = stix_header for indicator in stix_indicators: stix_package.add(indicator) stix_export_file.write(stix_package.to_xml()) stix_export_file.close() if args.yara_export_path: yara_export_file.close() if args.snort_export_path: