mirror of https://github.com/MISP/MISP
new: [Correlations] added dedicated controller/model/views
parent
0a1c3f3458
commit
9e1b9f9b6e
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
App::uses('AppController', 'Controller');
|
||||
|
||||
/**
|
||||
* @property AuthKey $AuthKey
|
||||
*/
|
||||
class CorrelationsController extends AppController
|
||||
{
|
||||
public function top_correlations()
|
||||
{
|
||||
$options = [
|
||||
'filters' => ['value', 'quickFilter'],
|
||||
'quickFilters' => ['value']
|
||||
];
|
||||
$this->Correlation->virtualFields['count'] = 'COUNT(*)';
|
||||
$params = $this->IndexFilter->harvestParameters(empty($options['filters']) ? [] : $options['filters']);
|
||||
$query = [
|
||||
'fields' => ['value', 'count'],
|
||||
'group' => ['value'],
|
||||
'order' => 'count desc',
|
||||
'recursive' => -1
|
||||
];
|
||||
if (!empty($this->params['named']['limit'])) {
|
||||
$query['limit'] = $this->params['named']['limit'];
|
||||
}
|
||||
if (!empty($this->params['named']['page'])) {
|
||||
$query['page'] = $this->params['named']['page'];
|
||||
}
|
||||
$query = $this->CRUD->setFilters($params, $query);
|
||||
$query = $this->CRUD->setQuickFilters($params, $query, empty($options['quickFilters']) ? [] : $options['quickFilters']);
|
||||
if ($this->IndexFilter->isRest()) {
|
||||
$data = $this->Correlation->find('all', $query);
|
||||
return $this->RestResponse->viewData($data, 'json');
|
||||
} else {
|
||||
if (empty($query['limit'])) {
|
||||
$query['limit'] = 20;
|
||||
}
|
||||
if (empty($query['page'])) {
|
||||
$query['page'] = 1;
|
||||
}
|
||||
$this->paginate = $query;
|
||||
$data = $this->Correlation->find('all', $query);
|
||||
$this->set('data', $data);
|
||||
$this->set('title_for_layout', __('Top correlations index'));
|
||||
$this->set('menuData', [
|
||||
'menuList' => 'correlationExclusions',
|
||||
'menuItem' => 'top_correlations'
|
||||
]);
|
||||
}
|
||||
if ($this->IndexFilter->isRest()) {
|
||||
return $this->restResponsePayload;
|
||||
}
|
||||
$this->set('title_for_layout', __('Correlation Exclusions index'));
|
||||
$this->set('menuData', [
|
||||
'menuList' => 'correlationExclusions',
|
||||
'menuItem' => 'index'
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
<?php
|
||||
App::uses('AppModel', 'Model');
|
||||
App::uses('RandomTool', 'Tools');
|
||||
|
||||
class Correlation extends AppModel
|
||||
{
|
||||
|
||||
public function correlateValueRouter($value)
|
||||
{
|
||||
if (Configure::read('MISP.background_jobs')) {
|
||||
$job = ClassRegistry::init('Job');
|
||||
$job->create();
|
||||
$data = array(
|
||||
'worker' => 'default',
|
||||
'job_type' => 'correlateValue',
|
||||
'job_input' => $value,
|
||||
'status' => 0,
|
||||
'retries' => 0,
|
||||
'org_id' => 0,
|
||||
'org' => 0,
|
||||
'message' => 'Recorrelating',
|
||||
);
|
||||
$job->save($data);
|
||||
$jobId = $job->id;
|
||||
$process_id = CakeResque::enqueue(
|
||||
'email',
|
||||
'EventShell',
|
||||
['correlateValue', $value, $jobId],
|
||||
true
|
||||
);
|
||||
$job->saveField('process_id', $process_id);
|
||||
return true;
|
||||
} else {
|
||||
return $this->correlateValue($value, $jobId);
|
||||
}
|
||||
}
|
||||
|
||||
public function addAdvancedCorrelations($correlatingAttribute)
|
||||
{
|
||||
$a = $correlatingAttribute['Attribute'];
|
||||
if (Configure::read('MISP.enable_advanced_correlations')) {
|
||||
if (in_array($a['type'], array('ip-src', 'ip-dst', 'ip-src|port', 'ip-dst|port'))) {
|
||||
return $this->Attribute->cidrCorrelation($a);
|
||||
} else if ($a['type'] === 'ssdeep' && function_exists('ssdeep_fuzzy_compare')) {
|
||||
$this->FuzzyCorrelateSsdeep = ClassRegistry::init('FuzzyCorrelateSsdeep');
|
||||
$fuzzyIds = $this->FuzzyCorrelateSsdeep->query_ssdeep_chunks($a['value1'], $a['id']);
|
||||
if (!empty($fuzzyIds)) {
|
||||
$ssdeepIds = $this->find('list', array(
|
||||
'recursive' => -1,
|
||||
'conditions' => array(
|
||||
'Attribute.type' => 'ssdeep',
|
||||
'Attribute.id' => $fuzzyIds
|
||||
),
|
||||
'fields' => array('Attribute.id', 'Attribute.value1')
|
||||
));
|
||||
$threshold = Configure::read('MISP.ssdeep_correlation_threshold') ?: 40;
|
||||
$attributeIds = array();
|
||||
foreach ($ssdeepIds as $attributeId => $v) {
|
||||
$ssdeep_value = ssdeep_fuzzy_compare($a['value1'], $v);
|
||||
if ($ssdeep_value >= $threshold) {
|
||||
$attributeIds[] = $attributeId;
|
||||
}
|
||||
}
|
||||
return ['Attribute.id' => $attributeIds];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function correlateValue($value, $jobId)
|
||||
{
|
||||
$valueConditions = [
|
||||
'Attribute.value1' => $exclusion['CorrelationExclusion']['value'],
|
||||
'AND' => [
|
||||
'Attribute.value2' => $exclusion['CorrelationExclusion']['value'],
|
||||
'NOT' => ['Attribute.type' => $this->Attribute->primaryOnlyCorrelatingTypes]
|
||||
]
|
||||
];
|
||||
$conditions = [
|
||||
'OR' => $valueConditions,
|
||||
'NOT' => [
|
||||
'Attribute.type' => $this->Attribute->nonCorrelatingTypes,
|
||||
],
|
||||
'Attribute.disable_correlation' => 0,
|
||||
'Event.disable_correlation' => 0,
|
||||
'Attribute.deleted' => 0
|
||||
];
|
||||
$this->Attribute = ClassRegistry::init('Attribute');
|
||||
$correlatingAttributes[$k] = $this->Attribute->find('all', [
|
||||
'conditions' => $conditions,
|
||||
'recursive' => -1,
|
||||
'fields' => [
|
||||
'Attribute.event_id',
|
||||
'Attribute.id',
|
||||
'Attribute.distribution',
|
||||
'Attribute.sharing_group_id',
|
||||
'Attribute.value1',
|
||||
'Attribute.value2',
|
||||
],
|
||||
'contain' => [
|
||||
'Event' => [
|
||||
'fields' => ['Event.id', 'Event.date', 'Event.info', 'Event.org_id', 'Event.distribution', 'Event.sharing_group_id', 'Event.disable_correlation']
|
||||
]
|
||||
],
|
||||
'order' => [],
|
||||
]);
|
||||
$count = count($correlatingAttributes);
|
||||
$correlations = [];
|
||||
foreach ($correlatingAttributes as $k => $correlatingAttribute) {
|
||||
if (
|
||||
in_array($correlatingAttribute2['Attribute']['type'], $this->Attribute->nonCorrelatingTypes) ||
|
||||
!empty($correlatingAttribute['Event']['disable_correlation'])
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
foreach ($correlatingAttribute as $k2 => $correlatingAttribute2) {
|
||||
if (
|
||||
$correlatingAttribute['Attribute']['event_id'] === $correlatingAttribute2['Attribute']['event_id'] ||
|
||||
!empty($correlatingAttribute2['Event']['disable_correlation']) ||
|
||||
in_array($correlatingAttribute2['Attribute']['type'], $this->Attribute->nonCorrelatingTypes)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
$correlations[] = array(
|
||||
'value' => $value,
|
||||
'1_event_id' => $correlatingAttribute['Event']['id'],
|
||||
'1_attribute_id' => $correlatingAttribute['Attribute']['id'],
|
||||
'event_id' => $correlatingAttribute2['Attribute']['event_id'],
|
||||
'attribute_id' => $correlatingAttribute2['Attribute']['id'],
|
||||
'org_id' => $correlatingAttribute2['Event']['org_id'],
|
||||
'distribution' => $correlatingAttribute2['Event']['distribution'],
|
||||
'a_distribution' => $correlatingAttribute2['Attribute']['distribution'],
|
||||
'sharing_group_id' => $correlatingAttribute2['Event']['sharing_group_id'],
|
||||
'a_sharing_group_id' => $correlatingAttribute2['Attribute']['sharing_group_id'],
|
||||
'date' => $correlatingAttribute2['Event']['date'],
|
||||
'info' => $correlatingAttribute2['Event']['info']
|
||||
);
|
||||
}
|
||||
$correlations = $this->addAdvancedCorrelations($correlatingAttribute);
|
||||
}
|
||||
|
||||
if (Configure::read('MISP.deadlock_avoidance')) {
|
||||
return $this->saveMany($correlations, array(
|
||||
'atomic' => false,
|
||||
'callbacks' => false,
|
||||
'deep' => false,
|
||||
'validate' => false,
|
||||
'fieldList' => $fields,
|
||||
));
|
||||
} else {
|
||||
$db = $this->getDataSource();
|
||||
return $db->insertMulti('correlations', $fields, $correlations);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
echo sprintf('<div%s>', empty($ajax) ? ' class="index"' : '');
|
||||
echo $this->element('genericElements/IndexTable/index_table', [
|
||||
'data' => [
|
||||
'stupid_pagination' => 1,
|
||||
'data' => $data,
|
||||
'top_bar' => [
|
||||
'pull' => 'right',
|
||||
'children' => [
|
||||
[
|
||||
'type' => 'search',
|
||||
'button' => __('Filter'),
|
||||
'placeholder' => __('Enter value to search'),
|
||||
'searchKey' => 'quickFilter',
|
||||
]
|
||||
]
|
||||
],
|
||||
'fields' => [
|
||||
[
|
||||
'name' => 'Value',
|
||||
'sort' => 'Correlation.value',
|
||||
'data_path' => 'Correlation.value',
|
||||
'class' => 'short'
|
||||
],
|
||||
[
|
||||
'name' => 'Correlation count',
|
||||
'sort' => 'Correlation.count',
|
||||
'data_path' => 'Correlation.count'
|
||||
]
|
||||
],
|
||||
'title' => empty($ajax) ? $title_for_layout : false,
|
||||
'description' => empty($ajax) ? __('The values with the most correlation entries.') : false,
|
||||
'pull' => 'right',
|
||||
'actions' => [
|
||||
[
|
||||
'onclick' => sprintf(
|
||||
'openGenericModal(\'%s/correlation_exclusions/add/redirect:top_correlations/value:[onclick_params_data_path]\');',
|
||||
$baseurl
|
||||
),
|
||||
'onclick_params_data_path' => 'Correlation.value',
|
||||
'icon' => 'trash',
|
||||
'title' => __('Add exclusion entry for value'),
|
||||
]
|
||||
]
|
||||
]
|
||||
]);
|
||||
echo '</div>';
|
||||
if (empty($ajax)) {
|
||||
echo $this->element('/genericElements/SideMenu/side_menu', $menuData);
|
||||
}
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
var passedArgsArray = <?php echo $passedArgs; ?>;
|
||||
$(function() {
|
||||
$('#quickFilterButton').click(function() {
|
||||
runIndexQuickFilter();
|
||||
});
|
||||
});
|
||||
</script>
|
Loading…
Reference in New Issue