|
|
|
@ -1,6 +1,7 @@
|
|
|
|
|
<?php
|
|
|
|
|
App::uses('AppController', 'Controller');
|
|
|
|
|
App::uses('Xml', 'Utility');
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Events Controller
|
|
|
|
|
*
|
|
|
|
@ -19,17 +20,16 @@ class EventsController extends AppController {
|
|
|
|
|
'RequestHandler',
|
|
|
|
|
'HidsMd5Export',
|
|
|
|
|
'HidsSha1Export',
|
|
|
|
|
//'NidsSuricataExport',
|
|
|
|
|
'NidsExport',
|
|
|
|
|
'IOCExport',
|
|
|
|
|
'IOCImport',
|
|
|
|
|
'Cidr'
|
|
|
|
|
'IOCImport'
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
public $paginate = array(
|
|
|
|
|
'limit' => 60,
|
|
|
|
|
'maxLimit' => 9999, // LATER we will bump here on a problem once we have more than 9999 events <- no we won't, this is the max a user van view/page.
|
|
|
|
|
'order' => array(
|
|
|
|
|
'Event.timestamp' => 'DESC'
|
|
|
|
|
'Event.id' => 'DESC'
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
@ -45,7 +45,6 @@ class EventsController extends AppController {
|
|
|
|
|
$this->Auth->allow('hids_sha1');
|
|
|
|
|
$this->Auth->allow('text');
|
|
|
|
|
$this->Auth->allow('dot');
|
|
|
|
|
$this->Auth->allow('restSearch');
|
|
|
|
|
|
|
|
|
|
// TODO Audit, activate logable in a Controller
|
|
|
|
|
if (count($this->uses) && $this->{$this->modelClass}->Behaviors->attached('SysLogLogable')) {
|
|
|
|
@ -150,11 +149,6 @@ class EventsController extends AppController {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$this->paginate = array('contain' => array(
|
|
|
|
|
'ThreatLevel' => array(
|
|
|
|
|
'fields' => array(
|
|
|
|
|
'ThreatLevel.name'))
|
|
|
|
|
));
|
|
|
|
|
$this->set('events', $this->paginate());
|
|
|
|
|
if (!$this->Auth->user('gpgkey')) {
|
|
|
|
|
$this->Session->setFlash(__('No GPG key set in your profile. To receive emails, submit your public key in your profile.'));
|
|
|
|
@ -253,54 +247,6 @@ class EventsController extends AppController {
|
|
|
|
|
$this->set('pivot', $pivot);
|
|
|
|
|
$this->set('currentEvent', $id);
|
|
|
|
|
}
|
|
|
|
|
$this->set('allPivots', $this->Session->read('pivot_thread'));
|
|
|
|
|
// Show the discussion
|
|
|
|
|
$this->loadModel('Thread');
|
|
|
|
|
$params = array('conditions' => array('event_id' => $id),
|
|
|
|
|
'recursive' => -1,
|
|
|
|
|
'fields' => array('id', 'event_id', 'distribution', 'title')
|
|
|
|
|
);
|
|
|
|
|
$thread = $this->Thread->find('first', $params);
|
|
|
|
|
if (empty($thread)) {
|
|
|
|
|
$newThread = array(
|
|
|
|
|
'date_created' => date('Y/m/d H:i:s'),
|
|
|
|
|
'date_modified' => date('Y/m/d H:i:s'),
|
|
|
|
|
'user_id' => $this->Auth->user('id'),
|
|
|
|
|
'event_id' => $id,
|
|
|
|
|
'title' => 'Discussion about Event #' . $result['Event']['id'] . ' (' . $result['Event']['info'] . ')',
|
|
|
|
|
'distribution' => $result['Event']['distribution'],
|
|
|
|
|
'post_count' => 0,
|
|
|
|
|
'org' => $result['Event']['orgc']
|
|
|
|
|
);
|
|
|
|
|
$this->Thread->save($newThread);
|
|
|
|
|
$thread = ($this->Thread->read());
|
|
|
|
|
} else {
|
|
|
|
|
if ($thread['Thread']['distribution'] != $result['Event']['distribution']) {
|
|
|
|
|
$this->Thread->saveField('distribution', $result['Event']['distribution']);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$this->loadModel('Post');
|
|
|
|
|
$this->paginate['Post'] = array(
|
|
|
|
|
'limit' => 5,
|
|
|
|
|
'conditions' => array('Post.thread_id' => $thread['Thread']['id']),
|
|
|
|
|
'contain' => 'User'
|
|
|
|
|
);
|
|
|
|
|
$posts = $this->paginate('Post');
|
|
|
|
|
// Show the discussion
|
|
|
|
|
$this->set('posts', $posts);
|
|
|
|
|
$this->set('thread_id', $thread['Thread']['id']);
|
|
|
|
|
$this->set('myuserid', $this->Auth->user('id'));
|
|
|
|
|
$this->set('thread_title', $thread['Thread']['title']);
|
|
|
|
|
if ($this->request->is('ajax')) {
|
|
|
|
|
$this->disableCache();
|
|
|
|
|
$this->layout = 'ajax';
|
|
|
|
|
$this->render('/Elements/eventdiscussion');
|
|
|
|
|
}
|
|
|
|
|
$pivot = $this->Session->read('pivot_thread');
|
|
|
|
|
$this->__arrangePivotVertical($pivot);
|
|
|
|
|
$this->__setDeletable($pivot, $id, true);
|
|
|
|
|
$this->set('pivot', $pivot);
|
|
|
|
|
$this->set('currentEvent', $id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function __startPivoting($id, $info, $date){
|
|
|
|
@ -404,6 +350,122 @@ class EventsController extends AppController {
|
|
|
|
|
return !$pivot['deletable'];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
public function view($id = null) {
|
|
|
|
|
// If the length of the id provided is 36 then it is most likely a Uuid - find the id of the event, change $id to it and proceed to read the event as if the ID was entered.
|
|
|
|
|
$perm_publish = $this->userRole['perm_publish'];
|
|
|
|
|
if (strlen($id) == 36) {
|
|
|
|
|
$this->Event->recursive = -1;
|
|
|
|
|
$temp = $this->Event->findByUuid($id);
|
|
|
|
|
if ($temp == null) throw new NotFoundException(__('Invalid event'));
|
|
|
|
|
$id = $temp['Event']['id'];
|
|
|
|
|
}
|
|
|
|
|
$isSiteAdmin = $this->_isSiteAdmin();
|
|
|
|
|
|
|
|
|
|
$this->Event->id = $id;
|
|
|
|
|
if(!$this->Event->exists()) {
|
|
|
|
|
throw new NotFoundException(__('Invalid event, it already exists.'));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->Event->recursive = 2;
|
|
|
|
|
$this->Event->contain('Attribute', 'ShadowAttribute', 'User.email');
|
|
|
|
|
$this->Event->read();
|
|
|
|
|
$myEvent = true;
|
|
|
|
|
if (!$isSiteAdmin) {
|
|
|
|
|
// check private
|
|
|
|
|
if (($this->Event->data['Event']['distribution'] == 0) && ($this->Event->data['Event']['org'] != $this->Auth->user('org'))) {
|
|
|
|
|
$this->Session->setFlash(__('Invalid event.'));
|
|
|
|
|
$this->redirect(array('controller' => 'events', 'action' => 'index'));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ($this->Event->data['Event']['org'] != $this->Auth->user('org')) {
|
|
|
|
|
$myEvent = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Now that we're loaded the event and made sure that we can actually see it, let's do 2 thngs:
|
|
|
|
|
// run through each attribute and unset it if it's private and we're not an admin or from the owner org of the event
|
|
|
|
|
// if we didn't unset the attribute, rearrange the shadow attributes
|
|
|
|
|
foreach ($this->Event->data['Attribute'] as $key => &$attribute) {
|
|
|
|
|
if (!$isSiteAdmin && !$myEvent && ($attribute['distribution'] == 0)) {
|
|
|
|
|
unset($this->Event->data['Attribute'][$key]);
|
|
|
|
|
} else {
|
|
|
|
|
if (!isset($attribute['ShadowAttribute'])) $attribute['ShadowAttribute'] = array();
|
|
|
|
|
foreach ($this->Event->data['ShadowAttribute'] as $k => &$sa) {
|
|
|
|
|
if ($sa['old_id'] == $attribute['id']) {
|
|
|
|
|
$this->Event->data['Attribute'][$key]['ShadowAttribute'][] = $sa;
|
|
|
|
|
unset($this->Event->data['ShadowAttribute'][$k]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// since we unset some attributes and shadowattributes, let's reindex them.
|
|
|
|
|
$this->Event->data['ShadowAttribute'] = array_values($this->Event->data['ShadowAttribute']);
|
|
|
|
|
$this->Event->data['Attribute'] = array_values($this->Event->data['Attribute']);
|
|
|
|
|
|
|
|
|
|
$this->set('analysisLevels', $this->Event->analysisLevels);
|
|
|
|
|
|
|
|
|
|
$relatedEvents = $this->Event->getRelatedEvents($this->Auth->user());
|
|
|
|
|
$relatedAttributes = $this->Event->getRelatedAttributes($this->Auth->user());
|
|
|
|
|
$this->loadModel('Attribute');
|
|
|
|
|
if ($this->_isRest()) {
|
|
|
|
|
foreach ($this->Event->data['Attribute'] as &$attribute) {
|
|
|
|
|
// for REST requests also add the encoded attachment
|
|
|
|
|
if ($this->Attribute->typeIsAttachment($attribute['type'])) {
|
|
|
|
|
// LATER check if this has a serious performance impact on XML conversion and memory usage
|
|
|
|
|
$encodedFile = $this->Attribute->base64EncodeAttachment($attribute);
|
|
|
|
|
$attribute['data'] = $encodedFile;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// set up the ShadowAttributes for the view - the only shadow attributes that should be passed to the view are the ones that the user is eligible to see
|
|
|
|
|
// This means: Proposals of other organisations to own events, if the user is a publisher
|
|
|
|
|
// Also: proposals made by the current user's organisation
|
|
|
|
|
if (!$this->_isRest()) {
|
|
|
|
|
foreach ($this->Event->data['Attribute'] as &$attribute) {
|
|
|
|
|
// if the user is of the same org as the event and has publishing rights, just show everything
|
|
|
|
|
if (($this->Auth->user('org') != $this->Event->data['Event']['org'] || !$perm_publish) && !$this->_isSiteAdmin()) {
|
|
|
|
|
$counter = 0;
|
|
|
|
|
foreach ($attribute['ShadowAttribute'] as &$shadow) {
|
|
|
|
|
if ($shadow['org'] != $this->Auth->user('org')) unset($attribute['ShadowAttribute'][$counter]);
|
|
|
|
|
$counter++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// params for the jQuery RESTfull interface
|
|
|
|
|
$this->set('authkey', $this->Auth->user('authkey'));
|
|
|
|
|
$this->set('baseurl', Configure::read('CyDefSIG.baseurl'));
|
|
|
|
|
|
|
|
|
|
$this->set('relatedAttributes', $relatedAttributes);
|
|
|
|
|
// passing decriptions for model fields
|
|
|
|
|
$this->set('eventDescriptions', $this->Event->fieldDescriptions);
|
|
|
|
|
$this->set('attrDescriptions', $this->Attribute->fieldDescriptions);
|
|
|
|
|
$this->set('event', $this->Event->data);
|
|
|
|
|
if(isset($this->Event->data['ShadowAttribute'])) {
|
|
|
|
|
$this->set('remaining', $this->Event->data['ShadowAttribute']);
|
|
|
|
|
}
|
|
|
|
|
$this->set('relatedEvents', $relatedEvents);
|
|
|
|
|
|
|
|
|
|
$this->set('categories', $this->Attribute->validate['category']['rule'][1]);
|
|
|
|
|
|
|
|
|
|
// passing type and category definitions (explanations)
|
|
|
|
|
$this->set('typeDefinitions', $this->Attribute->typeDefinitions);
|
|
|
|
|
$this->set('categoryDefinitions', $this->Attribute->categoryDefinitions);
|
|
|
|
|
|
|
|
|
|
// combobox for analysis
|
|
|
|
|
$this->set('distributionDescriptions', $this->Event->distributionDescriptions);
|
|
|
|
|
$this->set('distributionLevels', $this->Event->distributionLevels);
|
|
|
|
|
|
|
|
|
|
// combobox for analysis
|
|
|
|
|
$analysiss = $this->Event->validate['analysis']['rule'][1];
|
|
|
|
|
$analysiss = $this->_arrayToValuesIndexArray($analysiss);
|
|
|
|
|
$this->set('analysiss', $analysiss);
|
|
|
|
|
// tooltip for analysis
|
|
|
|
|
$this->set('analysisDescriptions', $this->Event->analysisDescriptions);
|
|
|
|
|
$this->set('analysisLevels', $this->Event->analysisLevels);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* add method
|
|
|
|
@ -468,9 +530,11 @@ class EventsController extends AppController {
|
|
|
|
|
$this->set('distributionLevels', $this->Event->distributionLevels);
|
|
|
|
|
|
|
|
|
|
// combobox for risks
|
|
|
|
|
$threat_levels = $this->Event->ThreatLevel->find('all');
|
|
|
|
|
$this->set('threatLevels', Set::combine($threat_levels, '{n}.ThreatLevel.id', '{n}.ThreatLevel.name'));
|
|
|
|
|
$this->set('riskDescriptions', Set::combine($threat_levels, '{n}.ThreatLevel.id', '{n}.ThreatLevel.form_description'));
|
|
|
|
|
$risks = $this->Event->validate['risk']['rule'][1];
|
|
|
|
|
$risks = $this->_arrayToValuesIndexArray($risks);
|
|
|
|
|
$this->set('risks',$risks);
|
|
|
|
|
// tooltip for risk
|
|
|
|
|
$this->set('riskDescriptions', $this->Event->riskDescriptions);
|
|
|
|
|
|
|
|
|
|
// combobox for analysis
|
|
|
|
|
$analysiss = $this->Event->validate['analysis']['rule'][1];
|
|
|
|
@ -512,41 +576,37 @@ class EventsController extends AppController {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// combobox for distribution
|
|
|
|
|
$distributions = array_keys($this->Event->distributionDescriptions);
|
|
|
|
|
$distributions = $this->_arrayToValuesIndexArray($distributions);
|
|
|
|
|
$this->set('distributions', $distributions);
|
|
|
|
|
// tooltip for distribution
|
|
|
|
|
$this->set('distributionDescriptions', $this->Event->distributionDescriptions);
|
|
|
|
|
$this->set('distributionLevels', $this->Event->distributionLevels);
|
|
|
|
|
|
|
|
|
|
// combobox for risks
|
|
|
|
|
$risks = $this->Event->validate['risk']['rule'][1];
|
|
|
|
|
$risks = $this->_arrayToValuesIndexArray($risks);
|
|
|
|
|
$this->set('risks',$risks);
|
|
|
|
|
|
|
|
|
|
// set the id
|
|
|
|
|
$this->set('id', $id);
|
|
|
|
|
// set whether it is published or not
|
|
|
|
|
$this->set('published', $this->Event->data['Event']['published']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function add_xml() {
|
|
|
|
|
if (!$this->userRole['perm_modify']) {
|
|
|
|
|
throw new UnauthorizedException('You do not have permission to do that.');
|
|
|
|
|
}
|
|
|
|
|
if ($this->request->is('post')) {
|
|
|
|
|
if (!empty($this->data)) {
|
|
|
|
|
$ext = '';
|
|
|
|
|
if (isset($this->data['Event']['submittedxml'])) {
|
|
|
|
|
App::uses('File', 'Utility');
|
|
|
|
|
$file = new File($this->data['Event']['submittedxml']['name']);
|
|
|
|
|
$ext = $file->ext();
|
|
|
|
|
}
|
|
|
|
|
if (isset($this->data['Event']['submittedxml']) && ($ext != 'xml') && $this->data['Event']['submittedxml']['size'] > 0 &&
|
|
|
|
|
is_uploaded_file($this->data['Event']['submittedxml']['tmp_name'])) {
|
|
|
|
|
$this->Session->setFlash(__('You may only upload OpenIOC ioc files.'));
|
|
|
|
|
}
|
|
|
|
|
if (isset($this->data['Event']['submittedxml'])) $this->_addXMLFile();
|
|
|
|
|
// tooltip for risk
|
|
|
|
|
$this->set('riskDescriptions', $this->Event->riskDescriptions);
|
|
|
|
|
|
|
|
|
|
// redirect to the view of the newly created event
|
|
|
|
|
if (!CakeSession::read('Message.flash')) {
|
|
|
|
|
$this->Session->setFlash(__('The event has been saved'));
|
|
|
|
|
} else {
|
|
|
|
|
$existingFlash = CakeSession::read('Message.flash');
|
|
|
|
|
$this->Session->setFlash(__('The event has been saved. ' . $existingFlash['message']));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// combobox for analysis
|
|
|
|
|
$analysiss = $this->Event->validate['analysis']['rule'][1];
|
|
|
|
|
$analysiss = $this->_arrayToValuesIndexArray($analysiss);
|
|
|
|
|
$this->set('analysiss',$analysiss);
|
|
|
|
|
// tooltip for analysis
|
|
|
|
|
$this->set('analysisDescriptions', $this->Event->analysisDescriptions);
|
|
|
|
|
$this->set('analysisLevels', $this->Event->analysisLevels);
|
|
|
|
|
|
|
|
|
|
$this->set('eventDescriptions', $this->Event->fieldDescriptions);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Low level function to add an Event based on an Event $data array
|
|
|
|
@ -574,6 +634,7 @@ class EventsController extends AppController {
|
|
|
|
|
unset($this->Event->Attribute->validate['event_id']);
|
|
|
|
|
unset($this->Event->Attribute->validate['value']['unique']); // otherwise gives bugs because event_id is not set
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unset ($data['Event']['id']);
|
|
|
|
|
if (isset($data['Event']['uuid'])) {
|
|
|
|
|
// check if the uuid already exists
|
|
|
|
@ -594,12 +655,10 @@ class EventsController extends AppController {
|
|
|
|
|
}
|
|
|
|
|
// FIXME chri: validatebut the necessity for all these fields...impact on security !
|
|
|
|
|
$fieldList = array(
|
|
|
|
|
'Event' => array('org', 'orgc', 'date', 'threat_level_id', 'analysis', 'info', 'user_id', 'published', 'uuid', 'timestamp', 'distribution', 'locked'),
|
|
|
|
|
'Event' => array('org', 'orgc', 'date', 'risk', 'analysis', 'info', 'user_id', 'published', 'uuid', 'timestamp', 'distribution', 'locked'),
|
|
|
|
|
'Attribute' => array('event_id', 'category', 'type', 'value', 'value1', 'value2', 'to_ids', 'uuid', 'revision', 'timestamp', 'distribution')
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$saveResult = $this->Event->saveAssociated($data, array('validate' => true, 'fieldList' => $fieldList,
|
|
|
|
|
'atomic' => true));
|
|
|
|
|
$saveResult = $this->Event->saveAssociated($data, array('validate' => true, 'fieldList' => $fieldList));
|
|
|
|
|
// FIXME chri: check if output of $saveResult is what we expect when data not valid, see issue #104
|
|
|
|
|
if ($saveResult) {
|
|
|
|
|
if (!empty($data['Event']['published']) && 1 == $data['Event']['published']) {
|
|
|
|
@ -628,7 +687,7 @@ class EventsController extends AppController {
|
|
|
|
|
return 'Event originated on this instance, any changes to it have to be done locally.';
|
|
|
|
|
}
|
|
|
|
|
$fieldList = array(
|
|
|
|
|
'Event' => array('date', 'threat_level_id', 'analysis', 'info', 'published', 'uuid', 'from', 'distribution', 'timestamp'),
|
|
|
|
|
'Event' => array('date', 'risk', 'analysis', 'info', 'published', 'uuid', 'from', 'distribution', 'timestamp'),
|
|
|
|
|
'Attribute' => array('event_id', 'category', 'type', 'value', 'value1', 'value2', 'to_ids', 'uuid', 'revision', 'distribution', 'timestamp')
|
|
|
|
|
);
|
|
|
|
|
$data['Event']['id'] = $this->Event->data['Event']['id'];
|
|
|
|
@ -684,6 +743,7 @@ class EventsController extends AppController {
|
|
|
|
|
$this->redirect(array('controller' => 'events', 'action' => 'index'));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($this->request->is('post') || $this->request->is('put')) {
|
|
|
|
|
if ($this->_isRest()) {
|
|
|
|
|
$saveEvent = false;
|
|
|
|
@ -719,7 +779,7 @@ class EventsController extends AppController {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$fieldList = array(
|
|
|
|
|
'Event' => array('date', 'threat_level_id', 'analysis', 'info', 'published', 'uuid', 'from', 'distribution', 'timestamp'),
|
|
|
|
|
'Event' => array('date', 'risk', 'analysis', 'info', 'published', 'uuid', 'from', 'distribution', 'timestamp'),
|
|
|
|
|
'Attribute' => array('event_id', 'category', 'type', 'value', 'value1', 'value2', 'to_ids', 'uuid', 'revision', 'distribution', 'timestamp')
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
@ -772,7 +832,7 @@ class EventsController extends AppController {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// say what fields are to be updated
|
|
|
|
|
$fieldList = array('date', 'threat_level_id', 'analysis', 'info', 'published', 'distribution', 'timestamp');
|
|
|
|
|
$fieldList = array('date', 'risk', 'analysis', 'info', 'published', 'distribution', 'timestamp');
|
|
|
|
|
|
|
|
|
|
$this->Event->read();
|
|
|
|
|
// always force the org, but do not force it for admins
|
|
|
|
@ -805,9 +865,12 @@ class EventsController extends AppController {
|
|
|
|
|
$this->set('distributionLevels', $this->Event->distributionLevels);
|
|
|
|
|
|
|
|
|
|
// combobox for types
|
|
|
|
|
$threat_levels = $this->Event->ThreatLevel->find('all');
|
|
|
|
|
$this->set('threatLevels', Set::combine($threat_levels, '{n}.ThreatLevel.id', '{n}.ThreatLevel.name'));
|
|
|
|
|
$this->set('riskDescriptions', Set::combine($threat_levels, '{n}.ThreatLevel.id', '{n}.ThreatLevel.form_description'));
|
|
|
|
|
$risks = $this->Event->validate['risk']['rule'][1];
|
|
|
|
|
$risks = $this->_arrayToValuesIndexArray($risks);
|
|
|
|
|
$this->set('risks',$risks);
|
|
|
|
|
|
|
|
|
|
// tooltip for risk
|
|
|
|
|
$this->set('riskDescriptions', $this->Event->riskDescriptions);
|
|
|
|
|
|
|
|
|
|
// combobox for analysis
|
|
|
|
|
$analysiss = $this->Event->validate['analysis']['rule'][1];
|
|
|
|
@ -819,8 +882,6 @@ class EventsController extends AppController {
|
|
|
|
|
$this->set('analysisLevels', $this->Event->analysisLevels);
|
|
|
|
|
|
|
|
|
|
$this->set('eventDescriptions', $this->Event->fieldDescriptions);
|
|
|
|
|
|
|
|
|
|
$this->set('event', $this->Event->data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -1058,11 +1119,11 @@ class EventsController extends AppController {
|
|
|
|
|
if ('true' == Configure::read('CyDefSIG.showorg')) {
|
|
|
|
|
$body .= 'Reported by : ' . $event['Event']['org'] . "\n";
|
|
|
|
|
}
|
|
|
|
|
$body .= 'Risk : ' . $event['ThreatLevel']['name'] . "\n";
|
|
|
|
|
$body .= 'Risk : ' . $event['Event']['risk'] . "\n";
|
|
|
|
|
$body .= 'Analysis : ' . $this->Event->analysisLevels[$event['Event']['analysis']] . "\n";
|
|
|
|
|
$body .= 'Info : ' . "\n";
|
|
|
|
|
$body .= $event['Event']['info'] . "\n";
|
|
|
|
|
$relatedEvents = $this->Event->getRelatedEvents($this->Auth->user(), $this->_isSiteAdmin());
|
|
|
|
|
$relatedEvents = $this->Event->getRelatedEvents($this->Auth->user());
|
|
|
|
|
if (!empty($relatedEvents)) {
|
|
|
|
|
$body .= '----------------------------------------------' . "\n";
|
|
|
|
|
$body .= 'Related to : '. "\n";
|
|
|
|
@ -1120,7 +1181,7 @@ class EventsController extends AppController {
|
|
|
|
|
// prepare the the unencrypted email
|
|
|
|
|
$this->Email->from = Configure::read('CyDefSIG.email');
|
|
|
|
|
$this->Email->to = $user['User']['email'];
|
|
|
|
|
$this->Email->subject = "[" . Configure::read('CyDefSIG.org') . " " . Configure::read('CyDefSIG.name') . "] Event " . $id . " - " . $event['ThreatLevel']['name'] . " - TLP Amber";
|
|
|
|
|
$this->Email->subject = "[" . Configure::read('CyDefSIG.org') . " " . Configure::read('CyDefSIG.name') . "] Event " . $id . " - " . $event['Event']['risk'] . " - TLP Amber";
|
|
|
|
|
$this->Email->template = 'body';
|
|
|
|
|
$this->Email->sendAs = 'text'; // both text or html
|
|
|
|
|
$this->set('body', $bodySigned);
|
|
|
|
@ -1149,7 +1210,7 @@ class EventsController extends AppController {
|
|
|
|
|
// send the email
|
|
|
|
|
$this->Email->from = Configure::read('CyDefSIG.email');
|
|
|
|
|
$this->Email->to = $user['User']['email'];
|
|
|
|
|
$this->Email->subject = "[" . Configure::read('CyDefSIG.org') . " " . Configure::read('CyDefSIG.name') . "] Event " . $id . " - " . $event['ThreatLevel']['name'] . " - TLP Amber";
|
|
|
|
|
$this->Email->subject = "[" . Configure::read('CyDefSIG.org') . " " . Configure::read('CyDefSIG.name') . "] Event " . $id . " - " . $event['Event']['risk'] . " - TLP Amber";
|
|
|
|
|
$this->Email->template = 'body';
|
|
|
|
|
$this->Email->sendAs = 'text'; // both text or html
|
|
|
|
|
|
|
|
|
@ -1275,9 +1336,9 @@ class EventsController extends AppController {
|
|
|
|
|
if ('true' == Configure::read('CyDefSIG.showorg')) {
|
|
|
|
|
$body .= 'Reported by : ' . $event['Event']['org'] . "\n";
|
|
|
|
|
}
|
|
|
|
|
$body .= 'Risk : ' . $event['ThreatLevel']['name'] . "\n";
|
|
|
|
|
$body .= 'Risk : ' . $event['Event']['risk'] . "\n";
|
|
|
|
|
$body .= 'Analysis : ' . $event['Event']['analysis'] . "\n";
|
|
|
|
|
$relatedEvents = $this->Event->getRelatedEvents($this->Auth->user(), $this->_isSiteAdmin());
|
|
|
|
|
$relatedEvents = $this->Event->getRelatedEvents($this->Auth->user());
|
|
|
|
|
if (!empty($relatedEvents)) {
|
|
|
|
|
foreach ($relatedEvents as &$relatedEvent) {
|
|
|
|
|
$body .= 'Related to : ' . Configure::read('CyDefSIG.baseurl') . '/events/view/' . $relatedEvent['Event']['id'] . ' (' . $relatedEvent['Event']['date'] . ')' . "\n";
|
|
|
|
@ -1389,7 +1450,7 @@ class EventsController extends AppController {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function xml($key, $eventid=null, $withAttachment = false) {
|
|
|
|
|
public function xml($key, $eventid=null) {
|
|
|
|
|
if ($key != 'download') {
|
|
|
|
|
// check if the key is valid -> search for users based on key
|
|
|
|
|
$user = $this->checkAuthUser($key);
|
|
|
|
@ -1414,15 +1475,6 @@ class EventsController extends AppController {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$results = $this->__fetchEvent($eventid);
|
|
|
|
|
if ($withAttachment) {
|
|
|
|
|
$this->loadModel('Attribute');
|
|
|
|
|
foreach ($results[0]['Attribute'] as &$attribute) {
|
|
|
|
|
if ($this->Attribute->typeIsAttachment($attribute['type'])) {
|
|
|
|
|
$encodedFile = $this->Attribute->base64EncodeAttachment($attribute);
|
|
|
|
|
$attribute['data'] = $encodedFile;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Whitelist check
|
|
|
|
|
$this->loadModel('Whitelist');
|
|
|
|
|
$results = $this->Whitelist->removeWhitelistedFromArray($results, false);
|
|
|
|
@ -1431,7 +1483,7 @@ class EventsController extends AppController {
|
|
|
|
|
|
|
|
|
|
// Grab an event or a list of events for the event view or any of the XML exports. The returned object includes an array of events (or an array that only includes a single event if an ID was given)
|
|
|
|
|
// Included with the event are the attached attributes, shadow attributes, related events, related attribute information for the event view and the creating user's email address where appropriate
|
|
|
|
|
private function __fetchEvent($eventid = null, $idList = null, $orgFromFetch = null, $isSiteAdmin = false) {
|
|
|
|
|
private function __fetchEvent($eventid = null, $idList = null) {
|
|
|
|
|
if (isset($eventid)) {
|
|
|
|
|
$this->Event->id = $eventid;
|
|
|
|
|
if (!$this->Event->exists()) {
|
|
|
|
@ -1441,20 +1493,11 @@ class EventsController extends AppController {
|
|
|
|
|
} else {
|
|
|
|
|
$conditions = array();
|
|
|
|
|
}
|
|
|
|
|
// if we come from automation, we may not be logged in - instead we used an auth key in the URL.
|
|
|
|
|
if (!empty($orgFromFetch)) {
|
|
|
|
|
$org = $orgFromFetch;
|
|
|
|
|
} else {
|
|
|
|
|
$org = $this->_checkOrg();
|
|
|
|
|
$isSiteAdmin = $this->_isSiteAdmin();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$conditionsAttributes = array();
|
|
|
|
|
$conditionsShadowAttributes = array();
|
|
|
|
|
//restricting to non-private or same org if the user is not a site-admin.
|
|
|
|
|
if (!$isSiteAdmin) {
|
|
|
|
|
if (!empty($orgFromFetch)) $org = $orgFromFetch;
|
|
|
|
|
else $org = $this->_checkOrg();
|
|
|
|
|
if (!$this->_isSiteAdmin()) {
|
|
|
|
|
$org = $this->_checkOrg();
|
|
|
|
|
$conditions['AND']['OR'] = array(
|
|
|
|
|
'Event.distribution >' => 0,
|
|
|
|
|
'Event.org LIKE' => $org
|
|
|
|
@ -1470,6 +1513,8 @@ class EventsController extends AppController {
|
|
|
|
|
array('(SELECT events.org FROM events WHERE events.id = ShadowAttribute.event_id) LIKE' => $org),
|
|
|
|
|
array('ShadowAttribute.org LIKE' => $org),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($idList) {
|
|
|
|
@ -1482,17 +1527,14 @@ class EventsController extends AppController {
|
|
|
|
|
// $conditions['AND'][] = array('Event.published =' => 1);
|
|
|
|
|
|
|
|
|
|
// do not expose all the data ...
|
|
|
|
|
$fields = array('Event.id', 'Event.org', 'Event.date','Event.info', 'Event.published', 'Event.uuid', 'Event.attribute_count', 'Event.analysis', 'Event.timestamp', 'Event.distribution', 'Event.proposal_email_lock', 'Event.orgc', 'Event.user_id', 'Event.locked');
|
|
|
|
|
$fieldsAtt = array('Attribute.id', 'Attribute.type', 'Attribute.category', 'Attribute.value', 'Attribute.to_ids', 'Attribute.uuid', 'Attribute.event_id', 'Attribute.distribution', 'Attribute.timestamp', 'Attribute.comment');
|
|
|
|
|
$fields = array('Event.id', 'Event.org', 'Event.date', 'Event.risk', 'Event.info', 'Event.published', 'Event.uuid', 'Event.attribute_count', 'Event.analysis', 'Event.timestamp', 'Event.distribution', 'Event.proposal_email_lock', 'Event.orgc', 'Event.user_id', 'Event.locked');
|
|
|
|
|
$fieldsAtt = array('Attribute.id', 'Attribute.type', 'Attribute.category', 'Attribute.value', 'Attribute.to_ids', 'Attribute.uuid', 'Attribute.event_id', 'Attribute.distribution', 'Attribute.timestamp');
|
|
|
|
|
$fieldsShadowAtt = array('ShadowAttribute.id', 'ShadowAttribute.type', 'ShadowAttribute.category', 'ShadowAttribute.value', 'ShadowAttribute.to_ids', 'ShadowAttribute.uuid', 'ShadowAttribute.event_id', 'ShadowAttribute.old_id');
|
|
|
|
|
|
|
|
|
|
$params = array('conditions' => $conditions,
|
|
|
|
|
'recursive' => 0,
|
|
|
|
|
'fields' => $fields,
|
|
|
|
|
'contain' => array(
|
|
|
|
|
'ThreatLevel' => array(
|
|
|
|
|
'fields' => array('ThreatLevel.name')
|
|
|
|
|
),
|
|
|
|
|
'Attribute' => array(
|
|
|
|
|
'fields' => $fieldsAtt,
|
|
|
|
|
'conditions' => $conditionsAttributes,
|
|
|
|
@ -1503,14 +1545,14 @@ class EventsController extends AppController {
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
if ($isSiteAdmin) $params['contain']['User'] = array('fields' => 'email');
|
|
|
|
|
if ($this->_isAdmin()) $params['contain']['User'] = array('fields' => 'email');
|
|
|
|
|
$results = $this->Event->find('all', $params);
|
|
|
|
|
// Do some refactoring with the event
|
|
|
|
|
foreach ($results as $eventKey => &$event) {
|
|
|
|
|
// Let's find all the related events and attach it to the event itself
|
|
|
|
|
$results[$eventKey]['RelatedEvent'] = $this->Event->getRelatedEvents($this->Auth->user(), $this->_isSiteAdmin(), $event['Event']['id']);
|
|
|
|
|
$results[$eventKey]['RelatedEvent'] = $this->Event->getRelatedEvents($this->Auth->user(), $event['Event']['id']);
|
|
|
|
|
// Let's also find all the relations for the attributes - this won't be in the xml export though
|
|
|
|
|
$results[$eventKey]['RelatedAttribute'] = $this->Event->getRelatedAttributes($this->Auth->user(), $this->_isSiteAdmin(), $event['Event']['id']);
|
|
|
|
|
$results[$eventKey]['RelatedAttribute'] = $this->Event->getRelatedAttributes($this->Auth->user(), $event['Event']['id']);
|
|
|
|
|
foreach ($event['Attribute'] as $key => &$attribute) {
|
|
|
|
|
$attribute['ShadowAttribute'] = array();
|
|
|
|
|
// If a shadowattribute can be linked to an attribute, link it to it then remove it from the event
|
|
|
|
@ -1528,14 +1570,7 @@ class EventsController extends AppController {
|
|
|
|
|
return $results;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function nids($format = 'suricata', $key = '') {
|
|
|
|
|
|
|
|
|
|
// backwards compatibility, swap key and format
|
|
|
|
|
if ($format != 'snort' && $format != 'suricata') {
|
|
|
|
|
$key = $format;
|
|
|
|
|
$format = 'suricata'; // default format
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function nids($key) {
|
|
|
|
|
if ($key != 'download') {
|
|
|
|
|
$this->response->type('txt'); // set the content type
|
|
|
|
|
$this->header('Content-Disposition: inline; filename="misp.rules"');
|
|
|
|
@ -1578,17 +1613,7 @@ class EventsController extends AppController {
|
|
|
|
|
unset($this->Attribute->virtualFields['category_order']); // not needed for IDS export and speeds things up
|
|
|
|
|
$items = $this->Attribute->find('all', $params);
|
|
|
|
|
|
|
|
|
|
// export depending of the requested type
|
|
|
|
|
switch ($format) {
|
|
|
|
|
case 'suricata':
|
|
|
|
|
$this->NidsExport = $this->Components->load('NidsSuricataExport');
|
|
|
|
|
break;
|
|
|
|
|
case 'snort':
|
|
|
|
|
$this->NidsExport = $this->Components->load('NidsSnortExport');
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
$rules = $this->NidsExport->export($items, $user['User']['nids_sid']);
|
|
|
|
|
|
|
|
|
|
$this->set('rules', $rules);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1925,7 +1950,7 @@ class EventsController extends AppController {
|
|
|
|
|
$this->Event->read(null, $id);
|
|
|
|
|
$saveEvent['Event'] = $this->Event->data['Event'];
|
|
|
|
|
$saveEvent['Event']['published'] = false;
|
|
|
|
|
$dist = '3';
|
|
|
|
|
$dist = 3;
|
|
|
|
|
if (Configure::read('MISP.default_attribute_distribution') != null) {
|
|
|
|
|
if (Configure::read('MISP.default_attribute_distribution') === 'event') {
|
|
|
|
|
$dist = $this->Event->data['Event']['distribution'];
|
|
|
|
@ -1951,7 +1976,7 @@ class EventsController extends AppController {
|
|
|
|
|
|
|
|
|
|
$fieldList = array(
|
|
|
|
|
'Event' => array('published', 'timestamp'),
|
|
|
|
|
'Attribute' => array('event_id', 'category', 'type', 'value', 'value1', 'value2', 'to_ids', 'uuid', 'distribution', 'timestamp', 'comment')
|
|
|
|
|
'Attribute' => array('event_id', 'category', 'type', 'value', 'value1', 'value2', 'to_ids', 'uuid', 'distribution', 'timestamp')
|
|
|
|
|
);
|
|
|
|
|
// Save it all
|
|
|
|
|
$saveResult = $this->Event->saveAssociated($saveEvent, array('validate' => true, 'fieldList' => $fieldList));
|
|
|
|
@ -1968,46 +1993,24 @@ class EventsController extends AppController {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function _addXMLFile() {
|
|
|
|
|
if (!empty($this->data) && $this->data['Event']['submittedxml']['size'] > 0 &&
|
|
|
|
|
is_uploaded_file($this->data['Event']['submittedxml']['tmp_name'])) {
|
|
|
|
|
$xmlData = fread(fopen($this->data['Event']['submittedxml']['tmp_name'], "r"),
|
|
|
|
|
$this->data['Event']['submittedxml']['size']);
|
|
|
|
|
App::uses('Xml', 'Utility');
|
|
|
|
|
$xmlArray = Xml::toArray(Xml::build($xmlData));
|
|
|
|
|
|
|
|
|
|
// In case we receive an event that is not encapsulated in a response. This should never happen (unless it's a copy+paste fail),
|
|
|
|
|
// but just in case, let's clean it up anyway.
|
|
|
|
|
if (isset($xmlArray['Event'])) {
|
|
|
|
|
$xmlArray['response']['Event'] = $xmlArray['Event'];
|
|
|
|
|
unset($xmlArray['Event']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!isset($xmlArray['response']) || !isset($xmlArray['response']['Event'])) {
|
|
|
|
|
throw new Exception('This is not a valid MISP XML file.');
|
|
|
|
|
}
|
|
|
|
|
if (isset($xmlArray['response']['Event'][0])) {
|
|
|
|
|
foreach ($xmlArray['response']['Event'] as $event) {
|
|
|
|
|
$temp['Event'] = $event;
|
|
|
|
|
$this->_add($temp, true);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
$temp['Event'] = $xmlArray['response']['Event'];
|
|
|
|
|
$this->_add($temp, true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function _readGfiXML($data, $id) {
|
|
|
|
|
$this->loadModel('Attribute');
|
|
|
|
|
|
|
|
|
|
$this->Event->recursive = -1;
|
|
|
|
|
$this->Event->read(array('id', 'uuid', 'distribution'), $id);
|
|
|
|
|
// import XML class
|
|
|
|
|
App::uses('Xml', 'Utility');
|
|
|
|
|
// now parse it
|
|
|
|
|
$parsedXml = Xml::build($data, array('return' => 'simplexml'));
|
|
|
|
|
|
|
|
|
|
// xpath..
|
|
|
|
|
|
|
|
|
|
if (Configure::read('MISP.default_attribute_distribution') != null) {
|
|
|
|
|
if (Configure::read('MISP.default_attribute_distribution') === 'event') {
|
|
|
|
|
$dist = $this->Event->data['Event']['distribution'];
|
|
|
|
|
} else {
|
|
|
|
|
$dist = '';
|
|
|
|
|
$dist .= Configure::read('MISP.default_attribute_distribution');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//Payload delivery -- malware-sample
|
|
|
|
|
$results = $parsedXml->xpath('/analysis');
|
|
|
|
|
foreach ($results as $result) {
|
|
|
|
@ -2018,13 +2021,13 @@ class EventsController extends AppController {
|
|
|
|
|
$realMalware = $realFileName;
|
|
|
|
|
$rootDir = APP . "files" . DS . $id . DS;
|
|
|
|
|
$malware = $rootDir . DS . 'sample';
|
|
|
|
|
$this->Event->Attribute->uploadAttachment($malware, $realFileName, true, $id, null, '', '', true);
|
|
|
|
|
$this->Event->Attribute->uploadAttachment($malware, $realFileName, true, $id, null, '', $this->Event->data['Event']['uuid'] . '-sample', $dist, true);
|
|
|
|
|
|
|
|
|
|
//Network activity -- .pcap
|
|
|
|
|
$realFileName = 'analysis.pcap';
|
|
|
|
|
$rootDir = APP . "files" . DS . $id . DS;
|
|
|
|
|
$malware = $rootDir . DS . 'Analysis' . DS . 'analysis.pcap';
|
|
|
|
|
$this->Event->Attribute->uploadAttachment($malware, $realFileName, false, $id, 'Network activity', '', '', true);
|
|
|
|
|
$this->Event->Attribute->uploadAttachment($malware, $realFileName, false, $id, 'Network activity', '', $this->Event->data['Event']['uuid'] . '-analysis.pcap', $dist, true);
|
|
|
|
|
|
|
|
|
|
//Artifacts dropped -- filename|md5
|
|
|
|
|
$files = array();
|
|
|
|
@ -2073,11 +2076,10 @@ class EventsController extends AppController {
|
|
|
|
|
$extraPath = 'Analysis' . DS . 'proc_' . $index . DS . 'modified_files' . DS;
|
|
|
|
|
$file = new File($actualFile);
|
|
|
|
|
if ($file->exists()) { // TODO put in array for test later
|
|
|
|
|
$this->Event->Attribute->uploadAttachment($actualFile, $realFileName, true, $id, null, $extraPath, $keyName, true); // TODO was false
|
|
|
|
|
$this->Event->Attribute->uploadAttachment($actualFile, $realFileName, true, $id, null, $extraPath, $keyName, $dist, true); // TODO was false
|
|
|
|
|
} else {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Network activity -- ip-dst
|
|
|
|
|
$ips = array();
|
|
|
|
|
$hostnames = array();
|
|
|
|
@ -2098,9 +2100,9 @@ class EventsController extends AppController {
|
|
|
|
|
'category' => 'Network activity',
|
|
|
|
|
'type' => 'ip-dst',
|
|
|
|
|
'value' => $ip,
|
|
|
|
|
'to_ids' => false,
|
|
|
|
|
'distribution' => $dist,
|
|
|
|
|
'comment' => 'GFI import',
|
|
|
|
|
));
|
|
|
|
|
'to_ids' => false));
|
|
|
|
|
}
|
|
|
|
|
foreach ($hostnames as $hostname) {
|
|
|
|
|
// add attribute..
|
|
|
|
@ -2110,9 +2112,9 @@ class EventsController extends AppController {
|
|
|
|
|
'category' => 'Network activity',
|
|
|
|
|
'type' => 'hostname',
|
|
|
|
|
'value' => $hostname,
|
|
|
|
|
'to_ids' => false,
|
|
|
|
|
'distribution' => $dist,
|
|
|
|
|
'comment' => 'GFI import',
|
|
|
|
|
));
|
|
|
|
|
'to_ids' => false));
|
|
|
|
|
}
|
|
|
|
|
// Persistence mechanism -- regkey|value
|
|
|
|
|
$regs = array();
|
|
|
|
@ -2132,31 +2134,19 @@ class EventsController extends AppController {
|
|
|
|
|
foreach ($regs as $key => $val) {
|
|
|
|
|
// add attribute..
|
|
|
|
|
$this->Attribute->create();
|
|
|
|
|
if ($val == '[binary_data]') {
|
|
|
|
|
$itsCategory = 'Artifacts dropped';
|
|
|
|
|
$itsType = 'regkey';
|
|
|
|
|
$itsValue = $key;
|
|
|
|
|
} else {
|
|
|
|
|
if ($this->strposarray($val,$actualFileNameArray)) {
|
|
|
|
|
$itsCategory = 'Persistence mechanism';
|
|
|
|
|
$itsType = 'regkey|value';
|
|
|
|
|
$itsValue = $key . '|' . $val;
|
|
|
|
|
} else {
|
|
|
|
|
$itsCategory = 'Artifacts dropped'; // Persistence mechanism
|
|
|
|
|
$itsType = 'regkey|value';
|
|
|
|
|
$itsValue = $key . '|' . $val;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$this->Attribute->save(array(
|
|
|
|
|
'event_id' => $id,
|
|
|
|
|
'category' => $itsCategory, // 'Persistence mechanism'
|
|
|
|
|
'type' => $itsType,
|
|
|
|
|
'value' => $itsValue,
|
|
|
|
|
'to_ids' => false,
|
|
|
|
|
'category' => 'Persistence mechanism', // 'Persistence mechanism'
|
|
|
|
|
'type' => 'regkey|value',
|
|
|
|
|
'value' => $key . '|' . $val,
|
|
|
|
|
'distribution' => $dist,
|
|
|
|
|
'comment' => 'GFI import',
|
|
|
|
|
'to_ids' => false
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function strposarray($string, $array) {
|
|
|
|
|
$toReturn = false;
|
|
|
|
@ -2185,95 +2175,6 @@ class EventsController extends AppController {
|
|
|
|
|
$this->render('xml');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Use the rest interface to search for attributes or events. Usage:
|
|
|
|
|
// MISP-base-url/events/restSearch/[api-key]/[value]/[type]/[category]/[orgc]
|
|
|
|
|
// value, type, category, orgc are optional
|
|
|
|
|
// target can be either "event" or "attribute"
|
|
|
|
|
// the last 4 fields accept the following operators:
|
|
|
|
|
// && - you can use && between two search values to put a logical OR between them. for value, 1.1.1.1&&2.2.2.2 would find attributes with the value being either of the two.
|
|
|
|
|
// ! - you can negate a search term. For example: google.com&&!mail would search for all attributes with value google.com but not ones that include mail. www.google.com would get returned, mail.google.com wouldn't.
|
|
|
|
|
public function restSearch($key, $value=null, $type=null, $category=null, $org=null) {
|
|
|
|
|
$user = $this->checkAuthUser($key);
|
|
|
|
|
if (!$user) {
|
|
|
|
|
throw new UnauthorizedException('This authentication key is not authorized to be used for exports. Contact your administrator.');
|
|
|
|
|
}
|
|
|
|
|
$value = str_replace('|', '/', $value);
|
|
|
|
|
$this->response->type('xml'); // set the content type
|
|
|
|
|
$this->layout = 'xml/default';
|
|
|
|
|
$this->header('Content-Disposition: download; filename="misp.search.events.results.xml"');
|
|
|
|
|
$conditions['AND'] = array();
|
|
|
|
|
$subcondition = array();
|
|
|
|
|
$this->loadModel('Attribute');
|
|
|
|
|
// add the values as specified in the 2nd parameter to the conditions
|
|
|
|
|
$values = explode('&&', $value);
|
|
|
|
|
$parameters = array('value', 'type', 'category', 'org');
|
|
|
|
|
|
|
|
|
|
foreach ($parameters as $k => $param) {
|
|
|
|
|
if (isset(${$parameters[$k]})) {
|
|
|
|
|
$elements = explode('&&', ${$parameters[$k]});
|
|
|
|
|
foreach($elements as $v) {
|
|
|
|
|
if (substr($v, 0, 1) == '!') {
|
|
|
|
|
if ($parameters[$k] === 'value' && preg_match('@^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(\d|[1-2]\d|3[0-2]))$@', substr($v, 1))) {
|
|
|
|
|
$cidrresults = $this->Cidr->CIDR(substr($v, 1));
|
|
|
|
|
foreach ($cidrresults as $result) {
|
|
|
|
|
$subcondition['AND'][] = array('Attribute.value NOT LIKE' => $result);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if ($parameters[$k] === 'org') {
|
|
|
|
|
$subcondition['AND'][] = array('Event.' . $parameters[$k] . ' NOT LIKE' => '%'.substr($v, 1).'%');
|
|
|
|
|
} else {
|
|
|
|
|
$subcondition['AND'][] = array('Attribute.' . $parameters[$k] . ' NOT LIKE' => '%'.substr($v, 1).'%');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if ($parameters[$k] === 'value' && preg_match('@^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(\d|[1-2]\d|3[0-2]))$@', substr($v, 1))) {
|
|
|
|
|
$cidrresults = $this->Cidr->CIDR($v);
|
|
|
|
|
foreach ($cidrresults as $result) {
|
|
|
|
|
$subcondition['OR'][] = array('Attribute.value LIKE' => $result);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if ($parameters[$k] === 'org') {
|
|
|
|
|
$subcondition['OR'][] = array('Event.' . $parameters[$k] . ' LIKE' => '%'.$v.'%');
|
|
|
|
|
} else {
|
|
|
|
|
$subcondition['OR'][] = array('Attribute.' . $parameters[$k] . ' LIKE' => '%'.$v.'%');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
array_push ($conditions['AND'], $subcondition);
|
|
|
|
|
$subcondition = array();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If we are looking for an attribute, we want to retrieve some extra data about the event to be able to check for the permissions.
|
|
|
|
|
|
|
|
|
|
if (!$user['User']['siteAdmin']) {
|
|
|
|
|
$temp = array();
|
|
|
|
|
$temp['AND'] = array('Event.distribution >' => 0, 'Attribute.distribution >' => 0);
|
|
|
|
|
$subcondition['OR'][] = $temp;
|
|
|
|
|
$subcondition['OR'][] = array('Event.org' => $user['User']['org']);
|
|
|
|
|
array_push($conditions['AND'], $subcondition);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$params = array(
|
|
|
|
|
'conditions' => $conditions,
|
|
|
|
|
'fields' => array('Attribute.event_id'),
|
|
|
|
|
);
|
|
|
|
|
$attributes = $this->Attribute->find('all', $params);
|
|
|
|
|
$eventIds = array();
|
|
|
|
|
foreach ($attributes as $attribute) {
|
|
|
|
|
if (!in_array($attribute['Attribute']['event_id'], $eventIds)) $eventIds[] = $attribute['Attribute']['event_id'];
|
|
|
|
|
}
|
|
|
|
|
if (!empty($eventIds)) {
|
|
|
|
|
$results = $this->__fetchEvent(null, $eventIds, $user['User']['org'], true);
|
|
|
|
|
} else {
|
|
|
|
|
throw new NotFoundException('No matches.');
|
|
|
|
|
}
|
|
|
|
|
$this->loadModel('Whitelist');
|
|
|
|
|
$results = $this->Whitelist->removeWhitelistedFromArray($results, true);
|
|
|
|
|
$this->set('results', $results);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function downloadOpenIOCEvent($eventid) {
|
|
|
|
|
|
|
|
|
|
// return a downloadable text file called misp.openIOC.<eventId>.ioc for individual events
|
|
|
|
@ -2311,6 +2212,34 @@ class EventsController extends AppController {
|
|
|
|
|
$this->set('final', $final);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function _addXMLFile() {
|
|
|
|
|
if (!empty($this->data) && $this->data['Event']['submittedxml']['size'] > 0 &&
|
|
|
|
|
is_uploaded_file($this->data['Event']['submittedxml']['tmp_name'])) {
|
|
|
|
|
$xmlData = fread(fopen($this->data['Event']['submittedxml']['tmp_name'], "r"),
|
|
|
|
|
$this->data['Event']['submittedxml']['size']);
|
|
|
|
|
App::uses('Xml', 'Utility');
|
|
|
|
|
$xmlArray = Xml::toArray(Xml::build($xmlData));
|
|
|
|
|
|
|
|
|
|
// In case we receive an event that is not encapsulated in a response. This should never happen (unless it's a copy+paste fail),
|
|
|
|
|
// but just in case, let's clean it up anyway.
|
|
|
|
|
if (isset($xmlArray['Event'])) {
|
|
|
|
|
unset($xmlArray['Event']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!isset($xmlArray['response']) || !isset($xmlArray['response']['Event'])) {
|
|
|
|
|
throw new Exception('This is not a valid MISP XML file.');
|
|
|
|
|
}
|
|
|
|
|
if (isset($xmlArray['response']['Event'][0])) {
|
|
|
|
|
foreach ($xmlArray['response']['Event'] as $event) {
|
|
|
|
|
$temp['Event'] = $event;
|
|
|
|
|
$this->_add($temp, true);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
$temp['Event'] = $xmlArray['response']['Event'];
|
|
|
|
|
$this->_add($temp, true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
public function create_dummy_event() {
|
|
|
|
|
if (!$this->_isSiteAdmin()) throw new MethodNotAllowedException('You don\'t have the privileges to access this.');
|
|
|
|
|
$date = new DateTime();
|
|
|
|
@ -2367,8 +2296,8 @@ class EventsController extends AppController {
|
|
|
|
|
'to_ids' => '0',
|
|
|
|
|
'distribution' => '0',
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$this->_add($data, false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|