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. 'recursive' => -1, 'order' => array( 'GalaxyCluster.value' => 'ASC' ), 'contain' => array( 'Tag' => array( 'fields' => array('Tag.id'), /* 'EventTag' => array( 'fields' => array('EventTag.event_id') ), 'AttributeTag' => array( 'fields' => array('AttributeTag.event_id', 'AttributeTag.attribute_id') ) */ ), 'GalaxyElement' => array( 'conditions' => array('GalaxyElement.key' => 'synonyms'), 'fields' => array('value') ), ) ); public function index($id) { $this->paginate['conditions'] = array('GalaxyCluster.galaxy_id' => $id); if (isset($this->params['named']['searchall']) && strlen($this->params['named']['searchall']) > 0) { $synonym_hits = $this->GalaxyCluster->GalaxyElement->find( 'list', array( 'recursive' => -1, 'conditions' => array( 'LOWER(GalaxyElement.value) LIKE' => '%' . strtolower($this->params['named']['searchall']) . '%', 'GalaxyElement.key' => 'synonyms' ), 'fields' => array( 'GalaxyElement.galaxy_cluster_id') ) ); $this->paginate['conditions'] = array("AND" => array( 'OR' => array( "LOWER(GalaxyCluster.value) LIKE" => '%'. strtolower($this->params['named']['searchall']) .'%', "LOWER(GalaxyCluster.description) LIKE" => '%'. strtolower($this->params['named']['searchall']) .'%', "GalaxyCluster.id" => array_values($synonym_hits) ), "GalaxyCluster.galaxy_id" => $id )); $this->set('passedArgsArray', array('all'=>$this->params['named']['searchall'])); } $clusters = $this->paginate(); $sgs = $this->GalaxyCluster->Tag->EventTag->Event->SharingGroup->fetchAllAuthorised($this->Auth->user()); foreach ($clusters as $k => $cluster) { if (!empty($cluster['Tag']['id'])) { $clusters[$k]['GalaxyCluster']['event_count'] = $this->GalaxyCluster->Tag->EventTag->countForTag($cluster['Tag']['id'], $this->Auth->user(), $sgs); } } $tagIds = array(); $sightings = array(); if (!empty($clusters)) { $galaxyType = $clusters[0]['GalaxyCluster']['type']; foreach ($clusters as $k => $v) { $clusters[$k]['event_ids'] = array(); if (!empty($v['Tag'])) { $tagIds[] = $v['Tag']['id']; $clusters[$k]['GalaxyCluster']['tag_id'] = $v['Tag']['id']; } $clusters[$k]['GalaxyCluster']['synonyms'] = array(); foreach ($v['GalaxyElement'] as $element) { $clusters[$k]['GalaxyCluster']['synonyms'][] = $element['value']; } } } $this->loadModel('Sighting'); $sightings['tags'] = array(); foreach ($clusters as $k => $cluster) { if (!empty($cluster['GalaxyCluster']['tag_id'])) { $temp = $this->Sighting->getSightingsForTag($this->Auth->user(), $cluster['GalaxyCluster']['tag_id']); $clusters[$k]['sightings'] = $temp; } } $csv = array(); foreach ($clusters as $k => $cluster) { $startDate = !empty($cluster['sightings']) ? min(array_keys($cluster['sightings'])) : date('Y-m-d'); $startDate = date('Y-m-d', strtotime("-3 days", strtotime($startDate))); $to = date('Y-m-d', time()); for ($date = $startDate; strtotime($date) <= strtotime($to); $date = date('Y-m-d', strtotime("+1 day", strtotime($date)))) { if (!isset($csv[$k])) { $csv[$k] = 'Date,Close\n'; } if (isset($cluster['sightings'][$date])) { $csv[$k] .= $date . ',' . $cluster['sightings'][$date] . '\n'; } else { $csv[$k] .= $date . ',0\n'; } } } $this->set('csv', $csv); $this->set('list', $clusters); $this->set('galaxy_id', $id); if ($this->request->is('ajax')) { $this->layout = 'ajax'; $this->render('ajax/index'); } } public function view($id) { $conditions = array('GalaxyCluster.id' => $id); if (Validation::uuid($id)) { $conditions = array('GalaxyCluster.uuid' => $id); } $contain = array('Galaxy'); if ($this->_isRest()) { $contain[] = 'GalaxyElement'; } $cluster = $this->GalaxyCluster->find('first', array( 'recursive' => -1, 'contain' => $contain, 'conditions' => $conditions )); if (!empty($cluster)) { $galaxyType = $cluster['GalaxyCluster']['type']; $this->loadModel('Tag'); $tag = $this->Tag->find('first', array( 'conditions' => array( 'name' => $cluster['GalaxyCluster']['tag_name'] ), 'fields' => array('id'), 'recursive' => -1, 'contain' => array('EventTag.tag_id') )); if (!empty($tag)) { $cluster['GalaxyCluster']['tag_count'] = count($tag['EventTag']); $cluster['GalaxyCluster']['tag_id'] = $tag['Tag']['id']; } } else { throw new NotFoundException('Cluster not found.'); } if ($this->_isRest()) { $cluster['GalaxyCluster']['Galaxy'] = $cluster['Galaxy']; $cluster['GalaxyCluster']['GalaxyElement'] = $cluster['GalaxyElement']; return $this->RestResponse->viewData(array('GalaxyCluster' => $cluster['GalaxyCluster']), $this->response->type()); } else { $this->set('id', $id); $this->set('galaxy_id', $cluster['Galaxy']['id']); $this->set('cluster', $cluster); } } public function attachToEvent($event_id, $tag_name) { $this->loadModel('Event'); $this->Event->id = $event_id; $this->Event->recursive = -1; $event = $this->Event->read(array(), $event_id); if (empty($event)) { throw new MethodNotAllowedException('Invalid Event.'); } if (!$this->_isSiteAdmin() && !$this->userRole['perm_sync']) { if (!$this->userRole['perm_tagger'] || ($this->Auth->user('org_id') !== $event['Event']['org_id'] && $this->Auth->user('org_id') !== $event['Event']['orgc_id'])) { throw new MethodNotAllowedException('Invalid Event.'); } } $tag = $this->Event->EventTag->Tag->find('first', array('conditions' => array('Tag.name' => $tag_name), 'recursive' => -1)); if (empty($tag)) { $this->Event->EventTag->Tag->create(); $this->Event->EventTag->Tag->save(array('name' => $tag_name, 'colour' => '#0088cc', 'exportable' => 1)); $tag_id = $this->Event->EventTag->Tag->id; } else { $tag_id = $tag['Tag']['id']; } $existingEventTag = $this->Event->EventTag->find('first', array('conditions' => array('EventTag.tag_id' => $tag_id, 'EventTag.event_id' => $event_id), 'recursive' => -1)); if (empty($existingEventTag)) { $cluster = $this->GalaxyCluster->find('first', array( 'recursive' => -1, 'conditions' => array('GalaxyCluster.tag_name' => $existingEventTag['Tag']['name']) )); $this->Event->EventTag->create(); $this->Event->EventTag->save(array('EventTag.tag_id' => $tag_id, 'EventTag.event_id' => $event_id)); $this->Log = ClassRegistry::init('Log'); $this->Log->create(); $this->Log->save(array( 'org' => $this->Auth->user('Organisation')['name'], 'model' => 'Event', 'model_id' => $event_id, 'email' => $this->Auth->user('email'), 'action' => 'galaxy', 'title' => 'Attached ' . $cluster['GalaxyCluster']['value'] . ' (' . $cluster['GalaxyCluster']['id'] . ') to event (' . $event_id . ')', 'change' => '' )); $event['Event']['published'] = 0; $date = new DateTime(); $event['Event']['timestamp'] = $date->getTimestamp(); $this->Event->save($event); $this->Flash->success('Galaxy attached.'); } else { $this->Flash->error('Galaxy already attached.'); } $this->redirect($this->referer()); } public function detach($target_id, $target_type, $tag_id) { $this->loadModel('Event'); if ($target_type == 'attribute') { $attribute = $this->Event->Attribute->find('first', array( 'recursive' => -1, 'fields' => array('id', 'event_id'), 'conditions' => array('Attribute.id' => $target_id) )); if (empty($attribute)) { throw new MethodNotAllowedException('Invalid Attribute.'); } $event_id = $attribute['Attribute']['event_id']; } elseif ($target_type == 'event') { $event_id = $target_id; } elseif ($target_type === 'tag_collection') { // pass } else { throw new MethodNotAllowedException('Invalid options'); } if ($target_type === 'tag_collection') { $tag_collection = $this->GalaxyCluster->Tag->TagCollectionTag->TagCollection->fetchTagCollection($this->Auth->user(), array( 'conditions' => array('TagCollection.id' => $target_id), 'contain' => array('Organisation', 'TagCollectionTag' => array('Tag')) )); if (empty($tag_collection)) { throw new MethodNotAllowedException('Invalid Tag Collection'); } $tag_collection = $tag_collection[0]; if (!$this->_isSiteAdmin()) { if (!$this->userRole['perm_tag_editor'] || $this->Auth->user('org_id') !== $tag_collection['TagCollection']['org_id']) { throw new MethodNotAllowedException('Invalid Tag Collection'); } } } else { $this->Event->id = $event_id; $this->Event->recursive = -1; $event = $this->Event->read(array(), $event_id); if (empty($event)) { throw new MethodNotAllowedException('Invalid Event.'); } if (!$this->_isSiteAdmin() && !$this->userRole['perm_sync']) { if (!$this->userRole['perm_tagger'] || ($this->Auth->user('org_id') !== $event['Event']['org_id'] && $this->Auth->user('org_id') !== $event['Event']['orgc_id'])) { throw new MethodNotAllowedException('Invalid Event.'); } } } if ($target_type == 'attribute') { $existingTargetTag = $this->Event->Attribute->AttributeTag->find('first', array( 'conditions' => array('AttributeTag.tag_id' => $tag_id, 'AttributeTag.attribute_id' => $target_id), 'recursive' => -1, 'contain' => array('Tag') )); } elseif ($target_type == 'event') { $existingTargetTag = $this->Event->EventTag->find('first', array( 'conditions' => array('EventTag.tag_id' => $tag_id, 'EventTag.event_id' => $target_id), 'recursive' => -1, 'contain' => array('Tag') )); } elseif ($target_type == 'tag_collection') { $existingTargetTag = $this->GalaxyCluster->Tag->TagCollectionTag->find('first', array( 'conditions' => array('TagCollectionTag.tag_id' => $tag_id, 'TagCollectionTag.tag_collection_id' => $target_id), 'recursive' => -1, 'contain' => array('Tag') )); } if (empty($existingTargetTag)) { $this->Flash->error('Galaxy not attached.'); } else { $cluster = $this->GalaxyCluster->find('first', array( 'recursive' => -1, 'conditions' => array('GalaxyCluster.tag_name' => $existingTargetTag['Tag']['name']) )); if ($target_type == 'event') { $result = $this->Event->EventTag->delete($existingTargetTag['EventTag']['id']); } elseif ($target_type == 'attribute') { $result = $this->Event->Attribute->AttributeTag->delete($existingTargetTag['AttributeTag']['id']); } elseif ($target_type == 'tag_collection') { $result = $this->GalaxyCluster->Tag->TagCollectionTag->delete($existingTargetTag['TagCollectionTag']['id']); } if ($result) { $event['Event']['published'] = 0; $date = new DateTime(); $event['Event']['timestamp'] = $date->getTimestamp(); $this->Event->save($event); $this->Flash->success('Galaxy successfully detached.'); $this->Log = ClassRegistry::init('Log'); $this->Log->create(); $this->Log->save(array( 'org' => $this->Auth->user('Organisation')['name'], 'model' => ucfirst($target_type), 'model_id' => $target_id, 'email' => $this->Auth->user('email'), 'action' => 'galaxy', 'title' => 'Detached ' . $cluster['GalaxyCluster']['value'] . ' (' . $cluster['GalaxyCluster']['id'] . ') from ' . $target_type . ' (' . $target_id . ')', 'change' => '' )); } else { $this->Flash->error('Could not detach galaxy from event.'); } } $this->redirect($this->referer()); } public function delete($id) { { if ($this->request->is('post')) { $result = false; $galaxy_cluster = $this->GalaxyCluster->find('first', array( 'recursive' => -1, 'conditions' => array('GalaxyCluster.id' => $id) )); if (!empty($galaxy_cluster)) { $result = $this->GalaxyCluster->delete($id, true); $galaxy_id = $galaxy_cluster['GalaxyCluster']['galaxy_id']; } if ($result) { $message = 'Galaxy cluster successfuly deleted.'; if ($this->_isRest()) { return $this->RestResponse->saveSuccessResponse('GalaxyCluster', 'delete', $id, $this->response->type()); } else { $this->Flash->success($message); $this->redirect(array('controller' => 'galaxies', 'action' => 'view', $galaxy_id)); } } else { $message = 'Galaxy cluster could not be deleted.'; if ($this->_isRest()) { return $this->RestResponse->saveFailResponse('GalaxyCluster', 'delete', $id, $message, $this->response->type()); } else { $this->Flash->error($message); $this->redirect(array('controller' => 'taxonomies', 'action' => 'index')); } } } else { if ($this->request->is('ajax')) { $this->set('id', $id); $this->render('ajax/galaxy_cluster_delete_confirmation'); } else { throw new MethodNotAllowedException('This function can only be reached via AJAX.'); } } } } public function viewGalaxyMatrix($id) { if (!$this->request->is('ajax')) { throw new MethodNotAllowedException('This function can only be reached via AJAX.'); } $cluster = $this->GalaxyCluster->find('first', array( 'conditions' => array('id' => $id) )); if (empty($cluster)) { throw new Exception("Invalid Galaxy Cluster."); } $this->loadModel('Event'); $mitreAttackGalaxyId = $this->GalaxyCluster->Galaxy->getMitreAttackGalaxyId(); $attackPatternTagNames = $this->GalaxyCluster->find('list', array( 'conditions' => array('galaxy_id' => $mitreAttackGalaxyId), 'fields' => array('tag_name') )); $cluster = $cluster['GalaxyCluster']; $tag_name = $cluster['tag_name']; // fetch all event ids having the requested cluster $eventIds = $this->Event->EventTag->find('list', array( 'contain' => array('Tag'), 'conditions' => array( 'Tag.name' => $tag_name ), 'fields' => array('event_id'), 'recursive' => -1 )); // fetch all attribute ids having the requested cluster $attributes = $this->Event->Attribute->AttributeTag->find('all', array( 'contain' => array('Tag'), 'conditions' => array( 'Tag.name' => $tag_name ), 'fields' => array('attribute_id', 'event_id'), 'recursive' => -1 )); $attributeIds = array(); $additional_event_ids = array(); foreach ($attributes as $attribute) { $attributeIds[] = $attribute['AttributeTag']['attribute_id']; $additional_event_ids[$attribute['AttributeTag']['event_id']] = $attribute['AttributeTag']['event_id']; } $additional_event_ids = array_keys($additional_event_ids); $eventIds = array_merge($eventIds, $additional_event_ids); unset($attributes); unset($additional_event_ids); // fetch all related tags belonging to attack pattern $eventTags = $this->Event->EventTag->find('all', array( 'contain' => array('Tag'), 'conditions' => array( 'event_id' => $eventIds, 'Tag.name' => $attackPatternTagNames ), 'fields' => array('Tag.name, COUNT(DISTINCT event_id) as tag_count'), 'recursive' => -1, 'group' => array('Tag.name') )); // fetch all related tags belonging to attack pattern or belonging to an event having this cluster $attributeTags = $this->Event->Attribute->AttributeTag->find('all', array( 'contain' => array('Tag'), 'conditions' => array( 'OR' => array( 'event_id' => $eventIds, 'attribute_id' => $attributeIds ), 'Tag.name' => $attackPatternTagNames ), 'fields' => array('Tag.name, COUNT(DISTINCT event_id) as tag_count'), 'recursive' => -1, 'group' => array('Tag.name') )); $scores = array(); foreach ($attributeTags as $tag) { $tagName = $tag['Tag']['name']; $scores[$tagName] = intval($tag[0]['tag_count']); } foreach ($eventTags as $tag) { $tagName = $tag['Tag']['name']; if (isset($scores[$tagName])) { $scores[$tagName] = $scores[$tagName] + intval($tag[0]['tag_count']); } else { $scores[$tagName] = intval($tag[0]['tag_count']); } } $maxScore = count($scores) > 0 ? max(array_values($scores)) : 0; $matrixData = $this->GalaxyCluster->Galaxy->getMatrix($mitreAttackGalaxyId, $scores); $tabs = $matrixData['tabs']; $matrixTags = $matrixData['matrixTags']; $killChainOrders = $matrixData['killChain']; $instanceUUID = $matrixData['instance-uuid']; App::uses('ColourGradientTool', 'Tools'); $gradientTool = new ColourGradientTool(); $colours = $gradientTool->createGradientFromValues($scores); $this->set('target_type', 'attribute'); $this->set('columnOrders', $killChainOrders); $this->set('tabs', $tabs); $this->set('scores', $scores); $this->set('maxScore', $maxScore); if (!empty($colours)) { $this->set('colours', $colours['mapping']); $this->set('interpolation', $colours['interpolation']); } $this->set('pickingMode', false); $this->set('defaultTabName', 'mitre-attack'); $this->set('removeTrailling', 2); $this->render('cluster_matrix'); } }