Skip to content

casework/CASE-Mapping-Python

Repository files navigation

CASE Mapping Python

About the purpose and origins of this tool

INSPECTr Logo

EU Flag





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".

Usage

In a nutshell, in order to create a CASE file you need to:

  • Create Facets describing all the information you'd like to record (Device Facets to describe devices, Email Address Facets to describe email addresses, etc.).
  • Append Facets to Objects that "enclose" them. The type of object depends on the facet; e.g, a Device Facet should be enclosed by an Observable Object. More than one Facet can be enclosed by the same object. For example, an Investigative Action Object can enclose both a Device Facet and an Action Facet (describing an investigative action performed on the device).
  • Append Objects to a CASE Bundle.

Codebase Structure

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.
  • All classes included within all modules in the case and uco folders inherit from either of these two classes, depending on whether these are facets or objects.

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.

Example Usage

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)