mirror of https://github.com/MISP/misp-modules
Cytomic Orion MISP Module
An expansion module to enrich attributes in MISP and share indicators of compromise with Cytomic Orionpull/379/head
parent
0b4d6738de
commit
e023f0b470
|
@ -33,6 +33,7 @@ For more information: [Extending MISP with Python modules](https://www.misp-proj
|
||||||
* [CVE](misp_modules/modules/expansion/cve.py) - a hover module to give more information about a vulnerability (CVE).
|
* [CVE](misp_modules/modules/expansion/cve.py) - a hover module to give more information about a vulnerability (CVE).
|
||||||
* [CVE advanced](misp_modules/modules/expansion/cve_advanced.py) - An expansion module to query the CIRCL CVE search API for more information about a vulnerability (CVE).
|
* [CVE advanced](misp_modules/modules/expansion/cve_advanced.py) - An expansion module to query the CIRCL CVE search API for more information about a vulnerability (CVE).
|
||||||
* [Cuckoo submit](misp_modules/modules/expansion/cuckoo_submit.py) - A hover module to submit malware sample, url, attachment, domain to Cuckoo Sandbox.
|
* [Cuckoo submit](misp_modules/modules/expansion/cuckoo_submit.py) - A hover module to submit malware sample, url, attachment, domain to Cuckoo Sandbox.
|
||||||
|
* [Cytomic Orion](misp_modules/modules/expansion/cytomic_orion.py) - An expansion module to enrich attributes in MISP and share indicators of compromise with Cytomic Orion.
|
||||||
* [DBL Spamhaus](misp_modules/modules/expansion/dbl_spamhaus.py) - a hover module to check Spamhaus DBL for a domain name.
|
* [DBL Spamhaus](misp_modules/modules/expansion/dbl_spamhaus.py) - a hover module to check Spamhaus DBL for a domain name.
|
||||||
* [DNS](misp_modules/modules/expansion/dns.py) - a simple module to resolve MISP attributes like hostname and domain to expand IP addresses attributes.
|
* [DNS](misp_modules/modules/expansion/dns.py) - a simple module to resolve MISP attributes like hostname and domain to expand IP addresses attributes.
|
||||||
* [docx-enrich](misp_modules/modules/expansion/docx_enrich.py) - an enrichment module to get text out of Word document into MISP (using free-text parser).
|
* [docx-enrich](misp_modules/modules/expansion/docx_enrich.py) - an enrichment module to get text out of Word document into MISP (using free-text parser).
|
||||||
|
|
|
@ -16,4 +16,4 @@ __all__ = ['cuckoo_submit', 'vmray_submit', 'bgpranking', 'circl_passivedns', 'c
|
||||||
'ods_enrich', 'odt_enrich', 'joesandbox_submit', 'joesandbox_query', 'urlhaus',
|
'ods_enrich', 'odt_enrich', 'joesandbox_submit', 'joesandbox_query', 'urlhaus',
|
||||||
'virustotal_public', 'apiosintds', 'urlscan', 'securitytrails', 'apivoid',
|
'virustotal_public', 'apiosintds', 'urlscan', 'securitytrails', 'apivoid',
|
||||||
'assemblyline_submit', 'assemblyline_query', 'ransomcoindb',
|
'assemblyline_submit', 'assemblyline_query', 'ransomcoindb',
|
||||||
'lastline_query', 'lastline_submit', 'sophoslabs_intelix']
|
'lastline_query', 'lastline_submit', 'sophoslabs_intelix', 'cytomic_orion.py']
|
||||||
|
|
|
@ -0,0 +1,183 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
'''
|
||||||
|
Cytomic Orion MISP Module
|
||||||
|
An expansion module to enrich attributes in MISP and share indicators of compromise with Cytomic Orion
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
from pymisp import MISPAttribute, MISPEvent, MISPObject, MISPTag
|
||||||
|
import json
|
||||||
|
import requests
|
||||||
|
import re
|
||||||
|
|
||||||
|
misperrors = {'error': 'Error'}
|
||||||
|
mispattributes = {'input': ['md5'], 'format': 'misp_standard'}
|
||||||
|
moduleinfo = {'version': '0.3', 'author': 'Koen Van Impe',
|
||||||
|
'description': 'an expansion module to enrich attributes in MISP and share indicators of compromise with Cytomic Orion',
|
||||||
|
'module-type': ['expansion']}
|
||||||
|
moduleconfig = ['api_url', 'token_url', 'clientid', 'clientsecret', 'clientsecret', 'username', 'password', 'upload_timeframe', 'upload_tag', 'delete_tag', 'upload_ttlDays', 'upload_threat_level_id', 'limit_upload_events', 'limit_upload_attributes']
|
||||||
|
# There are more config settings in this module than used by the enrichment
|
||||||
|
# There is also a PyMISP module which reuses the module config, and requires additional configuration, for example used for pushing indicators to the API
|
||||||
|
|
||||||
|
|
||||||
|
class CytomicParser():
|
||||||
|
def __init__(self, attribute, config_object):
|
||||||
|
self.misp_event = MISPEvent()
|
||||||
|
self.attribute = MISPAttribute()
|
||||||
|
self.attribute.from_dict(**attribute)
|
||||||
|
self.misp_event.add_attribute(**self.attribute)
|
||||||
|
|
||||||
|
self.config_object = config_object
|
||||||
|
|
||||||
|
if self.config_object:
|
||||||
|
self.token = self.get_token()
|
||||||
|
else:
|
||||||
|
return {'error': 'Missing configuration'}
|
||||||
|
|
||||||
|
def get_token(self):
|
||||||
|
try:
|
||||||
|
scope = self.config_object['scope']
|
||||||
|
grant_type = self.config_object['grant_type']
|
||||||
|
username = self.config_object['username']
|
||||||
|
password = self.config_object['password']
|
||||||
|
token_url = self.config_object['token_url']
|
||||||
|
clientid = self.config_object['clientid']
|
||||||
|
clientsecret = self.config_object['clientsecret']
|
||||||
|
|
||||||
|
if scope and grant_type and username and password:
|
||||||
|
data = {'scope': scope, 'grant_type': grant_type, 'username': username, 'password': password}
|
||||||
|
|
||||||
|
if token_url and clientid and clientsecret:
|
||||||
|
access_token_response = requests.post(token_url, data=data, verify=False, allow_redirects=False, auth=(clientid, clientsecret))
|
||||||
|
tokens = json.loads(access_token_response.text)
|
||||||
|
if 'access_token' in tokens:
|
||||||
|
return tokens['access_token']
|
||||||
|
else:
|
||||||
|
self.result = {'error': 'No token received.'}
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
self.result = {'error': 'No token_url, clientid or clientsecret supplied.'}
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
self.result = {'error': 'No scope, grant_type, username or password supplied.'}
|
||||||
|
return
|
||||||
|
except Exception:
|
||||||
|
self.result = {'error': 'Unable to connect to token_url.'}
|
||||||
|
return
|
||||||
|
|
||||||
|
def get_results(self):
|
||||||
|
if hasattr(self, 'result'):
|
||||||
|
return self.result
|
||||||
|
event = json.loads(self.misp_event.to_json())
|
||||||
|
results = {key: event[key] for key in ('Attribute', 'Object')}
|
||||||
|
return {'results': results}
|
||||||
|
|
||||||
|
def parse(self, searchkey):
|
||||||
|
|
||||||
|
if self.token:
|
||||||
|
|
||||||
|
endpoint_fileinformation = self.config_object['endpoint_fileinformation']
|
||||||
|
endpoint_machines = self.config_object['endpoint_machines']
|
||||||
|
endpoint_machines_client = self.config_object['endpoint_machines_client']
|
||||||
|
query_machines = self.config_object['query_machines']
|
||||||
|
query_machine_info = self.config_object['query_machine_info']
|
||||||
|
|
||||||
|
# Update endpoint URLs
|
||||||
|
query_endpoint_fileinformation = endpoint_fileinformation.format(md5=searchkey)
|
||||||
|
query_endpoint_machines = endpoint_machines.format(md5=searchkey)
|
||||||
|
|
||||||
|
# API calls
|
||||||
|
api_call_headers = {'Authorization': 'Bearer ' + self.token}
|
||||||
|
result_query_endpoint_fileinformation = requests.get(query_endpoint_fileinformation, headers=api_call_headers, verify=False)
|
||||||
|
json_result_query_endpoint_fileinformation = json.loads(result_query_endpoint_fileinformation.text)
|
||||||
|
|
||||||
|
if json_result_query_endpoint_fileinformation:
|
||||||
|
|
||||||
|
cytomic_object = MISPObject('cytomic-orion-file')
|
||||||
|
|
||||||
|
cytomic_object.add_attribute('fileName', type='text', value=json_result_query_endpoint_fileinformation['fileName'])
|
||||||
|
cytomic_object.add_attribute('fileSize', type='text', value=json_result_query_endpoint_fileinformation['fileSize'])
|
||||||
|
cytomic_object.add_attribute('last-seen', type='datetime', value=json_result_query_endpoint_fileinformation['lastSeen'])
|
||||||
|
cytomic_object.add_attribute('first-seen', type='datetime', value=json_result_query_endpoint_fileinformation['firstSeen'])
|
||||||
|
cytomic_object.add_attribute('classification', type='text', value=json_result_query_endpoint_fileinformation['classification'])
|
||||||
|
cytomic_object.add_attribute('classificationName', type='text', value=json_result_query_endpoint_fileinformation['classificationName'])
|
||||||
|
self.misp_event.add_object(**cytomic_object)
|
||||||
|
|
||||||
|
result_query_endpoint_machines = requests.get(query_endpoint_machines, headers=api_call_headers, verify=False)
|
||||||
|
json_result_query_endpoint_machines = json.loads(result_query_endpoint_machines.text)
|
||||||
|
|
||||||
|
if json_result_query_endpoint_machines and len(json_result_query_endpoint_machines) > 0:
|
||||||
|
for machine in json_result_query_endpoint_machines:
|
||||||
|
|
||||||
|
if machine['muid'] and query_machine_info:
|
||||||
|
query_endpoint_machines_client = endpoint_machines_client.format(muid=machine['muid'])
|
||||||
|
result_endpoint_machines_client = requests.get(query_endpoint_machines_client, headers=api_call_headers, verify=False)
|
||||||
|
json_result_endpoint_machines_client = json.loads(result_endpoint_machines_client.text)
|
||||||
|
|
||||||
|
if json_result_endpoint_machines_client:
|
||||||
|
|
||||||
|
cytomic_machine_object = MISPObject('cytomic-orion-machine')
|
||||||
|
|
||||||
|
clienttag = [{'name': json_result_endpoint_machines_client['clientName']}]
|
||||||
|
|
||||||
|
cytomic_machine_object.add_attribute('machineName', type='target-machine', value=json_result_endpoint_machines_client['machineName'], Tag=clienttag)
|
||||||
|
cytomic_machine_object.add_attribute('machineMuid', type='text', value=machine['muid'])
|
||||||
|
cytomic_machine_object.add_attribute('clientName', type='target-org', value=json_result_endpoint_machines_client['clientName'], Tag=clienttag)
|
||||||
|
cytomic_machine_object.add_attribute('clientId', type='text', value=machine['clientId'])
|
||||||
|
cytomic_machine_object.add_attribute('machinePath', type='text', value=machine['lastPath'])
|
||||||
|
cytomic_machine_object.add_attribute('first-seen', type='datetime', value=machine['firstSeen'])
|
||||||
|
cytomic_machine_object.add_attribute('last-seen', type='datetime', value=machine['lastSeen'])
|
||||||
|
cytomic_machine_object.add_attribute('creationDate', type='datetime', value=json_result_endpoint_machines_client['creationDate'])
|
||||||
|
cytomic_machine_object.add_attribute('clientCreationDateUTC', type='datetime', value=json_result_endpoint_machines_client['clientCreationDateUTC'])
|
||||||
|
cytomic_machine_object.add_attribute('lastSeenUtc', type='datetime', value=json_result_endpoint_machines_client['lastSeenUtc'])
|
||||||
|
self.misp_event.add_object(**cytomic_machine_object)
|
||||||
|
else:
|
||||||
|
self.result = {'error': 'No (valid) token.'}
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def handler(q=False):
|
||||||
|
if q is False:
|
||||||
|
return False
|
||||||
|
request = json.loads(q)
|
||||||
|
|
||||||
|
if not request.get('attribute'):
|
||||||
|
return {'error': 'Unsupported input.'}
|
||||||
|
|
||||||
|
attribute = request['attribute']
|
||||||
|
if not any(input_type == attribute['type'] for input_type in mispattributes['input']):
|
||||||
|
return {'error': 'Unsupported attributes type'}
|
||||||
|
|
||||||
|
if not request.get('config'):
|
||||||
|
return {'error': 'Missing configuration'}
|
||||||
|
|
||||||
|
config_object = {
|
||||||
|
'clientid': request["config"].get("clientid"),
|
||||||
|
'clientsecret': request["config"].get("clientsecret"),
|
||||||
|
'scope': 'orion.api',
|
||||||
|
'password': request["config"].get("password"),
|
||||||
|
'username': request["config"].get("username"),
|
||||||
|
'grant_type': 'password',
|
||||||
|
'token_url': request["config"].get("token_url"),
|
||||||
|
'endpoint_fileinformation': '{api_url}{endpoint}'.format(api_url=request["config"].get("api_url"), endpoint='/forensics/md5/{md5}/info'),
|
||||||
|
'endpoint_machines': '{api_url}{endpoint}'.format(api_url=request["config"].get("api_url"), endpoint='/forensics/md5/{md5}/muids'),
|
||||||
|
'endpoint_machines_client': '{api_url}{endpoint}'.format(api_url=request["config"].get("api_url"), endpoint='/forensics/muid/{muid}/info'),
|
||||||
|
'query_machines': True,
|
||||||
|
'query_machine_info': True
|
||||||
|
}
|
||||||
|
|
||||||
|
cytomic_parser = CytomicParser(attribute, config_object)
|
||||||
|
cytomic_parser.parse(attribute['value'])
|
||||||
|
|
||||||
|
return cytomic_parser.get_results()
|
||||||
|
|
||||||
|
|
||||||
|
def introspection():
|
||||||
|
return mispattributes
|
||||||
|
|
||||||
|
|
||||||
|
def version():
|
||||||
|
moduleinfo['config'] = moduleconfig
|
||||||
|
return moduleinfo
|
Loading…
Reference in New Issue