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
pull/8208/head
Sami Mokaddem 2022-03-08 13:40:15 +01:00
parent 69b0937ea2
commit 155bf23776
No known key found for this signature in database
GPG Key ID: 164C473F627A06FA
3 changed files with 241 additions and 0 deletions

View File

@ -0,0 +1,163 @@
<?php
class ContextExport
{
private $__attack_export_tool = null;
public $additional_params = [
'flatten' => 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,
];
}
}
}

View File

@ -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'),

View File

@ -0,0 +1,77 @@
<div>
<h1><?= __('Aggregated context data') ?></h1>
<h2><?= __('Tags and Taxonomies') ?></h2>
<div>
<?php
$htmlTags = '';
foreach ($tags as $namespace => $entries) {
$htmlTags .= sprintf('<div><h4>%s</h4></div>', h($namespace));
if (!empty($entries[0]['Taxonomy']['description'])) {
$htmlTags .= sprintf('<div><i>%s</i></div>', h($entries[0]['Taxonomy']['description']));
}
$htmlTags .= '<ul>';
foreach ($entries as $entry) {
$taxonomyInfo = '<ul>';
if (!empty($entry['TaxonomyPredicate'])) {
$taxonomyInfo .= sprintf(
'<li><strong>%s</strong>: %s</li>',
h($entry['TaxonomyPredicate']['value']),
h($entry['TaxonomyPredicate']['expanded'])
);
}
if (!empty($entry['TaxonomyEntry'])) {
$taxonomyInfo .= sprintf(
'<li><strong>%s</strong>: %s</li>',
h($entry['TaxonomyEntry']['value']),
h($entry['TaxonomyEntry']['expanded'])
);
}
$taxonomyInfo .= '</ul>';
$htmlTags .= sprintf(
'<li>%s</li>%s',
$this->element('tag', ['tag' => $entry]),
$taxonomyInfo
);
}
$htmlTags .= '</ul>';
}
echo $htmlTags;
?>
</div>
<h2><?= __('Galaxy Clusters') ?></h2>
<div>
<?php
$htmlClusters = '';
foreach ($clusters as $tagname => $entries) {
$htmlClusters .= sprintf(
'<div><h4>%s %s</h4></div>',
sprintf('<i class="%s"></i>', $this->FontAwesome->getClass($entries[0]['Galaxy']['icon'])),
h($entries[0]['Galaxy']['name'])
);
if (!empty($entries[0]['Galaxy']['description'])) {
$htmlClusters .= sprintf('<div><i>%s</i></div>', h($entries[0]['Galaxy']['description']));
}
$htmlClusters .= '<ul>';
foreach ($entries as $cluster) {
$htmlClusters .= sprintf(
'<li><strong><a href="%s" target="_blank">%s</a></strong></li> %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 .= '</ul>';
}
echo $htmlClusters;
?>
</div>
<h2><?= __('Mitre ATT&CK Matrix') ?></h2>
<div id="attackmatrix_div" style="position: relative; border: solid 1px;" class="statistics_attack_matrix">
<?php
echo $this->element('view_galaxy_matrix', $attackData);
?>
</div>
</div>