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