Skip to content

CybOX Design: Object Hierarchy Structuring

Ivan Kirillov edited this page Feb 15, 2016 · 7 revisions

Issue Description

As currently designed, the CybOX Object hierarchy is defined around the ability to create subclasses of its various Objects, as outlined in the diagram below. Here, each arrow (-->) originating from an Object and going to another indicates that the Object at the end of the arrow is a child of its parent.

CybOX Object Subclasses

There are three main issues that exist around this implementation:

  • Excessive sub-classing. Objects such as the Windows Driver are three levels deep in their respective class hierarchy, which means that changes to any of their parents cascade to their "leaf" Objects. Accordingly, this makes maintenance and versioning difficult, as it means that the version of any "leaf" Objects needs to be updated in conjunction with their parents. Also, if one considers the future potential for CybOX to incorporate additional types of system-specific Objects (e.g., Android, iOS), etc., this could lead to even more complicated and deep Object hierarchies.
  • Inconsistent class-based design. Currently, CybOX is inconsistent with the way it uses sub-classing in its Objects. For instance, there are cases (such as with the Windows Thread Object) where a parent Object should be defined (i.e., a Thread Object) to serve as the base class and yet is not. Conversely, there are cases where a parent Object is defined only to serve as a base class and is unlikely to be ever used by itself, such as with the GUI Object.
  • Restrictive classing. The nature of sub-classing means that when creating content, an Object is either an instance of one class or another - it cannot be both. For instance, one cannot currently define an instance of an Archive File with Windows-specific properties, since these Objects do not inherit from each other.

Potential Refactoring

As we see it, there are two possible avenues that we could take for solving this issue:

  • Keep the class-based approach, and fix the issues around the inconsistent class-based design by refactoring the existing Objects as necessary. Develop a set of guidelines as to when sub-classes should be defined, and potentially set a hard-limit on the maximum depth of any Object hierarchy. However, the issue of restrictive classing would still remain.
  • Adopt an extension-based approach, as outlined in the File Object Refactoring proposal. This would do away with the existing class-based design, and instead "flatten" the existing CybOX Object model in favor of one without any subclassing. This would solve the issues outlined above, but would represent a significant departure in CybOX design.

Accordingly, since these two approaches are incompatible with each other, as they offer different models for handling complex Objects, there is a need to define one approach for the future of CybOX. Given its potential benefits as outlined above, this proposal will focus on the specifics of refactoring the CybOX Objects into an extension-based model.

Extension-based Approach

The key principles of the extension-based approach are the following:

  • Only a single base Object will exist for each type of Object. Wherever possible, this Object will be platform/implementation agnostic, so that any platform or implementation specific properties can be covered by extensions.
  • Extensions specific to a platform or implementation can be defined for each base Object.
    • Extensions may be mutually exclusive in CybOX instances, so that conflicting sets of extensions cannot be defined.
    • Extensions may not inherit from each other.

Object Model

Another important aspect of this approach is the refactoring the existing CybOX Object model into one where a single "base" Object is defined for each type of Object that we wish to characterize in CybOX. Each such "base" Object will have its default set of properties and may have 0-N extensions, for defining properties that may be specific to an implementation, platform, or domain:

  • Object
    • Properties
    • Extensions [0-N]

Note: the Object model would include other fields that are currently present, such as Location and Description; these are not covered here for the sake of simplicity and provide focus to the concept of extensions.

Object Hierarchy

Given this approach, the CybOX Object Hierarchy would notionally look like the following. Note that this also incorporates some of the proposed refactoring around the File and Address Object, as well as some changes to address the existing inconsistencies in the class-based design along with those documented in the issue tracker. Extensions are italicized; new or modified Objects are highlighted in bold.

  • API
  • ARP Cache
  • AS
  • Account
    • User Account Extension
    • Computer Account Extension
    • Unix Account Extension
    • Unix User Account Extension
    • Windows User Account Extension
  • IP Address
  • IPv6 Address
  • IPv4 Address
  • MAC Address
  • Email Address
  • File
    • File Metadata Extension
    • EXT3 File Extension
    • NTFS File Extension
    • Image File Extension
    • PDF File Extension
    • Archive File Extension
    • PE Binary File Extension
    • Library File Extension
    • Linux Package Extension
    • Windows Driver Extension
  • Artifact
  • Code
  • Custom
  • DNS Cache
  • DNS Query
  • DNS Response
  • DNS Record
  • Device
    • Disk Device Extension
  • Disk Partition
  • Domain Name
  • Email Message
  • GUI Dialogbox
  • GUI Window
  • HTTP Request
  • HTTP Response
  • Memory
    • Windows Memory Page Region Extension
  • Mutex
    • Windows Mutex Extension
  • Network Connection
  • Network Flow
  • Network Packet
  • Network Route Entry
    • Unix Network Route Entry Extension
    • Windows Network Route Entry Extension
  • Network Route
  • Network Socket
  • Network Subnet
  • Pipe
    • Unix Pipe Extension
    • Windows Pipe Extension
  • Process
    • Unix Process Extension
    • Windows Process Extension
    • Windows Service Extension
  • Product
  • SMS Message
  • Semaphore
    • Windows Semaphore Extension
  • Socket Address
  • System
    • Windows System Extension
  • Thread
    • Windows Thread Extension
  • URI
  • URL History
  • User Session
  • Volume
    • Unix Volume Extension
    • Windows Volume Extension
  • Windows Critical Section
  • Windows Event Log
  • Windows Event
  • Windows Filemapping
  • Windows Handle
  • Windows Hook
  • Windows Kernel Hook
  • Windows Kernel
  • Windows Mailslot
  • Windows Network Share
  • Windows Registry Key
  • Windows System Restore
  • Windows Task
  • Windows Waitable Timer
  • X509 Certificate

As a comparison to CybOX v2.1, here are some raw numbers:

CybOX v2.1

  • Number of Objects: 87
  • Number of Extensions: 0

CybOX v3.0

  • Number of Objects: 61
  • Number of Extensions: 30

Potential Issues/Open Questions

While we feel that this approach is a substantial improvement over the existing sub-classing approach in flexibility and simplicity, there are a few potential issues around it worth noting:

  • Duplicate fields. In some cases with conceptually related Objects, such as with the GUI Objects, because there is no longer Object inheritance, there may exist some duplicate fields. Note that this is in rare cases where it does not make sense to define a "base" Object because it is too abstract.
  • Additional verbosity in content. With the sub-class based approach, all properties of an Object instance are defined inline, as they are inherited from their parent Object. With the extension-based approach, any properties that are part of an extension need to be defined separately, likely in their own structure, leading to slightly more verbose content.

There are also a few important open questions around extensions:

  • Extension management - how should extensions be managed?
    • Should they be defined as part of an Object schema, e.g., all File extensions would live in the File Object schema?
    • Should they be defined separately and imported by their respective Object schema, e.g., the ntfs_file_extension.json would be imported by file.json?
    • Comments: defining extensions in separate Object schemas would offer the greatest flexibility, and so may make the most sense.
  • Base Object/Extension versioning - how should base Objects and extensions be versioned?
    • Should extensions be versioned separately from Base Objects?
      • If so, does updating an extension necessitate an update to the version of the Base Object?
    • Comments: extensions may be updated individually, so it would probably make sense to version them separately from their base Object.
  • How should mutually exclusive extensions be handled?
    • Should it be done at a schema/structural level, or at a specification/documentation level (or both)?
    • Comments: looking at the example below, it appears likely that they could be handled at the JSON schema level, although this entails a dependency between the base Object and its extensions.
  • How would extensions work with patterning?
    • Comments: given the proposed 'flattened' approach to referencing Object properties in a pattern with a single string, it's likely that extensions can be handled in a similar way, e.g. File/EXT3FileExtension/inode.
  • Should we allow for custom extensions (including those based on existing ones)?
    • Comments: given that we support custom Objects given the existing approach, it would follow that we should support custom extensions as well.

Example

As an example, here's how the Volume Object and its extensions could be defined using this approach. Note that this make a number of assumptions:

  • For the extensions, there is no inheritance from a base ObjectExtension object, since this would conflict with the use of the additionalProperties statement, allowing any arbitrary content to be embedded in the Object.
  • Mutual exclusion of extensions is handled at the specification level and not JSON schema level.

JSON Schema

{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "definitions": {
        "Object": {
            "type": "object",
            "properties": {"id": {"type": "string"}},
            "required": ["id"]
        },
        "Volume": {
            "type": "object",
            "properties": {
                "is_mounted": {"type": "boolean"},
                "name": {"type": "string"},
                "device_path": {"type": "string"},
                "file_system_type": {"type": "string"},
                "total_allocation_units": {"type": "number"},
                "sectors_per_allocation_unit": {"type": "number"},
                "bytes_per_sector": {"type": "number"},
                "actual_available_allocation_units": {"type": "number"},
                "creation_time": {"type": "string"},
                "serial_number": {"type": "string"},
                "extended_properties": {"type": "object"}
            },
            "allOf": [{"$ref": "#/definitions/Object"}]
        },
        "UnixVolumeExtension": {
            "type": "object",
            "properties": {
                "mount_point": {"type": "string"},
                "options": {"type": "string"}
            },
            "additionalProperties": false
        },
        "WindowsVolumeExtension": {
            "type": "object",
            "properties": {
                "drive_letter": {"type": "string"},
                "drive_type": {"type": "string"}
            },
            "additionalProperties": false
        }
    },
    "properties": {"Volume": {"$ref": "#/definitions/Volume"}}
}

Example Instance

{"Volume": {
    "id": "object-1",
    "is_mounted": false,
    "device_name": "disk1",
    "serial_number": "12345FFA",
    "extended_properties": {
        "WindowsVolumeExtension": {"drive_letter": "c"},
        "UnixVolumeExtension": {"mount_point": "/ext/tst"},
        "CustomExtension":{"foo":"bar"}
    }
}}
Clone this wiki locally