From 155bf237765ceeef21b7b2b0087b9b4fec252a01 Mon Sep 17 00:00:00 2001 From: Sami Mokaddem Date: Tue, 8 Mar 2022 13:40:15 +0100 Subject: [PATCH] new: [events:restSearch] Added `context` export format The `context` export format includes: - List of used taxonomies - List of used galaxy cluster - List of custom tags - Mitre Att&ck matrix --- app/Lib/Export/ContextExport.php | 163 ++++++++++++++++++ app/Model/Event.php | 1 + app/View/Events/module_views/context_view.ctp | 77 +++++++++ 3 files changed, 241 insertions(+) create mode 100644 app/Lib/Export/ContextExport.php create mode 100644 app/View/Events/module_views/context_view.ctp diff --git a/app/Lib/Export/ContextExport.php b/app/Lib/Export/ContextExport.php new file mode 100644 index 000000000..6adc21189 --- /dev/null +++ b/app/Lib/Export/ContextExport.php @@ -0,0 +1,163 @@ + 1, + 'includeEventTags' => 1, + 'includeGalaxy' => 1, + 'noSightings' => true, + 'noEventReports' => true, + 'noShadowAttributes' => true, + 'sgReferenceOnly' => true, + 'includeEventCorrelations' => false, + ]; + private $__eventTags = []; + private $__eventGalaxies = []; + + private $__aggregatedTags = []; + private $__aggregatedClusters = []; + + private $__taxonomyFetched = []; + private $__galaxyFetched = []; + + public $non_restrictive_export = true; + public $renderView = 'context_view'; + + public function handler($data, $options = array()) + { + $this->__aggregate($data, Hash::extract($data, 'EventTag.{n}.Tag')); + if (!empty($data['Attribute'])) { + foreach ($data['Attribute'] as $attribute) { + $this->__aggregate($attribute, Hash::extract($attribute, 'AttributeTag.{n}.Tag')); + } + } + + $this->__attack_export_tool->handler($data, $options); + return ''; + } + + public function header($options = array()) + { + $this->__TaxonomyModel = ClassRegistry::init('Taxonomy'); + $this->__GalaxyModel = ClassRegistry::init('Galaxy'); + App::uses('AttackExport', 'Export'); + $this->__attack_export_tool = new AttackExport(); + $this->__attack_export_tool->handler($options); + + return ''; + } + + public function footer() + { + $attackFinal = $this->__attack_export_tool->footer(); + $this->__aggregateTagsPerTaxonomy(); + $this->__aggregateClustersPerGalaxy(); + $attackData = json_decode($attackFinal, true); + return json_encode([ + 'attackData' => $attackData, + 'tags' => $this->__aggregatedTags, + 'clusters' => $this->__aggregatedClusters, + ]); + } + + public function separator() + { + $this->__attack_export_tool->separator(); + return ''; + } + + private function __aggregate($entity, $tags) + { + if (!empty($entity['Galaxy'])) { + foreach ($entity['Galaxy'] as $galaxy) { + foreach ($galaxy['GalaxyCluster'] as $galaxyCluster) { + $this->__eventGalaxies[$galaxyCluster['tag_name']] = $galaxyCluster; + $this->fetchGalaxyForTag($galaxyCluster['tag_name']); + } + } + } + if (!empty($tags)) { + foreach ($tags as $tag) { + if (strpos($tag['name'], 'misp-galaxy:') === 0) { + continue; + } + $this->__eventTags[$tag['name']] = $tag; + $this->fetchTaxonomyForTag($tag['name']); + } + } + } + + private function fetchTaxonomyForTag($tagname) + { + $splits = $this->__TaxonomyModel->splitTagToComponents($tagname); + if (!isset($this->__taxonomyFetched[$splits['namespace']])) { + $fetchedTaxonomy = $this->__TaxonomyModel->getTaxonomyForTag($tagname, false, true); + if (!empty($fetchedTaxonomy)) { + $this->__taxonomyFetched[$splits['namespace']]['Taxonomy'] = $fetchedTaxonomy['Taxonomy']; + $this->__taxonomyFetched[$splits['namespace']]['TaxonomyPredicate'] = []; + foreach ($fetchedTaxonomy['TaxonomyPredicate'] as $predicate) { + $this->__taxonomyFetched[$splits['namespace']]['TaxonomyPredicate'][$predicate['value']] = $predicate; + if (!empty($predicate['TaxonomyEntry'])) { + $this->__taxonomyFetched[$splits['namespace']]['TaxonomyPredicate'][$predicate['value']]['TaxonomyEntry'] = []; + foreach ($predicate['TaxonomyEntry'] as $entry) { + $this->__taxonomyFetched[$splits['namespace']]['TaxonomyPredicate'][$predicate['value']]['TaxonomyEntry'][$entry['value']] = $entry; + } + } + } + } + } + } + + private function fetchGalaxyForTag($tagname) + { + $splits = $this->__TaxonomyModel->splitTagToComponents($tagname); + $galaxy = $this->__GalaxyModel->find('first', array( + 'recursive' => -1, + 'conditions' => array('Galaxy.type' => $splits['predicate']) + )); + $this->__galaxyFetched[$splits['predicate']] = $galaxy; + } + + private function __aggregateTagsPerTaxonomy() + { + ksort($this->__eventTags); + foreach ($this->__eventTags as $tagname => $tagData) { + $splits = $this->__TaxonomyModel->splitTagToComponents($tagname); + $taxonomy = []; + if (!empty($this->__taxonomyFetched[$splits['namespace']])) { + $taxonomy = $this->__taxonomyFetched[$splits['namespace']]; + } + if (!empty($taxonomy['TaxonomyPredicate'][$splits['predicate']])) { + $predicate = $taxonomy['TaxonomyPredicate'][$splits['predicate']]; + $entry = null; + if (!empty($splits['value'])) { + $entry = $predicate['TaxonomyEntry'][$splits['value']]; + } + unset($predicate['TaxonomyEntry']); + $this->__aggregatedTags[$splits['namespace']][] = [ + 'Taxonomy' => $taxonomy['Taxonomy'], + 'TaxonomyPredicate' => $predicate, + 'TaxonomyEntry' => $entry, + 'Tag' => $tagData, + ]; + } else { + $this->__aggregatedTags['Custom Tags'][]['Tag'] = $tagData; + } + } + } + + private function __aggregateClustersPerGalaxy() + { + ksort($this->__eventGalaxies); + foreach ($this->__eventGalaxies as $tagname => $cluster) { + $splits = $this->__TaxonomyModel->splitTagToComponents($tagname); + $galaxy = $this->__galaxyFetched[$splits['predicate']]; + $this->__aggregatedClusters[$splits['predicate']][] = [ + 'Galaxy' => $galaxy['Galaxy'], + 'GalaxyCluster' => $cluster, + ]; + } + } +} diff --git a/app/Model/Event.php b/app/Model/Event.php index facdaf451..02d49de40 100755 --- a/app/Model/Event.php +++ b/app/Model/Event.php @@ -73,6 +73,7 @@ class Event extends AppModel 'attack' => array('html', 'AttackExport', 'html'), 'attack-sightings' => array('json', 'AttackSightingsExport', 'json'), 'cache' => array('txt', 'CacheExport', 'cache'), + 'context' => array('html', 'ContextExport', 'html'), 'count' => array('txt', 'CountExport', 'txt'), 'csv' => array('csv', 'CsvExport', 'csv'), 'hashes' => array('txt', 'HashesExport', 'txt'), diff --git a/app/View/Events/module_views/context_view.ctp b/app/View/Events/module_views/context_view.ctp new file mode 100644 index 000000000..eca88b194 --- /dev/null +++ b/app/View/Events/module_views/context_view.ctp @@ -0,0 +1,77 @@ +
+

+

+
+ $entries) { + $htmlTags .= sprintf('

%s

', h($namespace)); + if (!empty($entries[0]['Taxonomy']['description'])) { + $htmlTags .= sprintf('
%s
', h($entries[0]['Taxonomy']['description'])); + } + $htmlTags .= '
    '; + foreach ($entries as $entry) { + $taxonomyInfo = '
      '; + if (!empty($entry['TaxonomyPredicate'])) { + $taxonomyInfo .= sprintf( + '
    • %s: %s
    • ', + h($entry['TaxonomyPredicate']['value']), + h($entry['TaxonomyPredicate']['expanded']) + ); + } + if (!empty($entry['TaxonomyEntry'])) { + $taxonomyInfo .= sprintf( + '
    • %s: %s
    • ', + h($entry['TaxonomyEntry']['value']), + h($entry['TaxonomyEntry']['expanded']) + ); + } + $taxonomyInfo .= '
    '; + $htmlTags .= sprintf( + '
  • %s
  • %s', + $this->element('tag', ['tag' => $entry]), + $taxonomyInfo + ); + } + $htmlTags .= '
'; + } + echo $htmlTags; + ?> +
+ +

+
+ $entries) { + $htmlClusters .= sprintf( + '

%s %s

', + sprintf('', $this->FontAwesome->getClass($entries[0]['Galaxy']['icon'])), + h($entries[0]['Galaxy']['name']) + ); + if (!empty($entries[0]['Galaxy']['description'])) { + $htmlClusters .= sprintf('
%s
', h($entries[0]['Galaxy']['description'])); + } + $htmlClusters .= '
    '; + foreach ($entries as $cluster) { + $htmlClusters .= sprintf( + '
  • %s
  • %s', + $baseurl . '/galaxy_clusters/view/' . h($cluster['GalaxyCluster']['id']), + h($cluster['GalaxyCluster']['value']), + strlen(h($cluster['GalaxyCluster']['description'])) > 300 ? + (substr(h($cluster['GalaxyCluster']['description']), 0, 300) . '...') : h($cluster['GalaxyCluster']['description']), + ); + } + $htmlClusters .= '
'; + } + echo $htmlClusters; + ?> +
+ +

+
+ element('view_galaxy_matrix', $attackData); + ?> +
+