From 374539a6cc7fe0f380ab598ed39d791967119afb Mon Sep 17 00:00:00 2001 From: Greg Back Date: Thu, 12 Oct 2017 14:38:25 +0000 Subject: [PATCH 01/19] Don't try to re-parse STIX Objects when adding to Bundle. --- stix2/core.py | 11 ++++++++--- stix2/test/test_bundle.py | 8 ++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/stix2/core.py b/stix2/core.py index 8ee11f5..20bd187 100644 --- a/stix2/core.py +++ b/stix2/core.py @@ -7,9 +7,9 @@ from .base import _STIXBase from .common import MarkingDefinition from .properties import IDProperty, ListProperty, Property, TypeProperty from .sdo import (AttackPattern, Campaign, CourseOfAction, Identity, Indicator, - IntrusionSet, Malware, ObservedData, Report, ThreatActor, - Tool, Vulnerability) -from .sro import Relationship, Sighting + IntrusionSet, Malware, ObservedData, Report, + STIXDomainObject, ThreatActor, Tool, Vulnerability) +from .sro import Relationship, Sighting, STIXRelationshipObject from .utils import get_dict @@ -20,6 +20,11 @@ class STIXObjectProperty(Property): super(STIXObjectProperty, self).__init__() def clean(self, value): + # Any STIX Object (SDO, SRO, or Marking Definition) can be added to + # a bundle with no further checks. + if isinstance(value, (STIXDomainObject, STIXRelationshipObject, + MarkingDefinition)): + return value try: dictified = get_dict(value) except ValueError: diff --git a/stix2/test/test_bundle.py b/stix2/test/test_bundle.py index c7c95a8..12b2149 100644 --- a/stix2/test/test_bundle.py +++ b/stix2/test/test_bundle.py @@ -158,3 +158,11 @@ def test_parse_unknown_type(): with pytest.raises(stix2.exceptions.ParseError) as excinfo: stix2.parse(unknown) assert str(excinfo.value) == "Can't parse unknown object type 'other'! For custom types, use the CustomObject decorator." + + +def test_stix_object_property(): + prop = stix2.core.STIXObjectProperty() + + identity = stix2.Identity(name="test", identity_class="individual") + assert prop.clean(identity) == identity + assert prop.clean(identity) is identity From 134267bfd6159caed17882c3a6a54ef49eb7346f Mon Sep 17 00:00:00 2001 From: Chris Lenk Date: Thu, 12 Oct 2017 11:20:20 -0400 Subject: [PATCH 02/19] Add FileSystem test fixture, test adding bundle --- stix2/sources/filesystem.py | 10 ++++++---- stix2/test/test_data_sources.py | 24 ++++++++++++++++++------ 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/stix2/sources/filesystem.py b/stix2/sources/filesystem.py index 103b882..f11df65 100644 --- a/stix2/sources/filesystem.py +++ b/stix2/sources/filesystem.py @@ -8,10 +8,12 @@ TODO: import json import os -from stix2.base import _STIXBase +from stix2.common import MarkingDefinition from stix2.core import Bundle, parse +from stix2.sdo import STIXDomainObject from stix2.sources import DataSink, DataSource, DataStore from stix2.sources.filters import Filter, apply_common_filters +from stix2.sro import STIXRelationshipObject from stix2.utils import deduplicate @@ -81,7 +83,7 @@ class FileSystemSink(DataSink): # Bundle() can take dict or STIX obj as argument f.write(str(Bundle(stix_obj))) - if isinstance(stix_data, _STIXBase): + if isinstance(stix_data, (STIXDomainObject, STIXRelationshipObject, MarkingDefinition)): # adding python STIX object _check_path_and_write(self._stix_dir, stix_data) @@ -94,11 +96,11 @@ class FileSystemSink(DataSink): # adding json-formatted STIX _check_path_and_write(self._stix_dir, stix_data) - elif isinstance(stix_data, str): + elif isinstance(stix_data, (str, Bundle)): # adding json encoded string of STIX content stix_data = parse(stix_data) if stix_data["type"] == "bundle": - for stix_obj in stix_data["objects"]: + for stix_obj in stix_data.get("objects", []): self.add(stix_obj) else: self.add(stix_data) diff --git a/stix2/test/test_data_sources.py b/stix2/test/test_data_sources.py index 689fe8c..3ee81a9 100644 --- a/stix2/test/test_data_sources.py +++ b/stix2/test/test_data_sources.py @@ -1,10 +1,11 @@ import os +import shutil import pytest from taxii2client import Collection -from stix2 import (Campaign, FileSystemSink, FileSystemSource, FileSystemStore, - Filter, MemorySource, MemoryStore) +from stix2 import (Bundle, Campaign, FileSystemSink, FileSystemSource, + FileSystemStore, Filter, MemorySource, MemoryStore) from stix2.sources import (CompositeDataSource, DataSink, DataSource, DataStore, make_id, taxii) from stix2.sources.filters import apply_common_filters @@ -29,6 +30,15 @@ def ds(): return DataSource() +@pytest.fixture +def fs_store(): + # create + yield FileSystemStore(FS_PATH) + + # remove campaign dir + shutil.rmtree(os.path.join(FS_PATH, "campaign")) + + IND1 = { "created": "2017-01-27T13:49:53.935Z", "id": "indicator--d81f86b9-975b-bc0b-775e-810c5ad45a4f", @@ -681,10 +691,7 @@ def test_filesystem_sink(): os.rmdir(os.path.join(FS_PATH, "campaign")) -def test_filesystem_store(): - # creation - fs_store = FileSystemStore(FS_PATH) - +def test_filesystem_store(fs_store): # get() coa = fs_store.get("course-of-action--d9727aee-48b8-4fdb-89e2-4c49746ba4dd") assert coa.id == "course-of-action--d9727aee-48b8-4fdb-89e2-4c49746ba4dd" @@ -716,3 +723,8 @@ def test_filesystem_store(): # remove campaign dir os.rmdir(os.path.join(FS_PATH, "campaign")) + + +def test_filesystem_add_object_with_custom_property_in_bundle(fs_store): + bundle = Bundle() + fs_store.add(bundle) From 6deaddc04eaee700042ae96da91473a63b4e4fa1 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Thu, 12 Oct 2017 14:08:32 -0400 Subject: [PATCH 03/19] Make sure custom properties are returned by object. closes #85 --- stix2/base.py | 9 ++++++++- stix2/test/test_custom.py | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/stix2/base.py b/stix2/base.py index 5307393..b0cf6ff 100644 --- a/stix2/base.py +++ b/stix2/base.py @@ -40,7 +40,14 @@ class _STIXBase(collections.Mapping): """Base class for STIX object types""" def object_properties(self): - return list(self._properties.keys()) + props = set(self._properties.keys()) + custom_props = list(set(self._inner.keys()) - props) + custom_props.sort() + + all_properties = list(self._properties.keys()) + all_properties.extend(custom_props) # Any custom properties to the bottom + + return all_properties def _check_property(self, prop_name, prop, kwargs): if prop_name not in kwargs: diff --git a/stix2/test/test_custom.py b/stix2/test/test_custom.py index 48529b9..c5726b8 100644 --- a/stix2/test/test_custom.py +++ b/stix2/test/test_custom.py @@ -91,6 +91,7 @@ def test_custom_property_in_bundled_object(): bundle = stix2.Bundle(identity, allow_custom=True) assert bundle.objects[0].x_foo == "bar" + assert '"x_foo": "bar"' in str(bundle) @stix2.sdo.CustomObject('x-new-type', [ From 84094e9f79ee0fef741f0335d99b9c6268f23b9b Mon Sep 17 00:00:00 2001 From: Chris Lenk Date: Wed, 18 Oct 2017 08:27:12 -0400 Subject: [PATCH 04/19] Separate out filesystem tests --- stix2/test/test_data_sources.py | 222 +-------------------------- stix2/test/test_filesystem.py | 255 ++++++++++++++++++++++++++++++++ 2 files changed, 256 insertions(+), 221 deletions(-) create mode 100644 stix2/test/test_filesystem.py diff --git a/stix2/test/test_data_sources.py b/stix2/test/test_data_sources.py index 3ee81a9..d7fd576 100644 --- a/stix2/test/test_data_sources.py +++ b/stix2/test/test_data_sources.py @@ -1,18 +1,13 @@ -import os -import shutil - import pytest from taxii2client import Collection -from stix2 import (Bundle, Campaign, FileSystemSink, FileSystemSource, - FileSystemStore, Filter, MemorySource, MemoryStore) +from stix2 import Filter, MemorySource, MemoryStore from stix2.sources import (CompositeDataSource, DataSink, DataSource, DataStore, make_id, taxii) from stix2.sources.filters import apply_common_filters from stix2.utils import deduplicate COLLECTION_URL = 'https://example.com/api1/collections/91a7b528-80eb-42ed-a74d-c6fbd5a26116/' -FS_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), "stix2_data") class MockTAXIIClient(object): @@ -30,15 +25,6 @@ def ds(): return DataSource() -@pytest.fixture -def fs_store(): - # create - yield FileSystemStore(FS_PATH) - - # remove campaign dir - shutil.rmtree(os.path.join(FS_PATH, "campaign")) - - IND1 = { "created": "2017-01-27T13:49:53.935Z", "id": "indicator--d81f86b9-975b-bc0b-775e-810c5ad45a4f", @@ -522,209 +508,3 @@ def test_composite_datasource_operations(): # STIX_OBJS2 has indicator with later time, one with different id, one with # original time in STIX_OBJS1 assert len(results) == 3 - - -def test_filesytem_source(): - # creation - fs_source = FileSystemSource(FS_PATH) - assert fs_source.stix_dir == FS_PATH - - # get object - mal = fs_source.get("malware--6b616fc1-1505-48e3-8b2c-0d19337bff38") - assert mal.id == "malware--6b616fc1-1505-48e3-8b2c-0d19337bff38" - assert mal.name == "Rover" - - # all versions - (currently not a true all versions call as FileSystem cant have multiple versions) - id_ = fs_source.get("identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5") - assert id_.id == "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5" - assert id_.name == "The MITRE Corporation" - assert id_.type == "identity" - - # query - intrusion_sets = fs_source.query([Filter("type", '=', "intrusion-set")]) - assert len(intrusion_sets) == 2 - assert "intrusion-set--a653431d-6a5e-4600-8ad3-609b5af57064" in [is_.id for is_ in intrusion_sets] - assert "intrusion-set--f3bdec95-3d62-42d9-a840-29630f6cdc1a" in [is_.id for is_ in intrusion_sets] - - is_1 = [is_ for is_ in intrusion_sets if is_.id == "intrusion-set--f3bdec95-3d62-42d9-a840-29630f6cdc1a"][0] - assert "DragonOK" in is_1.aliases - assert len(is_1.external_references) == 4 - - # query2 - is_2 = fs_source.query([Filter("external_references.external_id", '=', "T1027")]) - assert len(is_2) == 1 - - is_2 = is_2[0] - assert is_2.id == "attack-pattern--b3d682b6-98f2-4fb0-aa3b-b4df007ca70a" - assert is_2.type == "attack-pattern" - - -def test_filesystem_sink(): - # creation - fs_sink = FileSystemSink(FS_PATH) - assert fs_sink.stix_dir == FS_PATH - - fs_source = FileSystemSource(FS_PATH) - - # Test all the ways stix objects can be added (via different supplied forms) - - # add python stix object - camp1 = Campaign(name="Hannibal", - objective="Targeting Italian and Spanish Diplomat internet accounts", - aliases=["War Elephant"]) - - fs_sink.add(camp1) - - assert os.path.exists(os.path.join(FS_PATH, "campaign", camp1.id + ".json")) - - camp1_r = fs_source.get(camp1.id) - assert camp1_r.id == camp1.id - assert camp1_r.name == "Hannibal" - assert "War Elephant" in camp1_r.aliases - - # add stix object dict - camp2 = { - "name": "Aurelius", - "type": "campaign", - "objective": "German and French Intelligence Services", - "aliases": ["Purple Robes"], - "id": "campaign--111111b6-1112-4fb0-111b-b111107ca70a", - "created": "2017-05-31T21:31:53.197755Z" - } - - fs_sink.add(camp2) - - assert os.path.exists(os.path.join(FS_PATH, "campaign", camp2["id"] + ".json")) - - camp2_r = fs_source.get(camp2["id"]) - assert camp2_r.id == camp2["id"] - assert camp2_r.name == camp2["name"] - assert "Purple Robes" in camp2_r.aliases - - # add stix bundle dict - bund = { - "type": "bundle", - "id": "bundle--112211b6-1112-4fb0-111b-b111107ca70a", - "spec_version": "2.0", - "objects": [ - { - "name": "Atilla", - "type": "campaign", - "objective": "Bulgarian, Albanian and Romanian Intelligence Services", - "aliases": ["Huns"], - "id": "campaign--133111b6-1112-4fb0-111b-b111107ca70a", - "created": "2017-05-31T21:31:53.197755Z" - } - ] - } - - fs_sink.add(bund) - - assert os.path.exists(os.path.join(FS_PATH, "campaign", bund["objects"][0]["id"] + ".json")) - - camp3_r = fs_source.get(bund["objects"][0]["id"]) - assert camp3_r.id == bund["objects"][0]["id"] - assert camp3_r.name == bund["objects"][0]["name"] - assert "Huns" in camp3_r.aliases - - # add json-encoded stix obj - camp4 = '{"type": "campaign", "id":"campaign--144111b6-1112-4fb0-111b-b111107ca70a",'\ - ' "created":"2017-05-31T21:31:53.197755Z", "name": "Ghengis Khan", "objective": "China and Russian infrastructure"}' - - fs_sink.add(camp4) - - assert os.path.exists(os.path.join(FS_PATH, "campaign", "campaign--144111b6-1112-4fb0-111b-b111107ca70a" + ".json")) - - camp4_r = fs_source.get("campaign--144111b6-1112-4fb0-111b-b111107ca70a") - assert camp4_r.id == "campaign--144111b6-1112-4fb0-111b-b111107ca70a" - assert camp4_r.name == "Ghengis Khan" - - # add json-encoded stix bundle - bund2 = '{"type": "bundle", "id": "bundle--332211b6-1132-4fb0-111b-b111107ca70a",' \ - ' "spec_version": "2.0", "objects": [{"type": "campaign", "id": "campaign--155155b6-1112-4fb0-111b-b111107ca70a",' \ - ' "created":"2017-05-31T21:31:53.197755Z", "name": "Spartacus", "objective": "Oppressive regimes of Africa and Middle East"}]}' - fs_sink.add(bund2) - - assert os.path.exists(os.path.join(FS_PATH, "campaign", "campaign--155155b6-1112-4fb0-111b-b111107ca70a" + ".json")) - - camp5_r = fs_source.get("campaign--155155b6-1112-4fb0-111b-b111107ca70a") - assert camp5_r.id == "campaign--155155b6-1112-4fb0-111b-b111107ca70a" - assert camp5_r.name == "Spartacus" - - # add list of objects - camp6 = Campaign(name="Comanche", - objective="US Midwest manufacturing firms, oil refineries, and businesses", - aliases=["Horse Warrior"]) - - camp7 = { - "name": "Napolean", - "type": "campaign", - "objective": "Central and Eastern Europe military commands and departments", - "aliases": ["The Frenchmen"], - "id": "campaign--122818b6-1112-4fb0-111b-b111107ca70a", - "created": "2017-05-31T21:31:53.197755Z" - } - - fs_sink.add([camp6, camp7]) - - assert os.path.exists(os.path.join(FS_PATH, "campaign", camp6.id + ".json")) - assert os.path.exists(os.path.join(FS_PATH, "campaign", "campaign--122818b6-1112-4fb0-111b-b111107ca70a" + ".json")) - - camp6_r = fs_source.get(camp6.id) - assert camp6_r.id == camp6.id - assert "Horse Warrior" in camp6_r.aliases - - camp7_r = fs_source.get(camp7["id"]) - assert camp7_r.id == camp7["id"] - assert "The Frenchmen" in camp7_r.aliases - - # remove all added objects - os.remove(os.path.join(FS_PATH, "campaign", camp1_r.id + ".json")) - os.remove(os.path.join(FS_PATH, "campaign", camp2_r.id + ".json")) - os.remove(os.path.join(FS_PATH, "campaign", camp3_r.id + ".json")) - os.remove(os.path.join(FS_PATH, "campaign", camp4_r.id + ".json")) - os.remove(os.path.join(FS_PATH, "campaign", camp5_r.id + ".json")) - os.remove(os.path.join(FS_PATH, "campaign", camp6_r.id + ".json")) - os.remove(os.path.join(FS_PATH, "campaign", camp7_r.id + ".json")) - - # remove campaign dir (that was added in course of testing) - os.rmdir(os.path.join(FS_PATH, "campaign")) - - -def test_filesystem_store(fs_store): - # get() - coa = fs_store.get("course-of-action--d9727aee-48b8-4fdb-89e2-4c49746ba4dd") - assert coa.id == "course-of-action--d9727aee-48b8-4fdb-89e2-4c49746ba4dd" - assert coa.type == "course-of-action" - - # all versions() - (note at this time, all_versions() is still not applicable to FileSystem, as only one version is ever stored) - rel = fs_store.all_versions("relationship--70dc6b5c-c524-429e-a6ab-0dd40f0482c1")[0] - assert rel.id == "relationship--70dc6b5c-c524-429e-a6ab-0dd40f0482c1" - assert rel.type == "relationship" - - # query() - tools = fs_store.query([Filter("labels", "in", "tool")]) - assert len(tools) == 2 - assert "tool--242f3da3-4425-4d11-8f5c-b842886da966" in [tool.id for tool in tools] - assert "tool--03342581-f790-4f03-ba41-e82e67392e23" in [tool.id for tool in tools] - - # add() - camp1 = Campaign(name="Great Heathen Army", - objective="Targeting the government of United Kingdom and insitutions affiliated with the Church Of England", - aliases=["Ragnar"]) - fs_store.add(camp1) - - camp1_r = fs_store.get(camp1.id) - assert camp1_r.id == camp1.id - assert camp1_r.name == camp1.name - - # remove - os.remove(os.path.join(FS_PATH, "campaign", camp1_r.id + ".json")) - - # remove campaign dir - os.rmdir(os.path.join(FS_PATH, "campaign")) - - -def test_filesystem_add_object_with_custom_property_in_bundle(fs_store): - bundle = Bundle() - fs_store.add(bundle) diff --git a/stix2/test/test_filesystem.py b/stix2/test/test_filesystem.py new file mode 100644 index 0000000..9ef40a6 --- /dev/null +++ b/stix2/test/test_filesystem.py @@ -0,0 +1,255 @@ +import os +import shutil + +import pytest + +from stix2 import (Bundle, Campaign, FileSystemSink, FileSystemSource, + FileSystemStore, Filter) + +FS_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), "stix2_data") + + +@pytest.fixture +def fs_store(): + # create + yield FileSystemStore(FS_PATH) + + # remove campaign dir + shutil.rmtree(os.path.join(FS_PATH, "campaign"), True) + + +@pytest.fixture +def fs_source(): + # create + fs = FileSystemSource(FS_PATH) + assert fs.stix_dir == FS_PATH + yield fs + + # remove campaign dir + shutil.rmtree(os.path.join(FS_PATH, "campaign"), True) + + +@pytest.fixture +def fs_sink(): + # create + fs = FileSystemSink(FS_PATH) + assert fs.stix_dir == FS_PATH + yield fs + + # remove campaign dir + shutil.rmtree(os.path.join(FS_PATH, "campaign"), True) + + +def test_filesytem_source_get_object(fs_source): + # get object + mal = fs_source.get("malware--6b616fc1-1505-48e3-8b2c-0d19337bff38") + assert mal.id == "malware--6b616fc1-1505-48e3-8b2c-0d19337bff38" + assert mal.name == "Rover" + + +def test_filesytem_source_all_versions(fs_source): + # all versions - (currently not a true all versions call as FileSystem cant have multiple versions) + id_ = fs_source.get("identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5") + assert id_.id == "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5" + assert id_.name == "The MITRE Corporation" + assert id_.type == "identity" + + +def test_filesytem_source_query_single(fs_source): + # query2 + is_2 = fs_source.query([Filter("external_references.external_id", '=', "T1027")]) + assert len(is_2) == 1 + + is_2 = is_2[0] + assert is_2.id == "attack-pattern--b3d682b6-98f2-4fb0-aa3b-b4df007ca70a" + assert is_2.type == "attack-pattern" + + +def test_filesytem_source_query_multiple(fs_source): + # query + intrusion_sets = fs_source.query([Filter("type", '=', "intrusion-set")]) + assert len(intrusion_sets) == 2 + assert "intrusion-set--a653431d-6a5e-4600-8ad3-609b5af57064" in [is_.id for is_ in intrusion_sets] + assert "intrusion-set--f3bdec95-3d62-42d9-a840-29630f6cdc1a" in [is_.id for is_ in intrusion_sets] + + is_1 = [is_ for is_ in intrusion_sets if is_.id == "intrusion-set--f3bdec95-3d62-42d9-a840-29630f6cdc1a"][0] + assert "DragonOK" in is_1.aliases + assert len(is_1.external_references) == 4 + + +def test_filesystem_sink_add_python_stix_object(fs_sink, fs_source): + # add python stix object + camp1 = Campaign(name="Hannibal", + objective="Targeting Italian and Spanish Diplomat internet accounts", + aliases=["War Elephant"]) + + fs_sink.add(camp1) + + assert os.path.exists(os.path.join(FS_PATH, "campaign", camp1.id + ".json")) + + camp1_r = fs_source.get(camp1.id) + assert camp1_r.id == camp1.id + assert camp1_r.name == "Hannibal" + assert "War Elephant" in camp1_r.aliases + + os.remove(os.path.join(FS_PATH, "campaign", camp1_r.id + ".json")) + + +def test_filesystem_sink_add_stix_object_dict(fs_sink, fs_source): + # add stix object dict + camp2 = { + "name": "Aurelius", + "type": "campaign", + "objective": "German and French Intelligence Services", + "aliases": ["Purple Robes"], + "id": "campaign--111111b6-1112-4fb0-111b-b111107ca70a", + "created": "2017-05-31T21:31:53.197755Z" + } + + fs_sink.add(camp2) + + assert os.path.exists(os.path.join(FS_PATH, "campaign", camp2["id"] + ".json")) + + camp2_r = fs_source.get(camp2["id"]) + assert camp2_r.id == camp2["id"] + assert camp2_r.name == camp2["name"] + assert "Purple Robes" in camp2_r.aliases + + os.remove(os.path.join(FS_PATH, "campaign", camp2_r.id + ".json")) + + +def test_filesystem_sink_add_stix_bundle_dict(fs_sink, fs_source): + # add stix bundle dict + bund = { + "type": "bundle", + "id": "bundle--112211b6-1112-4fb0-111b-b111107ca70a", + "spec_version": "2.0", + "objects": [ + { + "name": "Atilla", + "type": "campaign", + "objective": "Bulgarian, Albanian and Romanian Intelligence Services", + "aliases": ["Huns"], + "id": "campaign--133111b6-1112-4fb0-111b-b111107ca70a", + "created": "2017-05-31T21:31:53.197755Z" + } + ] + } + + fs_sink.add(bund) + + assert os.path.exists(os.path.join(FS_PATH, "campaign", bund["objects"][0]["id"] + ".json")) + + camp3_r = fs_source.get(bund["objects"][0]["id"]) + assert camp3_r.id == bund["objects"][0]["id"] + assert camp3_r.name == bund["objects"][0]["name"] + assert "Huns" in camp3_r.aliases + + os.remove(os.path.join(FS_PATH, "campaign", camp3_r.id + ".json")) + + +def test_filesystem_sink_add_json_stix_object(fs_sink, fs_source): + # add json-encoded stix obj + camp4 = '{"type": "campaign", "id":"campaign--144111b6-1112-4fb0-111b-b111107ca70a",'\ + ' "created":"2017-05-31T21:31:53.197755Z", "name": "Ghengis Khan", "objective": "China and Russian infrastructure"}' + + fs_sink.add(camp4) + + assert os.path.exists(os.path.join(FS_PATH, "campaign", "campaign--144111b6-1112-4fb0-111b-b111107ca70a" + ".json")) + + camp4_r = fs_source.get("campaign--144111b6-1112-4fb0-111b-b111107ca70a") + assert camp4_r.id == "campaign--144111b6-1112-4fb0-111b-b111107ca70a" + assert camp4_r.name == "Ghengis Khan" + + os.remove(os.path.join(FS_PATH, "campaign", camp4_r.id + ".json")) + + +def test_filesystem_sink_json_stix_bundle(fs_sink, fs_source): + # add json-encoded stix bundle + bund2 = '{"type": "bundle", "id": "bundle--332211b6-1132-4fb0-111b-b111107ca70a",' \ + ' "spec_version": "2.0", "objects": [{"type": "campaign", "id": "campaign--155155b6-1112-4fb0-111b-b111107ca70a",' \ + ' "created":"2017-05-31T21:31:53.197755Z", "name": "Spartacus", "objective": "Oppressive regimes of Africa and Middle East"}]}' + fs_sink.add(bund2) + + assert os.path.exists(os.path.join(FS_PATH, "campaign", "campaign--155155b6-1112-4fb0-111b-b111107ca70a" + ".json")) + + camp5_r = fs_source.get("campaign--155155b6-1112-4fb0-111b-b111107ca70a") + assert camp5_r.id == "campaign--155155b6-1112-4fb0-111b-b111107ca70a" + assert camp5_r.name == "Spartacus" + + os.remove(os.path.join(FS_PATH, "campaign", camp5_r.id + ".json")) + + +def test_filesystem_sink_add_objects_list(fs_sink, fs_source): + # add list of objects + camp6 = Campaign(name="Comanche", + objective="US Midwest manufacturing firms, oil refineries, and businesses", + aliases=["Horse Warrior"]) + + camp7 = { + "name": "Napolean", + "type": "campaign", + "objective": "Central and Eastern Europe military commands and departments", + "aliases": ["The Frenchmen"], + "id": "campaign--122818b6-1112-4fb0-111b-b111107ca70a", + "created": "2017-05-31T21:31:53.197755Z" + } + + fs_sink.add([camp6, camp7]) + + assert os.path.exists(os.path.join(FS_PATH, "campaign", camp6.id + ".json")) + assert os.path.exists(os.path.join(FS_PATH, "campaign", "campaign--122818b6-1112-4fb0-111b-b111107ca70a" + ".json")) + + camp6_r = fs_source.get(camp6.id) + assert camp6_r.id == camp6.id + assert "Horse Warrior" in camp6_r.aliases + + camp7_r = fs_source.get(camp7["id"]) + assert camp7_r.id == camp7["id"] + assert "The Frenchmen" in camp7_r.aliases + + # remove all added objects + os.remove(os.path.join(FS_PATH, "campaign", camp6_r.id + ".json")) + os.remove(os.path.join(FS_PATH, "campaign", camp7_r.id + ".json")) + + +def test_filesystem_store_get(fs_store): + # get() + coa = fs_store.get("course-of-action--d9727aee-48b8-4fdb-89e2-4c49746ba4dd") + assert coa.id == "course-of-action--d9727aee-48b8-4fdb-89e2-4c49746ba4dd" + assert coa.type == "course-of-action" + + +def test_filesystem_store_all_versions(fs_store): + # all versions() - (note at this time, all_versions() is still not applicable to FileSystem, as only one version is ever stored) + rel = fs_store.all_versions("relationship--70dc6b5c-c524-429e-a6ab-0dd40f0482c1")[0] + assert rel.id == "relationship--70dc6b5c-c524-429e-a6ab-0dd40f0482c1" + assert rel.type == "relationship" + + +def test_filesystem_store_query(fs_store): + # query() + tools = fs_store.query([Filter("labels", "in", "tool")]) + assert len(tools) == 2 + assert "tool--242f3da3-4425-4d11-8f5c-b842886da966" in [tool.id for tool in tools] + assert "tool--03342581-f790-4f03-ba41-e82e67392e23" in [tool.id for tool in tools] + + +def test_filesystem_store_add(fs_store): + # add() + camp1 = Campaign(name="Great Heathen Army", + objective="Targeting the government of United Kingdom and insitutions affiliated with the Church Of England", + aliases=["Ragnar"]) + fs_store.add(camp1) + + camp1_r = fs_store.get(camp1.id) + assert camp1_r.id == camp1.id + assert camp1_r.name == camp1.name + + # remove + os.remove(os.path.join(FS_PATH, "campaign", camp1_r.id + ".json")) + + +def test_filesystem_add_object_with_custom_property_in_bundle(fs_store): + bundle = Bundle() + fs_store.add(bundle) From e1d8c2872ef5905f6b08945c1c1ca6093b1ac457 Mon Sep 17 00:00:00 2001 From: Chris Lenk Date: Wed, 18 Oct 2017 15:42:21 -0400 Subject: [PATCH 05/19] Don't Bundlify data in FileSystemStore Don't wrap objects in a Bundle when adding them to a FileSystemStore, but still support getting objects from FileSystemStore that were saved in a bundle. Also: - Add option to allow custom content in FileSystemStore - Simplify an if statement - Improve FileSystem docstrings - Remove an unnecessary parse() call in FileSystemSource.get() --- stix2/sources/__init__.py | 34 +++--- stix2/sources/filesystem.py | 101 +++++++++--------- ...-d9727aee-48b8-4fdb-89e2-4c49746ba4dd.json | 21 ++-- stix2/test/test_filesystem.py | 60 ++++++++++- 4 files changed, 127 insertions(+), 89 deletions(-) diff --git a/stix2/sources/__init__.py b/stix2/sources/__init__.py index 9d46ba9..9c5510e 100644 --- a/stix2/sources/__init__.py +++ b/stix2/sources/__init__.py @@ -44,7 +44,7 @@ class DataStore(object): self.source = source self.sink = sink - def get(self, stix_id): + def get(self, stix_id, allow_custom=False): """Retrieve the most recent version of a single STIX object by ID. Translate get() call to the appropriate DataSource call. @@ -57,9 +57,9 @@ class DataStore(object): object specified by the "id". """ - return self.source.get(stix_id) + return self.source.get(stix_id, allow_custom=allow_custom) - def all_versions(self, stix_id): + def all_versions(self, stix_id, allow_custom=False): """Retrieve all versions of a single STIX object by ID. Implement: Translate all_versions() call to the appropriate DataSource call @@ -71,9 +71,9 @@ class DataStore(object): stix_objs (list): a list of STIX objects """ - return self.source.all_versions(stix_id) + return self.source.all_versions(stix_id, allow_custom=allow_custom) - def query(self, query): + def query(self, query, allow_custom=False): """Retrieve STIX objects matching a set of filters. Implement: Specific data source API calls, processing, @@ -89,7 +89,7 @@ class DataStore(object): """ return self.source.query(query=query) - def add(self, stix_objs): + def add(self, stix_objs, allow_custom=False): """Store STIX objects. Translates add() to the appropriate DataSink call. @@ -97,7 +97,7 @@ class DataStore(object): Args: stix_objs (list): a list of STIX objects """ - return self.sink.add(stix_objs) + return self.sink.add(stix_objs, allow_custom=allow_custom) class DataSink(object): @@ -111,7 +111,7 @@ class DataSink(object): def __init__(self): self.id = make_id() - def add(self, stix_objs): + def add(self, stix_objs, allow_custom=False): """Store STIX objects. Implement: Specific data sink API calls, processing, @@ -139,7 +139,7 @@ class DataSource(object): self.id = make_id() self.filters = set() - def get(self, stix_id, _composite_filters=None): + def get(self, stix_id, _composite_filters=None, allow_custom=False): """ Implement: Specific data source API calls, processing, functionality required for retrieving data from the data source @@ -158,7 +158,7 @@ class DataSource(object): """ raise NotImplementedError() - def all_versions(self, stix_id, _composite_filters=None): + def all_versions(self, stix_id, _composite_filters=None, allow_custom=False): """ Implement: Similar to get() except returns list of all object versions of the specified "id". In addition, implement the specific data @@ -179,7 +179,7 @@ class DataSource(object): """ raise NotImplementedError() - def query(self, query, _composite_filters=None): + def query(self, query, _composite_filters=None, allow_custom=False): """ Implement:Implement the specific data source API calls, processing, functionality required for retrieving query from the data source @@ -224,7 +224,7 @@ class CompositeDataSource(DataSource): super(CompositeDataSource, self).__init__() self.data_sources = [] - def get(self, stix_id, _composite_filters=None): + def get(self, stix_id, _composite_filters=None, allow_custom=False): """Retrieve STIX object by STIX ID Federated retrieve method, iterates through all DataSources @@ -259,7 +259,7 @@ class CompositeDataSource(DataSource): # for every configured Data Source, call its retrieve handler for ds in self.data_sources: - data = ds.get(stix_id=stix_id, _composite_filters=all_filters) + data = ds.get(stix_id=stix_id, _composite_filters=all_filters, allow_custom=allow_custom) if data: all_data.append(data) @@ -272,7 +272,7 @@ class CompositeDataSource(DataSource): return stix_obj - def all_versions(self, stix_id, _composite_filters=None): + def all_versions(self, stix_id, _composite_filters=None, allow_custom=False): """Retrieve STIX objects by STIX ID Federated all_versions retrieve method - iterates through all DataSources @@ -305,7 +305,7 @@ class CompositeDataSource(DataSource): # retrieve STIX objects from all configured data sources for ds in self.data_sources: - data = ds.all_versions(stix_id=stix_id, _composite_filters=all_filters) + data = ds.all_versions(stix_id=stix_id, _composite_filters=all_filters, allow_custom=allow_custom) all_data.extend(data) # remove exact duplicates (where duplicates are STIX 2.0 objects @@ -315,7 +315,7 @@ class CompositeDataSource(DataSource): return all_data - def query(self, query=None, _composite_filters=None): + def query(self, query=None, _composite_filters=None, allow_custom=False): """Retrieve STIX objects that match query Federate the query to all DataSources attached to the @@ -351,7 +351,7 @@ class CompositeDataSource(DataSource): # federate query to all attached data sources, # pass composite filters to id for ds in self.data_sources: - data = ds.query(query=query, _composite_filters=all_filters) + data = ds.query(query=query, _composite_filters=all_filters, allow_custom=allow_custom) all_data.extend(data) # remove exact duplicates (where duplicates are STIX 2.0 diff --git a/stix2/sources/filesystem.py b/stix2/sources/filesystem.py index f11df65..1dcf85b 100644 --- a/stix2/sources/filesystem.py +++ b/stix2/sources/filesystem.py @@ -18,9 +18,8 @@ from stix2.utils import deduplicate class FileSystemStore(DataStore): - """FileSystemStore + """Interface to a file directory of STIX objects. - Provides an interface to an file directory of STIX objects. FileSystemStore is a wrapper around a paired FileSystemSink and FileSystemSource. @@ -40,10 +39,8 @@ class FileSystemStore(DataStore): class FileSystemSink(DataSink): - """FileSystemSink - - Provides an interface for adding/pushing STIX objects - to file directory of STIX objects. + """Interface for adding/pushing STIX objects to file directory of STIX + objects. Can be paired with a FileSystemSource, together as the two components of a FileSystemStore. @@ -63,15 +60,19 @@ class FileSystemSink(DataSink): def stix_dir(self): return self._stix_dir - def add(self, stix_data=None): - """add STIX objects to file directory + def add(self, stix_data=None, allow_custom=False): + """Add STIX objects to file directory. Args: stix_data (STIX object OR dict OR str OR list): valid STIX 2.0 content - in a STIX object(or list of), dict (or list of), or a STIX 2.0 - json encoded string + in a STIX object (or list of), dict (or list of), or a STIX 2.0 + json encoded string. + + Note: + ``stix_data`` can be a Bundle object, but each object in it will be + saved separately; you will be able to retrieve any of the objects + the Bundle contained, but not the Bundle itself. - TODO: Bundlify STIX content or no? When dumping to disk. """ def _check_path_and_write(stix_dir, stix_obj): path = os.path.join(stix_dir, stix_obj["type"], stix_obj["id"] + ".json") @@ -80,45 +81,41 @@ class FileSystemSink(DataSink): os.makedirs(os.path.dirname(path)) with open(path, "w") as f: - # Bundle() can take dict or STIX obj as argument - f.write(str(Bundle(stix_obj))) + f.write(str(stix_obj)) if isinstance(stix_data, (STIXDomainObject, STIXRelationshipObject, MarkingDefinition)): # adding python STIX object _check_path_and_write(self._stix_dir, stix_data) - elif isinstance(stix_data, dict): + elif isinstance(stix_data, (str, dict)): + stix_data = parse(stix_data, allow_custom) if stix_data["type"] == "bundle": - # adding json-formatted Bundle - extracting STIX objects - for stix_obj in stix_data["objects"]: + # extract STIX objects + for stix_obj in stix_data.get("objects", []): self.add(stix_obj) else: # adding json-formatted STIX _check_path_and_write(self._stix_dir, stix_data) - elif isinstance(stix_data, (str, Bundle)): - # adding json encoded string of STIX content - stix_data = parse(stix_data) - if stix_data["type"] == "bundle": - for stix_obj in stix_data.get("objects", []): - self.add(stix_obj) - else: - self.add(stix_data) + elif isinstance(stix_data, Bundle): + # recursively add individual STIX objects + for stix_obj in stix_data.get("objects", []): + self.add(stix_obj) elif isinstance(stix_data, list): - # if list, recurse call on individual STIX objects + # recursively add individual STIX objects for stix_obj in stix_data: self.add(stix_obj) else: - raise ValueError("stix_data must be a STIX object(or list of), json formatted STIX(or list of) or a json formatted STIX bundle") + raise ValueError("stix_data must be a STIX object (or list of), " + "json formatted STIX (or list of), " + "or a json formatted STIX bundle") class FileSystemSource(DataSource): - """FileSystemSource - - Provides an interface for searching/retrieving - STIX objects from a STIX object file directory. + """Interface for searching/retrieving STIX objects from a STIX object file + directory. Can be paired with a FileSystemSink, together as the two components of a FileSystemStore. @@ -138,8 +135,8 @@ class FileSystemSource(DataSource): def stix_dir(self): return self._stix_dir - def get(self, stix_id, _composite_filters=None): - """retrieve STIX object from file directory via STIX ID + def get(self, stix_id, _composite_filters=None, allow_custom=False): + """Retrieve STIX object from file directory via STIX ID. Args: stix_id (str): The STIX ID of the STIX object to be retrieved. @@ -155,18 +152,17 @@ class FileSystemSource(DataSource): """ query = [Filter("id", "=", stix_id)] - all_data = self.query(query=query, _composite_filters=_composite_filters) + all_data = self.query(query=query, _composite_filters=_composite_filters, allow_custom=allow_custom) if all_data: stix_obj = sorted(all_data, key=lambda k: k['modified'])[0] - stix_obj = parse(stix_obj) else: stix_obj = None return stix_obj - def all_versions(self, stix_id, _composite_filters=None): - """retrieve STIX object from file directory via STIX ID, all versions + def all_versions(self, stix_id, _composite_filters=None, allow_custom=False): + """Retrieve STIX object from file directory via STIX ID, all versions. Note: Since FileSystem sources/sinks don't handle multiple versions of a STIX object, this operation is unnecessary. Pass call to get(). @@ -181,11 +177,12 @@ class FileSystemSource(DataSource): (list): of STIX objects that has the supplied STIX ID. The STIX objects are loaded from their json files, parsed into a python STIX objects and then returned - """ - return [self.get(stix_id=stix_id, _composite_filters=_composite_filters)] - def query(self, query=None, _composite_filters=None): - """search and retrieve STIX objects based on the complete query + """ + return [self.get(stix_id=stix_id, _composite_filters=_composite_filters, allow_custom=allow_custom)] + + def query(self, query=None, _composite_filters=None, allow_custom=False): + """Search and retrieve STIX objects based on the complete query. A "complete query" includes the filters from the query, the filters attached to MemorySource, and any filters passed from a @@ -275,34 +272,32 @@ class FileSystemSource(DataSource): for path in include_paths: for root, dirs, files in os.walk(path): for file_ in files: - if id_: - if id_ == file_.split(".")[0]: - # since ID is specified in one of filters, can evaluate against filename first without loading - stix_obj = json.load(open(os.path.join(root, file_)))["objects"][0] - # check against other filters, add if match - all_data.extend(apply_common_filters([stix_obj], query)) - else: + if not id_ or id_ == file_.split(".")[0]: # have to load into memory regardless to evaluate other filters - stix_obj = json.load(open(os.path.join(root, file_)))["objects"][0] + stix_obj = json.load(open(os.path.join(root, file_))) + if stix_obj.get('type', '') == 'bundle': + stix_obj = stix_obj['objects'][0] + # check against other filters, add if match all_data.extend(apply_common_filters([stix_obj], query)) all_data = deduplicate(all_data) # parse python STIX objects from the STIX object dicts - stix_objs = [parse(stix_obj_dict) for stix_obj_dict in all_data] + stix_objs = [parse(stix_obj_dict, allow_custom) for stix_obj_dict in all_data] return stix_objs def _parse_file_filters(self, query): - """utility method to extract STIX common filters - that can used to possibly speed up querying STIX objects - from the file system + """Extract STIX common filters. + + Possibly speeds up querying STIX objects from the file system. Extracts filters that are for the "id" and "type" field of a STIX object. As the file directory is organized by STIX object type with filenames that are equivalent to the STIX object ID, these filters can be used first to reduce the - search space of a FileSystemStore(or FileSystemSink) + search space of a FileSystemStore (or FileSystemSink). + """ file_filters = set() for filter_ in query: diff --git a/stix2/test/stix2_data/course-of-action/course-of-action--d9727aee-48b8-4fdb-89e2-4c49746ba4dd.json b/stix2/test/stix2_data/course-of-action/course-of-action--d9727aee-48b8-4fdb-89e2-4c49746ba4dd.json index 5bfb8bb..cb9cfe2 100755 --- a/stix2/test/stix2_data/course-of-action/course-of-action--d9727aee-48b8-4fdb-89e2-4c49746ba4dd.json +++ b/stix2/test/stix2_data/course-of-action/course-of-action--d9727aee-48b8-4fdb-89e2-4c49746ba4dd.json @@ -1,16 +1,9 @@ { - "id": "bundle--2ed6ab6a-ca68-414f-8493-e4db8b75dd51", - "objects": [ - { - "created": "2017-05-31T21:30:41.022744Z", - "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", - "description": "Identify unnecessary system utilities or potentially malicious software that may be used to collect data from a network share, and audit and/or block them by using whitelisting[[CiteRef::Beechey 2010]] tools, like AppLocker,[[CiteRef::Windows Commands JPCERT]][[CiteRef::NSA MS AppLocker]] or Software Restriction Policies[[CiteRef::Corio 2008]] where appropriate.[[CiteRef::TechNet Applocker vs SRP]]", - "id": "course-of-action--d9727aee-48b8-4fdb-89e2-4c49746ba4dd", - "modified": "2017-05-31T21:30:41.022744Z", - "name": "Data from Network Shared Drive Mitigation", - "type": "course-of-action" - } - ], - "spec_version": "2.0", - "type": "bundle" + "created": "2017-05-31T21:30:41.022744Z", + "created_by_ref": "identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5", + "description": "Identify unnecessary system utilities or potentially malicious software that may be used to collect data from a network share, and audit and/or block them by using whitelisting[[CiteRef::Beechey 2010]] tools, like AppLocker,[[CiteRef::Windows Commands JPCERT]][[CiteRef::NSA MS AppLocker]] or Software Restriction Policies[[CiteRef::Corio 2008]] where appropriate.[[CiteRef::TechNet Applocker vs SRP]]", + "id": "course-of-action--d9727aee-48b8-4fdb-89e2-4c49746ba4dd", + "modified": "2017-05-31T21:30:41.022744Z", + "name": "Data from Network Shared Drive Mitigation", + "type": "course-of-action" } \ No newline at end of file diff --git a/stix2/test/test_filesystem.py b/stix2/test/test_filesystem.py index 9ef40a6..8b9aa22 100644 --- a/stix2/test/test_filesystem.py +++ b/stix2/test/test_filesystem.py @@ -3,8 +3,8 @@ import shutil import pytest -from stix2 import (Bundle, Campaign, FileSystemSink, FileSystemSource, - FileSystemStore, Filter) +from stix2 import (Bundle, Campaign, CustomObject, FileSystemSink, + FileSystemSource, FileSystemStore, Filter, properties) FS_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), "stix2_data") @@ -213,8 +213,13 @@ def test_filesystem_sink_add_objects_list(fs_sink, fs_source): os.remove(os.path.join(FS_PATH, "campaign", camp7_r.id + ".json")) -def test_filesystem_store_get(fs_store): - # get() +def test_filesystem_store_get_stored_as_bundle(fs_store): + coa = fs_store.get("course-of-action--95ddb356-7ba0-4bd9-a889-247262b8946f") + assert coa.id == "course-of-action--95ddb356-7ba0-4bd9-a889-247262b8946f" + assert coa.type == "course-of-action" + + +def test_filesystem_store_get_stored_as_object(fs_store): coa = fs_store.get("course-of-action--d9727aee-48b8-4fdb-89e2-4c49746ba4dd") assert coa.id == "course-of-action--d9727aee-48b8-4fdb-89e2-4c49746ba4dd" assert coa.type == "course-of-action" @@ -250,6 +255,51 @@ def test_filesystem_store_add(fs_store): os.remove(os.path.join(FS_PATH, "campaign", camp1_r.id + ".json")) -def test_filesystem_add_object_with_custom_property_in_bundle(fs_store): +def test_filesystem_add_bundle_object(fs_store): bundle = Bundle() fs_store.add(bundle) + + +def test_filesystem_object_with_custom_property(fs_store): + camp = Campaign(name="Scipio Africanus", + objective="Defeat the Carthaginians", + x_empire="Roman", + allow_custom=True) + + fs_store.add(camp, True) + + camp_r = fs_store.get(camp.id, True) + assert camp_r.id == camp.id + assert camp_r.x_empire == camp.x_empire + + +def test_filesystem_object_with_custom_property_in_bundle(fs_store): + camp = Campaign(name="Scipio Africanus", + objective="Defeat the Carthaginians", + x_empire="Roman", + allow_custom=True) + + bundle = Bundle(camp, allow_custom=True) + fs_store.add(bundle, True) + + camp_r = fs_store.get(camp.id, True) + assert camp_r.id == camp.id + assert camp_r.x_empire == camp.x_empire + + +def test_filesystem_custom_object(fs_store): + @CustomObject('x-new-obj', [ + ('property1', properties.StringProperty(required=True)), + ]) + class NewObj(): + pass + + newobj = NewObj(property1='something') + fs_store.add(newobj, True) + + newobj_r = fs_store.get(newobj.id, True) + assert newobj_r.id == newobj.id + assert newobj_r.property1 == 'something' + + # remove dir + shutil.rmtree(os.path.join(FS_PATH, "x-new-obj"), True) From c6d5eee0839a51d21c3c171c88f4be59a88be6aa Mon Sep 17 00:00:00 2001 From: Chris Lenk Date: Wed, 18 Oct 2017 18:31:46 -0400 Subject: [PATCH 06/19] Separate out Memory datatstore tests Makes sure custom content can be added to a MemoryStore. --- stix2/sources/memory.py | 86 ++++++------ stix2/test/test_data_sources.py | 24 +--- stix2/test/test_memory.py | 237 ++++++++++++++++++++++++++++++++ 3 files changed, 281 insertions(+), 66 deletions(-) create mode 100644 stix2/test/test_memory.py diff --git a/stix2/sources/memory.py b/stix2/sources/memory.py index 0d5901e..1b738ab 100644 --- a/stix2/sources/memory.py +++ b/stix2/sources/memory.py @@ -24,8 +24,8 @@ from stix2.sources import DataSink, DataSource, DataStore from stix2.sources.filters import Filter, apply_common_filters -def _add(store, stix_data=None): - """Adds STIX objects to MemoryStore/Sink. +def _add(store, stix_data=None, allow_custom=False): + """Add STIX objects to MemoryStore/Sink. Adds STIX objects to an in-memory dictionary for fast lookup. Recursive function, breaks down STIX Bundles and lists. @@ -41,35 +41,35 @@ def _add(store, stix_data=None): elif isinstance(stix_data, dict): if stix_data["type"] == "bundle": # adding a json bundle - so just grab STIX objects - for stix_obj in stix_data["objects"]: - _add(store, stix_obj) + for stix_obj in stix_data.get("objects", []): + _add(store, stix_obj, allow_custom=allow_custom) else: # adding a json STIX object store._data[stix_data["id"]] = stix_data elif isinstance(stix_data, str): # adding json encoded string of STIX content - stix_data = parse(stix_data) + stix_data = parse(stix_data, allow_custom=allow_custom) if stix_data["type"] == "bundle": # recurse on each STIX object in bundle - for stix_obj in stix_data: - _add(store, stix_obj) + for stix_obj in stix_data.get("objects", []): + _add(store, stix_obj, allow_custom=allow_custom) else: _add(store, stix_data) elif isinstance(stix_data, list): # STIX objects are in a list- recurse on each object for stix_obj in stix_data: - _add(store, stix_obj) + _add(store, stix_obj, allow_custom=allow_custom) else: raise TypeError("stix_data must be as STIX object(or list of),json formatted STIX (or list of), or a json formatted STIX bundle") class MemoryStore(DataStore): - """Provides an interface to an in-memory dictionary - of STIX objects. MemoryStore is a wrapper around a paired - MemorySink and MemorySource + """Interface to an in-memory dictionary of STIX objects. + + MemoryStore is a wrapper around a paired MemorySink and MemorySource. Note: It doesn't make sense to create a MemoryStore by passing in existing MemorySource and MemorySink because there could @@ -87,26 +87,25 @@ class MemoryStore(DataStore): """ - def __init__(self, stix_data=None): + def __init__(self, stix_data=None, allow_custom=False): super(MemoryStore, self).__init__() self._data = {} if stix_data: - _add(self, stix_data) + _add(self, stix_data, allow_custom=allow_custom) - self.source = MemorySource(stix_data=self._data, _store=True) - self.sink = MemorySink(stix_data=self._data, _store=True) + self.source = MemorySource(stix_data=self._data, _store=True, allow_custom=allow_custom) + self.sink = MemorySink(stix_data=self._data, _store=True, allow_custom=allow_custom) - def save_to_file(self, file_path): - return self.sink.save_to_file(file_path=file_path) + def save_to_file(self, file_path, allow_custom=False): + return self.sink.save_to_file(file_path=file_path, allow_custom=allow_custom) - def load_from_file(self, file_path): - return self.source.load_from_file(file_path=file_path) + def load_from_file(self, file_path, allow_custom=False): + return self.source.load_from_file(file_path=file_path, allow_custom=allow_custom) class MemorySink(DataSink): - """Provides an interface for adding/pushing STIX objects - to an in-memory dictionary. + """Interface for adding/pushing STIX objects to an in-memory dictionary. Designed to be paired with a MemorySource, together as the two components of a MemoryStore. @@ -125,24 +124,24 @@ class MemorySink(DataSink): a MemorySource """ - def __init__(self, stix_data=None, _store=False): + def __init__(self, stix_data=None, _store=False, allow_custom=False): super(MemorySink, self).__init__() self._data = {} if _store: self._data = stix_data elif stix_data: - _add(self, stix_data) + _add(self, stix_data, allow_custom=allow_custom) - def add(self, stix_data): + def add(self, stix_data, allow_custom=False): """add STIX objects to in-memory dictionary maintained by the MemorySink (MemoryStore) see "_add()" for args documentation """ - _add(self, stix_data) + _add(self, stix_data, allow_custom=allow_custom) - def save_to_file(self, file_path): + def save_to_file(self, file_path, allow_custom=False): """write SITX objects in in-memory dictionary to json file, as a STIX Bundle Args: @@ -153,12 +152,12 @@ class MemorySink(DataSink): if not os.path.exists(os.path.dirname(file_path)): os.makedirs(os.path.dirname(file_path)) with open(file_path, "w") as f: - f.write(str(Bundle(self._data.values()))) + f.write(str(Bundle(self._data.values(), allow_custom=allow_custom))) class MemorySource(DataSource): - """Provides an interface for searching/retrieving - STIX objects from an in-memory dictionary. + """Interface for searching/retrieving STIX objects from an in-memory + dictionary. Designed to be paired with a MemorySink, together as the two components of a MemoryStore. @@ -177,17 +176,17 @@ class MemorySource(DataSource): a MemorySink """ - def __init__(self, stix_data=None, _store=False): + def __init__(self, stix_data=None, _store=False, allow_custom=False): super(MemorySource, self).__init__() self._data = {} if _store: self._data = stix_data elif stix_data: - _add(self, stix_data) + _add(self, stix_data, allow_custom=allow_custom) - def get(self, stix_id, _composite_filters=None): - """retrieve STIX object from in-memory dict via STIX ID + def get(self, stix_id, _composite_filters=None, allow_custom=False): + """Retrieve STIX object from in-memory dict via STIX ID. Args: stix_id (str): The STIX ID of the STIX object to be retrieved. @@ -200,8 +199,8 @@ class MemorySource(DataSource): ID. As the MemoryStore(i.e. MemorySink) adds STIX objects to memory as they are supplied (either as python dictionary or STIX object), it is returned in the same form as it as added - """ + """ if _composite_filters is None: # if get call is only based on 'id', no need to search, just retrieve from dict try: @@ -213,15 +212,15 @@ class MemorySource(DataSource): # if there are filters from the composite level, process full query query = [Filter("id", "=", stix_id)] - all_data = self.query(query=query, _composite_filters=_composite_filters) + all_data = self.query(query=query, _composite_filters=_composite_filters, allow_custom=allow_custom) # reduce to most recent version stix_obj = sorted(all_data, key=lambda k: k['modified'])[0] return stix_obj - def all_versions(self, stix_id, _composite_filters=None): - """retrieve STIX objects from in-memory dict via STIX ID, all versions of it + def all_versions(self, stix_id, _composite_filters=None, allow_custom=False): + """Retrieve STIX objects from in-memory dict via STIX ID, all versions of it Note: Since Memory sources/sinks don't handle multiple versions of a STIX object, this operation is unnecessary. Translate call to get(). @@ -239,10 +238,10 @@ class MemorySource(DataSource): is returned in the same form as it as added """ - return [self.get(stix_id=stix_id, _composite_filters=_composite_filters)] + return [self.get(stix_id=stix_id, _composite_filters=_composite_filters, allow_custom=allow_custom)] - def query(self, query=None, _composite_filters=None): - """search and retrieve STIX objects based on the complete query + def query(self, query=None, _composite_filters=None, allow_custom=False): + """Search and retrieve STIX objects based on the complete query. A "complete query" includes the filters from the query, the filters attached to MemorySource, and any filters passed from a @@ -281,15 +280,16 @@ class MemorySource(DataSource): return all_data - def load_from_file(self, file_path): - """load STIX data from json file + def load_from_file(self, file_path, allow_custom=False): + """Load STIX data from json file. File format is expected to be a single json STIX object or json STIX bundle Args: file_path (str): file path to load STIX data from + """ file_path = os.path.abspath(file_path) stix_data = json.load(open(file_path, "r")) - _add(self, stix_data) + _add(self, stix_data, allow_custom=allow_custom) diff --git a/stix2/test/test_data_sources.py b/stix2/test/test_data_sources.py index d7fd576..6f47de8 100644 --- a/stix2/test/test_data_sources.py +++ b/stix2/test/test_data_sources.py @@ -1,7 +1,7 @@ import pytest from taxii2client import Collection -from stix2 import Filter, MemorySource, MemoryStore +from stix2 import Filter, MemorySource from stix2.sources import (CompositeDataSource, DataSink, DataSource, DataStore, make_id, taxii) from stix2.sources.filters import apply_common_filters @@ -144,28 +144,6 @@ def test_ds_abstract_class_smoke(): ds3.query([Filter("id", "=", "malware--fdd60b30-b67c-11e3-b0b9-f01faf20d111")]) -def test_memory_store_smoke(): - # Initialize MemoryStore with dict - ms = MemoryStore(STIX_OBJS1) - - # Add item to sink - ms.add(dict(id="bundle--%s" % make_id(), - objects=STIX_OBJS2, - spec_version="2.0", - type="bundle")) - - resp = ms.all_versions("indicator--d81f86b9-975b-bc0b-775e-810c5ad45a4f") - assert len(resp) == 1 - - resp = ms.get("indicator--d81f86b8-975b-bc0b-775e-810c5ad45a4f") - assert resp["id"] == "indicator--d81f86b8-975b-bc0b-775e-810c5ad45a4f" - - query = [Filter('type', '=', 'malware')] - - resp = ms.query(query) - assert len(resp) == 0 - - def test_ds_taxii(collection): ds = taxii.TAXIICollectionSource(collection) assert ds.collection is not None diff --git a/stix2/test/test_memory.py b/stix2/test/test_memory.py new file mode 100644 index 0000000..e8ba56b --- /dev/null +++ b/stix2/test/test_memory.py @@ -0,0 +1,237 @@ +import pytest + +from stix2 import (Bundle, Campaign, CustomObject, Filter, MemorySource, + MemoryStore, properties) +from stix2.sources import make_id + +IND1 = { + "created": "2017-01-27T13:49:53.935Z", + "id": "indicator--d81f86b9-975b-bc0b-775e-810c5ad45a4f", + "labels": [ + "url-watchlist" + ], + "modified": "2017-01-27T13:49:53.935Z", + "name": "Malicious site hosting downloader", + "pattern": "[url:value = 'http://x4z9arb.cn/4712']", + "type": "indicator", + "valid_from": "2017-01-27T13:49:53.935382Z" +} +IND2 = { + "created": "2017-01-27T13:49:53.935Z", + "id": "indicator--d81f86b9-975b-bc0b-775e-810c5ad45a4f", + "labels": [ + "url-watchlist" + ], + "modified": "2017-01-27T13:49:53.935Z", + "name": "Malicious site hosting downloader", + "pattern": "[url:value = 'http://x4z9arb.cn/4712']", + "type": "indicator", + "valid_from": "2017-01-27T13:49:53.935382Z" +} +IND3 = { + "created": "2017-01-27T13:49:53.935Z", + "id": "indicator--d81f86b9-975b-bc0b-775e-810c5ad45a4f", + "labels": [ + "url-watchlist" + ], + "modified": "2017-01-27T13:49:53.936Z", + "name": "Malicious site hosting downloader", + "pattern": "[url:value = 'http://x4z9arb.cn/4712']", + "type": "indicator", + "valid_from": "2017-01-27T13:49:53.935382Z" +} +IND4 = { + "created": "2017-01-27T13:49:53.935Z", + "id": "indicator--d81f86b8-975b-bc0b-775e-810c5ad45a4f", + "labels": [ + "url-watchlist" + ], + "modified": "2017-01-27T13:49:53.935Z", + "name": "Malicious site hosting downloader", + "pattern": "[url:value = 'http://x4z9arb.cn/4712']", + "type": "indicator", + "valid_from": "2017-01-27T13:49:53.935382Z" +} +IND5 = { + "created": "2017-01-27T13:49:53.935Z", + "id": "indicator--d81f86b8-975b-bc0b-775e-810c5ad45a4f", + "labels": [ + "url-watchlist" + ], + "modified": "2017-01-27T13:49:53.935Z", + "name": "Malicious site hosting downloader", + "pattern": "[url:value = 'http://x4z9arb.cn/4712']", + "type": "indicator", + "valid_from": "2017-01-27T13:49:53.935382Z" +} +IND6 = { + "created": "2017-01-27T13:49:53.935Z", + "id": "indicator--d81f86b9-975b-bc0b-775e-810c5ad45a4f", + "labels": [ + "url-watchlist" + ], + "modified": "2017-01-31T13:49:53.935Z", + "name": "Malicious site hosting downloader", + "pattern": "[url:value = 'http://x4z9arb.cn/4712']", + "type": "indicator", + "valid_from": "2017-01-27T13:49:53.935382Z" +} +IND7 = { + "created": "2017-01-27T13:49:53.935Z", + "id": "indicator--d81f86b8-975b-bc0b-775e-810c5ad45a4f", + "labels": [ + "url-watchlist" + ], + "modified": "2017-01-27T13:49:53.935Z", + "name": "Malicious site hosting downloader", + "pattern": "[url:value = 'http://x4z9arb.cn/4712']", + "type": "indicator", + "valid_from": "2017-01-27T13:49:53.935382Z" +} +IND8 = { + "created": "2017-01-27T13:49:53.935Z", + "id": "indicator--d81f86b8-975b-bc0b-775e-810c5ad45a4f", + "labels": [ + "url-watchlist" + ], + "modified": "2017-01-27T13:49:53.935Z", + "name": "Malicious site hosting downloader", + "pattern": "[url:value = 'http://x4z9arb.cn/4712']", + "type": "indicator", + "valid_from": "2017-01-27T13:49:53.935382Z" +} + +STIX_OBJS2 = [IND6, IND7, IND8] +STIX_OBJS1 = [IND1, IND2, IND3, IND4, IND5] + + +@pytest.fixture +def mem_store(): + yield MemoryStore(STIX_OBJS1) + + +@pytest.fixture +def mem_source(): + yield MemorySource(STIX_OBJS1) + + +def test_memory_source_get(mem_source): + resp = mem_source.get("indicator--d81f86b8-975b-bc0b-775e-810c5ad45a4f") + assert resp["id"] == "indicator--d81f86b8-975b-bc0b-775e-810c5ad45a4f" + + +def test_memory_source_get_nonexistant_object(mem_source): + resp = mem_source.get("tool--d81f86b8-975b-bc0b-775e-810c5ad45a4f") + assert resp is None + + +def test_memory_store_all_versions(mem_store): + # Add bundle of items to sink + mem_store.add(dict(id="bundle--%s" % make_id(), + objects=STIX_OBJS2, + spec_version="2.0", + type="bundle")) + + resp = mem_store.all_versions("indicator--d81f86b9-975b-bc0b-775e-810c5ad45a4f") + assert len(resp) == 1 # MemoryStore can only store 1 version of each object + + +def test_memory_store_query(mem_store): + query = [Filter('type', '=', 'malware')] + + resp = mem_store.query(query) + assert len(resp) == 0 + + +def test_memory_store_add_stix_object_str(mem_store): + # add stix object string + camp_id = "campaign--111111b6-1112-4fb0-111b-b111107ca70a" + camp_name = "Aurelius" + camp_alias = "Purple Robes" + camp = """{ + "name": "%s", + "type": "campaign", + "objective": "German and French Intelligence Services", + "aliases": ["%s"], + "id": "%s", + "created": "2017-05-31T21:31:53.197755Z" + }""" % (camp_name, camp_alias, camp_id) + + mem_store.add(camp) + + camp_r = mem_store.get(camp_id) + assert camp_r["id"] == camp_id + assert camp_r["name"] == camp_name + assert camp_alias in camp_r["aliases"] + + +def test_memory_store_add_stix_bundle_str(mem_store): + # add stix bundle string + camp_id = "campaign--133111b6-1112-4fb0-111b-b111107ca70a" + camp_name = "Atilla" + camp_alias = "Huns" + bund = """{ + "type": "bundle", + "id": "bundle--112211b6-1112-4fb0-111b-b111107ca70a", + "spec_version": "2.0", + "objects": [ + { + "name": "%s", + "type": "campaign", + "objective": "Bulgarian, Albanian and Romanian Intelligence Services", + "aliases": ["%s"], + "id": "%s", + "created": "2017-05-31T21:31:53.197755Z" + } + ] + }""" % (camp_name, camp_alias, camp_id) + + mem_store.add(bund) + + camp_r = mem_store.get(camp_id) + assert camp_r["id"] == camp_id + assert camp_r["name"] == camp_name + assert camp_alias in camp_r["aliases"] + + +def test_memory_store_object_with_custom_property(mem_store): + camp = Campaign(name="Scipio Africanus", + objective="Defeat the Carthaginians", + x_empire="Roman", + allow_custom=True) + + mem_store.add(camp, True) + + camp_r = mem_store.get(camp.id, True) + assert camp_r.id == camp.id + assert camp_r.x_empire == camp.x_empire + + +def test_memory_store_object_with_custom_property_in_bundle(mem_store): + camp = Campaign(name="Scipio Africanus", + objective="Defeat the Carthaginians", + x_empire="Roman", + allow_custom=True) + + bundle = Bundle(camp, allow_custom=True) + mem_store.add(bundle, True) + + bundle_r = mem_store.get(bundle.id, True) + camp_r = bundle_r['objects'][0] + assert camp_r.id == camp.id + assert camp_r.x_empire == camp.x_empire + + +def test_memory_store_custom_object(mem_store): + @CustomObject('x-new-obj', [ + ('property1', properties.StringProperty(required=True)), + ]) + class NewObj(): + pass + + newobj = NewObj(property1='something') + mem_store.add(newobj, True) + + newobj_r = mem_store.get(newobj.id, True) + assert newobj_r.id == newobj.id + assert newobj_r.property1 == 'something' From 476cd1ed5bb84f4a603466ada2556df09368f6ee Mon Sep 17 00:00:00 2001 From: Chris Lenk Date: Wed, 18 Oct 2017 18:34:08 -0400 Subject: [PATCH 07/19] Add option for custom content to TAXII datastore --- stix2/sources/taxii.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/stix2/sources/taxii.py b/stix2/sources/taxii.py index 7ecedca..619af0c 100644 --- a/stix2/sources/taxii.py +++ b/stix2/sources/taxii.py @@ -41,7 +41,7 @@ class TAXIICollectionSink(DataSink): super(TAXIICollectionSink, self).__init__() self.collection = collection - def add(self, stix_data): + def add(self, stix_data, allow_custom=False): """add/push STIX content to TAXII Collection endpoint Args: @@ -53,27 +53,27 @@ class TAXIICollectionSink(DataSink): if isinstance(stix_data, _STIXBase): # adding python STIX object - bundle = dict(Bundle(stix_data)) + bundle = dict(Bundle(stix_data, allow_custom=allow_custom)) elif isinstance(stix_data, dict): # adding python dict (of either Bundle or STIX obj) if stix_data["type"] == "bundle": bundle = stix_data else: - bundle = dict(Bundle(stix_data)) + bundle = dict(Bundle(stix_data, allow_custom=allow_custom)) elif isinstance(stix_data, list): # adding list of something - recurse on each for obj in stix_data: - self.add(obj) + self.add(obj, allow_custom=allow_custom) elif isinstance(stix_data, str): # adding json encoded string of STIX content - stix_data = parse(stix_data) + stix_data = parse(stix_data, allow_custom=allow_custom) if stix_data["type"] == "bundle": bundle = dict(stix_data) else: - bundle = dict(Bundle(stix_data)) + bundle = dict(Bundle(stix_data, allow_custom=allow_custom)) else: raise TypeError("stix_data must be as STIX object(or list of),json formatted STIX (or list of), or a json formatted STIX bundle") @@ -93,7 +93,7 @@ class TAXIICollectionSource(DataSource): super(TAXIICollectionSource, self).__init__() self.collection = collection - def get(self, stix_id, _composite_filters=None): + def get(self, stix_id, _composite_filters=None, allow_custom=False): """retrieve STIX object from local/remote STIX Collection endpoint. @@ -125,13 +125,13 @@ class TAXIICollectionSource(DataSource): if len(stix_obj): stix_obj = stix_obj[0] - stix_obj = parse(stix_obj) + stix_obj = parse(stix_obj, allow_custom=allow_custom) else: stix_obj = None return stix_obj - def all_versions(self, stix_id, _composite_filters=None): + def all_versions(self, stix_id, _composite_filters=None, allow_custom=False): """retrieve STIX object from local/remote TAXII Collection endpoint, all versions of it @@ -151,11 +151,11 @@ class TAXIICollectionSource(DataSource): Filter("match[version]", "=", "all") ] - all_data = self.query(query=query, _composite_filters=_composite_filters) + all_data = self.query(query=query, _composite_filters=_composite_filters, allow_custom=allow_custom) return all_data - def query(self, query=None, _composite_filters=None): + def query(self, query=None, _composite_filters=None, allow_custom=False): """search and retreive STIX objects based on the complete query A "complete query" includes the filters from the query, the filters @@ -194,7 +194,7 @@ class TAXIICollectionSource(DataSource): taxii_filters = self._parse_taxii_filters(query) # query TAXII collection - all_data = self.collection.get_objects(filters=taxii_filters)["objects"] + all_data = self.collection.get_objects(filters=taxii_filters, allow_custom=allow_custom)["objects"] # deduplicate data (before filtering as reduces wasted filtering) all_data = deduplicate(all_data) @@ -203,7 +203,7 @@ class TAXIICollectionSource(DataSource): all_data = list(apply_common_filters(all_data, query)) # parse python STIX objects from the STIX object dicts - stix_objs = [parse(stix_obj_dict) for stix_obj_dict in all_data] + stix_objs = [parse(stix_obj_dict, allow_custom=allow_custom) for stix_obj_dict in all_data] return stix_objs From e1e368c0d2d4c3916d05bbe213ac0294ee885e01 Mon Sep 17 00:00:00 2001 From: Chris Lenk Date: Fri, 20 Oct 2017 09:13:04 -0400 Subject: [PATCH 08/19] Add created_by() function to Environment --- stix2/environment.py | 14 ++++++++++++++ stix2/test/test_environment.py | 22 ++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/stix2/environment.py b/stix2/environment.py index c4816ee..bd50b7f 100644 --- a/stix2/environment.py +++ b/stix2/environment.py @@ -152,3 +152,17 @@ class Environment(object): def parse(self, *args, **kwargs): return _parse(*args, **kwargs) parse.__doc__ = _parse.__doc__ + + def created_by(self, obj): + """Retrieve the Identity refered to by the object's `created_by_ref`. + + Args: + obj: The STIX object whose `created_by_ref` property will be looked + up. + + Returns: + The STIX object's creator. + """ + + creator_id = obj.get('created_by_ref', '') + return self.get(creator_id) diff --git a/stix2/test/test_environment.py b/stix2/test/test_environment.py index 81f2cda..5758732 100644 --- a/stix2/test/test_environment.py +++ b/stix2/test/test_environment.py @@ -184,3 +184,25 @@ def test_parse_malware(): assert mal.modified == FAKE_TIME assert mal.labels == ['ransomware'] assert mal.name == "Cryptolocker" + + +def test_created_by(): + identity = stix2.Identity(**IDENTITY_KWARGS) + factory = stix2.ObjectFactory(created_by_ref=identity.id) + env = stix2.Environment(store=stix2.MemoryStore(), factory=factory) + env.add(identity) + + ind = env.create(stix2.Indicator, **INDICATOR_KWARGS) + creator = env.created_by(ind) + assert creator.id == identity.id + + +def test_created_by_no_datasource(): + identity = stix2.Identity(**IDENTITY_KWARGS) + factory = stix2.ObjectFactory(created_by_ref=identity.id) + env = stix2.Environment(factory=factory) + + ind = env.create(stix2.Indicator, **INDICATOR_KWARGS) + with pytest.raises(AttributeError) as excinfo: + env.created_by(ind) + assert 'Environment has no data source' in str(excinfo.value) From 5c28074364ee268242e3578d4644310eb436304e Mon Sep 17 00:00:00 2001 From: Chris Lenk Date: Tue, 24 Oct 2017 09:15:09 -0400 Subject: [PATCH 09/19] Add `allow_custom` to datastore docstrings --- stix2/sources/__init__.py | 28 +++++++++++--- stix2/sources/filesystem.py | 11 ++++-- stix2/sources/memory.py | 73 +++++++++++++++++++++---------------- stix2/sources/taxii.py | 25 +++++++------ 4 files changed, 84 insertions(+), 53 deletions(-) diff --git a/stix2/sources/__init__.py b/stix2/sources/__init__.py index 9c5510e..47c7573 100644 --- a/stix2/sources/__init__.py +++ b/stix2/sources/__init__.py @@ -51,6 +51,8 @@ class DataStore(object): Args: stix_id (str): the id of the STIX object to retrieve. + allow_custom (bool): whether to retrieve custom objects/properties + or not. Default: False. Returns: stix_obj: the single most recent version of the STIX @@ -66,6 +68,8 @@ class DataStore(object): Args: stix_id (str): the id of the STIX object to retrieve. + allow_custom (bool): whether to retrieve custom objects/properties + or not. Default: False. Returns: stix_objs (list): a list of STIX objects @@ -82,6 +86,8 @@ class DataStore(object): Args: query (list): a list of filters (which collectively are the query) to conduct search on. + allow_custom (bool): whether to retrieve custom objects/properties + or not. Default: False. Returns: stix_objs (list): a list of STIX objects @@ -96,6 +102,8 @@ class DataStore(object): Args: stix_objs (list): a list of STIX objects + allow_custom (bool): whether to allow custom objects/properties or + not. Default: False. """ return self.sink.add(stix_objs, allow_custom=allow_custom) @@ -120,6 +128,8 @@ class DataSink(object): Args: stix_objs (list): a list of STIX objects (where each object is a STIX object) + allow_custom (bool): whether to allow custom objects/properties or + not. Default: False. """ raise NotImplementedError() @@ -148,9 +158,10 @@ class DataSource(object): stix_id (str): the id of the STIX 2.0 object to retrieve. Should return a single object, the most recent version of the object specified by the "id". - _composite_filters (set): set of filters passed from the parent the CompositeDataSource, not user supplied + allow_custom (bool): whether to retrieve custom objects/properties + or not. Default: False. Returns: stix_obj: the STIX object @@ -169,9 +180,10 @@ class DataSource(object): stix_id (str): The id of the STIX 2.0 object to retrieve. Should return a list of objects, all the versions of the object specified by the "id". - _composite_filters (set): set of filters passed from the parent CompositeDataSource, not user supplied + allow_custom (bool): whether to retrieve custom objects/properties + or not. Default: False. Returns: stix_objs (list): a list of STIX objects @@ -187,9 +199,10 @@ class DataSource(object): Args: query (list): a list of filters (which collectively are the query) to conduct search on - _composite_filters (set): a set of filters passed from the parent CompositeDataSource, not user supplied + allow_custom (bool): whether to retrieve custom objects/properties + or not. Default: False. Returns: stix_objs (list): a list of STIX objects @@ -238,10 +251,11 @@ class CompositeDataSource(DataSource): Args: stix_id (str): the id of the STIX object to retrieve. - _composite_filters (list): a list of filters passed from a CompositeDataSource (i.e. if this CompositeDataSource is attached to another parent CompositeDataSource), not user supplied + allow_custom (bool): whether to retrieve custom objects/properties + or not. Default: False. Returns: stix_obj: the STIX object to be returned. @@ -283,10 +297,11 @@ class CompositeDataSource(DataSource): Args: stix_id (str): id of the STIX objects to retrieve - _composite_filters (list): a list of filters passed from a CompositeDataSource (i.e. if this CompositeDataSource is attached to a parent CompositeDataSource), not user supplied + allow_custom (bool): whether to retrieve custom objects/properties + or not. Default: False. Returns: all_data (list): list of STIX objects that have the specified id @@ -323,10 +338,11 @@ class CompositeDataSource(DataSource): Args: query (list): list of filters to search on - _composite_filters (list): a list of filters passed from a CompositeDataSource (i.e. if this CompositeDataSource is attached to a parent CompositeDataSource), not user supplied + allow_custom (bool): whether to retrieve custom objects/properties + or not. Default: False. Returns: all_data (list): list of STIX objects to be returned diff --git a/stix2/sources/filesystem.py b/stix2/sources/filesystem.py index 1dcf85b..1a8366b 100644 --- a/stix2/sources/filesystem.py +++ b/stix2/sources/filesystem.py @@ -67,6 +67,8 @@ class FileSystemSink(DataSink): stix_data (STIX object OR dict OR str OR list): valid STIX 2.0 content in a STIX object (or list of), dict (or list of), or a STIX 2.0 json encoded string. + allow_custom (bool): whether to allow custom objects/properties or + not. Default: False. Note: ``stix_data`` can be a Bundle object, but each object in it will be @@ -140,9 +142,10 @@ class FileSystemSource(DataSource): Args: stix_id (str): The STIX ID of the STIX object to be retrieved. - composite_filters (set): set of filters passed from the parent CompositeDataSource, not user supplied + allow_custom (bool): whether to retrieve custom objects/properties + or not. Default: False. Returns: (STIX object): STIX object that has the supplied STIX ID. @@ -169,9 +172,10 @@ class FileSystemSource(DataSource): Args: stix_id (str): The STIX ID of the STIX objects to be retrieved. - composite_filters (set): set of filters passed from the parent CompositeDataSource, not user supplied + allow_custom (bool): whether to retrieve custom objects/properties + or not. Default: False. Returns: (list): of STIX objects that has the supplied STIX ID. @@ -190,9 +194,10 @@ class FileSystemSource(DataSource): Args: query (list): list of filters to search on - composite_filters (set): set of filters passed from the CompositeDataSource, not user supplied + allow_custom (bool): whether to retrieve custom objects/properties + or not. Default: False. Returns: (list): list of STIX objects that matches the supplied diff --git a/stix2/sources/memory.py b/stix2/sources/memory.py index 1b738ab..0f10cf9 100644 --- a/stix2/sources/memory.py +++ b/stix2/sources/memory.py @@ -32,8 +32,10 @@ def _add(store, stix_data=None, allow_custom=False): Args: stix_data (list OR dict OR STIX object): STIX objects to be added - """ + allow_custom (bool): whether to allow custom objects/properties or + not. Default: False. + """ if isinstance(stix_data, _STIXBase): # adding a python STIX object store._data[stix_data["id"]] = stix_data @@ -77,16 +79,15 @@ class MemoryStore(DataStore): Args: stix_data (list OR dict OR STIX object): STIX content to be added + allow_custom (bool): whether to allow custom objects/properties or + not. Default: False. Attributes: _data (dict): the in-memory dict that holds STIX objects - source (MemorySource): MemorySource - sink (MemorySink): MemorySink """ - def __init__(self, stix_data=None, allow_custom=False): super(MemoryStore, self).__init__() self._data = {} @@ -98,9 +99,29 @@ class MemoryStore(DataStore): self.sink = MemorySink(stix_data=self._data, _store=True, allow_custom=allow_custom) def save_to_file(self, file_path, allow_custom=False): + """Write SITX objects from in-memory dictionary to JSON file, as a STIX + Bundle. + + Args: + file_path (str): file path to write STIX data to + allow_custom (bool): whether to allow custom objects/properties or + not. Default: False. + + """ return self.sink.save_to_file(file_path=file_path, allow_custom=allow_custom) def load_from_file(self, file_path, allow_custom=False): + """Load STIX data from JSON file. + + File format is expected to be a single JSON + STIX object or JSON STIX bundle. + + Args: + file_path (str): file path to load STIX data from + allow_custom (bool): whether to allow custom objects/properties or + not. Default: False. + + """ return self.source.load_from_file(file_path=file_path, allow_custom=allow_custom) @@ -113,17 +134,18 @@ class MemorySink(DataSink): Args: stix_data (dict OR list): valid STIX 2.0 content in bundle or a list. - _store (bool): if the MemorySink is a part of a DataStore, in which case "stix_data" is a direct reference to shared memory with DataSource. Not user supplied + allow_custom (bool): whether to allow custom objects/properties or + not. Default: False. Attributes: _data (dict): the in-memory dict that holds STIX objects. If apart of a MemoryStore, dict is shared between with a MemorySource - """ + """ def __init__(self, stix_data=None, _store=False, allow_custom=False): super(MemorySink, self).__init__() self._data = {} @@ -134,25 +156,16 @@ class MemorySink(DataSink): _add(self, stix_data, allow_custom=allow_custom) def add(self, stix_data, allow_custom=False): - """add STIX objects to in-memory dictionary maintained by - the MemorySink (MemoryStore) - - see "_add()" for args documentation - """ _add(self, stix_data, allow_custom=allow_custom) + add.__doc__ = _add.__doc__ def save_to_file(self, file_path, allow_custom=False): - """write SITX objects in in-memory dictionary to json file, as a STIX Bundle - - Args: - file_path (str): file path to write STIX data to - - """ file_path = os.path.abspath(file_path) if not os.path.exists(os.path.dirname(file_path)): os.makedirs(os.path.dirname(file_path)) with open(file_path, "w") as f: f.write(str(Bundle(self._data.values(), allow_custom=allow_custom))) + save_to_file.__doc__ = MemoryStore.save_to_file.__doc__ class MemorySource(DataSource): @@ -165,17 +178,18 @@ class MemorySource(DataSource): Args: stix_data (dict OR list OR STIX object): valid STIX 2.0 content in bundle or list. - _store (bool): if the MemorySource is a part of a DataStore, in which case "stix_data" is a direct reference to shared memory with DataSink. Not user supplied + allow_custom (bool): whether to allow custom objects/properties or + not. Default: False. Attributes: _data (dict): the in-memory dict that holds STIX objects. If apart of a MemoryStore, dict is shared between with a MemorySink - """ + """ def __init__(self, stix_data=None, _store=False, allow_custom=False): super(MemorySource, self).__init__() self._data = {} @@ -190,9 +204,10 @@ class MemorySource(DataSource): Args: stix_id (str): The STIX ID of the STIX object to be retrieved. - composite_filters (set): set of filters passed from the parent CompositeDataSource, not user supplied + allow_custom (bool): whether to retrieve custom objects/properties + or not. Default: False. Returns: (dict OR STIX object): STIX object that has the supplied @@ -227,9 +242,10 @@ class MemorySource(DataSource): Args: stix_id (str): The STIX ID of the STIX 2 object to retrieve. - composite_filters (set): set of filters passed from the parent CompositeDataSource, not user supplied + allow_custom (bool): whether to retrieve custom objects/properties + or not. Default: False. Returns: (list): list of STIX objects that has the supplied ID. As the @@ -249,15 +265,16 @@ class MemorySource(DataSource): Args: query (list): list of filters to search on - composite_filters (set): set of filters passed from the CompositeDataSource, not user supplied + allow_custom (bool): whether to retrieve custom objects/properties + or not. Default: False. Returns: (list): list of STIX objects that matches the supplied query. As the MemoryStore(i.e. MemorySink) adds STIX objects to memory as they are supplied (either as python dictionary or STIX object), it - is returned in the same form as it as added + is returned in the same form as it as added. """ if query is None: @@ -281,15 +298,7 @@ class MemorySource(DataSource): return all_data def load_from_file(self, file_path, allow_custom=False): - """Load STIX data from json file. - - File format is expected to be a single json - STIX object or json STIX bundle - - Args: - file_path (str): file path to load STIX data from - - """ file_path = os.path.abspath(file_path) stix_data = json.load(open(file_path, "r")) _add(self, stix_data, allow_custom=allow_custom) + load_from_file.__doc__ = MemoryStore.load_from_file.__doc__ diff --git a/stix2/sources/taxii.py b/stix2/sources/taxii.py index 619af0c..90d632e 100644 --- a/stix2/sources/taxii.py +++ b/stix2/sources/taxii.py @@ -21,7 +21,7 @@ class TAXIICollectionStore(DataStore): around a paired TAXIICollectionSink and TAXIICollectionSource. Args: - collection (taxii2.Collection): TAXII Collection instance + collection (taxii2.Collection): TAXII Collection instance """ def __init__(self, collection): super(TAXIICollectionStore, self).__init__() @@ -42,15 +42,16 @@ class TAXIICollectionSink(DataSink): self.collection = collection def add(self, stix_data, allow_custom=False): - """add/push STIX content to TAXII Collection endpoint + """Add/push STIX content to TAXII Collection endpoint Args: stix_data (STIX object OR dict OR str OR list): valid STIX 2.0 content in a STIX object (or Bundle), STIX onject dict (or Bundle dict), or a STIX 2.0 json encoded string, or list of any of the following + allow_custom (bool): whether to allow custom objects/properties or + not. Default: False. """ - if isinstance(stix_data, _STIXBase): # adding python STIX object bundle = dict(Bundle(stix_data, allow_custom=allow_custom)) @@ -94,21 +95,21 @@ class TAXIICollectionSource(DataSource): self.collection = collection def get(self, stix_id, _composite_filters=None, allow_custom=False): - """retrieve STIX object from local/remote STIX Collection + """Retrieve STIX object from local/remote STIX Collection endpoint. Args: stix_id (str): The STIX ID of the STIX object to be retrieved. - composite_filters (set): set of filters passed from the parent CompositeDataSource, not user supplied + allow_custom (bool): whether to retrieve custom objects/properties + or not. Default: False. Returns: (STIX object): STIX object that has the supplied STIX ID. The STIX object is received from TAXII has dict, parsed into a python STIX object and then returned - """ # combine all query filters query = set() @@ -132,14 +133,15 @@ class TAXIICollectionSource(DataSource): return stix_obj def all_versions(self, stix_id, _composite_filters=None, allow_custom=False): - """retrieve STIX object from local/remote TAXII Collection + """Retrieve STIX object from local/remote TAXII Collection endpoint, all versions of it Args: stix_id (str): The STIX ID of the STIX objects to be retrieved. - composite_filters (set): set of filters passed from the parent CompositeDataSource, not user supplied + allow_custom (bool): whether to retrieve custom objects/properties + or not. Default: False. Returns: (see query() as all_versions() is just a wrapper) @@ -156,7 +158,7 @@ class TAXIICollectionSource(DataSource): return all_data def query(self, query=None, _composite_filters=None, allow_custom=False): - """search and retreive STIX objects based on the complete query + """Search and retreive STIX objects based on the complete query A "complete query" includes the filters from the query, the filters attached to MemorySource, and any filters passed from a @@ -164,9 +166,10 @@ class TAXIICollectionSource(DataSource): Args: query (list): list of filters to search on - composite_filters (set): set of filters passed from the CompositeDataSource, not user supplied + allow_custom (bool): whether to retrieve custom objects/properties + or not. Default: False. Returns: (list): list of STIX objects that matches the supplied @@ -174,7 +177,6 @@ class TAXIICollectionSource(DataSource): parsed into python STIX objects and then returned. """ - if query is None: query = set() else: @@ -225,7 +227,6 @@ class TAXIICollectionSource(DataSource): for 'requests.get()'. """ - params = {} for filter_ in query: From 47b11453fa363b74d0e2213065e8c87d16a7ac0d Mon Sep 17 00:00:00 2001 From: Chris Lenk Date: Tue, 24 Oct 2017 12:43:30 -0400 Subject: [PATCH 10/19] Increase test coverage for memory datastore --- stix2/sources/__init__.py | 4 ++-- stix2/sources/memory.py | 4 ++-- stix2/test/test_memory.py | 35 ++++++++++++++++++++++++++++++++++- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/stix2/sources/__init__.py b/stix2/sources/__init__.py index 47c7573..a142e88 100644 --- a/stix2/sources/__init__.py +++ b/stix2/sources/__init__.py @@ -77,7 +77,7 @@ class DataStore(object): """ return self.source.all_versions(stix_id, allow_custom=allow_custom) - def query(self, query, allow_custom=False): + def query(self, query=None, allow_custom=False): """Retrieve STIX objects matching a set of filters. Implement: Specific data source API calls, processing, @@ -191,7 +191,7 @@ class DataSource(object): """ raise NotImplementedError() - def query(self, query, _composite_filters=None, allow_custom=False): + def query(self, query=None, _composite_filters=None, allow_custom=False): """ Implement:Implement the specific data source API calls, processing, functionality required for retrieving query from the data source diff --git a/stix2/sources/memory.py b/stix2/sources/memory.py index 0f10cf9..0846f9b 100644 --- a/stix2/sources/memory.py +++ b/stix2/sources/memory.py @@ -65,7 +65,7 @@ def _add(store, stix_data=None, allow_custom=False): _add(store, stix_obj, allow_custom=allow_custom) else: - raise TypeError("stix_data must be as STIX object(or list of),json formatted STIX (or list of), or a json formatted STIX bundle") + raise TypeError("stix_data must be a STIX object (or list of), JSON formatted STIX (or list of), or a JSON formatted STIX bundle") class MemoryStore(DataStore): @@ -283,7 +283,7 @@ class MemorySource(DataSource): if not isinstance(query, list): # make sure dont make set from a Filter object, # need to make a set from a list of Filter objects (even if just one Filter) - query = list(query) + query = [query] query = set(query) # combine all query filters diff --git a/stix2/test/test_memory.py b/stix2/test/test_memory.py index e8ba56b..0603bf7 100644 --- a/stix2/test/test_memory.py +++ b/stix2/test/test_memory.py @@ -138,11 +138,34 @@ def test_memory_store_all_versions(mem_store): def test_memory_store_query(mem_store): query = [Filter('type', '=', 'malware')] - resp = mem_store.query(query) assert len(resp) == 0 +def test_memory_store_query_single_filter(mem_store): + query = Filter('id', '=', 'indicator--d81f86b8-975b-bc0b-775e-810c5ad45a4f') + resp = mem_store.query(query) + assert len(resp) == 1 + + +def test_memory_store_query_empty_query(mem_store): + resp = mem_store.query() + # sort since returned in random order + resp = sorted(resp, key=lambda k: k['id']) + assert len(resp) == 2 + assert resp[0]['id'] == 'indicator--d81f86b8-975b-bc0b-775e-810c5ad45a4f' + assert resp[0]['modified'] == '2017-01-27T13:49:53.935Z' + assert resp[1]['id'] == 'indicator--d81f86b9-975b-bc0b-775e-810c5ad45a4f' + assert resp[1]['modified'] == '2017-01-27T13:49:53.936Z' + + +def test_memory_store_query_multiple_filters(mem_store): + mem_store.source.filters.add(Filter('type', '=', 'indicator')) + query = Filter('id', '=', 'indicator--d81f86b8-975b-bc0b-775e-810c5ad45a4f') + resp = mem_store.query(query) + assert len(resp) == 1 + + def test_memory_store_add_stix_object_str(mem_store): # add stix object string camp_id = "campaign--111111b6-1112-4fb0-111b-b111107ca70a" @@ -194,6 +217,16 @@ def test_memory_store_add_stix_bundle_str(mem_store): assert camp_alias in camp_r["aliases"] +def test_memory_store_add_invalid_object(mem_store): + ind = ('indicator', IND1) # tuple isn't valid + with pytest.raises(TypeError) as excinfo: + mem_store.add(ind) + assert 'stix_data must be' in str(excinfo.value) + assert 'a STIX object' in str(excinfo.value) + assert 'JSON formatted STIX' in str(excinfo.value) + assert 'JSON formatted STIX bundle' in str(excinfo.value) + + def test_memory_store_object_with_custom_property(mem_store): camp = Campaign(name="Scipio Africanus", objective="Defeat the Carthaginians", From 5dffe74867362566e60bfa973010220f704e009d Mon Sep 17 00:00:00 2001 From: Chris Lenk Date: Tue, 24 Oct 2017 14:20:42 -0400 Subject: [PATCH 11/19] Clean up creator_of (renamed from created_by) --- stix2/environment.py | 13 +++++++++---- stix2/sources/__init__.py | 2 ++ stix2/sources/memory.py | 10 +++++++--- stix2/test/test_environment.py | 16 +++++++++++++--- 4 files changed, 31 insertions(+), 10 deletions(-) diff --git a/stix2/environment.py b/stix2/environment.py index bd50b7f..4919335 100644 --- a/stix2/environment.py +++ b/stix2/environment.py @@ -153,7 +153,7 @@ class Environment(object): return _parse(*args, **kwargs) parse.__doc__ = _parse.__doc__ - def created_by(self, obj): + def creator_of(self, obj): """Retrieve the Identity refered to by the object's `created_by_ref`. Args: @@ -161,8 +161,13 @@ class Environment(object): up. Returns: - The STIX object's creator. - """ + The STIX object's creator, or + None, if the object contains no `created_by_ref` property or the + object's creator cannot be found. + """ creator_id = obj.get('created_by_ref', '') - return self.get(creator_id) + if creator_id: + return self.get(creator_id) + else: + return None diff --git a/stix2/sources/__init__.py b/stix2/sources/__init__.py index 9d46ba9..49cb3f3 100644 --- a/stix2/sources/__init__.py +++ b/stix2/sources/__init__.py @@ -266,6 +266,8 @@ class CompositeDataSource(DataSource): # remove duplicate versions if len(all_data) > 0: all_data = deduplicate(all_data) + else: + return None # reduce to most recent version stix_obj = sorted(all_data, key=lambda k: k['modified'], reverse=True)[0] diff --git a/stix2/sources/memory.py b/stix2/sources/memory.py index 0d5901e..967b886 100644 --- a/stix2/sources/memory.py +++ b/stix2/sources/memory.py @@ -215,10 +215,14 @@ class MemorySource(DataSource): all_data = self.query(query=query, _composite_filters=_composite_filters) - # reduce to most recent version - stix_obj = sorted(all_data, key=lambda k: k['modified'])[0] + if all_data: + print(all_data) + # reduce to most recent version + stix_obj = sorted(all_data, key=lambda k: k['modified'])[0] - return stix_obj + return stix_obj + else: + return None def all_versions(self, stix_id, _composite_filters=None): """retrieve STIX objects from in-memory dict via STIX ID, all versions of it diff --git a/stix2/test/test_environment.py b/stix2/test/test_environment.py index 5758732..c669a33 100644 --- a/stix2/test/test_environment.py +++ b/stix2/test/test_environment.py @@ -193,8 +193,8 @@ def test_created_by(): env.add(identity) ind = env.create(stix2.Indicator, **INDICATOR_KWARGS) - creator = env.created_by(ind) - assert creator.id == identity.id + creator = env.creator_of(ind) + assert creator is identity def test_created_by_no_datasource(): @@ -204,5 +204,15 @@ def test_created_by_no_datasource(): ind = env.create(stix2.Indicator, **INDICATOR_KWARGS) with pytest.raises(AttributeError) as excinfo: - env.created_by(ind) + env.creator_of(ind) assert 'Environment has no data source' in str(excinfo.value) + + +def test_created_by_not_found(): + identity = stix2.Identity(**IDENTITY_KWARGS) + factory = stix2.ObjectFactory(created_by_ref=identity.id) + env = stix2.Environment(store=stix2.MemoryStore(), factory=factory) + + ind = env.create(stix2.Indicator, **INDICATOR_KWARGS) + creator = env.creator_of(ind) + assert creator is None From 70929905652a7b90d669f5724e204cef02fd32f9 Mon Sep 17 00:00:00 2001 From: = Date: Wed, 25 Oct 2017 14:36:20 -0400 Subject: [PATCH 12/19] tested code with jupyter notebook and local TAXII server --- docs/guide/taxii.ipynb | 2357 +--------------------------------------- stix2/sources/taxii.py | 25 +- 2 files changed, 69 insertions(+), 2313 deletions(-) diff --git a/docs/guide/taxii.ipynb b/docs/guide/taxii.ipynb index 2890659..ef2cb73 100644 --- a/docs/guide/taxii.ipynb +++ b/docs/guide/taxii.ipynb @@ -71,7 +71,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 18, "metadata": {}, "outputs": [ { @@ -79,21 +79,27 @@ "output_type": "stream", "text": [ "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--fb2c0e55-52a0-423c-b544-8b09622cafc1\",\n", - " \"created\": \"2017-10-02T19:26:30.000Z\",\n", - " \"modified\": \"2017-10-02T19:26:30.000Z\",\n", + " \"type\": \"malware\",\n", + " \"id\": \"malware--fdd60b30-b67c-11e3-b0b9-f01faf20d111\",\n", + " \"created\": \"2017-01-27T13:49:53.997Z\",\n", + " \"modified\": \"2017-01-27T13:49:53.997Z\",\n", + " \"name\": \"Poison Ivy\",\n", + " \"description\": \"Poison Ivy\",\n", " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '98.138.19.88' ]\",\n", - " \"valid_from\": \"2017-10-02T19:26:30Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", + " \"remote-access-trojan\"\n", + " ]\n", + "}\n", + "-------\n", + "{\n", + " \"type\": \"indicator\",\n", + " \"id\": \"indicator--a932fcc6-e032-176c-126f-cb970a5a1ade\",\n", + " \"created\": \"2014-05-08T09:00:00.000Z\",\n", + " \"modified\": \"2014-05-08T09:00:00.000Z\",\n", + " \"name\": \"File hash for Poison Ivy variant\",\n", + " \"pattern\": \"[file:hashes.'SHA-256' = 'ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c']\",\n", + " \"valid_from\": \"2014-05-08T09:00:00Z\",\n", + " \"labels\": [\n", + " \"file-hash-watchlist\"\n", " ]\n", "}\n" ] @@ -104,2293 +110,41 @@ "from taxii2client import Collection\n", "\n", "# establish TAXII2 Collection instance\n", - "collection = Collection(\"https://test.freetaxii.com:8000/api1/collections/9cfa669c-ee94-4ece-afd2-f8edac37d8fd/\")\n", + "collection = Collection(\"http://127.0.0.1:5000/trustgroup1/collections/91a7b528-80eb-42ed-a74d-c6fbd5a26116/\", user=\"admin\", password=\"password\")\n", "# supply the TAXII2 collection to TAXIICollection\n", "tc_source = TAXIICollectionSource(collection)\n", "\n", - "#retrieve STIX object by id\n", - "stix_obj = tc_source.get(\"indicator--0f63229c-07a2-46dd-939d-312c7bf6d114\")\n", + "#retrieve STIX objects by id\n", + "stix_obj = tc_source.get(\"malware--fdd60b30-b67c-11e3-b0b9-f01faf20d111\")\n", + "stix_obj_versions = tc_source.all_versions(\"indicator--a932fcc6-e032-176c-126f-cb970a5a1ade\")\n", "\n", "#for visual purposes\n", - "print(stix_obj)\n" + "print(stix_obj)\n", + "print(\"-------\")\n", + "for so in stix_obj_versions:\n", + " print(so)\n" ] }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "indicators: 126\n", + "indicators: 1\n", "{\n", " \"type\": \"indicator\",\n", - " \"id\": \"indicator--569b8969-bfce-4ab4-9a45-06ce78799a35\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", + " \"id\": \"indicator--a932fcc6-e032-176c-126f-cb970a5a1ade\",\n", + " \"created\": \"2014-05-08T09:00:00.000Z\",\n", + " \"modified\": \"2014-05-08T09:00:00.000Z\",\n", + " \"name\": \"File hash for Poison Ivy variant\",\n", + " \"pattern\": \"[file:hashes.'SHA-256' = 'ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c']\",\n", + " \"valid_from\": \"2014-05-08T09:00:00Z\",\n", " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '207.158.1.150' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--9c418633-9970-424e-8030-2c3dfa3105da\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '64.4.30.34' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--9d7cdfc1-94c3-49b5-b124-ebdce709fd99\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '216.152.67.22' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--37390a22-5d82-4ebc-9b90-7368a5efc8f7\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '69.16.172.34' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--30731d72-64b0-4851-bd97-c3d164d2fd2b\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '194.24.188.100' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--a4eb3524-992c-4b50-9729-99be3048625e\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '213.232.93.3' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--c00fb599-7e7b-4033-a6c2-d279212578a0\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '216.152.66.45' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--e7273b13-847c-4a69-8faf-08fc24af5ef0\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '89.16.176.16' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--b8d21867-c812-4ff9-866b-182a801b88ce\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '130.239.18.172' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--4c39b1a0-17f0-4cf1-9e48-250f0dd1f75c\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '140.211.166.4' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--8eeff049-f7da-45d9-89bb-713063baed2c\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '213.92.8.4' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--e3981158-1934-4236-8454-4dcfc27ac248\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '208.87.120.111' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--206c2a0c-149f-426f-a734-c0c534aa396b\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '216.93.243.34' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--58d7aa16-8baf-4026-b3d7-328267ed4bab\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '216.165.191.52' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--e6fd4a21-8290-40e5-9b1c-701f6f11e260\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '195.204.1.132' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--cca5ce5f-4c0e-4031-9997-063eb3badead\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '209.177.146.34' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--43a7784e-f11c-4739-91a8-dc87d05ddbb6\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '145.220.21.40' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--5716d954-e5b1-4bec-ba43-80b1053dee61\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '50.7.55.82' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--9135d4ab-a807-495b-8fff-b8433342501f\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '82.165.47.254' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--e070c86b-40e5-49ea-8d83-56bcae10b303\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '140.211.166.3' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--f4125383-930c-42ae-b57f-2c36f898d0b5\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '208.71.169.36' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--fa063c6a-1a9f-4a58-9470-ed80a23cc943\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '204.152.221.218' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--41b3ba86-dd1b-4f3d-a156-5dc27f31fb40\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '78.40.125.4' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--a9fcaba5-cd50-447d-8540-2dfe4e3c6c88\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '216.152.66.68' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--30b68eff-3c38-4c74-9783-1114a7759066\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '195.197.175.21' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--f10fa7c0-7a10-434e-908f-59a7e25e18c0\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '194.14.236.50' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--183f8cd7-2e6f-4073-bbe8-d5dc6b570fac\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '69.16.172.34' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--dd95ff3a-3ef1-409e-827b-087eb9cc3b2c\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '140.211.166.3' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--a97dc9cb-2b9f-4c1d-92cc-2fc15100e3ed\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '91.205.185.104' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--5552096e-b2b8-4057-bf5e-ccf300b8276e\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '193.163.220.3' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--0cc30ea9-eeaf-4f39-ab8d-3d2664c2b75e\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '64.202.189.170' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--7582ed02-c78d-451d-b0a5-065ae511f3ae\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '86.65.39.15' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--37fde688-ca75-4c1e-b5e1-1acb5bbfb23c\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '140.211.167.98' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--e967d3a0-0cfe-482c-b53a-390c0bb564f4\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '199.16.156.6' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--fda4f25d-8252-4593-bd8b-0a90764a561f\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '217.168.95.245' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--109b3de1-2353-42dc-8316-e2f7c0b5c67d\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '192.99.16.195' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--1efa50e4-ed2c-4fb5-ae9b-cb347bd4ad24\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '64.18.128.86' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--c7b60a1a-4c93-451f-b7c1-993c0dc14391\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '194.109.129.220' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--469381d9-c24e-4cf4-b25b-18a48975ef14\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '208.99.193.130' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--c5694bbd-3a11-4c16-ae73-eeed55acf9cc\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '70.84.101.150' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--a9b4301e-0327-4edc-b407-b7915bb0e7bc\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '64.4.30.62' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--f5ac23ca-8ab4-4597-837b-3d5e48d325cb\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '64.4.30.61' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--1a2a539b-d3f3-410b-a32c-4d1a5599364e\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '66.186.59.50' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--585e6f7b-7bad-45b0-a36b-9f3b3bff72c6\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '93.152.160.101' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--0a7dd603-d826-428f-b5f7-c82ff8bb60f3\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '216.152.66.46' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--cb2cebd2-c11f-43b1-a9a1-3c4b9893f38a\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '192.99.150.27' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--6a6c81df-7cb9-48b3-a4ea-db6924e47b5d\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '193.107.206.21' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--45177dce-6cfe-44b5-ac41-cbc1bee80527\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '69.16.172.40' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--6f58bdf5-1f26-4a17-8ba3-14c023e73a0f\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '72.51.18.254' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--d5731bef-623c-4793-994c-a6f3840bc2cf\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '193.190.67.98' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--4e8ac337-2e00-4d71-8526-bbfdb105e77f\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '140.211.166.4' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--b681b1fc-7cce-473e-81e9-f5f3657cf85b\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '130.237.188.200' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--08453fee-f3b8-449a-95a8-abc0d79710c3\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '216.155.130.130' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--79e2a4f6-ee8d-4466-8e82-ecb928e87c0d\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '208.71.169.36' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--2d3326c5-c112-4670-b6bd-6de667f4280b\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '216.152.66.47' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--4adc0666-89d1-4c67-a3c8-3b02fc351442\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '213.161.196.11' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--dc1e9fec-6d1e-46a1-902c-dc170424a23f\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '195.47.220.2' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--2d7480b1-ded5-4466-a1dd-470110eacdba\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '152.3.102.53' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--f06d6873-1538-4951-a069-d6af0dd0f8ed\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '84.208.29.17' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--4eaf258d-28d8-48d8-98f8-0d8442ba83fa\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '82.96.64.4' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--d7e4bba4-485d-4c1f-95c0-55e7d8a015f8\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '213.179.58.83' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--5c060dc8-a8cd-4067-985d-52d85ab3f256\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '128.237.157.136' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--d397fccb-3dbb-47c3-84ae-aa09f4223eca\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '193.110.95.1' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--d37d0928-c86b-474a-85ef-46e942fff510\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '98.138.19.88' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--5e6dd813-58bd-454e-9be7-246f3db01999\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '69.16.172.40' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--adb3c6bc-9694-471e-bf1f-0d0a02d70876\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '137.226.34.46' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--3ce88e57-edfb-45fa-81be-ed95d4564316\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '67.198.195.194' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--fbce496c-e9a6-4246-ad12-73b8f5a12a2a\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '149.9.1.16' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--efce84a3-0d17-4ae8-88be-86c86aa80bbd\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '193.109.122.77' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--20789570-8c07-42c4-8a45-b3ab170cf6ee\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '209.126.116.149' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--5c1b2889-6fec-4276-83e0-173938934ba9\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '64.250.116.136' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--bdad2fdb-71bd-49c3-8bf2-50d396fa55d5\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '163.172.17.231' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--07fd3e36-5500-4652-935f-23a2955b19f3\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '38.114.116.5' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--9e70a102-3440-4ad0-ab1d-653144632668\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '66.186.59.50' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--f566b659-ca36-42a9-8ebf-9476e6b651ab\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '195.204.1.130' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--40c0d87c-287a-4692-8227-b4976d14a5f0\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '212.27.60.27' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--da56b536-6ac7-44d5-a036-0db986926016\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '213.236.208.178' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--95f9c0f4-351b-43c9-81da-c5fdcfe4fa6d\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '94.125.182.252' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--5007db19-0906-4aec-b18b-e0819b3f13de\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '208.83.20.130' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--9e0667cd-9a83-4e19-b16f-78c3ed33bfc5\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '216.18.228.34' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--f170e9a9-abb8-4919-9902-7a5214e95cde\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '192.99.150.28' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--a30f883d-956d-4fdd-b926-db81d1893d81\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '178.79.132.147' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--8fc0e9c0-4d4d-4c4f-86a7-2f6c07cd69a4\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '193.109.122.67' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--586dc7e8-a08e-4ec2-8365-e2ee897d9ca3\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '195.47.220.2' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--16c9900c-ce48-4306-b8fa-a2de726be847\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '208.83.20.130' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--13f73e28-acf7-45b8-a5e9-6c37af914ef2\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '174.143.119.91' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--a09c4e42-8843-4c84-a75f-684bf90c5207\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '74.208.174.239' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--76646197-18a2-4513-8465-ccf72734a2e1\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '216.152.66.48' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--1169c1db-fd5b-4dcf-b4cb-9c0101ef0ea2\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '212.117.163.190' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--cdeb6ddb-5151-49ea-a488-23d806063eff\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '216.155.130.130' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--05d1ab76-d0a1-4a58-8137-98f5fdbc777c\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '90.147.160.69' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--876d7d09-248a-45ad-bcce-d92c73ad5aa3\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '89.16.176.16' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--ae1f860d-dc4f-4953-9e74-d4d7c389fdef\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '85.188.1.26' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--91bb4edc-f29f-41ba-87d9-d6a81ac8fdba\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '130.239.18.172' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--f006d048-f24f-46fa-837b-8f7fa41b43ca\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '8.7.233.233' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--436dcbec-48e2-4dc2-90f0-0876a876a38a\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '216.152.66.54' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--ff18364d-99f6-4d3d-b267-8401518af42c\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '194.68.45.50' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--8b26f167-b0ad-469b-b221-12896e2a0966\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '64.4.30.33' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--171268fb-f6a7-4085-adf5-2055a461cb93\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '64.161.254.20' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--b56c7a58-71cb-47c2-b615-f4e8a89a0732\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '141.213.238.252' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--bf09ce9a-3bb9-47c8-a686-ea1d8e1adbe8\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '213.92.8.4' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--42490e45-7350-4f48-884b-5d1610794a32\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '72.14.191.81' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--c28e91bf-a9a1-4bac-b3f3-cda89c7d28b8\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '69.16.172.2' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--ebe624b5-fb73-420a-a110-c1dc82baa6e4\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '69.61.21.115' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--ef65505f-4898-4968-82b4-f980e9705d21\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '64.18.128.86' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--b33c35ce-20f6-4fba-912c-dbf7756113f9\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '161.53.178.240' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--b3785934-f4f0-4ce7-b20c-e4384886ec45\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '204.11.244.21' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--10bbe70c-7bd3-443a-8f2c-1e56cd7a8a54\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '216.93.242.10' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--bcb54665-3461-43e2-8dbf-6b92c2413f67\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '216.152.67.23' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--a407b16b-cf5b-4f3a-a153-ba4dac5ce0e0\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '205.188.234.121' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--e7e50d3a-802d-41c8-b667-a27d29871098\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '82.96.64.4' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--017dfb8c-84b9-402f-8401-428477af7be4\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '80.88.108.18' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--84664128-cc14-480b-8d90-735727fd4b9f\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '154.35.200.44' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--f0aa750f-82cb-47f9-9c74-ace584fdadcb\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '195.68.221.222' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--9461c426-6404-4b7a-8552-c29dc60c9123\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '195.197.175.21' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--ba59cc70-03e4-47f4-871e-d40b727267f3\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '78.129.164.123' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--1b48b107-92e2-487f-9eae-3496eb64e125\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '140.211.167.99' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--e9aea5e2-9ef6-40b6-8f12-dff6ccd8eff4\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '85.25.43.27' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--cdbd95b1-17fb-4b2f-89b6-8c0f865b9e4d\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '193.219.128.49' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--afe4738d-bd3c-47de-9cc5-97e248291571\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '195.40.6.37' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--5eecb66e-f8fa-4ab9-85e4-599db7790edf\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '173.252.110.27' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--40b6b332-9a5a-42a7-8b25-6e3eb6d371d4\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '38.229.70.20' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--a16905d7-4452-4e9f-88a3-fc9338ea5116\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '38.99.64.210' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--5fcfa412-514f-43b5-b873-ed8c9b70bbb0\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '192.99.200.113' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--8259bca6-7c9c-4967-b048-a6f13f333f90\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '68.168.184.57' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", - " ]\n", - "}\n", - "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--96763c7c-4f52-436a-919a-8b09c841f6bd\",\n", - " \"created\": \"2017-10-02T20:40:44.000Z\",\n", - " \"modified\": \"2017-10-02T20:40:44.000Z\",\n", - " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '64.237.34.150' ]\",\n", - " \"valid_from\": \"2017-10-02T20:40:44Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", + " \"file-hash-watchlist\"\n", " ]\n", "}\n" ] @@ -2457,7 +211,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 13, "metadata": {}, "outputs": [ { @@ -2465,21 +219,14 @@ "output_type": "stream", "text": [ "{\n", - " \"type\": \"indicator\",\n", - " \"id\": \"indicator--d8e1cd37-4a6c-4088-aded-ed79c4ea2caa\",\n", - " \"created\": \"2017-10-02T20:24:03.000Z\",\n", - " \"modified\": \"2017-10-02T20:24:03.000Z\",\n", + " \"type\": \"malware\",\n", + " \"id\": \"malware--fdd60b30-b67c-11e3-b0b9-f01faf20d111\",\n", + " \"created\": \"2017-01-27T13:49:53.997Z\",\n", + " \"modified\": \"2017-01-27T13:49:53.997Z\",\n", + " \"name\": \"Poison Ivy\",\n", + " \"description\": \"Poison Ivy\",\n", " \"labels\": [\n", - " \"malicious-activity\"\n", - " ],\n", - " \"name\": \"Emerging Threats - Block Rules - Compromised IPs\",\n", - " \"pattern\": \"[ ipv4-addr:value = '98.138.19.88' ]\",\n", - " \"valid_from\": \"2017-10-02T20:24:03Z\",\n", - " \"kill_chain_phases\": [\n", - " {\n", - " \"kill_chain_name\": \"lockheed-martin-cyber-kill-chain\",\n", - " \"phase_name\": \"delivery\"\n", - " }\n", + " \"remote-access-trojan\"\n", " ]\n", "}\n" ] @@ -2494,7 +241,7 @@ "\n", "# retrieve STIX object by id from TAXII Collection through\n", "# TAXIICollectionStore\n", - "stix_obj2 = tc_source.get(\"indicator--6850d393-36b6-4a67-ad45-f9e4d512c799\")\n", + "stix_obj2 = tc_source.get(\"malware--fdd60b30-b67c-11e3-b0b9-f01faf20d111\")\n", "\n", "print(stix_obj2)" ] @@ -2520,21 +267,21 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "cti-python-stix2", "language": "python", - "name": "python3" + "name": "cti-python-stix2" }, "language_info": { "codemirror_mode": { "name": "ipython", - "version": 3 + "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.5.2" + "pygments_lexer": "ipython2", + "version": "2.7.12" } }, "nbformat": 4, diff --git a/stix2/sources/taxii.py b/stix2/sources/taxii.py index 7ecedca..3d8dcaa 100644 --- a/stix2/sources/taxii.py +++ b/stix2/sources/taxii.py @@ -1,8 +1,9 @@ """ -Python STIX 2.0 TAXII Source/Sink - -TODO: - Test everything +Python STIX 2.x +Classes: + TAXIICollectionStore + TAXIICollectionSink + TAXIICollectionSource """ @@ -121,11 +122,13 @@ class TAXIICollectionSource(DataSource): # as directly retrieveing a STIX object by ID stix_objs = self.collection.get_object(stix_id)["objects"] - stix_obj = list(apply_common_filters(stix_objs, query)) + stix_obj = [apply_common_filters(stix_objs, query)] if len(stix_obj): - stix_obj = stix_obj[0] - stix_obj = parse(stix_obj) + stix_obj = parse(stix_obj[0]) + if stix_obj.id != stix_id: + # check - was added to handle erroneous TAXII servers + stix_obj = None else: stix_obj = None @@ -153,7 +156,13 @@ class TAXIICollectionSource(DataSource): all_data = self.query(query=query, _composite_filters=_composite_filters) - return all_data + # parse STIX objects from TAXII returned json + all_data = [parse(stix_obj) for stix_obj in all_data] + + # check - was added to handle erroneous TAXII servers + all_data_clean = [stix_obj for stix_obj in all_data if stix_obj.id == stix_id] + + return all_data_clean def query(self, query=None, _composite_filters=None): """search and retreive STIX objects based on the complete query From 313c6f56ffb198495a66aeaebbc398dabd0a38c2 Mon Sep 17 00:00:00 2001 From: = Date: Wed, 25 Oct 2017 14:38:25 -0400 Subject: [PATCH 13/19] guide output --- docs/guide/taxii.ipynb | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/guide/taxii.ipynb b/docs/guide/taxii.ipynb index ef2cb73..d44b12e 100644 --- a/docs/guide/taxii.ipynb +++ b/docs/guide/taxii.ipynb @@ -127,14 +127,13 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "indicators: 1\n", "{\n", " \"type\": \"indicator\",\n", " \"id\": \"indicator--a932fcc6-e032-176c-126f-cb970a5a1ade\",\n", @@ -160,7 +159,6 @@ "indicators = tc_source.query([f1])\n", "\n", "#for visual purposes\n", - "print(\"indicators: {0}\").format(str(len(indicators)))\n", "for indicator in indicators:\n", " print(indicator)" ] @@ -211,7 +209,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 19, "metadata": {}, "outputs": [ { From 082973f780c89c81245a08ee93d9cfdab1a6d570 Mon Sep 17 00:00:00 2001 From: = Date: Wed, 25 Oct 2017 15:18:32 -0400 Subject: [PATCH 14/19] whitespace - somehow pre-commit got turned off?? --- stix2/sources/taxii.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix2/sources/taxii.py b/stix2/sources/taxii.py index 3d8dcaa..5dcd9f2 100644 --- a/stix2/sources/taxii.py +++ b/stix2/sources/taxii.py @@ -1,5 +1,5 @@ """ -Python STIX 2.x +Python STIX 2.x Classes: TAXIICollectionStore TAXIICollectionSink From 4e3752912d81881ee9c81d1c4da53812ea925208 Mon Sep 17 00:00:00 2001 From: Chris Lenk Date: Thu, 26 Oct 2017 15:35:19 -0400 Subject: [PATCH 15/19] Remove stray `print` statement --- stix2/sources/memory.py | 1 - 1 file changed, 1 deletion(-) diff --git a/stix2/sources/memory.py b/stix2/sources/memory.py index 967b886..9dc7062 100644 --- a/stix2/sources/memory.py +++ b/stix2/sources/memory.py @@ -216,7 +216,6 @@ class MemorySource(DataSource): all_data = self.query(query=query, _composite_filters=_composite_filters) if all_data: - print(all_data) # reduce to most recent version stix_obj = sorted(all_data, key=lambda k: k['modified'])[0] From f10308443988e8195b94132a2c8c985f2a25567a Mon Sep 17 00:00:00 2001 From: Chris Lenk Date: Fri, 27 Oct 2017 12:23:57 -0400 Subject: [PATCH 16/19] Add `bundlify` parameter to FileSystemStore/Sink This brings back the option (disabled by default) to wrap objects in a bundle when saving them to the filesystem. --- stix2/sources/filesystem.py | 41 +++++++++++++++++++++-------------- stix2/test/test_bundle.py | 1 - stix2/test/test_filesystem.py | 18 +++++++++++++++ 3 files changed, 43 insertions(+), 17 deletions(-) diff --git a/stix2/sources/filesystem.py b/stix2/sources/filesystem.py index 1a8366b..9fd658d 100644 --- a/stix2/sources/filesystem.py +++ b/stix2/sources/filesystem.py @@ -25,17 +25,18 @@ class FileSystemStore(DataStore): Args: stix_dir (str): path to directory of STIX objects + bundlify (bool): Whether to wrap objects in bundles when saving them. + Default: False. Attributes: source (FileSystemSource): FuleSystemSource - sink (FileSystemSink): FileSystemSink """ - def __init__(self, stix_dir): + def __init__(self, stix_dir, bundlify=False): super(FileSystemStore, self).__init__() self.source = FileSystemSource(stix_dir=stix_dir) - self.sink = FileSystemSink(stix_dir=stix_dir) + self.sink = FileSystemSink(stix_dir=stix_dir, bundlify=bundlify) class FileSystemSink(DataSink): @@ -46,12 +47,15 @@ class FileSystemSink(DataSink): components of a FileSystemStore. Args: - stix_dir (str): path to directory of STIX objects + stix_dir (str): path to directory of STIX objects. + bundlify (bool): Whether to wrap objects in bundles when saving them. + Default: False. """ - def __init__(self, stix_dir): + def __init__(self, stix_dir, bundlify=False): super(FileSystemSink, self).__init__() self._stix_dir = os.path.abspath(stix_dir) + self.bundlify = bundlify if not os.path.exists(self._stix_dir): raise ValueError("directory path for STIX data does not exist") @@ -60,6 +64,20 @@ class FileSystemSink(DataSink): def stix_dir(self): return self._stix_dir + def _check_path_and_write(self, stix_obj): + """Write the given STIX object to a file in the STIX file directory. + """ + path = os.path.join(self._stix_dir, stix_obj["type"], stix_obj["id"] + ".json") + + if not os.path.exists(os.path.dirname(path)): + os.makedirs(os.path.dirname(path)) + + if self.bundlify: + stix_obj = Bundle(stix_obj) + + with open(path, "w") as f: + f.write(str(stix_obj)) + def add(self, stix_data=None, allow_custom=False): """Add STIX objects to file directory. @@ -76,18 +94,9 @@ class FileSystemSink(DataSink): the Bundle contained, but not the Bundle itself. """ - def _check_path_and_write(stix_dir, stix_obj): - path = os.path.join(stix_dir, stix_obj["type"], stix_obj["id"] + ".json") - - if not os.path.exists(os.path.dirname(path)): - os.makedirs(os.path.dirname(path)) - - with open(path, "w") as f: - f.write(str(stix_obj)) - if isinstance(stix_data, (STIXDomainObject, STIXRelationshipObject, MarkingDefinition)): # adding python STIX object - _check_path_and_write(self._stix_dir, stix_data) + self._check_path_and_write(stix_data) elif isinstance(stix_data, (str, dict)): stix_data = parse(stix_data, allow_custom) @@ -97,7 +106,7 @@ class FileSystemSink(DataSink): self.add(stix_obj) else: # adding json-formatted STIX - _check_path_and_write(self._stix_dir, stix_data) + self._check_path_and_write(stix_data) elif isinstance(stix_data, Bundle): # recursively add individual STIX objects diff --git a/stix2/test/test_bundle.py b/stix2/test/test_bundle.py index 12b2149..24bbd43 100644 --- a/stix2/test/test_bundle.py +++ b/stix2/test/test_bundle.py @@ -164,5 +164,4 @@ def test_stix_object_property(): prop = stix2.core.STIXObjectProperty() identity = stix2.Identity(name="test", identity_class="individual") - assert prop.clean(identity) == identity assert prop.clean(identity) is identity diff --git a/stix2/test/test_filesystem.py b/stix2/test/test_filesystem.py index 8b9aa22..1e79d05 100644 --- a/stix2/test/test_filesystem.py +++ b/stix2/test/test_filesystem.py @@ -255,6 +255,24 @@ def test_filesystem_store_add(fs_store): os.remove(os.path.join(FS_PATH, "campaign", camp1_r.id + ".json")) +def test_filesystem_store_add_as_bundle(): + fs_store = FileSystemStore(FS_PATH, bundlify=True) + + camp1 = Campaign(name="Great Heathen Army", + objective="Targeting the government of United Kingdom and insitutions affiliated with the Church Of England", + aliases=["Ragnar"]) + fs_store.add(camp1) + + with open(os.path.join(FS_PATH, "campaign", camp1.id + ".json")) as bundle_file: + assert '"type": "bundle"' in bundle_file.read() + + camp1_r = fs_store.get(camp1.id) + assert camp1_r.id == camp1.id + assert camp1_r.name == camp1.name + + shutil.rmtree(os.path.join(FS_PATH, "campaign"), True) + + def test_filesystem_add_bundle_object(fs_store): bundle = Bundle() fs_store.add(bundle) From 612f2fbab8e607abd44efb5610184aaadf6ef23f Mon Sep 17 00:00:00 2001 From: Chris Lenk Date: Fri, 27 Oct 2017 15:50:43 -0400 Subject: [PATCH 17/19] Increase code coverage for filesystem datastore Found a couple bugs in the process and fixed them, too. --- stix2/sources/filesystem.py | 16 +++++------ stix2/sources/memory.py | 4 +-- stix2/test/test_filesystem.py | 54 +++++++++++++++++++++++++++++++++++ stix2/utils.py | 9 ++++-- 4 files changed, 70 insertions(+), 13 deletions(-) diff --git a/stix2/sources/filesystem.py b/stix2/sources/filesystem.py index 9fd658d..34dbcf0 100644 --- a/stix2/sources/filesystem.py +++ b/stix2/sources/filesystem.py @@ -119,9 +119,9 @@ class FileSystemSink(DataSink): self.add(stix_obj) else: - raise ValueError("stix_data must be a STIX object (or list of), " - "json formatted STIX (or list of), " - "or a json formatted STIX bundle") + raise TypeError("stix_data must be a STIX object (or list of), " + "JSON formatted STIX (or list of), " + "or a JSON formatted STIX bundle") class FileSystemSource(DataSource): @@ -198,8 +198,8 @@ class FileSystemSource(DataSource): """Search and retrieve STIX objects based on the complete query. A "complete query" includes the filters from the query, the filters - attached to MemorySource, and any filters passed from a - CompositeDataSource (i.e. _composite_filters) + attached to this FileSystemSource, and any filters passed from a + CompositeDataSource (i.e. _composite_filters). Args: query (list): list of filters to search on @@ -222,7 +222,7 @@ class FileSystemSource(DataSource): if not isinstance(query, list): # make sure dont make set from a Filter object, # need to make a set from a list of Filter objects (even if just one Filter) - query = list(query) + query = [query] query = set(query) # combine all query filters @@ -267,8 +267,8 @@ class FileSystemSource(DataSource): # so query will look in all STIX directories that are not # the specified type. Compile correct dir paths for dir in os.listdir(self._stix_dir): - if os.path.abspath(dir) not in declude_paths: - include_paths.append(os.path.abspath(dir)) + if os.path.abspath(os.path.join(self._stix_dir, dir)) not in declude_paths: + include_paths.append(os.path.abspath(os.path.join(self._stix_dir, dir))) # grab stix object ID as well - if present in filters, as # may forgo the loading of STIX content into memory diff --git a/stix2/sources/memory.py b/stix2/sources/memory.py index 0846f9b..ec44dba 100644 --- a/stix2/sources/memory.py +++ b/stix2/sources/memory.py @@ -260,8 +260,8 @@ class MemorySource(DataSource): """Search and retrieve STIX objects based on the complete query. A "complete query" includes the filters from the query, the filters - attached to MemorySource, and any filters passed from a - CompositeDataSource (i.e. _composite_filters) + attached to this MemorySource, and any filters passed from a + CompositeDataSource (i.e. _composite_filters). Args: query (list): list of filters to search on diff --git a/stix2/test/test_filesystem.py b/stix2/test/test_filesystem.py index 1e79d05..7aaa3f5 100644 --- a/stix2/test/test_filesystem.py +++ b/stix2/test/test_filesystem.py @@ -40,6 +40,18 @@ def fs_sink(): shutil.rmtree(os.path.join(FS_PATH, "campaign"), True) +def test_filesystem_source_nonexistent_folder(): + with pytest.raises(ValueError) as excinfo: + FileSystemSource('nonexistent-folder') + assert "for STIX data does not exist" in str(excinfo) + + +def test_filesystem_sink_nonexistent_folder(): + with pytest.raises(ValueError) as excinfo: + FileSystemSink('nonexistent-folder') + assert "for STIX data does not exist" in str(excinfo) + + def test_filesytem_source_get_object(fs_source): # get object mal = fs_source.get("malware--6b616fc1-1505-48e3-8b2c-0d19337bff38") @@ -47,6 +59,11 @@ def test_filesytem_source_get_object(fs_source): assert mal.name == "Rover" +def test_filesytem_source_get_nonexistent_object(fs_source): + ind = fs_source.get("indicator--6b616fc1-1505-48e3-8b2c-0d19337bff38") + assert ind is None + + def test_filesytem_source_all_versions(fs_source): # all versions - (currently not a true all versions call as FileSystem cant have multiple versions) id_ = fs_source.get("identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5") @@ -240,6 +257,33 @@ def test_filesystem_store_query(fs_store): assert "tool--03342581-f790-4f03-ba41-e82e67392e23" in [tool.id for tool in tools] +def test_filesystem_store_query_single_filter(fs_store): + query = Filter("labels", "in", "tool") + tools = fs_store.query(query) + assert len(tools) == 2 + assert "tool--242f3da3-4425-4d11-8f5c-b842886da966" in [tool.id for tool in tools] + assert "tool--03342581-f790-4f03-ba41-e82e67392e23" in [tool.id for tool in tools] + + +def test_filesystem_store_empty_query(fs_store): + results = fs_store.query() # returns all + assert len(results) == 26 + assert "tool--242f3da3-4425-4d11-8f5c-b842886da966" in [obj.id for obj in results] + assert "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" in [obj.id for obj in results] + + +def test_filesystem_store_query_multiple_filters(fs_store): + fs_store.source.filters.add(Filter("labels", "in", "tool")) + tools = fs_store.query(Filter("id", "=", "tool--242f3da3-4425-4d11-8f5c-b842886da966")) + assert len(tools) == 1 + assert tools[0].id == "tool--242f3da3-4425-4d11-8f5c-b842886da966" + + +def test_filesystem_store_query_dont_include_type_folder(fs_store): + results = fs_store.query(Filter("type", "!=", "tool")) + assert len(results) == 24 + + def test_filesystem_store_add(fs_store): # add() camp1 = Campaign(name="Great Heathen Army", @@ -278,6 +322,16 @@ def test_filesystem_add_bundle_object(fs_store): fs_store.add(bundle) +def test_filesystem_store_add_invalid_object(fs_store): + ind = ('campaign', 'campaign--111111b6-1112-4fb0-111b-b111107ca70a') # tuple isn't valid + with pytest.raises(TypeError) as excinfo: + fs_store.add(ind) + assert 'stix_data must be' in str(excinfo.value) + assert 'a STIX object' in str(excinfo.value) + assert 'JSON formatted STIX' in str(excinfo.value) + assert 'JSON formatted STIX bundle' in str(excinfo.value) + + def test_filesystem_object_with_custom_property(fs_store): camp = Campaign(name="Scipio Africanus", objective="Defeat the Carthaginians", diff --git a/stix2/utils.py b/stix2/utils.py index 8df4323..4623f28 100644 --- a/stix2/utils.py +++ b/stix2/utils.py @@ -34,7 +34,7 @@ class STIXdatetime(dt.datetime): def deduplicate(stix_obj_list): - """Deduplicate a list of STIX objects to a unique set + """Deduplicate a list of STIX objects to a unique set. Reduces a set of STIX objects to unique set by looking at 'id' and 'modified' fields - as a unique object version @@ -44,7 +44,6 @@ def deduplicate(stix_obj_list): of deduplicate(),that if the "stix_obj_list" argument has multiple STIX objects of the same version, the last object version found in the list will be the one that is returned. - () Args: stix_obj_list (list): list of STIX objects (dicts) @@ -56,7 +55,11 @@ def deduplicate(stix_obj_list): unique_objs = {} for obj in stix_obj_list: - unique_objs[(obj['id'], obj['modified'])] = obj + try: + unique_objs[(obj['id'], obj['modified'])] = obj + except KeyError: + # Handle objects with no `modified` property, e.g. marking-definition + unique_objs[(obj['id'], obj['created'])] = obj return list(unique_objs.values()) From 4ffad6d34f8312be837e3b241f7331495f613000 Mon Sep 17 00:00:00 2001 From: Chris Lenk Date: Fri, 27 Oct 2017 16:01:51 -0400 Subject: [PATCH 18/19] Remove stix2-validator dependency Fixes #94. --- .isort.cfg | 1 - setup.py | 1 - 2 files changed, 2 deletions(-) diff --git a/.isort.cfg b/.isort.cfg index f55fec7..d535851 100644 --- a/.isort.cfg +++ b/.isort.cfg @@ -9,7 +9,6 @@ known_third_party = simplejson six, stix2patterns, - stix2validator, taxii2client, known_first_party = stix2 force_sort_within_sections = 1 diff --git a/setup.py b/setup.py index e359147..75b5a43 100644 --- a/setup.py +++ b/setup.py @@ -53,7 +53,6 @@ setup( 'simplejson', 'six', 'stix2-patterns', - 'stix2-validator', 'taxii2-client', ], ) From d8e4f1ab98b32b8492fbb6f36d30a3cddf5ac770 Mon Sep 17 00:00:00 2001 From: = Date: Tue, 31 Oct 2017 13:48:31 -0400 Subject: [PATCH 19/19] addessing requested changes --- docs/guide/taxii.ipynb | 2 +- stix2/sources/taxii.py | 11 +++-------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/docs/guide/taxii.ipynb b/docs/guide/taxii.ipynb index d44b12e..016f9d8 100644 --- a/docs/guide/taxii.ipynb +++ b/docs/guide/taxii.ipynb @@ -110,7 +110,7 @@ "from taxii2client import Collection\n", "\n", "# establish TAXII2 Collection instance\n", - "collection = Collection(\"http://127.0.0.1:5000/trustgroup1/collections/91a7b528-80eb-42ed-a74d-c6fbd5a26116/\", user=\"admin\", password=\"password\")\n", + "collection = Collection(\"http://127.0.0.1:5000/trustgroup1/collections/91a7b528-80eb-42ed-a74d-c6fbd5a26116/\", user=\"admin\", password=\"Password0\")\n", "# supply the TAXII2 collection to TAXIICollection\n", "tc_source = TAXIICollectionSource(collection)\n", "\n", diff --git a/stix2/sources/taxii.py b/stix2/sources/taxii.py index 5dcd9f2..4c659ed 100644 --- a/stix2/sources/taxii.py +++ b/stix2/sources/taxii.py @@ -1,10 +1,5 @@ """ -Python STIX 2.x -Classes: - TAXIICollectionStore - TAXIICollectionSink - TAXIICollectionSource - +Python STIX 2.x TaxiiCollectionStore """ from stix2.base import _STIXBase @@ -122,7 +117,7 @@ class TAXIICollectionSource(DataSource): # as directly retrieveing a STIX object by ID stix_objs = self.collection.get_object(stix_id)["objects"] - stix_obj = [apply_common_filters(stix_objs, query)] + stix_obj = list(apply_common_filters(stix_objs, query)) if len(stix_obj): stix_obj = parse(stix_obj[0]) @@ -190,7 +185,7 @@ class TAXIICollectionSource(DataSource): if not isinstance(query, list): # make sure dont make set from a Filter object, # need to make a set from a list of Filter objects (even if just one Filter) - query = list(query) + query = [query] query = set(query) # combine all query filters