taranis-ai icon indicating copy to clipboard operation
taranis-ai copied to clipboard

Update MISP Presenter template

Open b3n4kh opened this issue 1 year ago • 4 comments

From Taranis-NG created by ewoiset: ait-cs-IaaS/Taranis-NG#91

Review and update misp template in presenter, to export all relevant information - tags, topics, etc...

Using https://pymisp.readthedocs.io/en/latest/ in https://github.com/ait-cs-IaaS/Taranis-NG/blob/awake/src/worker/worker/publishers/misp_publisher.py to publish a json created by:

https://github.com/ait-cs-IaaS/Taranis-NG/blob/awake/src/core/core/managers/workers_pre_seed.py#L286C6-L286C6

with this template: https://github.com/ait-cs-IaaS/Taranis-NG/blob/awake/src/core/core/static/presenter_templates/misp_template.json

So the main change for this issue is to adapt the misp_template.json to include the "relevant information".

See https://www.misp-project.org/openapi/#tag/Events/operation/addEvent for available fields

Adding the actual stories would be a good first improvement

        {% for story in report_item.news_item_aggregates %}
        {{ story }}
        {% endfor %}

b3n4kh avatar Oct 17 '23 14:10 b3n4kh

The initial thought of mapping our data to plain attributes in events seems not to be the most effective approach. => Therefore I made a mock up of how the mapping to MISP could look like.

I tried to map data from news-item-aggregate_* testdata.py

To not make things complex, a well-fitting MISPObject was picked (Vulnerability).

The initial event data:

    type = "MISP_PUBLISHER"
    name = "MISP Publisher"
    description = "Publisher for publishing in MISP"

    # MISP BASE_URL fix https://github.com/MISP/misp-docker/issues/130#issuecomment-1033312591
    misp_url = "https://localhost"
    misp_verifycert = False
    misp_key = <key>

    event_json = {
        "org_id": "1231231231416",
        "distribution": "0",
        "info": "wow_with_attribute",
        "orgc_id": "123452",
        # "uuid": "c99506a6-1255-4b71-afa5-7b8ba48c3b11",
        "date": "1991-01-15",
        "published": False,
        "analysis": "0",
        "attribute_count": "321",
        "timestamp": "1617875569",
        "sharing_group_id": "1",
        "proposal_email_lock": True,
        "locked": True,
        "threat_level_id": "1",
        "publish_timestamp": "1617875569",
        "sighting_timestamp": "1617875569",
        "disable_correlation": False,
        # "extends_uuid": "c99506a6-1255-4b71-afa5-7b8ba48c3b11",
        "event_creator_email": "[email protected]",
        "Attribute": [{
            "category": "External analysis",
            "type": "text",
            "value": "This is a story",
            "to_ids": False,
            "uuid": "c99506a6-1255-4b71-afa5-7b8ba48c3b1s",
            "timestamp": "1617875569",
            "distribution": "0",
            "sharing_group_id": "1",
            "comment": "logged source ip",
            "deleted": False,
            "disable_correlation": True
        }]
    }

Creation of the event.

    misp = ExpandedPyMISP(misp_url, misp_key, misp_verifycert)
    event = MISPEvent()
    event.load(event_json)

Keys in JSON need to be adjusted to match the Vulnerability MISPObject.

    # @description is "title"
    # @references is "link"
    # @summary is "content"
    # @published stays unchanged
    object_json = {
        "description": "Test News Item 14",
        "references": "https://url/13",
        "summary": "CVE-2020-1234 - Test Aggregate 1",
        "published": "2023-08-01T17:01:04.801998"
    }

Importing to MISP instance could look like this:

    misp_object = event.add_object(name='vulnerability')
    for key, value in object_json.items():
        misp_object.add_attribute(key, value=value)
    misp.add_event(event)

or like this:

    misp_object = event.add_object(name='vulnerability')
    obj_attr = misp_object.add_attribute('description', value=object_json['description'])
    misp_object.add_attribute('summary', value=object_json['summary'])
    misp_object.add_attribute('references', value=object_json['summary'])
    misp_object.add_attribute('published', value=object_json['published'])
    misp.add_event(event)

Ad.1 - I was not able to load the JSON data without the FOR loop. Ad.2 - From what I understood, it should be able to create custom MISPObjects dynamically without a template (Did not make it work.). Nevertheless, without an object template in the MISP instance, the object might not be possible to edit in the UI. Ad.3 - Using fields of the Vulnerability object, stories can be added to the text fields.

not4Pedro avatar Oct 30 '23 16:10 not4Pedro

Can you have a look? @b3n4kh

not4Pedro avatar Oct 31 '23 10:10 not4Pedro

That looks like a good start! To increase reuseability and readability I would suggest creating our own MISPObject the

class TaranisObejct(AbstractMISPObjectGenerator):

Looking something like:

https://github.com/MISP/PyMISP/blob/main/pymisp/tools/urlobject.py or https://github.com/MISP/PyMISP/blob/main/pymisp/tools/fail2banobject.py

These Objects could than be created and added in a loop to the event:

https://github.com/MISP/PyMISP/blob/3a3096664109639322bff7285956ef7cc376a260/examples/load_csv.py#L74

The event JSON could be simplified by removing the now obsolete attributes since this would represented in the TaranisObject.

b3n4kh avatar Oct 31 '23 15:10 b3n4kh

The base class for TaranisObject:

    class TaranisObject(MISPObject):

    def __init__(self, parameters: dict, strict: bool = True, **kwargs):
        super().__init__(name='taranis-news-item', strict=strict, **kwargs)
        self._parameters = parameters
        self.generate_attributes()

    def generate_attributes(self):
        """Contains the logic where all the values of the object are gathered"""
        if hasattr(self, '_parameters'):
            for object_relation in self._definition['attributes']:
                value = self._parameters.pop(object_relation, None)
                if not value:
                    continue
                if isinstance(value, dict):
                    self.add_attribute(object_relation, **value)
                elif isinstance(value, list):
                    self.add_attributes(object_relation, *value)
                else:
                    # Assume it is the value only
                    self.add_attribute(object_relation, value=value)
            if self._strict and self._known_template and self._parameters:
                raise InvalidMISPObject(
                    'Some object relations are unknown in the template and could not be attached: {}'.format(
                        ', '.join(self._parameters)))

Test scenario:

    type = "MISP_PUBLISHER"
    name = "MISP Publisher"
    description = "Publisher for publishing in MISP"

    misp_url = "https://localhost"
    misp_verifycert = False
    misp_key = <key>

    event_json = {
        # "distribution": "0", # this attribute might be interesting
        "info": "Event with Taranis objects",
        # "orgc_id": "taranis_id", # this attribute could be interesting
        "disable_correlation": False
    }

    stories = [
        {
            "title": "Test News Item 1",
            "link": "https://url/13",
            "content": "CVE-2020-1234 - Test Aggregate 1",
            "published": "2023-08-01T17:01:04.801998"
        },
        {
            "title": "Test News Item 2",
            "link": "https://url/13",
            "content": "CVE-2020-1234 - Test Aggregate 1",
            "published": "2023-08-01T17:01:04.801998"
        },
        {
            "title": "Test News Item 3",
            "link": "https://url/13",
            "content": "CVE-2020-1234 - Test Aggregate 1",
            "published": "2023-08-01T17:01:04.801998"
        },
        {
            "title": "Test News Item 4",
            "link": "https://url/13",
            "content": "CVE-2020-1234 - Test Aggregate 1",
            "published": "2023-08-01T17:01:04.801998"
        },
        {
            "title": "Test News Item 5",
            "link": "https://url/13",
            "content": "CVE-2020-1234 - Test Aggregate 1",
            "published": "2023-08-01T17:01:04.801998"
        }
    ]

    misp = ExpandedPyMISP(misp_url, misp_key, misp_verifycert)
    event = MISPEvent()
    event.load(event_json)

    for story in stories:
        taranis_obj = TaranisObject(parameters=story)
        event.add_object(taranis_obj)
   
    misp.add_event(event)

taranis-news-item template:

{
  "attributes": {
    "title": {
      "description": "Title of the Taranis news item",
      "misp-attribute": "text",
      "ui-priority": 0
    },
    "link": {
      "description": "URL address to the Taranis news item source.",
      "misp-attribute": "link",
      "ui-priority": 0
    },
    "content": {
      "description": "Content of the Taranis news item",
      "misp-attribute": "text",
      "multiple": true,
      "ui-priority": 0
    },
    "published": {
      "description": "Publish date of the Taranis news item ",
      "misp-attribute": "datetime",
      "ui-priority": 0
    }
  },
  "description": "An object describing a news item from Taranis AI",
  "meta-category": "misc",
  "name": "taranis",
  "uuid": "e4b7e5e3-2c4c-4edf-b9a3-2c2a32844e61",
  "version": 1
}

This way the MISP template is already in use (solely for PyMISP, not for the MISP instance per see).

See the whole mock-up: https://github.com/not4Pedro/misp-implementation

@b3n4kh what do you think?

not4Pedro avatar Nov 14 '23 12:11 not4Pedro