new: [entities] Split MISPGalaxy: Threat Actor, Attack Technique , Software

pull/40/head v1.4.0
Christophe Vandeplas 2019-12-17 21:42:24 +01:00
parent dd7c8e2460
commit eb80120d2d
7 changed files with 119 additions and 33 deletions

View File

@ -19,8 +19,10 @@ These instructions have been tested on Ubuntu 18.04 LTS, but should be similar o
MISP-Maltego tries to use as much as possible the default Paterva entities, or the most popular from the community. It however comes with a few custom entities:
* **MISPEvent**: A representation of an *Event* on MISP, containing *Attributes* (MISP) / *Entities* (Maltego)
* **MISPObject**: A way to group associated attributes in a structured way.
* **MISPGalaxy**: A *Tag* containing much more metadata. Please refer to the [MISP Galaxy
](https://github.com/MISP/misp-galaxy) for more information. **MITRE ATT&CK** is for example completely available through MISPGalaxy entities (see use-cases for an example)
* **MISPGalaxy**: A *Tag* containing much more metadata. Please refer to the [MISP Galaxy](https://github.com/MISP/misp-galaxy) for more information. **MITRE ATT&CK** is for example completely available through MISPGalaxy entities (see use-cases for an example)
* **Attack Technique**: Attack patterns or techniques, see [MITRE ATT&CK](https://attack.mitre.org/techniques/enterprise/) for more information.
* **Threat Actor**: Threat actor or intrusion sets.
* **Software**: Software is a generic term for custom or commercial code, operating system utilities, open-source software, or other tools used to conduct behavior modeled in ATT&CK.
# Use Cases
## Transform on existing data

Binary file not shown.

Before

Width:  |  Height:  |  Size: 379 KiB

After

Width:  |  Height:  |  Size: 80 KiB

View File

@ -6,7 +6,7 @@ setup(
name='MISP_maltego',
author='Christophe Vandeplas',
# also update version in util.py
version='1.3.7',
version='1.4.0',
author_email='christophe@vandeplas.com',
maintainer='Christophe Vandeplas',
url='https://github.com/MISP/MISP-maltego',

View File

@ -13,7 +13,10 @@ __status__ = 'Development'
__all__ = [
'MISPEvent',
'MISPObject',
'MISPGalaxy'
'MISPGalaxy',
'ThreatActor',
'Software',
'AttackTechnique'
]
@ -55,3 +58,18 @@ class MISPGalaxy(Entity):
cluster_value = StringEntityField('value', display_name='Value', matching_rule=MatchingRule.Loose)
synonyms = StringEntityField('synonyms', display_name='Synonyms', matching_rule=MatchingRule.Loose)
tag_name = StringEntityField('tag_name', display_name='Tag')
class ThreatActor(MISPGalaxy):
_category_ = 'MISP'
_namespace_ = 'misp'
class Software(MISPGalaxy):
_category_ = 'MISP'
_namespace_ = 'misp'
class AttackTechnique(MISPGalaxy):
_category_ = 'MISP'
_namespace_ = 'misp'

View File

@ -1,7 +1,7 @@
from canari.maltego.entities import Hash, Domain, IPv4Address, URL, DNSName, AS, Website, NSRecord, PhoneNumber, EmailAddress, File, Person, Hashtag, Location, Company, Alias, Port, Twitter
from canari.maltego.message import Label, LinkStyle, MaltegoException, Bookmark, LinkDirection, UIMessage, UIMessageType
from distutils.version import StrictVersion
from MISP_maltego.transforms.common.entities import MISPEvent, MISPObject, MISPGalaxy
from MISP_maltego.transforms.common.entities import MISPEvent, MISPObject, MISPGalaxy, ThreatActor, Software, AttackTechnique
from pymisp import ExpandedPyMISP as PyMISP
import json
import os
@ -12,7 +12,7 @@ import time
# FIXME from galaxy 'to MISP Event' is confusing
__version__ = '1.3.7' # also update version in setup.py
__version__ = '1.4.0' # also update version in setup.py
mapping_misp_to_maltego = {
'AS': [AS],
@ -82,6 +82,40 @@ mapping_galaxy_icon = {
"user-secret": "threat_actor",
}
mapping_galaxy_type = {
# 'amitt-misinformation-pattern': '',
'android': Software,
'backdoor': Software,
'banker': Software,
'botnet': Software,
# 'branded-vulnerability': '',
# 'cert-eu-govsector': '',
'cloud-security': AttackTechnique,
'exploit-kit': Software,
'financial-fraud': AttackTechnique,
'guidelines': AttackTechnique,
'malpedia': Software,
'microsoft-activity-group': ThreatActor,
'mitre-attack-pattern': AttackTechnique,
# 'mitre-course-of-action': '',
'mitre-intrusion-set': ThreatActor,
'mitre-malware': Software,
'mitre-tool': Software,
# 'preventive-measure': '',
'ransomware': Software,
'rat': Software,
# 'region': '',
# 'sector': '',
'social-dark-patterns': AttackTechnique,
'stealer': Software,
'surveillance-vendor': ThreatActor,
# 'target-information': '',
'tds': Software,
'threat-actor': ThreatActor,
'tool': Software
}
tag_note_prefixes = ['tlp:', 'PAP:', 'de-vs:', 'euci:', 'fr-classif:', 'nato:']
misp_connection = None
@ -399,15 +433,20 @@ def galaxycluster_to_entity(c, link_label=None, link_direction=LinkDirection.Inp
synonyms = ''
galaxy_cluster = get_galaxy_cluster(c['uuid'])
icon_url = None
if 'icon' in galaxy_cluster: # map the 'icon' name from the cluster to the icon filename of the intelligence-icons repository
try:
icon_url = mapping_galaxy_icon[galaxy_cluster['icon']]
except Exception:
# it's not in our mapping, just ignore and leave the default Galaxy icon
pass
# map the 'icon' name from the cluster to the icon filename of the intelligence-icons repository
try:
icon_url = mapping_galaxy_icon[galaxy_cluster['icon']]
except KeyError:
icon_url = None
# it's not in our mapping, just ignore and leave the default Galaxy icon
pass
return MISPGalaxy(
# create the right sub-galaxy: ThreatActor, Software, AttackTechnique, ... or MISPGalaxy
try:
galaxy_type = mapping_galaxy_type[galaxy_cluster['type']]
except KeyError:
galaxy_type = MISPGalaxy
return galaxy_type(
'{}\n{}'.format(c['type'], c['value']),
uuid=c['uuid'],
description=c.get('description'),

View File

@ -1,6 +1,6 @@
from canari.maltego.transform import Transform
# from canari.framework import EnableDebugWindow
from MISP_maltego.transforms.common.entities import MISPEvent, MISPGalaxy
from MISP_maltego.transforms.common.entities import MISPEvent, MISPGalaxy, ThreatActor, Software, AttackTechnique
from MISP_maltego.transforms.common.util import check_update, get_misp_connection, galaxycluster_to_entity, get_galaxy_cluster, get_galaxies_relating, search_galaxy_cluster, mapping_galaxy_icon
from canari.maltego.message import UIMessageType, UIMessage, LinkDirection
@ -16,16 +16,6 @@ __email__ = 'christophe@vandeplas.com'
__status__ = 'Development'
class GalaxyTo(Transform):
input_type = None
def __init__(self):
self.request = None
self.response = None
self.config = None
self.misp = None
# @EnableDebugWindow
class GalaxyToEvents(Transform):
"""Expands a Galaxy to multiple MISP Events."""
@ -48,14 +38,14 @@ class GalaxyToEvents(Transform):
# @EnableDebugWindow
class GalaxyToRelations(Transform):
"""Expans a Galaxy to related Galaxies and Clusters"""
input_type = MISPGalaxy
class GalaxyToTransform(Transform):
input_type = None
def do_transform(self, request, response, config):
def do_transform(self, request, response, config, type_filter=MISPGalaxy):
response += check_update(config)
maltego_misp_galaxy = request.entity
current_cluster = None
if maltego_misp_galaxy.uuid:
current_cluster = get_galaxy_cluster(uuid=maltego_misp_galaxy.uuid)
elif maltego_misp_galaxy.tag_name:
@ -63,7 +53,7 @@ class GalaxyToRelations(Transform):
elif maltego_misp_galaxy.name:
current_cluster = get_galaxy_cluster(tag=maltego_misp_galaxy.name)
if not current_cluster:
if not current_cluster and maltego_misp_galaxy.name != '-':
# maybe the user is searching for a cluster based on a substring.
# Search in the list for those that match and return galaxy entities
potential_clusters = search_galaxy_cluster(maltego_misp_galaxy.name)
@ -77,8 +67,8 @@ class GalaxyToRelations(Transform):
response += UIMessage("Galaxy Cluster UUID not in local mapping. Please update local cache; non-public UUID are not supported yet.", type=UIMessageType.Inform)
return response
c = current_cluster
# update existing object
# update existing object
galaxy_cluster = get_galaxy_cluster(c['uuid'])
icon_url = None
if 'icon' in galaxy_cluster: # map the 'icon' name from the cluster to the icon filename of the intelligence-icons repository
@ -100,12 +90,15 @@ class GalaxyToRelations(Transform):
request.entity.tag_name = c['tag_name']
request.entity.icon_url = icon_url
# response += request.entity
# find related objects
if 'related' in current_cluster:
for related in current_cluster['related']:
related_cluster = get_galaxy_cluster(related['dest-uuid'])
if related_cluster:
response += galaxycluster_to_entity(related_cluster, link_label=related['type'])
new_entity = galaxycluster_to_entity(related_cluster, link_label=related['type'])
if isinstance(new_entity, type_filter):
response += new_entity
# find objects that are relating to this one
for related in get_galaxies_relating(current_cluster['uuid']):
related_link_label = ''
@ -113,5 +106,39 @@ class GalaxyToRelations(Transform):
if rel_in_rel['dest-uuid'] == current_cluster['uuid']:
related_link_label = rel_in_rel['type']
break
response += galaxycluster_to_entity(related, link_label=related_link_label, link_direction=LinkDirection.OutputToInput)
new_entity = galaxycluster_to_entity(related, link_label=related_link_label, link_direction=LinkDirection.OutputToInput)
if isinstance(new_entity, type_filter):
response += new_entity
return response
class GalaxyToRelations(GalaxyToTransform):
"""Expands a Galaxy to related Galaxies and Clusters"""
input_type = MISPGalaxy
def do_transform(self, request, response, config, type_filter=MISPGalaxy):
return super().do_transform(request, response, config, type_filter)
class GalaxyToSoftware(GalaxyToTransform):
"""Expands a Galaxy to related Software/Tool Galaxies"""
input_type = MISPGalaxy
def do_transform(self, request, response, config, type_filter=Software):
return super().do_transform(request, response, config, type_filter)
class GalaxyToThreatActor(GalaxyToTransform):
"""Expands a Galaxy to related ThreatActor Galaxies"""
input_type = MISPGalaxy
def do_transform(self, request, response, config, type_filter=ThreatActor):
return super().do_transform(request, response, config, type_filter)
class GalaxyToAttackTechnique(GalaxyToTransform):
"""Expands a Galaxy to related Attack Techniques Galaxies"""
input_type = MISPGalaxy
def do_transform(self, request, response, config, type_filter=AttackTechnique):
return super().do_transform(request, response, config, type_filter)