Merge remote-tracking branch 'upstream/2.4' into distributionGraph

pull/3214/head
Sami Mokaddem 2018-04-23 12:52:12 +00:00
commit 72ca4260be
9 changed files with 73 additions and 11 deletions

View File

@ -1200,7 +1200,7 @@ INSERT INTO `roles` (`id`, `name`, `created`, `modified`, `perm_add`, `perm_modi
VALUES (1, 'admin', NOW(), NOW(), 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0); VALUES (1, 'admin', NOW(), NOW(), 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0);
INSERT INTO `roles` (`id`, `name`, `created`, `modified`, `perm_add`, `perm_modify`, `perm_modify_org`, `perm_publish`, `perm_sync`, `perm_admin`, `perm_audit`, `perm_full`, `perm_auth`, `perm_regexp_access`, `perm_tagger`, `perm_site_admin`, `perm_template`, `perm_sharing_group`, `perm_tag_editor`, `perm_delegate`, `perm_sighting`, `perm_object_template`, `default_role`) INSERT INTO `roles` (`id`, `name`, `created`, `modified`, `perm_add`, `perm_modify`, `perm_modify_org`, `perm_publish`, `perm_sync`, `perm_admin`, `perm_audit`, `perm_full`, `perm_auth`, `perm_regexp_access`, `perm_tagger`, `perm_site_admin`, `perm_template`, `perm_sharing_group`, `perm_tag_editor`, `perm_delegate`, `perm_sighting`, `perm_object_template`, `default_role`)
VALUES (2, 'Org Admin', NOW(), NOW(), 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0); VALUES (2, 'Org Admin', NOW(), NOW(), 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0);
INSERT INTO `roles` (`id`, `name`, `created`, `modified`, `perm_add`, `perm_modify`, `perm_modify_org`, `perm_publish`, `perm_sync`, `perm_admin`, `perm_audit`, `perm_full`, `perm_auth`, `perm_regexp_access`, `perm_tagger`, `perm_site_admin`, `perm_template`, `perm_sharing_group`, `perm_tag_editor`, `perm_delegate`, `perm_sighting`, `perm_object_template`, `default_role`) INSERT INTO `roles` (`id`, `name`, `created`, `modified`, `perm_add`, `perm_modify`, `perm_modify_org`, `perm_publish`, `perm_sync`, `perm_admin`, `perm_audit`, `perm_full`, `perm_auth`, `perm_regexp_access`, `perm_tagger`, `perm_site_admin`, `perm_template`, `perm_sharing_group`, `perm_tag_editor`, `perm_delegate`, `perm_sighting`, `perm_object_template`, `default_role`)
VALUES (3, 'User', NOW(), NOW(), 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1); VALUES (3, 'User', NOW(), NOW(), 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1);

View File

@ -1 +1 @@
{"major":2, "minor":4, "hotfix":89} {"major":2, "minor":4, "hotfix":90}

View File

@ -628,15 +628,20 @@ class EventsController extends AppController {
) )
) )
)); ));
foreach ($eventTags as $et) { foreach ($eventTags as $ket => $et) {
$et['EventTag']['Tag'] = $et['Tag']; if (empty($et['Tag']['id'])) {
unset($et['Tag']); unset($eventTags[$ket]);
if (empty($event_tag_objects[$et['EventTag']['event_id']])) {
$event_tag_objects[$et['EventTag']['event_id']] = array($et['EventTag']);
} else { } else {
$event_tag_objects[$et['EventTag']['event_id']][] = $et['EventTag']; $et['EventTag']['Tag'] = $et['Tag'];
unset($et['Tag']);
if (empty($event_tag_objects[$et['EventTag']['event_id']])) {
$event_tag_objects[$et['EventTag']['event_id']] = array($et['EventTag']);
} else {
$event_tag_objects[$et['EventTag']['event_id']][] = $et['EventTag'];
}
} }
} }
$eventTags = array_values($eventTags);
for ($j = 0; $j < $elements; $j++) { for ($j = 0; $j < $elements; $j++) {
if (!empty($event_tag_objects[$events[($i*1000) + $j]['Event']['id']])) { if (!empty($event_tag_objects[$events[($i*1000) + $j]['Event']['id']])) {
$events[($i*1000) + $j]['EventTag'] = $event_tag_objects[$events[($i*1000) + $j]['Event']['id']]; $events[($i*1000) + $j]['EventTag'] = $event_tag_objects[$events[($i*1000) + $j]['Event']['id']];

View File

@ -171,7 +171,7 @@ class TagsController extends AppController {
if ($this->Tag->save($this->request->data)) { if ($this->Tag->save($this->request->data)) {
if ($this->_isRest()) { if ($this->_isRest()) {
$tag = $this->Tag->find('first', array( $tag = $this->Tag->find('first', array(
'contidions' => array( 'conditions' => array(
'Tag.id' => $this->Tag->id 'Tag.id' => $this->Tag->id
), ),
'recursive' => -1 'recursive' => -1

View File

@ -2700,6 +2700,7 @@ class Event extends AppModel {
} }
} }
} }
throw new Exception();
} }
if ($fromXml) $created_id = $this->id; if ($fromXml) $created_id = $this->id;
if (!empty($data['Event']['published']) && 1 == $data['Event']['published']) { if (!empty($data['Event']['published']) && 1 == $data['Event']['published']) {
@ -3608,7 +3609,8 @@ class Event extends AppModel {
$this->__fTool = new FinancialTool(); $this->__fTool = new FinancialTool();
} }
if ($object['type'] == 'attachment' && preg_match('/.*\.(jpg|png|jpeg|gif)$/i', $object['value'])) { if ($object['type'] == 'attachment' && preg_match('/.*\.(jpg|png|jpeg|gif)$/i', $object['value'])) {
$object['image'] = $this->Attribute->base64EncodeAttachment($object); if (!empty($object['data'])) $object['image'] = $object['data'];
else $object['image'] = $this->Attribute->base64EncodeAttachment($object);
} }
if (isset($object['distribution']) && $object['distribution'] != 4) unset($object['SharingGroup']); if (isset($object['distribution']) && $object['distribution'] != 4) unset($object['SharingGroup']);
if ($object['objectType'] !== 'object') { if ($object['objectType'] !== 'object') {

View File

@ -10,7 +10,7 @@
if ($attribute['Attribute']['disable_correlation']) { if ($attribute['Attribute']['disable_correlation']) {
echo __('Re-enable the correlation for this attribute.'); echo __('Re-enable the correlation for this attribute.');
} else { } else {
echo __('This will remove all correlations that already exist for this attribute and prevents any attributes to be related as long as this setting is disabled. Make sure you understand the downasides of disabling correlations.'); echo __('This will remove all correlations that already exist for this attribute and prevents any attributes to be related as long as this setting is disabled. Make sure you understand the downsides of disabling correlations.');
} }
?> ?>
</p> </p>

View File

@ -129,6 +129,8 @@ if (h($user['User']['change_pw']) == 1) {
</dd> </dd>
</dl> </dl>
<br /> <br />
<a href="<?php echo $baseurl . '/admin/users/view/' . h($user['User']['id']) . '.json'; ?>" class="btn btn-inverse" download>Download user profile for data portability</a>
<br />
<div id="userEvents"></div> <div id="userEvents"></div>
</div> </div>
<?php <?php

View File

@ -86,6 +86,8 @@
</dd> </dd>
<?php endif; ?> <?php endif; ?>
</dl> </dl>
<br />
<a href="<?php echo $baseurl . '/users/view/me.json'; ?>" class="btn btn-inverse" download>Download user profile for data portability</a>
</div> </div>
<?php <?php
echo $this->element('side_menu', array('menuList' => 'globalActions', 'menuItem' => 'view')); echo $this->element('side_menu', array('menuList' => 'globalActions', 'menuItem' => 'view'));

View File

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