This tool allows the user to create a .json formatted CASE Bundle and add entities from the CASE and UCO ontologies. Work on it begun in 2020 as part of the INSPECTr project which received funding from the European Union’s Horizon 2020 research and innovation programme, under grant agreement No 833276. It was created for the internal purposes of the project and originally named CASE Builder. It was developed by Ray Genoe, Cormac Doherty, and Robert Dowdall of UCD - Centre for Cybersecurity and Cybercrime Investigation and Panos Protopapas of Inlecom Innovation. Throughout the development process Fabrizio Turchi of CNR aided the development by raising issues relating to (i) the creation of new CASE/UCO entities and (ii) changes that would make the tool more "CASE compliant".
In a nutshell, in order to create a CASE file you need to:
The central part of the codebase is located inside base.py that contains two classes (FacetEntity
, ObjectEntity
) and a helper function:
FacetEntity
is the class that all ontology classes are inheriting from either directly (in the case of facet-classes) or through ObjectEntity
(in the case of object-classes). FacetEntity
includes all the type checking (e.g., that int
types are provided where integers are expected according to the ontology) as well as error handling when incorrect data-types are passed.ObjectEntity
inherits FacetEntity
and adds an @id
value (random generated uuid4 string) to all classes inheriting from it. It also provides methods to append facet-classes to an object-class.Moreover, all modules within the case and uco folders include a directory
variable; a dictionary returning a class object when provided with the class's type (the classes @type
value). The directory.py module then aggregates all these variables and can be imported by the user and used when they require to create classes based on their type.
All instructions below follow the CASE bundle creation example provided in example.py which can be run via
python3 example.py
. Note that at any point in the example printing an object will return the object's contents (as a pretty-printed dictionary).
Import the package. This will provide access to the uco
and case
libraries where all object classses are located. The naming of all UCO and CASE classes follows that found in the equivalent ontologies, e.g., the Bundle
class found in uco-core of the UCO ontology, is provided at uco.core.Bundle
in the builder.
from case_mapping import *
Generate a CASE Bundle by calling on the Bundle
object from uco.core
, adding an (optional) uco_core_name
. Also create an empty array where the
investigative items will be appended at.
bundle = uco.core.Bundle(uco_core_name="A Deepthought Case File")
investigation_items = []
To report an observable (a device in this example) create an Observable Object (cyber_item1
) and a Device Facet (device1
) and append the facet to the object. Finally, add
the observable (and appended facet) to the bundle.
cyber_item1 = uco.observable.ObservableObject()
device1 = uco.observable.FacetDevice(manufacturer="Canon", model="PowerShot SX540")
cyber_item1.append_facets(device1)
bundle.append_to_uco_object(cyber_item1)
To report the existence, contents, and related metadata of a paricular file in the Bundle, create an observable and
append it to the array of investigation_items
. Create a File Facet, a Content Data Facet, a Raster Picture Facet,
and an EXIF Data Facet, and append all to the observable. Finally, add the observable to the bundle.
cyber_item2 = uco.observable.ObservableObject()
investigation_items.append(cyber_item2) # NOTE: Appending whole object not just id
file1 = uco.observable.FacetFile(file_system_type="EXT4", file_name="IMG_0123.jpg", file_path="/sdcard/ImG_0123.jpg",
file_extension="jpg", size_bytes=35002)
file_content1 = uco.observable.FacetContentData(byte_order="BigEndian", magic_number="/9j/ww==",
mime_type="image/jpg", size_bytes=35000,
data_payload="<base 64 encoded data of the file>",
hash_method="SHA256",
hash_value="6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b")
file_raster1 = uco.observable.FacetRasterPicture(picture_type="jpg", picture_height=12345, picture_width=12346, bits_per_pixel=2)
exif = {"Make": "Canon", "Model": "Powershot"}
file_exif1 = uco.observable.FacetEXIF(**exif)
cyber_item2.append_facets(file1, file_content1, file_raster1, file_exif1)
bundle.append_to_uco_object(cyber_item2)
To report an investigative action performed on a particular observable (a device in this example), create an
Investigation Action and as before, append it to the investigation items
. Append to the investigative action an Action Reference Facet and a
Device Facet.
inv_act = case.investigation.InvestigativeAction(name="annotated", end_time="2010-01-15T18:59:43.25Z", start_time="2010-01-15T17:59:43.25Z")
investigation_items.append(inv_act) # NOTE: Appending whole object not just id
action_ref = uco.action.FacetActionReferences(performer="Dave", instrument="DiskAnalysisTool", environment="Lab", location="Dublin")
device2 = uco.observable.FacetDevice(device_type="iphone", manufacturer="apple", model="6XS", serial="77")
inv_act.append_facets(action_ref, device2)
bundle.append_to_uco_object(inv_act)
To report the relationship between two observables, create a Cyber Relationship betweemn them and add it to the Bundle.
cyber_rel1 = uco.observable.CyberRelationship(source=cyber_item1, # created previously in the example
target=cyber_item2, # created previously in the example
kind_of_relationship="Contained_Within")
path_rel1 = uco.observable.FacetPathRelation(path="/sdcard/IMG_0123.jpg")
cyber_rel1.append_facets(path_rel1)
bundle.append_to_uco_object(cyber_rel1)
For each e-mail account that must be reported, first create an observable appending to it an Email Address Facet. Then,
Then create a second observable appending to it an Email Account Facet, where when creating the latter you indicate the initial
"Email Address" observable as an email_address
.
email_address_object_1 = uco.observable.ObservableObject()
email_address_1 = uco.observable.FacetEmailAddress(email_address_value="test@test.com", display_name="George Test")
email_address_object_1.append_facets(email_address_1)
email_account_object_1 = uco.observable.ObservableObject()
account_1 = uco.observable.FacetEmailAccount(email_address=email_address_object_1)
email_account_object_1.append_facets(account_1)
bundle.append_to_uco_object(email_account_object_1)
To report an e-mail message, append an Email Message Facet to an observable, and append the latter to the Bundle.
cyber_item3 = uco.observable.ObservableObject()
email_msg = uco.observable.FacetEmailMessage(msg_to=[email_address_object_1, email_address_object_2],
msg_from=email_address_object_1,
subject="Revenge our father",
body="To me, too, grant this boon-dark death to "
"deal unto Aegisthus, and to 'scape my doom.",
received_time="2017-06-21T13:44:23.40Z",
sent_time="2017-06-21T13:44:22.19Z",
message_id="CAKBqNfyKo+ZXtkz6DUjWpvHy6"
"O82jTbkNA@mail.gmail.com")
cyber_item3.append_facets(email_msg)
bundle.append_to_uco_object(cyber_item3)
A phone number (or sms account) can be reported by appending a Phone Account Facet to an observable.
phone_account_object = uco.observable.ObservableObject()
phone_account1 = uco.observable.FacetPhoneAccount(phone_number="0035397876543")
phone_account_object.append_facets(phone_account1)
bundle.append_to_uco_object(phone_account_object)
An sms message can be reported by appending to an observable a Message Facet where the sender and receiver(s) of the
sms message are reported by passing the observable objects holding the corresponding phone accounts as msg_to
and msg_from
properties;
similarly, the application
property must be filled with an observable object holding an Application Facet.
cyber_item4 = uco.observable.ObservableObject()
application_cyber_item = uco.observable.ObservableObject()
sms_application = uco.observable.FacetApplication(app_name="WhatsApp")
application_cyber_item.append_facets(sms_application)
sms_msg = uco.observable.FacetMessage(msg_to=[phone_account_object, phone_account_object2],
msg_from=phone_account_object,
message_text="A wedded wife, she slays her lord, "
"Helped by another hand!",
sent_time="2017-06-20T09:34:42.12Z",
application=application_cyber_item)
cyber_item4.append_facets(sms_msg)
bundle.append_to_uco_object(cyber_item4)
Reporting the identity of a person is done by first creating an Identity Object and appending to it a Simple Name Facet, and (if known) a Birthday Information Facet.
identity = uco.identity.Identity()
identity_name = uco.identity.FacetSimpleName(given_name="Forename", family_name="Family-name")
identity_birth = uco.identity.FacetBirthInformation(birthdate="01-01-1988")
identity.append_facets(identity_birth, identity_name)
bundle.append_to_uco_object(identity)
To report a location, create a Location Object and append to it a Location Facet.
location1 = uco.location.Location()
lat_long = uco.location.FacetLocation(latitude=61.185055, longitude=9.468836)
location1.append_facets(lat_long)
bundle.append_to_uco_object(location1)
Finally, an Investigation Object is being created where the investigation actions
performed are being reported throught the
core_objects
parameter.
investigation = case.investigation.CaseInvestigation(focus="Transfer of Illicit Materials",
name="Crime A",
description="Inquiry into the transfer of illicit materials and "
"the devices used to do so",
core_objects=investigation_items)
bundle.append_to_uco_object(investigation)