new: [user:periodic_report] Added security recommendations section showing course of actions related to attack techniques

pull/8641/head
Sami Mokaddem 2022-10-04 16:01:09 +02:00
parent e0fce46994
commit 44c5fceb63
No known key found for this signature in database
GPG Key ID: 164C473F627A06FA
5 changed files with 115 additions and 7 deletions

View File

@ -1635,6 +1635,9 @@ class Event extends AppModel
if (!isset($options['fetchFullClusters'])) {
$options['fetchFullClusters'] = true;
}
if (!isset($options['fetchFullClusterRelationship'])) {
$options['fetchFullClusterRelationship'] = false;
}
foreach ($possibleOptions as $opt) {
if (!isset($options[$opt])) {
$options[$opt] = false;
@ -1983,7 +1986,7 @@ class Event extends AppModel
$event['warnings'] = $eventWarnings;
}
$this->__attachTags($event, $justExportableTags);
$this->__attachGalaxies($event, $user, $options['excludeGalaxy'], $options['fetchFullClusters']);
$this->__attachGalaxies($event, $user, $options['excludeGalaxy'], $options['fetchFullClusters'], $options['fetchFullClusterRelationship']);
$event = $this->Orgc->attachOrgs($event, $fieldsOrg);
if (!$sharingGroupReferenceOnly && $event['Event']['sharing_group_id']) {
if (isset($sharingGroupData[$event['Event']['sharing_group_id']])) {
@ -2147,7 +2150,7 @@ class Event extends AppModel
* @param bool $excludeGalaxy
* @param bool $fetchFullCluster
*/
private function __attachGalaxies(array &$event, array $user, $excludeGalaxy, $fetchFullCluster)
private function __attachGalaxies(array &$event, array $user, $excludeGalaxy, $fetchFullCluster, $fetchFullRelationship=false)
{
$galaxyTags = [];
$event['Galaxy'] = [];
@ -2176,7 +2179,7 @@ class Event extends AppModel
}
$this->GalaxyCluster = ClassRegistry::init('GalaxyCluster');
$clusters = $this->GalaxyCluster->getClustersByTags($galaxyTags, $user, true, $fetchFullCluster);
$clusters = $this->GalaxyCluster->getClustersByTags($galaxyTags, $user, true, $fetchFullCluster, $fetchFullRelationship);
if (empty($clusters)) {
return;
@ -7614,4 +7617,52 @@ class Event extends AppModel
'all_timestamps' => array_keys($clusteredTags['eventNumberPerRollingWindow']),
];
}
public function extractRelatedCourseOfActions(array $events): array
{
$mitre_attack_galaxy_type = 'mitre-attack-pattern';
$mitre_coa_galaxy_type = 'mitre-course-of-action';
$allowedRelationTypes = ['mitigates'];
$coa = [];
foreach ($events as $event) {
foreach ($event['Galaxy'] as $galaxy) {
foreach ($galaxy['GalaxyCluster'] as $cluster) {
foreach ($cluster['GalaxyClusterRelation'] as $relation) {
if (in_array($relation['referenced_galaxy_cluster_type'], $allowedRelationTypes) && $relation['TargetCluster']['type'] == $mitre_coa_galaxy_type) {
if (!isset($coa[$relation['TargetCluster']['tag_name']])) {
$coa[$relation['TargetCluster']['tag_name']] = $relation['TargetCluster'];
$coa[$relation['TargetCluster']['tag_name']]['occurrence'] = 0;
$coa[$relation['TargetCluster']['tag_name']]['techniques'] = [];
}
$coa[$relation['TargetCluster']['tag_name']]['occurrence'] += 1;
if ($cluster['type'] == $mitre_attack_galaxy_type) {
$coa[$relation['TargetCluster']['tag_name']]['techniques'][$cluster['tag_name']] = $cluster;
}
}
}
if (!empty($cluster['TargetingClusterRelation'])) {
foreach ($cluster['TargetingClusterRelation'] as $relation) {
if (in_array($relation['referenced_galaxy_cluster_type'], $allowedRelationTypes) && $relation['GalaxyCluster']['type'] == $mitre_coa_galaxy_type) {
if (!isset($coa[$relation['GalaxyCluster']['tag_name']])) {
$coa[$relation['GalaxyCluster']['tag_name']] = $relation['GalaxyCluster'];
$coa[$relation['GalaxyCluster']['tag_name']]['techniques'] = [];
$coa[$relation['GalaxyCluster']['tag_name']]['occurrence'] = 0;
}
$coa[$relation['GalaxyCluster']['tag_name']]['occurrence'] += 1;
if ($cluster['type'] == $mitre_attack_galaxy_type
) {
$coa[$relation['GalaxyCluster']['tag_name']]['techniques'][$cluster['tag_name']] = $cluster;
}
}
}
}
}
}
}
uasort($coa, function ($a, $b) {
return $a['occurrence'] > $b['occurrence'] ? -1 : 1;
});
return $coa;
}
}

View File

@ -973,7 +973,7 @@ class GalaxyCluster extends AppModel
* @param bool $fetchFullCluster
* @return array
*/
public function getClustersByTags(array $tagNames, array $user, $postProcess = true, $fetchFullCluster = true)
public function getClustersByTags(array $tagNames, array $user, $postProcess = true, $fetchFullCluster = true, $fetchFullRelationship = false)
{
$options = [
'conditions' => ['GalaxyCluster.tag_name' => $tagNames],
@ -982,7 +982,7 @@ class GalaxyCluster extends AppModel
$options['contain'] = ['Galaxy', 'GalaxyElement'];
}
$clusters = $this->fetchGalaxyClusters($user, $options, $fetchFullCluster);
$clusters = $this->fetchGalaxyClusters($user, $options, $fetchFullCluster, $fetchFullRelationship);
if (!empty($clusters) && $postProcess) {
$tagIds = array_change_key_case(array_flip($tagNames));
@ -1028,7 +1028,7 @@ class GalaxyCluster extends AppModel
* @param bool $full
* @return array
*/
public function fetchGalaxyClusters(array $user, array $options, $full=false)
public function fetchGalaxyClusters(array $user, array $options, $full=false, $includeFullClusterRelationship=false)
{
$params = array(
'conditions' => $this->buildConditions($user),
@ -1048,6 +1048,9 @@ class GalaxyCluster extends AppModel
'SharingGroup'
);
}
if (!empty($includeFullClusterRelationship)) {
$params['contain']['GalaxyClusterRelation'][] = 'TargetCluster';
}
if (!empty($options['contain'])) {
$params['contain'] = $options['contain'];
}
@ -1126,6 +1129,9 @@ class GalaxyCluster extends AppModel
if (!empty($targetingClusterRelation['SharingGroup']['id'])) {
$targetingClusterRelation['TargetingClusterRelation']['SharingGroup'] = $targetingClusterRelation['SharingGroup'];
}
if ($includeFullClusterRelationship) {
$targetingClusterRelation['TargetingClusterRelation']['GalaxyCluster'] = $targetingClusterRelation['SourceCluster'];
}
$targetingClusterRelations[$k] = $targetingClusterRelation['TargetingClusterRelation'];
}
}

View File

@ -1808,7 +1808,8 @@ class User extends AppModel
$filters['includeEventCorrelations'] = !empty($periodicSettings['include_correlations']);
$filters['includeGranularCorrelations'] = !empty($periodicSettings['include_correlations']);
$filters['noSightings'] = true;
$filters['fetchFullClusters'] = false;
$filters['fetchFullClusters'] = true;
$filters['fetchFullClusterRelationship'] = true;
$filters['includeScoresOnEvent'] = true;
$events = $this->Event->fetchEvent($user, $filters);
@ -1833,6 +1834,10 @@ class User extends AppModel
'tagFilterPrefixes' => $tagFilterPrefixes,
];
$trending_summary = $this->__renderTrendingSummary($trendData);
$securityRecommendationsData = [
'course_of_action' => $this->Event->extractRelatedCourseOfActions($events),
];
$security_recommendations = $this->__renderSecurityRecommenrations($securityRecommendationsData);
$emailTemplate = $this->prepareEmailTemplate($period);
$emailTemplate->set('baseurl', $this->Event->__getAnnounceBaseurl());
@ -1843,6 +1848,7 @@ class User extends AppModel
$emailTemplate->set('period', $period);
$emailTemplate->set('aggregated_context', $aggregated_context);
$emailTemplate->set('trending_summary', $trending_summary);
$emailTemplate->set('security_recommendations', $security_recommendations);
$emailTemplate->set('analysisLevels', $this->Event->analysisLevels);
$emailTemplate->set('distributionLevels', $this->Event->distributionLevels);
if ($rendered) {
@ -1862,6 +1868,11 @@ class User extends AppModel
return $this->__renderGeneric('Elements' . DS . 'Events', 'trendingSummary', $trendData);
}
private function __renderSecurityRecommenrations(array $data): string
{
return $this->__renderGeneric('Elements' . DS . 'Events', 'securityRecommendations', $data);
}
private function __renderGeneric(string $viewPath, string $viewFile, array $viewVars): string
{
$view = new View();

View File

@ -0,0 +1,27 @@
<?php
$colorMapping = [
0 => '#cc0033',
1 => '#f89406',
];
?>
<h2><?= __('Preventive Measures & Mitigations') ?></h2>
<?php foreach (array_values($course_of_action) as $i => $coa) : ?>
<div style="margin-bottom: 0.5em;">
<div>
<span class="tag" style="background-color: <?= $colorMapping[$i] ?? '#999' ?>; color: #fff; border-radius: 9px; padding: 2px 8px;">
<?= h($coa['occurrence']) ?>
</span>
<strong><a href="<?= $baseurl . '/galaxy_clusters/view/' . h($coa['id']) ?>" target="_blank"><?= h($coa['value']) ?></a>: </strong>
<?= h($this->Markdown->toText($coa['description'])) ?>
</div>
<ul>
<?php foreach ($coa['techniques'] as $technique) : ?>
<li>
<code><?= h($technique['value']) ?></code>:
<small><?= h($technique['description']) ?></small>
</li>
<?php endforeach; ?>
</ul>
</div>
<?php endforeach; ?>

View File

@ -552,6 +552,19 @@ $top_mitre_attack_techniques = array_slice($mitre_attack_techniques, 0, 10);
</div>
<?php endif; ?>
<?php if ($this->fetch('security-recommendations')) : ?>
<?= $this->fetch('security-recommendations'); ?>
<?php else: ?>
<div class="panel">
<div class="panel-header">
<?= __('Security Recommendations') ?>
</div>
<div class="panel-body">
<?= $security_recommendations; ?>
</div>
</div>
<?php endif; ?>
<?= $this->fetch('content'); ?>
<style>