mirror of https://github.com/MISP/PyMISP
156 lines
5.3 KiB
Python
156 lines
5.3 KiB
Python
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
import os
|
|
|
|
from pymisp import MISPEvent
|
|
try:
|
|
from bs4 import BeautifulSoup
|
|
has_bs4 = True
|
|
except ImportError:
|
|
has_bs4 = False
|
|
|
|
|
|
iocMispMapping = {
|
|
'DriverItem/DriverName': {'category': 'Artifacts dropped', 'type': 'other', 'comment': 'DriverName.'},
|
|
|
|
'DnsEntryItem/Host': {'type': 'domain'},
|
|
|
|
'Email/To': {'type': 'target-email'},
|
|
'Email/Date': {'type': 'comment', 'comment': 'EmailDate.'},
|
|
# 'Email/Body': {'type': 'email-subject'},
|
|
'Email/From': {'type': 'email-dst'},
|
|
'Email/Subject': {'type': 'email-subject'},
|
|
'Email/Attachment/Name': {'type': 'email-attachment'},
|
|
|
|
'FileItem/Md5sum': {'type': 'md5'},
|
|
'FileItem/Sha1sum': {'type': 'sha1'},
|
|
'FileItem/Sha256sum': {'type': 'sha256'},
|
|
|
|
'ServiceItem/serviceDLLmd5sum': {'type': 'md5', 'category': 'Payload installation'},
|
|
'ServiceItem/serviceDLLsha1sum': {'type': 'sha1', 'category': 'Payload installation'},
|
|
'ServiceItem/serviceDLLsha256sum': {'type': 'sha256', 'category': 'Payload installation'},
|
|
|
|
'TaskItem/md5sum': {'type': 'md5'},
|
|
'TaskItem/sha1sum': {'type': 'sha1'},
|
|
'TaskItem/Sha256sum': {'type': 'sha256'},
|
|
|
|
'FileItem/FileName': {'type': 'filename'},
|
|
'FileItem/FullPath': {'type': 'filename'},
|
|
'FileItem/FilePath': {'type': 'filename'},
|
|
'DriverItem/DriverName': {'type': 'filename'},
|
|
|
|
'Network/URI': {'type': 'uri'},
|
|
'Network/DNS': {'type': 'domain'},
|
|
'Network/String': {'type': 'ip-dst'},
|
|
'RouteEntryItem/Destination': {'type': 'ip-dst'},
|
|
'Network/UserAgent': {'type': 'user-agent'},
|
|
|
|
'PortItem/localIP': {'type': 'ip-src'},
|
|
'PortItem/remoteIP': {'type': 'ip-dst'},
|
|
|
|
'ProcessItem/name': {'type': 'pattern-in-memory', 'comment': 'ProcessName.'},
|
|
'ProcessItem/path': {'type': 'pattern-in-memory', 'comment': 'ProcessPath.'},
|
|
'ProcessItem/Mutex': {'type': 'mutex'},
|
|
'ProcessItem/Pipe/Name': {'type': 'named pipe'},
|
|
'ProcessItem/Mutex/Name': {'type': 'mutex', 'comment': 'MutexName.'},
|
|
|
|
'CookieHistoryItem/HostName': {'type': 'hostname'},
|
|
'FormHistoryItem/HostName': {'type': 'hostname'},
|
|
'SystemInfoItem/HostName': {'type': 'hostname'},
|
|
'UrlHistoryItem/HostName': {'type': 'hostname'},
|
|
'DnsEntryItem/RecordName': {'type': 'hostname'},
|
|
'DnsEntryItem/Host': {'type': 'hostname'},
|
|
|
|
# Is it the regkey value?
|
|
# 'RegistryItem/Text': {'type': 'regkey', 'RegistryText. '},
|
|
'RegistryItem/KeyPath': {'type': 'regkey'},
|
|
'RegistryItem/Path': {'type': 'regkey'},
|
|
|
|
'ServiceItem/name': {'type': 'windows-service-name'},
|
|
'ServiceItem/type': {'type': 'pattern-in-memory', 'comment': 'ServiceType. '},
|
|
|
|
'Snort/Snort': {'type': 'snort'},
|
|
}
|
|
|
|
|
|
def extract_field(report, field_name):
|
|
data = report.find(field_name.lower())
|
|
if data and hasattr(data, 'text'):
|
|
return data.text
|
|
return None
|
|
|
|
|
|
def load_openioc_file(openioc_path):
|
|
if not os.path.exists(openioc_path):
|
|
raise Exception("Path doesn't exists.")
|
|
with open(openioc_path, 'r') as f:
|
|
return load_openioc(f)
|
|
|
|
|
|
def load_openioc(openioc):
|
|
# Takes a opened file, or a string
|
|
if not has_bs4:
|
|
raise Exception('You need to install BeautifulSoup: pip install bs4')
|
|
misp_event = MISPEvent()
|
|
iocreport = BeautifulSoup(openioc, "html.parser")
|
|
# Set event fields
|
|
info = extract_field(iocreport, 'short_description')
|
|
if info:
|
|
misp_event.info = info
|
|
date = extract_field(iocreport, 'authored_date')
|
|
if date:
|
|
misp_event.set_date(date)
|
|
# Set special attributes
|
|
description = extract_field(iocreport, 'description')
|
|
if description:
|
|
if not misp_event.info:
|
|
misp_event.info = description
|
|
else:
|
|
misp_event.add_attribute('comment', description)
|
|
if not misp_event.info:
|
|
misp_event.info = 'OpenIOC import'
|
|
author = extract_field(iocreport, 'authored_by')
|
|
if author:
|
|
misp_event.add_attribute('comment', author)
|
|
misp_event = set_all_attributes(iocreport, misp_event)
|
|
return misp_event
|
|
|
|
|
|
def get_mapping(openioc_type):
|
|
t = openioc_type.lower()
|
|
for k, v in iocMispMapping.items():
|
|
if k.lower() == t:
|
|
return v
|
|
return False
|
|
|
|
|
|
def set_all_attributes(openioc, misp_event):
|
|
for item in openioc.find_all("indicatoritem"):
|
|
attribute_values = {'comment': ''}
|
|
if item.find('context'):
|
|
mapping = get_mapping(item.find('context')['search'])
|
|
if mapping:
|
|
attribute_values.update(mapping)
|
|
else:
|
|
# Unknown mapping, ignoring
|
|
# print(item.find('context'))
|
|
continue
|
|
else:
|
|
continue
|
|
value = extract_field(item, 'Content')
|
|
if value:
|
|
attribute_values['value'] = value
|
|
else:
|
|
# No value, ignoring
|
|
continue
|
|
comment = extract_field(item, 'Comment')
|
|
if comment:
|
|
attribute_values["comment"] = '{} {}'.format(attribute_values["comment"], comment)
|
|
|
|
if mapping['type'] in ['ip-src', 'ip-dst'] and value.count(':') == 1:
|
|
attribute_values['type'] = mapping['type'] + '|port'
|
|
attribute_values['value'] = attribute_values['value'].replace(':', '|')
|
|
misp_event.add_attribute(**attribute_values)
|
|
return misp_event
|