Data Markings

Creating Objects With Data Markings

To create an object with a (predefined) TLP marking to an object, just provide it as a keyword argument to the constructor. The TLP markings can easily be imported from python-stix2.

In [7]:
from stix2 import Indicator, TLP_AMBER

indicator = Indicator(labels=["malicious-activity"],
                      pattern="[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']",
                      object_marking_refs=TLP_AMBER)
print(indicator)
Out[7]:
{
    "type": "indicator",
    "id": "indicator--95a71cff-fad0-4ffb-a641-8a6eaa642290",
    "created": "2018-04-05T19:49:47.924Z",
    "modified": "2018-04-05T19:49:47.924Z",
    "pattern": "[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']",
    "valid_from": "2018-04-05T19:49:47.924708Z",
    "labels": [
        "malicious-activity"
    ],
    "object_marking_refs": [
        "marking-definition--f88d31f6-486f-44da-b317-01333bde0b82"
    ]
}

If you’re creating your own marking (for example, a Statement marking), first create the statement marking:

In [8]:
from stix2 import MarkingDefinition, StatementMarking

marking_definition = MarkingDefinition(
    definition_type="statement",
    definition=StatementMarking(statement="Copyright 2017, Example Corp")
)
print(marking_definition)
Out[8]:
{
    "type": "marking-definition",
    "id": "marking-definition--13680b12-3d19-4b42-abe6-0d31effe5368",
    "created": "2018-04-05T19:49:53.98008Z",
    "definition_type": "statement",
    "definition": {
        "statement": "Copyright 2017, Example Corp"
    }
}

Then you can add it to an object as it’s being created (passing either full object or the the ID as a keyword argument, like with relationships).

In [9]:
indicator2 = Indicator(labels=["malicious-activity"],
                      pattern="[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']",
                      object_marking_refs=marking_definition)
print(indicator2)
Out[9]:
{
    "type": "indicator",
    "id": "indicator--7caeab49-2472-41bb-a988-2f990aea99bd",
    "created": "2018-04-05T19:49:55.763Z",
    "modified": "2018-04-05T19:49:55.763Z",
    "pattern": "[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']",
    "valid_from": "2018-04-05T19:49:55.763364Z",
    "labels": [
        "malicious-activity"
    ],
    "object_marking_refs": [
        "marking-definition--13680b12-3d19-4b42-abe6-0d31effe5368"
    ]
}
In [10]:
indicator3 = Indicator(labels=["malicious-activity"],
                      pattern="[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']",
                      object_marking_refs="marking-definition--f88d31f6-486f-44da-b317-01333bde0b82")
print(indicator3)
Out[10]:
{
    "type": "indicator",
    "id": "indicator--4eb21bbe-b8a9-4348-86cf-1ed52f9abdd7",
    "created": "2018-04-05T19:49:57.248Z",
    "modified": "2018-04-05T19:49:57.248Z",
    "pattern": "[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']",
    "valid_from": "2018-04-05T19:49:57.248658Z",
    "labels": [
        "malicious-activity"
    ],
    "object_marking_refs": [
        "marking-definition--f88d31f6-486f-44da-b317-01333bde0b82"
    ]
}

Granular markings work in the same way, except you also need to provide a full granular-marking object (including the selector).

In [11]:
from stix2 import Malware, TLP_WHITE

malware = Malware(name="Poison Ivy",
                  labels=['remote-access-trojan'],
                  description="A ransomware related to ...",
                  granular_markings=[
                      {
                          "selectors": ["description"],
                          "marking_ref": marking_definition
                      },
                      {
                          "selectors": ["name"],
                          "marking_ref": TLP_WHITE
                      }
                  ])
print(malware)
Out[11]:
{
    "type": "malware",
    "id": "malware--ef1eddbb-b5a5-47e0-b607-75b9870d8d91",
    "created": "2018-04-05T19:49:59.103Z",
    "modified": "2018-04-05T19:49:59.103Z",
    "name": "Poison Ivy",
    "description": "A ransomware related to ...",
    "labels": [
        "remote-access-trojan"
    ],
    "granular_markings": [
        {
            "marking_ref": "marking-definition--13680b12-3d19-4b42-abe6-0d31effe5368",
            "selectors": [
                "description"
            ]
        },
        {
            "marking_ref": "marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9",
            "selectors": [
                "name"
            ]
        }
    ]
}

Make sure that the selector is a field that exists and is populated on the object, otherwise this will cause an error:

In [12]:
Malware(name="Poison Ivy",
        labels=['remote-access-trojan'],
        description="A ransomware related to ...",
        granular_markings=[
            {
                "selectors": ["title"],
                "marking_ref": marking_definition
            }
        ])
InvalidSelectorError: Selector title in Malware is not valid!

Adding Data Markings To Existing Objects

Several functions exist to support working with data markings.

Both object markings and granular markings can be added to STIX objects which have already been created.

Note: Doing so will create a new version of the object (note the updated modified time).

In [13]:
indicator4 = indicator.add_markings(marking_definition)
print(indicator4)
Out[13]:
{
    "type": "indicator",
    "id": "indicator--95a71cff-fad0-4ffb-a641-8a6eaa642290",
    "created": "2018-04-05T19:49:47.924Z",
    "modified": "2018-04-05T19:50:03.387Z",
    "pattern": "[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']",
    "valid_from": "2018-04-05T19:49:47.924708Z",
    "labels": [
        "malicious-activity"
    ],
    "object_marking_refs": [
        "marking-definition--13680b12-3d19-4b42-abe6-0d31effe5368",
        "marking-definition--f88d31f6-486f-44da-b317-01333bde0b82"
    ]
}

You can also remove specific markings from STIX objects. This will also create a new version of the object.

In [14]:
indicator5 = indicator4.remove_markings(marking_definition)
print(indicator5)
Out[14]:
{
    "type": "indicator",
    "id": "indicator--95a71cff-fad0-4ffb-a641-8a6eaa642290",
    "created": "2018-04-05T19:49:47.924Z",
    "modified": "2018-04-05T19:50:05.109Z",
    "pattern": "[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']",
    "valid_from": "2018-04-05T19:49:47.924708Z",
    "labels": [
        "malicious-activity"
    ],
    "object_marking_refs": [
        "marking-definition--f88d31f6-486f-44da-b317-01333bde0b82"
    ]
}

The markings on an object can be replaced with a different set of markings:

In [15]:
from stix2 import TLP_GREEN

indicator6 = indicator5.set_markings([TLP_GREEN, marking_definition])
print(indicator6)
Out[15]:
{
    "type": "indicator",
    "id": "indicator--95a71cff-fad0-4ffb-a641-8a6eaa642290",
    "created": "2018-04-05T19:49:47.924Z",
    "modified": "2018-04-05T19:50:06.773Z",
    "pattern": "[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']",
    "valid_from": "2018-04-05T19:49:47.924708Z",
    "labels": [
        "malicious-activity"
    ],
    "object_marking_refs": [
        "marking-definition--13680b12-3d19-4b42-abe6-0d31effe5368",
        "marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da"
    ]
}

STIX objects can also be cleared of all markings with clear_markings():

In [16]:
indicator7 = indicator5.clear_markings()
print(indicator7)
Out[16]:
{
    "type": "indicator",
    "id": "indicator--95a71cff-fad0-4ffb-a641-8a6eaa642290",
    "created": "2018-04-05T19:49:47.924Z",
    "modified": "2018-04-05T19:50:08.616Z",
    "pattern": "[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']",
    "valid_from": "2018-04-05T19:49:47.924708Z",
    "labels": [
        "malicious-activity"
    ]
}

All of these functions can be used for granular markings by passing in a list of selectors. Note that they will create new versions of the objects.

Evaluating Data Markings

You can get a list of the object markings on a STIX object:

In [17]:
indicator6.get_markings()
Out[17]:
['marking-definition--13680b12-3d19-4b42-abe6-0d31effe5368',
 'marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da']

To get a list of the granular markings on an object, pass the object and a list of selectors to get_markings():

In [18]:
from stix2 import get_markings

get_markings(malware, 'name')
Out[18]:
['marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9']

You can also call get_markings() as a method on the STIX object.

In [19]:
malware.get_markings('name')
Out[19]:
['marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9']

Finally, you may also check if an object is marked by a specific markings. Again, for granular markings, pass in the selector or list of selectors.

In [20]:
indicator.is_marked(TLP_AMBER.id)
Out[20]:
True
In [21]:
malware.is_marked(TLP_WHITE.id, 'name')
Out[21]:
True
In [22]:
malware.is_marked(TLP_WHITE.id, 'description')
Out[22]:
False