Skip to content

Commit

Permalink
Merge pull request #308 from STIXProject/issue303
Browse files Browse the repository at this point in the history
Parsing MAECInstance from XML
  • Loading branch information
gtback committed Oct 21, 2016
2 parents 4e2f4f4 + 689cbae commit 8516991
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 14 deletions.
18 changes: 9 additions & 9 deletions stix/extensions/malware/maec_4_1_malware.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ def from_obj(cls, obj):
else:
obj.MAEC = obj.MAEC

super(MAECInstance, cls).from_obj(obj)
return_obj = super(MAECInstance, cls).from_obj(obj)

return return_obj

Expand Down Expand Up @@ -192,11 +192,11 @@ def _maec_from_dict(cls, d):
def from_dict(cls, d, return_obj=None):
if not d:
return None

d = d.copy()

maec = d.get('maec')

if maec is None:
pass
elif isinstance(maec, dict):
Expand All @@ -205,9 +205,9 @@ def from_dict(cls, d, return_obj=None):
d['maec'] = mixbox.xml.get_etree_root(BytesIO(maec))
else:
raise TypeError("Unknown type for 'maec' entry.")

return_obj = super(MAECInstance, cls).from_dict(d)

return return_obj

def to_dict(self):
Expand All @@ -219,13 +219,13 @@ def to_dict(self):
root = mixbox.xml.get_etree_root(tree)
self._parse_etree(root)
self.maec = root

if _MAEC_INSTALLED and isinstance(self.maec, maecPackage):
d['maec'] = self.maec.to_dict()
else:
d['maec'] = etree.tostring(self.maec)

if self._XSI_TYPE:
d['xsi:type'] = self._XSI_TYPE

return d
7 changes: 3 additions & 4 deletions stix/test/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ def round_trip_dict(cls, dict_):
dict2 = cls.to_dict(api_obj)
return dict2


def round_trip(o, output=False, list_=False):
""" Performs all eight conversions to verify import/export functionality.
Expand Down Expand Up @@ -124,14 +125,15 @@ def round_trip(o, output=False, list_=False):
# Before parsing the XML, make sure the cache is clear
cybox.utils.cache_clear()

#7. XML String -> Bindings Object
# 7. XML String -> Bindings Object
xobj2 = klass._binding.parseString(xml_string)

# 8. Bindings object -> cybox.Entity
o3 = klass.from_obj(xobj2)

return o3


class EntityTestCase(object):
"""A base class for testing STIX Entities"""

Expand All @@ -157,15 +159,13 @@ def _combine(self, d):

return dict(items)


@silence_warnings
def test_round_trip_full(self):
# Don't run this test on the base class
if type(self) is EntityTestCase:
return

ent = self.klass.from_dict(self._full_dict)

ent2 = round_trip(ent, output=True)

@silence_warnings
Expand All @@ -190,4 +190,3 @@ def test_round_trip_rt(self):
obj = self.klass.from_dict(self._full_dict)
dict2 = obj.to_dict()
self.assertEqual(self._full_dict, dict2)

98 changes: 98 additions & 0 deletions stix/test/extensions/malware/maec_4_1_malware_test.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import unittest
from stix.core import STIXPackage
from mixbox.vendor.six import StringIO, BytesIO, text_type

from lxml import etree
Expand Down Expand Up @@ -113,5 +114,102 @@ def test_etree_dict(self):
self._test_xml(ext2)


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"
timestamp="2014-05-08T09:00:00.000000Z"
>
<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"
timestamp="2014-05-08T09:00:00.000000Z"
>
<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)


if __name__ == "__main__":
unittest.main()
2 changes: 1 addition & 1 deletion stix/ttp/malware_instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def add_short_description(self, description):
This is the same as calling "foo.short_descriptions.add(bar)".
"""
self.short_descriptions.add(description)

def add_name(self, name):
self.names.append(name)

Expand Down

0 comments on commit 8516991

Please sign in to comment.