def test_custom_property_dict_in_observable_extension(): with pytest.raises(stix2.exceptions.ExtraPropertiesError): artifact = stix2.File( name='test', extensions={'ntfs-ext': { 'sid': 1, 'x_foo': 'bar', }}, ) artifact = stix2.File( allow_custom=True, name='test', extensions={ 'ntfs-ext': { 'allow_custom': True, 'sid': 1, 'x_foo': 'bar', } }, ) observed_data = stix2.ObservedData( allow_custom=True, first_observed="2015-12-21T19:00:00Z", last_observed="2015-12-21T19:00:00Z", number_observed=0, objects={"0": artifact}, ) assert observed_data.objects['0'].extensions['ntfs-ext'].x_foo == "bar" assert '"x_foo": "bar"' in str(observed_data)
def test_file_example_encryption_error(): with pytest.raises(stix2.exceptions.DependentPropertiesError) as excinfo: stix2.File(name="qwerty.dll", is_encrypted=False, encryption_algorithm="AES128-CBC") assert excinfo.value.cls == stix2.File assert excinfo.value.dependencies == [("is_encrypted", "encryption_algorithm")] assert "property dependencies" in str(excinfo.value) assert "are not met" in str(excinfo.value) with pytest.raises(stix2.exceptions.DependentPropertiesError) as excinfo: stix2.File(name="qwerty.dll", encryption_algorithm="AES128-CBC")
def test_file_example_with_empty_NTFSExt(): with pytest.raises(stix2.exceptions.AtLeastOnePropertyError) as excinfo: stix2.File(name="abc.txt", extensions={"ntfs-ext": {}}) assert excinfo.value.cls == stix2.NTFSExt assert excinfo.value.properties == sorted( list(stix2.NTFSExt._properties.keys()))
def test_file_example(): f = stix2.File( name="qwerty.dll", hashes={ "SHA-256": "ceafbfd424be2ca4a5f0402cae090dda2fb0526cf521b60b60077c0f622b285a" }, size=100, magic_number_hex="1C", mime_type="application/msword", created="2016-12-21T19:00:00Z", modified="2016-12-24T19:00:00Z", accessed="2016-12-21T20:00:00Z", is_encrypted=True, encryption_algorithm="AES128-CBC", decryption_key="fred") assert f.name == "qwerty.dll" assert f.size == 100 assert f.magic_number_hex == "1C" assert f.hashes[ "SHA-256"] == "ceafbfd424be2ca4a5f0402cae090dda2fb0526cf521b60b60077c0f622b285a" assert f.mime_type == "application/msword" assert f.created == dt.datetime(2016, 12, 21, 19, 0, 0, tzinfo=pytz.utc) assert f.modified == dt.datetime(2016, 12, 24, 19, 0, 0, tzinfo=pytz.utc) assert f.accessed == dt.datetime(2016, 12, 21, 20, 0, 0, tzinfo=pytz.utc) assert f.is_encrypted assert f.encryption_algorithm == "AES128-CBC" assert f.decryption_key == "fred" # does the key have a format we can test for?
def test_custom_extension_wrong_observable_type(): ext = NewExtension(property1='something') with pytest.raises(ValueError) as excinfo: stix2.File(name="abc.txt", extensions={ "ntfs-ext": ext, }) assert 'Cannot determine extension type' in excinfo.value.reason
def test_custom_property_in_observed_data(): artifact = stix2.File(allow_custom=True, name='test', x_foo='bar') observed_data = stix2.ObservedData( allow_custom=True, first_observed="2015-12-21T19:00:00Z", last_observed="2015-12-21T19:00:00Z", number_observed=0, objects={"0": artifact}, ) assert observed_data.objects['0'].x_foo == "bar" assert '"x_foo": "bar"' in str(observed_data)
def test_file_example_with_NTFSExt(): f = stix2.File(name="abc.txt", extensions={ "ntfs-ext": { "alternate_data_streams": [{ "name": "second.stream", "size": 25536 }] } }) assert f.name == "abc.txt" assert f.extensions["ntfs-ext"].alternate_data_streams[0].size == 25536
def test_file_example_with_RasterImageExt_Object(): f = stix2.File(name="qwerty.jpeg", extensions={ "raster-image-ext": { "bits_per_pixel": 123, "exif_tags": { "Make": "Nikon", "Model": "D7000", "XResolution": 4928, "YResolution": 3264 } } }) assert f.name == "qwerty.jpeg" assert f.extensions["raster-image-ext"].bits_per_pixel == 123 assert f.extensions["raster-image-ext"].exif_tags["XResolution"] == 4928
def test_custom_property_object_in_observable_extension(): ntfs = stix2.NTFSExt( allow_custom=True, sid=1, x_foo='bar', ) artifact = stix2.File( name='test', extensions={'ntfs-ext': ntfs}, ) observed_data = stix2.ObservedData( allow_custom=True, first_observed="2015-12-21T19:00:00Z", last_observed="2015-12-21T19:00:00Z", number_observed=0, objects={"0": artifact}, ) assert observed_data.objects['0'].extensions['ntfs-ext'].x_foo == "bar" assert '"x_foo": "bar"' in str(observed_data)
def test_file_example_with_PDFExt_Object(): f = stix2.File(name="qwerty.dll", extensions={ "pdf-ext": stix2.PDFExt( version="1.7", document_info_dict={ "Title": "Sample document", "Author": "Adobe Systems Incorporated", "Creator": "Adobe FrameMaker 5.5.3 for Power Macintosh", "Producer": "Acrobat Distiller 3.01 for Power Macintosh", "CreationDate": "20070412090123-02" }, pdfid0="DFCE52BD827ECF765649852119D", pdfid1="57A1E0F9ED2AE523E313C") }) assert f.name == "qwerty.dll" assert f.extensions["pdf-ext"].version == "1.7" assert f.extensions["pdf-ext"].document_info_dict[ "Title"] == "Sample document"
def test_file_example_with_WindowsPEBinaryExt(): f = stix2.File(name="qwerty.dll", extensions={ "windows-pebinary-ext": { "pe_type": "exe", "machine_hex": "014c", "number_of_sections": 4, "time_date_stamp": "2016-01-22T12:31:12Z", "pointer_to_symbol_table_hex": "74726144", "number_of_symbols": 4542568, "size_of_optional_header": 224, "characteristics_hex": "818f", "optional_header": { "magic_hex": "010b", "major_linker_version": 2, "minor_linker_version": 25, "size_of_code": 512, "size_of_initialized_data": 283648, "size_of_uninitialized_data": 0, "address_of_entry_point": 4096, "base_of_code": 4096, "base_of_data": 8192, "image_base": 14548992, "section_alignment": 4096, "file_alignment": 4096, "major_os_version": 1, "minor_os_version": 0, "major_image_version": 0, "minor_image_version": 0, "major_subsystem_version": 4, "minor_subsystem_version": 0, "win32_version_value_hex": "00", "size_of_image": 299008, "size_of_headers": 4096, "checksum_hex": "00", "subsystem_hex": "03", "dll_characteristics_hex": "00", "size_of_stack_reserve": 100000, "size_of_stack_commit": 8192, "size_of_heap_reserve": 100000, "size_of_heap_commit": 4096, "loader_flags_hex": "abdbffde", "number_of_rva_and_sizes": 3758087646 }, "sections": [{ "name": "CODE", "entropy": 0.061089 }, { "name": "DATA", "entropy": 7.980693 }, { "name": "NicolasB", "entropy": 0.607433 }, { "name": ".idata", "entropy": 0.607433 }] } }) assert f.name == "qwerty.dll" assert f.extensions["windows-pebinary-ext"].sections[2].entropy == 0.607433
def obs_view(request, id): o = ObservableObject.objects.get(id=id) dict = {id: {}} if o.type.model_name: m = apps.get_model(o._meta.app_label, o.type.model_name) o = m.objects.get(id=o.id) s = None refs = [] if o.type.name == "domain-name": for r in o.resolves_to_refs.all(): m = apps.get_model(r._meta.app_label, r.type.model_name) ref = m.objects.get(id=r.id) if ref.type.name == "ipv4-addr": i = stix2.IPv4Address(value=ref.value) dict[ref.id] = json.loads(str(i)) refs.append(str(ref.id)) s = stix2.DomainName(value=o.value, #resolves_to_refs=refs, ) #dict[id] = json.loads(str(s)) #dict[id]["resolves_to_refs"] = refs elif o.type.name == "file": s = stix2.File(name=o.name, ) #dict[id] = json.loads(str(s)) elif o.type.name == "ipv4-addr": s = stix2.IPv4Address(value=o.value, ) elif o.type.name == "url": s = stix2.URL(value=o.value, ) if s: dict[id] = json.loads(str(s)) if refs: dict[id]["resolves_to_refs"] = refs form = getobsform(o.type.name, instance=o) if request.POST: if "update" in request.POST: form = getobsform(o.type.name, instance=o, request=request) if form.is_valid(): if o.type.name in ["file"]: o.name = form.cleaned_data["value"] o.save() else: s = form.save() if o.type.name in ["domain-name"]: new = form.cleaned_data["new_refs"] for line in new.split("\n"): if line: r = create_obs_from_line(line) o.resolve_to_refs.add(r) o.save() objects = [] rels = [] sights = [] observables = [] value = None if hasattr(o, "value"): value = o.value elif hasattr(o, "name"): value = o.name ods = ObservedData.objects.filter(observable_objects=o) for od in ods: for s in Sighting.objects.filter(observed_data_refs=od): for ro in get_related_obj(s): if ro.object_type.name == "sighting": if not ro in sights: sights.append(ro) elif ro.object_type.name == "relationship": if not ro in rels: rels.append(ro) else: if not ro in objects: objects.append(ro) ind = Indicator.objects.filter(pattern__pattern__icontains=value) for i in ind: if not i in objects: objects.append(i) rs = Relationship.objects.filter( source_ref=i.object_id, relationship_type=RelationshipType.objects.get( name="indicates")) for r in rs: if not r in rels: rels.append(r) for tgt in rel.values_list("target_ref", flat=True): t = get_obj_from_id(tgt) if not t in objects: objects.append(t) c = { "obj": o, "type": o.type.name, "form": form, "stix": json.dumps(dict, indent=2), "objects": objects, "rels": rels, "sights": sights, } return render(request, 'base_view.html', c)
def stix_bundle(objs, mask=True): objects = () for obj in objs: oid = obj.object_id.object_id dscr = "" if not mask and hasattr(obj, "description"): dscr = obj.description if obj.object_type.name == 'attack-pattern': a = stix2.AttackPattern( id=oid, name=obj.name, description=dscr, created=obj.created, modified=obj.modified, kill_chain_phases=stix2killchain(obj), ) objects += (a, ) elif obj.object_type.name == 'campaign': c = stix2.Campaign( id=oid, name=obj.name, description=dscr, aliases=[str(a.name) for a in obj.aliases.all()], created=obj.created, modified=obj.modified, first_seen=obj.first_seen, last_seen=obj.last_seen, ) objects += (c, ) elif obj.object_type.name == 'course-of-action': c = stix2.CourseOfAction( id=oid, name=obj.name, description=dscr, created=obj.created, modified=obj.modified, ) objects += (c, ) elif obj.object_type.name == 'identity': name = obj.name if mask: name = oid label = obj.labels.all() if label.count() >= 1: name = str(obj.id) if label[0].alias: name += '-' + label[0].alias else: name += '-' + label[0].value i = stix2.Identity( id=oid, name=name, identity_class=obj.identity_class, description=dscr, sectors=[str(s.value) for s in obj.sectors.all()], labels=[str(l.value) for l in obj.labels.all()], created=obj.created, modified=obj.modified, ) objects += (i, ) elif obj.object_type.name == 'indicator': pattern = "[]" if not mask and obj.pattern: pattern = obj.pattern.pattern i = stix2.Indicator( id=oid, name=obj.name, description=dscr, labels=[str(l.value) for l in obj.labels.all()], pattern=pattern, created=obj.created, modified=obj.modified, valid_from=obj.valid_from, valid_until=obj.valid_until, ) objects += (i, ) elif obj.object_type.name == 'intrusion-set': i = stix2.IntrusionSet( id=oid, name=obj.name, description=dscr, aliases=[str(a.name) for a in obj.aliases.all()], created=obj.created, modified=obj.modified, first_seen=obj.first_seen, #last_seen=obj.last_seen, ) objects += (i, ) elif obj.object_type.name == 'malware': m = stix2.Malware( id=oid, name=obj.name, description=dscr, labels=[str(l.value) for l in obj.labels.all()], created=obj.created, modified=obj.modified, kill_chain_phases=stix2killchain(obj), ) objects += (m, ) elif obj.object_type.name == 'observed-data': obs = {} for o in obj.observable_objects.all(): ob = None if o.type.name == "file": f = FileObject.objects.get(id=o.id) ob = stix2.File(name=f.name) elif o.type.name == "ipv4-addr": i = IPv4AddressObject.objects.get(id=o.id) ob = stix2.IPv4Address(value=i.value) elif o.type.name == "url": u = URLObject.objects.get(id=o.id) ob = stix2.URL(value=u.value) elif o.type.name == "domain-name": dn = DomainNameObject.objects.get(id=o.id) ob = stix2.DomainName(value=dn.value) if ob and not mask: obs[str(o.id)] = json.loads(str(ob)) od = stix2.ObservedData( id=oid, created=obj.created, modified=obj.modified, first_observed=obj.first_observed, last_observed=obj.last_observed, number_observed=obj.number_observed, objects=obs, ) objects += (od, ) elif obj.object_type.name == 'report': created_by = None if obj.created_by_ref: created_by = obj.created_by_ref.object_id r = stix2.Report( id=oid, labels=[str(l.value) for l in obj.labels.all()], name=obj.name, description=dscr, published=obj.published, object_refs=[str(r.object_id) for r in obj.object_refs.all()], created_by_ref=created_by, created=obj.created, modified=obj.modified, ) objects += (r, ) elif obj.object_type.name == 'threat-actor': t = stix2.ThreatActor( id=oid, name=obj.name, description=dscr, labels=[str(l.value) for l in obj.labels.all()], aliases=[str(a.name) for a in obj.aliases.all()], created=obj.created, modified=obj.modified, ) objects += (t, ) elif obj.object_type.name == 'tool': t = stix2.Tool( id=oid, name=obj.name, description=dscr, labels=[str(l.value) for l in obj.labels.all()], created=obj.created, modified=obj.modified, kill_chain_phases=stix2killchain(obj), ) objects += (t, ) elif obj.object_type.name == 'vulnerability': v = stix2.Vulnerability( id=oid, name=obj.name, description=dscr, created=obj.created, modified=obj.modified, ) objects += (v, ) elif obj.object_type.name == 'relationship': r = stix2.Relationship( id=oid, relationship_type=obj.relationship_type.name, description=dscr, source_ref=obj.source_ref.object_id, target_ref=obj.target_ref.object_id, created=obj.created, modified=obj.modified, ) objects += (r, ) elif obj.object_type.name == 'sighting': s = stix2.Sighting( id=oid, sighting_of_ref=obj.sighting_of_ref.object_id, where_sighted_refs=[ str(w.object_id.object_id) for w in obj.where_sighted_refs.all() ], observed_data_refs=[ str(od.object_id.object_id) for od in obj.observed_data_refs.all() ], first_seen=obj.first_seen, last_seen=obj.last_seen, created=obj.created, modified=obj.modified, ) objects += (s, ) bundle = stix2.Bundle(*objects) return bundle