mirror of https://github.com/MISP/MISP
new: [statistics:galaxyMatrix] Added filtering capabilities
parent
e38358de69
commit
0c69e739cc
|
@ -1900,101 +1900,159 @@ class UsersController extends AppController
|
|||
{
|
||||
$this->loadModel('Event');
|
||||
$this->loadModel('Galaxy');
|
||||
$this->loadModel('Organisation');
|
||||
$mitre_galaxy_id = $this->Galaxy->getMitreAttackGalaxyId();
|
||||
if (isset($params['galaxy_id'])) {
|
||||
$galaxy_id = $params['galaxy_id'];
|
||||
} else {
|
||||
$galaxy_id = $mitre_galaxy_id;
|
||||
}
|
||||
$matrixData = $this->Galaxy->getMatrix($galaxy_id);
|
||||
|
||||
$tabs = $matrixData['tabs'];
|
||||
$matrixTags = $matrixData['matrixTags'];
|
||||
$killChainOrders = $matrixData['killChain'];
|
||||
$instanceUUID = $matrixData['instance-uuid'];
|
||||
|
||||
$scoresDataAttr = $this->Event->Attribute->AttributeTag->getTagScores(0, $matrixTags);
|
||||
$scoresDataEvent = $this->Event->EventTag->getTagScores(0, $matrixTags);
|
||||
$scoresData = array();
|
||||
foreach (array_keys($scoresDataAttr['scores'] + $scoresDataEvent['scores']) as $key) {
|
||||
$scoresData[$key] = (isset($scoresDataAttr['scores'][$key]) ? $scoresDataAttr['scores'][$key] : 0) + (isset($scoresDataEvent['scores'][$key]) ? $scoresDataEvent['scores'][$key] : 0);
|
||||
$organisations = $this->Organisation->find('all', array(
|
||||
'recursive' => -1,
|
||||
));
|
||||
array_unshift($organisations, array('Organisation' => array('id' => 0, 'name' => 'All')));
|
||||
$this->set('organisations', $organisations);
|
||||
$picked_organisation = 0;
|
||||
if (isset($params['organisation']) && $params['organisation'] != 0) {
|
||||
$org = $this->Organisation->find('first', array(
|
||||
'recursive' => -1,
|
||||
'conditions' => array('id' => $params['organisation']),
|
||||
));
|
||||
if (!empty($org)) {
|
||||
$picked_organisation = $org;
|
||||
$this->set('picked_organisation', $picked_organisation);
|
||||
} else {
|
||||
$this->set('picked_organisation', array('Organisation' => array('id' => '')));
|
||||
}
|
||||
} else {
|
||||
$this->set('picked_organisation', array('Organisation' => array('id' => '')));
|
||||
}
|
||||
$maxScore = max($scoresDataAttr['maxScore'], $scoresDataEvent['maxScore']);
|
||||
$scores = $scoresData;
|
||||
// FIXME: temporary fix: add the score of deprecated mitre galaxies to the new one (for the stats)
|
||||
if ($matrixData['galaxy']['id'] == $mitre_galaxy_id) {
|
||||
$mergedScore = array();
|
||||
foreach ($scoresData as $tag => $v) {
|
||||
$predicateValue = explode(':', $tag, 2)[1];
|
||||
$predicateValue = explode('=', $predicateValue, 2);
|
||||
$predicate = $predicateValue[0];
|
||||
$clusterValue = $predicateValue[1];
|
||||
$mappedTag = '';
|
||||
$mappingWithoutExternalId = array();
|
||||
if ($predicate == 'mitre-attack-pattern') {
|
||||
$mappedTag = $tag;
|
||||
$name = explode(" ", $tag);
|
||||
$name = join(" ", array_slice($name, 0, -2)); // remove " - external_id"
|
||||
$mappingWithoutExternalId[$name] = $tag;
|
||||
} else {
|
||||
$name = explode(" ", $clusterValue);
|
||||
$name = join(" ", array_slice($name, 0, -2)); // remove " - external_id"
|
||||
if (isset($mappingWithoutExternalId[$name])) {
|
||||
$mappedTag = $mappingWithoutExternalId[$name];
|
||||
|
||||
$rest_response_empty = true;
|
||||
$ignore_score = false;
|
||||
if (
|
||||
isset($params['dateFrom'])
|
||||
|| isset($params['dateTo'])
|
||||
|| isset($params['organisation']) && $params['organisation'] != 0
|
||||
) { // use restSearch
|
||||
$filters = array();
|
||||
if (isset($params['dateFrom'])) {
|
||||
$filters['from'] = $params['dateFrom'];
|
||||
$this->set('dateFrom', $params['dateFrom']);
|
||||
}
|
||||
if (isset($params['dateTo'])) {
|
||||
$filters['to'] = $params['dateTo'];
|
||||
$this->set('dateTo', $params['dateTo']);
|
||||
}
|
||||
if (isset($params['organisation'])) {
|
||||
$filters['org'] = $params['organisation'];
|
||||
}
|
||||
$elementCounter = 0;
|
||||
$renderView = '';
|
||||
$final = $this->Event->Attribute->restSearch($this->Auth->user(), 'attack', $filters, false, false, $elementCounter, $renderView);
|
||||
$final = json_decode($final, true);
|
||||
if (!empty($final)) {
|
||||
$rest_response_empty = false;
|
||||
$ignore_score = true;
|
||||
}
|
||||
foreach ($final as $key => $data) {
|
||||
$this->set($key, $data);
|
||||
}
|
||||
}
|
||||
|
||||
if ($rest_response_empty) {
|
||||
$matrixData = $this->Galaxy->getMatrix($galaxy_id);
|
||||
$tabs = $matrixData['tabs'];
|
||||
$matrixTags = $matrixData['matrixTags'];
|
||||
$killChainOrders = $matrixData['killChain'];
|
||||
$instanceUUID = $matrixData['instance-uuid'];
|
||||
if ($ignore_score) {
|
||||
$scoresDataAttr = array('scores' => array(), 'maxScore' => 0);
|
||||
$scoresDataEvent = array('scores' => array(), 'maxScore' => 0);
|
||||
} else {
|
||||
$scoresDataAttr = $this->Event->Attribute->AttributeTag->getTagScores(0, $matrixTags);
|
||||
$scoresDataEvent = $this->Event->EventTag->getTagScores(0, $matrixTags, true);
|
||||
}
|
||||
$scoresData = array();
|
||||
foreach (array_keys($scoresDataAttr['scores'] + $scoresDataEvent['scores']) as $key) {
|
||||
$scoresData[$key] = (isset($scoresDataAttr['scores'][$key]) ? $scoresDataAttr['scores'][$key] : 0) + (isset($scoresDataEvent['scores'][$key]) ? $scoresDataEvent['scores'][$key] : 0);
|
||||
}
|
||||
$maxScore = max($scoresDataAttr['maxScore'], $scoresDataEvent['maxScore']);
|
||||
$scores = $scoresData;
|
||||
// FIXME: temporary fix: add the score of deprecated mitre galaxies to the new one (for the stats)
|
||||
if ($matrixData['galaxy']['id'] == $mitre_galaxy_id) {
|
||||
$mergedScore = array();
|
||||
foreach ($scoresData as $tag => $v) {
|
||||
$predicateValue = explode(':', $tag, 2)[1];
|
||||
$predicateValue = explode('=', $predicateValue, 2);
|
||||
$predicate = $predicateValue[0];
|
||||
$clusterValue = $predicateValue[1];
|
||||
$mappedTag = '';
|
||||
$mappingWithoutExternalId = array();
|
||||
if ($predicate == 'mitre-attack-pattern') {
|
||||
$mappedTag = $tag;
|
||||
$name = explode(" ", $tag);
|
||||
$name = join(" ", array_slice($name, 0, -2)); // remove " - external_id"
|
||||
$mappingWithoutExternalId[$name] = $tag;
|
||||
} else {
|
||||
$adjustedTagName = $this->Galaxy->GalaxyCluster->find('list', array(
|
||||
'group' => array('GalaxyCluster.id', 'GalaxyCluster.tag_name'),
|
||||
'conditions' => array('GalaxyCluster.tag_name LIKE' => 'misp-galaxy:mitre-attack-pattern=' . $name . '% T%'),
|
||||
'fields' => array('GalaxyCluster.tag_name')
|
||||
));
|
||||
$adjustedTagName = array_values($adjustedTagName)[0];
|
||||
$mappingWithoutExternalId[$name] = $adjustedTagName;
|
||||
$mappedTag = $mappingWithoutExternalId[$name];
|
||||
$name = explode(" ", $clusterValue);
|
||||
$name = join(" ", array_slice($name, 0, -2)); // remove " - external_id"
|
||||
if (isset($mappingWithoutExternalId[$name])) {
|
||||
$mappedTag = $mappingWithoutExternalId[$name];
|
||||
} else {
|
||||
$adjustedTagName = $this->Galaxy->GalaxyCluster->find('list', array(
|
||||
'group' => array('GalaxyCluster.id', 'GalaxyCluster.tag_name'),
|
||||
'conditions' => array('GalaxyCluster.tag_name LIKE' => 'misp-galaxy:mitre-attack-pattern=' . $name . '% T%'),
|
||||
'fields' => array('GalaxyCluster.tag_name')
|
||||
));
|
||||
$adjustedTagName = array_values($adjustedTagName)[0];
|
||||
$mappingWithoutExternalId[$name] = $adjustedTagName;
|
||||
$mappedTag = $mappingWithoutExternalId[$name];
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($mergedScore[$mappedTag])) {
|
||||
$mergedScore[$mappedTag] += $v;
|
||||
} else {
|
||||
$mergedScore[$mappedTag] = $v;
|
||||
}
|
||||
}
|
||||
$scores = $mergedScore;
|
||||
$maxScore = !empty($mergedScore) ? max(array_values($mergedScore)) : 0;
|
||||
}
|
||||
// end FIXME
|
||||
|
||||
if (isset($mergedScore[$mappedTag])) {
|
||||
$mergedScore[$mappedTag] += $v;
|
||||
} else {
|
||||
$mergedScore[$mappedTag] = $v;
|
||||
$this->Galaxy->sortMatrixByScore($tabs, $scores);
|
||||
if ($this->_isRest()) {
|
||||
$json = array('matrix' => $tabs, 'scores' => $scores, 'instance-uuid' => $instanceUUID);
|
||||
return $this->RestResponse->viewData($json, $this->response->type());
|
||||
} else {
|
||||
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);
|
||||
if ($matrixData['galaxy']['id'] == $mitre_galaxy_id) {
|
||||
$this->set('defaultTabName', "mitre-attack");
|
||||
$this->set('removeTrailling', 2);
|
||||
}
|
||||
|
||||
$this->set('galaxyName', $matrixData['galaxy']['name']);
|
||||
$this->set('galaxyId', $matrixData['galaxy']['id']);
|
||||
$matrixGalaxies = $this->Galaxy->getAllowedMatrixGalaxies();
|
||||
$this->set('matrixGalaxies', $matrixGalaxies);
|
||||
}
|
||||
$scores = $mergedScore;
|
||||
$maxScore = max(array_values($mergedScore));
|
||||
}
|
||||
// end FIXME
|
||||
|
||||
$this->Galaxy->sortMatrixByScore($tabs, $scores);
|
||||
if ($this->_isRest()) {
|
||||
$json = array('matrix' => $tabs, 'scores' => $scores, 'instance-uuid' => $instanceUUID);
|
||||
return $this->RestResponse->viewData($json, $this->response->type());
|
||||
} else {
|
||||
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);
|
||||
if ($matrixData['galaxy']['id'] == $mitre_galaxy_id) {
|
||||
$this->set('defaultTabName', "mitre-attack");
|
||||
$this->set('removeTrailling', 2);
|
||||
}
|
||||
|
||||
$this->set('galaxyName', $matrixData['galaxy']['name']);
|
||||
$this->set('galaxyId', $matrixData['galaxy']['id']);
|
||||
$matrixGalaxies = $this->Galaxy->getAllowedMatrixGalaxies();
|
||||
$this->set('matrixGalaxies', $matrixGalaxies);
|
||||
|
||||
$this->render('statistics_galaxymatrix');
|
||||
}
|
||||
$this->render('statistics_galaxymatrix');
|
||||
}
|
||||
|
||||
public function verifyGPG($full = false)
|
||||
|
|
|
@ -154,7 +154,7 @@ class EventTag extends AppModel
|
|||
}
|
||||
return $tags;
|
||||
}
|
||||
|
||||
|
||||
public function countForTag($tag_id, $user)
|
||||
{
|
||||
return $this->find('count', array(
|
||||
|
@ -163,34 +163,48 @@ class EventTag extends AppModel
|
|||
));
|
||||
}
|
||||
|
||||
public function getTagScores($eventId=0, $allowedTags=array())
|
||||
public function getTagScores($eventId=0, $allowedTags=array(), $propagateToAttribute=false)
|
||||
{
|
||||
// get score of galaxy
|
||||
$db = $this->getDataSource();
|
||||
$statementArray = array(
|
||||
'fields' => array('event_tag.tag_id as id', 'count(event_tag.tag_id) as value'),
|
||||
'table' => $db->fullTableName($this),
|
||||
'alias' => 'event_tag',
|
||||
'group' => 'tag_id'
|
||||
);
|
||||
if ($eventId != 0) {
|
||||
$statementArray['conditions'] = array('event_id' => $eventId);
|
||||
if ($propagateToAttribute) {
|
||||
$eventTagScores = $this->find('all', array(
|
||||
'recursive' => -1,
|
||||
'conditions' => array('Tag.id !=' => null),
|
||||
'contain' => array(
|
||||
'Event',
|
||||
'Tag' => array(
|
||||
'conditions' => array('name' => $allowedTags)
|
||||
)
|
||||
),
|
||||
'fields' => array('Tag.name', 'Event.attribute_count as value')
|
||||
));
|
||||
} else {
|
||||
// get score of galaxy
|
||||
$db = $this->getDataSource();
|
||||
$statementArray = array(
|
||||
'fields' => array('event_tag.tag_id as id', 'count(event_tag.tag_id) as value'),
|
||||
'table' => $db->fullTableName($this),
|
||||
'alias' => 'event_tag',
|
||||
'group' => 'tag_id'
|
||||
);
|
||||
if ($eventId != 0) {
|
||||
$statementArray['conditions'] = array('event_id' => $eventId);
|
||||
}
|
||||
// tag along with its occurence in the event
|
||||
$subQuery = $db->buildStatement(
|
||||
$statementArray,
|
||||
$this
|
||||
);
|
||||
$subQueryExpression = $db->expression($subQuery)->value;
|
||||
// get related galaxies
|
||||
$eventTagScores = $this->query("SELECT name, value FROM (" . $subQueryExpression . ") AS Event, Tag WHERE tags.id=score.id;");
|
||||
}
|
||||
// tag along with its occurence in the event
|
||||
$subQuery = $db->buildStatement(
|
||||
$statementArray,
|
||||
$this
|
||||
);
|
||||
$subQueryExpression = $db->expression($subQuery)->value;
|
||||
// get related galaxies
|
||||
$attributeTagScores = $this->query("SELECT name, value FROM (" . $subQueryExpression . ") AS score, tags WHERE tags.id=score.id;");
|
||||
|
||||
// arrange data
|
||||
$scores = array();
|
||||
$maxScore = 0;
|
||||
foreach ($attributeTagScores as $item) {
|
||||
$score = $item['score']['value'];
|
||||
$name = $item['tags']['name'];
|
||||
foreach ($eventTagScores as $item) {
|
||||
$score = $item['Event']['value'];
|
||||
$name = $item['Tag']['name'];
|
||||
if (in_array($name, $allowedTags)) {
|
||||
$maxScore = $score > $maxScore ? $score : $maxScore;
|
||||
$scores[$name] = $score;
|
||||
|
|
|
@ -5,19 +5,65 @@
|
|||
?>
|
||||
<p style="margin-bottom: 40px;"><?php echo sprintf(__('A heatmap showing the usage of %s.'), $galaxyName);?></p>
|
||||
|
||||
<select id="galaxyMatrixPicker" onchange="this.options[this.selectedIndex].value && (window.location = window.location.pathname.replace(/\/*galaxy_id:\d+/, '') + '/' + 'galaxy_id:' + this.options[this.selectedIndex].value);" >
|
||||
<?php foreach ($matrixGalaxies as $k => $galaxy): ?>
|
||||
<option value="<?php echo h($galaxy['Galaxy']['id']); ?>" <?php echo $galaxy['Galaxy']['id'] == $galaxyId ? 'selected' : ''; ?> ><?php echo h($galaxy['Galaxy']['name']); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<div style="height: 80px;">
|
||||
<div class="input select">
|
||||
<label>Galaxy</label>
|
||||
<select id="galaxyMatrixPicker" data-toggle="chosen">
|
||||
<?php foreach ($matrixGalaxies as $k => $galaxy): ?>
|
||||
<option value="<?php echo h($galaxy['Galaxy']['id']); ?>" <?php echo $galaxy['Galaxy']['id'] == $galaxyId ? 'selected' : ''; ?> ><?php echo h($galaxy['Galaxy']['name']); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="input select">
|
||||
<label>Organisation</label>
|
||||
<select id="organisationPicker" data-toggle="chosen">
|
||||
<?php foreach ($organisations as $k => $org): ?>
|
||||
<option value="<?php echo isset($org['Organisation']['id']) ? h($org['Organisation']['id']) : ''; ?>" <?php echo $org['Organisation']['id'] == $picked_organisation['Organisation']['id'] ? 'selected' : ''; ?> ><?php echo h($org['Organisation']['name']); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div style="display: inline-block;">
|
||||
<label>Dates</label>
|
||||
<input id="dateFrom" class="datepicker" placeholder="from" value="<?php echo isset($dateFrom) ? h($dateFrom) : ''; ?>"></input>
|
||||
<i class="fas fa-arrow-right"></i>
|
||||
<input id="dateTo" class="datepicker" placeholder="to" value="<?php echo isset($dateTo) ? h($dateTo) : ''; ?>"></input>
|
||||
</div>
|
||||
<button id="btnSubmit" class="btn btn-primary"><?php echo __('Submit') ?></button>
|
||||
</div>
|
||||
|
||||
<div id="attackmatrix_div" style="position: relative; border: solid 1px;" class="statistics_attack_matrix">
|
||||
<?php
|
||||
echo $this->element('view_galaxy_matrix');
|
||||
?>
|
||||
<div id="attackmatrix_div" style="position: relative; border: solid 1px;" class="statistics_attack_matrix">
|
||||
<?php
|
||||
echo $this->element('view_galaxy_matrix');
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('#btnSubmit').click(function() {
|
||||
var value = $('#galaxyMatrixPicker').val();
|
||||
var organisation = $('#organisationPicker').val();
|
||||
var dateFrom = $('#dateFrom').val();
|
||||
var dateTo = $('#dateTo').val();
|
||||
var eventTagsOnAttributes = $('#eventTagsOnAttributes').is(':checked');
|
||||
var url = '<?php echo $baseurl; ?>/users/statistics/galaxyMatrix/galaxy_id:' + value
|
||||
if (organisation) {
|
||||
url += '/' + 'organisation:' + organisation;
|
||||
}
|
||||
if (dateFrom) {
|
||||
url += '/' + 'dateFrom:' + dateFrom;
|
||||
}
|
||||
if (dateTo) {
|
||||
url += '/' + 'dateTo:' + dateTo;
|
||||
}
|
||||
$(this).text('').append('<i class="fas fa-spinner fa-spin"></i>')
|
||||
window.location = url;
|
||||
});
|
||||
|
||||
$('[data-toggle="chosen"]').chosen();
|
||||
|
||||
})
|
||||
</script>
|
||||
|
||||
<?php
|
||||
echo $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'globalActions', 'menuItem' => 'statistics'));
|
||||
|
|
Loading…
Reference in New Issue