diff --git a/pymisp/tools/openioc.py b/pymisp/tools/openioc.py index 488c5b09..b3ddc282 100644 --- a/pymisp/tools/openioc.py +++ b/pymisp/tools/openioc.py @@ -257,7 +257,7 @@ def set_all_attributes(openioc, misp_event): childList = [child.find('context')['search'] for child in childs] def check_and_add(value1, value2): - if (value1 and value2) in childList: + if value1 in childList and value2 in childList: if childs[0].find('context')['search'] == value1: attribute_values = set_values(childs[0], childs[1]) else: diff --git a/tests/test_openioc.py b/tests/test_openioc.py new file mode 100644 index 00000000..b09ba945 --- /dev/null +++ b/tests/test_openioc.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python + +from __future__ import annotations + +import unittest +import warnings + +from pymisp.tools import openioc + +try: + from bs4 import XMLParsedAsHTMLWarning # type: ignore + warnings.filterwarnings("ignore", category=XMLParsedAsHTMLWarning) +except ImportError: + pass + + +# Two children of an AND-indicator whose combined search-context pair is NOT a +# defined composite (RegistryItem/Value + FileItem/Md5sum). These must come back +# as their two individual attributes, not a merged composite. +NON_COMPOSITE = """ + + non-composite test + + + + + malicious_value + + + + d41d8cd98f00b204e9800998ecf8427e + + + +""" + +# A genuine, defined composite pair (FileItem/FileName + FileItem/Md5sum). This +# must still merge into a single filename|md5 attribute. +COMPOSITE = """ + + composite test + + + + + evil.exe + + + + d41d8cd98f00b204e9800998ecf8427e + + + +""" + + +class TestOpenIOC(unittest.TestCase): + + def test_non_composite_and_indicator_not_merged(self) -> None: + event = openioc.load_openioc(NON_COMPOSITE) + by_type = {attr.type: attr.value for attr in event.attributes} + # Two distinct, correctly typed attributes, no bogus merged composite. + self.assertEqual(len(event.attributes), 2) + self.assertEqual(by_type.get('regkey'), 'malicious_value') + self.assertEqual(by_type.get('md5'), 'd41d8cd98f00b204e9800998ecf8427e') + self.assertNotIn('other', by_type) + + def test_genuine_composite_still_merged(self) -> None: + event = openioc.load_openioc(COMPOSITE) + self.assertEqual(len(event.attributes), 1) + attr = event.attributes[0] + self.assertEqual(attr.type, 'filename|md5') + self.assertEqual(attr.value, 'evil.exe|d41d8cd98f00b204e9800998ecf8427e') + + +if __name__ == '__main__': + unittest.main()