Merge branch '2.4' of github.com:MISP/MISP into 2.4

pull/3183/head
iglocska 2018-04-23 11:49:10 +02:00
commit ff454b0303
1 changed files with 51 additions and 0 deletions

View File

@ -43,6 +43,7 @@ class StixParser():
self.misp_event = MISPEvent()
self.misp_event['Galaxy'] = []
# Load data from STIX document, and other usefull data
def load(self, args, pathname):
try:
filename = '{}/tmp/{}'.format(pathname, args[1])
@ -62,6 +63,7 @@ class StixParser():
print(json.dumps({'success': 0, 'message': 'The temporary STIX export file could not be read'}))
sys.exit(0)
# Event loading function, recursively itterating as long as namespace errors appear
def load_event(self, filename):
try:
return STIXPackage.from_xml(filename)
@ -75,6 +77,7 @@ class StixParser():
else:
return None
# Load the mapping dictionary for STIX object types
def load_mapping(self):
self.attribute_types_mapping = {
'AddressObjectType': self.handle_address,
@ -94,6 +97,8 @@ class StixParser():
"WindowsExecutableFileObjectType": self.handle_pe
}
# Define if the STIX document is from MISP or is an external one
# Call then the appropriate function to parse it
def handler(self):
self.outputname = '{}.json'.format(self.filename)
if self.fromMISP:
@ -103,12 +108,14 @@ class StixParser():
# external STIX format file
self.buildExternalDict()
# Build a MISP event, parsing STIX data following the structure used in our own exporter
def buildMispDict(self):
self.dictTimestampAndDate()
self.eventInfo()
for indicator in self.event.related_indicators.indicator:
self.parse_misp_indicator(indicator)
# Try to parse data from external STIX documents
def buildExternalDict(self):
self.dictTimestampAndDate()
self.eventInfo()
@ -121,6 +128,7 @@ class StixParser():
if self.event.courses_of_action:
self.parse_coa(self.event.courses_of_action)
# Set timestamp & date values in the new MISP event
def dictTimestampAndDate(self):
if self.event.timestamp:
stixTimestamp = self.event.timestamp
@ -131,6 +139,7 @@ class StixParser():
self.misp_event.date = date
self.misp_event.timestamp = self.getTimestampfromDate(stixTimestamp)
# Translate date into timestamp
@staticmethod
def getTimestampfromDate(date):
try:
@ -144,6 +153,7 @@ class StixParser():
d = int(time.mktime(date.timetuple()))
return d
# Set info & title values in the new MISP event
def eventInfo(self):
info = "Imported from external STIX event"
try:
@ -157,6 +167,7 @@ class StixParser():
pass
self.misp_event.info = str(info)
# Parse indicators of a STIX document coming from our exporter
def parse_misp_indicator(self, indicator):
# define is an indicator will be imported as attribute or object
if indicator.relationship in categories:
@ -164,6 +175,7 @@ class StixParser():
else:
self.parse_misp_object(indicator)
# Parse STIX objects that we know will give MISP attributes
def parse_misp_attribute(self, indicator):
misp_attribute = {'category': str(indicator.relationship)}
item = indicator.item
@ -184,6 +196,7 @@ class StixParser():
attribute_type, attribute_value = self.composite_type(attribute_dict)
self.misp_event.add_attribute(attribute_type, attribute_value, **misp_attribute)
# Return type & value of a composite attribute in MISP
@staticmethod
def composite_type(attributes):
if "port" in attributes:
@ -200,6 +213,7 @@ class StixParser():
ip_value = attributes["ip-dst"]
return "domain|ip", "{}|{}".format(attributes["domain"], ip_value)
# Define type & value of an attribute or object in MISP
def handle_attribute_type(self, properties, is_object=False, title=None):
xsi_type = properties._XSI_TYPE
try:
@ -214,6 +228,7 @@ class StixParser():
print("Unparsed type: {}".format(xsi_type))
sys.exit(1)
# Return type & value of an ip address attribute
@staticmethod
def handle_address(properties):
if properties.is_source:
@ -222,15 +237,18 @@ class StixParser():
ip_type = "ip-dst"
return ip_type, properties.address_value.value, "ip"
# Return type & value of an attachment attribute
@staticmethod
def handle_attachment(properties, title):
return eventTypes[properties._XSI_TYPE]['type'], title, properties.raw_artifact.value
# Return type & value of a domain or url attribute
@staticmethod
def handle_domain_or_url(properties):
event_types = eventTypes[properties._XSI_TYPE]
return event_types['type'], properties.value.value, event_types['relation']
# Return type & value of an email attribute
def handle_email_attribute(self, properties):
try:
if properties.from_:
@ -257,11 +275,13 @@ class StixParser():
print("Unsupported Email property")
sys.exit(1)
# Return type & value of an email attachment
@staticmethod
def handle_email_attachment(indicator_object):
properties = indicator_object.related_objects[0].properties
return "email-attachment", properties.file_name.value, "attachment"
# Return type & attributes of a file object
def handle_file(self, properties, is_object):
b_hash, b_file = False, False
attributes = []
@ -296,6 +316,7 @@ class StixParser():
return self.handle_filename_object(attributes, is_object)
return "file", self.return_attributes(attributes), ""
# Return the appropriate type & value when we have 1 filename & 1 hash value
@staticmethod
def handle_filename_object(attributes, is_object):
for attribute in attributes:
@ -313,6 +334,7 @@ class StixParser():
# it could be malware-sample as well, but STIX is losing this information
return "filename|{}".format(hash_type), value, ""
# Return type & value of a hash attribute
@staticmethod
def handle_hashes_attribute(properties):
hash_type = properties.type_.value.lower()
@ -322,11 +344,13 @@ class StixParser():
hash_value = properties.fuzzy_hash_value.value
return hash_type, hash_value, hash_type
# Return type & value of a hostname attribute
@staticmethod
def handle_hostname(properties):
event_types = eventTypes[properties._XSI_TYPE]
return event_types['type'], properties.hostname_value.value, event_types['relation']
# Return type & value of a http request attribute
@staticmethod
def handle_http(properties):
client_request = properties.http_request_response[0].http_client_request
@ -342,21 +366,25 @@ class StixParser():
value = client_request.http_request_line.http_method.value
return "http-method", value, "method"
# Return type & value of a mutex attribute
@staticmethod
def handle_mutex(properties):
event_types = eventTypes[properties._XSI_TYPE]
return event_types['type'], properties.name.value, event_types['relation']
# Return type & value of a port attribute
@staticmethod
def handle_port(properties):
event_types = eventTypes[properties._XSI_TYPE]
return event_types['type'], properties.port_value.value, event_types['relation']
# Return type & value of a regkey attribute
@staticmethod
def handle_regkey(properties):
event_types = eventTypes[properties._XSI_TYPE]
return event_types['type'], properties.key.value, event_types['relation']
# Return type & value of a composite attribute ip|port or hostname|port
def handle_socket_address(self, properties):
if properties.ip_address:
type1, value1, _ = self.handle_address(properties.ip_address)
@ -365,6 +393,9 @@ class StixParser():
value1 = properties.hostname.hostname_value.value
return "{}|port".format(type1), "{}|{}".format(value1, properties.port.port_value.value), ""
# Parse a whois object:
# Return type & attributes of a whois object if we have the required fields
# Otherwise create attributes and return type & value of the last attribute to avoid crashing the parent function
def handle_whois(self, properties):
required_one_of = False
attributes = []
@ -411,11 +442,14 @@ class StixParser():
self.misp_event.add_attribute(attribute_type, attribute_value, **misp_attributes)
return last_attribute
# Return type & attributes of the file defining a portable executable object
def handle_pe(self, properties):
pe_uuid = self.parse_pe(properties)
file_type, file_value, _ = self.handle_file(properties, False)
return file_type, file_value, pe_uuid
# Parse attributes of a portable executable, create the corresponding object,
# and return its uuid to build the reference for the file object generated at the same time
def parse_pe(self, properties):
misp_object = MISPObject('pe')
filename = properties.file_name.value
@ -445,6 +479,8 @@ class StixParser():
self.misp_event.add_object(**misp_object)
return {"pe_uuid": misp_object.uuid}
# Parse attributes of a portable executable section, create the corresponding object,
# and return its uuid to build the reference for the pe object generated at the same time
def parse_pe_section(self, section):
section_object = MISPObject('pe-section')
header_hashes = section.header_hashes
@ -463,6 +499,7 @@ class StixParser():
self.misp_event.add_object(**section_object)
return section_object.uuid
# Parse STIX object that we know will give MISP objects
def parse_misp_object(self, indicator):
object_type = str(indicator.relationship)
if object_type == 'file':
@ -477,6 +514,7 @@ class StixParser():
if object_type != "misc":
print("Unparsed Object type: {}".format(name))
# Create a MISP object, its attributes, and add it in the MISP event
def fill_misp_object(self, item, name):
misp_object = MISPObject(name)
misp_object.timestamp = self.getTimestampfromDate(item.timestamp)
@ -490,11 +528,13 @@ class StixParser():
self.parse_observable(properties, misp_object)
self.misp_event.add_object(**misp_object)
# Create a MISP attribute and add it in its MISP object
def parse_observable(self, properties, misp_object):
misp_attribute = MISPAttribute()
misp_attribute.type, misp_attribute.value, misp_attribute.object_relation = self.handle_attribute_type(properties, is_object=True)
misp_object.add_attribute(**misp_attribute)
# Parse indicators of an external STIX document
def parse_external_indicator(self, indicators):
for indicator in indicators:
try:
@ -514,6 +554,7 @@ class StixParser():
# otherwise, it is a dictionary of attributes, so we build an object
self.handle_object_case(attribute_type, attribute_value, compl_data)
# Parse observables of an external STIX document
def parse_external_observable(self, observables):
for observable in observables:
title = observable.title
@ -537,6 +578,7 @@ class StixParser():
if attribute_value:
self.handle_object_case(attribute_type, attribute_value, compl_data)
# Parse description of an external indicator or observable and add it in the MISP event as an attribute
def parse_description(self, stix_object):
if stix_object.description:
misp_attribute = {}
@ -544,11 +586,15 @@ class StixParser():
misp_attribute['timestamp'] = self.getTimestampfromDate(stix_object.timestamp)
self.misp_event.add_attribute("text", stix_object.description.value, **misp_attribute)
# The value returned by the indicators or observables parser is of type str or int
# Thus we can add an attribute in the MISP event with the type & value
def handle_attribute_case(self, attribute_type, attribute_value, data, attribute):
if attribute_type == 'attachment':
attribute['data'] = data
self.misp_event.add_attribute(attribute_type, attribute_value, **attribute)
# The value returned by the indicators or observables parser is a list of dictionaries
# These dictionaries are the attributes we add in an object, itself added in the MISP event
def handle_object_case(self, attribute_type, attribute_value, compl_data):
misp_object = MISPObject(attribute_type)
for attribute in attribute_value:
@ -560,6 +606,7 @@ class StixParser():
misp_object.add_reference(compl_data['pe_uuid'], 'pe')
self.misp_event.add_object(**misp_object)
# Parse the ttps field of an external STIX document
def parse_ttps(self, ttps):
for ttp in ttps:
if ttp.behavior and ttp.behavior.malware_instances:
@ -580,6 +627,7 @@ class StixParser():
galaxy['GalaxyCluster'] = [cluster]
self.misp_event['Galaxy'].append(galaxy)
# Parse the courses of action field of an external STIX document
def parse_coa(self, courses_of_action):
for coa in courses_of_action:
misp_object = MISPObject('course-of-action')
@ -626,6 +674,7 @@ class StixParser():
misp_object.add_reference(referenced_uuid, 'observable', None, **attribute)
self.misp_event.add_object(**misp_object)
# Return the attributes that will be added in a MISP object as a list of dictionaries
@staticmethod
def return_attributes(attributes):
return_attributes = []
@ -633,6 +682,8 @@ class StixParser():
return_attributes.append(dict(zip(('type', 'value', 'object_relation'), attribute)))
return return_attributes
# Convert the MISP event we create from the STIX document into json format
# and write it in the output file
def saveFile(self):
eventDict = self.misp_event.to_json()
with open(self.outputname, 'w') as f: