STIX Extensions

This page is specific for the STIX Extensions mechanism defined in STIX 2.1 CS 03. For the deprecated STIX Customization mechanisms see the Custom section.

Top Level Property Extensions

The example below shows how to create an indicator object with a toplevel-property-extension. Because an unregistered toplevel property extension is present, any unrecognized toplevel properties are assumed to be extension properties. So the library lets them pass.

[3]:
import stix2

indicator = stix2.v21.Indicator(
    id='indicator--e97bfccf-8970-4a3c-9cd1-5b5b97ed5d0c',
    created='2014-02-20T09:16:08.989000Z',
    modified='2014-02-20T09:16:08.989000Z',
    name='File hash for Poison Ivy variant',
    description='This file hash indicates that a sample of Poison Ivy is present.',
    labels=[
        'malicious-activity',
    ],
    rank=5,
    toxicity=8,
    pattern='[file:hashes.\'SHA-256\' = \'ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c\']',
    pattern_type='stix',
    valid_from='2014-02-20T09:00:00.000000Z',
    extensions={
        "extension-definition--dd73de4f-a7f3-49ea-8ec1-8e884196b7a8" : {
            'extension_type': 'toplevel-property-extension',
        },
    }
)

print(indicator.serialize(pretty=True))
[3]:
{
    "type": "indicator",
    "spec_version": "2.1",
    "id": "indicator--e97bfccf-8970-4a3c-9cd1-5b5b97ed5d0c",
    "created": "2014-02-20T09:16:08.989Z",
    "modified": "2014-02-20T09:16:08.989Z",
    "name": "File hash for Poison Ivy variant",
    "description": "This file hash indicates that a sample of Poison Ivy is present.",
    "pattern": "[file:hashes.'SHA-256' = 'ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c']",
    "pattern_type": "stix",
    "pattern_version": "2.1",
    "valid_from": "2014-02-20T09:00:00Z",
    "labels": [
        "malicious-activity"
    ],
    "extensions": {
        "extension-definition--dd73de4f-a7f3-49ea-8ec1-8e884196b7a8": {
            "extension_type": "toplevel-property-extension"
        }
    },
    "rank": 5,
    "toxicity": 8
}

Using CustomExtension decorator

However, in order to define which properties are actually included with an extension, the @CustomExtension decorator can be used to register an extension type and its properties with stix2. Use the extension_type class variable to define what kind of extension it is. Then its id can be passed into objects that use this extension.

[4]:
TOPLEVEL_EXTENSION_DEFINITION_ID = 'extension-definition--dd73de4f-a7f3-49ea-8ec1-8e884196b7a8'

@stix2.v21.CustomExtension(
    TOPLEVEL_EXTENSION_DEFINITION_ID, [
        ('rank', stix2.properties.IntegerProperty(required=True)),
        ('toxicity', stix2.properties.IntegerProperty(required=True)),
    ],
)
class ExtensionTopLevel:
    extension_type = 'toplevel-property-extension'

indicator = stix2.v21.Indicator(
    id='indicator--e97bfccf-8970-4a3c-9cd1-5b5b97ed5d0c',
    created='2014-02-20T09:16:08.989000Z',
    modified='2014-02-20T09:16:08.989000Z',
    name='File hash for Poison Ivy variant',
    description='This file hash indicates that a sample of Poison Ivy is present.',
    labels=[
        'malicious-activity',
    ],
    rank=5,
    toxicity=8,
    pattern='[file:hashes.\'SHA-256\' = \'ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c\']',
    pattern_type='stix',
    valid_from='2014-02-20T09:00:00.000000Z',
    extensions={
        TOPLEVEL_EXTENSION_DEFINITION_ID : {
            'extension_type': 'toplevel-property-extension',
        },
    }
)

print(indicator.serialize(pretty=True))
[4]:
{
    "type": "indicator",
    "spec_version": "2.1",
    "id": "indicator--e97bfccf-8970-4a3c-9cd1-5b5b97ed5d0c",
    "created": "2014-02-20T09:16:08.989Z",
    "modified": "2014-02-20T09:16:08.989Z",
    "name": "File hash for Poison Ivy variant",
    "description": "This file hash indicates that a sample of Poison Ivy is present.",
    "pattern": "[file:hashes.'SHA-256' = 'ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c']",
    "pattern_type": "stix",
    "pattern_version": "2.1",
    "valid_from": "2014-02-20T09:00:00Z",
    "labels": [
        "malicious-activity"
    ],
    "extensions": {
        "extension-definition--dd73de4f-a7f3-49ea-8ec1-8e884196b7a8": {
            "extension_type": "toplevel-property-extension"
        }
    },
    "rank": 5,
    "toxicity": 8
}

Using CustomObservable for Extension Definition

Similarly, when registering new objects via @CustomObservable you can pass the extension-definition id that defines this new SCO.

[3]:
@stix2.v21.CustomObservable(
    'my-favorite-sco', [
        ('name', stix2.properties.StringProperty(required=True)),
        ('some_network_protocol_field', stix2.properties.StringProperty(required=True)),
    ], ['name', 'some_network_protocol_field'], 'extension-definition--150c1738-28c9-44d0-802d-70523218240b',
)
class MyFavSCO:
    pass

my_favorite_sco = MyFavSCO(
    id='my-favorite-sco--f9dbe89c-0030-4a9d-8b78-0dcd0a0de874',
    name='This is the name of my favorite SCO',
    some_network_protocol_field='value',
)

print(my_favorite_sco.serialize(pretty=True))
[3]:
{
    "type": "my-favorite-sco",
    "spec_version": "2.1",
    "id": "my-favorite-sco--f9dbe89c-0030-4a9d-8b78-0dcd0a0de874",
    "name": "This is the name of my favorite SCO",
    "some_network_protocol_field": "value",
    "extensions": {
        "extension-definition--150c1738-28c9-44d0-802d-70523218240b": {
            "extension_type": "new-sco"
        }
    }
}

Custom Markings

The example below show how to create a user-defined marking based on an extension. The STIX marking-definition object is essentially a base upon which you build the particulars of your marking, via an extension. This is done in the same way as any other extension. Marking definitions are no different in this regard. The below example illustrates an alternative to building the extension entirely as a dictionary: it can also be built by instantiating the registered class.

[4]:
import stix2
import stix2.properties

MARKING_EXTENSION_ID = 'extension-definition--a932fcc6-e032-176c-126f-cb970a5a1fff'

@stix2.CustomExtension(MARKING_EXTENSION_ID, [
    ('some_marking_field', stix2.properties.StringProperty(required=True))
])
class MyFavMarking:
    extension_type = 'property-extension'

my_favorite_marking = stix2.MarkingDefinition(
    name='This is the name of my favorite Marking',
    extensions={
        MARKING_EXTENSION_ID: MyFavMarking(
            some_marking_field='value'
        )
    }
)

print(my_favorite_marking.serialize(pretty=True))
[4]:
{
    "type": "marking-definition",
    "spec_version": "2.1",
    "id": "marking-definition--9155f07c-dd4c-4320-be6a-0701311c3b84",
    "created": "2021-07-12T00:56:31.47566Z",
    "name": "This is the name of my favorite Marking",
    "extensions": {
        "extension-definition--a932fcc6-e032-176c-126f-cb970a5a1fff": {
            "extension_type": "property-extension",
            "some_marking_field": "value"
        }
    }
}

Using CustomObject for Extension Definition

Similar to the examples above, the same can be done for SDOs and SROs.

[4]:
invalid_refs = ['bundle', 'language-content', 'marking-definition', 'relationship', 'sighting', 'foobar']

@stix2.v21.CustomObject(
    'my-favorite-sro', [
        ('name', stix2.properties.StringProperty(required=False)),
        ('some_source_ref', stix2.properties.ReferenceProperty(invalid_types=invalid_refs, spec_version='2.1', required=True)),
        ('some_target_ref', stix2.properties.ReferenceProperty(invalid_types=invalid_refs, spec_version='2.1', required=True)),
    ], extension_name='extension-definition--e96690a5-dc13-4f27-99dd-0f2188ad74ce', is_sdo=False,
)
class MyFavSRO:
    pass


my_favorite_sro = MyFavSRO(
    name="My First SRO",
    some_source_ref="identity--b1da8c3e-34d8-470f-9d2b-392e275f1f7d",
    some_target_ref="identity--1ddfed54-e8cd-49c9-9c7d-8d1b03c94685",
)

print(my_favorite_sro.serialize(pretty=True))
[4]:
{
    "type": "my-favorite-sro",
    "spec_version": "2.1",
    "id": "my-favorite-sro--d6306d62-c08d-4d78-baf7-11e7a4c9bc36",
    "created": "2021-03-31T22:43:42.807698Z",
    "modified": "2021-03-31T22:43:42.807698Z",
    "name": "My First SRO",
    "some_source_ref": "identity--b1da8c3e-34d8-470f-9d2b-392e275f1f7d",
    "some_target_ref": "identity--1ddfed54-e8cd-49c9-9c7d-8d1b03c94685",
    "extensions": {
        "extension-definition--e96690a5-dc13-4f27-99dd-0f2188ad74ce": {
            "extension_type": "new-sro"
        }
    }
}