In [1]:
# Delete this cell to re-enable tracebacks
import sys
ipython = get_ipython()

def hide_traceback(exc_tuple=None, filename=None, tb_offset=None,
                   exception_only=False, running_compiled_code=False):
    etype, value, tb = sys.exc_info()
    value.__cause__ = None  # suppress chained exceptions
    return ipython._showtraceback(etype, value, ipython.InteractiveTB.get_exception_only(etype, value))

ipython.showtraceback = hide_traceback

In [2]:
# JSON output syntax highlighting
from __future__ import print_function
from pygments import highlight
from pygments.lexers import JsonLexer, TextLexer
from pygments.formatters import HtmlFormatter
from IPython.display import display, HTML
from IPython.core.interactiveshell import InteractiveShell

InteractiveShell.ast_node_interactivity = "all"

def json_print(inpt):
    string = str(inpt)
    formatter = HtmlFormatter()
    if string[0] == '{':
        lexer = JsonLexer()
    else:
        lexer = TextLexer()
    return HTML('<style type="text/css">{}</style>{}'.format(
                formatter.get_style_defs('.highlight'),
                highlight(string, lexer, formatter)))

globals()['print'] = json_print

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 [3]:
from stix2 import Indicator, TLP_AMBER

indicator = Indicator(pattern_type="stix",
                      pattern="[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']",
                      object_marking_refs=TLP_AMBER)
print(indicator)


Out[3]:
{
    "type": "indicator",
    "spec_version": "2.1",
    "id": "indicator--46498844-7689-4e7b-be25-b119d8401159",
    "created": "2020-06-24T20:55:56.088861Z",
    "modified": "2020-06-24T20:55:56.088861Z",
    "pattern": "[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']",
    "pattern_type": "stix",
    "pattern_version": "2.1",
    "valid_from": "2020-06-24T20:55:56.088861Z",
    "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 [4]:
from stix2 import MarkingDefinition, StatementMarking

marking_definition = MarkingDefinition(                                    
    definition_type="statement",                                            
    definition=StatementMarking(statement="Copyright 2017, Example Corp")
)
print(marking_definition)


Out[4]:
{
    "type": "marking-definition",
    "spec_version": "2.1",
    "id": "marking-definition--9a4efc30-a7ac-42d0-8776-16f390a0fd44",
    "created": "2020-06-24T20:56:06.779241Z",
    "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 [5]:
indicator2 = Indicator(pattern_type="stix",
                       pattern="[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']",
                       object_marking_refs=marking_definition)
print(indicator2)


Out[5]:
{
    "type": "indicator",
    "spec_version": "2.1",
    "id": "indicator--75d66696-9960-4229-ba89-2caac50891b3",
    "created": "2020-06-24T20:56:29.80259Z",
    "modified": "2020-06-24T20:56:29.80259Z",
    "pattern": "[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']",
    "pattern_type": "stix",
    "pattern_version": "2.1",
    "valid_from": "2020-06-24T20:56:29.80259Z",
    "object_marking_refs": [
        "marking-definition--9a4efc30-a7ac-42d0-8776-16f390a0fd44"
    ]
}

In [6]:
indicator3 = Indicator(pattern_type="stix",
                       pattern="[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']",
                       object_marking_refs="marking-definition--f88d31f6-486f-44da-b317-01333bde0b82")
print(indicator3)


Out[6]:
{
    "type": "indicator",
    "spec_version": "2.1",
    "id": "indicator--757ea853-138c-44e2-bb00-e78eebfaa378",
    "created": "2020-06-24T20:56:43.703563Z",
    "modified": "2020-06-24T20:56:43.703563Z",
    "pattern": "[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']",
    "pattern_type": "stix",
    "pattern_version": "2.1",
    "valid_from": "2020-06-24T20:56:43.703563Z",
    "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 [8]:
from stix2 import Malware, TLP_WHITE

malware = Malware(name="Poison Ivy",
                  description="A ransomware related to ...",
                  is_family=False,
                  granular_markings=[
                      {
                          "selectors": ["description"],
                          "marking_ref": marking_definition
                      },
                      {
                          "selectors": ["name"],
                          "marking_ref": TLP_WHITE
                      }
                  ])
print(malware)


Out[8]:
{
    "type": "malware",
    "spec_version": "2.1",
    "id": "malware--1752bbec-765a-4711-a304-f0e92ca902ae",
    "created": "2020-06-24T21:21:07.148194Z",
    "modified": "2020-06-24T21:21:07.148194Z",
    "name": "Poison Ivy",
    "description": "A ransomware related to ...",
    "is_family": false,
    "granular_markings": [
        {
            "marking_ref": "marking-definition--9a4efc30-a7ac-42d0-8776-16f390a0fd44",
            "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 [9]:
Malware(name="Poison Ivy",
        description="A ransomware related to ...",
        is_family=False,
        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 [10]:
indicator4 = indicator.add_markings(marking_definition)
print(indicator4)


Out[10]:
{
    "type": "indicator",
    "spec_version": "2.1",
    "id": "indicator--46498844-7689-4e7b-be25-b119d8401159",
    "created": "2020-06-24T20:55:56.088861Z",
    "modified": "2020-06-24T21:21:39.898475Z",
    "pattern": "[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']",
    "pattern_type": "stix",
    "pattern_version": "2.1",
    "valid_from": "2020-06-24T20:55:56.088861Z",
    "object_marking_refs": [
        "marking-definition--f88d31f6-486f-44da-b317-01333bde0b82",
        "marking-definition--9a4efc30-a7ac-42d0-8776-16f390a0fd44"
    ]
}

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


In [11]:
indicator5 = indicator4.remove_markings(marking_definition)
print(indicator5)


Out[11]:
{
    "type": "indicator",
    "spec_version": "2.1",
    "id": "indicator--46498844-7689-4e7b-be25-b119d8401159",
    "created": "2020-06-24T20:55:56.088861Z",
    "modified": "2020-06-24T21:21:43.529702Z",
    "pattern": "[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']",
    "pattern_type": "stix",
    "pattern_version": "2.1",
    "valid_from": "2020-06-24T20:55:56.088861Z",
    "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 [12]:
from stix2 import TLP_GREEN

indicator6 = indicator5.set_markings([TLP_GREEN, marking_definition])
print(indicator6)


Out[12]:
{
    "type": "indicator",
    "spec_version": "2.1",
    "id": "indicator--46498844-7689-4e7b-be25-b119d8401159",
    "created": "2020-06-24T20:55:56.088861Z",
    "modified": "2020-06-24T21:21:47.703212Z",
    "pattern": "[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']",
    "pattern_type": "stix",
    "pattern_version": "2.1",
    "valid_from": "2020-06-24T20:55:56.088861Z",
    "object_marking_refs": [
        "marking-definition--9a4efc30-a7ac-42d0-8776-16f390a0fd44",
        "marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da"
    ]
}

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


In [13]:
indicator7 = indicator5.clear_markings()
print(indicator7)


Out[13]:
{
    "type": "indicator",
    "spec_version": "2.1",
    "id": "indicator--46498844-7689-4e7b-be25-b119d8401159",
    "created": "2020-06-24T20:55:56.088861Z",
    "modified": "2020-06-24T21:21:53.287178Z",
    "pattern": "[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']",
    "pattern_type": "stix",
    "pattern_version": "2.1",
    "valid_from": "2020-06-24T20:55:56.088861Z"
}

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 [14]:
indicator6.get_markings()


Out[14]:
['marking-definition--9a4efc30-a7ac-42d0-8776-16f390a0fd44',
 '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 [15]:
from stix2 import get_markings

get_markings(malware, 'name')


Out[15]:
['marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9']

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


In [16]:
malware.get_markings('name')


Out[16]:
['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 [17]:
indicator.is_marked(TLP_AMBER.id)


Out[17]:
True

In [18]:
malware.is_marked(TLP_WHITE.id, 'name')


Out[18]:
True

In [19]:
malware.is_marked(TLP_WHITE.id, 'description')


Out[19]:
False

Extracting Lang Data Markings or marking-definition Data Markings

If you need a specific kind of marking, you can also filter them using the API. By default the library will get both types of markings by default. You can choose between lang=True/False or marking_ref=True/False depending on your use-case.


In [20]:
from stix2 import Indicator

v21_indicator = Indicator(
    description="Una descripcion sobre este indicador",
    pattern_type="stix",
    pattern="[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']",
    object_marking_refs=['marking-definition--f88d31f6-486f-44da-b317-01333bde0b82'],
    indicator_types=['malware'],
    granular_markings=[
        {
            'selectors': ['description'],
            'lang': 'es'
        },
        {
            'selectors': ['description'],
            'marking_ref': 'marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da'
        }
    ]
)
print(v21_indicator)

# Gets both lang and marking_ref markings for 'description'
print(v21_indicator.get_markings('description'))

# Exclude lang markings from results
print(v21_indicator.get_markings('description', lang=False))

# Exclude marking-definition markings from results
print(v21_indicator.get_markings('description', marking_ref=False))


Out[20]:
{
    "type": "indicator",
    "spec_version": "2.1",
    "id": "indicator--f4004de9-a6d9-4c7b-823e-3d8199173c09",
    "created": "2020-06-24T21:35:08.630228Z",
    "modified": "2020-06-24T21:35:08.630228Z",
    "description": "Una descripcion sobre este indicador",
    "indicator_types": [
        "malware"
    ],
    "pattern": "[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']",
    "pattern_type": "stix",
    "pattern_version": "2.1",
    "valid_from": "2020-06-24T21:35:08.630228Z",
    "object_marking_refs": [
        "marking-definition--f88d31f6-486f-44da-b317-01333bde0b82"
    ],
    "granular_markings": [
        {
            "lang": "es",
            "selectors": [
                "description"
            ]
        },
        {
            "marking_ref": "marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da",
            "selectors": [
                "description"
            ]
        }
    ]
}
Out[20]:
['marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da', 'es']
Out[20]:
['marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da']
Out[20]:
['es']

In this same manner, calls to clear_markings and set_markings also have the ability to operate in for one or both types of markings.


In [21]:
print(v21_indicator.clear_markings("description"))  # By default, both types of markings will be removed


Out[21]:
{
    "type": "indicator",
    "spec_version": "2.1",
    "id": "indicator--f4004de9-a6d9-4c7b-823e-3d8199173c09",
    "created": "2020-06-24T21:35:08.630228Z",
    "modified": "2020-06-24T21:35:14.54482Z",
    "description": "Una descripcion sobre este indicador",
    "indicator_types": [
        "malware"
    ],
    "pattern": "[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']",
    "pattern_type": "stix",
    "pattern_version": "2.1",
    "valid_from": "2020-06-24T21:35:08.630228Z",
    "object_marking_refs": [
        "marking-definition--f88d31f6-486f-44da-b317-01333bde0b82"
    ]
}

In [22]:
# If lang is False, no lang markings will be removed
print(v21_indicator.clear_markings("description", lang=False))


Out[22]:
{
    "type": "indicator",
    "spec_version": "2.1",
    "id": "indicator--f4004de9-a6d9-4c7b-823e-3d8199173c09",
    "created": "2020-06-24T21:35:08.630228Z",
    "modified": "2020-06-24T21:35:39.298138Z",
    "description": "Una descripcion sobre este indicador",
    "indicator_types": [
        "malware"
    ],
    "pattern": "[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']",
    "pattern_type": "stix",
    "pattern_version": "2.1",
    "valid_from": "2020-06-24T21:35:08.630228Z",
    "object_marking_refs": [
        "marking-definition--f88d31f6-486f-44da-b317-01333bde0b82"
    ],
    "granular_markings": [
        {
            "lang": "es",
            "selectors": [
                "description"
            ]
        }
    ]
}

In [23]:
# If marking_ref is False, no marking-definition markings will be removed
print(v21_indicator.clear_markings("description", marking_ref=False))


Out[23]:
{
    "type": "indicator",
    "spec_version": "2.1",
    "id": "indicator--f4004de9-a6d9-4c7b-823e-3d8199173c09",
    "created": "2020-06-24T21:35:08.630228Z",
    "modified": "2020-06-24T21:35:42.684794Z",
    "description": "Una descripcion sobre este indicador",
    "indicator_types": [
        "malware"
    ],
    "pattern": "[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']",
    "pattern_type": "stix",
    "pattern_version": "2.1",
    "valid_from": "2020-06-24T21:35:08.630228Z",
    "object_marking_refs": [
        "marking-definition--f88d31f6-486f-44da-b317-01333bde0b82"
    ],
    "granular_markings": [
        {
            "marking_ref": "marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da",
            "selectors": [
                "description"
            ]
        }
    ]
}