Merge branch '2.4' into fix-i18n

pull/4541/head
Steve Clement 2019-05-01 18:03:28 +09:00 committed by GitHub
commit 4b77fe35f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 2218 additions and 62 deletions

4
.gitignore vendored
View File

@ -48,6 +48,10 @@ tools/mkdocs
/app/files/scripts/mixbox/
/app/files/scripts/*.pyc
/app/files/scripts/*.py~
/app/files/scripts/__pycache__
/app/files/scripts/yara/__pycache__
/app/files/scripts/yara/*.pyc
/app/files/scripts/yara/*.py~
/app/files/scripts/mispzmq/*
!/app/files/scripts/mispzmq/mispzmq.py
!/app/files/scripts/mispzmq/mispzmqtest.py

View File

@ -1084,6 +1084,9 @@ installCore () {
# install python-magic
$SUDO_WWW ${PATH_TO_MISP}/venv/bin/pip install python-magic
# install plyara
$SUDO_WWW ${PATH_TO_MISP}/venv/bin/pip install plyara
# Install Crypt_GPG and Console_CommandLine
sudo pear install ${PATH_TO_MISP}/INSTALL/dependencies/Console_CommandLine/package.xml
sudo pear install ${PATH_TO_MISP}/INSTALL/dependencies/Crypt_GPG/package.xml
@ -1350,18 +1353,16 @@ mispmodules () {
$SUDO_USER git clone https://github.com/MISP/misp-modules.git
cd misp-modules
# some misp-modules dependencies
sudo apt-get install libpq5 libjpeg-dev libfuzzy-dev -y
sudo apt-get install python3-dev python3-pip libpq5 libjpeg-dev tesseract-ocr libpoppler-cpp-dev imagemagick virtualenv libopencv-dev zbar-tools libzbar0 libzbar-dev libfuzzy-dev -y
# If you build an egg, the user you build it as need write permissions in the CWD
sudo chgrp $WWW_USER .
sudo chmod g+w .
$SUDO_WWW ${PATH_TO_MISP}/venv/bin/pip install -I -r REQUIREMENTS
sudo chgrp staff .
$SUDO_WWW ${PATH_TO_MISP}/venv/bin/pip install -I .
sudo apt install ruby-pygments.rb -y
sudo apt install ruby-pygments.rb libopencv-dev zbar-tools -y
sudo gem install asciidoctor-pdf --pre
# install additional dependencies for extended object generation and extraction
$SUDO_WWW ${PATH_TO_MISP}/venv/bin/pip install wand yara pathlib
# Start misp-modules as a service
sudo cp etc/systemd/system/misp-modules.service /etc/systemd/system/
sudo systemctl daemon-reload
@ -1583,11 +1584,17 @@ viper () {
$SUDO_USER sed -i "s/^misp_key\ =/misp_key\ =\ $AUTH_KEY/g" ${VIPER_HOME}/viper.conf
# Reset admin password to: admin/Password1234
echo "Fixing admin.db with default password"
VIPER_COUNT=0
while [ "$(sudo sqlite3 ${VIPER_HOME}/admin.db 'UPDATE auth_user SET password="pbkdf2_sha256$100000$iXgEJh8hz7Cf$vfdDAwLX8tko1t0M1TLTtGlxERkNnltUnMhbv56wK/U="'; echo $?)" -ne "0" ]; do
# FIXME This might lead to a race condition, the while loop is sub-par
sudo chown $MISP_USER:$MISP_USER ${VIPER_HOME}/admin.db
echo "Updating viper-web admin password, giving process time to start-up, sleeping 5, 4, 3,…"
sleep 6
VIPER_COUNT=$[$VIPER_COUNT+1]
if [[ "$VIPER_COUNT" > '10' ]]; then
echo "Something is wrong with updating viper. Continuing without db update."
break
fi
done
# Add viper-web to rc.local to be started on boot

View File

@ -1 +1 @@
931fae16c4462a0f8aab1e7428fe4c168480d33a INSTALL.sh
81a19d45ae7f499cfe34e35e2c3af93af58ecc9f INSTALL.sh

View File

@ -1 +1 @@
01c7ad59ac9105c2fb8e8cd86e3794d71df0091e9d6f2110a302891561b2af65 INSTALL.sh
cb9ab4292ed6dac59884e4cf51f4a83a5525e499dfbc76a637f1d49811382280 INSTALL.sh

View File

@ -1 +1 @@
0f0f2e4005833dd563ec0a71e2fcf520da798c081c6c5df3d8f5d5684c09d9eb194097a721c6c7a0687c820f0f0a8dcd INSTALL.sh
0a807abd32d6d8f894d1466a0854b449c1bc53fde9b0fbb43582d007f48749c103c4b607f385a75c548a3422b5a9fd57 INSTALL.sh

View File

@ -1 +1 @@
0ea0ea8f1de9a03a85bf475732446388a096aac0c54e8ebd7203f5119731521ef30ca99cc998637037a8f50587fa4c0bcd0f3994249898ed164729f08bdf3c7d INSTALL.sh
4fa55166257b1438e503323d28ffc35cab19a7503709bac699393870ff2225899204f7263b583512e15e9214b912457ab52ab9281a957720c611bbdbc3b58815 INSTALL.sh

View File

@ -46,7 +46,7 @@ class AppController extends Controller
public $helpers = array('Utility', 'OrgImg', 'FontAwesome');
private $__queryVersion = '66';
private $__queryVersion = '67';
public $pyMispVersion = '2.4.106';
public $phpmin = '7.0';
public $phprec = '7.2';

View File

@ -2488,6 +2488,13 @@ class EventsController extends AppController
$errors = array();
// only allow form submit CSRF protection
if ($this->request->is('post') || $this->request->is('put')) {
if (!$this->_isRest()) {
$publishable = $this->Event->checkIfPublishable($id);
if ($publishable !== true) {
$this->Flash->error(__('Could not publish event - no tag for required taxonomies missing: %s', implode(', ', $publishable)));
$this->redirect(array('action' => 'view', $id));
}
}
// send out the email
$emailResult = $this->Event->sendAlertEmailRouter($id, $this->Auth->user(), $this->Event->data['Event']['publish_timestamp']);
if (is_bool($emailResult) && $emailResult == true) {

View File

@ -23,7 +23,7 @@ class ObjectsController extends AppController
}
}
public function revise_object($action, $event_id, $template_id, $object_id = false)
public function revise_object($action, $event_id, $template_id, $object_id = false, $similar_objects_display_threshold=15)
{
if (!$this->request->is('post') && !$this->request->is('put')) {
throw new MethodNotAllowedException(__('This action can only be reached via POST requests'));
@ -83,12 +83,65 @@ class ObjectsController extends AppController
}
$this->set('sg', $sg);
}
$multiple_template_elements = Hash::extract($template['ObjectTemplateElement'], sprintf('{n}[multiple=true]'));
$multiple_attribute_allowed = array();
foreach ($multiple_template_elements as $k => $template_element) {
$relation_type = $template_element['object_relation'] . ':' . $template_element['type'];
$multiple_attribute_allowed[$relation_type] = true;
}
$this->set('multiple_attribute_allowed', $multiple_attribute_allowed);
// try to fetch similar objects
$cur_attrs = Hash::extract($this->request->data, 'Attribute.{n}.value');
$conditions = array(
'AND' => array(
$this->MispObject->buildConditions($this->Auth->user()),
'event_id' => $event_id,
'value' => $cur_attrs,
'object_id !=' => '0'
)
);
$similar_objects = $this->MispObject->Attribute->find('all', array(
'conditions' => $conditions,
'recursive' => -1,
'fields' => 'object_id, count(object_id) as similarity_amount',
'group' => 'object_id',
'order' => 'similarity_amount DESC'
));
$similar_object_ids = array();
$similar_object_similarity_amount = array();
foreach ($similar_objects as $obj) {
$similar_object_ids[] = $obj['Attribute']['object_id'];
$similar_object_similarity_amount[$obj['Attribute']['object_id']] = $obj[0]['similarity_amount'];
}
$this->set('distributionLevels', $this->MispObject->Attribute->distributionLevels);
$this->set('action', $action);
$this->set('template', $template);
$this->set('object_id', $object_id);
$this->set('event', $event);
$this->set('data', $this->request->data);
if (!empty($similar_object_ids)) {
$this->set('similar_objects_count', count($similar_object_ids));
$similar_object_ids = array_slice($similar_object_ids, 0, $similar_objects_display_threshold); // slice to honor the threshold
$similar_objects = $this->MispObject->fetchObjects($this->Auth->user(), array(
'conditions' => array(
'Object.id' => $similar_object_ids,
'Object.template_uuid' => $template['ObjectTemplate']['uuid']
)
));
foreach ($similar_objects as $key => $obj) {
$similar_objects[$key]['Object']['similarity_amount'] = $similar_object_similarity_amount[$obj['Object']['id']]; // sorting function cannot use external variables
}
usort($similar_objects, function ($a, $b) { // fetch Object returns object sorted by IDs, force the sort by the similarity amount
if ($a['Object']['similarity_amount'] == $b['Object']['similarity_amount']) {
return 0;
}
return ($a['Object']['similarity_amount'] > $b['Object']['similarity_amount']) ? -1 : 1;
});
$this->set('similar_objects', $similar_objects);
$this->set('similar_object_similarity_amount', $similar_object_similarity_amount);
$this->set('similar_objects_display_threshold', $similar_objects_display_threshold);
}
}
@ -176,6 +229,7 @@ class ObjectsController extends AppController
if (isset($this->request->data['request'])) {
$this->request->data = $this->request->data['request'];
}
if (isset($this->request->data['Object']['data'])) {
$this->request->data = json_decode($this->request->data['Object']['data'], true);
}
@ -302,7 +356,7 @@ class ObjectsController extends AppController
$this->set('element', $element);
}
public function edit($id)
public function edit($id, $update_template_available=false)
{
if (Validation::uuid($id)) {
$conditions = array('Object.uuid' => $id);
@ -354,6 +408,119 @@ class ObjectsController extends AppController
$this->Flash->error('Object cannot be edited, no valid template found.');
$this->redirect(array('controller' => 'events', 'action' => 'view', $object['Object']['event_id']));
}
$newer_template = $this->MispObject->ObjectTemplate->find('first', array(
'conditions' => array(
'ObjectTemplate.uuid' => $object['Object']['template_uuid'],
'ObjectTemplate.version >' => $object['Object']['template_version'],
),
'recursive' => -1,
'contain' => array(
'ObjectTemplateElement'
),
'order' => array('ObjectTemplate.version DESC')
));
if (!empty($newer_template)) {
$newer_template_version = $newer_template['ObjectTemplate']['version'];
// ignore IDs for comparison
$cur_template_temp = Hash::remove(Hash::remove($template['ObjectTemplateElement'], '{n}.id'), '{n}.object_template_id');
$newer_template_temp = Hash::remove(Hash::remove($newer_template['ObjectTemplateElement'], '{n}.id'), '{n}.object_template_id');
$template_difference = array();
// check how current template is included in the newer
foreach ($cur_template_temp as $cur_obj_rel) {
$flag_sim = false;
foreach ($newer_template_temp as $newer_obj_rel) {
$tmp = Hash::diff($cur_obj_rel, $newer_obj_rel);
if (count($tmp) == 0) {
$flag_sim = true;
break;
}
}
if (!$flag_sim) {
$template_difference[] = $cur_obj_rel;
}
}
$updateable_attribute = $object['Attribute'];
$not_updateable_attribute = array();
if (!empty($template_difference)) { // older template not completely embeded in newer
foreach ($template_difference as $temp_diff_element) {
foreach ($object['Attribute'] as $i => $attribute) {
if (
$attribute['object_relation'] == $temp_diff_element['object_relation']
&& $attribute['type'] == $temp_diff_element['type']
) { // This attribute cannot be merged automatically
$attribute['merge-possible'] = false;
$not_updateable_attribute[] = $attribute;
unset($updateable_attribute[$i]);
}
}
}
}
$this->set('updateable_attribute', $updateable_attribute);
$this->set('not_updateable_attribute', $not_updateable_attribute);
if ($update_template_available) { // template version bump requested
$template = $newer_template; // bump the template version
}
} else {
$newer_template_version = false;
}
if (isset($this->params['named']['revised_object'])) { // revised object data to be injected
$revised_object = json_decode(base64_decode($this->params['named']['revised_object']), true);
$revised_object_both = array('mergeable' => array(), 'notMergeable' => array());
// Loop through attributes to inject and perform the correct action
// (inject, duplicate, add warnings, ...) when applicable
foreach ($revised_object['Attribute'] as $attribute_to_inject) {
$flag_no_collision = true;
foreach ($object['Attribute'] as $attribute) {
if (
$attribute['object_relation'] == $attribute_to_inject['object_relation']
&& $attribute['type'] == $attribute_to_inject['type']
&& $attribute['value'] !== $attribute_to_inject['value']
) { // Collision on value
$multiple = !empty(Hash::extract($template['ObjectTemplateElement'], sprintf('{n}[object_relation=%s][type=%s][multiple=true]', $attribute['object_relation'], $attribute['type'])));
if ($multiple) { // if multiple is set, check if an entry exists already
$flag_entry_exists = false;
foreach ($object['Attribute'] as $attr) {
if (
$attr['object_relation'] == $attribute_to_inject['object_relation']
&& $attr['type'] == $attribute_to_inject['type']
&& $attr['value'] === $attribute_to_inject['value']
) {
$flag_entry_exists = true;
break;
}
}
if (!$flag_entry_exists) { // entry does no exists, can be duplicated
$attribute_to_inject['is_multiple'] = true;
$revised_object_both['mergeable'][] = $attribute_to_inject;
$object['Attribute'][] = $attribute_to_inject;
}
} else { // Collision on value, multiple not set => propose overwrite
$attribute_to_inject['current_value'] = $attribute['value'];
$attribute_to_inject['merge-possible'] = true; // the user can still swap value
$revised_object_both['notMergeable'][] = $attribute_to_inject;
}
$flag_no_collision = false;
} else if (
$attribute['object_relation'] == $attribute_to_inject['object_relation']
&& $attribute['type'] == $attribute_to_inject['type']
&& $attribute['value'] === $attribute_to_inject['value']
) { // all good, they are basically the same, do nothing
$revised_object_both['mergeable'][] = $attribute_to_inject;
$flag_no_collision = false;
}
}
if ($flag_no_collision) { // no collision, nor equalities => inject it straight away
$revised_object_both['mergeable'][] = $attribute_to_inject;
$object['Attribute'][] = $attribute_to_inject;
}
}
$this->set('revised_object', $revised_object_both);
}
$template = $this->MispObject->prepareTemplate($template, $object);
$enabledRows = false;
@ -426,6 +593,8 @@ class ObjectsController extends AppController
$this->set('template', $template);
$this->set('action', 'edit');
$this->set('object', $object);
$this->set('update_template_available', $update_template_available);
$this->set('newer_template_version', $newer_template_version);
$this->render('add');
}

View File

@ -878,6 +878,7 @@ class ServersController extends AppController
$mixboxVersion = array(0 => __('Incorrect mixbox version installed, found $current, expecting $expected'), 1 => __('OK'));
$maecVersion = array(0 => __('Incorrect maec version installed, found $current, expecting $expected'), 1 => __('OK'));
$pymispVersion = array(0 => __('Incorrect PyMISP version installed, found $current, expecting $expected'), 1 => __('OK'));
$plyaraVersion = array(0 => __('Incorrect plyara version installed, found $current, expecting $expected'), 1 => __('OK'));
$sessionErrors = array(0 => __('OK'), 1 => __('High'), 2 => __('Alternative setting used'), 3 => __('Test failed'));
$moduleErrors = array(0 => __('OK'), 1 => __('System not enabled'), 2 => __('No modules found'));
@ -999,6 +1000,8 @@ class ServersController extends AppController
// check if the STIX and Cybox libraries are working and the correct version using the test script stixtest.py
$stix = $this->Server->stixDiagnostics($diagnostic_errors, $stixVersion, $cyboxVersion, $mixboxVersion, $maecVersion, $stix2Version, $pymispVersion);
$yaraStatus = $this->Server->yaraDiagnostics($diagnostic_errors);
// if GnuPG is set up in the settings, try to encrypt a test message
$gpgStatus = $this->Server->gpgDiagnostics($diagnostic_errors);
@ -1018,7 +1021,7 @@ class ServersController extends AppController
$sessionStatus = $this->Server->sessionDiagnostics($diagnostic_errors, $sessionCount);
$this->set('sessionCount', $sessionCount);
$additionalViewVars = array('gpgStatus', 'sessionErrors', 'proxyStatus', 'sessionStatus', 'zmqStatus', 'stixVersion', 'cyboxVersion', 'mixboxVersion', 'maecVersion', 'stix2Version', 'pymispVersion', 'moduleStatus', 'gpgErrors', 'proxyErrors', 'zmqErrors', 'stixOperational', 'stix', 'moduleErrors', 'moduleTypes');
$additionalViewVars = array('gpgStatus', 'sessionErrors', 'proxyStatus', 'sessionStatus', 'zmqStatus', 'stixVersion', 'cyboxVersion', 'mixboxVersion', 'maecVersion', 'stix2Version', 'pymispVersion', 'moduleStatus', 'yaraStatus', 'gpgErrors', 'proxyErrors', 'zmqErrors', 'stixOperational', 'stix', 'moduleErrors', 'moduleTypes');
}
// check whether the files are writeable
$writeableDirs = $this->Server->writeableDirsDiagnostics($diagnostic_errors);

View File

@ -0,0 +1,141 @@
<?php
App::uses('JsonExport', 'Export');
class YaraExport
{
private $__script_path = APP . 'files/scripts/yara/yaraexport.py';
private $__tmp_dir = APP . 'tmp/yara/';
private $__end_of_cmd = ' 2>>' . APP . 'tmp/logs/yara_export.log';
private $__n_attributes = 0;
private $__MAX_n_attributes = 15000;
private $__yara_file_gen = null;
private $__yara_file_asis = null;
private $__curr_input_file = null;
private $__scope = false;
private $__curr_input_is_empty = true;
private $__JsonExporter = false;
private $__raw_mode = true;
public $non_restrictive_export = true;
private static function __count_atributes($data)
{
$attributes_count = count($data['Attribute']);
// foreach ($data['Object'] as $_object) {
// $attributes_count += count($_object['Attribute']);
// }
}
public function header($options = array())
{
if($this->__JsonExporter === false){
$this->__JsonExporter = new JsonExport();
}
$this->__initialize_yara_file();
$this->__initialize_misp_file($options);
if($options['returnFormat'] === 'yara-json'){
$this->__raw_mode = false;
}
return '';
}
private function __initialize_yara_file()
{
$yaraFileName = $this->generateRandomFileName();
$this->__yara_file_gen = new File($this->__tmp_dir . $yaraFileName . '_generated', true, 0644);
$this->__yara_file_asis = new File($this->__tmp_dir . $yaraFileName . '_asis', true, 0644);
$this->__yara_file_gen->close();
$this->__yara_file_asis->close();
}
private function __initialize_misp_file($options)
{
$mispFileName = $this->generateRandomFileName();
$this->__curr_input_file = new File($this->__tmp_dir . $mispFileName, true, 0644);
$header = $this->__JsonExporter->header($options);
$this->__curr_input_file->append($header);
$this->__curr_input_is_empty = true;
}
public function handler($data, $options = array())
{
// convert attribute(s) to json and write them to input queue file
if ($options['scope'] === 'Attribute') {
$attr_count = 1;
} else if($options['scope'] === 'Event') {
$attr_count = YaraExport::__count_atributes($data);
}
if(!empty($data)){
if(!$this->__curr_input_is_empty){
$this->separator(); // calling separator since returning '' will prevent it
}
$jsonData = $this->__JsonExporter->handler($data, $options);
$this->__curr_input_file->append($jsonData);
$this->__curr_input_is_empty = false;
}
$this->__n_attributes += $attr_count;
// if the file exceeds the max_attributes, process it, delete it and reset the counter
if ($this->__n_attributes >= $this->__MAX_n_attributes){
$this->__process_file($options);
$this->__initialize_misp_file($options);
}
return '';
}
public function footer($options = array())
{
if(!($this->__curr_input_is_empty)){
$this->__process_file($options);
}
$file = new File($this->__yara_file_gen->path);
$data_gen = $file->read(true, 'r');
$file->close();
$file->delete();
$file = new File($this->__yara_file_asis->path);
$data_asis = $file->read(true, 'r');
$file->close();
$file->delete();
if($this->__raw_mode){
$output =
'// ===================================== GENERATED ===================================='. PHP_EOL .
$data_gen . PHP_EOL .
'// ===================================== AS-IS ===================================='. PHP_EOL .
$data_asis;
}else{
$output = '{"generated":['. $data_gen .'],'.
'"as-is":[' . $data_asis . ']}';
}
return $output;
}
public function separator()
{
if(!$this->__curr_input_is_empty){
$this->__curr_input_file->append(',');
}
return '';
}
private function __process_file($options)
{
$footer = $this->__JsonExporter->footer($options);
$this->__curr_input_file->append($footer);
$pythonSrcipt = $this->__script_path;
$in = $this->__curr_input_file->path;
$out1 = $this->__yara_file_gen->path;
$out2 = $this->__yara_file_asis->path;
$logging = $this->__end_of_cmd;
$raw_flag = $this->__raw_mode ? '--raw' : '';
$result = shell_exec("python3 $pythonSrcipt --input $in --out-generated $out1 --out-asis $out2 $raw_flag $logging");
$this->__curr_input_file->close();
$this->__curr_input_file->delete();
$this->__n_attributes = 0;
}
public function generateRandomFileName()
{
return (new RandomTool())->random_str(false, 12);
}
}

View File

@ -388,6 +388,8 @@ class Attribute extends AppModel
'suricata' => array('txt', 'NidsSuricataExport', 'rules'),
'snort' => array('txt', 'NidsSnortExport', 'rules'),
'text' => array('txt', 'TextExport', 'txt'),
'yara' => array('txt', 'YaraExport', 'yara'),
'yara-json' => array('json', 'YaraExport', 'json'),
'rpz' => array('rpz', 'RPZExport', 'rpz'),
'csv' => array('csv', 'CsvExport', 'csv'),
'cache' => array('txt', 'CacheExport', 'cache')

View File

@ -58,7 +58,112 @@ class Event extends AppModel
private $__assetCache = array();
public $export_types = array();
public $export_types = array(
'json' => array(
'extension' => '.json',
'type' => 'JSON',
'scope' => 'Event',
'requiresPublished' => 0,
'params' => array('includeAttachments' => 1, 'ignore' => 1, 'returnFormat' => 'json'),
'description' => 'Click this to download all events and attributes that you have access to in MISP JSON format.',
),
'xml' => array(
'extension' => '.xml',
'type' => 'XML',
'scope' => 'Event',
'params' => array('includeAttachments' => 1, 'ignore' => 1, 'returnFormat' => 'xml'),
'requiresPublished' => 0,
'description' => 'Click this to download all events and attributes that you have access to in MISP XML format.',
),
'csv_sig' => array(
'extension' => '.csv',
'type' => 'CSV_Sig',
'scope' => 'Event',
'requiresPublished' => 1,
'params' => array('published' => 1, 'to_ids' => 1, 'returnFormat' => 'csv'),
'description' => 'Click this to download all attributes that are indicators and that you have access to <small>(except file attachments)</small> in CSV format.',
),
'csv_all' => array(
'extension' => '.csv',
'type' => 'CSV_All',
'scope' => 'Event',
'requiresPublished' => 0,
'params' => array('ignore' => 1, 'returnFormat' => 'csv'),
'description' => 'Click this to download all attributes that you have access to <small>(except file attachments)</small> in CSV format.',
),
'suricata' => array(
'extension' => '.rules',
'type' => 'Suricata',
'scope' => 'Attribute',
'requiresPublished' => 1,
'params' => array('returnFormat' => 'suricata'),
'description' => 'Click this to download all network related attributes that you have access to under the Suricata rule format. Only published events and attributes marked as IDS Signature are exported. Administration is able to maintain a whitelist containing host, domain name and IP numbers to exclude from the NIDS export.',
),
'snort' => array(
'extension' => '.rules',
'type' => 'Snort',
'scope' => 'Attribute',
'requiresPublished' => 1,
'params' => array('returnFormat' => 'snort'),
'description' => 'Click this to download all network related attributes that you have access to under the Snort rule format. Only published events and attributes marked as IDS Signature are exported. Administration is able to maintain a whitelist containing host, domain name and IP numbers to exclude from the NIDS export.',
),
'bro' => array(
'extension' => '.intel',
'type' => 'Bro',
'scope' => 'Attribute',
'requiresPublished' => 1,
'params' => array('returnFormat' => 'bro'),
'description' => 'Click this to download all network related attributes that you have access to under the Bro rule format. Only published events and attributes marked as IDS Signature are exported. Administration is able to maintain a whitelist containing host, domain name and IP numbers to exclude from the NIDS export.',
),
'stix' => array(
'extension' => '.xml',
'type' => 'STIX',
'scope' => 'Event',
'requiresPublished' => 1,
'params' => array('returnFormat' => 'stix', 'includeAttachments' => 1),
'description' => 'Click this to download an a STIX document containing the STIX version of all events and attributes that you have access to.'
),
'stix2' => array(
'extension' => '.json',
'type' => 'STIX2',
'scope' => 'Event',
'requiresPublished' => 1,
'params' => array('returnFormat' => 'stix2', 'includeAttachments' => 1),
'description' => 'Click this to download an a STIX2 document containing the STIX2 version of all events and attributes that you have access to.'
),
'rpz' => array(
'extension' => '.txt',
'type' => 'RPZ',
'scope' => 'Attribute',
'requiresPublished' => 1,
'params' => array('returnFormat' => 'rpz'),
'description' => 'Click this to download an RPZ Zone file generated from all ip-src/ip-dst, hostname, domain attributes. This can be useful for DNS level firewalling. Only published events and attributes marked as IDS Signature are exported.'
),
'text' => array(
'extension' => '.txt',
'type' => 'TEXT',
'scope' => 'Attribute',
'requiresPublished' => 1,
'params' => array('returnFormat' => 'text', 'includeAttachments' => 1),
'description' => 'Click on one of the buttons below to download all the attributes with the matching type. This list can be used to feed forensic software when searching for susipicious files. Only published events and attributes marked as IDS Signature are exported.'
),
'yara' => array(
'extension' => '.yara',
'type' => 'Yara',
'scope' => 'Event',
'requiresPublished' => 1,
'params' => array('returnFormat' => 'yara'),
'description' => 'Click this to download Yara rules generated from all relevant attributes.'
),
'yara-json' => array(
'extension' => '.json',
'type' => 'Yara',
'scope' => 'Event',
'requiresPublished' => 1,
'params' => array('returnFormat' => 'yara-json'),
'description' => 'Click this to download Yara rules generated from all relevant attributes. Rules are returned in a JSON format with information about origin (generated or parsed) and validity.'
),
);
public $validFormats = array(
'json' => array('json', 'JsonExport', 'json'),

View File

@ -4046,6 +4046,13 @@ class Server extends AppModel
return $readableFiles;
}
public function yaraDiagnostics(&$diagnostic_errors)
{
$scriptResult = shell_exec($this->getPythonVersion() . ' ' . APP . 'files' . DS . 'scripts' . DS . 'yaratest.py');
$scriptResult = json_decode($scriptResult, true);
return array('operational' => $scriptResult['success'], 'plyara' => $scriptResult['plyara']);
}
public function stixDiagnostics(&$diagnostic_errors, &$stixVersion, &$cyboxVersion, &$mixboxVersion, &$maecVersion, &$stix2Version, &$pymispVersion)
{
$result = array();
@ -4640,7 +4647,11 @@ class Server extends AppModel
}
if ($status['isReadable'] && !empty($status['remoteTimestamp']) && !empty($status['currentTimestamp'])) {
$status['timeDiff'] = (DateTime::createFromFormat('U', $status['remoteTimestamp']))->diff(DateTime::createFromFormat('U', $status['currentTimestamp']));
$date1 = new DateTime();
$date1->setTimestamp($status['remoteTimestamp']);
$date2 = new DateTime();
$date2->setTimestamp($status['currentTimestamp']);
$status['timeDiff'] = $date1->diff($date2);
} else {
$status['upToDate'] = 'error';
}

View File

@ -7,7 +7,7 @@
?>
</span>
<?php
if ($isAclAdd):
if ($isAclSighting):
?>
<span class="icon-thumbs-up useCursorPointer" title="<?php echo __('Add sighting');?>" role="button" tabindex="0" aria-label="<?php echo __('Add sighting');?>" onmouseover="flexibleAddSighting(this, '0', '<?php echo h($object['id']); ?>', '<?php echo h($object['event_id']);?>', '<?php echo h($object['value']);?>', '<?php echo h($page); ?>', 'top');" onclick="addSighting('0', '<?php echo h($object['id']); ?>', '<?php echo h($object['event_id']);?>', '<?php echo h($page); ?>');">&nbsp;</span>
<span class="icon-thumbs-down useCursorPointer" title="<?php echo __('Mark as false-positive');?>" role="button" tabindex="0" aria-label="<?php echo __('Mark as false-positive');?>" onmouseover="flexibleAddSighting(this, '1', '<?php echo h($object['id']); ?>', '<?php echo h($object['event_id']);?>', '<?php echo h($object['value']);?>', '<?php echo h($page); ?>', 'bottom');" onclick="addSighting('1', '<?php echo h($object['id']); ?>', '<?php echo h($object['event_id']);?>', '<?php echo h($page); ?>');">&nbsp;</span>

View File

@ -0,0 +1,220 @@
<?php
/*
View that can be used to concisely display an object and potentially highlight differences/similarities with another one
Required Args:
- object => The object to be drawed
Optional Args:
- template => The template used to compare the object with
- attribute_fields => The fields to be displayed.
Default: [`object_relation`, `category`, `type`, `value`]
- meta_fields => The fields to be displayed from the object meta.
Default: [`id`, `name`, `description`, `distribution`, `template_version`]
- similar_object_similarity_amount => The amount of attributes both contained in `object` and the object to compare to
- simple_flattened_attribute => array containing the aggregate of multiple fields used for the comparison. Has the format:
array(
'object_relation1.type1.val1' => attribute_id1,
'object_relation2.type2.val2' => attribute_id2
)
- simple_flattened_attribute_noval => array containing the aggregate of multiple fields used for the comparison without the value. Has the format:
array(
'object_relation1.type1' => attribute_id1,
'object_relation2.type2' => attribute_id2
)
- merge_button_functionname => If provided, draw a merge button and link the onClick event with the function name
- target_comparison_object => Will be used to compute `simple_flattened_attribute` and `simple_flattened_attribute_noval` only if they are not provided.
*/
if (!isset($attribute_fields)) {
$attribute_fields = array('object_relation', 'category', 'type', 'value');
}
if (!isset($meta_fields)) {
$meta_fields = array('id', 'name', 'description', 'distribution', 'template_version');
}
$flag_comparison_enabled = true;
if (!isset($simple_flattened_attribute_noval) || !isset($simple_flattened_attribute)) {
if (!isset($simple_flattened_attribute_noval) && !isset($simple_flattened_attribute) && isset($target_comparison_object)) {
// compute these fields from the provided target object
$simple_flattened_attribute_noval = array();
$simple_flattened_attribute = array();
foreach ($target_comparison_object['Attribute'] as $id => $attribute) {
$cur_flat = h($attribute['object_relation']) . '.' . h($attribute['type']) . '.' .h($attribute['value']);
$cur_flat_noval = h($attribute['object_relation']) . '.' . h($attribute['type']);
$simple_flattened_attribute[$cur_flat] = $id;
$simple_flattened_attribute_noval[$cur_flat_noval] = $id;
}
} else {
$flag_comparison_enabled = false;
}
}
?>
<?php
if (!isset($template) || !isset($object['Object'])) {
$temp_comparison = 'equal';
} else if ($object['Object']['template_version'] < $template['ObjectTemplate']['version']) {
$temp_comparison = 'below';
} else if ($object['Object']['template_version'] > $template['ObjectTemplate']['version']) {
$temp_comparison = 'above';
} else {
$temp_comparison = 'equal';
}
?>
<div style="border: 1px solid #3465a4 ; border-radius: 5px; margin-top: 15px; display: inline-block; vertical-align: top; float: unset; overflow-x: auto; <?php echo $temp_comparison == 'above' ? 'filter: grayscale(60%);' : ''; ?>" class="span5 similarObjectPanel">
<?php
if ($temp_comparison == 'below') {
$btn_style = 'btn-warning';
$temp_text = __('Update template and merge');
} else if ($temp_comparison == 'above') {
$btn_style = 'btn-danger';
$temp_text = __('Can\'t merge due to template version');
} else {
$temp_text = __('Review merge');
$btn_style = 'btn-success';
}
?>
<?php if (isset($object['Object'])): ?>
<div class="blueElement" style="padding: 4px 5px;">
<div style="text-align: center; position: relative;">
<?php if (isset($merge_button_functionname)): ?>
<input type="button" class="btn <?php echo $btn_style; ?>" onclick="<?php echo h($merge_button_functionname); ?>(this)" data-objectid="<?php echo h($object['Object']['id']) ?>" data-updatetemplate="<?php echo $temp_comparison == 'below' ? 'true' : 'false'; ?>" value="<?php echo $temp_text; ?>" <?php echo $temp_comparison == 'above' ? 'disabled' : ''; ?>></input>
<?php endif; ?>
<?php if (isset($similar_object_similarity_amount[$object['Object']['id']])): ?>
<span class="badge badge-inverse" style="position: absolute; right: 0;" title="<?php echo __('Similarity amount') ?>">
<?php echo number_format(intval($similar_object_similarity_amount[$object['Object']['id']]) / count($data['Attribute']), 2)*100 . '%'; ?>
</span>
<?php endif; ?>
</div>
<?php foreach ($meta_fields as $field): ?>
<?php if (isset($object['Object'][$field])): ?>
<?php switch ($field):
case 'id': ?>
<div>
<span class="bold"><?php echo h(__(Inflector::humanize($field))) . ':'; ?></span>
<a href="<?php echo $baseurl . '/objects/edit/' . h($object['Object'][$field]); ?>" style="color: white;"><?php echo h($object['Object'][$field]); ?></a>
</div>
<?php break; ?>
<?php case 'distribution': ?>
<div>
<span class="bold"><?php echo h(__(Inflector::humanize($field))) . ':'; ?></span>
<span>
<?php
echo h($distributionLevels[$object['Object'][$field]])
?>
</span>
</div>
<?php break; ?>
<?php case 'template_version': ?>
<?php
$temp_style = '';
if ($temp_comparison == 'below') {
$temp_style .= 'background-color: #fcf8e3; color: black; padding: 2px;';
} else if ($temp_comparison == 'above') {
$temp_style .= 'background-color: #bd362f; color: white; padding: 2px;';
}
?>
<div style="<?php echo $temp_style ?> border-radius: 3px;" data-templatecomparison="<?php echo $temp_comparison; ?>" title="<?php echo __('The template version used by this object.'); ?>">
<span class="bold"><?php echo h(__(Inflector::humanize($field))) . ':'; ?></span>
<span ><?php echo h($object['Object'][$field]); ?></span>
</div>
<?php break; ?>
<?php default: ?>
<div>
<span class="bold"><?php echo h(__(Inflector::humanize($field))) . ':'; ?></span>
<span><?php echo h($object['Object'][$field]); ?></span>
</div>
<?php break; ?>
<?php endswitch; ?>
<?php endif; ?>
<?php endforeach; ?>
</div>
<?php endif; ?>
<?php $flattened_ids_in_similar_object = array(); ?>
<table class="table table-striped table-condensed" style="margin-bottom: 0px;">
<tbody>
<?php foreach ($object['Attribute'] as $attribute): ?>
<?php
$to_highlight = '';
$classname = '';
$title = '';
if ($flag_comparison_enabled) { // Comparison enabled
$simple_flattened_similar_attribute = h($attribute['object_relation']) . '.' . h($attribute['type']) . '.' .h($attribute['value']);
$simple_flattened_similar_attribute_noval = h($attribute['object_relation']) . '.' . h($attribute['type']);
$flattened_ids_in_similar_object[$simple_flattened_similar_attribute_noval] = $attribute['id'];
if (
isset($simple_flattened_attribute_noval[$simple_flattened_similar_attribute_noval])
&& !isset($simple_flattened_attribute[$simple_flattened_similar_attribute])
&& isset($multiple_attribute_allowed[$attribute['object_relation'] . ':' . $attribute['type']])
) { // Multiple allowed
$classname = 'warning';
$title = __('This attribute is also contained in the revised object. However, as multiple instantiations are allowed by the template, both attributes will be kept.');
$to_highlight = $simple_flattened_similar_attribute_noval;
} else if (
isset($simple_flattened_attribute_noval[$simple_flattened_similar_attribute_noval])
&& !isset($simple_flattened_attribute[$simple_flattened_similar_attribute])
) { // Not overridable attribute
$classname = 'error';
$title = __('This attribute is conflicting with the one in the revised object. Manual merge will be required.');
$to_highlight = $simple_flattened_similar_attribute_noval;
} else if (
!isset($simple_flattened_attribute[$simple_flattened_similar_attribute])
) { // Attribute not present in the revised object
$classname = 'info';
$title = __('This attribute is only contained in this matching object. It will remain untouched.');
} else { // Attributes are basically the same
$classname = '';
$title = __('This attribute has the same value as the one in the revised object.');
}
}
?>
<tr class="<?php echo $classname ?>" data-tohighlight="<?php echo h($to_highlight); ?>" title="<?php echo $title; ?>">
<?php foreach ($attribute_fields as $field): ?>
<?php if (isset($attribute[$field])): ?>
<?php if ($field == 'object_relation'): ?>
<td style="white-space: nowrap;"><?php echo h($attribute[$field]); ?></td>
<?php else: ?>
<td><?php echo h($attribute[$field]); ?></td>
<?php endif; ?>
<?php else: ?>
<td></td>
<?php endif; ?>
<?php endforeach; ?>
</tr>
<?php endforeach; ?>
<?php
if (isset($simple_flattened_attribute_noval)) {
$attribute_ids_to_inject = array_values(array_diff_key($simple_flattened_attribute_noval, $flattened_ids_in_similar_object));
} else {
$simple_flattened_attribute_noval = array();
}
?>
<?php if (!empty($attribute_ids_to_inject)): ?>
<?php foreach ($attribute_ids_to_inject as $i => $attribute_id): ?>
<?php $attribute = $data['Attribute'][$attribute_id]; ?>
<tr class="success" title="<?php echo __('This attribute will be added to this similar object during the merge.'); ?>" style="<?php echo $i == 0 ? 'border-top: 2px dashed #3465a4' : ''; ?>">
<?php foreach ($attribute_fields as $field): ?>
<?php if (isset($attribute[$field])): ?>
<?php if ($field == 'object_relation'): ?>
<td style="white-space: nowrap;"><?php echo h($attribute[$field]); ?></td>
<?php else: ?>
<td><?php echo h($attribute[$field]); ?></td>
<?php endif; ?>
<?php else: ?>
<td></td>
<?php endif; ?>
<?php endforeach; ?>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>

View File

@ -253,6 +253,20 @@
}
?>
</div>
<h3><?php echo __('Yara');?></h3>
<p><?php echo __('This tool tests whether plyara, the library used by the yara export tool is installed or not.');?></p>
<div style="background-color:#f7f7f9;width:400px;">
<?php
$colour = 'green';
$message = __('OK');
if ($yaraStatus['operational'] == 0) {
$colour = 'red';
$message = __('Invalid plyara version / plyara not installed. Please run pip3 install plyara');
}
echo __('plyara library installed') . '…<span style="color:' . $colour . ';">' . $message . '</span>';
?>
</div>
<h3><?php echo __('GnuPG');?></h3>
<p><?php echo __('This tool tests whether your GnuPG is set up correctly or not.');?></p>
<div style="background-color:#f7f7f9;width:400px;">

View File

@ -1,6 +1,7 @@
<?php $update_template_available = isset($update_template_available) ? $update_template_available : false; ?>
<div class="<?php if (!isset($ajax) || !$ajax) echo 'form';?>">
<?php
$url = ($action == 'add') ? '/objects/revise_object/add/' . $event['Event']['id'] . '/' . $template['ObjectTemplate']['id'] : '/objects/revise_object/edit/' . $event['Event']['id'] . '/' . $template['ObjectTemplate']['id'] . '/' . $object['Object']['id'];
$url = ($action == 'add') ? '/objects/revise_object/add/' . $event['Event']['id'] . '/' . $template['ObjectTemplate']['id'] : '/objects/revise_object/edit/' . $event['Event']['id'] . '/' . $template['ObjectTemplate']['id'] . '/' . h($object['Object']['id']);
echo $this->Form->create('Object', array('id', 'url' => $url, 'enctype' => 'multipart/form-data'));
?>
<h3><?php echo ucfirst($action) . ' ' . Inflector::humanize(h($template['ObjectTemplate']['name'])) . __(' Object'); ?></h3>
@ -10,7 +11,12 @@
<dd>
<?php
echo Inflector::humanize(h($template['ObjectTemplate']['name'])) . ' v' . h($template['ObjectTemplate']['version']);
?>
if ($action == 'edit' && !$update_template_available && $newer_template_version !== false): ?>
<a class="btn btn-mini btn-primary useCursorPointer" title="<?php echo __('Update the template of this object to the newer version: ') . h($newer_template_version) ?>" href="<?php echo $baseurl . '/objects/edit/' . h($object['Object']['id']) . '/1'; ?>">
<span class="fa fa-arrow-circle-up"></span>
<?php echo __('Update template') ?>
</a>
<?php endif; ?>
&nbsp;
</dd>
<dt><?php echo __('Description');?></dt>
@ -87,7 +93,7 @@
<?php
endif;
?>
<table class="table table-striped table-condensed">
<table id="editTable" class="table table-striped table-condensed">
<tr>
<th><?php echo __('Save');?></th>
<th><?php echo __('Name :: type');?></th>
@ -161,10 +167,147 @@
<p style="color:red;font-weight:bold;display:none;" id="warning-message"><?php echo __('Warning: You are about to share data that is of a classified nature. Make sure that you are authorised to share this.');?></p>
<?php
echo $this->Form->button('Submit', array('class' => 'btn btn-primary'));
?>
<a href="#" style="margin-left:10px;" class="btn btn-inverse" onclick="window.history.back();"><?php echo __('Back to review');?></a>
<?php
endif;
echo $this->Form->end();
?>
</div>
<?php if ($update_template_available || isset($revised_object)): //add control panel (same as distribution network) and fill with data ?>
<div class="fixedRightPanel" style="width: unset; height:unset; background-color: #ffffff">
<?php if ($update_template_available): ?>
<div class="fixedRightPanelHeader useCursorPointer" style="box-shadow: 0px 0px 6px #B2B2B2;margin-bottom: 2px;width: 100%;overflow: hidden; padding: 5px;">
<i class="fas fa-chevron-circle-down"></i>
<span style="margin-left: 5px; display: inline-block; font-size: large;"><?php echo __('Pre-update object\'s template'); ?></span>
</div>
<div class="row" style="max-height: 800px; max-width: 800px; overflow: auto; padding: 15px;">
<div style="border: 1px solid #3465a4 ; border-radius: 5px; overflow: hidden;" class="span5">
<div class="blueElement" style="padding: 4px 5px;">
<div>
<span class="bold"><?php echo __('ID') . ':'; ?></span>
<a href="<?php echo $baseurl . '/objects/edit/' . h($object['Object']['id']); ?>" style="color: white;"><?php echo h($object['Object']['id']); ?></a>
</div>
<div>
<span class="bold"><?php echo __('Name') . ':'; ?></span>
<span><?php echo h($object['Object']['name']); ?></span>
</div>
<div>
<span class="bold"><?php echo __('Description') . ':'; ?></span>
<span><?php echo h($object['Object']['description']); ?></span><br>
</div>
<div>
<span class="bold"><?php echo __('Distribution') . ':'; ?></span>
<span><?php echo h($object['Object']['distribution']); ?></span>
</div>
<div style="background-color: #fcf8e3; color: black; padding: 2px; border-radius: 3px;">
<span class="bold"><?php echo __('Template version') . ':'; ?></span>
<span><?php echo h($object['Object']['template_version']); ?></span>
</div>
</div>
<table class="table table-striped table-condensed" style="margin-bottom: 0px;">
<tbody>
<?php foreach ($not_updateable_attribute as $attribute): ?>
<tr class="error" title="<?php echo __('Can not be merged automatically'); ?>">
<td style="white-space: nowrap;">
<?php if ($attribute['merge-possible']): ?>
<i class="fas fa-sign-in-alt fa-flip-horizontal useCursorPointer" style="margin-right: 3px;"></i>
<?php else: ?>
<i class="fas fa-times useCursorPointer" style="margin-right: 3px;" title="<?php echo __('This attribute type is missing from the new template. It will be lost if not taken care of right now.'); ?>"></i>
<?php endif; ?>
<?php echo h($attribute['object_relation']); ?>
</td>
<td><?php echo h($attribute['category']); ?></td>
<td><?php echo h($attribute['type']); ?></td>
<td><?php echo h($attribute['value']); ?></td>
</tr>
<?php if (!$attribute['merge-possible']): ?>
<?php
$validOptions = Hash::extract($template['ObjectTemplateElement'], sprintf('{n}[type=%s]', $attribute['type']));
?>
<tr>
<td class="apply_css_arrow" colspan="4">
<?php if (!empty($validOptions)): ?>
<select style="width: calc(100% - 100px); margin: 0px;" data-type="<?php echo h($attribute['type']); ?>" data-attrval="<?php echo h($attribute['value']); ?>">
<?php foreach ($validOptions as $option): ?>
<option value="<?php echo h($option['object_relation']); ?>" data-type="<?php echo h($option['type']); ?>"><?php echo h($option['object_relation']); ?></option>
<?php endforeach; ?>
</select>
<span class="btn btn-inverse useCursorPointer" onclick="insertObjectRelation(this)">
<i class="fas useCursorPointer fa-sign-in-alt fa-flip-horizontal"></i>
<?php echo __('Insert'); ?>
</span>
<?php else: ?>
<?php echo __('No valid type. This attribute will be lost.'); ?>
<?php endif; ?>
</td>
</tr>
<?php endif; ?>
<?php endforeach; ?>
<?php foreach ($updateable_attribute as $attribute): ?>
<tr class="success" title="<?php echo __('This attribute can be merged automatically. Injection in the template done.'); ; ?>">
<td style="white-space: nowrap;"><?php echo h($attribute['object_relation']); ?></td>
<td><?php echo h($attribute['category']); ?></td>
<td><?php echo h($attribute['type']); ?></td>
<td><?php echo h($attribute['value']); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<?php endif; ?>
<?php if (isset($revised_object)): ?>
<div class="fixedRightPanelHeader useCursorPointer" style="box-shadow: 0px 0px 6px #B2B2B2;margin-bottom: 2px;width: 100%;overflow: hidden; margin-top: 10px; padding: 5px;">
<i class="fas fa-chevron-circle-down"></i>
<span style="margin-left: 5px; display: inline-block; font-size: large;"><?php echo __('Attributes to merge'); ?></span>
<span style="margin-left: 25px; display: block;" class="apply_css_arrow"><?php echo __('Contextual information and actions'); ?></span>
</div>
<div class="row" style="max-height: 800px; max-width: 800px; overflow: auto; padding: 15px;">
<div style="border: 1px solid #3465a4 ; border-radius: 5px; overflow: hidden;" class="span5">
<table class="table table-striped table-condensed" style="margin-bottom: 0px;">
<tbody>
<?php foreach ($revised_object['notMergeable'] as $attribute): ?>
<tr class="error" title="<?php echo __('Can not be merged automatically'); ?>">
<td style="white-space: nowrap;">
<?php if ($attribute['merge-possible']): ?>
<i class="fas fa-sign-in-alt fa-flip-horizontal useCursorPointer" style="margin-right: 3px;" title="<?php echo __('Overwrite the current attribute value with this one'); ?>" data-valueold="<?php echo h($attribute['current_value']); ?>" data-valuerevised="<?php echo h($attribute['value']); ?>" data-objectrelation="<?php echo h($attribute['object_relation']); ?>" data-type="<?php echo h($attribute['type']); ?>" onclick="swapValue(this);"></i>
<?php else: ?>
<i class="fas fa-times useCursorPointer" style="margin-right: 3px;" title="<?php echo __('This attribute type is missing from the new template. It will be lost if not taken care of right now.'); ?>"></i>
<?php endif; ?>
<?php echo h($attribute['object_relation']); ?>
</td>
<td><?php echo h($attribute['category']); ?></td>
<td><?php echo h($attribute['type']); ?></td>
<td>
<?php echo h($attribute['value']); ?>
<i class="fas fa-question-circle" title="<?php echo __('Original value: ') . h($attribute['current_value']); ?>"></i>
</td>
</tr>
<?php endforeach; ?>
<?php foreach ($revised_object['mergeable'] as $attribute): ?>
<tr class="success" title="<?php echo __('Can be merged automatically. Injection done.'); ; ?>">
<td style="white-space: nowrap;">
<?php if (isset($attribute['is_multiple']) && $attribute['is_multiple']): ?>
<i class="fas fa-copy useCursorPointer" style="margin-right: 3px;" title="<?php echo __('An instance of this attribute already exists. However, as multiple instanciation is allowed by this template, the two attributes will be keept.'); ?>" data-objectrelation="<?php echo h($attribute['object_relation']); ?>" data-type="<?php echo h($attribute['type']); ?>" onclick="scrollinRow(this);"></i>
<?php endif; ?>
<?php echo h($attribute['object_relation']); ?>
</td>
<td><?php echo h($attribute['category']); ?></td>
<td><?php echo h($attribute['type']); ?></td>
<td><?php echo h($attribute['value']); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<?php endif; ?>
</div>
<?php endif; ?>
<?php
if (!$ajax) {
echo $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'event', 'menuItem' => 'addObject', 'event' => $event));
@ -187,10 +330,60 @@
$(".Attribute_value_select").change(function() {
checkAndEnable($(this).parent().find('.Attribute_value'), $(this).val() == '<?php echo __('Enter value manually');?>');
});
$('.add_attribute_row').click(function() {
var selector = $(this).data('target');
var count = $(this).parent().children(selector).length;
$(this).parent().children(selector).first().clone().appendTo($(this).parent()).insertBefore($('.add_unlocked_field'));
});
$('.add_attribute_row').click(function() {
var selector = $(this).data('target');
var count = $(this).parent().children(selector).length;
$(this).parent().children(selector).first().clone().appendTo($(this).parent()).insertBefore($('.add_unlocked_field'));
});
$('.fixedRightPanel .fixedRightPanelHeader').click(function() {
$(this).next().toggle('blind');
return false;
});
});
function swapValue(clicked) {
var $clicked = $(clicked);
var old_value = $clicked.data('valueold');
var revised_value = $clicked.data('valuerevised');
var col_object_relation = $clicked.data('objectrelation');
var col_type = $clicked.data('type');
insertValueAndScroll(col_object_relation, col_type, revised_value, old_value, $clicked);
}
function scrollinRow(clicked) {
var $clicked = $(clicked);
var col_object_relation = $clicked.data('objectrelation');
var col_type = $clicked.data('type');
var $matching_rows = $('#editTable').find('tr.attribute_row:has(td:eq(1) > input[name$="[object_relation]"][value="' + col_object_relation + '"]):has(td:eq(1) > input[name$="[type]"][value="' + col_type + '"])');
$matching_rows.children().effect('highlight', { queue: false }, 2500, function() { $(this).css('background-color', 'unset'); });
$matching_rows[$matching_rows.length-1].scrollIntoView(false);
}
function insertValueAndScroll(col_object_relation, col_type, revised_value, old_value, $clicked) {
var $matching_row = $('#editTable').find('tr.attribute_row:has(td:eq(1) > input[name$="[object_relation]"][value="' + col_object_relation + '"]):has(td:eq(1) > input[name$="[type]"][value="' + col_type + '"])');
var row_id = $matching_row.attr('id').split('_').slice(-1);
var $value_field = $($matching_row.find('div.object_value_field select, div.object_value_field textarea')[0]);
var cur_val = $value_field.val();
var selected_value;
if (cur_val !== old_value) {
selected_value = old_value;
$value_field.val(old_value);
$clicked.addClass('fa-sign-in-alt fa-flip-horizontal').removeClass('fa-trash-restore');
} else {
selected_value = revised_value;
$value_field.val(revised_value);
$clicked.removeClass('fa-sign-in-alt fa-flip-horizontal').addClass('fa-trash-restore');
}
$matching_row[0].scrollIntoView(false);
$matching_row.children().effect('highlight', { queue: false, color: $value_field.val() === selected_value ? '#468847' : '#b94a48' }, 2500, function() { $(this).css('background-color', 'unset'); });
}
function insertObjectRelation(clicked) {
var $clicked = $(clicked);
var $select = $clicked.parent().find('select');
var col_object_relation = $select.val();
var col_type = $select.find('option:selected').data('type');
var revised_value = $select.data('attrval');
insertValueAndScroll(col_object_relation, col_type, revised_value, '', $('p'));
}
</script>

View File

@ -12,6 +12,14 @@
);
echo $this->Form->input('data', $formSettings);
?>
<div class='hidden'>
<?php
echo $this->Form->input('mergeIntoObject', array(
'value' => 0,
'div' => false
));
?>
</div>
<div style="margin-bottom:20px;">
<table class="table table-condensed table-striped">
<tbody>
@ -33,12 +41,16 @@
}
?></td>
</tr>
<tr>
<td class="bold"><?php echo __('Template version');?></td>
<td><?php echo h($template['ObjectTemplate']['version']); ?></td>
</tr>
<tr>
<td class="bold"><?php echo __('Comment');?></td>
<td><?php echo h($data['Object']['comment']); ?></td>
</tr>
<tr>
<table class="table table-condensed table-striped">
<table id="attribute_table" class="table table-condensed table-striped">
<thead>
<th><?php echo __('Attribute');?></th>
<th><?php echo __('Category');?></th>
@ -51,10 +63,16 @@
</thead>
<tbody>
<?php
$simple_flattened_attribute = array();
$simple_flattened_attribute_noval = array();
$attributeFields = array('category', 'type', 'value', 'to_ids' , 'comment', 'uuid', 'distribution');
if (!empty($data['Attribute'])):
foreach ($data['Attribute'] as $attribute):
echo '<tr>';
foreach ($data['Attribute'] as $id => $attribute):
$cur_flat = h($attribute['object_relation']) . '.' . h($attribute['type']) . '.' .h($attribute['value']);
$cur_flat_noval = h($attribute['object_relation']) . '.' . h($attribute['type']);
$simple_flattened_attribute[$cur_flat] = $id;
$simple_flattened_attribute_noval[$cur_flat_noval] = $id;
echo sprintf('<tr data-curflat="%s" data-curflatnoval="%s">', h($cur_flat), h($cur_flat_noval));
echo '<td>' . h($attribute['object_relation']) . '</td>';
foreach ($attributeFields as $field):
if ($field == 'distribution') {
@ -81,15 +99,96 @@
</tbody>
</table>
</div>
<?php
echo $this->Form->button(__('Submit'), array('class' => 'btn btn-primary'));
?>
<?php echo $this->Form->button(__('Create new object'), array('class' => 'btn btn-primary')); ?>
<a href="#" style="margin-left:10px;" class="btn btn-inverse" onclick="window.history.back();"><?php echo __('Back to review');?></a>
<a href="<?php echo $baseurl . '/events/view/' . h($event['Event']['id']); ?>" style="margin-left:10px;" class="btn btn-inverse"><?php echo __('Cancel');?></a>
<?php if (!empty($similar_objects) && $action !== 'edit'): ?>
<?php echo '<h3 style="margin-top: 20px;">' . __('This event contains similar objects.') . '</h3>'; ?>
<?php echo '<h5>' . __('Instead of creating a new object, would you like to merge your new object into one of the following?') . '</h5>'; ?>
<div class="row" style="margin-bottom: 20px;">
<?php foreach ($similar_objects as $object): ?>
<?php
echo $this->element('Objects/object_similarities', array(
'object' => $object,
'template' => $template,
'similar_object_similarity_amount' => $similar_object_similarity_amount,
'simple_flattened_attribute_noval' => $simple_flattened_attribute_noval,
'simple_flattened_attribute' => $simple_flattened_attribute,
'merge_button_functionname' => 'setMergeObject'
));
?>
<?php endforeach; ?>
<?php if ($similar_objects_count > $similar_objects_display_threshold): ?>
<div class="span5" style="margin-top: 20px;display: inline-block;float: unset;">
<div class="alert alert-info">
<h4><?php echo __('All similar objects not displayed...'); ?></h4>
<?php echo sprintf(__('%s Similar objects found. %s not displayed'), $similar_objects_count, $similar_objects_count-$similar_objects_display_threshold); ?>
</div>
</div>
<?php endif; ?>
</div>
<?php endif; ?>
<?php
echo $this->Form->end();
?>
</div>
<script>
function setMergeObject(clicked) {
var $clicked = $(clicked);
var object_id = $clicked.data('objectid');
var update_template = $clicked.data('updatetemplate');
update_template = update_template === undefined ? false : update_template;
var cur_object = $('input[name="data[Object][data]"]').val();
window.location = "<?php echo $baseurl . '/objects/edit/'; ?>" + object_id + (update_template ? '/1' : '') + "/revised_object:" + btoa(cur_object);
}
function highlight_rows($panel, state) {
$('#attribute_table').find('tr.error, tr.warning').removeClass('error warning').attr('title', '');
var rows = $panel.find('tr.error, tr.warning');
var to_highlight = [];
rows.each(function() {
var row_class = $(this).hasClass('error') ? 'error' : 'warning';
to_highlight.push([$(this).data().tohighlight, row_class]);
});
to_highlight.forEach(function(arr) {
var curflat = arr[0];
var row_class = arr[1];
var $row_to_highlight = $('#attribute_table').find('tr[data-curflatnoval="' + curflat + '"]');
if (state === undefined) {
$row_to_highlight.addClass(row_class);
if (row_class == 'error') {
$row_to_highlight.attr('title', '<?php echo __('This attribute will NOT be merged into the similar object as it is conflicting with another attribute.'); ?>')
}
} else if (state) {
$row_to_highlight.addClass(row_class);
} else {
$row_to_highlight.removeClass(row_class);
}
});
}
var un_highlight_time;
$(document).ready(function() {
$('.similarObjectPanel').hover(
function() {
var $panel = $(this);
if (un_highlight_time !== undefined) {
clearTimeout(un_highlight_time);
}
highlight_rows($panel);
},
function() {
un_highlight_time = setTimeout(function () {
$('#attribute_table').find('tr.error').removeClass('error').attr('title', '');
$('#attribute_table').find('tr.warning').removeClass('warning').attr('title', '');
}, 1000);
}
);
});
</script>
<?php
echo $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'event', 'menuItem' => 'addObject', 'event' => $event));
?>

@ -1 +1 @@
Subproject commit 094f0e0684efa8857944aed6e70a29b33b5065d8
Subproject commit 94466d8196dce3dafd2a41942d02e4c5362dbe51

View File

@ -0,0 +1,549 @@
from yaratemplate import YaraRuleTemplate, YaraTemplateException
import uuid
# =========================== CORE EXPORTERS ===================================
def mispevent2yara(event, options={}):
default_opts = {
'chaining_op': 'or',
'display_attr_uuids': False,
'max_attrs_per_rule': 1000,
'event_uuid_only': True
}
default_opts.update(options)
opts = default_opts
if not event['Attribute']:
return []
generated, asis_valid, asis_broken = mispattrs2yara(event['Attribute'], opts)
for rule_index, r in enumerate(generated + asis_valid):
if not r.loaded_from_source and r.attr_count() > 1:
rulename = 'MISP_EVENT_{}_PART{}'.format(event['uuid'].replace('-', '_'), rule_index+1)
r.set_name(rulename)
r.add_meta('MISP_EVENT_UUID', event['uuid'])
r.add_meta('MISP_EVENT_INFO', event['info'])
return generated, asis_valid, asis_broken
def mispobject2yara(obj):
pass
def mispattrs2yara(attrs_array, options={}):
if not attrs_array:
return []
opts = {
'chaining_op': 'or',
'max_attrs_per_rule': 1
}
opts.update(options)
generated_rules = []
asis_valid_rules = []
asis_broken_rules = []
current_rule = MISPRuleTemplate()
for i, attr in enumerate(attrs_array):
if attr['type'] == 'yara':
try:
yara_rules = MISPRuleTemplate.from_yara_attr(attr)
asis_valid_rules += yara_rules
except YaraTemplateException as e:
comment = '/* MISP EXPORT COMMENT\n'
comment += ' MISP_UUID: {}\n'.format(attr['uuid'])
comment += ' {}\n'.format(str(e))
comment += '*/\n'
commented_attr = '{}{}'.format(comment, attr['value'])
asis_broken_rules.append(commented_attr)
else:
current_rule.add_attribute(attr, opts)
last_attr_reached = i == len(attrs_array)-1
max_size_reached = current_rule.attr_count() >= opts['max_attrs_per_rule']
if last_attr_reached or max_size_reached:
# if rule has "strings" section, generate the corresponding "condition"
if current_rule.strings:
if opts['chaining_op'] == 'or':
current_rule.or_condition('any of them')
elif opts['chaining_op'] == 'and':
current_rule.and_condition('all of them')
# if rule has "condition" section, add meta, rename and add it to results, else discard it
if current_rule.condition:
generated_rules.append(current_rule)
current_rule = MISPRuleTemplate()
return generated_rules, asis_valid_rules, asis_broken_rules
# =========================== ATTR HANDLERS CORE ===============================
class MISPRuleTemplate(YaraRuleTemplate):
def __init__(self, rulename=None):
super().__init__(rulename)
self._attributes_count = 0
@classmethod
def from_yara_attr(cls, mispattr):
rules = cls.from_source(mispattr['value'])
for rule in rules:
rule._enrich(mispattr)
return rules
def add_attribute(self, mispattr, options):
opts = {
'chaining_op': 'or',
}
opts.update(options)
self._handle(mispattr, opts)
self._attributes_count += 1
event_only = False
if 'event_uuid_only' in opts and opts['event_uuid_only']:
event_only = True
self._enrich(mispattr, event_uuid_only=event_only)
self._generate_name(mispattr)
return self
def _enrich(self, attr, event=None, event_uuid_only=False):
if not event and 'Event' in attr:
event = attr['Event']
# META:
# attribute uuids
if not event_uuid_only:
uuid_meta = '{} ({})'.format(attr['uuid'], attr['type'])
self.add_meta('MISP_UUID', uuid_meta)
# event uuids
if event:
self.add_meta('MISP_EVENT_UUID', event['uuid'])
self.add_meta('MISP_EVENT_INFO', event['info'])
# other META and TAGS:
if self.loaded_from_source:
self.add_tag('as_is')
if self.autofixed:
self.add_tag('repaired')
origin_msg = 'Loaded from a corrupted Yara attribute, '\
+ 'automatically repaired.'\
+ 'Some comments may have been removed by parser. '\
+ 'Rule may be unreliable.'
self.add_meta('MISP_ORIGIN', origin_msg)
self.add_meta('MISP_FIX_NOTES', self.autofixed_comment)
else:
self.add_tag('valid')
validity_msg = 'Loaded as-is from a Yara attribute. ' \
+ 'Some comments may have been removed by parser.'
self.add_meta('MISP_ORIGIN', validity_msg)
else:
self.add_tag('generated')
self.add_meta('MISP_ORIGIN', 'Automatically generated ' \
+ 'from non-Yara attribute(s)')
return self
def _generate_name(self, attr):
if self.loaded_from_source:
pass
elif self._attributes_count == 1:
name = 'MISP_ATTRIBUTE_{}'.format(attr['uuid'])
self.set_name(name)
else:
rand_id = str(uuid.uuid4()).replace('-', '')
name = 'MISP_MULTI_ATTRIBUTES_{}'.format(rand_id)
self.set_name(name)
return self
def attr_count(self):
return self._attributes_count
def _handle(self, attr, opts):
attr_type = attr['type']
handler = self._get_type_handler(attr_type)
if handler:
handler(attr, opts)
return self
# =========================== ATTR HANDLERS ====================================
def _get_type_handler(self, attr_type):
handlers = {
'md5': self._md5,
'sha1': self._sha1,
'sha256': self._sha256,
# 'filename': self._filename, # unsupported by yara
'filename|md5': self._filename_md5,
'filename|sha1': self._filename_sha1,
'filename|sha256': self._filename_sha256,
'ip-src': self._ip_src,
'ip-dst': self._ip_dst,
'hostname': self._hostname,
'domain': self._domain,
'domain|ip': self._domain_ip,
'email-src': self._email_src,
'email-dst': self._email_dst,
'email-subject': self._email_subject,
'email-body': self._email_body,
'url': self._url,
'regkey': self._regkey,
'regkey|value': self._regkey_value,
'pattern-in-file': self._pattern_in_file,
'pattern-in-traffic': self._pattern_in_traffic,
'pattern-in-memory': self._pattern_in_memory,
# 'yara': self._yara, # specific case, see _yara2yaras()
'cookie': self._cookie,
'vulnerability': self._vulnerability,
'text': self._text,
'hex': self._hex,
'named pipe': self._named_pipe,
'mutex': self._mutex,
'btc': self._btc,
'xmr': self._xmr,
'uri': self._uri,
# 'authentihash': self._authentihash, # unsupported by yara
# 'ssdeep': self._ssdeep, # unsupported by yara
'imphash': self._imphash,
# 'pehash': self._pehash, # unsupported by yara
# 'impfuzzy': self._impfuzzy, # unsupported by yara
# 'sha224': self._sha224, # unsupported by yara
# 'sha384': self._sha384, # unsupported by yara
# 'sha512': self._sha512, # unsupported by yara
# 'sha512/224': self._sha512_224, # unsupported by yara
# 'sha512/256': self._sha512_256, # unsupported by yara
# 'tlsh': self._tlsh, # unsupported by yara
# 'cdhash': self._cdhash, # unsupported by yara
# 'filename|authentihash': self._filename_authentihash, # unsupported by yara
# 'filename|ssdeep': self._filename_ssdeep, # unsupported by yara
'filename|imphash': self._filename_imphash,
# 'filename|impfuzzy': self._filename_impfuzzy, # unsupported by yara
# 'filename|pehash': self._filename_pehash, # unsupported by yara
# 'filename|sha224': self._filename_sha224, # unsupported by yara
# 'filename|sha384': self._filename_sha384, # unsupported by yara
# 'filename|sha512': self._filename_sha512, # unsupported by yara
# 'filename|sha512/224': self._filename_sha512_224, # unsupported by yara
# 'filename|sha512/256': self._filename_sha512_256, # unsupported by yara
# 'filename|tlsh': self._filename_tlsh, # unsupported by yara
'windows-scheduled-task': self._windows_scheduled_task,
'windows-service-name': self._windows_service_name,
'windows-service-displayname': self._windows_service_displayname,
# 'x509-fingerprint-sha1': self._x509_fingerprint_sha1, # TODO check if doable
# 'x509-fingerprint-md5': self._x509_fingerprint_md5, # TODO check if doable
# 'x509-fingerprint-sha256': self._x509_fingerprint_sha256, # TODO check if doable
# 'size-in-bytes': self._size_in_bytes, # too many false positives
'ip-dst|port': self._ip_dst_port,
'ip-src|port': self._ip_src_port,
'hostname|port': self._hostname_port,
'email-dst-display-name': self._email_dst_display_name,
'email-src-display-name': self._email_src_display_name,
'email-header': self._email_header,
'email-reply-to': self._email_reply_to,
'email-x-mailer': self._email_x_mailer,
'email-mime-boundary': self._email_mime_boundary,
'email-thread-index': self._email_thread_index,
'email-message-id': self._email_message_id,
'github-username': self._github_username,
'github-repository': self._github_repository,
'github-organisation': self._github_organisation,
'mobile-application-id': self._mobile_application_id,
'user-agent': self._user_agent,
}
if attr_type in handlers:
return handlers[attr_type]
else:
return None
def __generic_string(self, value, opts):
self.strings_text(None, value,
escape_newlines=True,
nocase=False,
ascii=True,
wide=True,
xor=False,
fullword=False)
return self
def _md5(self, attr, opts):
filehash = attr['value']
self.add_module_dependency('hash')
self.or_condition('hash.md5(0, filesize) == "{}"'.format(filehash))
return self
def _sha1(self, attr, opts):
filehash = attr['value']
self.add_module_dependency('hash')
self.or_condition('hash.sha1(0, filesize) == "{}"'.format(filehash))
return self
def _sha256(self, attr, opts):
filehash = attr['value']
self.add_module_dependency('hash')
self.or_condition('hash.sha256(0, filesize) == "{}"'.format(filehash))
return self
# def _filename(self, attr, opts):
# self.__generic_string(attr['value'], opts)
# return self
def _filename_md5(self, attr, opts):
filename, _, filehash = attr['value'].rpartition('|')
self.add_module_dependency('hash')
self.or_condition('hash.md5(0, filesize) == "{}"'.format(filehash))
return self
def _filename_sha1(self, attr, opts):
filename, _, filehash = attr['value'].rpartition('|')
self.add_module_dependency('hash')
self.or_condition('hash.sha1(0, filesize) == "{}"'.format(filehash))
return self
def _filename_sha256(self, attr, opts):
filename, _, filehash = attr['value'].rpartition('|')
self.add_module_dependency('hash')
self.or_condition('hash.sha256(0, filesize) == "{}"'.format(filehash))
return self
def _ip_src(self, attr, opts):
self.__generic_string(attr['value'], opts)
return self
def _ip_dst(self, attr, opts):
self.__generic_string(attr['value'], opts)
return self
def _hostname(self, attr, opts):
self.__generic_string(attr['value'], opts)
return self
def _domain(self, attr, opts):
self.__generic_string(attr['value'], opts)
return self
def _domain_ip(self, attr, opts):
domain, _, ip = attr['value'].rpartition('|')
self.__generic_string(domain, opts)
self.__generic_string(ip, opts)
return self
def _email_src(self, attr, opts):
self.__generic_string(attr['value'], opts)
return self
def _email_dst(self, attr, opts):
self.__generic_string(attr['value'], opts)
return self
def _email_subject(self, attr, opts):
self.__generic_string(attr['value'], opts)
return self
def _email_body(self, attr, opts):
self.__generic_string(attr['value'], opts)
return self
def _url(self, attr, opts):
self.__generic_string(attr['value'], opts)
return self
def _regkey(self, attr, opts):
self.__generic_string(attr['value'], opts)
return self
def _regkey_value(self, attr, opts):
regkey, _, regvalue = attr['value'].rpartition('|')
self.__generic_string(regkey, opts)
self.__generic_string(regvalue, opts)
return self
def _pattern_in_file(self, attr, opts):
self.__generic_string(attr['value'], opts)
return self
def _pattern_in_traffic(self, attr, opts):
self.__generic_string(attr['value'], opts)
return self
def _pattern_in_memory(self, attr, opts):
self.__generic_string(attr['value'], opts)
return self
def _yara(self, attr, opts):
self.__generic_string(attr['value'], opts)
return self
def _cookie(self, attr, opts):
self.__generic_string(attr['value'], opts)
return self
def _vulnerability(self, attr, opts):
self.__generic_string(attr['value'], opts)
return self
def _text(self, attr, opts):
self.__generic_string(attr['value'], opts)
return self
def _hex(self, attr, opts):
self.strings_hex(None, attr['value'])
return self
def _named_pipe(self, attr, opts):
self.__generic_string(attr['value'], opts)
return self
def _mutex(self, attr, opts):
self.__generic_string(attr['value'], opts)
return self
def _btc(self, attr, opts):
self.__generic_string(attr['value'], opts)
return self
def _xmr(self, attr, opts):
self.__generic_string(attr['value'], opts)
return self
def _uri(self, attr, opts):
self.__generic_string(attr['value'], opts)
return self
# def _authentihash(self, attr, opts):
# self.__generic_string(attr['value'], opts)
# return self
#
# def _ssdeep(self, attr, opts):
# self.__generic_string(attr['value'], opts)
# return self
def _imphash(self, attr, opts):
filehash = attr['value']
self.add_module_dependency('pe')
self.or_condition('pe.imphash() == "{}"'.format(filehash))
return self
def _filename_imphash(self, attr, opts):
filename, _, filehash = attr['value'].rpartition('|')
self.add_module_dependency('pe')
self.or_condition('pe.imphash() == "{}"'.format(filehash))
return self
# def _filename_impfuzzy(self, attr, opts):
# self.__generic_string(attr['value'], opts)
# return self
#
# def _filename_pehash(self, attr, opts):
# self.__generic_string(attr['value'], opts)
# return self
#
# def _filename_sha224(self, attr, opts):
# self.__generic_string(attr['value'], opts)
# return self
#
# def _filename_sha384(self, attr, opts):
# self.__generic_string(attr['value'], opts)
# return self
#
# def _filename_sha512(self, attr, opts):
# self.__generic_string(attr['value'], opts)
# return self
#
# def _filename_sha512_224(self, attr, opts):
# self.__generic_string(attr['value'], opts)
# return self
#
# def _filename_sha512_256(self, attr, opts):
# self.__generic_string(attr['value'], opts)
# return self
#
# def _filename_tlsh(self, attr, opts):
# self.__generic_string(attr['value'], opts)
# return self
def _windows_scheduled_task(self, attr, opts):
self.__generic_string(attr['value'], opts)
return self
def _windows_service_name(self, attr, opts):
self.__generic_string(attr['value'], opts)
return self
def _windows_service_displayname(self, attr, opts):
self.__generic_string(attr['value'], opts)
return self
# TODO: check if that can be implemented
# def _x509_fingerprint_sha1(self, attr, opts):
# self.__generic_string(attr['value'], opts)
# return self
#
# def _x509_fingerprint_md5(self, attr, opts):
# self.__generic_string(attr['value'], opts)
# return self
#
# def _x509_fingerprint_sha256(self, attr, opts):
# self.__generic_string(attr['value'], opts)
# return self
# TODO: too many false-positives but could be OK in objects
# def _size_in_bytes(self, attr, opts):
# self.__generic_string(attr['value'], opts)
# return self
#
# likely false positives on ports, also can't guess ip:port format.
# Ignoring port
def _ip_dst_port(self, attr, opts):
ip, _, port = attr['value'].rpartition('|')
self.__generic_string(ip, opts)
return self
def _ip_src_port(self, attr, opts):
ip, _, port = attr['value'].rpartition('|')
self.__generic_string(ip, opts)
return self
def _hostname_port(self, attr, opts):
host, _, port = attr['value'].rpartition('|')
self.__generic_string(host, opts)
return self
def _email_dst_display_name(self, attr, opts):
self.__generic_string(attr['value'], opts)
return self
def _email_src_display_name(self, attr, opts):
self.__generic_string(attr['value'], opts)
return self
def _email_header(self, attr, opts):
self.__generic_string(attr['value'], opts)
return self
def _email_reply_to(self, attr, opts):
self.__generic_string(attr['value'], opts)
return self
def _email_x_mailer(self, attr, opts):
self.__generic_string(attr['value'], opts)
return self
def _email_mime_boundary(self, attr, opts):
self.__generic_string(attr['value'], opts)
return self
def _email_thread_index(self, attr, opts):
self.__generic_string(attr['value'], opts)
return self
def _email_message_id(self, attr, opts):
self.__generic_string(attr['value'], opts)
return self
def _github_username(self, attr, opts):
self.__generic_string(attr['value'], opts)
return self
def _github_repository(self, attr, opts):
self.__generic_string(attr['value'], opts)
return self
def _github_organisation(self, attr, opts):
self.__generic_string(attr['value'], opts)
return self
def _mobile_application_id(self, attr, opts):
self.__generic_string(attr['value'], opts)
return self
def _user_agent(self, attr, opts):
self.__generic_string(attr['value'], opts)
return self

View File

@ -0,0 +1,157 @@
import plyara
from plyara.exceptions import ParseError
from plyara import *
from unittest import mock
import re
import string
PERMISSIVE_MODE = True # set to False to use the regular, strict, plyara parser for debugging
_original_match = re.match
def _multiline_match(pattern, string, flags=0):
return _original_match(pattern, string, flags=flags | re.DOTALL | re.MULTILINE)
class _MultilinePlyara(plyara.Plyara):
def parse_string(self, input_string):
with mock.patch.object(re, 'match', _multiline_match):
return super(plyara.Plyara, self).parse_string(input_string)
class PermissivePlyara():
def parse_string(self, input_string):
try:
if PERMISSIVE_MODE:
return self._permissive_parse_string(input_string)
else:
return plyara.Plyara().parse_string(input_string)
except ParseError as e:
raise
# some errors are not properly caught by plyara
# convert everything to ParseError to avoid uncatchable crashes
except Exception as e:
raise ParseError('Uncaught plyara exception ({}): {}'.format(type(e).__name__, str(e)), None, None)
def _permissive_parse_string(self, input_string, fix_notes=None, original_error=None):
if not fix_notes:
fix_notes = set()
# with mock.patch.object(re, 'match', overridden_match):
try:
# res = super(Plyara, self).parse_string(input_string) # weird failures, couldn't debug. possibly due to internal state
# re-instanciating playra to avoid internal state errors
res = _MultilinePlyara().parse_string(input_string)
if fix_notes:
for r in res:
r['permissive_plyara_fixed'] = True
r['permissive_plyara_comment'] = '. '.join(fix_notes)
return res
except ParseError as e:
if not original_error:
original_error = e
str_error = str(e)
fixed = input_string
if str_error.startswith('Illegal character') and any(elem in str_error for elem in '”“″'):
fixed = _fix_quotes(input_string)
fix_notes.add('Wrong quotes characters')
elif str_error.startswith('Unknown text Rule'):
fixed = _fix_capital(input_string)
fix_notes.add('Rule => rule')
elif str_error.startswith('Illegal character'):
fixed = _fix_illegal_chars(input_string)
fix_notes.add('Illegal characters')
elif str_error.startswith('Unknown text { for token of type LBRACE') \
and input_string.lstrip().startswith \
and input_string.rstrip().endswith('}'):
fixed = _fix_noname(input_string)
fix_notes.add('Missing rule name')
elif re.match(r'Unknown text\s?_\s?for token of type ID', str_error):
fixed = _fix_spaced_underscores(input_string)
fix_notes.add("' _ ' => '_'")
else:
fixed = _fix_magic(input_string)
fix_notes.add('Magic fix (highly unreliable)')
if fixed != input_string:
return self._permissive_parse_string(fixed, fix_notes, original_error)
else:
raise original_error
# best_error = 'BEST GUESS ERROR: {}\n'.format(str(e))
# best_guess = 'BEST GUESS: \n{}'.format(input_string)
# raise ParseError(best_error+best_guess, None, None) from e
def _fix_quotes(yara_src):
repaired = yara_src
repaired = repaired.replace('', '"')
repaired = repaired.replace('', '"')
repaired = repaired.replace('', '"')
return repaired
def _fix_capital(yara_src):
repaired = yara_src.replace('Rule', 'rule')
return repaired
def _fix_illegal_chars(yara_src):
repaired = ''.join(filter(lambda x: x in string.printable, yara_src))
return repaired
def _fix_noname(yara_src):
repaired = 'rule UnnamedRule ' + yara_src
return repaired
def _fix_spaced_underscores(yara_src):
repaired = yara_src.replace(' _ ', '_')
return repaired
def _fix_magic(yara_src):
repaired = ''
for line in yara_src.splitlines():
if '//' not in line:
repaired += line
else:
repaired += '\n{}\n'.format(line)
return repaired if repaired else yara_src
# Keeping this code for later as it contains more advanced fixes
# def _try_simple_repairs(yara_src, error):
# reasons = []
# # common quotes error
# repaired = yara_src
# repaired = repaired.replace('”', '"')
# repaired = repaired.replace('“', '"')
# repaired = repaired.replace('″', '"')
# if repaired != yara_src:
# reasons.append('wrong quotes characters')
# # missing rule declaration
# if repaired.strip().startswith('{'):
# reasons.append('missing rule name')
# rulename = 'UnnamedRule'
# repaired = 'rule {} {}'.format(rulename, repaired)
# # capital letter rule declaration
# if repaired.strip().startswith('Rule'):
# reasons.append('Rule => rule')
# repaired = repaired.replace('Rule', 'rule')
# if 'Illegal character' in str(error):
# repaired = ''.join(filter(lambda x: x in string.printable, repaired))
# reasons.append('illegal characters')
# # badly formated declaration:
# # check if rule matches format : DATA rule DECLARATION { CONTENT } DATA
# split_source = re.split(r'rule\s(.*?){(.*)}', repaired, flags=re.MULTILINE|re.DOTALL)
# if len(split_source) == 4:
# split_source = {'pre': split_source[0],
# 'declaration': split_source[1].replace(' ', '').rstrip().rstrip(':'),
# 'content': split_source[2],
# 'post': split_source[3]}
# quoted_content = re.split(r'\"(.+?)\"', split_source['content'], re.MULTILINE | re.DOTALL)
# nolinebreak_content = ''
# for chunk in quoted_content: # remove line breaks in strings and meta
# if chunk.startswith('"') and chunk.endswith('"'):
# nolinebreak_content += ''.join(chunk.splitlines())
# reassembled = 'rule {} {{ {} }}'.format(split_source['declaration'], split_source['content'])
# repaired = reassembled
# return repaired, reasons

View File

@ -0,0 +1,94 @@
from misp2yara import mispevent2yara, mispattrs2yara, MISPRuleTemplate
import sys
import json
import os
from optparse import OptionParser
def rules2json_export(rules, extra_comment=''):
return json.dumps([rule2json_export(r) for r in rules])
def rule2json_export(rule, extra_comment=''):
json_dict = {
'value': str(rule),
'comment': '',
'valid': None
}
if isinstance(rule, MISPRuleTemplate):
if rule.loaded_from_source:
json_dict['comment'] += 'Loaded from source. '
else:
json_dict['comment'] += 'Generated. '
if rule.autofixed:
json_dict['comment'] += 'May be unreliable due to automatic repairs: '
json_dict['comment'] += rule.autofixed_comment
json_dict['valid'] = True
return json_dict
else:
json_dict['comment'] += 'Broken yara attribute. Could not parse or repair.'
json_dict['valid'] = False
return json_dict
def file_is_empty(path):
return os.stat(path).st_size==0
def output_json(output_path, output_rules):
with open(output_path, 'a+', encoding='utf-8') as f:
if file_is_empty(output_path):
pass
else:
f.write(',')
to_write = rules2json_export(output_rules)[1:-1]
f.write(to_write)
def output_raw(output_path, output_rules):
with open(output_path, 'a+', encoding='utf-8') as f:
to_write = '\n\n'.join([str(r) for r in output_rules])
f.write(to_write)
if __name__ == "__main__":
parser = OptionParser()
parser.add_option("-i", "--input", dest="in_file",
help="input file", metavar="FILE")
parser.add_option("-g", "--out-generated", dest="out_gen",
help="output for generated rules", metavar="FILE")
parser.add_option("-a", "--out-asis", dest="out_asis",
help="output for as-is rules", metavar="FILE")
parser.add_option("-r", "--raw",
action="store_true", dest="raw_output", default=False,
help="outputs raw yara rules instead of json-structured rules")
(options, args) = parser.parse_args()
in_path = options.in_file
out_path_gen = options.out_gen
out_path_asis = options.out_asis
raw_mode = options.raw_output
loaded = None
with open(in_path, 'r', encoding='utf-8') as in_file:
content = in_file.read()
if content:
loaded = json.loads(content)['response']
# raise Warning("loaded {}".format(content))
if 'Attribute' in loaded:
generated, asis_valid, asis_broken = mispattrs2yara(loaded['Attribute'])
elif isinstance(loaded, list):
generated = []
asis_valid = []
asis_broken = []
for event_dict in loaded:
if 'Event' in event_dict:
curr_generated, curr_asis_valid, curr_asis_broken = mispevent2yara(event_dict['Event'])
generated += curr_generated
asis_valid += curr_asis_valid
asis_broken += curr_asis_broken
else:
raise Exception('Json doesn\'t seem to be an list of attributes or events')
else:
raise Exception('Json doesn\'t seem to be an list of attributes or events')
if raw_mode:
output_raw(out_path_gen, generated)
output_raw(out_path_asis, asis_valid + asis_broken)
else:
output_json(out_path_gen, generated)
output_json(out_path_asis, asis_valid + asis_broken)

View File

@ -0,0 +1,352 @@
from permissive_plyara import PermissivePlyara
from permissive_plyara import ParseError
import plyara
from plyara import utils
import warnings
import re
__version__ = '0.1'
__yara_version__ = '8.1'
class YaraTemplateException(Exception):
def __init__(self, message, source=None):
super(Exception, self).__init__(message)
self.source = source
class YaraLexerException(YaraTemplateException):
pass
class YaraTemplateRuleConflictException(YaraTemplateException):
pass
class YaraTemplateRuleDependencyException(YaraTemplateException):
pass
class YaraRuleTemplate:
class _YaraStringsItem:
def __init__(self, stringstype, name, value,
modifiers, force_escape=True):
if not name.startswith('$'):
name = '${}'.format(name)
if stringstype == 'byte':
value = '{{ {} }}'.format(value)
elif stringstype == 'text':
if force_escape:
value = yara_escape_str(value)
value = '"{}"'.format(value)
elif stringstype == 'regex':
if force_escape:
# escape all unescaped '/'
value = re.sub(r'(?<=[^\\])/', r'\\'+r'/', value)
# # quick and dirty way to get rid of illegal line carriages in regexes
# value = ''.join([l.strip() for l in value.splitlines()])
value = '/{}/'.format(value)
self.stringstype = stringstype
self.name = name
self.value = value
self.modifiers = modifiers
def __str__(self):
name = self.name
value = self.value
modifiers = ' '.join(self.modifiers)
return "{} = {} {}".format(name, value, modifiers)
def __init__(self, rulename):
self.rulename = rulename
self.ruletags = set()
self.rulescopes = set() # can be empty, 'global' or 'private'
self.meta = set()
self.strings = [] # list instead of name=>value dict because of anonymous strings
self.condition = ''
self.file_dependencies = []
self.rule_dependencies = []
self.module_dependencies = []
self.loaded_from_source = False
self.autofixed = False
self.autofixed_comment = ''
@classmethod
def from_source(cls, yara_source):
if not isinstance(yara_source, str):
yara_source = str(yara_source)
try:
plyara_parsed = PermissivePlyara().parse_string(yara_source)
except ParseError as e:
raise YaraLexerException(str(e), yara_source)
rules = []
try:
for plyara_rule in plyara_parsed:
rule = cls._from_plyara(plyara_rule)
rules.append(rule)
return rules
except YaraTemplateException as e:
e.source = yara_source
raise
# Creates a YaraRuleTemplate from plyara's array output format
@classmethod
def _from_plyara(cls, plyara_out):
plyara_out = cls._ensure_one_rule(plyara_out)
rule = cls(plyara_out['rule_name'])
rule.loaded_from_source = True
if 'tags' in plyara_out:
rule.ruletags.update(plyara_out['tags'])
if 'scopes' in plyara_out:
rule.rulescopes.update(plyara_out['scopes'])
if 'metadata' in plyara_out:
for m in plyara_out['metadata']:
for k, v in m.items():
rule.add_meta(k,v)
if 'strings' in plyara_out:
for s in plyara_out['strings']:
s_modifiers = s['modifiers'] if 'modifiers' in s else []
if s['type'] == 'byte' or s['type'] == 'regex':
value = s['value'][1:-1]
else:
value = s['value']
rule._strings(s['type'], s['name'], value, s_modifiers)
if 'raw_condition' in plyara_out:
_, cond = plyara_out['raw_condition'].split("condition:",1)
rule.condition = cond
# parsing conditions is too tricky and prone to errors
# rule.condition = " ".join(plyara_out['condition_terms'])
else:
return rule # stop and return to avoid uncaught plyara exceptions
if 'includes' in plyara_out:
rule.file_dependencies = plyara_out['includes']
rule.rule_dependencies = plyara.utils.detect_dependencies(plyara_out)
rule.module_dependencies = plyara.utils.detect_imports(plyara_out)
if 'permissive_plyara_fixed' in plyara_out \
and plyara_out['permissive_plyara_fixed']:
rule.autofixed = True
if 'permissive_plyara_comment' in plyara_out:
rule.autofixed_comment = plyara_out['permissive_plyara_comment']
return rule
def __str__(self):
includes = set(self.file_dependencies)
imports = set(self.module_dependencies)
includes_str = '\n'.join(['include "{}"'.format(i) for i in includes])
imports_str = '\n'.join(['import "{}"'.format(i) for i in imports])
scopes = (' '.join(self.rulescopes) + ' ') if self.rulescopes else ''
tags_str = (' : ' + ' '.join(self.ruletags)) if self.ruletags else ''
declaration = '{}rule {}{}'.format(scopes, self.rulename, tags_str)
meta_section = ''
strings_section = ''
condition_section = ''
if self.meta:
sorted_meta = sorted(self.meta)
meta_section += '\tmeta:'
for (m, v) in sorted_meta:
meta_section += '\n\t\t{} = "{}"'.format(m, v)
meta_section += '\n'
if self.strings:
strings_section += '\tstrings:'
for s in self.strings:
strings_section += '\n\t\t{}'.format(s)
strings_section += '\n'
if self.condition:
condition_section += '\tcondition:'
for cond_line in self.condition.splitlines():
stripped = cond_line.strip()
if stripped:
condition_section += '\n\t\t{}'.format(stripped)
result = '{}\n{}\n{}\n{{\n{}{}{}\n}}'.format(includes_str,
imports_str,
declaration,
meta_section,
strings_section,
condition_section)
if not self.condition:
result = '// this rule will not compile (mandatory "condition" section missing)\n{}'.format(result)
return result
def add_meta(self, meta_key, meta_value):
# remove illegal characters (same filter as "strings" entries)
meta_value = yara_escape_str(str(meta_value))
self.meta.add((meta_key, meta_value))
return self
def set_name(self, name):
# replace forbidden characters with '_'
name = re.sub(r'[^A-Za-z0-9_]', '_', name)
if name[0].isdigit():
name = '_{}'.format(name)
self.rulename = name
return self
def add_tag(self, tag):
# replace forbidden characters with '_'
tag = re.sub(r'[^A-Za-z0-9_]', '_', tag)
if tag[0].isdigit():
tag = '_{}'.format(tag)
self.ruletags.add(tag)
return self
def set_condition(self, condition_expression):
self.condition = condition_expression
return self
def and_condition(self, condition_expression):
if not self.condition:
self.condition = '{}'.format(condition_expression)
else:
self.condition = '{}\n and {}'.format(self.condition,
condition_expression)
return self
def or_condition(self, condition_expression):
if not self.condition:
self.condition = '{}'.format(condition_expression)
else:
self.condition = '{}\n or {}'.format(self.condition,
condition_expression)
return self
# Adds an entry to the 'strings' section
# str_type can be 'byte', 'text' or 'regex'
# name could be None for anonymous strings
def _strings(self, str_type, name, value, modifiers):
if name == '$' or not name:
name = '$'
force_escape = False if self.loaded_from_source else True
str_entry = self._YaraStringsItem(str_type, name, value, modifiers, force_escape)
if str_entry.name == '$' or str_entry.name not in (o.name for o in self.strings):
self.strings.append(str_entry)
else:
raise YaraTemplateException(
'There is already a string named "{}"'.format(str_entry.name))
return self
# adds a 'byte' entry ({}) to strings section (default: nocase ascii wide)
def strings_hex(self, name, value):
self._strings('byte', name, value, [])
return self
# adds a 'text' entry ("") to strings section (default: nocase ascii wide)
def strings_text(self, name, value, escape_newlines=True, nocase=True,
ascii=True, wide=True, xor=False, fullword=False):
modifiers = []
# escaping unescaped double quotes
if nocase:
modifiers.append('nocase')
if ascii:
modifiers.append('ascii')
if wide:
modifiers.append('wide')
if xor:
modifiers.append('xor')
if fullword:
modifiers.append('fullword')
if escape_newlines and len(value.splitlines()) > 1:
# only regex supports system-agnostic line breaks
value = _str2yara_regex(value)
self._strings('regex', name, value, modifiers)
elif len(value.splitlines()) > 1:
for line in value.splitlines():
self._strings('text', name, line, modifiers)
# TODO: imporvement: group lines with 'all of $*'
# instead of (\r|\r\n|\n|\x1E)
else:
self._strings('text', name, value, modifiers)
return self
# adds a 'regex' entry (//) to strings section (default: nocase ascii wide)
def strings_regex(self, name, value, nocase=True, ascii=True,
wide=True, fullword=False):
modifiers = []
if nocase:
modifiers.append('nocase')
if ascii:
modifiers.append('ascii')
if wide:
modifiers.append('wide')
if fullword:
modifiers.append('fullword')
self._strings('regex', name, value, modifiers)
return self
# adds an 'include' statement
def add_file_dependency(self, file_name):
if file_name not in self.file_dependencies:
self.file_dependencies.append(file_name)
return self
# adds an rule dependency, useful to determine the order in a group of rules
def add_rule_dependency(self, rule_name):
if rule_name not in self.rule_dependencies:
self.rule_dependencies.append(rule_name)
return self
# adds an 'import' dependency
def add_module_dependency(self, module_name):
if module_name not in self.module_dependencies:
self.module_dependencies.append(module_name)
return self
@staticmethod
def _ensure_one_rule(plyara_output):
if isinstance(plyara_output, list):
if len(plyara_output) != 1:
error_msg = 'Single rule expected, \
string contains {} rules'.format(len(plyara_output))
raise YaraTemplateException(error_msg)
else:
return plyara_output[0]
else:
return plyara_output
# =============== Tools ===================
# replaces special characters in yara 'text' strings
def yara_escape_str(pattern):
_special_chars_map = {
ord(b'\\'): '\\\\',
ord(b'"'): '\\"',
ord(b'\n'): '\\n',
ord(b'\t'): '\\t',
ord(b'\r'): '\\\\r'
}
return pattern.translate(_special_chars_map)
# helps convert a python string to a yara 'regex' string, escapes special chars
# handles newlines by making them system-agnostic and optional
def _str2yara_regex(pattern):
_special_chars_map = {
ord(b'/'): '\\/',
# covers '\' and all escapes not valid in python but valid in yara:
# \w \W \s \S \d \D \B
ord(b'\\'): '\\\\',
ord(b'^'): '\\^',
ord(b'$'): '\\$',
ord(b'|'): '\\|',
ord(b'('): '\\(',
ord(b')'): '\\)',
ord(b'['): '\\[',
ord(b']'): '\\]',
ord(b'*'): '\\*',
ord(b'+'): '\\+',
ord(b'?'): '\\?',
ord(b'{'): '\\{',
ord(b'}'): '\\}',
ord(b'\t'): '\\t',
ord(b'\f'): '\\f',
ord(b'\a'): '\\a',
# covers \n \r\n \r and other exotic line breaks (\x1E)
ord(b'\n'): '(\\x0D|\\x0A\\x0D|\\x0A|\\x1E)?',
ord(b'\b'): '\\b'
}
pattern = '\n'.join(pattern.splitlines())
return pattern.translate(_special_chars_map)

View File

@ -0,0 +1,20 @@
#!/usr/bin/env python3
import json
import sys
results = {
'success': 1,
'plyara': 0,
}
try:
import plyara
results['plyara'] = 1
except Exception:
results['playara'] = 0
results['success'] = 0
print(json.dumps({
'success': results['success'],
'plyara': results['plyara']
}))
sys.exit(0)

0
app/tmp/yara/empty Normal file
View File

View File

@ -144,19 +144,6 @@ label.center-in-network-header {
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0);
}
.advancedSharingNetwork {
position: fixed;
top: 45px;
right: 0px;
height: 800px;
width: 800px;
background: #ffffffcc;;
z-index: 1;
border: 1px solid #0088cc;
border-radius: 6px;
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
}
.sharingNetworkOrgFinder {
position: absolute !important;
right: 30px !important;

View File

@ -2270,3 +2270,16 @@ table tr:hover .down-expand-button {
margin-left:2px;
color: black;
}
.fixedRightPanel {
position: fixed;
top: 45px;
right: 0px;
height: 800px;
width: 800px;
background: #ffffffcc;;
z-index: 1;
border: 1px solid #0088cc;
border-radius: 6px;
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
}

View File

@ -593,6 +593,7 @@ function quickSubmitTagForm(selected_tag_ids, addData) {
$('#EventTag').val(JSON.stringify(selected_tag_ids));
$.ajax({
data: $('#EventAddTagForm').serialize(),
cache: false,
beforeSend: function (XMLHttpRequest) {
$(".loading").show();
},

View File

@ -255,7 +255,7 @@
var allow_interactive_picking = $('#attributes_div table tr').length > 0;
var $div = '<div id="sharingNetworkWrapper" class="advancedSharingNetwork hidden">'
var $div = '<div id="sharingNetworkWrapper" class="fixedRightPanel hidden">'
+ '<div class="eventgraph_header" style="border-radius: 5px; display: flex;">'
+ '<it class="fa fa-circle-o" style="margin: auto 10px; font-size: x-large"></it>'
+ '<input type="text" id="sharingNetworkTargetId" class="center-in-network-header network-typeahead" style="width: 200px;" disabled></input>';

View File

@ -175,6 +175,9 @@ installCore () {
# install python-magic
$SUDO_WWW ${PATH_TO_MISP}/venv/bin/pip install python-magic
# install plyara
$SUDO_WWW ${PATH_TO_MISP}/venv/bin/pip install plyara
# Install Crypt_GPG and Console_CommandLine
sudo pear install ${PATH_TO_MISP}/INSTALL/dependencies/Console_CommandLine/package.xml
sudo pear install ${PATH_TO_MISP}/INSTALL/dependencies/Crypt_GPG/package.xml

View File

@ -49,11 +49,17 @@ viper () {
$SUDO_USER sed -i "s/^misp_key\ =/misp_key\ =\ $AUTH_KEY/g" ${VIPER_HOME}/viper.conf
# Reset admin password to: admin/Password1234
echo "Fixing admin.db with default password"
VIPER_COUNT=0
while [ "$(sudo sqlite3 ${VIPER_HOME}/admin.db 'UPDATE auth_user SET password="pbkdf2_sha256$100000$iXgEJh8hz7Cf$vfdDAwLX8tko1t0M1TLTtGlxERkNnltUnMhbv56wK/U="'; echo $?)" -ne "0" ]; do
# FIXME This might lead to a race condition, the while loop is sub-par
sudo chown $MISP_USER:$MISP_USER ${VIPER_HOME}/admin.db
echo "Updating viper-web admin password, giving process time to start-up, sleeping 5, 4, 3,…"
sleep 6
VIPER_COUNT=$[$VIPER_COUNT+1]
if [[ "$VIPER_COUNT" > '10' ]]; then
echo "Something is wrong with updating viper. Continuing without db update."
break
fi
done
# Add viper-web to rc.local to be started on boot

View File

@ -5,13 +5,13 @@
------------------------------------
!!! notice
Maintained and tested by @SteveClement on 20190405
Maintained and tested by @SteveClement on 20190425
!!! warning
This install document is NOT working as expected. There are Python issues as we "only" have python 3.5 but need at least python 3.6
This install document is **NOT** working as expected. There are Python issues as we "only" have python 3.5 but need at least python 3.6
This guide effectively converts your "stretch" install into a partial "testing" install.
Thus following the "testing" install guide is a better choice, but not for production.
One manual work-around is to install Python >3.5 from source.
One manual work-around is to install Python >3.5 from source and leaving apt untouched.
### 1/ Minimal Debian install
-------------------------
@ -80,10 +80,11 @@ sudo apt -t testing install -y \
mariadb-client \
mariadb-server
# /!\
# This is maybe needed. If mysql does not start and you find a solution, please contribute.
# What did work for me was running mysqld interactively: sudo mysqld
mkdir -p /var/run/mysqld
chown mysql /var/run/mysqld
sudo mkdir -p /var/run/mysqld
sudo chown mysql /var/run/mysqld
sudo /etc/init.d/mysql restart
sudo apt -t testing install -y jupyter-notebook

View File

@ -1,4 +1,4 @@
# INSTALLATION INSTRUCTIONS for RHEL 8.x (beta)
# INSTALLATION INSTRUCTIONS for RHEL 8.x (beta) and partially Fedora Server 30
-------------------------
### -1/ Installer and Manual install instructions
@ -129,6 +129,7 @@ sudo yum install gcc git zip \
mod_ssl \
redis \
mariadb \
mariadb-server \
python3-devel python3-pip python3-virtualenv \
libxslt-devel zlib-devel ssdeep-devel -y
sudo alternatives --set python /usr/bin/python3
@ -159,11 +160,6 @@ sudo yum install php php-fpm php-devel php-pear \
sudo systemctl enable --now php-fpm.service
```
## 2.07/ Start redis service and enable to start on boot
```bash
sudo systemctl enable --now redis.service
```
```bash
# <snippet-begin 0_yumInstallHaveged.sh>
# GPG needs lots of entropy, haveged provides entropy
@ -237,7 +233,8 @@ $SUDO_WWW $PATH_TO_MISP/venv/bin/pip install -U zmq
$SUDO_WWW $PATH_TO_MISP/venv/bin/pip install -U redis
# lief needs manual compilation
sudo yum install devtoolset-8 cmake3 cppcheck -y
sudo yum groupinstall "Development Tools" -y
sudo yum install cmake3 cppcheck -y
cd $PATH_TO_MISP/app/files/scripts/lief
$SUDO_WWW mkdir build
@ -289,10 +286,10 @@ installCake_RHEL ()
sudo chown $WWW_USER:$WWW_USER /usr/share/httpd/.composer
cd $PATH_TO_MISP/app
# Update composer.phar (optional)
#$SUDO_WWW php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
#$SUDO_WWW php -r "if (hash_file('SHA384', 'composer-setup.php') === '48e3236262b34d30969dca3c37281b3b4bbe3221bda826ac6a9a62d6444cdb0dcd0615698a5cbe587c3f0fe57a54d8f5') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
#$SUDO_WWW php composer-setup.php
#$SUDO_WWW php -r "unlink('composer-setup.php');"
$SUDO_WWW php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
$SUDO_WWW php -r "if (hash_file('SHA384', 'composer-setup.php') === '48e3236262b34d30969dca3c37281b3b4bbe3221bda826ac6a9a62d6444cdb0dcd0615698a5cbe587c3f0fe57a54d8f5') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
$SUDO_WWW php composer-setup.php
$SUDO_WWW php -r "unlink('composer-setup.php');"
$SUDO_WWW php composer.phar require kamisama/cake-resque:4.1.2
$SUDO_WWW php composer.phar config vendor-dir Vendor
$SUDO_WWW php composer.phar install
@ -650,7 +647,7 @@ Make the workers' script executable and reload the systemd units :
```bash
sudo chmod +x /var/www/MISP/app/Console/worker/start.sh
sudo systemctl daemon-reload
sudo checkmodule -M -m -o /tmp/workerstartsh.mod $PATH_TO_MISP/INSTALL/workerstartsh.te
sudo checkmodule -M -m -o /tmp/workerstartsh.mod $PATH_TO_MISP/INSTALL/worker/startsh.te
sudo semodule_package -o /tmp/workerstartsh.pp -m /tmp/workerstartsh.mod
sudo semodule -i /tmp/workerstartsh.pp
```
@ -670,10 +667,10 @@ sudo chown root:users /usr/local/src
cd /usr/local/src/
$SUDO_WWW git clone https://github.com/MISP/misp-modules.git
cd misp-modules
sudo yum install rubygem-rouge rubygem-asciidoctor zbar-devel opencv-core poppler-cpp-devel -y
# pip install
$SUDO_WWW $PATH_TO_MISP/venv/bin/pip install -U -I -r REQUIREMENTS
$SUDO_WWW $PATH_TO_MISP/venv/bin/pip install -U .
sudo yum install rubygem-rouge rubygem-asciidoctor zbar-devel opencv-core -y
echo "[Unit]
Description=MISP's modules

View File

@ -7,3 +7,4 @@ requests-mock
pip
nose
jsonschema
plyara >= 2.0.2