mirror of https://github.com/MISP/MISP
chg: merge develop, fix conflicts.
commit
f2c9d12eae
|
@ -117,7 +117,8 @@ MISPvars () {
|
|||
# MISP configuration variables
|
||||
PATH_TO_MISP="${PATH_TO_MISP:-/var/www/MISP}"
|
||||
PATH_TO_MISP_SCRIPTS="${PATH_TO_MISP}/app/files/scripts"
|
||||
|
||||
## For future use
|
||||
# TMPDIR="${TMPDIR:-$PATH_TO_MISP/app/tmp}"
|
||||
|
||||
FQDN="${FQDN:-misp.local}"
|
||||
|
||||
|
@ -1542,6 +1543,9 @@ coreCAKE () {
|
|||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "Session.timeout" 600
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "Session.cookieTimeout" 3600
|
||||
|
||||
# Set the default temp dir
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "MISP.tmpdir" "${PATH_TO_MISP}/app/tmp"
|
||||
|
||||
# Change base url, either with this CLI command or in the UI
|
||||
[[ ! -z ${MISP_BASEURL} ]] && ${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Baseurl $MISP_BASEURL
|
||||
# example: 'baseurl' => 'https://<your.FQDN.here>',
|
||||
|
@ -1562,7 +1566,7 @@ coreCAKE () {
|
|||
# Enable installer org and tune some configurables
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "MISP.host_org_id" 1
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "MISP.email" "info@admin.test"
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "MISP.disable_emailing" true
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "MISP.disable_emailing" true --force
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "MISP.contact" "info@admin.test"
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "MISP.disablerestalert" true
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "MISP.showCorrelationsOnIndex" true
|
||||
|
@ -1573,7 +1577,7 @@ coreCAKE () {
|
|||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "Plugin.Cortex_services_url" "http://127.0.0.1"
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "Plugin.Cortex_services_port" 9000
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "Plugin.Cortex_timeout" 120
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "Plugin.Cortex_authkey" ""
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "Plugin.Cortex_authkey" false
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "Plugin.Cortex_ssl_verify_peer" false
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "Plugin.Cortex_ssl_verify_host" false
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "Plugin.Cortex_ssl_allow_self_signed" true
|
||||
|
@ -1632,7 +1636,7 @@ coreCAKE () {
|
|||
Plugin.ElasticSearch_logging_enable
|
||||
Plugin.S3_enable)
|
||||
for PLUG in "${PLUGS[@]}"; do
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting ${PLUG} false
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting ${PLUG} false 2> /dev/null
|
||||
done
|
||||
|
||||
# Plugin CustomAuth tuneable
|
||||
|
@ -1648,7 +1652,7 @@ coreCAKE () {
|
|||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "Plugin.RPZ_minimum_ttl" "1h"
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "Plugin.RPZ_ttl" "1w"
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "Plugin.RPZ_ns" "localhost."
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "Plugin.RPZ_ns_alt" ""
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "Plugin.RPZ_ns_alt" false
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "Plugin.RPZ_email" "root.localhost"
|
||||
|
||||
# Kafka settings
|
||||
|
@ -1899,6 +1903,7 @@ mispmodules () {
|
|||
# If you build an egg, the user you build it as need write permissions in the CWD
|
||||
sudo chgrp $WWW_USER .
|
||||
sudo chmod og+w .
|
||||
$SUDO_WWW ${PATH_TO_MISP}/venv/bin/pip install pillow
|
||||
$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 .
|
||||
|
@ -3045,10 +3050,6 @@ installSupported () {
|
|||
echo "Proceeding with the installation of MISP core"
|
||||
space
|
||||
|
||||
# Set Base URL - functionLocation('generic/supportFunctions.md')
|
||||
[[ -n $CORE ]] || [[ -n $ALL ]] && setBaseURL
|
||||
progress 4
|
||||
|
||||
# Check if sudo is installed and etckeeper - functionLocation('generic/sudo_etckeeper.md')
|
||||
[[ -n $CORE ]] || [[ -n $ALL ]] && checkSudoKeeper
|
||||
[[ ! -z ${MISP_USER} ]] && [[ ! -f /etc/sudoers.d/misp ]] && echo "%${MISP_USER} ALL=(ALL:ALL) NOPASSWD:ALL" |sudo tee /etc/sudoers.d/misp
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
; Generated by RHash v1.3.9 on 2021-10-18 at 10:56.53
|
||||
; Generated by RHash v1.4.2 on 2021-11-04 at 15:44.11
|
||||
; Written by Kravchenko Aleksey (Akademgorodok) - http://rhash.sf.net/
|
||||
;
|
||||
; 160201 10:56.53 2021-10-18 INSTALL.sh
|
||||
INSTALL.sh 8F59974F7AE69DFBF7B1C492E35F0B421AAC10C1 6F9E9C2C24880D2E69E04AB6AE490F72D8B5CBE5BB98596F4FA50C1CFEAA632F CBCFBA692B57E027A9861C4D4FB1D4808511A23148516946802B0364D428638E60087AD6EA7E2F016B2F65CD216DE288 7221893A49C924974F7D28C094C6CB27FC8ACA6E07FECD7B8DE4D55D283C9D6A5FF63409F55EEC110BF6612E8578BD1373E39B83A7986A6369ACF32A6A92F538
|
||||
; 160342 15:44.11 2021-11-04 INSTALL.sh
|
||||
INSTALL.sh E10075FB44DD06A1C4248264085BDC8217B900CC 30E5EDCE721AF81B18744CA7B2062147BCF873FB5FE71798B8543EBA52F4FB4C 1E68603F4304D5B4EAA456A6B8A9A79C2CE86C48D595C9DCCD341A0D8959C52A7A9EEF0B3ABDB1C3534023350BC18B64 FAFAE6A7E6BD81C87AA1C90CD52721BF314BAD6BB41B33CF3E1E8070E5DDCA786761A6205AD104BF565DE68E4FF100EC7D55837D4F9CAD60A72825BCFFBE5D65
|
||||
|
|
|
@ -1 +1 @@
|
|||
8f59974f7ae69dfbf7b1c492e35f0b421aac10c1 INSTALL.sh
|
||||
e10075fb44dd06a1c4248264085bdc8217b900cc INSTALL.sh
|
||||
|
|
|
@ -1 +1 @@
|
|||
6f9e9c2c24880d2e69e04ab6ae490f72d8b5cbe5bb98596f4fa50c1cfeaa632f INSTALL.sh
|
||||
30e5edce721af81b18744ca7b2062147bcf873fb5fe71798b8543eba52f4fb4c INSTALL.sh
|
||||
|
|
|
@ -1 +1 @@
|
|||
cbcfba692b57e027a9861c4d4fb1d4808511a23148516946802b0364d428638e60087ad6ea7e2f016b2f65cd216de288 INSTALL.sh
|
||||
1e68603f4304d5b4eaa456a6b8a9a79c2ce86c48d595c9dccd341a0d8959c52a7a9eef0b3abdb1c3534023350bc18b64 INSTALL.sh
|
||||
|
|
|
@ -1 +1 @@
|
|||
7221893a49c924974f7d28c094c6cb27fc8aca6e07fecd7b8de4d55d283c9d6a5ff63409f55eec110bf6612e8578bd1373e39b83a7986a6369acf32a6a92f538 INSTALL.sh
|
||||
fafae6a7e6bd81c87aa1c90cd52721bf314bad6bb41b33cf3e1e8070e5ddca786761a6205ad104bf565de68e4ff100ec7d55837d4f9cad60a72825bcffbe5d65 INSTALL.sh
|
||||
|
|
|
@ -260,10 +260,6 @@ installSupported () {
|
|||
echo "Proceeding with the installation of MISP core"
|
||||
space
|
||||
|
||||
# Set Base URL - functionLocation('generic/supportFunctions.md')
|
||||
[[ -n $CORE ]] || [[ -n $ALL ]] && setBaseURL
|
||||
progress 4
|
||||
|
||||
# Check if sudo is installed and etckeeper - functionLocation('generic/sudo_etckeeper.md')
|
||||
[[ -n $CORE ]] || [[ -n $ALL ]] && checkSudoKeeper
|
||||
[[ ! -z ${MISP_USER} ]] && [[ ! -f /etc/sudoers.d/misp ]] && echo "%${MISP_USER} ALL=(ALL:ALL) NOPASSWD:ALL" |sudo tee /etc/sudoers.d/misp
|
||||
|
|
|
@ -51,7 +51,6 @@ $config = array(
|
|||
'unpublishedprivate' => false,
|
||||
'disable_emailing' => false,
|
||||
'manage_workers' => true,
|
||||
'Attributes_Values_Filter_In_Event' => 'id, uuid, value, comment, type, category, Tag.name',
|
||||
'python_bin' => null,
|
||||
'external_baseurl' => '',
|
||||
'forceHTTPSforPreLoginRequestedURL' => false,
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* AppShell file
|
||||
*
|
||||
* PHP 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @since CakePHP(tm) v 2.0
|
||||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
App::uses('Shell', 'Console', 'AppModel', 'Model');
|
||||
|
||||
/**
|
||||
* Application Shell
|
||||
*
|
||||
* Add your application-wide methods in the class below, your shells
|
||||
* will inherit them.
|
||||
*
|
||||
* @package app.Console.Command
|
||||
*/
|
||||
class AppShell extends Shell {
|
||||
public function perform() {
|
||||
$this->initialize();
|
||||
$this->{array_shift($this->args)}();
|
||||
}
|
||||
}
|
|
@ -22,12 +22,18 @@ class AdminShell extends AppShell
|
|||
'value' => ['help' => __('Setting value'), 'required' => true],
|
||||
],
|
||||
'options' => [
|
||||
'force' => array(
|
||||
'force' => [
|
||||
'short' => 'f',
|
||||
'help' => 'Force the command.',
|
||||
'default' => false,
|
||||
'boolean' => true
|
||||
)
|
||||
],
|
||||
'null' => [
|
||||
'short' => 'n',
|
||||
'help' => 'Set the value to null.',
|
||||
'default' => false,
|
||||
'boolean' => true
|
||||
],
|
||||
]
|
||||
],
|
||||
]);
|
||||
|
@ -375,14 +381,13 @@ class AdminShell extends AppShell
|
|||
|
||||
public function getSetting()
|
||||
{
|
||||
$this->ConfigLoad->execute();
|
||||
$param = empty($this->args[0]) ? 'all' : $this->args[0];
|
||||
$settings = $this->Server->serverSettingsRead();
|
||||
$result = $settings;
|
||||
if ($param != 'all') {
|
||||
if ($param !== 'all') {
|
||||
$result = 'No valid setting found for ' . $param;
|
||||
foreach ($settings as $setting) {
|
||||
if ($setting['setting'] == $param) {
|
||||
if ($setting['setting'] === $param) {
|
||||
$result = $setting;
|
||||
break;
|
||||
}
|
||||
|
@ -393,15 +398,17 @@ class AdminShell extends AppShell
|
|||
|
||||
public function setSetting()
|
||||
{
|
||||
$setting_name = !isset($this->args[0]) ? null : $this->args[0];
|
||||
$value = !isset($this->args[1]) ? null : $this->args[1];
|
||||
list($setting_name, $value) = $this->args;
|
||||
if ($value === 'false') {
|
||||
$value = 0;
|
||||
} elseif ($value === 'true') {
|
||||
$value = 1;
|
||||
}
|
||||
if ($this->params['null']) {
|
||||
$value = null;
|
||||
}
|
||||
$cli_user = array('id' => 0, 'email' => 'SYSTEM', 'Organisation' => array('name' => 'SYSTEM'));
|
||||
if (empty($setting_name) || $value === null) {
|
||||
if (empty($setting_name) || ($value === null && !$this->params['null'])) {
|
||||
die('Usage: ' . $this->Server->command_line_functions['console_admin_tasks']['data']['Set setting'] . PHP_EOL);
|
||||
}
|
||||
$setting = $this->Server->getSettingData($setting_name);
|
||||
|
@ -411,7 +418,7 @@ class AdminShell extends AppShell
|
|||
}
|
||||
$result = $this->Server->serverSettingsEditValue($cli_user, $setting, $value, $this->params['force']);
|
||||
if ($result === true) {
|
||||
echo 'Setting "' . $setting_name . '" changed to ' . $value . PHP_EOL;
|
||||
$this->out(__('Setting "%s" changed to %s', $setting_name, is_string($value) ? '"' . $value . '"' : (string)$value));
|
||||
} else {
|
||||
$message = __("The setting change was rejected. MISP considers the requested setting value as invalid and would lead to the following error:\n\n\"%s\"\n\nIf you still want to force this change, please supply the --force argument.\n", $result);
|
||||
$this->error(__('Setting change rejected.'), $message);
|
||||
|
|
|
@ -30,10 +30,10 @@ class AppShell extends Shell
|
|||
{
|
||||
public $tasks = array('ConfigLoad');
|
||||
|
||||
public function perform()
|
||||
public function initialize()
|
||||
{
|
||||
$this->initialize();
|
||||
$this->{array_shift($this->args)}();
|
||||
parent::initialize();
|
||||
$this->ConfigLoad->execute();
|
||||
}
|
||||
|
||||
protected function _welcome()
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
<?php
|
||||
class ConfigLoadTask extends Shell {
|
||||
public function execute() {
|
||||
class ConfigLoadTask extends Shell
|
||||
{
|
||||
public function execute()
|
||||
{
|
||||
Configure::load('config');
|
||||
|
||||
if (Configure::read('MISP.system_setting_db')) {
|
||||
App::uses('SystemSetting', 'Model');
|
||||
SystemSetting::setGlobalSetting();
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
|
|
@ -31,7 +31,7 @@ class AppController extends Controller
|
|||
*/
|
||||
public $defaultModel = '';
|
||||
|
||||
public $helpers = array('OrgImg', 'FontAwesome', 'UserName', 'DataPathCollector');
|
||||
public $helpers = array('OrgImg', 'FontAwesome', 'UserName');
|
||||
|
||||
private $__queryVersion = '131';
|
||||
public $pyMispVersion = '2.4.148';
|
||||
|
@ -97,6 +97,11 @@ class AppController extends Controller
|
|||
|
||||
public function beforeFilter()
|
||||
{
|
||||
if (Configure::read('MISP.system_setting_db')) {
|
||||
App::uses('SystemSetting', 'Model');
|
||||
SystemSetting::setGlobalSetting();
|
||||
}
|
||||
|
||||
$this->_setupBaseurl();
|
||||
$this->Auth->loginRedirect = $this->baseurl . '/users/routeafterlogin';
|
||||
|
||||
|
@ -342,7 +347,7 @@ class AppController extends Controller
|
|||
$this->User->Server->updateDatabase('cleanSessionTable');
|
||||
}
|
||||
}
|
||||
if (Configure::read('site_admin_debug') && (Configure::read('debug') < 2)) {
|
||||
if (Configure::read('site_admin_debug') && Configure::read('debug') < 2) {
|
||||
Configure::write('debug', 1);
|
||||
}
|
||||
}
|
||||
|
@ -373,7 +378,7 @@ class AppController extends Controller
|
|||
if (!empty($homepage)) {
|
||||
$this->set('homepage', $homepage);
|
||||
}
|
||||
if (version_compare(phpversion(), '8.0') >= 0) {
|
||||
if (PHP_MAJOR_VERSION >= 8) {
|
||||
$this->Flash->error(__('WARNING: MISP is currently running under PHP 8.0, which is unsupported. Background jobs will fail, so please contact your administrator to run a supported PHP version (such as 7.4)'));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,12 +11,23 @@ class AttributesController extends AppController
|
|||
{
|
||||
public $components = array('Security', 'RequestHandler');
|
||||
|
||||
public $paginate = array(
|
||||
public $paginate = [
|
||||
'limit' => 60,
|
||||
'maxLimit' => 9999,
|
||||
'conditions' => array('AND' => array('Attribute.deleted' => 0)),
|
||||
'order' => 'Attribute.event_id DESC'
|
||||
);
|
||||
'order' => 'Attribute.event_id DESC',
|
||||
'recursive' => -1,
|
||||
'contain' => array(
|
||||
'Event' => array(
|
||||
'fields' => array('Event.id', 'Event.orgc_id', 'Event.org_id', 'Event.info', 'Event.user_id', 'Event.date'),
|
||||
),
|
||||
'AttributeTag',
|
||||
'Object' => array(
|
||||
'fields' => array('Object.id', 'Object.distribution', 'Object.sharing_group_id')
|
||||
),
|
||||
'SharingGroup' => ['fields' => ['SharingGroup.name']],
|
||||
),
|
||||
];
|
||||
|
||||
public function beforeFilter()
|
||||
{
|
||||
|
@ -53,36 +64,19 @@ class AttributesController extends AppController
|
|||
$this->params->addParams(array('pass' => array($id))); // FIXME find better way to change id variable if uuid is found. params->url and params->here is not modified accordingly now
|
||||
}
|
||||
}
|
||||
// do not show private to other orgs
|
||||
if (!$this->_isSiteAdmin()) {
|
||||
$this->paginate = Set::merge($this->paginate, array('conditions' => $this->Attribute->buildConditions($this->Auth->user())));
|
||||
}
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$this->Attribute->recursive = -1;
|
||||
$this->paginate['recursive'] = -1;
|
||||
$this->paginate['contain'] = array(
|
||||
'Event' => array(
|
||||
'fields' => array('Event.id', 'Event.orgc_id', 'Event.org_id', 'Event.info', 'Event.user_id', 'Event.date'),
|
||||
),
|
||||
'AttributeTag' => array('Tag'),
|
||||
'Object' => array(
|
||||
'fields' => array('Object.id', 'Object.distribution', 'Object.sharing_group_id')
|
||||
),
|
||||
'SharingGroup' => ['fields' => ['SharingGroup.name']],
|
||||
);
|
||||
$this->Attribute->contain(array('AttributeTag' => array('Tag')));
|
||||
$this->set('isSearch', 0);
|
||||
$this->paginate['conditions']['AND'][] = $this->Attribute->buildConditions($this->Auth->user());
|
||||
$attributes = $this->paginate();
|
||||
|
||||
if ($this->_isRest()) {
|
||||
foreach ($attributes as $k => $attribute) {
|
||||
$attributes[$k] = $attribute['Attribute'];
|
||||
}
|
||||
$attributes = array_column($attributes, 'Attribute');
|
||||
return $this->RestResponse->viewData($attributes, $this->response->type());
|
||||
}
|
||||
|
||||
$this->Attribute->attachTagsToAttributes($attributes, ['includeAllTags' => true]);
|
||||
$orgTable = $this->Attribute->Event->Orgc->find('all', [
|
||||
'fields' => ['Orgc.id', 'Orgc.name', 'Orgc.uuid'],
|
||||
]);
|
||||
|
@ -94,6 +88,7 @@ class AttributesController extends AppController
|
|||
}
|
||||
|
||||
list($attributes, $sightingsData) = $this->__searchUI($attributes);
|
||||
$this->set('isSearch', 0);
|
||||
$this->set('sightingsData', $sightingsData);
|
||||
$this->set('orgTable', array_column($orgTable, 'name', 'id'));
|
||||
$this->set('shortDist', $this->Attribute->shortDist);
|
||||
|
@ -920,28 +915,25 @@ class AttributesController extends AppController
|
|||
if (empty($attribute)) {
|
||||
return new CakeResponse(array('body'=> json_encode(array('fail' => false, 'errors' => 'Invalid attribute')), 'status' => 200, 'type' => 'json'));
|
||||
}
|
||||
$this->Attribute->data = $attribute;
|
||||
$this->Attribute->id = $attribute['Attribute']['id'];
|
||||
if (!$this->__canModifyEvent($attribute)) {
|
||||
return new CakeResponse(array('body' => json_encode(array('fail' => false, 'errors' => 'You do not have permission to do that')), 'status' => 200, 'type' => 'json'));
|
||||
}
|
||||
if (!$this->_isRest()) {
|
||||
$this->Attribute->Event->insertLock($this->Auth->user(), $attribute['Attribute']['event_id']);
|
||||
}
|
||||
$validFields = array('value', 'category', 'type', 'comment', 'to_ids', 'distribution', 'first_seen', 'last_seen');
|
||||
$changed = false;
|
||||
if (empty($this->request->data['Attribute'])) {
|
||||
$this->request->data = array('Attribute' => $this->request->data);
|
||||
if (empty($this->request->data['Attribute'])) {
|
||||
throw new MethodNotAllowedException(__('Invalid input.'));
|
||||
}
|
||||
}
|
||||
$validFields = array('value', 'category', 'type', 'comment', 'to_ids', 'distribution', 'first_seen', 'last_seen');
|
||||
$changed = false;
|
||||
foreach ($this->request->data['Attribute'] as $changedKey => $changedField) {
|
||||
if (!in_array($changedKey, $validFields)) {
|
||||
if (!in_array($changedKey, $validFields, true)) {
|
||||
throw new MethodNotAllowedException(__('Invalid field.'));
|
||||
}
|
||||
if ($attribute['Attribute'][$changedKey] == $changedField) {
|
||||
$this->autoRender = false;
|
||||
return new CakeResponse(array('body'=> json_encode(array('errors'=> array('value' => 'nochange'))), 'status'=>200, 'type' => 'json'));
|
||||
}
|
||||
$attribute['Attribute'][$changedKey] = $changedField;
|
||||
|
@ -952,16 +944,23 @@ class AttributesController extends AppController
|
|||
}
|
||||
$date = new DateTime();
|
||||
$attribute['Attribute']['timestamp'] = $date->getTimestamp();
|
||||
if ($this->Attribute->save($attribute)) {
|
||||
$this->Attribute->Event->unpublishEvent($attribute['Attribute']['event_id']);
|
||||
|
||||
$fieldsToSave = ['timestamp'];
|
||||
if ($changedKey === 'value') {
|
||||
$fieldsToSave[] = 'value1';
|
||||
$fieldsToSave[] = 'value2';
|
||||
} else {
|
||||
$fieldsToSave[] = $changedKey;
|
||||
}
|
||||
|
||||
if ($this->Attribute->save($attribute, true, $fieldsToSave)) {
|
||||
$this->Attribute->Event->unpublishEvent($attribute['Attribute']['event_id'], false, $date->getTimestamp());
|
||||
|
||||
if ($attribute['Attribute']['object_id'] != 0) {
|
||||
$this->Attribute->Object->updateTimestamp($attribute['Attribute']['object_id'], $date->getTimestamp());
|
||||
}
|
||||
$this->autoRender = false;
|
||||
return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'success' => 'Field updated.', 'check_publish' => true)), 'status'=>200, 'type' => 'json'));
|
||||
} else {
|
||||
$this->autoRender = false;
|
||||
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => $this->Attribute->validationErrors)), 'status'=>200, 'type' => 'json'));
|
||||
}
|
||||
}
|
||||
|
@ -1577,25 +1576,9 @@ class AttributesController extends AppController
|
|||
if (!isset($params['conditions']['Attribute.deleted'])) {
|
||||
$params['conditions']['Attribute.deleted'] = 0;
|
||||
}
|
||||
$this->paginate = $params;
|
||||
if (empty($this->paginate['limit'])) {
|
||||
$this->paginate['limit'] = 60;
|
||||
}
|
||||
if (empty($this->paginate['page'])) {
|
||||
$this->paginate['page'] = 1;
|
||||
}
|
||||
$this->paginate['recursive'] = -1;
|
||||
$this->paginate['contain'] = array(
|
||||
'Event' => array(
|
||||
'fields' => array('Event.id', 'Event.orgc_id', 'Event.org_id', 'Event.info', 'Event.user_id', 'Event.date'),
|
||||
),
|
||||
'AttributeTag' => array('Tag'),
|
||||
'Object' => array(
|
||||
'fields' => array('Object.id', 'Object.distribution', 'Object.sharing_group_id')
|
||||
),
|
||||
'SharingGroup' => ['fields' => ['SharingGroup.name']],
|
||||
);
|
||||
$this->paginate['conditions'] = $params['conditions'];
|
||||
$attributes = $this->paginate();
|
||||
$this->Attribute->attachTagsToAttributes($attributes, ['includeAllTags' => true]);
|
||||
|
||||
$orgTable = $this->Attribute->Event->Orgc->find('all', [
|
||||
'fields' => ['Orgc.id', 'Orgc.name', 'Orgc.uuid'],
|
||||
|
@ -1649,7 +1632,7 @@ class AttributesController extends AppController
|
|||
}
|
||||
}
|
||||
|
||||
private function __searchUI($attributes)
|
||||
private function __searchUI(array $attributes)
|
||||
{
|
||||
if (empty($attributes)) {
|
||||
return [[], []];
|
||||
|
@ -1661,9 +1644,9 @@ class AttributesController extends AppController
|
|||
$this->loadModel('AttachmentScan');
|
||||
$user = $this->Auth->user();
|
||||
$attributeIds = [];
|
||||
foreach ($attributes as $k => $attribute) {
|
||||
$attributeId = $attribute['Attribute']['id'];
|
||||
$attributeIds[] = $attributeId;
|
||||
$galaxyTags = [];
|
||||
foreach ($attributes as &$attribute) {
|
||||
$attributeIds[] = $attribute['Attribute']['id'];
|
||||
if ($this->Attribute->isImage($attribute['Attribute'])) {
|
||||
if (extension_loaded('gd')) {
|
||||
// if extension is loaded, the data is not passed to the view because it is asynchronously fetched
|
||||
|
@ -1671,20 +1654,33 @@ class AttributesController extends AppController
|
|||
} else {
|
||||
$attribute['Attribute']['image'] = $this->Attribute->base64EncodeAttachment($attribute['Attribute']);
|
||||
}
|
||||
$attributes[$k] = $attribute;
|
||||
}
|
||||
if ($attribute['Attribute']['type'] === 'attachment' && $this->AttachmentScan->isEnabled()) {
|
||||
$infected = $this->AttachmentScan->isInfected(AttachmentScan::TYPE_ATTRIBUTE, $attribute['Attribute']['id']);
|
||||
$attributes[$k]['Attribute']['infected'] = $infected;
|
||||
$attribute['Attribute']['infected'] = $infected;
|
||||
}
|
||||
|
||||
if ($attribute['Attribute']['distribution'] == 4) {
|
||||
$attributes[$k]['Attribute']['SharingGroup'] = $attribute['SharingGroup'];
|
||||
$attribute['Attribute']['SharingGroup'] = $attribute['SharingGroup'];
|
||||
}
|
||||
|
||||
$attributes[$k]['Attribute']['AttributeTag'] = $attributes[$k]['AttributeTag'];
|
||||
$attributes[$k]['Attribute'] = $this->Attribute->Event->massageTags($this->Auth->user(), $attributes[$k]['Attribute'], 'Attribute', $excludeGalaxy = false, $cullGalaxyTags = true);
|
||||
unset($attributes[$k]['AttributeTag']);
|
||||
$attribute['Attribute']['AttributeTag'] = $attribute['AttributeTag'];
|
||||
foreach ($attribute['Attribute']['AttributeTag'] as $at) {
|
||||
if (substr($at['Tag']['name'], 0, 12) === 'misp-galaxy:') {
|
||||
$galaxyTags[] = $at['Tag']['name'];
|
||||
}
|
||||
}
|
||||
unset($attribute['AttributeTag']);
|
||||
}
|
||||
unset($attribute);
|
||||
|
||||
// Fetch galaxy clusters in one query
|
||||
if (!empty($galaxyTags)) {
|
||||
$this->loadModel('GalaxyCluster');
|
||||
$clusters = $this->GalaxyCluster->getClusters($galaxyTags, $user, true, false);
|
||||
$clusters = array_column(array_column($clusters, 'GalaxyCluster'), null, 'tag_id');
|
||||
} else {
|
||||
$clusters = [];
|
||||
}
|
||||
|
||||
// Fetch correlations in one query
|
||||
|
@ -1696,6 +1692,27 @@ class AttributesController extends AppController
|
|||
$attributesWithFeedCorrelations = $this->Feed->attachFeedCorrelations(array_column($attributes, 'Attribute'), $user, $fakeEventArray);
|
||||
|
||||
foreach ($attributes as $k => $attribute) {
|
||||
// Assign galaxies
|
||||
$galaxies = [];
|
||||
foreach ($attribute['Attribute']['AttributeTag'] as $k2 => $attributeTag) {
|
||||
if (!isset($clusters[$attributeTag['Tag']['id']])) {
|
||||
continue;
|
||||
}
|
||||
$cluster = $clusters[$attributeTag['Tag']['id']];
|
||||
$galaxyId = $cluster['Galaxy']['id'];
|
||||
$cluster['local'] = isset($attributeTag['local']) ? $attributeTag['local'] : false;
|
||||
if (isset($attribute['Attribute']['Galaxy'][$galaxyId])) {
|
||||
unset($cluster['Galaxy']);
|
||||
$galaxies[$galaxyId]['GalaxyCluster'][] = $cluster;
|
||||
} else {
|
||||
$galaxies[$galaxyId] = $cluster['Galaxy'];
|
||||
unset($cluster['Galaxy']);
|
||||
$galaxies[$galaxyId]['GalaxyCluster'] = [$cluster];
|
||||
}
|
||||
unset($attributes[$k]['Attribute']['AttributeTag'][$k2]); // remove galaxy tag
|
||||
}
|
||||
$attributes[$k]['Attribute']['Galaxy'] = array_values($galaxies);
|
||||
|
||||
if (isset($attributesWithFeedCorrelations[$k]['Feed'])) {
|
||||
$attributes[$k]['Attribute']['Feed'] = $attributesWithFeedCorrelations[$k]['Feed'];
|
||||
}
|
||||
|
@ -1707,65 +1724,6 @@ class AttributesController extends AppController
|
|||
return array($attributes, $sightingsData);
|
||||
}
|
||||
|
||||
// If the checkbox for the alternate search is ticked, then this method is called to return the data to be represented
|
||||
// This alternate view will show a list of events with matching search results and the percentage of those matched attributes being marked as to_ids
|
||||
// events are sorted based on relevance (as in the percentage of matches being flagged as indicators for IDS)
|
||||
public function searchAlternate($data)
|
||||
{
|
||||
$attributes = $this->Attribute->fetchAttributes(
|
||||
$this->Auth->user(),
|
||||
array(
|
||||
'conditions' => array(
|
||||
'AND' => $data
|
||||
),
|
||||
'contain' => array('Event' => array('Orgc' => array('fields' => array('Orgc.name')))),
|
||||
'fields' => array(
|
||||
'Attribute.id', 'Attribute.event_id', 'Attribute.type', 'Attribute.category', 'Attribute.to_ids', 'Attribute.value', 'Attribute.distribution',
|
||||
'Event.id', 'Event.org_id', 'Event.orgc_id', 'Event.info', 'Event.distribution', 'Event.attribute_count', 'Event.date',
|
||||
)
|
||||
)
|
||||
);
|
||||
$events = array();
|
||||
foreach ($attributes as $attribute) {
|
||||
if (isset($events[$attribute['Event']['id']])) {
|
||||
if ($attribute['Attribute']['to_ids']) {
|
||||
$events[$attribute['Event']['id']]['to_ids']++;
|
||||
} else {
|
||||
$events[$attribute['Event']['id']]['no_ids']++;
|
||||
}
|
||||
} else {
|
||||
$events[$attribute['Event']['id']]['Event'] = $attribute['Event'];
|
||||
$events[$attribute['Event']['id']]['to_ids'] = 0;
|
||||
$events[$attribute['Event']['id']]['no_ids'] = 0;
|
||||
if ($attribute['Attribute']['to_ids']) {
|
||||
$events[$attribute['Event']['id']]['to_ids']++;
|
||||
} else {
|
||||
$events[$attribute['Event']['id']]['no_ids']++;
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($events as $key => $event) {
|
||||
$events[$key]['relevance'] = 100 * $event['to_ids'] / ($event['no_ids'] + $event['to_ids']);
|
||||
}
|
||||
if (!empty($events)) {
|
||||
$events = $this->__subval_sort($events, 'relevance');
|
||||
}
|
||||
return $events;
|
||||
}
|
||||
|
||||
// Sort the array of arrays based on a value of a sub-array
|
||||
private function __subval_sort($a, $subkey)
|
||||
{
|
||||
foreach ($a as $k=>$v) {
|
||||
$b[$k] = strtolower($v[$subkey]);
|
||||
}
|
||||
arsort($b);
|
||||
foreach ($b as $key=>$val) {
|
||||
$c[] = $a[$key];
|
||||
}
|
||||
return $c;
|
||||
}
|
||||
|
||||
public function checkComposites()
|
||||
{
|
||||
if (!self::_isAdmin()) {
|
||||
|
|
|
@ -37,6 +37,7 @@ class AuditLogsController extends AppController
|
|||
'Server',
|
||||
'ShadowAttribute',
|
||||
'SharingGroup',
|
||||
'SystemSetting',
|
||||
'Tag',
|
||||
'TagCollection',
|
||||
'TagCollectionTag',
|
||||
|
@ -484,10 +485,12 @@ class AuditLogsController extends AppController
|
|||
|
||||
if (!empty($eventIds)) {
|
||||
$this->loadModel('Event');
|
||||
$events = $this->Event->fetchSimpleEvents($this->Auth->user(), [
|
||||
'conditions' => ['Event.id' => array_unique($eventIds)],
|
||||
$conditions = $this->Event->createEventConditions($this->Auth->user());
|
||||
$conditions['Event.id'] = array_unique($eventIds);
|
||||
$events = $this->Event->find('list', [
|
||||
'conditions' => $conditions,
|
||||
'fields' => ['Event.id', 'Event.info'],
|
||||
]);
|
||||
$events = array_column(array_column($events, 'Event'), null, 'id');
|
||||
}
|
||||
|
||||
$links = [
|
||||
|
@ -525,7 +528,7 @@ class AuditLogsController extends AppController
|
|||
case 'Event':
|
||||
if (isset($events[$modelId])) {
|
||||
$url = '/events/view/' . $modelId;
|
||||
$eventInfo = $events[$modelId]['info'];
|
||||
$eventInfo = $events[$modelId];
|
||||
}
|
||||
break;
|
||||
case 'ObjectReference':
|
||||
|
@ -535,7 +538,7 @@ class AuditLogsController extends AppController
|
|||
$url .= '/deleted:2';
|
||||
}
|
||||
if (isset($events[$objects[$objectReferences[$modelId]]['event_id']])) {
|
||||
$eventInfo = $events[$objects[$objectReferences[$modelId]]['event_id']]['info'];
|
||||
$eventInfo = $events[$objects[$objectReferences[$modelId]]['event_id']];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -546,7 +549,7 @@ class AuditLogsController extends AppController
|
|||
$url .= '/deleted:2';
|
||||
}
|
||||
if (isset($events[$objects[$modelId]['event_id']])) {
|
||||
$eventInfo = $events[$objects[$modelId]['event_id']]['info'];
|
||||
$eventInfo = $events[$objects[$modelId]['event_id']];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -557,7 +560,7 @@ class AuditLogsController extends AppController
|
|||
$url .= '/deleted:2';
|
||||
}
|
||||
if (isset($events[$attributes[$modelId]['event_id']])) {
|
||||
$eventInfo = $events[$attributes[$modelId]['event_id']]['info'];
|
||||
$eventInfo = $events[$attributes[$modelId]['event_id']];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -565,7 +568,7 @@ class AuditLogsController extends AppController
|
|||
if (isset($shadowAttributes[$modelId])) {
|
||||
$url = '/events/view/' . $shadowAttributes[$modelId]['event_id'] . '/focus:' . $shadowAttributes[$modelId]['uuid'];
|
||||
if (isset($events[$shadowAttributes[$modelId]['event_id']])) {
|
||||
$eventInfo = $events[$shadowAttributes[$modelId]['event_id']]['info'];
|
||||
$eventInfo = $events[$shadowAttributes[$modelId]['event_id']];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -54,7 +54,6 @@ class ACLComponent extends Component
|
|||
'returnAttributes' => array('*'),
|
||||
'rpz' => array('*'),
|
||||
'search' => array('*'),
|
||||
'searchAlternate' => array('*'),
|
||||
'toggleCorrelation' => array('perm_add'),
|
||||
'text' => array('*'),
|
||||
'toggleToIDS' => array('perm_add'),
|
||||
|
|
|
@ -372,7 +372,7 @@ class OrganisationsController extends AppController
|
|||
}
|
||||
$idList = json_decode($idList, true);
|
||||
$id_exclusion_list = array_merge($idList, array($this->Auth->user('Organisation')['id']));
|
||||
$temp = $this->Organisation->find('all', array(
|
||||
$orgs = $this->Organisation->find('list', array(
|
||||
'conditions' => array(
|
||||
'local' => $local,
|
||||
'id !=' => $id_exclusion_list,
|
||||
|
@ -381,10 +381,6 @@ class OrganisationsController extends AppController
|
|||
'fields' => array('id', 'name'),
|
||||
'order' => array('lower(name) ASC')
|
||||
));
|
||||
$orgs = array();
|
||||
foreach ($temp as $org) {
|
||||
$orgs[] = array('id' => $org['Organisation']['id'], 'name' => $org['Organisation']['name']);
|
||||
}
|
||||
$this->set('local', $local);
|
||||
$this->layout = false;
|
||||
$this->autoRender = false;
|
||||
|
@ -402,10 +398,13 @@ class OrganisationsController extends AppController
|
|||
$this->render('ajax/sg_org_row_empty');
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Probably not used anywhere.
|
||||
*/
|
||||
public function getUUIDs()
|
||||
{
|
||||
if (!$this->Auth->user('Role')['perm_sync']) {
|
||||
throw new MethodNotAllowedException(__('This action is restricted to sync users'));
|
||||
if (Configure::read('Security.hide_organisation_index_from_users')) {
|
||||
throw new MethodNotAllowedException(__('This action is not enabled on this instance.'));
|
||||
}
|
||||
$temp = $this->Organisation->find('all', array(
|
||||
'recursive' => -1,
|
||||
|
|
|
@ -1485,8 +1485,8 @@ class ServersController extends AppController
|
|||
}
|
||||
}
|
||||
$this->autoRender = false;
|
||||
if (!Configure::read('MISP.system_setting_db') && !is_writeable(APP . 'Config/config.php')) {
|
||||
$this->loadModel('Log');
|
||||
if (!is_writeable(APP . 'Config/config.php')) {
|
||||
$this->Log->create();
|
||||
$this->Log->save(array(
|
||||
'org' => $this->Auth->user('Organisation')['name'],
|
||||
|
|
|
@ -1210,8 +1210,7 @@ class UsersController extends AppController
|
|||
}
|
||||
}
|
||||
// populate the DB with the first role (site admin) if it's empty
|
||||
$this->loadModel('Role');
|
||||
if ($this->Role->find('count') == 0) {
|
||||
if (!$this->User->Role->hasAny()) {
|
||||
$siteAdmin = array('Role' => array(
|
||||
'id' => 1,
|
||||
'name' => 'Site Admin',
|
||||
|
@ -1230,14 +1229,14 @@ class UsersController extends AppController
|
|||
'perm_template' => 1,
|
||||
'perm_tagger' => 1,
|
||||
));
|
||||
$this->Role->save($siteAdmin);
|
||||
$this->User->Role->save($siteAdmin);
|
||||
// PostgreSQL: update value of auto incremented serial primary key after setting the column by force
|
||||
if ($dataSource == 'Database/Postgres') {
|
||||
if ($dataSource === 'Database/Postgres') {
|
||||
$sql = "SELECT setval('roles_id_seq', (SELECT MAX(id) FROM roles));";
|
||||
$this->Role->query($sql);
|
||||
$this->User->Role->query($sql);
|
||||
}
|
||||
}
|
||||
if ($this->User->Organisation->find('count', array('conditions' => array('Organisation.local' => true))) == 0) {
|
||||
if (!$this->User->Organisation->hasAny(array('Organisation.local' => true))) {
|
||||
$this->User->runUpdates();
|
||||
$date = date('Y-m-d H:i:s');
|
||||
$org = array('Organisation' => array(
|
||||
|
@ -1253,12 +1252,16 @@ class UsersController extends AppController
|
|||
));
|
||||
$this->User->Organisation->save($org);
|
||||
// PostgreSQL: update value of auto incremented serial primary key after setting the column by force
|
||||
if ($dataSource == 'Database/Postgres') {
|
||||
if ($dataSource === 'Database/Postgres') {
|
||||
$sql = "SELECT setval('organisations_id_seq', (SELECT MAX(id) FROM organisations));";
|
||||
$this->User->Organisation->query($sql);
|
||||
}
|
||||
$org_id = $this->User->Organisation->id;
|
||||
} else {
|
||||
}
|
||||
|
||||
// populate the DB with the first user if it's empty
|
||||
if (!$this->User->hasAny()) {
|
||||
if (!isset($org_id)) {
|
||||
$hostOrg = $this->User->Organisation->find('first', array('conditions' => array('Organisation.name' => Configure::read('MISP.org'), 'Organisation.local' => true), 'recursive' => -1));
|
||||
if (!empty($hostOrg)) {
|
||||
$org_id = $hostOrg['Organisation']['id'];
|
||||
|
@ -1268,8 +1271,6 @@ class UsersController extends AppController
|
|||
}
|
||||
}
|
||||
|
||||
// populate the DB with the first user if it's empty
|
||||
if ($this->User->find('count') == 0) {
|
||||
$this->User->runUpdates();
|
||||
$this->User->createInitialUser($org_id);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
|
||||
class BetterSecurity
|
||||
{
|
||||
const METHOD = 'AES-256-GCM';
|
||||
const TAG_SIZE = 16;
|
||||
|
||||
/**
|
||||
* @param string $plain
|
||||
* @param string $key
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function encrypt($plain, $key)
|
||||
{
|
||||
if (strlen($key) < 32) {
|
||||
throw new Exception('Invalid key, key must be at least 256 bits (32 bytes) long.');
|
||||
}
|
||||
|
||||
// Generate the encryption key.
|
||||
$key = hash('sha256', $key, true);
|
||||
|
||||
$ivlen = openssl_cipher_iv_length(self::METHOD);
|
||||
$iv = openssl_random_pseudo_bytes($ivlen);
|
||||
if ($iv === false) {
|
||||
throw new Exception('Could not generate random bytes.');
|
||||
}
|
||||
$ciphertext = openssl_encrypt($plain, self::METHOD, $key, OPENSSL_RAW_DATA, $iv, $tag);
|
||||
if ($ciphertext === false) {
|
||||
throw new Exception('Could not encrypt.');
|
||||
}
|
||||
return $iv . $tag . $ciphertext;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $cipher
|
||||
* @param string $key
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function decrypt($cipher, $key)
|
||||
{
|
||||
if (strlen($key) < 32) {
|
||||
throw new Exception('Invalid key, key must be at least 256 bits (32 bytes) long.');
|
||||
}
|
||||
if (empty($cipher)) {
|
||||
throw new Exception('The data to decrypt cannot be empty.');
|
||||
}
|
||||
|
||||
// Generate the encryption key.
|
||||
$key = hash('sha256', $key, true);
|
||||
|
||||
$ivSize = openssl_cipher_iv_length(self::METHOD);
|
||||
|
||||
// Split out hmac for comparison
|
||||
$iv = substr($cipher, 0, $ivSize);
|
||||
$tag = substr($cipher, $ivSize, self::TAG_SIZE);
|
||||
$cipher = substr($cipher, $ivSize + self::TAG_SIZE);
|
||||
|
||||
$decrypted = openssl_decrypt($cipher, self::METHOD, $key, true, $iv, $tag);
|
||||
if ($decrypted === false) {
|
||||
throw new Exception('Could not decrypt. Maybe invalid encryption key?');
|
||||
}
|
||||
return $decrypted;
|
||||
}
|
||||
}
|
|
@ -23,11 +23,11 @@
|
|||
App::uses('Model', 'Model');
|
||||
App::uses('LogableBehavior', 'Assets.models/behaviors');
|
||||
App::uses('RandomTool', 'Tools');
|
||||
App::uses('FileAccessTool', 'Tools');
|
||||
App::uses('JsonTool', 'Tools');
|
||||
|
||||
class AppModel extends Model
|
||||
{
|
||||
public $name;
|
||||
|
||||
/** @var PubSubTool */
|
||||
private static $loadedPubSubTool;
|
||||
|
||||
|
@ -42,7 +42,7 @@ class AppModel extends Model
|
|||
|
||||
private $__profiler = array();
|
||||
|
||||
public $elasticSearchClient = false;
|
||||
public $elasticSearchClient;
|
||||
|
||||
/** @var AttachmentTool|null */
|
||||
private $attachmentTool;
|
||||
|
@ -50,8 +50,6 @@ class AppModel extends Model
|
|||
public function __construct($id = false, $table = null, $ds = null)
|
||||
{
|
||||
parent::__construct($id, $table, $ds);
|
||||
|
||||
$this->name = get_class($this);
|
||||
$this->findMethods['column'] = true;
|
||||
}
|
||||
|
||||
|
@ -87,7 +85,7 @@ class AppModel extends Model
|
|||
57 => false, 58 => false, 59 => false, 60 => false, 61 => false, 62 => false,
|
||||
63 => true, 64 => false, 65 => false, 66 => false, 67 => false, 68 => false,
|
||||
69 => false, 70 => false, 71 => true, 72 => true, 73 => false, 74 => false,
|
||||
75 => false, 76 => false
|
||||
75 => false, 76 => true, 77 => true
|
||||
);
|
||||
|
||||
public $advanced_updates_description = array(
|
||||
|
@ -1537,7 +1535,7 @@ class AppModel extends Model
|
|||
`value` text NOT NULL,
|
||||
`from_json` tinyint(1) default 0,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE INDEX `value` (`value`(255))
|
||||
UNIQUE INDEX `value` (`value`(191))
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;";
|
||||
break;
|
||||
case 66:
|
||||
|
@ -1597,6 +1595,13 @@ class AppModel extends Model
|
|||
$this->__dropIndex('object_references', 'referenced_uuid');
|
||||
break;
|
||||
case 76:
|
||||
$sqlArray[] = "CREATE TABLE IF NOT EXISTS `system_settings` (
|
||||
`setting` varchar(255) NOT NULL,
|
||||
`value` blob NOT NULL,
|
||||
PRIMARY KEY (`setting`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;";
|
||||
break;
|
||||
case 77:
|
||||
$sqlArray[] = "ALTER TABLE `jobs` MODIFY COLUMN `process_id` varchar(36) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL;";
|
||||
case 'fixNonEmptySharingGroupID':
|
||||
$sqlArray[] = 'UPDATE `events` SET `sharing_group_id` = 0 WHERE `distribution` != 4;';
|
||||
|
@ -1989,7 +1994,8 @@ class AppModel extends Model
|
|||
}
|
||||
|
||||
// Try to create a table with a BIGINT(20)
|
||||
public function seenOnAttributeAndObjectPreUpdate() {
|
||||
public function seenOnAttributeAndObjectPreUpdate()
|
||||
{
|
||||
$sqlArray[] = "CREATE TABLE IF NOT EXISTS testtable (
|
||||
`testfield` BIGINT(6) NULL DEFAULT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;";
|
||||
|
@ -2007,10 +2013,6 @@ class AppModel extends Model
|
|||
}
|
||||
}
|
||||
|
||||
public function failingPreUpdate() {
|
||||
throw new Exception('Yolo fail');
|
||||
}
|
||||
|
||||
public function runUpdates($verbose = false, $useWorker = true, $processId = false)
|
||||
{
|
||||
$this->AdminSetting = ClassRegistry::init('AdminSetting');
|
||||
|
@ -2379,6 +2381,10 @@ class AppModel extends Model
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $db_version
|
||||
* @return array
|
||||
*/
|
||||
protected function findUpgrades($db_version)
|
||||
{
|
||||
$updates = array();
|
||||
|
@ -2503,13 +2509,6 @@ class AppModel extends Model
|
|||
public function getKafkaPubTool()
|
||||
{
|
||||
if (!$this->loadedKafkaPubTool) {
|
||||
$this->loadKafkaPubTool();
|
||||
}
|
||||
return $this->loadedKafkaPubTool;
|
||||
}
|
||||
|
||||
public function loadKafkaPubTool()
|
||||
{
|
||||
App::uses('KafkaPubTool', 'Tools');
|
||||
$kafkaPubTool = new KafkaPubTool();
|
||||
$rdkafkaIni = Configure::read('Plugin.Kafka_rdkafka_config');
|
||||
|
@ -2520,7 +2519,8 @@ class AppModel extends Model
|
|||
$brokers = Configure::read('Plugin.Kafka_brokers');
|
||||
$kafkaPubTool->initTool($brokers, $kafkaConf);
|
||||
$this->loadedKafkaPubTool = $kafkaPubTool;
|
||||
return true;
|
||||
}
|
||||
return $this->loadedKafkaPubTool;
|
||||
}
|
||||
|
||||
public function publishKafkaNotification($topicName, $data, $action = false)
|
||||
|
@ -2671,15 +2671,6 @@ class AppModel extends Model
|
|||
}
|
||||
}
|
||||
|
||||
public function getRowCount($table = false)
|
||||
{
|
||||
if (empty($table)) {
|
||||
$table = $this->table;
|
||||
}
|
||||
$table_data = $this->query("show table status like '" . $table . "'");
|
||||
return $table_data[0]['TABLES']['Rows'];
|
||||
}
|
||||
|
||||
public function benchmarkCustomAdd($valueToAdd = 0, $name = 'default', $customName = 'custom')
|
||||
{
|
||||
if (empty($this->__profiler[$name]['custom'][$customName])) {
|
||||
|
@ -2742,9 +2733,8 @@ class AppModel extends Model
|
|||
{
|
||||
static $versionArray;
|
||||
if ($versionArray === null) {
|
||||
$file = new File(ROOT . DS . 'VERSION.json');
|
||||
$versionArray = $this->jsonDecode($file->read());
|
||||
$file->close();
|
||||
$content = FileAccessTool::readFromFile(ROOT . DS . 'VERSION.json');
|
||||
$versionArray = JsonTool::decode($content);
|
||||
}
|
||||
return $versionArray;
|
||||
}
|
||||
|
@ -3110,10 +3100,7 @@ class AppModel extends Model
|
|||
$message .= "\n";
|
||||
|
||||
do {
|
||||
$message .= sprintf("[%s] %s",
|
||||
get_class($exception),
|
||||
$exception->getMessage()
|
||||
);
|
||||
$message .= sprintf("[%s] %s", get_class($exception), $exception->getMessage());
|
||||
$message .= "\nStack Trace:\n" . $exception->getTraceAsString();
|
||||
$exception = $exception->getPrevious();
|
||||
} while ($exception !== null);
|
||||
|
|
|
@ -2031,7 +2031,7 @@ class Attribute extends AppModel
|
|||
'Event' => array(
|
||||
'fields' => array('id', 'info', 'org_id', 'orgc_id', 'uuid'),
|
||||
),
|
||||
'AttributeTag', // tags are fetched separately, @see Attribute::__attachTagsToAttributes
|
||||
'AttributeTag', // tags are fetched separately, @see Attribute::attachTagsToAttributes
|
||||
'Object' => array(
|
||||
'fields' => array('id', 'distribution', 'sharing_group_id')
|
||||
)
|
||||
|
@ -2232,7 +2232,7 @@ class Attribute extends AppModel
|
|||
unset($eventsById, $result); // unset result is important, because it is reference
|
||||
}
|
||||
|
||||
$this->__attachTagsToAttributes($results, $options);
|
||||
$this->attachTagsToAttributes($results, $options);
|
||||
|
||||
foreach ($results as $k => $result) {
|
||||
if (!empty($options['includeSightings'])) {
|
||||
|
@ -2361,7 +2361,14 @@ class Attribute extends AppModel
|
|||
return $eventsById;
|
||||
}
|
||||
|
||||
private function __attachTagsToAttributes(array &$attributes, array $options)
|
||||
/**
|
||||
* Options:
|
||||
* - includeAllTags - if true, include also exportable tags
|
||||
*
|
||||
* @param array $attributes
|
||||
* @param array $options
|
||||
*/
|
||||
public function attachTagsToAttributes(array &$attributes, array $options)
|
||||
{
|
||||
$tagIdsToFetch = [];
|
||||
foreach ($attributes as $attribute) {
|
||||
|
@ -2382,15 +2389,12 @@ class Attribute extends AppModel
|
|||
$conditions['Tag.exportable'] = 1;
|
||||
}
|
||||
|
||||
$tagsToModify = $this->AttributeTag->Tag->find('all', [
|
||||
$tags = $this->AttributeTag->Tag->find('all', [
|
||||
'conditions' => $conditions,
|
||||
'fields' => ['id', 'name', 'colour', 'numerical_value'],
|
||||
'recursive' => -1,
|
||||
]);
|
||||
$tags = [];
|
||||
foreach ($tagsToModify as $tag) {
|
||||
$tags[$tag['Tag']['id']] = $tag['Tag'];
|
||||
}
|
||||
$tags = array_column(array_column($tags, 'Tag'), null, 'id');
|
||||
|
||||
foreach ($attributes as $k => $attribute) {
|
||||
$tagCulled = false;
|
||||
|
|
|
@ -131,13 +131,17 @@ class AuditLog extends AppModel
|
|||
if (in_array($auditLog['model'], ['Attribute', 'Object', 'ShadowAttribute'], true)) {
|
||||
$modelName = $auditLog['model'] === 'ShadowAttribute' ? 'Proposal' : $auditLog['model'];
|
||||
$title = __('%s from Event #%s', $modelName, $auditLog['event_id']);
|
||||
} else {
|
||||
$title = "{$auditLog['model']} #{$auditLog['model_id']}";
|
||||
}
|
||||
|
||||
if (isset($auditLog['model_title']) && $auditLog['model_title']) {
|
||||
if (isset($title)) {
|
||||
$title .= ": {$auditLog['model_title']}";
|
||||
}
|
||||
return $title;
|
||||
} else {
|
||||
return $auditLog['model_title'];
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -39,6 +39,7 @@ class AuditLogBehavior extends ModelBehavior
|
|||
'TagCollection' => 'name',
|
||||
'Taxonomy' => 'namespace',
|
||||
'Organisation' => 'name',
|
||||
'SystemSetting' => 'setting',
|
||||
'AdminSetting' => 'setting',
|
||||
'UserSetting' => 'setting',
|
||||
'Galaxy' => 'name',
|
||||
|
@ -117,7 +118,7 @@ class AuditLogBehavior extends ModelBehavior
|
|||
return;
|
||||
}
|
||||
|
||||
$id = $model->id ?: null;
|
||||
$id = $model->id ?: 0;
|
||||
$data = $model->data[$model->alias];
|
||||
|
||||
if ($created) {
|
||||
|
@ -127,7 +128,7 @@ class AuditLogBehavior extends ModelBehavior
|
|||
if (isset($data['deleted'])) {
|
||||
if ($data['deleted']) {
|
||||
$action = AuditLog::ACTION_SOFT_DELETE;
|
||||
} else if ($this->old[$model->alias]['deleted']) {
|
||||
} else if (isset($this->old[$model->alias]['deleted']) && $this->old[$model->alias]['deleted']) {
|
||||
$action = AuditLog::ACTION_UNDELETE;
|
||||
}
|
||||
}
|
||||
|
@ -177,14 +178,14 @@ class AuditLogBehavior extends ModelBehavior
|
|||
}
|
||||
$id = $modelName === 'AttributeTag' ? $data['attribute_id'] : $data['event_id'];
|
||||
$modelName = $modelName === 'AttributeTag' ? 'Attribute' : 'Event';
|
||||
}
|
||||
|
||||
if ($modelName === 'Event') {
|
||||
} else if ($modelName === 'Event') {
|
||||
if (isset($changedFields['published'][1]) && $changedFields['published'][1]) {
|
||||
$action = AuditLog::ACTION_PUBLISH;
|
||||
} else if (isset($changedFields['sighting_timestamp'][1]) && $changedFields['sighting_timestamp'][1]) {
|
||||
$action = AuditLog::ACTION_PUBLISH_SIGHTINGS;
|
||||
}
|
||||
} else if ($modelName === 'SystemSetting') {
|
||||
$id = 0;
|
||||
}
|
||||
|
||||
$this->auditLog()->insert(['AuditLog' => [
|
||||
|
@ -253,6 +254,8 @@ class AuditLogBehavior extends ModelBehavior
|
|||
}
|
||||
$id = $modelName === 'AttributeTag' ? $model->data[$model->alias]['attribute_id'] : $model->data[$model->alias]['event_id'];
|
||||
$modelName = $modelName === 'AttributeTag' ? 'Attribute' : 'Event';
|
||||
} else if ($modelName === 'SystemSetting') {
|
||||
$id = 0;
|
||||
}
|
||||
|
||||
$this->auditLog()->insert(['AuditLog' => [
|
||||
|
@ -350,7 +353,7 @@ class AuditLogBehavior extends ModelBehavior
|
|||
continue;
|
||||
}
|
||||
|
||||
if ($key === 'password' || $key === 'authkey') {
|
||||
if ($key === 'password' || $key === 'authkey' || ($key === 'value' && $model->name === 'SystemSetting' && SystemSetting::isSensitive($model->data[$model->alias]['setting']))) {
|
||||
$value = '*****';
|
||||
if ($old !== null) {
|
||||
$old = $value;
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
<?php
|
||||
App::uses('AppModel', 'Model');
|
||||
App::uses('CakeEmail', 'Network/Email');
|
||||
App::uses('FileAccessTool', 'Tools');
|
||||
App::uses('AttachmentTool', 'Tools');
|
||||
App::uses('JsonTool', 'Tools');
|
||||
App::uses('TmpFileTool', 'Tools');
|
||||
App::uses('SendEmailTemplate', 'Tools');
|
||||
|
||||
|
@ -2362,10 +2360,7 @@ class Event extends AppModel
|
|||
return;
|
||||
}
|
||||
|
||||
$clustersByTagNames = [];
|
||||
foreach ($clusters as $cluster) {
|
||||
$clustersByTagNames[mb_strtolower($cluster['GalaxyCluster']['tag_name'])] = $cluster['GalaxyCluster'];
|
||||
}
|
||||
$clustersByTagIds = array_column(array_column($clusters, 'GalaxyCluster'), null, 'tag_id');
|
||||
unset($clusters);
|
||||
|
||||
if (isset($event['EventTag'])) {
|
||||
|
@ -2373,9 +2368,9 @@ class Event extends AppModel
|
|||
if (!$eventTag['Tag']['is_galaxy']) {
|
||||
continue;
|
||||
}
|
||||
$tagName = mb_strtolower($eventTag['Tag']['name']);
|
||||
if (isset($clustersByTagNames[$tagName])) {
|
||||
$cluster = $clustersByTagNames[$tagName];
|
||||
$tagId = $eventTag['Tag']['id'];
|
||||
if (isset($clustersByTagIds[$tagId])) {
|
||||
$cluster = $clustersByTagIds[$tagId];
|
||||
$galaxyId = $cluster['Galaxy']['id'];
|
||||
$cluster['local'] = isset($eventTag['local']) ? $eventTag['local'] : false;
|
||||
if (isset($event['Galaxy'][$galaxyId])) {
|
||||
|
@ -2397,9 +2392,9 @@ class Event extends AppModel
|
|||
if (!$attributeTag['Tag']['is_galaxy']) {
|
||||
continue;
|
||||
}
|
||||
$tagName = mb_strtolower($attributeTag['Tag']['name']);
|
||||
if (isset($clustersByTagNames[$tagName])) {
|
||||
$cluster = $clustersByTagNames[$tagName];
|
||||
$tagId = $attributeTag['Tag']['id'];
|
||||
if (isset($clustersByTagIds[$tagId])) {
|
||||
$cluster = $clustersByTagIds[$tagId];
|
||||
$galaxyId = $cluster['Galaxy']['id'];
|
||||
$cluster['local'] = isset($attributeTag['local']) ? $attributeTag['local'] : false;
|
||||
if (isset($attribute['Galaxy'][$galaxyId])) {
|
||||
|
@ -5848,7 +5843,14 @@ class Event extends AppModel
|
|||
}
|
||||
}
|
||||
|
||||
public function unpublishEvent($id, $proposalLock = false)
|
||||
/**
|
||||
* @param int $id
|
||||
* @param bool $proposalLock
|
||||
* @param int|null $timestamp If not provided, current time will be used
|
||||
* @return array|bool|mixed|null
|
||||
* @throws Exception
|
||||
*/
|
||||
public function unpublishEvent($id, $proposalLock = false, $timestamp = null)
|
||||
{
|
||||
$event = $this->find('first', array(
|
||||
'recursive' => -1,
|
||||
|
@ -5860,7 +5862,7 @@ class Event extends AppModel
|
|||
}
|
||||
$fields = ['published', 'timestamp'];
|
||||
$event['Event']['published'] = 0;
|
||||
$event['Event']['timestamp'] = time();
|
||||
$event['Event']['timestamp'] = $timestamp ?: time();
|
||||
if ($proposalLock) {
|
||||
$event['Event']['proposal_email_lock'] = 0;
|
||||
$fields[] = 'proposal_email_lock';
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
App::uses('AppModel', 'Model');
|
||||
App::uses('RandomTool', 'Tools');
|
||||
App::uses('TmpFileTool', 'Tools');
|
||||
App::uses('FileAccessTool', 'Tools');
|
||||
App::uses('AttributeValidationTool', 'Tools');
|
||||
|
||||
class Feed extends AppModel
|
||||
|
|
|
@ -1088,18 +1088,23 @@ class GalaxyCluster extends AppModel
|
|||
if (isset($options['list']) && $options['list']) {
|
||||
return $this->find('list', $params);
|
||||
}
|
||||
|
||||
if (isset($options['first']) && $options['first']) {
|
||||
$clusters = $this->find('first', $params);
|
||||
} else if (isset($options['count']) && $options['count']) {
|
||||
$clusterCount = $this->find('count', $params);
|
||||
return $clusterCount;
|
||||
return $this->find('count', $params);
|
||||
} else {
|
||||
$clusters = $this->find('all', $params);
|
||||
}
|
||||
|
||||
if (empty($clusters)) {
|
||||
return $clusters;
|
||||
}
|
||||
|
||||
if (isset($options['first']) && $options['first']) {
|
||||
$clusters = [$clusters];
|
||||
}
|
||||
|
||||
if ($full) {
|
||||
$clusterIds = array_column(array_column($clusters, 'GalaxyCluster'), 'id');
|
||||
$targetingClusterRelations = $this->TargetingClusterRelation->fetchRelations($user, array(
|
||||
|
@ -1115,11 +1120,15 @@ class GalaxyCluster extends AppModel
|
|||
$tagsToFetch = Hash::extract($clusters, "{n}.GalaxyClusterRelation.{n}.GalaxyClusterRelationTag.{n}.tag_id");
|
||||
$tagsToFetch = array_merge($tagsToFetch, Hash::extract($targetingClusterRelations, "GalaxyClusterRelationTag.{n}.tag_id"));
|
||||
|
||||
if (!empty($tagsToFetch)) {
|
||||
$tags = $this->GalaxyClusterRelation->GalaxyClusterRelationTag->Tag->find('all', [
|
||||
'conditions' => ['id' => array_unique($tagsToFetch)],
|
||||
'recursive' => -1,
|
||||
]);
|
||||
$tags = array_column(array_column($tags, 'Tag'), null, 'id');
|
||||
} else {
|
||||
$tags = [];
|
||||
}
|
||||
|
||||
foreach ($targetingClusterRelations as $k => $targetingClusterRelation) {
|
||||
if (!empty($targetingClusterRelation['GalaxyClusterRelationTag'])) {
|
||||
|
@ -1165,6 +1174,11 @@ class GalaxyCluster extends AppModel
|
|||
}
|
||||
$clusters[$i] = $this->arrangeData($clusters[$i]);
|
||||
}
|
||||
|
||||
if (isset($options['first']) && $options['first']) {
|
||||
return $clusters[0];
|
||||
}
|
||||
|
||||
return $clusters;
|
||||
}
|
||||
|
||||
|
|
|
@ -79,9 +79,9 @@ class GalaxyClusterRelation extends AppModel
|
|||
|
||||
public function buildConditions($user, $clusterConditions = true)
|
||||
{
|
||||
$this->Event = ClassRegistry::init('Event');
|
||||
$conditions = [];
|
||||
if (!$user['Role']['perm_site_admin']) {
|
||||
$this->Event = ClassRegistry::init('Event');
|
||||
$alias = $this->alias;
|
||||
$sgids = $this->Event->cacheSgids($user, true);
|
||||
$gcOwnerIds = $this->SourceCluster->cacheGalaxyClusterOwnerIDs($user);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,198 @@
|
|||
<?php
|
||||
App::uses('AppModel', 'Model');
|
||||
App::uses('JsonTool', 'Tools');
|
||||
App::uses('BetterSecurity', 'Tools');
|
||||
|
||||
/**
|
||||
* Class for ondemand encryption of JSON serialized value
|
||||
*/
|
||||
class EncryptedValue implements JsonSerializable
|
||||
{
|
||||
const ENCRYPTED_MAGIC = "\x1F\x1D";
|
||||
|
||||
/** @var string */
|
||||
private $value;
|
||||
|
||||
public function __construct($value)
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
* @throws JsonException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function decrypt()
|
||||
{
|
||||
$decrypt = BetterSecurity::decrypt($this->value, Configure::read('Security.encryption_key'));
|
||||
return JsonTool::decode($decrypt);
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->decrypt();
|
||||
}
|
||||
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return $this->decrypt();
|
||||
}
|
||||
}
|
||||
|
||||
class SystemSetting extends AppModel
|
||||
{
|
||||
public $actsAs = [
|
||||
'AuditLog'
|
||||
];
|
||||
|
||||
public $primaryKey = 'setting';
|
||||
|
||||
// Blocked setting that cannot be saved or fetched from DB. The same as cli_only settings.
|
||||
const BLOCKED_SETTINGS = [
|
||||
'Security.encryption_key',
|
||||
'Security.disable_local_feed_access',
|
||||
'GnuPG.binary',
|
||||
'MISP.python_bin',
|
||||
'MISP.ca_path',
|
||||
'MISP.tmpdir',
|
||||
'MISP.system_setting_db',
|
||||
'MISP.attachments_dir',
|
||||
];
|
||||
|
||||
// Allow to set config values just for these categories
|
||||
const ALLOWED_CATEGORIES = [
|
||||
'MISP',
|
||||
'Security',
|
||||
'GnuPG',
|
||||
'SMIME',
|
||||
'Proxy',
|
||||
'SecureAuth',
|
||||
'Session',
|
||||
'Plugin',
|
||||
'debug',
|
||||
'site_admin_debug',
|
||||
];
|
||||
|
||||
/**
|
||||
* Set config values from database into global Configure class
|
||||
*/
|
||||
public static function setGlobalSetting()
|
||||
{
|
||||
$systemSetting = ClassRegistry::init('SystemSetting');
|
||||
$settings = $systemSetting->getSettings();
|
||||
foreach ($settings as $settingName => $settingValue) {
|
||||
$firstPart = explode('.', $settingName)[0];
|
||||
if (in_array($firstPart, self::ALLOWED_CATEGORIES, true) && !in_array($settingName, self::BLOCKED_SETTINGS, true)) {
|
||||
Configure::write($settingName, $settingValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getSettings()
|
||||
{
|
||||
$settings = $this->find('list', [
|
||||
'fields' => ['SystemSetting.setting', 'SystemSetting.value'],
|
||||
]);
|
||||
return array_map([$this, 'decode'], $settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $setting Setting name
|
||||
* @param mixed $value
|
||||
* @throws Exception
|
||||
*/
|
||||
public function setSetting($setting, $value)
|
||||
{
|
||||
$firstPart = explode('.', $setting)[0];
|
||||
if (!in_array($firstPart, self::ALLOWED_CATEGORIES, true) || in_array($setting, self::BLOCKED_SETTINGS, true)) {
|
||||
return false; // blocked setting
|
||||
}
|
||||
|
||||
if ($value === '' || $value === null) {
|
||||
if ($this->hasAny(['SystemSetting.setting' => $setting])) {
|
||||
return $this->delete($setting); // delete the whole setting when value is empty
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
$value = JsonTool::encode($value);
|
||||
|
||||
// If encryption is enabled and setting name contains `password` or `apikey` string, encrypt value to protect it
|
||||
$key = Configure::read('Security.encryption_key');
|
||||
if ($key && self::isSensitive($setting)) {
|
||||
$value = EncryptedValue::ENCRYPTED_MAGIC . BetterSecurity::encrypt($value, $key);
|
||||
}
|
||||
|
||||
$valid = $this->save(['SystemSetting' => [
|
||||
'setting' => $setting,
|
||||
'value' => $value,
|
||||
]]);
|
||||
if (!$valid) {
|
||||
throw new Exception("Could not save system setting `$setting` because of validation errors: " . JsonTool::encode($this->validationErrors));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $old Old (or current) encryption key.
|
||||
* @param string|null $new New encryption key. If empty, encrypted values will be decrypted.
|
||||
* @throws JsonException
|
||||
*/
|
||||
public function reencrypt($old, $new)
|
||||
{
|
||||
$settings = $this->find('list', [
|
||||
'fields' => ['SystemSetting.setting', 'SystemSetting.value'],
|
||||
]);
|
||||
$toSave = [];
|
||||
foreach ($settings as $setting => $value) {
|
||||
if (!self::isSensitive($setting)) {
|
||||
continue;
|
||||
}
|
||||
if (substr($value, 0, 2) === EncryptedValue::ENCRYPTED_MAGIC) {
|
||||
$value = BetterSecurity::decrypt(substr($value, 2), $old);
|
||||
}
|
||||
if (!empty($new)) {
|
||||
$value = EncryptedValue::ENCRYPTED_MAGIC . BetterSecurity::encrypt($value, $new);
|
||||
}
|
||||
$toSave[] = ['SystemSetting' => [
|
||||
'setting' => $setting,
|
||||
'value' => $value,
|
||||
]];
|
||||
}
|
||||
return $this->saveMany($toSave);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
* @return EncryptedValue|mixed
|
||||
* @throws JsonException
|
||||
*/
|
||||
private function decode($value)
|
||||
{
|
||||
if (substr($value, 0, 2) === EncryptedValue::ENCRYPTED_MAGIC) {
|
||||
return new EncryptedValue(substr($value, 2));
|
||||
} else {
|
||||
return JsonTool::decode($value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sensitive setting are passwords or api keys.
|
||||
* @param string $setting Setting name
|
||||
* @return bool
|
||||
*/
|
||||
public static function isSensitive($setting)
|
||||
{
|
||||
if ($setting === 'Security.encryption_key' || $setting === 'Security.salt') {
|
||||
return true;
|
||||
}
|
||||
if (substr($setting, 0, 7) === 'Plugin.' && (strpos($setting, 'apikey') !== false || strpos($setting, 'secret') !== false)) {
|
||||
return true;
|
||||
}
|
||||
return strpos($setting, 'password') !== false;
|
||||
}
|
||||
}
|
|
@ -72,9 +72,4 @@ class Template extends AppModel
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function generateRandomFileName()
|
||||
{
|
||||
return (new RandomTool())->random_str(false, 12);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,10 +39,11 @@ class ApacheShibbAuthenticate extends BaseAuthenticate
|
|||
* 'group_one' => 1,
|
||||
* ),
|
||||
* 'DefaultOrg' => 'MY_ORG',
|
||||
* 'BlockOrgModifications' => false // set to true if you wish for the user's organisation never to be updated during login. Especially useful if you manually change organisations in MISP
|
||||
* 'DefaultRole' => false // set to a specific value if you wish to hard-set users created via ApacheShibbAuth
|
||||
* 'BlockRoleModifications' => false // set to true if you wish for the roles never to be updated during login. Especially * // useful if you manually change roles in MISP
|
||||
* 'BlockOrgModifications' => false // set to true if you wish for the organizations never to be updated during login. Especially * // useful if you manually change orgs in MISP
|
||||
* 'DefaultRole' => false, // set to a specific value if you wish to hard-set users created via ApacheShibbAuth
|
||||
* 'BlockRoleModifications' => false, // set to true if you wish for the roles never to be updated during login. Especially
|
||||
* // useful if you manually change roles in MISP
|
||||
* 'BlockOrgModifications' => false, // set to true if you wish for the organizations never to be updated during login. Especially
|
||||
* // useful if you manually change orgs in MISP
|
||||
* ),
|
||||
* @param CakeRequest $request The request that contains login information.
|
||||
* @param CakeResponse $response Unused response object.
|
||||
|
|
|
@ -145,6 +145,9 @@ in the list given by apache. By default, you can leave it at ';'.
|
|||
'possible_group_attribute_value_1' => 1,
|
||||
),
|
||||
'DefaultOrg' => 'MISP_DEFAULT_ORG',
|
||||
'DefaultRole' => false, // set to a specific value if you wish to hard-set users created via ApacheShibbAuth
|
||||
'BlockRoleModifications' => false, // set to true if you wish for the roles never to be updated during login. Especially useful if you manually change roles in MISP
|
||||
'BlockOrgModifications' => false, // set to true if you wish for the organizations never to be updated during login. Especially useful if you manually change orgs in MISP
|
||||
),
|
||||
```
|
||||
|
||||
|
|
|
@ -28,10 +28,6 @@
|
|||
'type' => 'checkbox',
|
||||
'label' => __('Only find IOCs flagged as to IDS')
|
||||
));
|
||||
echo $this->Form->input('alternate', array(
|
||||
'type' => 'checkbox',
|
||||
'label' => __('Alternate Search Result (Events)')
|
||||
));
|
||||
echo $this->Form->input('first_seen', array(
|
||||
'type' => 'text',
|
||||
'div' => 'input hidden',
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
<?php
|
||||
$data = $this->DataPathCollector->extract($row, $field['data_path']);
|
||||
if ($data['Feed.enabled']) {
|
||||
if (in_array($data['Feed.source_format'], array('freetext', 'csv'))) {
|
||||
if ($data['Feed.fixed_event']) {
|
||||
if (!empty($data['Feed.event_error'])) {
|
||||
$feed = $row['Feed'];
|
||||
if ($feed['enabled']) {
|
||||
if (in_array($feed['source_format'], array('freetext', 'csv'))) {
|
||||
if ($feed['fixed_event']) {
|
||||
if (!empty($feed['event_error'])) {
|
||||
echo sprintf(
|
||||
'<span class="red bold">%s</span>',
|
||||
__('Error: Invalid event!')
|
||||
);
|
||||
} else {
|
||||
if ($data['Feed.event_id']) {
|
||||
if ($feed['event_id']) {
|
||||
echo sprintf(
|
||||
'<a href="%s/events/view/%s">%s</a>',
|
||||
$baseurl,
|
||||
h($data['Feed.event_id']),
|
||||
__('Fixed event %s', h($data['Feed.event_id']))
|
||||
h($feed['event_id']),
|
||||
__('Fixed event %s', h($feed['event_id']))
|
||||
);
|
||||
} else {
|
||||
echo __('New fixed event');
|
||||
|
|
|
@ -505,6 +505,12 @@
|
|||
'url' => empty($homepage['path']) ? $baseurl : $baseurl . h($homepage['path']),
|
||||
'html' => '<span class="logoBlueStatic bold" id="smallLogo">MISP</span>'
|
||||
),
|
||||
[
|
||||
'type' => 'root',
|
||||
'url' => Configure::read('MISP.menu_custom_right_link'),
|
||||
'html' => Configure::read('MISP.menu_custom_right_link_html'),
|
||||
'requirement' => !empty(Configure::read('MISP.menu_custom_right_link')),
|
||||
],
|
||||
array(
|
||||
'type' => 'root',
|
||||
'url' => $baseurl . '/dashboards',
|
||||
|
@ -528,7 +534,7 @@
|
|||
);
|
||||
}
|
||||
?>
|
||||
<div id="topBar" class="navbar navbar-inverse <?php echo $debugMode;?>">
|
||||
<div id="topBar" class="navbar navbar-inverse <?= $debugMode ?>">
|
||||
<div class="navbar-inner">
|
||||
<ul class="nav">
|
||||
<?php
|
||||
|
|
|
@ -7,7 +7,9 @@
|
|||
2 => 'success',
|
||||
3 => 'info'
|
||||
);
|
||||
if ($setting['type'] == 'boolean') $setting['value'] = ($setting['value'] === true ? 'true' : 'false');
|
||||
if ($setting['type'] === 'boolean') {
|
||||
$setting['value'] = $setting['value'] === true ? 'true' : 'false';
|
||||
}
|
||||
if (isset($setting['options'])) {
|
||||
$setting['value'] = empty($setting['options'][$setting['value']]) ? null : $setting['options'][$setting['value']];
|
||||
}
|
||||
|
@ -100,4 +102,4 @@
|
|||
$columns
|
||||
);
|
||||
}
|
||||
?>
|
||||
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* Helper used to extract variables from an array based on path
|
||||
* Used by the index factories
|
||||
*
|
||||
*/
|
||||
App::uses('AppHelper', 'View/Helper');
|
||||
class DataPathCollectorHelper extends AppHelper {
|
||||
public function extract($data, $data_path, $options = array())
|
||||
{
|
||||
$result = array();
|
||||
if (!is_array($data_path)) {
|
||||
$data_path = array($data_path);
|
||||
}
|
||||
foreach ($data_path as $path) {
|
||||
$temp = Hash::extract($data, $path);
|
||||
if (is_array($temp)) {
|
||||
if (count($temp) > 1) {
|
||||
$temp = implode(', ', $temp);
|
||||
} else {
|
||||
if (count($temp) > 0) {
|
||||
$temp = $temp[0];
|
||||
} else {
|
||||
$temp = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
$result[$path] = $temp;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
<?php
|
||||
App::uses('AppHelper', 'View/Helper');
|
||||
class XmlOutputHelper extends AppHelper {
|
||||
public function recursiveEcho($array) {
|
||||
foreach ($array as $k => $v) {
|
||||
if (is_array($v)) {
|
||||
if (empty($v)) echo '<' . $k . '/>';
|
||||
else {
|
||||
foreach ($v as $element) {
|
||||
echo '<' . $k . '>';
|
||||
$this->recursiveEcho($element);
|
||||
echo '</' . $k . '>';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($v === false) $v = 0;
|
||||
if ($v === "" || $v === null) echo '<' . $k . '/>';
|
||||
else {
|
||||
echo '<' . $k . '>' . $v . '</' . $k . '>';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,8 +7,8 @@
|
|||
<p><?php echo __('Available Organisations');?></p>
|
||||
<select id="leftValues" size="5" multiple style="width:285px;">
|
||||
<?php
|
||||
foreach ($orgs as $org) {
|
||||
echo '<option value="' . h($org['id']) . '" selected>' . h($org['name']) . '</option>';
|
||||
foreach ($orgs as $orgId => $orgName) {
|
||||
echo '<option value="' . intval($orgId) . '" selected>' . h($orgName) . '</option>';
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
<div class="server index">
|
||||
<?php if ($writeableFiles[APP . 'Config/config.php'] != 0): ?>
|
||||
<div class="bold" style="background-color:red;width:100%;color:white;"><span style="padding-left:10px;"><?php echo __('Warning: app/Config/config.php is not writeable. This means that any setting changes made here will NOT be saved.');?></span></div>
|
||||
<?php if ($writeableFiles[APP . 'Config/config.php'] != 0 && !Configure::read('MISP.system_setting_db')): ?>
|
||||
<div class="alert alert-error"><?= __('Warning: app/Config/config.php is not writeable. This means that any setting changes made here will NOT be saved.') ?></div>
|
||||
<?php endif; ?>
|
||||
<h2><?php echo __('Server Settings & Maintenance');?></h2>
|
||||
<?php
|
||||
echo $this->element('healthElements/tabs', array('active_tab' => $tab));
|
||||
if (in_array($tab, array('MISP', 'Security', 'Encryption', 'Proxy', 'Plugin'))) {
|
||||
if (in_array($tab, ['MISP', 'Security', 'Encryption', 'Proxy', 'Plugin'], true)) {
|
||||
echo $this->element('healthElements/settings_tab');
|
||||
} else if ($tab == 'diagnostics') {
|
||||
} else if ($tab === 'diagnostics') {
|
||||
echo $this->element('healthElements/diagnostics');
|
||||
} else if ($tab == 'workers') {
|
||||
} else if ($tab === 'workers') {
|
||||
echo $this->element('healthElements/workers');
|
||||
} else if ($tab == 'files') {
|
||||
} else if ($tab === 'files') {
|
||||
echo $this->element('healthElements/files');
|
||||
} else {
|
||||
echo $this->element('healthElements/overview');
|
||||
|
@ -20,14 +20,11 @@
|
|||
<div style="font-style: italic;"><?php echo __('To edit a setting, simply double click it.');?></div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
$('#liveFilterField').focus();
|
||||
$('#liveFilterField').keyup(function() {
|
||||
$(function() {
|
||||
$('#liveFilterField').focus().keyup(function() {
|
||||
liveFilter();
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
<?php
|
||||
echo $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'admin', 'menuItem' => 'serverSettings'));
|
||||
?>
|
||||
<?= $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'admin', 'menuItem' => 'serverSettings'));
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit ae6a527bcb11767abafcc46939c269d297c5de19
|
||||
Subproject commit 0f0093ba4b59e469c0e75bd15415ccddc679e4c7
|
|
@ -6082,7 +6082,7 @@ components:
|
|||
format: date
|
||||
example: "2021-03-05"
|
||||
org:
|
||||
description: "Filter events by matching an the creator organisation name"
|
||||
description: "Filter events by matching the creator organisation name"
|
||||
type: string
|
||||
nullable: true
|
||||
example: "CIRCL"
|
||||
|
|
|
@ -6144,6 +6144,30 @@
|
|||
"extra": ""
|
||||
}
|
||||
],
|
||||
"system_settings": [
|
||||
{
|
||||
"column_name": "setting",
|
||||
"is_nullable": "NO",
|
||||
"data_type": "varchar",
|
||||
"character_maximum_length": "255",
|
||||
"numeric_precision": null,
|
||||
"collation_name": "utf8mb4_unicode_ci",
|
||||
"column_type": "varchar(255)",
|
||||
"column_default": null,
|
||||
"extra": ""
|
||||
},
|
||||
{
|
||||
"column_name": "value",
|
||||
"is_nullable": "NO",
|
||||
"data_type": "blob",
|
||||
"character_maximum_length": "65535",
|
||||
"numeric_precision": null,
|
||||
"collation_name": null,
|
||||
"column_type": "blob",
|
||||
"column_default": null,
|
||||
"extra": ""
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
{
|
||||
"column_name": "id",
|
||||
|
@ -8096,6 +8120,9 @@
|
|||
"source": false,
|
||||
"type": false
|
||||
},
|
||||
"system_settings": {
|
||||
"setting": true
|
||||
},
|
||||
"tags": {
|
||||
"id": true,
|
||||
"name": true,
|
||||
|
|
|
@ -26,6 +26,9 @@ coreCAKE () {
|
|||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "Session.timeout" 600
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "Session.cookieTimeout" 3600
|
||||
|
||||
# Set the default temp dir
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "MISP.tmpdir" "${PATH_TO_MISP}/app/tmp"
|
||||
|
||||
# Change base url, either with this CLI command or in the UI
|
||||
[[ ! -z ${MISP_BASEURL} ]] && ${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Baseurl $MISP_BASEURL
|
||||
# example: 'baseurl' => 'https://<your.FQDN.here>',
|
||||
|
@ -46,7 +49,7 @@ coreCAKE () {
|
|||
# Enable installer org and tune some configurables
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "MISP.host_org_id" 1
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "MISP.email" "info@admin.test"
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "MISP.disable_emailing" true
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "MISP.disable_emailing" true --force
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "MISP.contact" "info@admin.test"
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "MISP.disablerestalert" true
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "MISP.showCorrelationsOnIndex" true
|
||||
|
@ -57,7 +60,7 @@ coreCAKE () {
|
|||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "Plugin.Cortex_services_url" "http://127.0.0.1"
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "Plugin.Cortex_services_port" 9000
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "Plugin.Cortex_timeout" 120
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "Plugin.Cortex_authkey" ""
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "Plugin.Cortex_authkey" false
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "Plugin.Cortex_ssl_verify_peer" false
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "Plugin.Cortex_ssl_verify_host" false
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "Plugin.Cortex_ssl_allow_self_signed" true
|
||||
|
@ -116,7 +119,7 @@ coreCAKE () {
|
|||
Plugin.ElasticSearch_logging_enable
|
||||
Plugin.S3_enable)
|
||||
for PLUG in "${PLUGS[@]}"; do
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting ${PLUG} false
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting ${PLUG} false 2> /dev/null
|
||||
done
|
||||
|
||||
# Plugin CustomAuth tuneable
|
||||
|
@ -132,7 +135,7 @@ coreCAKE () {
|
|||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "Plugin.RPZ_minimum_ttl" "1h"
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "Plugin.RPZ_ttl" "1w"
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "Plugin.RPZ_ns" "localhost."
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "Plugin.RPZ_ns_alt" ""
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "Plugin.RPZ_ns_alt" false
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "Plugin.RPZ_email" "root.localhost"
|
||||
|
||||
# Kafka settings
|
||||
|
|
|
@ -30,7 +30,7 @@ sudo update-grub > /dev/null 2>&1
|
|||
```
|
||||
|
||||
!!! notice
|
||||
On recent Ubuntu install Netplan is default and you need to change the Network name.
|
||||
On recent Ubuntu install Netplan is default and you might need to change the Network name in its respective config file.
|
||||
```
|
||||
sudo sed -i "s/enp0s3/eth0/" /etc/netplan/50-cloud-init.yaml
|
||||
```
|
||||
|
@ -38,3 +38,7 @@ sudo update-grub > /dev/null 2>&1
|
|||
```
|
||||
sudo sed -i "s/enp0s3/eth0/" /etc/netplan/01-netcfg.yaml
|
||||
```
|
||||
OR on Ubuntu 22.04
|
||||
```
|
||||
sudo sed -i "s/enp0s3/eth0/" /etc/netplan/00-installer-config.yaml
|
||||
```
|
||||
|
|
|
@ -59,7 +59,8 @@ MISPvars () {
|
|||
# MISP configuration variables
|
||||
PATH_TO_MISP="${PATH_TO_MISP:-/var/www/MISP}"
|
||||
PATH_TO_MISP_SCRIPTS="${PATH_TO_MISP}/app/files/scripts"
|
||||
|
||||
## For future use
|
||||
# TMPDIR="${TMPDIR:-$PATH_TO_MISP/app/tmp}"
|
||||
|
||||
FQDN="${FQDN:-misp.local}"
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ mispmodules () {
|
|||
# If you build an egg, the user you build it as need write permissions in the CWD
|
||||
sudo chgrp $WWW_USER .
|
||||
sudo chmod og+w .
|
||||
$SUDO_WWW ${PATH_TO_MISP}/venv/bin/pip install pillow
|
||||
$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 .
|
||||
|
|
|
@ -0,0 +1,531 @@
|
|||
# INSTALLATION INSTRUCTIONS
|
||||
## for Ubuntu 22.04-server
|
||||
|
||||
{!generic/manual-install-notes.md!}
|
||||
|
||||
### -1/ Installer and Manual install instructions
|
||||
|
||||
Make sure you are reading the parsed version of this Document. When in doubt [click here](https://misp.github.io/MISP/INSTALL.ubuntu2004/).
|
||||
|
||||
### 0/ MISP Ubuntu 20.04-server install - status
|
||||
-------------------------
|
||||
!!! notice
|
||||
Installer tested working by [@SteveClement](https://twitter.com/SteveClement) on 20211002
|
||||
|
||||
!!! notice
|
||||
If the next line is `[!generic/core.md!]()` [click here](https://misp.github.io/MISP/INSTALL.ubuntu2204/).
|
||||
|
||||
{!generic/core.md!}
|
||||
|
||||
### 1/ Minimal Ubuntu install
|
||||
-------------------------
|
||||
|
||||
#### Install a minimal Ubuntu 20.04-server system with the software:
|
||||
- OpenSSH server
|
||||
- This guide assumes a user name of 'misp' with sudo working but can be overwritten by setting the environment variable: *${MISP_USER}*
|
||||
|
||||
#### Make sure your system is up2date
|
||||
```bash
|
||||
# <snippet-begin 0_apt-upgrade.sh>
|
||||
aptUpgrade () {
|
||||
debug "Upgrading system"
|
||||
checkAptLock
|
||||
|
||||
# If we run in non-interactive mode, make sure we do not stop all of a sudden
|
||||
if [[ "${PACKER}" == "1" || "${UNATTENDED}" == "1" ]]; then
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
export DEBIAN_PRIORITY=critical
|
||||
sudo -E apt-get -qy -o "Dpkg::Options::=--force-confdef" -o "Dpkg::Options::=--force-confold" upgrade
|
||||
sudo -E apt-get -qy autoclean
|
||||
else
|
||||
sudo apt-get upgrade -qy
|
||||
fi
|
||||
}
|
||||
# <snippet-end 0_apt-upgrade.sh>
|
||||
```
|
||||
|
||||
{!generic/sudo_etckeeper.md!}
|
||||
|
||||
{!generic/ethX.md!}
|
||||
|
||||
#### install postfix, there will be some questions.
|
||||
```bash
|
||||
# <snippet-begin postfix.sh>
|
||||
sudo apt-get install postfix dialog -qy
|
||||
# <snippet-end postfix.sh>
|
||||
```
|
||||
|
||||
!!! notice
|
||||
Postfix Configuration: Satellite system<br />
|
||||
change the relay server later with:
|
||||
```bash
|
||||
sudo postconf -e 'relayhost = example.com'
|
||||
sudo postfix reload
|
||||
```
|
||||
|
||||
{!generic/globalVariables.md!}
|
||||
|
||||
### 2/ Install LAMP & dependencies
|
||||
------------------------------
|
||||
Once the system is installed you can perform the following steps.
|
||||
```bash
|
||||
# <snippet-begin 0_installCoreDeps.sh>
|
||||
installCoreDeps () {
|
||||
debug "Installing core dependencies"
|
||||
# Install the dependencies: (some might already be installed)
|
||||
sudo apt-get install curl gcc git gpg-agent make python3 openssl redis-server sudo vim zip unzip virtualenv libfuzzy-dev sqlite3 moreutils -qy
|
||||
|
||||
# Install MariaDB (a MySQL fork/alternative)
|
||||
sudo apt-get install mariadb-client mariadb-server -qy
|
||||
|
||||
# Install Apache2
|
||||
sudo apt-get install apache2 apache2-doc apache2-utils -qy
|
||||
|
||||
# install Mitre's STIX and its dependencies by running the following commands:
|
||||
sudo apt-get install python3-dev python3-pip libxml2-dev libxslt1-dev zlib1g-dev python-setuptools -qy
|
||||
}
|
||||
# <snippet-end 0_installCoreDeps.sh>
|
||||
|
||||
# <snippet-begin 0_installDepsPhp80.sh>
|
||||
# Install Php 8.0 dependencies
|
||||
# FIXME: Ugly hack to get 7.4 working until 8.0 (cake4) will be implemented.
|
||||
echo "deb http://ppa.launchpad.net/ondrej/php/ubuntu devel main" |sudo tee /etc/apt/sources.list.d/ondrej-ubuntu-php-devel.list
|
||||
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 4F4EA0AAE5267A6C
|
||||
sudo apt update
|
||||
installDepsPhp80 () {
|
||||
debug "Installing PHP 8.0 dependencies"
|
||||
PHP_ETC_BASE=/etc/php/7.4
|
||||
PHP_INI=${PHP_ETC_BASE}/apache2/php.ini
|
||||
checkAptLock
|
||||
sudo apt install -qy \
|
||||
libapache2-mod-php7.4 \
|
||||
php7.4 php7.4-cli \
|
||||
php7.4-dev \
|
||||
php-json php7.4-xml php7.4-mysql php7.4-opcache php7.4-readline php7.4-mbstring php7.4-zip \
|
||||
php-redis php-gnupg \
|
||||
php7.4-intl php7.4-bcmath \
|
||||
php7.4-gd
|
||||
|
||||
for key in upload_max_filesize post_max_size max_execution_time max_input_time memory_limit
|
||||
do
|
||||
sudo sed -i "s/^\($key\).*/\1 = $(eval echo \${$key})/" $PHP_INI
|
||||
done
|
||||
sudo sed -i "s/^\(session.sid_length\).*/\1 = $(eval echo \${session0sid_length})/" $PHP_INI
|
||||
sudo sed -i "s/^\(session.use_strict_mode\).*/\1 = $(eval echo \${session0use_strict_mode})/" $PHP_INI
|
||||
}
|
||||
# <snippet-end 0_installDepsPhp80.sh>
|
||||
```
|
||||
|
||||
### 3/ MISP code
|
||||
------------
|
||||
```bash
|
||||
# <snippet-begin 1_mispCoreInstall.sh>
|
||||
installCore () {
|
||||
debug "Installing ${LBLUE}MISP${NC} core"
|
||||
# Download MISP using git in the /var/www/ directory.
|
||||
if [[ ! -d ${PATH_TO_MISP} ]]; then
|
||||
sudo mkdir ${PATH_TO_MISP}
|
||||
sudo chown ${WWW_USER}:${WWW_USER} ${PATH_TO_MISP}
|
||||
false; while [[ $? -ne 0 ]]; do checkAptLock; ${SUDO_WWW} git clone https://github.com/MISP/MISP.git ${PATH_TO_MISP}; done
|
||||
false; while [[ $? -ne 0 ]]; do checkAptLock; ${SUDO_WWW} git -C ${PATH_TO_MISP} submodule update --progress --init --recursive; done
|
||||
# Make git ignore filesystem permission differences for submodules
|
||||
${SUDO_WWW} git -C ${PATH_TO_MISP} submodule foreach --recursive git config core.filemode false
|
||||
|
||||
# Make git ignore filesystem permission differences
|
||||
${SUDO_WWW} git -C ${PATH_TO_MISP} config core.filemode false
|
||||
|
||||
# Create a python3 virtualenv
|
||||
${SUDO_WWW} virtualenv -p python3 ${PATH_TO_MISP}/venv
|
||||
|
||||
# make pip happy
|
||||
sudo mkdir /var/www/.cache/
|
||||
sudo chown ${WWW_USER}:${WWW_USER} /var/www/.cache
|
||||
|
||||
# install python-stix dependencies
|
||||
${SUDO_WWW} ${PATH_TO_MISP}/venv/bin/pip install ordered-set python-dateutil six weakrefmethod
|
||||
|
||||
debug "Install PyMISP"
|
||||
${SUDO_WWW} ${PATH_TO_MISP}/venv/bin/pip install ${PATH_TO_MISP}/PyMISP
|
||||
|
||||
# FIXME: Remove libfaup etc once the egg has the library baked-in
|
||||
sudo apt-get install cmake libcaca-dev liblua5.3-dev -y
|
||||
cd /tmp
|
||||
false; while [[ $? -ne 0 ]]; do [[ ! -d "faup" ]] && ${SUDO_CMD} git clone https://github.com/stricaud/faup.git faup; done
|
||||
false; while [[ $? -ne 0 ]]; do [[ ! -d "gtcaca" ]] && ${SUDO_CMD} git clone https://github.com/stricaud/gtcaca.git gtcaca; done
|
||||
sudo chown -R ${MISP_USER}:${MISP_USER} faup gtcaca
|
||||
cd gtcaca
|
||||
${SUDO_CMD} mkdir -p build
|
||||
cd build
|
||||
${SUDO_CMD} cmake .. && ${SUDO_CMD} make
|
||||
sudo make install
|
||||
cd ../../faup
|
||||
${SUDO_CMD} mkdir -p build
|
||||
cd build
|
||||
${SUDO_CMD} cmake .. && ${SUDO_CMD} make
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
|
||||
# install pydeep
|
||||
false; while [[ $? -ne 0 ]]; do checkAptLock; ${SUDO_WWW} ${PATH_TO_MISP}/venv/bin/pip install git+https://github.com/kbandla/pydeep.git; done
|
||||
|
||||
# install lief
|
||||
${SUDO_WWW} ${PATH_TO_MISP}/venv/bin/pip install lief
|
||||
|
||||
# install zmq needed by mispzmq
|
||||
${SUDO_WWW} ${PATH_TO_MISP}/venv/bin/pip install zmq redis
|
||||
|
||||
# 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
|
||||
else
|
||||
debug "Trying to git pull existing install"
|
||||
${SUDO_WWW} git pull -C ${PATH_TO_MISP}
|
||||
false; while [[ $? -ne 0 ]]; do ${SUDO_WWW} git -C ${PATH_TO_MISP} submodule update --progress --init --recursive; done
|
||||
|
||||
${SUDO_WWW} ${PATH_TO_MISP}/venv/bin/pip install -U ${PATH_TO_MISP}/PyMISP
|
||||
false; while [[ $? -ne 0 ]]; do checkAptLock; ${SUDO_WWW} ${PATH_TO_MISP}/venv/bin/pip install -U git+https://github.com/kbandla/pydeep.git; done
|
||||
fi
|
||||
}
|
||||
# <snippet-end 1_mispCoreInstall.sh>
|
||||
```
|
||||
|
||||
### 4/ CakePHP
|
||||
-----------
|
||||
|
||||
```bash
|
||||
# <snippet-begin 1_installCake.sh>
|
||||
installCake () {
|
||||
debug "Installing CakePHP"
|
||||
# Make composer cache happy
|
||||
# /!\ composer on Ubuntu when invoked with sudo -u doesn't set $HOME to /var/www but keeps it /home/misp \!/
|
||||
sudo mkdir -p /var/www/.composer ; sudo chown ${WWW_USER}:${WWW_USER} /var/www/.composer
|
||||
${SUDO_WWW} sh -c "cd ${PATH_TO_MISP}/app ;php composer.phar install --no-dev"
|
||||
|
||||
# Enable CakeResque with php-redis
|
||||
sudo phpenmod redis
|
||||
sudo phpenmod gnupg
|
||||
|
||||
# To use the scheduler worker for scheduled tasks, do the following:
|
||||
${SUDO_WWW} cp -fa ${PATH_TO_MISP}/INSTALL/setup/config.php ${PATH_TO_MISP}/app/Plugin/CakeResque/Config/config.php
|
||||
|
||||
# If you have multiple MISP instances on the same system, don't forget to have a different Redis per MISP instance for the CakeResque workers
|
||||
# The default Redis port can be updated in Plugin/CakeResque/Config/config.php
|
||||
}
|
||||
# <snippet-end 1_installCake.sh>
|
||||
```
|
||||
|
||||
### 5/ Set the permissions
|
||||
----------------------
|
||||
|
||||
```bash
|
||||
# <snippet-begin 2_permissions.sh>
|
||||
# Main function to fix permissions to something sane
|
||||
permissions () {
|
||||
debug "Setting permissions"
|
||||
sudo chown -R ${WWW_USER}:${WWW_USER} ${PATH_TO_MISP}
|
||||
sudo chmod -R 750 ${PATH_TO_MISP}
|
||||
sudo chmod -R g+ws ${PATH_TO_MISP}/app/tmp
|
||||
sudo chmod -R g+ws ${PATH_TO_MISP}/app/files
|
||||
sudo chmod -R g+ws ${PATH_TO_MISP}/app/files/scripts/tmp
|
||||
}
|
||||
# <snippet-end 2_permissions.sh>
|
||||
```
|
||||
|
||||
### 6/ Create a database and user
|
||||
-----------------------------
|
||||
|
||||
#### Set-up DB, User and import empty MISP DB
|
||||
|
||||
```bash
|
||||
# <snippet-begin 1_prepareDB.sh>
|
||||
prepareDB () {
|
||||
if sudo test ! -e "/var/lib/mysql/mysql/"; then
|
||||
#Make sure initial tables are created in MySQL
|
||||
debug "Install mysql tables"
|
||||
sudo mysql_install_db --user=mysql --basedir=/usr --datadir=/var/lib/mysql
|
||||
sudo service mysql start
|
||||
fi
|
||||
|
||||
if sudo test ! -e "/var/lib/mysql/misp/"; then
|
||||
debug "Start mysql"
|
||||
sudo service mysql start
|
||||
|
||||
debug "Setting up database"
|
||||
# Kill the anonymous users
|
||||
sudo mysql -h $DBHOST -e "DROP USER IF EXISTS ''@'localhost'"
|
||||
# Because our hostname varies we'll use some Bash magic here.
|
||||
sudo mysql -h $DBHOST -e "DROP USER IF EXISTS ''@'$(hostname)'"
|
||||
# Kill off the demo database
|
||||
sudo mysql -h $DBHOST -e "DROP DATABASE IF EXISTS test"
|
||||
# No root remote logins
|
||||
sudo mysql -h $DBHOST -e "DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1')"
|
||||
# Make sure that NOBODY can access the server without a password
|
||||
sudo mysqladmin -h $DBHOST -u "${DBUSER_ADMIN}" password "${DBPASSWORD_ADMIN}"
|
||||
# Make our changes take effect
|
||||
sudo mysql -h $DBHOST -e "FLUSH PRIVILEGES"
|
||||
|
||||
sudo mysql -h $DBHOST -u "${DBUSER_ADMIN}" -p"${DBPASSWORD_ADMIN}" -e "CREATE DATABASE ${DBNAME};"
|
||||
sudo mysql -h $DBHOST -u "${DBUSER_ADMIN}" -p"${DBPASSWORD_ADMIN}" -e "CREATE USER '${DBUSER_MISP}'@'localhost' IDENTIFIED BY '${DBPASSWORD_MISP}';"
|
||||
sudo mysql -h $DBHOST -u "${DBUSER_ADMIN}" -p"${DBPASSWORD_ADMIN}" -e "GRANT USAGE ON *.* to '${DBUSER_MISP}'@'localhost';"
|
||||
sudo mysql -h $DBHOST -u "${DBUSER_ADMIN}" -p"${DBPASSWORD_ADMIN}" -e "GRANT ALL PRIVILEGES on ${DBNAME}.* to '${DBUSER_MISP}'@'localhost';"
|
||||
sudo mysql -h $DBHOST -u "${DBUSER_ADMIN}" -p"${DBPASSWORD_ADMIN}" -e "FLUSH PRIVILEGES;"
|
||||
# Import the empty MISP database from MYSQL.sql
|
||||
${SUDO_WWW} cat ${PATH_TO_MISP}/INSTALL/MYSQL.sql | mysql -h $DBHOST -u "${DBUSER_MISP}" -p"${DBPASSWORD_MISP}" ${DBNAME}
|
||||
fi
|
||||
}
|
||||
# <snippet-end 1_prepareDB.sh>
|
||||
```
|
||||
|
||||
### 7/ Apache configuration
|
||||
-----------------------
|
||||
Now configure your Apache webserver with the DocumentRoot ${PATH_TO_MISP}/app/webroot/
|
||||
|
||||
#### Apache version 2.4 config:
|
||||
|
||||
!!! notice
|
||||
Be aware that the configuration files for apache 2.4 and up have changed.
|
||||
The configuration file has to have the .conf extension in the sites-available directory
|
||||
For more information, visit http://httpd.apache.org/docs/2.4/upgrading.html
|
||||
|
||||
```bash
|
||||
# <snippet-begin 1_apacheConfig.sh>
|
||||
apacheConfig () {
|
||||
debug "Generating Apache config, if this hangs, make sure you have enough entropy (install: haveged or wait)"
|
||||
sudo cp ${PATH_TO_MISP}/INSTALL/apache.24.misp.ssl /etc/apache2/sites-available/misp-ssl.conf
|
||||
|
||||
if [[ ! -z ${MISP_BASEURL} ]] && [[ "$(echo $MISP_BASEURL|cut -f 1 -d :)" == "http" || "$(echo $MISP_BASEURL|cut -f 1 -d :)" == "https" ]]; then
|
||||
|
||||
echo "Potentially replacing misp.local with $MISP_BASEURL in misp-ssl.conf"
|
||||
|
||||
fi
|
||||
|
||||
# If a valid SSL certificate is not already created for the server,
|
||||
# create a self-signed certificate:
|
||||
sudo openssl req -newkey rsa:4096 -days 365 -nodes -x509 \
|
||||
-subj "/C=${OPENSSL_C}/ST=${OPENSSL_ST}/L=${OPENSSL_L}/O=${OPENSSL_O}/OU=${OPENSSL_OU}/CN=${OPENSSL_CN}/emailAddress=${OPENSSL_EMAILADDRESS}" \
|
||||
-keyout /etc/ssl/private/misp.local.key -out /etc/ssl/private/misp.local.crt
|
||||
|
||||
# Enable modules, settings, and default of SSL in Apache
|
||||
sudo a2dismod status
|
||||
sudo a2enmod ssl
|
||||
sudo a2enmod rewrite
|
||||
sudo a2enmod headers
|
||||
sudo a2dissite 000-default
|
||||
sudo a2ensite default-ssl
|
||||
|
||||
# Apply all changes
|
||||
sudo systemctl restart apache2
|
||||
# activate new vhost
|
||||
sudo a2dissite default-ssl
|
||||
sudo a2ensite misp-ssl
|
||||
|
||||
# Restart apache
|
||||
sudo systemctl restart apache2
|
||||
}
|
||||
# <snippet-end 1_apacheConfig.sh>
|
||||
```
|
||||
|
||||
!!! notice
|
||||
Please find a sample conf file for an SSL enabled conf file in-line below (alternatively use one of the samples provided in /var/www/MISP/INSTALL).<br />
|
||||
Also remember to verify the SSLCertificateChainFile property in your config file.<br />
|
||||
This is usually commented out for the self-generated certificate in the sample configurations, such as the one pasted below.<br />
|
||||
Otherwise, copy the SSLCertificateFile, SSLCertificateKeyFile, and SSLCertificateChainFile to /etc/ssl/private/. (Modify path and config to fit your environment)
|
||||
|
||||
```
|
||||
============================================= Begin sample working SSL config for MISP
|
||||
<VirtualHost <IP, FQDN, or *>:80>
|
||||
ServerName <your.FQDN.here>
|
||||
|
||||
Redirect permanent / https://<your.FQDN.here>
|
||||
|
||||
LogLevel warn
|
||||
ErrorLog /var/log/apache2/misp.local_error.log
|
||||
CustomLog /var/log/apache2/misp.local_access.log combined
|
||||
ServerSignature Off
|
||||
</VirtualHost>
|
||||
|
||||
<VirtualHost <IP, FQDN, or *>:443>
|
||||
ServerAdmin admin@<your.FQDN.here>
|
||||
ServerName <your.FQDN.here>
|
||||
DocumentRoot /var/www/MISP/app/webroot
|
||||
<Directory /var/www/MISP/app/webroot>
|
||||
Options -Indexes
|
||||
AllowOverride all
|
||||
Order allow,deny
|
||||
allow from all
|
||||
</Directory>
|
||||
|
||||
SSLEngine On
|
||||
SSLCertificateFile /etc/ssl/private/misp.local.crt
|
||||
SSLCertificateKeyFile /etc/ssl/private/misp.local.key
|
||||
# SSLCertificateChainFile /etc/ssl/private/misp-chain.crt
|
||||
|
||||
LogLevel warn
|
||||
ErrorLog /var/log/apache2/misp.local_error.log
|
||||
CustomLog /var/log/apache2/misp.local_access.log combined
|
||||
ServerSignature Off
|
||||
</VirtualHost>
|
||||
============================================= End sample working SSL config for MISP
|
||||
```
|
||||
|
||||
### 8/ Log rotation
|
||||
---------------
|
||||
```bash
|
||||
# <snippet-begin 2_logRotation.sh>
|
||||
logRotation () {
|
||||
# MISP saves the stdout and stderr of its workers in ${PATH_TO_MISP}/app/tmp/logs
|
||||
# To rotate these logs install the supplied logrotate script:
|
||||
sudo cp ${PATH_TO_MISP}/INSTALL/misp.logrotate /etc/logrotate.d/misp
|
||||
sudo chmod 0640 /etc/logrotate.d/misp
|
||||
}
|
||||
# <snippet-end 2_logRotation.sh>
|
||||
```
|
||||
|
||||
### 9/ MISP configuration
|
||||
---------------------
|
||||
```bash
|
||||
# <snippet-begin 2_configMISP.sh>
|
||||
configMISP () {
|
||||
debug "Generating ${LBLUE}MISP${NC} config files"
|
||||
# There are 4 sample configuration files in ${PATH_TO_MISP}/app/Config that need to be copied
|
||||
${SUDO_WWW} cp -a ${PATH_TO_MISP}/app/Config/bootstrap.default.php ${PATH_TO_MISP}/app/Config/bootstrap.php
|
||||
${SUDO_WWW} cp -a ${PATH_TO_MISP}/app/Config/database.default.php ${PATH_TO_MISP}/app/Config/database.php
|
||||
${SUDO_WWW} cp -a ${PATH_TO_MISP}/app/Config/core.default.php ${PATH_TO_MISP}/app/Config/core.php
|
||||
${SUDO_WWW} cp -a ${PATH_TO_MISP}/app/Config/config.default.php ${PATH_TO_MISP}/app/Config/config.php
|
||||
|
||||
echo "<?php
|
||||
class DATABASE_CONFIG {
|
||||
public \$default = array(
|
||||
'datasource' => 'Database/Mysql',
|
||||
//'datasource' => 'Database/Postgres',
|
||||
'persistent' => false,
|
||||
'host' => '$DBHOST',
|
||||
'login' => '$DBUSER_MISP',
|
||||
'port' => 3306, // MySQL & MariaDB
|
||||
//'port' => 5432, // PostgreSQL
|
||||
'password' => '$DBPASSWORD_MISP',
|
||||
'database' => '$DBNAME',
|
||||
'prefix' => '',
|
||||
'encoding' => 'utf8',
|
||||
);
|
||||
}" | ${SUDO_WWW} tee ${PATH_TO_MISP}/app/Config/database.php
|
||||
|
||||
# Important! Change the salt key in ${PATH_TO_MISP}/app/Config/config.php
|
||||
# The salt key must be a string at least 32 bytes long.
|
||||
# The admin user account will be generated on the first login, make sure that the salt is changed before you create that user
|
||||
# If you forget to do this step, and you are still dealing with a fresh installation, just alter the salt,
|
||||
# delete the user from mysql and log in again using the default admin credentials (admin@admin.test / admin)
|
||||
|
||||
# and make sure the file permissions are still OK
|
||||
sudo chown -R ${WWW_USER}:${WWW_USER} ${PATH_TO_MISP}/app/Config
|
||||
sudo chmod -R 750 ${PATH_TO_MISP}/app/Config
|
||||
}
|
||||
# <snippet-end 2_configMISP.sh>
|
||||
```
|
||||
|
||||
{!generic/gnupg.md!}
|
||||
|
||||
!!! notice
|
||||
If entropy is not high enough, you can install havegd and then start the service
|
||||
```bash
|
||||
sudo apt install haveged -qy
|
||||
sudo service haveged start
|
||||
```
|
||||
|
||||
```bash
|
||||
# <snippet-begin 2_backgroundWorkers.sh>
|
||||
backgroundWorkers () {
|
||||
debug "Setting up background workers"
|
||||
# To make the background workers start on boot
|
||||
sudo chmod +x ${PATH_TO_MISP}/app/Console/worker/start.sh
|
||||
|
||||
if [ ! -e /etc/rc.local ]
|
||||
then
|
||||
echo '#!/bin/sh -e' | sudo tee -a /etc/rc.local
|
||||
echo 'exit 0' | sudo tee -a /etc/rc.local
|
||||
sudo chmod u+x /etc/rc.local
|
||||
fi
|
||||
|
||||
echo "[Unit]
|
||||
Description=MISP background workers
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
User=${WWW_USER}
|
||||
Group=${WWW_USER}
|
||||
ExecStart=${PATH_TO_MISP}/app/Console/worker/start.sh
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target" | sudo tee /etc/systemd/system/misp-workers.service
|
||||
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable --now misp-workers
|
||||
|
||||
# Add the following lines before the last line (exit 0). Make sure that you replace www-data with your apache user:
|
||||
sudo sed -i -e '$i \echo never > /sys/kernel/mm/transparent_hugepage/enabled\n' /etc/rc.local
|
||||
sudo sed -i -e '$i \echo 1024 > /proc/sys/net/core/somaxconn\n' /etc/rc.local
|
||||
sudo sed -i -e '$i \sysctl vm.overcommit_memory=1\n' /etc/rc.local
|
||||
}
|
||||
# <snippet-end 2_backgroundWorkers.sh>
|
||||
```
|
||||
|
||||
```bash
|
||||
echo "Admin (root) DB Password: $DBPASSWORD_ADMIN"
|
||||
echo "User (misp) DB Password: $DBPASSWORD_MISP"
|
||||
```
|
||||
|
||||
{!generic/MISP_CAKE_init.md!}
|
||||
|
||||
{!generic/misp-modules-debian.md!}
|
||||
|
||||
{!generic/misp-modules-cake.md!}
|
||||
|
||||
{!generic/INSTALL.done.md!}
|
||||
|
||||
{!generic/recommended.actions.md!}
|
||||
|
||||
### Optional features
|
||||
-----------------
|
||||
#### MISP has a new pub/sub feature, using ZeroMQ. To enable it, simply run the following command
|
||||
```bash
|
||||
${SUDO_WWW} ${PATH_TO_MISP}/venv/bin/pip install pyzmq
|
||||
```
|
||||
|
||||
#### MISP has a feature for publishing events to Kafka. To enable it, simply run the following commands
|
||||
```bash
|
||||
# <snippet-begin 4_kafka.sh>
|
||||
installKafka () {
|
||||
sudo apt-get install librdkafka-dev php-dev -y
|
||||
sudo pecl channel-update pecl.php.net
|
||||
sudo pecl install rdkafka
|
||||
echo "extension=rdkafka.so" | sudo tee ${PHP_ETC_BASE}/mods-available/rdkafka.ini
|
||||
sudo phpenmod rdkafka
|
||||
sudo service apache2 restart
|
||||
}
|
||||
# <snippet-end 4_kafka.sh>
|
||||
```
|
||||
|
||||
{!generic/misp-dashboard-debian.md!}
|
||||
|
||||
{!generic/misp-dashboard-cake.md!}
|
||||
|
||||
{!generic/viper-debian.md!}
|
||||
|
||||
{!generic/ssdeep-debian.md!}
|
||||
|
||||
{!generic/mail_to_misp-debian.md!}
|
||||
|
||||
{!generic/hardening.md!}
|
||||
|
||||
# INSTALL.sh
|
||||
|
||||
!!! notice
|
||||
The following section is an administrative section that is used by the "[INSTALL.sh](https://raw.githubusercontent.com/MISP/MISP/2.4/INSTALL/INSTALL.sh)" script.
|
||||
Please ignore.
|
||||
|
||||
{!generic/supportFunctions.md!}
|
|
@ -77,6 +77,7 @@ nav:
|
|||
- 'Debian 10': 'xINSTALL.debian10.md'
|
||||
- 'Tsurugi Linux': 'xINSTALL.tsurugi.md'
|
||||
- 'OpenBSD 7.0': 'xINSTALL.OpenBSD.md'
|
||||
- 'Ubuntu 22.04': 'xINSTALL.ubuntu2204.md'
|
||||
- Config Guides:
|
||||
- 'Elastic Search Logging': 'CONFIG.elasticsearch-logging.md'
|
||||
- 'Amazon S3 attachments': 'CONFIG.s3-attachments.md'
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
# MISP fetcher
|
||||
|
||||
Simple shell script to generate a zip file containing MISP with all submodules and composer libraries.
|
||||
|
||||
Simply run the script from its directory and use the zip's contents to update an airgapped MISP's codebase.
|
||||
|
||||
You will need to have composer installed and accessible
|
||||
|
||||
Assuming the standard MISP install path and www-data as your apache user, just run the following to update your MISP
|
||||
|
||||
```
|
||||
unzip misp_flat.zip /var/www/MISP
|
||||
chown -R www-data:www-data /var/www/MISP
|
||||
```
|
|
@ -0,0 +1,18 @@
|
|||
# Stupid script to fetch MISP's install files including submodules and composer sourced libraries
|
||||
|
||||
# This is currently a relative path, highly recommended to replace with an absolute path
|
||||
# For example, if you want the fetcher to work in /foo/bar/baz, use "/foo/bar/baz/MISPflat"
|
||||
MISP_FLAT_ROOT="MISPflat"
|
||||
|
||||
git clone https://github.com/MISP/MISP.git $MISP_FLAT_ROOT
|
||||
cd $MISP_FLAT_ROOT
|
||||
git submodule update --init --recursive
|
||||
cd ..
|
||||
cd $MISP_FLAT_ROOT/app
|
||||
composer install --no-dev
|
||||
cd ../..
|
||||
cd $MISP_FLAT_ROOT
|
||||
zip -r ../misp_flat.zip .
|
||||
cd ..
|
||||
rm -rf $MISP_FLAT_ROOT
|
||||
|
Loading…
Reference in New Issue