def parseString(inString): from mixbox.vendor.six import StringIO doc = parsexml_(StringIO(inString)) rootNode = doc.getroot() rootTag, rootClass = get_root_tag(rootNode) if rootClass is None: rootTag = 'Windows_Event_Log' rootClass = WindowsEventLogObjectType rootObj = rootClass.factory() rootObj.build(rootNode) # Enable Python to collect the space used by the DOM. doc = None # sys.stdout.write('<?xml version="1.0" ?>\n') # rootObj.export(sys.stdout.write, 0, name_="Windows_Event_Log", # namespacedef_='') return rootObj
def parseString(inString): from mixbox.vendor.six import StringIO doc = parsexml_(StringIO(inString)) rootNode = doc.getroot() rootTag, rootClass = get_root_tag(rootNode) if rootClass is None: rootTag = 'CIQAddress3.0InstanceType' rootClass = CIQAddress3_0InstanceType rootObj = rootClass.factory() rootObj.build(rootNode) # Enable Python to collect the space used by the DOM. # doc = None # sys.stdout.write('<?xml version="1.0" ?>\n') # rootObj.export(sys.stdout, 0, name_="CIQAddress3.0InstanceType", # namespacedef_='') return rootObj
def parseString(inString): from mixbox.vendor.six import StringIO doc = parsexml_(StringIO(inString)) rootNode = doc.getroot() rootTag, rootClass = get_root_tag(rootNode) if rootClass is None: rootTag = 'ISAMarkingsAssertions' rootClass = ISAMarkingsAssertionType rootObj = rootClass.factory() rootObj.build(rootNode) # Enable Python to collect the space used by the DOM. doc = None # sys.stdout.write('<?xml version="1.0" ?>\n') # rootObj.export(sys.stdout, 0, name_="Indicator", # namespacedef_='') return rootObj
def test_marking_path_parsing(self): """Test that parsed paths are applied correctly""" # paths to attempt for a global AMBER marking global_xpaths = [{ "path": "//node() | //@*", "should_pass": True }, { "path": "this is not a real xpath", "should_pass": False }] # paths to attempt for a local RED marking local_xpaths = [{ "path": "../../../descendant-or-self::node() | ../../../descendant-or-self::node()/@*", "should_pass": True }, { "path": "this is not a real xpath", "should_pass": False }] for global_path_dict in global_xpaths: for local_path_dict in local_xpaths: # Format our STIX XML template xml = STIX_XML_TEMPLATE_GLOBAL_AND_COMPONENT.format( global_path_dict["path"], local_path_dict["path"]) xml_readable = StringIO(xml) # Build and parse the MarkingContainer try: container = stixmarx.parse(xml_readable) except etree.XPathEvalError: self.assertTrue(global_path_dict["should_pass"] is False or local_path_dict["should_pass"] is False) continue package = container.package colors = [ marking_spec.marking_structures[0].color for marking_spec in container.get_markings(package.indicators[0]) ] self.assertTrue( ('AMBER' in colors) == global_path_dict["should_pass"]) self.assertTrue( ('RED' in colors) == local_path_dict["should_pass"])
def test_ts_tz_resolves(self): root = utils.get_etree_root(StringIO(TS_TZ_RESOLVES)) offset_resolves = common.idref_timestamp_resolves( root=root, idref="example:campaign-1", timestamp="2015-04-14T15:24:19.416203+00:00", namespaces=common.get_stix_namespaces('1.1.1')) zulu_resolves = common.idref_timestamp_resolves( root=root, idref="example:campaign-1", timestamp="2015-04-14T15:24:19.416203Z", namespaces=common.get_stix_namespaces('1.1.1')) self.assertTrue(zulu_resolves) self.assertTrue(offset_resolves)
def test_all_versions_in_single_package(self): package = STIXPackage.from_xml(StringIO(XML_GLOBAL)) self.assertTrue(isinstance(package.stix_header.handling[0].marking_structures[0], stix_edh.isa_markings.ISAMarkings)) self.assertTrue(isinstance(package.stix_header.handling[0].marking_structures[1], stix_edh.isa_markings_assertions.ISAMarkingsAssertion)) print(package.to_xml()) package = STIXPackage.from_dict(package.to_dict()) self.assertTrue(isinstance(package.stix_header.handling[0].marking_structures[0], stix_edh.isa_markings.ISAMarkings)) self.assertTrue(isinstance(package.stix_header.handling[0].marking_structures[1], stix_edh.isa_markings_assertions.ISAMarkingsAssertion)) json_string = json.dumps(package.to_dict()) print(json_string) print("-" * 40)
def test_description_output(self): incident = incident_binding.IncidentType() assets = incident_binding.AffectedAssetsType() asset = incident_binding.AffectedAssetType() description = StructuredText("A Description") asset.Structured_Description = description.to_obj() assets.add_Affected_Asset(asset) incident.Affected_Assets = assets s = StringIO() incident.export(s.write, 0, {'http://stix.mitre.org/Incident-1': 'incident'}) xml = s.getvalue() self.assertTrue("A Description" in xml, "Description not exported")
def test_same_value_different_location(self): """URL: https://github.com/mitre/stixmarx/pull/9""" sio = StringIO(ISSUE9_XML) parse_obj = parser.MarkingParser(sio) package = parse_obj.parse() for o in package.observables: file_obj = o.object_.properties size_in_bytes = file_obj.size_in_bytes hashes = file_obj.hashes self.assertTrue(hasattr(size_in_bytes, "__datamarkings__")) self.assertEqual(len(size_in_bytes.__datamarkings__), 1) for hash_ in hashes: self.assertTrue(hasattr(hash_, "__datamarkings__")) self.assertTrue( hasattr(hash_.simple_hash_value, "__datamarkings__")) self.assertEqual(len(hash_.__datamarkings__), 1) self.assertEqual(len(hash_.simple_hash_value.__datamarkings__), 1)
def setUpClass(cls): indicator = Indicator(title="Indicator 1", description="Description Indicator 1") indicator.alternative_id = "indicator:example1" indicator.observables = generate_observable() cls.stix_package = STIXPackage() cls.stix_package.add_indicator(indicator) cls.cybox = (address_object.Address(), address_object.EmailAddress(), disk_object.Disk(), win_executable_file_object.DOSHeader(), win_process_object.StartupInfo(), network_packet_object.NetworkPacket()) sio = StringIO(cls.stix_package.to_xml().decode("utf-8")) cls.PARSER = parser.MarkingParser(sio) cls.msg = "For entity {0}: {1} not found in _FIELDS dictionary."
def test_mapping_assertion(self): """Tests the mappings for objects.""" indicator = self.stix_package.indicators[0] for properties in indicator.typed_fields_with_attrnames(): attr, tf = properties selector = attrmap.xmlfield(indicator, attr) self.assertTrue(selector, self.msg.format(indicator, attr)) if selector == "Title": prefix = indicator._ID_PREFIX cntrl = generate_control_exp(prefix, selector) xpath = etree.XPath(cntrl, namespaces=self.PARSER._root.nsmap) result = xpath(self.PARSER._root) self.assertEqual(len(result), 1) name = xml.localname(result[0]) self.assertEqual(name, selector) self.assertEqual(result[0].text, getattr(indicator, attr)) apply_markings(self.stix_package, prefix, selector) # re-parse the document with marking changes. sio = StringIO(self.stix_package.to_xml().decode("utf-8")) self.PARSER = parser.MarkingParser(sio) package = self.PARSER.parse() self.assertEqual(len(package.indicators), 1) # See if the indicator was not marked. indicator = package.indicators[0] self.assertTrue(indicator in self.PARSER._entities) self.assertFalse(hasattr(indicator, api._ATTR_DATA_MARKINGS)) title = indicator.title self.assertTrue( isinstance(title, (types.MarkableText, types.MarkableBytes))) self.assertEqual(len(title.__datamarkings__), 1)
def test_marking_round_trip(self): """Test that get_markings() yields the same number of results after calling to_xml().""" container = stixmarx.new() package = container.package red_marking = generate_marking_spec(generate_red_marking_struct()) amber_marking = generate_marking_spec(generate_amber_marking_struct()) incident = Incident(title="Test Incident") package.add_incident(incident) indicator = Indicator(idref="example:Indicator-test-1234") incident.related_indicators.append(indicator) container.add_marking(incident, red_marking, descendants=True) container.add_global(amber_marking) self.assertTrue(container.is_marked(indicator, red_marking)) self.assertTrue(container.is_marked(indicator, amber_marking)) markings = container.get_markings(indicator) self.assertEqual(len(markings), 2) xml = container.to_xml() sio = StringIO(xml.decode("utf-8")) new_xml_container = stixmarx.parse(sio) parsed_indicator = new_xml_container.package.incidents[ 0].related_indicators[0] parsed_markings = new_xml_container.get_markings(parsed_indicator) for x in parsed_markings: print(x.to_dict()) self.assertEqual(len(parsed_markings), 2)
def test_defined_version(self): xml = StringIO(STIX_NO_VERSION_XML) results = sdv.validate_xml(xml, version="1.1.1") self.assertTrue(results.is_valid)
class PythonMAECInPackageTests(unittest.TestCase): XML = StringIO(""" <stix:STIX_Package xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:stix="http://stix.mitre.org/stix-1" xmlns:stixCommon="http://stix.mitre.org/common-1" xmlns:stixVocabs="http://stix.mitre.org/default_vocabularies-1" xmlns:ttp="http://stix.mitre.org/TTP-1" xmlns:example="http://example.com" xsi:schemaLocation=" http://stix.mitre.org/TTP-1 http://stix.mitre.org/XMLSchema/ttp/1.2/ttp.xsd http://stix.mitre.org/common-1 http://stix.mitre.org/XMLSchema/common/1.2/stix_common.xsd http://stix.mitre.org/default_vocabularies-1 http://stix.mitre.org/XMLSchema/default_vocabularies/1.2.0/stix_default_vocabularies.xsd http://stix.mitre.org/stix-1 http://stix.mitre.org/XMLSchema/core/1.2/stix_core.xsd" id="example:Package-2b8fb66f-b6b3-4d40-865a-33e4a5ee1246" version="1.2" > <stix:TTPs> <stix:TTP xsi:type="ttp:TTPType" id="example:ttp-7d9fe1f7-429d-077e-db51-92c70b8da45a"> <ttp:Title>Poison Ivy Variant v4392-acc</ttp:Title> <ttp:Behavior> <ttp:Malware> <ttp:Malware_Instance> <ttp:Type xsi:type="stixVocabs:MalwareTypeVocab-1.0">Remote Access Trojan</ttp:Type> <ttp:Name>Poison Ivy Variant v4392-acc</ttp:Name> </ttp:Malware_Instance> </ttp:Malware> </ttp:Behavior> </stix:TTP> </stix:TTPs> </stix:STIX_Package> """) XML_MAEC = StringIO(""" <stix:STIX_Package xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:stix="http://stix.mitre.org/stix-1" xmlns:stixCommon="http://stix.mitre.org/common-1" xmlns:stixVocabs="http://stix.mitre.org/default_vocabularies-1" xmlns:ttp="http://stix.mitre.org/TTP-1" xmlns:stix-maec="http://stix.mitre.org/extensions/Malware#MAEC4.1-1" xmlns:maecPackage="http://maec.mitre.org/XMLSchema/maec-package-2" xmlns:example="http://example.com" xsi:schemaLocation=" http://stix.mitre.org/TTP-1 http://stix.mitre.org/XMLSchema/ttp/1.2/ttp.xsd http://stix.mitre.org/common-1 http://stix.mitre.org/XMLSchema/common/1.2/stix_common.xsd http://stix.mitre.org/default_vocabularies-1 http://stix.mitre.org/XMLSchema/default_vocabularies/1.2.0/stix_default_vocabularies.xsd http://stix.mitre.org/stix-1 http://stix.mitre.org/XMLSchema/core/1.2/stix_core.xsd http://stix.mitre.org/extensions/Malware#MAEC4.1-1 http://stix.mitre.org/XMLSchema/extensions/malware/maec_4.1/1.0/maec_4.1_malware.xsd http://maec.mitre.org/XMLSchema/maec-package-2 http://maec.mitre.org/language/version4.1/maec_package_schema.xsd" id="example:Package-2b8fb66f-b6b3-4d40-865a-33e4a5ee1246" version="1.2" > <stix:TTPs> <stix:TTP xsi:type="ttp:TTPType" id="example:ttp-7d9fe1f7-429d-077e-db51-92c70b8da45a"> <ttp:Title>Poison Ivy Variant v4392-acc</ttp:Title> <ttp:Behavior> <ttp:Malware> <ttp:Malware_Instance xsi:type="stix-maec:MAEC4.1InstanceType"> <ttp:Type xsi:type="stixVocabs:MalwareTypeVocab-1.0">Remote Access Trojan</ttp:Type> <ttp:Name>Poison Ivy Variant v4392-acc</ttp:Name> <stix-maec:MAEC id="example:package-2fb96bef-1b11-436e-af4a-15588ac3198b" schema_version="2.1"> <maecPackage:Malware_Subjects> <maecPackage:Malware_Subject id="example:Subject-57cd4839-436e-1b11-af4a-15588ac3198b"> <maecPackage:Malware_Instance_Object_Attributes> </maecPackage:Malware_Instance_Object_Attributes> </maecPackage:Malware_Subject> </maecPackage:Malware_Subjects> </stix-maec:MAEC> </ttp:Malware_Instance> </ttp:Malware> </ttp:Behavior> </stix:TTP> </stix:TTPs> </stix:STIX_Package> """) def test_parse_malware(self): """Test parsing a normal MalwareInstance from XML """ stix_pkg = STIXPackage.from_xml(self.XML) mw = stix_pkg.ttps[0].behavior.malware_instances[0].to_dict() self.assertTrue('names' in mw) def test_parse_malware_maec(self): """Test parsing a MaecInstance from XML """ stix_pkg = STIXPackage.from_xml(self.XML_MAEC) mw = stix_pkg.ttps[0].behavior.malware_instances[0].to_dict() self.assertTrue('names' in mw)
def test_unknown_version(self): func = sdv.validate_xml xml = StringIO(STIX_NO_VERSION_XML) self.assertRaises(errors.UnknownSTIXVersionError, func, xml)
def test_get_etree_root_stringio(self): sio = StringIO(XML) root = utils.get_etree_root(sio) lname = etree.QName(root).localname self.assertEqual(lname, XML_ROOT_LOCALNAME)
def to_xml(self, include_namespaces=True, include_schemalocs=False, ns_dict=None, schemaloc_dict=None, pretty=True, auto_namespace=True, encoding='utf-8'): """Serializes a :class:`Entity` instance to an XML string. The default character encoding is ``utf-8`` and can be set via the `encoding` parameter. If `encoding` is ``None``, a string (unicode in Python 2, str in Python 3) is returned. Args: auto_namespace: Automatically discover and export XML namespaces for a STIX :class:`Entity` instance. include_namespaces: Export namespace definitions in the output XML. Default is ``True``. include_schemalocs: Export ``xsi:schemaLocation`` attribute in the output document. This will attempt to associate namespaces declared in the STIX document with schema locations. If a namespace cannot be resolved to a schemaLocation, a Python warning will be raised. Schemalocations will only be exported if `include_namespaces` is also ``True``. ns_dict: Dictionary of XML definitions (namespace is key, alias is value) to include in the exported document. This must be passed in if `auto_namespace` is ``False``. schemaloc_dict: Dictionary of XML ``namespace: schema location`` mappings to include in the exported document. These will only be included if `auto_namespace` is ``False``. pretty: Pretty-print the XML. encoding: The output character encoding. Default is ``utf-8``. If `encoding` is set to ``None``, a string (unicode in Python 2, str in Python 3) is returned. Returns: An XML string for this :class:`Entity` instance. Default character encoding is ``utf-8``. """ from mixbox.entities import NamespaceCollector if (not auto_namespace) and (not ns_dict): raise Exception( "Auto-namespacing was disabled but ns_dict was empty " "or missing.") ns_info = NamespaceCollector() obj = self.to_obj(ns_info=ns_info if auto_namespace else None) ns_info.finalize(ns_dict=ns_dict, schemaloc_dict=schemaloc_dict) if auto_namespace: obj_ns_dict = ns_info.binding_namespaces else: obj_ns_dict = dict( itertools.chain(iteritems(ns_info.binding_namespaces), iteritems(namespaces.get_full_ns_map()))) namespace_def = "" if include_namespaces: delim = "\n\t" if pretty else " " xmlns = ns_info.get_xmlns_string(delim) namespace_def += (delim + xmlns) if include_schemalocs: schemaloc = ns_info.get_schema_location_string(delim) namespace_def += (delim + schemaloc) with binding_utils.save_encoding(encoding): sio = StringIO() obj.export( sio.write, # output buffer 0, # output level obj_ns_dict, # namespace dictionary pretty_print=pretty, # pretty printing namespacedef_=namespace_def # namespace/schemaloc def string ) # Ensure that the StringIO buffer is unicode s = text_type(sio.getvalue()) if encoding: return s.encode(encoding) return s
def test_defined_version(self): xml = StringIO(CYBOX_2_1_XML) results = sdv.validate_xml(xml, version="2.1") self.assertTrue(results.is_valid)
def test_get_etree_root_raises(self): sio = StringIO(BROKEN_XML) self.assertRaises(errors.ValidationError, utils.get_etree_root, sio)
def test_parse(self): # Check to see if `parse` correctly returns lxml.etree._Element object ioc_xml = StringIO(OPENIOC_XML) root = xml.parse(ioc_xml) self.assertEqual(type(root), ET._Element)
def setUpClass(cls): StringIO(STIX_1_1_1_XML)
def test_target_ns(self): sio = StringIO(XML) target_ns = utils.get_target_ns(sio) self.assertEqual(target_ns, TARGET_NS)
def test_get_schemaloc_pairs_raises(self): sio = StringIO(XML) root = utils.get_etree_root(sio) self.assertRaises(KeyError, utils.get_schemaloc_pairs, root)
def test_get_schemaloc_pairs(self): sio = StringIO(XML_SCHEMALOC) root = utils.get_etree_root(sio) pairs = utils.get_schemaloc_pairs(root) self.assertEqual(2, len(list(pairs)))
def test_valid(self): xml = StringIO(STIX_1_1_1_XML) results = sdv.validate_xml(xml) self.assertTrue(results.is_valid)
def setUp(cls): sio = StringIO(BP_INVALID_XML) cls.results = sdv.validate_best_practices(sio)
def setUpClass(cls): sio = StringIO(XML_GLOBAL) cls.PARSER = parser.MarkingParser(sio)
def setUpClass(cls): StringIO(CYBOX_2_1_XML)
def setUpClass(cls): sio = StringIO(XML_LIST) cls.PARSER = parser.MarkingParser(sio) cls.PACKAGE = cls.PARSER.parse()
def test_invalid_profile(self): xml = StringIO(STIX_NO_VERSION_XML) func = sdv.validate_profile self.assertRaises(errors.ProfileParseError, func, xml, "INVALID Profile DOC")