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: 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) * **MISPEvent**: A representation of an *Event* on MISP, containing *Attributes* (MISP) / *Entities* (Maltego)
* **MISPObject**: A way to group associated attributes in a structured way. * **MISPObject**: A way to group associated attributes in a structured way.
* **MISPGalaxy**: A *Tag* containing much more metadata. Please refer to the [MISP Galaxy * **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)
](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 # Use Cases
## Transform on existing data ## 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', name='MISP_maltego',
author='Christophe Vandeplas', author='Christophe Vandeplas',
# also update version in util.py # also update version in util.py
version='1.3.7', version='1.4.0',
author_email='christophe@vandeplas.com', author_email='christophe@vandeplas.com',
maintainer='Christophe Vandeplas', maintainer='Christophe Vandeplas',
url='https://github.com/MISP/MISP-maltego', url='https://github.com/MISP/MISP-maltego',

View File

@ -13,7 +13,10 @@ __status__ = 'Development'
__all__ = [ __all__ = [
'MISPEvent', 'MISPEvent',
'MISPObject', 'MISPObject',
'MISPGalaxy' 'MISPGalaxy',
'ThreatActor',
'Software',
'AttackTechnique'
] ]
@ -55,3 +58,18 @@ class MISPGalaxy(Entity):
cluster_value = StringEntityField('value', display_name='Value', matching_rule=MatchingRule.Loose) cluster_value = StringEntityField('value', display_name='Value', matching_rule=MatchingRule.Loose)
synonyms = StringEntityField('synonyms', display_name='Synonyms', matching_rule=MatchingRule.Loose) synonyms = StringEntityField('synonyms', display_name='Synonyms', matching_rule=MatchingRule.Loose)
tag_name = StringEntityField('tag_name', display_name='Tag') 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.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 canari.maltego.message import Label, LinkStyle, MaltegoException, Bookmark, LinkDirection, UIMessage, UIMessageType
from distutils.version import StrictVersion 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 from pymisp import ExpandedPyMISP as PyMISP
import json import json
import os import os
@ -12,7 +12,7 @@ import time
# FIXME from galaxy 'to MISP Event' is confusing # 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 = { mapping_misp_to_maltego = {
'AS': [AS], 'AS': [AS],
@ -82,6 +82,40 @@ mapping_galaxy_icon = {
"user-secret": "threat_actor", "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:'] tag_note_prefixes = ['tlp:', 'PAP:', 'de-vs:', 'euci:', 'fr-classif:', 'nato:']
misp_connection = None misp_connection = None
@ -399,15 +433,20 @@ def galaxycluster_to_entity(c, link_label=None, link_direction=LinkDirection.Inp
synonyms = '' synonyms = ''
galaxy_cluster = get_galaxy_cluster(c['uuid']) galaxy_cluster = get_galaxy_cluster(c['uuid'])
icon_url = None # map the 'icon' name from the cluster to the icon filename of the intelligence-icons repository
if 'icon' in galaxy_cluster: # map the 'icon' name from the cluster to the icon filename of the intelligence-icons repository try:
try: icon_url = mapping_galaxy_icon[galaxy_cluster['icon']]
icon_url = mapping_galaxy_icon[galaxy_cluster['icon']] except KeyError:
except Exception: icon_url = None
# it's not in our mapping, just ignore and leave the default Galaxy icon # it's not in our mapping, just ignore and leave the default Galaxy icon
pass 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']), '{}\n{}'.format(c['type'], c['value']),
uuid=c['uuid'], uuid=c['uuid'],
description=c.get('description'), description=c.get('description'),

View File

@ -1,6 +1,6 @@
from canari.maltego.transform import Transform from canari.maltego.transform import Transform
# from canari.framework import EnableDebugWindow # 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 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 from canari.maltego.message import UIMessageType, UIMessage, LinkDirection
@ -16,16 +16,6 @@ __email__ = 'christophe@vandeplas.com'
__status__ = 'Development' __status__ = 'Development'
class GalaxyTo(Transform):
input_type = None
def __init__(self):
self.request = None
self.response = None
self.config = None
self.misp = None
# @EnableDebugWindow # @EnableDebugWindow
class GalaxyToEvents(Transform): class GalaxyToEvents(Transform):
"""Expands a Galaxy to multiple MISP Events.""" """Expands a Galaxy to multiple MISP Events."""
@ -48,14 +38,14 @@ class GalaxyToEvents(Transform):
# @EnableDebugWindow # @EnableDebugWindow
class GalaxyToRelations(Transform): class GalaxyToTransform(Transform):
"""Expans a Galaxy to related Galaxies and Clusters""" input_type = None
input_type = MISPGalaxy
def do_transform(self, request, response, config): def do_transform(self, request, response, config, type_filter=MISPGalaxy):
response += check_update(config) response += check_update(config)
maltego_misp_galaxy = request.entity maltego_misp_galaxy = request.entity
current_cluster = None
if maltego_misp_galaxy.uuid: if maltego_misp_galaxy.uuid:
current_cluster = get_galaxy_cluster(uuid=maltego_misp_galaxy.uuid) current_cluster = get_galaxy_cluster(uuid=maltego_misp_galaxy.uuid)
elif maltego_misp_galaxy.tag_name: elif maltego_misp_galaxy.tag_name:
@ -63,7 +53,7 @@ class GalaxyToRelations(Transform):
elif maltego_misp_galaxy.name: elif maltego_misp_galaxy.name:
current_cluster = get_galaxy_cluster(tag=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. # maybe the user is searching for a cluster based on a substring.
# Search in the list for those that match and return galaxy entities # Search in the list for those that match and return galaxy entities
potential_clusters = search_galaxy_cluster(maltego_misp_galaxy.name) 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) 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 return response
c = current_cluster c = current_cluster
# update existing object
# update existing object
galaxy_cluster = get_galaxy_cluster(c['uuid']) galaxy_cluster = get_galaxy_cluster(c['uuid'])
icon_url = None icon_url = None
if 'icon' in galaxy_cluster: # map the 'icon' name from the cluster to the icon filename of the intelligence-icons repository 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.tag_name = c['tag_name']
request.entity.icon_url = icon_url request.entity.icon_url = icon_url
# response += request.entity # response += request.entity
# find related objects # find related objects
if 'related' in current_cluster: if 'related' in current_cluster:
for related in current_cluster['related']: for related in current_cluster['related']:
related_cluster = get_galaxy_cluster(related['dest-uuid']) related_cluster = get_galaxy_cluster(related['dest-uuid'])
if related_cluster: 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 # find objects that are relating to this one
for related in get_galaxies_relating(current_cluster['uuid']): for related in get_galaxies_relating(current_cluster['uuid']):
related_link_label = '' related_link_label = ''
@ -113,5 +106,39 @@ class GalaxyToRelations(Transform):
if rel_in_rel['dest-uuid'] == current_cluster['uuid']: if rel_in_rel['dest-uuid'] == current_cluster['uuid']:
related_link_label = rel_in_rel['type'] related_link_label = rel_in_rel['type']
break 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 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)