mirror of https://github.com/MISP/MISP
new: [attributes/enrich] endpoint added
- simply post a list of modules you wish to enrich the attribute by - url: /attributes/enrich/[attrribute_id|attribute_uuid] - post body in the format of `{"dns":1, "foo_bar_baz": 1}` listing all modules to executepull/9764/head
parent
ad71ddf11e
commit
148e20a24f
|
@ -501,6 +501,57 @@ class EventShell extends AppShell
|
|||
$log->createLogEntry($user, 'publish', 'GalaxyCluster', $clusterId, 'GalaxyCluster (' . $clusterId . '): published.', 'published () => (1)');
|
||||
}
|
||||
|
||||
public function attribute_enrichment()
|
||||
{
|
||||
if (empty($this->args[0]) || empty($this->args[1]) || empty($this->args[2])) {
|
||||
die('Usage: ' . $this->Server->command_line_functions['event_management_tasks']['data']['Run attribute enrichment'] . PHP_EOL);
|
||||
}
|
||||
|
||||
$userId = $this->args[0];
|
||||
$user = $this->getUser($userId);
|
||||
$id = $this->args[1];
|
||||
$modulesRaw = $this->args[2];
|
||||
try {
|
||||
$modules = json_decode($modulesRaw, true);
|
||||
} catch (Exception $e) {
|
||||
die('Invalid module JSON');
|
||||
}
|
||||
if (!empty($this->args[3])) {
|
||||
$jobId = $this->args[3];
|
||||
} else {
|
||||
$this->Job->create();
|
||||
$data = [
|
||||
'worker' => 'default',
|
||||
'job_type' => 'enrichment',
|
||||
'job_input' => 'Attribute: ' . $id . ' modules: ' . $modulesRaw,
|
||||
'status' => 0,
|
||||
'retries' => 0,
|
||||
'org' => $user['Organisation']['name'],
|
||||
'message' => 'Enriching event.',
|
||||
];
|
||||
$this->Job->save($data);
|
||||
$jobId = $this->Job->id;
|
||||
}
|
||||
$job = $this->Job->read(null, $jobId);
|
||||
$options = array(
|
||||
'user' => $user,
|
||||
'id' => $id,
|
||||
'modules' => $modules
|
||||
);
|
||||
$result = $this->Attribute->enrichment($options);
|
||||
$job['Job']['progress'] = 100;
|
||||
$job['Job']['date_modified'] = date("Y-m-d H:i:s");
|
||||
if ($result) {
|
||||
$job['Job']['message'] = 'Added ' . $result . ' attribute' . ($result > 1 ? 's.' : '.');
|
||||
} else {
|
||||
$job['Job']['message'] = 'Enrichment finished, but no attributes added.';
|
||||
}
|
||||
echo $job['Job']['message'] . PHP_EOL;
|
||||
$this->Job->save($job);
|
||||
$log = ClassRegistry::init('Log');
|
||||
$log->createLogEntry($user, 'enrichment', 'Attribute', $id, 'Attribute (' . $id . '): enriched.', 'enriched () => (1)');
|
||||
}
|
||||
|
||||
public function enrichment()
|
||||
{
|
||||
if (empty($this->args[0]) || empty($this->args[1]) || empty($this->args[2])) {
|
||||
|
@ -546,7 +597,7 @@ class EventShell extends AppShell
|
|||
} else {
|
||||
$job['Job']['message'] = 'Enrichment finished, but no attributes added.';
|
||||
}
|
||||
echo $job['Job']['message'] . PHP_EOL;
|
||||
echo $job['Job']['message'] . PHP_EOL;
|
||||
$this->Job->save($job);
|
||||
$log = ClassRegistry::init('Log');
|
||||
$log->createLogEntry($user, 'enrichment', 'Event', $eventId, 'Event (' . $eventId . '): enriched.', 'enriched () => (1)');
|
||||
|
|
|
@ -3050,4 +3050,29 @@ class AttributesController extends AppController
|
|||
$this->set('object', $attribute[0]['Attribute']);
|
||||
$this->set('seed', $seed);
|
||||
}
|
||||
|
||||
public function enrich($id)
|
||||
{
|
||||
$conditions = $this->__idToConditions($id);
|
||||
$attributes = $this->Attribute->fetchAttributes($this->Auth->user(), ['conditions' => $conditions, 'flatten' => true]);
|
||||
if (empty($attributes)) {
|
||||
throw new MethodNotAllowedException(__('Invalid Attribute'));
|
||||
}
|
||||
$attribute = $attributes[0];
|
||||
if (!$this->request->is('post') || !$this->_isRest()) {
|
||||
throw new MethodNotAllowedException(__('This endpoint allows for API POST requests only.'));
|
||||
}
|
||||
$modules = [];
|
||||
foreach ($this->request->data as $module => $enabled) {
|
||||
if ($enabled) {
|
||||
$modules[] = $module;
|
||||
}
|
||||
}
|
||||
$result = $this->Attribute->enrichmentRouter([
|
||||
'user' => $this->Auth->user(),
|
||||
'id' => $attribute['Attribute']['id'],
|
||||
'modules' => $modules
|
||||
]);
|
||||
return $this->RestResponse->successResponse(0, $result);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3877,4 +3877,136 @@ class Attribute extends AppModel
|
|||
'fields' => ['Attribute.id', 'Attribute.uuid']
|
||||
]);
|
||||
}
|
||||
|
||||
public function enrichmentRouter($options)
|
||||
{
|
||||
if (Configure::read('MISP.background_jobs')) {
|
||||
|
||||
/** @var Job $job */
|
||||
$job = ClassRegistry::init('Job');
|
||||
$jobId = $job->createJob(
|
||||
$options['user'],
|
||||
Job::WORKER_PRIO,
|
||||
'enrichment',
|
||||
'Attribute ID: ' . $options['id'] . ' modules: ' . json_encode($options['modules']),
|
||||
'Enriching attribute.'
|
||||
);
|
||||
|
||||
$this->getBackgroundJobsTool()->enqueue(
|
||||
BackgroundJobsTool::PRIO_QUEUE,
|
||||
BackgroundJobsTool::CMD_EVENT,
|
||||
[
|
||||
'attribute_enrichment',
|
||||
$options['user']['id'],
|
||||
$options['id'],
|
||||
json_encode($options['modules']),
|
||||
$jobId
|
||||
],
|
||||
true,
|
||||
$jobId
|
||||
);
|
||||
return __('Job queued (job ID: %s).', $jobId);
|
||||
} else {
|
||||
$result = $this->enrichment($options);
|
||||
return __('#' . $result . ' attributes have been created during the enrichment process.');
|
||||
}
|
||||
}
|
||||
|
||||
public function enrichment($params)
|
||||
{
|
||||
$option_fields = ['user', 'id', 'modules'];
|
||||
foreach ($option_fields as $option_field) {
|
||||
if (empty($params[$option_field])) {
|
||||
throw new MethodNotAllowedException(__('%s not set', $option_field));
|
||||
}
|
||||
}
|
||||
$attribute = $this->fetchAttributes($params['user'], [
|
||||
'conditions' => [
|
||||
'Attribute.id' => $params['id'],
|
||||
],
|
||||
'withAttachments' => 1,
|
||||
]);
|
||||
if (empty($attribute)) {
|
||||
throw new MethodNotAllowedException('Invalid attribute.');
|
||||
}
|
||||
$attribute = $attribute[0]['Attribute'];
|
||||
$this->Module = ClassRegistry::init('Module');
|
||||
$enabledModules = $this->Module->getEnabledModules($params['user']);
|
||||
if (empty($enabledModules) || is_string($enabledModules)) {
|
||||
return true;
|
||||
}
|
||||
$options = array();
|
||||
foreach ($enabledModules['modules'] as $k => $temp) {
|
||||
if (isset($temp['meta']['config'])) {
|
||||
$settings = array();
|
||||
foreach ($temp['meta']['config'] as $conf) {
|
||||
$settings[$conf] = Configure::read('Plugin.Enrichment_' . $temp['name'] . '_' . $conf);
|
||||
}
|
||||
$enabledModules['modules'][$k]['config'] = $settings;
|
||||
}
|
||||
}
|
||||
$attributes_added = 0;
|
||||
$initial_objects = array();
|
||||
$event_id = $attribute['event_id'];
|
||||
$event = $this->Event->find('first', ['conditions' => ['Event.id' => $event_id], 'recursive' => -1]);
|
||||
if (empty($event)) {
|
||||
throw new MethodNotAllowedException('Invalid event.');
|
||||
}
|
||||
$object_id = $attribute['object_id'];
|
||||
if ($object_id != '0' && empty($initial_objects[$object_id])) {
|
||||
$initial_objects[$object_id] = $this->Event->fetchInitialObject($event_id, $object_id);
|
||||
}
|
||||
foreach ($enabledModules['modules'] as $module) {
|
||||
if (in_array($module['name'], $params['modules'])) {
|
||||
if (in_array($attribute['type'], $module['mispattributes']['input'])) {
|
||||
$data = array('module' => $module['name'], 'event_id' => $event_id, 'attribute_uuid' => $attribute['uuid']);
|
||||
if (!empty($module['config'])) {
|
||||
$data['config'] = $module['config'];
|
||||
}
|
||||
if (!empty($module['mispattributes']['format']) && $module['mispattributes']['format'] == 'misp_standard') {
|
||||
$data['attribute'] = $attribute;
|
||||
} else {
|
||||
$data[$attribute['type']] = $attribute['value'];
|
||||
}
|
||||
if ($object_id != '0' && !empty($initial_objects[$object_id])) {
|
||||
$attribute['Object'] = $initial_objects[$object_id]['Object'];
|
||||
}
|
||||
$triggerData = $event;
|
||||
$triggerData['Attribute'] = [$attribute];
|
||||
$result = $this->Module->queryModuleServer($data, false, 'Enrichment', false, $triggerData);
|
||||
if ($result === false) {
|
||||
throw new MethodNotAllowedException(h($module['name']) . ' service not reachable.');
|
||||
} else if (!is_array($result)) {
|
||||
continue;
|
||||
}
|
||||
if (!empty($module['mispattributes']['format']) && $module['mispattributes']['format'] == 'misp_standard') {
|
||||
if ($object_id != '0' && !empty($initial_objects[$object_id])) {
|
||||
$result['initialObject'] = $initial_objects[$object_id];
|
||||
}
|
||||
$default_comment = $attribute['value'] . ': enriched via the ' . $module['name'] . ' module.';
|
||||
$attributes_added += $this->Event->processModuleResultsData($params['user'], $result['results'], $event_id, $default_comment, false, false, true);
|
||||
} else {
|
||||
$attributes = $this->Event->handleModuleResult($result, $event_id);
|
||||
foreach ($attributes as $a) {
|
||||
$this->create();
|
||||
$a['distribution'] = $attribute['distribution'];
|
||||
$a['sharing_group_id'] = $attribute['sharing_group_id'];
|
||||
$comment = 'Attribute #' . $attribute['id'] . ' enriched by ' . $module['name'] . '.';
|
||||
if (!empty($a['comment'])) {
|
||||
$a['comment'] .= PHP_EOL . $comment;
|
||||
} else {
|
||||
$a['comment'] = $comment;
|
||||
}
|
||||
$a['type'] = empty($a['default_type']) ? $a['types'][0] : $a['default_type'];
|
||||
$result = $this->save($a);
|
||||
if ($result) {
|
||||
$attributes_added++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $attributes_added;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue