Merge branch '2.4' into tools

pull/4229/head
Steve Clement 2019-02-27 07:27:51 +05:30
commit ceacaf56d1
444 changed files with 112340 additions and 17041 deletions

3
.gitignore vendored
View File

@ -53,6 +53,9 @@ tools/mkdocs
!/app/files/scripts/mispzmq/mispzmqtest.py
/app/files/scripts/tmp/*
!/app/files/scripts/tmp/empty
/app/files/scripts/stix2/*
!/app/files/scripts/stix2/misp2stix2*.py
!/app/files/scripts/stix2/stix2misp*.py
!/app/files/empty
/app/files/terms/*
!/app/files/terms/empty

11
.gitmodules vendored
View File

@ -29,7 +29,7 @@
url = https://github.com/MISP/misp-vagrant.git
[submodule "cti-python-stix2"]
path = cti-python-stix2
url = https://github.com/oasis-open/cti-python-stix2
url = https://github.com/MISP/cti-python-stix2
[submodule "app/files/noticelists"]
path = app/files/noticelists
url = https://github.com/MISP/misp-noticelist
@ -37,3 +37,12 @@
path = Plugin/DebugKit
url = https://github.com/cakephp/debug_kit.git
branch = 2.2
[submodule "INSTALL/Crypt_GPG"]
path = INSTALL/dependencies/Crypt_GPG
url = https://github.com/pear/Crypt_GPG
[submodule "INSTALL/Console_CommandLine"]
path = INSTALL/dependencies/Console_CommandLine
url = https://github.com/pear/Console_CommandLine
[submodule "INSTALL/dependencies/Net_GeoIP"]
path = INSTALL/dependencies/Net_GeoIP
url = https://github.com/pear/Net_GeoIP

View File

@ -4,6 +4,7 @@ php:
- 7.0
- 7.1
- 7.2
- 7.3
- nightly
services:
@ -34,6 +35,7 @@ install:
- sudo pip3.6 install --upgrade pip setuptools requests
- hash -r
- sudo pip3.6 install --upgrade -r requirements.txt
- sudo pip3.6 install pipenv
- phpenv rehash
- pushd app
- composer install
@ -110,20 +112,18 @@ script:
- ./curl_tests.sh $AUTH
- popd
- pushd PyMISP
- sudo pip3.6 install nose python-dateutil
- sudo pip3.6 install git+https://github.com/kbandla/pydeep.git
- sudo pip3.6 install -e .[fileobjects,neo,openioc,virustotal]
- pipenv install -d
- pushd tests
- git clone https://github.com/viper-framework/viper-test-files.git
- popd
- python3.6 tests/test.py
- python3.6 tests/test_mispevent.py
- python3.6 tests/test_offline.py
- python3.6 tests/testlive_comprehensive.py
- pipenv run python tests/test.py
- pipenv run python tests/test_mispevent.py
- pipenv run python tests/test_offline.py
- pipenv run python tests/testlive_comprehensive.py
- popd
- cp PyMISP/tests/keys.py PyMISP/examples/events/
- pushd PyMISP/examples/events/
- python3.6 ./create_massive_dummy_events.py -l 5 -a 30
- pipenv run python ./create_massive_dummy_events.py -l 5 -a 30
- popd
- pushd app/files/feed-metadata
- jsonschema -i defaults.json schema.json

2128
INSTALL/INSTALL.debian.sh Executable file

File diff suppressed because it is too large Load Diff

695
INSTALL/INSTALL.debian.tpl.sh Executable file
View File

@ -0,0 +1,695 @@
#!/usr/bin/env bash
############################################################
###### #
##### Please AutoGenerated... ##
#### Do NOT was ###
### Manually It ####
## Change this Script... #####
# ######
############################################################
############################################################
#INSTALLATION INSTRUCTIONS #
##########################################################
#------------------------- for Debian Flavored Linux Distributions
#
#-------------------------------------------------------|
# 0/ Quick MISP Instance on Debian Based Linux - Status |
#-------------------------------------------------------|
#
# 20190208: Kali Linux tested and working.
#
#
#-------------------------------------------------------|
# 1/ For Kali, download and run Installer Script |
#-------------------------------------------------------|
#
# To install MISP on Kali copy paste the following to your r00t shell:
# # wget -O /tmp/misp-kali.sh https://raw.githubusercontent.com/MISP/MISP/2.4/INSTALL/INSTALL.debian.sh && bash /tmp/misp-kali.sh
# /!\ Please read the installer script before randomly doing the above.
# The script is tested on a plain vanilla Kali Linux Boot CD and installs quite a few dependencies.
#
#
#---------------------------------------------------------------------------------------------|
# 2/ For other Debian based Linux distributions, download script and run as unprivileged user |
#---------------------------------------------------------------------------------------------|
#
# $ wget -O ~/INSTALL.debian.sh https://raw.githubusercontent.com/MISP/MISP/2.4/INSTALL/INSTALL.debian.sh && bash ~/INSTALL.debian.sh -C
#
#
#----------------------------------------------------------|
# 3/ The following script has been partially autogenerated |
#----------------------------------------------------------|
#
# To generate this script yourself, the following steps need to be taken.
# $ git clone https://github.com/SteveClement/xsnippet.git
# Make sure xsnippet resides somewhere in your $PATH - It is a shell script so a simple, copy to somewhere sane is enough.
# $ git clone https://github.com/MISP/MISP.git
# $ cd MISP/INSTALL ; ./INSTALL.debian.tpl.sh
#
##
###
####----------------\
## Developer Note |
####--------------------------------------------------------------------------------------------------|
## In theory the order does not matter as everything is a self-contained function. |
# That said, ideally leave the order as is and do NOT change the lines as they are place-holders. |
# Script files that do NOT have a #_name.sh are scripts that have NO functions. This is by design. |
#-----------------------------------------------------------------------------------------------------|
#
# ToC #
#
#### BEGIN AUTOMATED SECTION ####
#
## 0_global-vars.sh ##
## 0_support-functions.sh ##
## 0_apt-upgrade.sh ##
## 0_sudoKeeper.sh ##
## 0_installCoreDeps.sh ##
## 0_installDepsPhp73.sh ##
## 0_installDepsPhp72.sh ##
## 1_prepareDB.sh ##
## 1_apacheConfig.sh ##
## 1_mispCoreInstall.sh ##
## 1_installCake.sh ##
## 2_permissions.sh ##
## 2_configMISP.sh ##
## 2_core-cake.sh ##
## 2_gnupg.sh ##
## 2_logRotation.sh ##
## 2_backgroundWorkers.sh ##
## 3_misp-modules.sh ##
## 4_misp-dashboard.sh ##
## 4_misp-dashboard-cake.sh ##
## 5_mail_to_misp.sh ##
## 6_ssdeep.sh ##
## 6_viper.sh ##
# No functions scripts:
## apt-upgrade.sh ##
## postfix.sh ##
## interfaces.sh ##
#
### END AUTOMATED SECTION ###
# This function will generate the main installer.
# It is a helper function for the maintainers for the installer.
colors () {
# Some colors for easier debug and better UX (not colorblind compatible, PR welcome)
RED='\033[0;31m'
GREEN='\033[0;32m'
LBLUE='\033[1;34m'
YELLOW='\033[0;33m'
HIDDEN='\e[8m'
NC='\033[0m'
}
generateInstaller () {
if [ ! -f $(which xsnippet) ]; then
echo 'xsnippet is NOT installed. Clone the repository below and copy the xsnippet shell script somehwere in your $PATH'
echo "git clone https://github.com/SteveClement/xsnippet.git"
exit 1
fi
if [[ $(echo $0 |grep -e '^\.\/') != "./INSTALL.debian.tpl.sh" ]]; then
echo -e "${RED}iAmError!${NC}"
echo -e "To generate the installer call it with './INSTALL.debian.tpl.sh' otherwise things will break."
echo -e "You called: ${RED}$0${NC}"
exit 1
fi
mkdir installer ; cd installer
cp ../INSTALL.debian.tpl.sh .
# Pull code snippets out of Main Install Documents
for f in `echo INSTALL.ubuntu1804.md xINSTALL.debian9.md INSTALL.kali.md xINSTALL.debian_testing.md xINSTALL.tsurugi.md xINSTALL.debian9-postgresql.md xINSTALL.ubuntu1804.with.webmin.md`; do
xsnippet . ../../docs/${f}
done
# Pull out code snippets from generic Install Documents
for f in `echo globalVariables.md mail_to_misp-debian.md MISP_CAKE_init.md misp-dashboard-debian.md misp-modules-debian.md gnupg.md ssdeep-debian.md sudo_etckeeper.md supportFunctions.md viper-debian.md`; do
xsnippet . ../../docs/generic/${f}
done
# TODO: Fix the below.
# $ for f in `echo ls [0-9]_*`; do
# $ perl -pe 's/## ${f} ##/`cat ${f}`/ge' -i INSTALL.debian.sh
# $ done
#
# Temporary copy/paste holder
perl -pe 's/^## 0_global-vars.sh ##/`cat 0_global-vars.sh`/ge' -i INSTALL.debian.tpl.sh
perl -pe 's/^## 0_apt-upgrade.sh ##/`cat 0_apt-upgrade.sh`/ge' -i INSTALL.debian.tpl.sh
perl -pe 's/^## 0_sudoKeeper.sh ##/`cat 0_sudoKeeper.sh`/ge' -i INSTALL.debian.tpl.sh
perl -pe 's/^## 0_installCoreDeps.sh ##/`cat 0_installCoreDeps.sh`/ge' -i INSTALL.debian.tpl.sh
perl -pe 's/^## 0_installDepsPhp73.sh ##/`cat 0_installDepsPhp73.sh`/ge' -i INSTALL.debian.tpl.sh
perl -pe 's/^## 0_installDepsPhp72.sh ##/`cat 0_installDepsPhp72.sh`/ge' -i INSTALL.debian.tpl.sh
perl -pe 's/^## 1_prepareDB.sh ##/`cat 1_prepareDB.sh`/ge' -i INSTALL.debian.tpl.sh
perl -pe 's/^## 1_apacheConfig.sh ##/`cat 1_apacheConfig.sh`/ge' -i INSTALL.debian.tpl.sh
perl -pe 's/^## 1_mispCoreInstall.sh ##/`cat 1_mispCoreInstall.sh`/ge' -i INSTALL.debian.tpl.sh
perl -pe 's/^## 1_installCake.sh ##/`cat 1_installCake.sh`/ge' -i INSTALL.debian.tpl.sh
perl -pe 's/^## 2_permissions.sh ##/`cat 2_permissions.sh`/ge' -i INSTALL.debian.tpl.sh
perl -pe 's/^## 2_configMISP.sh ##/`cat 2_configMISP.sh`/ge' -i INSTALL.debian.tpl.sh
perl -pe 's/^## 0_support-functions.sh ##/`cat 0_support-functions.sh`/ge' -i INSTALL.debian.tpl.sh
perl -pe 's/^## 2_gnupg.sh ##/`cat 2_gnupg.sh`/ge' -i INSTALL.debian.tpl.sh
perl -pe 's/^## 2_logRotation.sh ##/`cat 2_logRotation.sh`/ge' -i INSTALL.debian.tpl.sh
perl -pe 's/^## 2_backgroundWorkers.sh ##/`cat 2_backgroundWorkers.sh`/ge' -i INSTALL.debian.tpl.sh
perl -pe 's/^## 2_core-cake.sh ##/`cat 2_core-cake.sh`/ge' -i INSTALL.debian.tpl.sh
perl -pe 's/^## 3_misp-modules.sh ##/`cat 3_misp-modules.sh`/ge' -i INSTALL.debian.tpl.sh
perl -pe 's/^## 4_misp-dashboard-cake.sh ##/`cat 4_misp-dashboard-cake.sh`/ge' -i INSTALL.debian.tpl.sh
perl -pe 's/^## 4_misp-dashboard.sh ##/`cat 4_misp-dashboard.sh`/ge' -i INSTALL.debian.tpl.sh
perl -pe 's/^## 5_mail_to_misp.sh ##/`cat 5_mail_to_misp.sh`/ge' -i INSTALL.debian.tpl.sh
perl -pe 's/^## 6_viper.sh ##/`cat 6_viper.sh`/ge' -i INSTALL.debian.tpl.sh
perl -pe 's/^## 6_ssdeep.sh ##/`cat 6_ssdeep.sh`/ge' -i INSTALL.debian.tpl.sh
cp INSTALL.debian.tpl.sh ../INSTALL.debian.sh
cd ..
rm -rf installer
echo -e "${LBLUE}Generated INSTALL.debian.sh${NC}"
exit 0
}
# Simple debug function with message
# Make sure no alias exists
if [[ $(type -t debug) == "alias" ]]; then unalias debug; fi
debug () {
echo -e "${RED}Next step:${NC} ${GREEN}$1${NC}" > /dev/tty
if [ ! -z $DEBUG ]; then
NO_PROGRESS=1
echo -e "${RED}Debug Mode${NC}, press ${LBLUE}enter${NC} to continue..." > /dev/tty
exec 3>&1
read
else
# [Set up conditional redirection](https://stackoverflow.com/questions/8756535/conditional-redirection-in-bash)
#exec 3>&1 &>/dev/null
:
fi
}
installMISPubuntuSupported () {
space
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 2> /dev/null > /dev/null
progress 4
# Set locale if not set - functionLocation('generic/supportFunctions.md')
checkLocale
# Upgrade system to make sure we install the latest packages - functionLocation('INSTALL.ubuntu1804.md')
[[ -n $CORE ]] || [[ -n $ALL ]] && aptUpgrade 2> /dev/null > /dev/null
progress 4
# TODO: Double check how the user is added and subsequently used during the install.
# TODO: Work on possibility to install as user X and install MISP for user Y
# TODO: Check if logout needed. (run SUDO_USER in installer)
# <snippet-begin add-user.sh>
# TODO: Double check how to properly handle postfix
# <snippet-begin postfix.sh>
# Pull in all possible MISP Environment variables - functionLocation('generic/globalVariables.md')
[[ -n $CORE ]] || [[ -n $ALL ]] && MISPvars
progress 4
# Check if MISP user is installed and we do not run as root - functionLocation('generic/supportFunctions.md')
checkID
progress 4
# Starting friendly UI spinner
#spin &
#SPIN_PID=$!
#disown
#trap "kill -9 $SPIN_PID" `seq 0 15`
# Install Core Dependencies - functionLocation('INSTALL.ubuntu1804.md')
[[ -n $CORE ]] || [[ -n $ALL ]] && installCoreDeps
progress 4
# Install PHP 7.2 Dependencies - functionLocation('INSTALL.ubuntu1804.md')
[[ -n $CORE ]] || [[ -n $ALL ]] && installDepsPhp72
progress 4
# Install Core MISP - functionLocation('INSTALL.ubuntu1804.md')
[[ -n $CORE ]] || [[ -n $ALL ]] && installCore
progress 4
# Install PHP Cake - functionLocation('INSTALL.ubuntu1804.md')
[[ -n $CORE ]] || [[ -n $ALL ]] && installCake
progress 4
# Make sure permissions are sane - functionLocation('INSTALL.ubuntu1804.md')
[[ -n $CORE ]] || [[ -n $ALL ]] && permissions 2> /dev/null > /dev/null
progress 4
# TODO: Mysql install functions, make it upgrade safe, double check
# Setup Databse - functionLocation('INSTALL.ubuntu1804.md')
[[ -n $CORE ]] || [[ -n $ALL ]] && prepareDB 2> /dev/null > /dev/null
progress 4
# Roll Apache Config - functionLocation('INSTALL.ubuntu1804.md')
[[ -n $CORE ]] || [[ -n $ALL ]] && apacheConfig 2> /dev/null > /dev/null
progress 4
# Setup log logrotate - functionLocation('INSTALL.ubuntu1804.md')
[[ -n $CORE ]] || [[ -n $ALL ]] && logRotation 2> /dev/null > /dev/null
progress 4
# Generate MISP Config files - functionLocation('INSTALL.ubuntu1804.md')
[[ -n $CORE ]] || [[ -n $ALL ]] && configMISP 2> /dev/null > /dev/null
progress 4
# Generate GnuPG key - functionLocation('generic/gnupg.md')
[[ -n $CORE ]] || [[ -n $ALL ]] && setupGnuPG 2> /dev/null > /dev/null
progress 4
# Setup and start background workers - functionLocation('INSTALL.ubuntu1804.md')
[[ -n $CORE ]] || [[ -n $ALL ]] && backgroundWorkers 2> /dev/null > /dev/null
progress 4
# Run cake CLI for the core installation - functionLocation('generic/MISP_CAKE_init.md')
[[ -n $CORE ]] || [[ -n $ALL ]] && coreCAKE 2> /dev/null > /dev/null
progress 4
# Update Galaxies, Template Objects, Warning Lists, Notice Lists, Taxonomies - functionLocation('generic/MISP_CAKE_init.md')
[[ -n $CORE ]] || [[ -n $ALL ]] && updateGOWNT 2> /dev/null > /dev/null
progress 4
# Disable spinner
#(kill $SPIN_PID 2>&1) >/dev/null
# Check if /usr/local/src is writeable by target install user - functionLocation('generic/supportFunctions.md')
[[ -n $CORE ]] || [[ -n $ALL ]] && checkUsrLocalSrc
progress 4
## Resume spinner
#spin &
#SPIN_PID=$!
#disown
#trap "kill -9 $SPIN_PID" `seq 0 15`
# Install misp-modules - functionLocation('generic/misp-modules-debian.md')
[[ -n $MODULES ]] || [[ -n $ALL ]] && mispmodules
progress 4
# Install Viper - functionLocation('generic/viper-debian.md')
[[ -n $VIPER ]] || [[ -n $ALL ]] && viper
progress 4
# Install ssdeep - functionLocation('generic/ssdeep-debian.md')
[[ -n $SSDEEP ]] || [[ -n $ALL ]] && ssdeep
progress 4
# Install misp-dashboard - functionLocation('generic/misp-dashboard-debian.md')
[[ -n $DASHBOARD ]] || [[ -n $ALL ]] && mispDashboard ; dashboardCAKE 2> /dev/null > /dev/null
progress 4
# Install Mail2MISP - functionLocation('generic/mail_to_misp-debian.md')
[[ -n $MAIL2 ]] || [[ -n $ALL ]] && mail2misp
progress 100
# Run final script to inform the User what happened - functionLocation('generic/supportFunctions.md')
theEnd
}
# Main Kalin Install function
installMISPonKali () {
# Kali might have a bug on installs where libc6 is not up to date, this forces bash and libc to update - functionLocation('')
kaliUpgrade 2> /dev/null > /dev/null
# Set locale if not set - functionLocation('generic/supportFunctions.md')
checkLocale
# Set Base URL - functionLocation('generic/supportFunctions.md')
setBaseURL
# Install PHP 7.3 Dependencies - functionLocation('generic/supportFunctions.md')
installDepsPhp73 2> /dev/null > /dev/null
# Set custom Kali only variables and tweaks
space
# The following disables sleep on kali/gnome
### FIXME: Disabling for now, maybe source of some issues.
##disableSleep 2> /dev/null > /dev/null
##debug "Sleeping 3 seconds to make sure the disable sleep does not confuse the execution of the script."
##sleep 3
# Kali specific dependencies - functionLocation('generic/supportFunctions.md')
debug "Installing dependencies"
installDeps
# Install Core Dependencies - functionLocation('INSTALL.ubuntu1804.md')
installCoreDeps
debug "Enabling redis and gnupg modules"
phpenmod -v 7.3 redis
phpenmod -v 7.3 gnupg
debug "Apache2 ops: dismod: status php7.2 - dissite: 000-default enmod: ssl rewrite headers php7.3 ensite: default-ssl"
a2dismod status 2> /dev/null > /dev/null
a2dismod php7.2 2> /dev/null > /dev/null
a2enmod ssl rewrite headers php7.3 2> /dev/null > /dev/null
a2dissite 000-default 2> /dev/null > /dev/null
a2ensite default-ssl 2> /dev/null > /dev/null
debug "Restarting mysql.service"
systemctl restart mysql.service 2> /dev/null > /dev/null
debug "Fixing redis rc script on Kali"
fixRedis 2> /dev/null > /dev/null
debug "git clone, submodule update everything"
mkdir $PATH_TO_MISP
chown www-data:www-data $PATH_TO_MISP
cd $PATH_TO_MISP
$SUDO_WWW git clone https://github.com/MISP/MISP.git $PATH_TO_MISP
$SUDO_WWW git config core.filemode false
cd $PATH_TO_MISP
$SUDO_WWW git submodule update --init --recursive 2> /dev/null > /dev/null
# Make git ignore filesystem permission differences for submodules
$SUDO_WWW git submodule foreach --recursive git config core.filemode false
cd $PATH_TO_MISP/app/files/scripts
$SUDO_WWW git clone https://github.com/CybOXProject/python-cybox.git 2> /dev/null > /dev/null
$SUDO_WWW git clone https://github.com/STIXProject/python-stix.git 2> /dev/null > /dev/null
$SUDO_WWW git clone https://github.com/CybOXProject/mixbox.git 2> /dev/null > /dev/null
$SUDO_WWW git clone https://github.com/MAECProject/python-maec.git 2> /dev/null > /dev/null
mkdir /var/www/.cache/
MISP_USER_HOME=$(sudo -Hiu $MISP_USER env | grep HOME |cut -f 2 -d=)
mkdir $MISP_USER_HOME/.cache
chown $MISP_USER:$MISP_USER $MISP_USER_HOME/.cache
chown www-data:www-data /var/www/.cache
debug "Generating rc.local"
genRCLOCAL
debug "Setting up main MISP virtualenv"
# Needs virtualenv
sudo -u www-data virtualenv -p python3 ${PATH_TO_MISP}/venv
debug "Installing MISP dashboard"
mispDashboard
debug "Installing python-cybox"
cd $PATH_TO_MISP/app/files/scripts/python-cybox
sudo -H -u www-data ${PATH_TO_MISP}/venv/bin/pip install . 2> /dev/null > /dev/null
debug "Installing python-stix"
cd $PATH_TO_MISP/app/files/scripts/python-stix
sudo -H -u www-data ${PATH_TO_MISP}/venv/bin/pip install . 2> /dev/null > /dev/null
debug "Install maec"
cd $PATH_TO_MISP/app/files/scripts/python-maec
sudo -H -u www-data ${PATH_TO_MISP}/venv/bin/pip install . 2> /dev/null > /dev/null
# install STIX2.0 library to support STIX 2.0 export
debug "Installing cti-python-stix2"
cd ${PATH_TO_MISP}/cti-python-stix2
sudo -H -u www-data ${PATH_TO_MISP}/venv/bin/pip install -I . 2> /dev/null > /dev/null
debug "Installing mixbox"
cd $PATH_TO_MISP/app/files/scripts/mixbox
sudo -H -u www-data ${PATH_TO_MISP}/venv/bin/pip install . 2> /dev/null > /dev/null
# install PyMISP
debug "Installing PyMISP"
cd $PATH_TO_MISP/PyMISP
sudo -H -u www-data ${PATH_TO_MISP}/venv/bin/pip install . 2> /dev/null > /dev/null
# install pydeep
$SUDO_WWW ${PATH_TO_MISP}/venv/bin/pip install git+https://github.com/kbandla/pydeep.git 2> /dev/null > /dev/null
# install lief
$SUDO_WWW ${PATH_TO_MISP}/venv/bin/pip install https://github.com/lief-project/packages/raw/lief-master-latest/pylief-0.9.0.dev.zip 2> /dev/null > /dev/null
# install python-magic
$SUDO_WWW ${PATH_TO_MISP}/venv/bin/pip install python-magic 2> /dev/null > /dev/null
# Install Crypt_GPG and Console_CommandLine
debug "Installing pear Console_CommandLine"
pear install ${PATH_TO_MISP}/INSTALL/dependencies/Console_CommandLine/package.xml
debug "Installing pear Crypt_GPG"
pear install ${PATH_TO_MISP}/INSTALL/dependencies/Crypt_GPG/package.xml
debug "Installing composer with php 7.3 updates"
composer73
$SUDO_WWW cp -fa $PATH_TO_MISP/INSTALL/setup/config.php $PATH_TO_MISP/app/Plugin/CakeResque/Config/config.php
chown -R www-data:www-data $PATH_TO_MISP
chmod -R 750 $PATH_TO_MISP
chmod -R g+ws $PATH_TO_MISP/app/tmp
chmod -R g+ws $PATH_TO_MISP/app/files
chmod -R g+ws $PATH_TO_MISP/app/files/scripts/tmp
debug "Setting up database"
if [ ! -e /var/lib/mysql/misp/users.ibd ]; then
echo "
set timeout 10
spawn mysql_secure_installation
expect \"Enter current password for root (enter for none):\"
send -- \"\r\"
expect \"Set root password?\"
send -- \"y\r\"
expect \"New password:\"
send -- \"${DBPASSWORD_ADMIN}\r\"
expect \"Re-enter new password:\"
send -- \"${DBPASSWORD_ADMIN}\r\"
expect \"Remove anonymous users?\"
send -- \"y\r\"
expect \"Disallow root login remotely?\"
send -- \"y\r\"
expect \"Remove test database and access to it?\"
send -- \"y\r\"
expect \"Reload privilege tables now?\"
send -- \"y\r\"
expect eof" | expect -f -
mysql -u $DBUSER_ADMIN -p$DBPASSWORD_ADMIN -e "create database $DBNAME;"
mysql -u $DBUSER_ADMIN -p$DBPASSWORD_ADMIN -e "grant usage on *.* to $DBNAME@localhost identified by '$DBPASSWORD_MISP';"
mysql -u $DBUSER_ADMIN -p$DBPASSWORD_ADMIN -e "grant all privileges on $DBNAME.* to '$DBUSER_MISP'@'localhost';"
mysql -u $DBUSER_ADMIN -p$DBPASSWORD_ADMIN -e "flush privileges;"
enableServices
$SUDO_WWW cat $PATH_TO_MISP/INSTALL/MYSQL.sql | mysql -u $DBUSER_MISP -p$DBPASSWORD_MISP $DBNAME
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 2> /dev/null > /dev/null
else
echo "There might be a database already existing here: /var/lib/mysql/misp/users.ibd"
echo "Skipping any creations…"
sleep 3
fi
debug "Generating Certificate"
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
debug "Generating Apache Conf"
genApacheConf
echo "127.0.0.1 misp.local" | tee -a /etc/hosts
debug "Disabling site default-ssl, enabling misp-ssl"
a2dissite default-ssl
a2ensite misp-ssl
for key in upload_max_filesize post_max_size max_execution_time max_input_time memory_limit
do
sed -i "s/^\($key\).*/\1 = $(eval echo \${$key})/" $PHP_INI
done
debug "Restarting Apache2"
systemctl restart apache2
debug "Setting up logrotate"
cp $PATH_TO_MISP/INSTALL/misp.logrotate /etc/logrotate.d/misp
chmod 0640 /etc/logrotate.d/misp
$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/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
chown -R www-data:www-data $PATH_TO_MISP/app/Config
chmod -R 750 $PATH_TO_MISP/app/Config
debug "Setting up GnuPG"
setupGnuPG 2> /dev/null > /dev/null
debug "Starting workers"
chmod +x $PATH_TO_MISP/app/Console/worker/start.sh
$SUDO_WWW $PATH_TO_MISP/app/Console/worker/start.sh
debug "Running Core Cake commands"
coreCAKE 2> /dev/null > /dev/null
dashboardCAKE 2> /dev/null > /dev/null
debug "Update: Galaxies, Template Objects, Warning Lists, Notice Lists, Taxonomies"
updateGOWNT 2> /dev/null > /dev/null
gitPullAllRCLOCAL
checkUsrLocalSrc
debug "Installing misp-modules"
mispmodules
debug "Installing Viper"
viper
debug "Installing ssdeep"
ssdeep
phpenmod -v 7.3 ssdeep
debug "Setting permissions"
permissions
debug "Running Then End!"
theEnd
}
# End installMISPonKali ()
## End Function Section ##
colors
debug "Checking if we are run as the installer template"
if [[ "$0" == "./INSTALL.debian.tpl.sh" || "$(echo $0 |grep -o -e 'INSTALL.debian.tpl.sh')" == "INSTALL.debian.tpl.sh" ]]; then
generateInstaller
fi
space
debug "Setting MISP variables"
MISPvars
debug "Checking Linux distribution and flavour..."
checkFlavour
debug "Checking for parameters or Unattended Kali Install"
if [[ $# == 0 && $0 != "/tmp/misp-kali.sh" ]]; then
usage
exit
else
debug "Setting install options with given parameters."
# The setOpt/checkOpt function lives in generic/supportFunctions.md
setOpt $@
checkOpt core && echo "${LBLUE}MISP${NC} ${GREEN}core${NC} selected"
checkOpt viper && echo "${GREEN}Viper${NC} selected"
checkOpt modules && echo "${LBLUE}MISP${NC} ${GREEN}modules${NC} selected"
checkOpt dashboard && echo "${LBLUE}MISP${NC} ${GREEN}dashboard${NC} selected"
checkOpt mail2 && echo "${GREEN}Mail 2${NC} ${LBLUE}MISP${NC} selected"
checkOpt all && echo "${GREEN}All options${NC} selected"
checkOpt pre && echo "${GREEN}Pre-flight checks${NC} selected"
checkOpt unattended && echo "${GREEN}unattended${NC} install selected"
checkOpt upgrade && echo "${GREEN}upgrade${NC} install selected"
checkOpt force && echo "${GREEN}force${NC} install selected"
# Check if at least core is selected if no other options that do not require core are set
if [[ "$CORE" != "1" && "$ALL" != "1" && "$UPGRADE" != "1" && "$PRE" != "1" && "$0" != "/tmp/misp-kali.sh" ]]; then
space
usage
echo "You need to at least select core, or -A to install everything."
echo "$0 -c # Is the minima for install options"
exit 1
fi
fi
# Add upgrade option to do upgrade pre flight
[[ -n $PRE ]] && preInstall
[[ -n $UPGRADE ]] && upgrade
# If Ubuntu is detected, figure out which release it is and run the according scripts
if [ "${FLAVOUR}" == "ubuntu" ]; then
RELEASE=$(lsb_release -s -r| tr [A-Z] [a-z])
if [ "${RELEASE}" == "18.04" ]; then
echo "Install on Ubuntu 18.04 LTS fully supported."
echo "Please report bugs/issues here: https://github.com/MISP/MISP/issues"
installMISPubuntuSupported && exit || exit
fi
if [ "${RELEASE}" == "18.10" ]; then
echo "Install on Ubuntu 18.10 partially supported, bye."
installMISPubuntuSupported && exit || exit
fi
if [ "${RELEASE}" == "19.04" ]; then
echo "Install on Ubuntu 19.04 not supported, bye"
exit 1
fi
if [ "${RELEASE}" == "19.10" ]; then
echo "Install on Ubuntu 19.10 not supported, bye"
exit 1
fi
echo "Installation done!"
exit
fi
# If Debian is detected, figure out which release it is and run the according scripts
if [ "${FLAVOUR}" == "debian" ]; then
CODE=$(lsb_release -s -c| tr [A-Z] [a-z])
if [ "${CODE}" == "buster" ]; then
echo "Install on Debian testing fully supported."
echo "Please report bugs/issues here: https://github.com/MISP/MISP/issues"
installDepsPhp73
fi
if [ "${CODE}" == "sid" ]; then
echo "Install on Debian unstable not fully supported."
echo "Please report bugs/issues here: https://github.com/MISP/MISP/issues"
installDepsPhp73
fi
if [ "${CODE}" == "stretch" ]; then
echo "Install on Debian stable fully supported."
echo "Please report bugs/issues here: https://github.com/MISP/MISP/issues"
installDepsPhp72
fi
echo "Installation done!"
exit 0
fi
# If Tsurugi is detected, figure out which release it is and run the according scripts
if [ "${FLAVOUR}" == "tsurugi" ]; then
CODE=$(lsb_release -s -c| tr [A-Z] [a-z])
if [ "${CODE}" == "bamboo" ]; then
echo "Install on Tsurugi Lab partially supported."
echo "Please report bugs/issues here: https://github.com/MISP/MISP/issues"
fi
if [ "${CODE}" == "soy sauce" ]; then
echo "Install on Tsurugi Acquire partially supported."
echo "Please report bugs/issues here: https://github.com/MISP/MISP/issues"
fi
echo "Installation done!"
exit 0
fi
# If Kali Linux is detected, run the acccording scripts
if [ "${FLAVOUR}" == "kali" ]; then
KALI=1
kaliOnRootR0ckz
installMISPonKali
echo "Installation done!"
exit
fi

View File

@ -1 +0,0 @@
../docs/INSTALL.debian9.md

View File

@ -1,592 +0,0 @@
#!/usr/bin/env bash
#INSTALLATION INSTRUCTIONS
#------------------------- for Kali Linux
#
#0/ Quick MISP Instance on Kali Linux - Status
#---------------------------------------------
#
#1/ Prepare Kali with a MISP User
#--------------------------------
# To install MISP on Kali copy paste this in your r00t shell:
# wget -O /tmp/misp-kali.sh https://raw.githubusercontent.com/MISP/MISP/2.4/INSTALL/INSTALL.kali.txt && bash /tmp/misp-kali.sh
# /!\ Please read the installer script before randomly doing the above.
# The script is tested on a plain vanilla Kali Linux Boot CD and installs quite a few dependencies.
MISP_USER='misp'
MISP_PASSWORD='Password1234'
function kaliOnRootR0ckz() {
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root"
exit 1
elif [[ $(id misp >/dev/null; echo $?) -ne 0 ]]; then
useradd -s /bin/bash -m -G adm,cdrom,sudo,dip,plugdev,www-data misp
echo $MISP_USER:$MISP_PASSWORD | chpasswd
else
echo "User ${MISP_USER} exists, skipping creation"
fi
}
function installMISPonKali() {
# MISP configuration variables
PATH_TO_MISP='/var/www/MISP'
MISP_BASEURL='https://misp.local'
MISP_LIVE='1'
CAKE="$PATH_TO_MISP/app/Console/cake"
# Database configuration
DBHOST='localhost'
DBNAME='misp'
DBUSER_ADMIN='root'
DBPASSWORD_ADMIN="$(openssl rand -hex 32)"
DBUSER_MISP='misp'
DBPASSWORD_MISP="$(openssl rand -hex 32)"
# Webserver configuration
FQDN='misp.local'
# OpenSSL configuration
OPENSSL_CN=$FQDN
OPENSSL_C='LU'
OPENSSL_ST='State'
OPENSSL_L='Location'
OPENSSL_O='Organization'
OPENSSL_OU='Organizational Unit'
OPENSSL_EMAILADDRESS='info@localhost'
# GPG configuration
GPG_REAL_NAME='Autogenerated Key'
GPG_COMMENT='WARNING: MISP AutoGenerated Key consider this Key VOID!'
GPG_EMAIL_ADDRESS='admin@admin.test'
GPG_KEY_LENGTH='2048'
GPG_PASSPHRASE='Password1234'
# php.ini configuration
upload_max_filesize=50M
post_max_size=50M
max_execution_time=300
memory_limit=512M
PHP_INI=/etc/php/7.2/apache2/php.ini
# apt config
export DEBIAN_FRONTEND=noninteractive
# sudo config to run $LUSER commands
SUDO="sudo -u ${MISP_USER}"
SUDO_WWW="sudo -u www-data"
echo "Admin (${DBUSER_ADMIN}) DB Password: ${DBPASSWORD_ADMIN}"
echo "User (${DBUSER_MISP}) DB Password: ${DBPASSWORD_MISP}"
echo "-----------------------------------------------------------------------"
echo "Disabling sleep etc…"
gsettings set org.gnome.settings-daemon.plugins.power sleep-inactive-ac-timeout 0
gsettings set org.gnome.settings-daemon.plugins.power sleep-inactive-battery-timeout 0
gsettings set org.gnome.settings-daemon.plugins.power sleep-inactive-battery-type 'nothing'
xset s 0 0
xset dpms 0 0
xset s off
apt update
apt install -qy etckeeper
# Skip dist-upgrade for now, pulls in 500+ updated packages
#sudo apt -y dist-upgrade
git config --global user.email "root@kali.lan"
git config --global user.name "Root User"
apt install -qy postfix
apt install -qy \
curl gcc git gnupg-agent make openssl redis-server neovim zip libyara-dev python3-yara python3-redis python3-zmq \
mariadb-client \
mariadb-server \
apache2 apache2-doc apache2-utils \
libapache2-mod-php7.2 php7.2 php7.2-cli php7.2-mbstring php-pear php7.2-dev php7.2-json php7.2-xml php7.2-mysql php7.2-opcache php7.2-readline \
python3-dev python3-pip libpq5 libjpeg-dev libfuzzy-dev ruby asciidoctor \
libxml2-dev libxslt1-dev zlib1g-dev python3-setuptools expect
modprobe tpm-rng
echo tpm-rng >> /etc/modules
apt install -qy rng-tools # This might fail on TPM grounds, enable the security chip in your BIOS
service rng-tools start
systemctl restart mariadb.service
a2dismod status
a2enmod ssl rewrite headers
a2dissite 000-default
a2ensite default-ssl
pear channel-update pear.php.net
pear install Crypt_GPG
pecl channel-update pecl.php.net
yes '' |pecl install redis
echo "extension=redis.so" | tee /etc/php/7.2/mods-available/redis.ini
phpenmod redis
update-alternatives --install /usr/bin/python python /usr/bin/python2.7 1
update-alternatives --install /usr/bin/python python /usr/bin/python3.6 2
mkdir $PATH_TO_MISP
chown www-data:www-data $PATH_TO_MISP
cd $PATH_TO_MISP
$SUDO_WWW git clone https://github.com/MISP/MISP.git $PATH_TO_MISP
$SUDO_WWW git config core.filemode false
cd $PATH_TO_MISP/app/files/scripts
$SUDO_WWW git clone https://github.com/CybOXProject/python-cybox.git
$SUDO_WWW git clone https://github.com/STIXProject/python-stix.git
cd $PATH_TO_MISP/app/files/scripts/python-cybox
pip3 install .
cd $PATH_TO_MISP/app/files/scripts/python-stix
pip3 install .
cd $PATH_TO_MISP/app/files/scripts/
$SUDO_WWW git clone https://github.com/CybOXProject/mixbox.git
cd $PATH_TO_MISP/app/files/scripts/mixbox
pip3 install .
cd $PATH_TO_MISP
$SUDO_WWW git submodule update --init --recursive
# Make git ignore filesystem permission differences for submodules
$SUDO_WWW git submodule foreach --recursive git config core.filemode false
# install PyMISP
cd $PATH_TO_MISP/PyMISP
pip3 install .
cd $PATH_TO_MISP/app
mkdir /var/www/.composer ; chown www-data:www-data /var/www/.composer
$SUDO_WWW php composer.phar require kamisama/cake-resque:4.1.2
$SUDO_WWW php composer.phar config vendor-dir Vendor
$SUDO_WWW php composer.phar install
$SUDO_WWW cp -fa $PATH_TO_MISP/INSTALL/setup/config.php $PATH_TO_MISP/app/Plugin/CakeResque/Config/config.php
chown -R www-data:www-data $PATH_TO_MISP
chmod -R 750 $PATH_TO_MISP
chmod -R g+ws $PATH_TO_MISP/app/tmp
chmod -R g+ws $PATH_TO_MISP/app/files
chmod -R g+ws $PATH_TO_MISP/app/files/scripts/tmp
if [ ! -e /var/lib/mysql/misp/users.ibd ]; then
echo "
set timeout 10
spawn mysql_secure_installation
expect \"Enter current password for root (enter for none):\"
send -- \"\r\"
expect \"Set root password?\"
send -- \"y\r\"
expect \"New password:\"
send -- \"${DBPASSWORD_ADMIN}\r\"
expect \"Re-enter new password:\"
send -- \"${DBPASSWORD_ADMIN}\r\"
expect \"Remove anonymous users?\"
send -- \"y\r\"
expect \"Disallow root login remotely?\"
send -- \"y\r\"
expect \"Remove test database and access to it?\"
send -- \"y\r\"
expect \"Reload privilege tables now?\"
send -- \"y\r\"
expect eof" | expect -f -
mysql -u $DBUSER_ADMIN -p$DBPASSWORD_ADMIN -e "create database $DBNAME;"
mysql -u $DBUSER_ADMIN -p$DBPASSWORD_ADMIN -e "grant usage on *.* to $DBNAME@localhost identified by '$DBPASSWORD_MISP';"
mysql -u $DBUSER_ADMIN -p$DBPASSWORD_ADMIN -e "grant all privileges on $DBNAME.* to '$DBUSER_MISP'@'localhost';"
mysql -u $DBUSER_ADMIN -p$DBPASSWORD_ADMIN -e "flush privileges;"
update-rc.d mysql enable
update-rc.d apache2 enable
update-rc.d redis-server enable
$SUDO_WWW cat $PATH_TO_MISP/INSTALL/MYSQL.sql | mysql -u $DBUSER_MISP -p$DBPASSWORD_MISP $DBNAME
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
else
echo "There might be a database already existing here: /var/lib/mysql/misp/users.ibd"
echo "Skipping any creations…"
sleep 3
fi
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
if [ ! -e /etc/rc.local ]
then
echo '#!/bin/sh -e' | tee -a /etc/rc.local
echo 'exit 0' | tee -a /etc/rc.local
chmod u+x /etc/rc.local
fi
cd /var/www
mkdir misp-dashboard
chown www-data:www-data misp-dashboard
$SUDO_WWW git clone https://github.com/MISP/misp-dashboard.git
cd misp-dashboard
/var/www/misp-dashboard/install_dependencies.sh
sed -i "s/^host\ =\ localhost/host\ =\ 0.0.0.0/g" /var/www/misp-dashboard/config/config.cfg
sed -i -e '$i \sudo -u www-data bash /var/www/misp-dashboard/start_all.sh\n' /etc/rc.local
sed -i -e '$i \sudo -u misp /usr/local/src/viper/viper-web -p 8888 -H 0.0.0.0 &\n' /etc/rc.local
sed -i -e '$i \git_dirs="/usr/local/src/misp-modules/ /var/www/misp-dashboard /usr/local/src/faup /usr/local/src/mail_to_misp /usr/local/src/misp-modules /usr/local/src/viper /var/www/misp-dashboard"\n' /etc/rc.local
sed -i -e '$i \for d in $git_dirs; do\n' /etc/rc.local
sed -i -e '$i \ echo "Updating ${d}"\n' /etc/rc.local
sed -i -e '$i \ cd $d && sudo git pull &\n' /etc/rc.local
sed -i -e '$i \done\n' /etc/rc.local
$SUDO_WWW bash /var/www/misp-dashboard/start_all.sh
apt install libapache2-mod-wsgi-py3 -y
echo "<VirtualHost _default_:80>
ServerAdmin admin@localhost.lu
ServerName misp.local
Redirect permanent / https://misp.local
LogLevel warn
ErrorLog /var/log/apache2/misp.local_error.log
CustomLog /var/log/apache2/misp.local_access.log combined
ServerSignature Off
</VirtualHost>
<VirtualHost _default_:443>
ServerAdmin admin@localhost.lu
ServerName misp.local
DocumentRoot $PATH_TO_MISP/app/webroot
<Directory $PATH_TO_MISP/app/webroot>
Options -Indexes
AllowOverride all
Require all granted
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
Header set X-Content-Type-Options nosniff
Header set X-Frame-Options DENY
</VirtualHost>" | tee /etc/apache2/sites-available/misp-ssl.conf
echo "127.0.0.1 misp.local" | tee -a /etc/hosts
echo "<VirtualHost *:8001>
ServerAdmin admin@misp.local
ServerName misp.local
DocumentRoot /var/www/misp-dashboard
WSGIDaemonProcess misp-dashboard \
user=misp group=misp \
python-home=/var/www/misp-dashboard/DASHENV \
processes=1 \
threads=15 \
maximum-requests=5000 \
listen-backlog=100 \
queue-timeout=45 \
socket-timeout=60 \
connect-timeout=15 \
request-timeout=60 \
inactivity-timeout=0 \
deadlock-timeout=60 \
graceful-timeout=15 \
eviction-timeout=0 \
shutdown-timeout=5 \
send-buffer-size=0 \
receive-buffer-size=0 \
header-buffer-size=0 \
response-buffer-size=0 \
server-metrics=Off
WSGIScriptAlias / /var/www/misp-dashboard/misp-dashboard.wsgi
<Directory /var/www/misp-dashboard>
WSGIProcessGroup misp-dashboard
WSGIApplicationGroup %{GLOBAL}
Require all granted
</Directory>
LogLevel info
ErrorLog /var/log/apache2/misp-dashboard.local_error.log
CustomLog /var/log/apache2/misp-dashboard.local_access.log combined
ServerSignature Off
</VirtualHost>" | tee /etc/apache2/sites-available/misp-dashboard.conf
a2dissite default-ssl
a2ensite misp-ssl
a2ensite misp-dashboard
for key in upload_max_filesize post_max_size max_execution_time max_input_time memory_limit
do
sed -i "s/^\($key\).*/\1 = $(eval echo \${$key})/" $PHP_INI
done
systemctl restart apache2
cp $PATH_TO_MISP/INSTALL/misp.logrotate /etc/logrotate.d/misp
chmod 0640 /etc/logrotate.d/misp
$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/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
chown -R www-data:www-data $PATH_TO_MISP/app/Config
chmod -R 750 $PATH_TO_MISP/app/Config
$CAKE Live $MISP_LIVE
$CAKE Baseurl $MISP_BASEURL
echo "%echo Generating a default key
Key-Type: default
Key-Length: $GPG_KEY_LENGTH
Subkey-Type: default
Name-Real: $GPG_REAL_NAME
Name-Comment: $GPG_COMMENT
Name-Email: $GPG_EMAIL_ADDRESS
Expire-Date: 0
Passphrase: $GPG_PASSPHRASE
# Do a commit here, so that we can later print "done"
%commit
%echo done" > /tmp/gen-key-script
$SUDO_WWW gpg --homedir $PATH_TO_MISP/.gnupg --batch --gen-key /tmp/gen-key-script
$SUDO_WWW sh -c "gpg --homedir $PATH_TO_MISP/.gnupg --export --armor $GPG_EMAIL_ADDRESS" | $SUDO_WWW tee $PATH_TO_MISP/app/webroot/gpg.asc
chmod +x $PATH_TO_MISP/app/Console/worker/start.sh
$CAKE userInit -q
AUTH_KEY=$(mysql -u $DBUSER_MISP -p$DBPASSWORD_MISP misp -e "SELECT authkey FROM users;" | tail -1)
$CAKE Admin setSetting "Plugin.ZeroMQ_enable" true
$CAKE Admin setSetting "Plugin.ZeroMQ_event_notifications_enable" true
$CAKE Admin setSetting "Plugin.ZeroMQ_object_notifications_enable" true
$CAKE Admin setSetting "Plugin.ZeroMQ_object_reference_notifications_enable" true
$CAKE Admin setSetting "Plugin.ZeroMQ_attribute_notifications_enable" true
$CAKE Admin setSetting "Plugin.ZeroMQ_sighting_notifications_enable" true
$CAKE Admin setSetting "Plugin.ZeroMQ_user_notifications_enable" true
$CAKE Admin setSetting "Plugin.ZeroMQ_organisation_notifications_enable" true
$CAKE Admin setSetting "Plugin.ZeroMQ_port" 50000
$CAKE Admin setSetting "Plugin.ZeroMQ_redis_host" "localhost"
$CAKE Admin setSetting "Plugin.ZeroMQ_redis_port" 6379
$CAKE Admin setSetting "Plugin.ZeroMQ_redis_database" 1
$CAKE Admin setSetting "Plugin.ZeroMQ_redis_namespace" "mispq"
$CAKE Admin setSetting "Plugin.ZeroMQ_include_attachments" false
$CAKE Admin setSetting "Plugin.ZeroMQ_tag_notifications_enable" false
$CAKE Admin setSetting "Plugin.ZeroMQ_audit_notifications_enable" false
$CAKE Admin setSetting "GnuPG.email" "admin@admin.test"
$CAKE Admin setSetting "GnuPG.homedir" "/var/www/MISP/.gnupg"
$CAKE Admin setSetting "GnuPG.password" "Password1234"
$CAKE Admin setSetting "Plugin.Enrichment_services_enable" true
$CAKE Admin setSetting "Plugin.Enrichment_hover_enable" true
$CAKE Admin setSetting "Plugin.Enrichment_timeout" 300
$CAKE Admin setSetting "Plugin.Enrichment_hover_timeout" 150
$CAKE Admin setSetting "Plugin.Enrichment_cve_enabled" true
$CAKE Admin setSetting "Plugin.Enrichment_dns_enabled" true
$CAKE Admin setSetting "Plugin.Enrichment_services_url" "http://127.0.0.1"
$CAKE Admin setSetting "Plugin.Enrichment_services_port" 6666
$CAKE Admin setSetting "Plugin.Import_services_enable" true
$CAKE Admin setSetting "Plugin.Import_services_url" "http://127.0.0.1"
$CAKE Admin setSetting "Plugin.Import_services_port" 6666
$CAKE Admin setSetting "Plugin.Import_timeout" 300
$CAKE Admin setSetting "Plugin.Import_ocr_enabled" true
$CAKE Admin setSetting "Plugin.Import_csvimport_enabled" true
$CAKE Admin setSetting "Plugin.Export_services_enable" true
$CAKE Admin setSetting "Plugin.Export_services_url" "http://127.0.0.1"
$CAKE Admin setSetting "Plugin.Export_services_port" 6666
$CAKE Admin setSetting "Plugin.Export_timeout" 300
$CAKE Admin setSetting "Plugin.Export_pdfexport_enabled" true
$CAKE Admin setSetting "MISP.host_org_id" 1
$CAKE Admin setSetting "MISP.email" "info@admin.test"
$CAKE Admin setSetting "MISP.disable_emailing" false
$CAKE Admin setSetting "MISP.contact" "info@admin.test"
$CAKE Admin setSetting "MISP.disablerestalert" true
$CAKE Admin setSetting "MISP.showCorrelationsOnIndex" true
$CAKE Admin setSetting "Plugin.Cortex_services_enable" false
$CAKE Admin setSetting "Plugin.Cortex_services_url" "http://127.0.0.1"
$CAKE Admin setSetting "Plugin.Cortex_services_port" 9000
$CAKE Admin setSetting "Plugin.Cortex_timeout" 120
$CAKE Admin setSetting "Plugin.Cortex_services_url" "http://127.0.0.1"
$CAKE Admin setSetting "Plugin.Cortex_services_port" 9000
$CAKE Admin setSetting "Plugin.Cortex_services_timeout" 120
$CAKE Admin setSetting "Plugin.Cortex_services_authkey" ""
$CAKE Admin setSetting "Plugin.Cortex_ssl_verify_peer" false
$CAKE Admin setSetting "Plugin.Cortex_ssl_verify_host" false
$CAKE Admin setSetting "Plugin.Cortex_ssl_allow_self_signed" true
$CAKE Admin setSetting "Plugin.Sightings_policy" 0
$CAKE Admin setSetting "Plugin.Sightings_anonymise" false
$CAKE Admin setSetting "Plugin.Sightings_range" 365
$CAKE Admin setSetting "Plugin.CustomAuth_disable_logout" false
$CAKE Admin setSetting "Plugin.RPZ_policy" "DROP"
$CAKE Admin setSetting "Plugin.RPZ_walled_garden" "127.0.0.1"
$CAKE Admin setSetting "Plugin.RPZ_serial" "\$date00"
$CAKE Admin setSetting "Plugin.RPZ_refresh" "2h"
$CAKE Admin setSetting "Plugin.RPZ_retry" "30m"
$CAKE Admin setSetting "Plugin.RPZ_expiry" "30d"
$CAKE Admin setSetting "Plugin.RPZ_minimum_ttl" "1h"
$CAKE Admin setSetting "Plugin.RPZ_ttl" "1w"
$CAKE Admin setSetting "Plugin.RPZ_ns" "localhost."
$CAKE Admin setSetting "Plugin.RPZ_ns_alt" ""
$CAKE Admin setSetting "Plugin.RPZ_email" "root.localhost"
$CAKE Admin setSetting "MISP.language" "eng"
$CAKE Admin setSetting "MISP.proposals_block_attributes" false
$CAKE Admin setSetting "MISP.redis_host" "127.0.0.1"
$CAKE Admin setSetting "MISP.redis_port" 6379
$CAKE Admin setSetting "MISP.redis_database" 13
$CAKE Admin setSetting "MISP.redis_password" ""
$CAKE Admin setSetting "MISP.ssdeep_correlation_threshold" 40
$CAKE Admin setSetting "MISP.extended_alert_subject" false
$CAKE Admin setSetting "MISP.default_event_threat_level" 4
$CAKE Admin setSetting "MISP.newUserText" "Dear new MISP user,\\n\\nWe would hereby like to welcome you to the \$org MISP community.\\n\\n Use the credentials below to log into MISP at \$misp, where you will be prompted to manually change your password to something of your own choice.\\n\\nUsername: \$username\\nPassword: \$password\\n\\nIf you have any questions, don't hesitate to contact us at: \$contact.\\n\\nBest regards,\\nYour \$org MISP support team"
$CAKE Admin setSetting "MISP.passwordResetText" "Dear MISP user,\\n\\nA password reset has been triggered for your account. Use the below provided temporary password to log into MISP at \$misp, where you will be prompted to manually change your password to something of your own choice.\\n\\nUsername: \$username\\nYour temporary password: \$password\\n\\nIf you have any questions, don't hesitate to contact us at: \$contact.\\n\\nBest regards,\\nYour \$org MISP support team"
$CAKE Admin setSetting "MISP.enableEventBlacklisting" true
$CAKE Admin setSetting "MISP.enableOrgBlacklisting" true
$CAKE Admin setSetting "MISP.log_client_ip" false
$CAKE Admin setSetting "MISP.log_auth" false
$CAKE Admin setSetting "MISP.disableUserSelfManagement" false
$CAKE Admin setSetting "MISP.block_event_alert" false
$CAKE Admin setSetting "MISP.block_event_alert_tag" "no-alerts=\"true\""
$CAKE Admin setSetting "MISP.block_old_event_alert" false
$CAKE Admin setSetting "MISP.block_old_event_alert_age" ""
$CAKE Admin setSetting "MISP.incoming_tags_disabled_by_default" false
$CAKE Admin setSetting "MISP.footermidleft" "This is an autogenerated install"
$CAKE Admin setSetting "MISP.footermidright" "Please configure accordingly and do not use in production"
$CAKE Admin setSetting "MISP.welcome_text_top" "Autogenerated install, please configure and harden accordingly"
$CAKE Admin setSetting "MISP.welcome_text_bottom" "Welcome to MISP on Kali"
$CAKE Admin setSetting "Security.password_policy_length" 12
$CAKE Admin setSetting "Security.password_policy_complexity" '/^((?=.*\d)|(?=.*\W+))(?![\n])(?=.*[A-Z])(?=.*[a-z]).*$|.{16,}/'
$CAKE Admin setSetting "Session.autoRegenerate" 0
$CAKE Admin setSetting "Session.timeout" 600
$CAKE Admin setSetting "Session.cookie_timeout" 3600
$CAKE Live $MISP_LIVE
$CAKE Admin updateGalaxies
$CAKE Admin updateTaxonomies
#$CAKE Admin updateWarningLists
curl --header "Authorization: $AUTH_KEY" --header "Accept: application/json" --header "Content-Type: application/json" -k -X POST https://127.0.0.1/warninglists/update
curl --header "Authorization: $AUTH_KEY" --header "Accept: application/json" --header "Content-Type: application/json" -k -X POST https://127.0.0.1/noticelists/update
curl --header "Authorization: $AUTH_KEY" --header "Accept: application/json" --header "Content-Type: application/json" -k -X POST https://127.0.0.1/objectTemplates/update
sed -i -e '$i \echo never > /sys/kernel/mm/transparent_hugepage/enabled\n' /etc/rc.local
sed -i -e '$i \echo 1024 > /proc/sys/net/core/somaxconn\n' /etc/rc.local
sed -i -e '$i \sysctl vm.overcommit_memory=1\n' /etc/rc.local
sed -i -e '$i \sudo -u www-data bash /var/www/MISP/app/Console/worker/start.sh\n' /etc/rc.local
sed -i -e '$i \sudo -u www-data misp-modules -l 0.0.0.0 -s &\n' /etc/rc.local
$SUDO_WWW bash $PATH_TO_MISP/app/Console/worker/start.sh
cd /usr/local/src/
git clone https://github.com/MISP/misp-modules.git
cd misp-modules
# pip3 install
pip3 install -I -r REQUIREMENTS
pip3 install -I .
pip3 install maec lief python-magic wand yara
pip3 install git+https://github.com/kbandla/pydeep.git
pip3 install stix2
gem install pygments.rb
gem install asciidoctor-pdf --pre
$SUDO_WWW misp-modules -l 0.0.0.0 -s &
cd /usr/local/src/
apt-get install -y libssl-dev swig python3-ssdeep p7zip-full unrar-free sqlite python3-pyclamd exiftool radare2
pip3 install SQLAlchemy PrettyTable python-magic
git clone https://github.com/viper-framework/viper.git
chown -R $MISP_USER:$MISP_USER viper
cd viper
$SUDO git submodule update --init --recursive
pip3 install -r requirements.txt
pip3 uninstall yara -y
$SUDO /usr/local/src/viper/viper-cli -h > /dev/null
$SUDO /usr/local/src/viper/viper-web -p 8888 -H 0.0.0.0 &
echo 'PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/local/src/viper:/var/www/MISP/app/Console"' |tee /etc/environment
echo ". /etc/environment" >> /home/${MISP_USER}/.profile
$SUDO sed -i "s/^misp_url\ =/misp_url\ =\ http:\/\/localhost/g" /home/${MISP_USER}/.viper/viper.conf
$SUDO sed -i "s/^misp_key\ =/misp_key\ =\ $AUTH_KEY/g" /home/${MISP_USER}/.viper/viper.conf
while [ "$(sqlite3 /home/${MISP_USER}/.viper/admin.db 'UPDATE auth_user SET password="pbkdf2_sha256$100000$iXgEJh8hz7Cf$vfdDAwLX8tko1t0M1TLTtGlxERkNnltUnMhbv56wK/U="'; echo $?)" -ne "0" ]; do
# FIXME This might lead to a race condition, the while loop is sub-par
chown $MISP_USER:$MISP_USER /home/${MISP_USER}/.viper/admin.db
echo "Updating viper-web admin password, giving process time to start-up, sleeping 5, 4, 3,…"
sleep 6
done
chown -R www-data:www-data $PATH_TO_MISP
chmod -R 750 $PATH_TO_MISP
chmod -R g+ws $PATH_TO_MISP/app/tmp
chmod -R g+ws $PATH_TO_MISP/app/files
chmod -R g+ws $PATH_TO_MISP/app/files/scripts/tmp
# TODO: fix faup
cd /usr/local/src/
apt-get install -y cmake
git clone https://github.com/MISP/mail_to_misp.git
git clone git://github.com/stricaud/faup.git faup
chown -R ${MISP_USER}:${MISP_USER} faup mail_to_misp
cd faup
$SUDO mkdir -p build
cd build
$SUDO cmake .. && $SUDO make
make install
ldconfig
cd ../../
cd mail_to_misp
pip3 install -r requirements.txt
$SUDO cp mail_to_misp_config.py-example mail_to_misp_config.py
sed -i "s/^misp_url\ =\ 'YOUR_MISP_URL'/misp_url\ =\ 'http:\/\/localhost'/g" /usr/local/src/mail_to_misp/mail_to_misp_config.py
sed -i "s/^misp_key\ =\ 'YOUR_KEY_HERE'/misp_key\ =\ '$AUTH_KEY'/g" /usr/local/src/mail_to_misp/mail_to_misp_config.py
echo ""
echo "Admin (root) DB Password: $DBPASSWORD_ADMIN" > /home/${MISP_USER}/mysql.txt
echo "User (misp) DB Password: $DBPASSWORD_MISP" >> /home/${MISP_USER}/mysql.txt
echo "Authkey: $AUTH_KEY" > /home/${MISP_USER}/MISP-authkey.txt
clear
echo "-------------------------------------------------------------------------"
echo "MISP Installed, access here: https://misp.local"
echo "User: admin@admin.test"
echo "Password: admin"
echo "MISP Dashboard, access here: http://misp.local:8001"
echo "-------------------------------------------------------------------------"
cat /home/${MISP_USER}/mysql.txt
cat /home/${MISP_USER}/MISP-authkey.txt
echo "-------------------------------------------------------------------------"
echo "The LOCAL system credentials:"
echo "User: ${MISP_USER}"
echo "Password: ${MISP_PASSWORD}"
echo "-------------------------------------------------------------------------"
echo "viper-web installed, access here: http://misp.local:8888"
echo "viper-cli configured with your MISP Site Admin Auth Key"
echo "User: admin"
echo "Password: Password1234"
echo "-------------------------------------------------------------------------"
echo "To enable outgoing mails via postfix set a permissive SMTP server for the domains you want to contact:"
echo ""
echo "sudo postconf -e 'relayhost = example.com'"
echo "sudo postfix reload"
echo "-------------------------------------------------------------------------"
echo "Enjoy using MISP. For any issues see here: https://github.com/MISP/MISP/issues"
su - misp
}
kaliOnRootR0ckz
installMISPonKali

1
INSTALL/INSTALL.kali.txt Symbolic link
View File

@ -0,0 +1 @@
INSTALL.debian.sh

View File

@ -1 +0,0 @@
../docs/INSTALL.ubuntu1804.with.webmin.md

View File

@ -904,7 +904,7 @@ CREATE TABLE IF NOT EXISTS `tags` (
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`colour` varchar(7) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`exportable` tinyint(1) NOT NULL,
`org_id` tinyint(1) NOT NULL DEFAULT 0,
`org_id` int(11) NOT NULL DEFAULT 0,
`user_id` int(11) NOT NULL DEFAULT 0,
`hide_tag` tinyint(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,22 +1,22 @@
<VirtualHost *:443>
ServerAdmin me@me.local
ServerName misp.local
DocumentRoot /var/www/MISP/app/webroot
<Directory /var/www/MISP/app/webroot>
Options -Indexes
AllowOverride all
Require all granted
</Directory>
ServerAdmin me@me.local
ServerName misp.local
DocumentRoot /var/www/MISP/app/webroot
<Directory /var/www/MISP/app/webroot>
Options -Indexes
AllowOverride all
Require all granted
</Directory>
SSLEngine On
SSLCertificateFile /etc/ssl/private/misp.local.crt
SSLCertificateKeyFile /etc/ssl/private/misp.local.key
SSLCertificateChainFile /etc/ssl/private/misp-chain.crt
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
Header set X-Content-Type-Options nosniff
Header set X-Frame-Options DENY
LogLevel warn
ErrorLog /var/log/apache2/misp.local_error.log
CustomLog /var/log/apache2/misp.local_access.log combined
ServerSignature Off
Header set X-Content-Type-Options nosniff
Header set X-Frame-Options DENY
</VirtualHost>

View File

@ -1,26 +1,26 @@
<VirtualHost *:80>
ServerAdmin me@me.local
ServerName misp.local
DocumentRoot /var/www/MISP/app/webroot
<Directory /var/www/MISP/app/webroot>
Options -Indexes
AllowOverride all
Order allow,deny
allow from all
</Directory>
ServerAdmin me@me.local
ServerName misp.local
DocumentRoot /var/www/MISP/app/webroot
<Directory /var/www/MISP/app/webroot>
Options -Indexes
AllowOverride all
Order allow,deny
Allow from all
</Directory>
<IfModule !mod_php5.c>
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
DirectoryIndex /index.php index.php
<FilesMatch \.php$>
SetHandler "proxy:fcgi://127.0.0.1:9000"
</FilesMatch>
</IfModule>
<IfModule !mod_php5.c>
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
DirectoryIndex /index.php index.php
<FilesMatch \.php$>
SetHandler "proxy:fcgi://127.0.0.1:9000"
</FilesMatch>
</IfModule>
LogLevel warn
ErrorLog /var/log/httpd/misp.local_error.log
CustomLog /var/log/httpd/misp.local_access.log combined
ServerSignature Off
Header set X-Content-Type-Options nosniff
Header set X-Frame-Options DENY
LogLevel warn
ErrorLog /var/log/httpd/misp.local_error.log
CustomLog /var/log/httpd/misp.local_access.log combined
ServerSignature Off
Header set X-Content-Type-Options nosniff
Header set X-Frame-Options DENY
</VirtualHost>

View File

@ -0,0 +1,43 @@
<VirtualHost *:80>
ServerAdmin me@me.local
ServerName misp.local
Redirect permanent / https://127.0.0.1
LogLevel warn
ErrorLog /var/log/httpd/misp.local_error.log
CustomLog /var/log/httpd/misp.local_access.log combined
ServerSignature Off
</VirtualHost>
<VirtualHost *:443>
ServerAdmin me@me.local
ServerName misp.local
DocumentRoot /var/www/MISP/app/webroot
<Directory /var/www/MISP/app/webroot>
Options -Indexes
AllowOverride all
Order allow,deny
Allow from all
</Directory>
<IfModule !mod_php5.c>
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
DirectoryIndex /index.php index.php
<FilesMatch \.php$>
SetHandler "proxy:fcgi://127.0.0.1:9000"
</FilesMatch>
</IfModule>
SSLEngine On
SSLCertificateFile /etc/pki/tls/certs/misp.local.crt
SSLCertificateKeyFile /etc/pki/tls/private/misp.local.key
SSLCertificateChainFile /etc/pki/tls/certs/misp-chain.crt
LogLevel warn
ErrorLog /var/log/httpd/misp.local_error.log
CustomLog /var/log/httpd/misp.local_access.log combined
ServerSignature Off
Header set X-Content-Type-Options nosniff
Header set X-Frame-Options DENY
</VirtualHost>

View File

@ -1,18 +1,18 @@
<VirtualHost *:80>
ServerAdmin me@me.local
ServerName misp.local
DocumentRoot /var/www/MISP/app/webroot
<Directory /var/www/MISP/app/webroot>
Options -Indexes
AllowOverride all
Order allow,deny
allow from all
</Directory>
ServerAdmin me@me.local
ServerName misp.local
DocumentRoot /var/www/MISP/app/webroot
<Directory /var/www/MISP/app/webroot>
Options -Indexes
AllowOverride all
Order allow,deny
Allow from all
</Directory>
LogLevel warn
ErrorLog /var/log/apache2/misp.local_error.log
CustomLog /var/log/apache2/misp.local_access.log combined
ServerSignature Off
Header set X-Content-Type-Options nosniff
Header set X-Frame-Options DENY
LogLevel warn
ErrorLog /var/log/apache2/misp.local_error.log
CustomLog /var/log/apache2/misp.local_access.log combined
ServerSignature Off
Header set X-Content-Type-Options nosniff
Header set X-Frame-Options DENY
</VirtualHost>

@ -0,0 +1 @@
Subproject commit 40fca1d3dabbbb23e13b333bd5c615ca19d7d73f

@ -0,0 +1 @@
Subproject commit bf07ab51207446ed33ea0075083df9bbc2358617

@ -0,0 +1 @@
Subproject commit 5ccc654f03086febbec95e3358b7bae80ca9af6f

1
INSTALL/generic Symbolic link
View File

@ -0,0 +1 @@
../docs/generic

5
INSTALL/logos/README.md Normal file
View File

@ -0,0 +1,5 @@
# MISP logos
MISP logos are licensed under [CC-BY](https://creativecommons.org/licenses/by/4.0/).
If you are using the MISP logo, don't hesitate to contact us if you have any question.

167
INSTALL/logos/misp-logo.svg Normal file
View File

@ -0,0 +1,167 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="67.622406mm"
height="49.558979mm"
viewBox="0 0 67.622406 49.558979"
version="1.1"
id="svg108"
inkscape:version="0.92.3 (2405546, 2018-03-11)"
sodipodi:docname="misp-logo.svg">
<defs
id="defs102">
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath312-7">
<path
inkscape:connector-curvature="0"
d="M 0,0 H 595.276 V 841.89 H 0 Z"
id="path314-0" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath1086">
<path
inkscape:connector-curvature="0"
d="M 0,0 H 595.276 V 841.89 H 0 Z"
id="path1088" />
</clipPath>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.35"
inkscape:cx="-155.06677"
inkscape:cy="96.511905"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="1920"
inkscape:window-height="1025"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1" />
<metadata
id="metadata105">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-6.2542725,-124.80979)">
<g
id="g1076"
transform="matrix(0.35277777,0,0,-0.35277777,6.2542725,151.16434)"
inkscape:export-filename="/home/adulau/misp.png"
inkscape:export-xdpi="100"
inkscape:export-ydpi="100">
<path
d="M 0,0 H 14.014 L 22.629,-14.129 31.245,0 H 45.258 V -40.204 H 31.875 v 19.93 l -9.246,-14.302 h -0.23 l -9.247,14.302 v -19.93 H 0 Z"
style="fill:#5f6062;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path1078"
inkscape:connector-curvature="0" />
</g>
<path
d="m 24.567932,151.16434 h 4.741334 v 14.18308 h -4.741334 z"
style="fill:#5f6062;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.28222224"
id="path1080"
inkscape:connector-curvature="0"
inkscape:export-filename="/home/adulau/misp.png"
inkscape:export-xdpi="100"
inkscape:export-ydpi="100" />
<g
id="g1082"
transform="matrix(0.35277777,0,0,-0.35277777,-74.454256,298.51394)"
inkscape:export-filename="/home/adulau/misp.png"
inkscape:export-xdpi="100"
inkscape:export-ydpi="100">
<g
id="g1084"
clip-path="url(#clipPath1086)">
<g
id="g1090"
transform="translate(297.5875,384.2569)">
<path
d="m 0,0 7.18,8.558 c 4.365,-3.332 9.361,-4.71 14.071,-4.71 2.412,0 3.446,0.631 3.446,1.723 v 0.115 c 0,1.148 -1.263,1.78 -5.571,2.642 C 10.108,10.166 2.183,12.75 2.183,21.25 v 0.115 c 0,7.639 5.973,13.555 17.058,13.555 7.753,0 13.497,-1.838 18.149,-5.514 l -6.547,-9.074 c -3.791,2.756 -8.328,3.962 -12.062,3.962 -2.009,0 -2.928,-0.689 -2.928,-1.665 v -0.115 c 0,-1.091 1.09,-1.781 5.34,-2.585 10.282,-1.895 17.173,-4.882 17.173,-12.98 V 6.834 C 38.366,-1.608 31.417,-6.777 20.619,-6.777 12.464,-6.777 5.112,-4.48 0,0"
style="fill:#5f6062;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path1092"
inkscape:connector-curvature="0" />
</g>
<g
id="g1094"
transform="translate(340.0289,418.4302)">
<path
d="m 0,0 h 18.091 c 10.683,0 17.977,-4.767 17.977,-14.301 v -0.115 c 0,-9.707 -7.409,-14.876 -18.264,-14.876 H 13.439 V -40.204 H 0 Z m 17.058,-19.7 c 3.446,0 5.743,1.551 5.743,4.422 v 0.115 c 0,2.929 -2.125,4.423 -5.686,4.423 h -3.676 v -8.96 z"
style="fill:#5f6062;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path1096"
inkscape:connector-curvature="0" />
</g>
</g>
</g>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:3.38666677px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'Sans Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#5f6062;fill-opacity:1;stroke:none;stroke-width:0.28222224"
x="7.8113232"
y="172.66331"
id="text4094"
inkscape:export-filename="/home/adulau/misp.png"
inkscape:export-xdpi="100"
inkscape:export-ydpi="100"><tspan
sodipodi:role="line"
id="tspan4096"
x="7.8113232"
y="172.66331"
style="font-size:7.90222216px;line-height:1.25;font-family:sans-serif;stroke-width:0.28222224">Threat Sharing</tspan></text>
<g
id="g308"
transform="matrix(0.17650827,0,0,-0.17650827,-4.3435815,225.27546)">
<g
id="g310-5"
clip-path="url(#clipPath312-7)">
<g
id="g316"
transform="translate(385.579,529.5928)">
<path
d="m 0,0 h -5.184 v -56.985 c 0,-8.879 -5.16,-16.902 -15.523,-16.902 h -101.465 v -2.709 c 0,-7.851 8.922,-15.763 18.084,-15.763 h 77.581 l 29.678,-17.449 -4.31,17.449 H 0 c 9.156,0 13.287,7.906 13.287,15.763 v 63.068 C 13.287,-5.683 9.156,0 0,0"
style="fill:#2fa1db;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path318"
inkscape:connector-curvature="0" />
</g>
<g
id="g320-4"
transform="translate(349.7253,569.1839)">
<path
d="m 0,0 h -117.85 c -10.369,0 -22.301,-9.211 -22.301,-18.09 v -71.424 c 0,-8.177 10.11,-14.082 19.807,-14.987 l -6.311,-23.958 40.441,23.786 H 0 c 10.363,0 19.937,6.286 19.937,15.159 v 57.786 13.638 C 19.937,-9.211 10.363,0 0,0 m -99.871,-60.292 c -5.88,0 -10.645,4.766 -10.645,10.646 0,5.88 4.765,10.646 10.645,10.646 5.874,0 10.646,-4.766 10.646,-10.646 0,-5.88 -4.772,-10.646 -10.646,-10.646 m 39.764,0 c -5.88,0 -10.646,4.766 -10.646,10.646 0,5.88 4.766,10.646 10.646,10.646 5.88,0 10.646,-4.766 10.646,-10.646 0,-5.88 -4.766,-10.646 -10.646,-10.646 m 39.77,0 c -5.881,0 -10.652,4.766 -10.652,10.646 0,5.88 4.771,10.646 10.652,10.646 5.868,0 10.645,-4.766 10.645,-10.646 0,-5.88 -4.777,-10.646 -10.645,-10.646"
style="fill:#2fa1db;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path322-8"
inkscape:connector-curvature="0" />
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

@ -1,341 +0,0 @@
INSTALLATION INSTRUCTIONS
------------------------- for Ubuntu 16.04-server
1/ Minimal Ubuntu install
-------------------------
# Install a minimal Ubuntu 16.04-server system with the software:
- OpenSSH server
# Make sure your system is up2date:
sudo apt-get update
sudo apt-get upgrade
# install postfix, there will be some questions.
sudo apt-get install postfix
# Postfix Configuration: Satellite system
# change the relay server later with:
sudo postconf -e 'relayhost = example.com'
sudo postfix reload
2/ Install LAMP & dependencies
------------------------------
Once the system is installed you can perform the following steps:
# Install the dependencies: (some might already be installed)
sudo apt-get install curl gcc git gnupg-agent make python python3 openssl redis-server sudo vim zip
# Install MariaDB (a MySQL fork/alternative)
sudo apt-get install mariadb-client mariadb-server
# Secure the MariaDB installation (especially by setting a strong root password)
sudo mysql_secure_installation
# Install Apache2
sudo apt-get install apache2 apache2-doc apache2-utils
# 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
# Install PHP and dependencies
sudo apt-get install libapache2-mod-php php php-cli php-crypt-gpg php-dev php-json php-mysql php-opcache php-readline php-redis php-xml
# Apply all changes
sudo systemctl restart apache2
3/ MISP code
------------
# Download MISP using git in the /var/www/ directory.
sudo mkdir /var/www/MISP
sudo chown www-data:www-data /var/www/MISP
cd /var/www/MISP
sudo -u www-data git clone https://github.com/MISP/MISP.git /var/www/MISP
sudo -u www-data git checkout tags/$(git describe --tags `git rev-list --tags --max-count=1`)
# if the last shortcut doesn't work, specify the latest version manually
# example: git checkout tags/v2.4.XY
# the message regarding a "detached HEAD state" is expected behaviour
# (you only have to create a new branch, if you want to change stuff and do a pull request for example)
# Make git ignore filesystem permission differences
sudo -u www-data git config core.filemode false
# 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
cd /var/www/MISP/app/files/scripts
sudo -u www-data git clone https://github.com/CybOXProject/python-cybox.git
sudo -u www-data git clone https://github.com/STIXProject/python-stix.git
cd /var/www/MISP/app/files/scripts/python-cybox
sudo python3 setup.py install
cd /var/www/MISP/app/files/scripts/python-stix
sudo python3 setup.py install
# install mixbox to accommodate the new STIX dependencies:
cd /var/www/MISP/app/files/scripts/
sudo -u www-data git clone https://github.com/CybOXProject/mixbox.git
cd /var/www/MISP/app/files/scripts/mixbox
sudo python3 setup.py install
# install PyMISP
cd /var/www/MISP/PyMISP
sudo python3 setup.py install
# install support for STIX 2.0
sudo pip3 install stix2
4/ CakePHP
-----------
# CakePHP is included as a submodule of MISP, execute the following commands to let git fetch it:
cd /var/www/MISP
sudo -u www-data git submodule init
sudo -u www-data git submodule update
# Make git ignore filesystem permission differences for submodules
sudo -u www-data git submodule foreach git config core.filemode false
# Once done, install CakeResque along with its dependencies if you intend to use the built in background jobs:
cd /var/www/MISP/app
sudo -u www-data php composer.phar require kamisama/cake-resque:4.1.2
sudo -u www-data php composer.phar config vendor-dir Vendor
sudo -u www-data php composer.phar install
# Enable CakeResque with php-redis
sudo phpenmod redis
# To use the scheduler worker for scheduled tasks, do the following:
sudo -u www-data cp -fa /var/www/MISP/INSTALL/setup/config.php /var/www/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
5/ Set the permissions
----------------------
# Check if the permissions are set correctly using the following commands:
sudo chown -R www-data:www-data /var/www/MISP
sudo chmod -R 750 /var/www/MISP
sudo chmod -R g+ws /var/www/MISP/app/tmp
sudo chmod -R g+ws /var/www/MISP/app/files
sudo chmod -R g+ws /var/www/MISP/app/files/scripts/tmp
6/ Create a database and user
-----------------------------
# Enter the mysql shell
sudo mysql -u root -p
MariaDB [(none)]> create database misp;
MariaDB [(none)]> grant usage on *.* to misp@localhost identified by 'XXXXdbpasswordhereXXXXX';
MariaDB [(none)]> grant all privileges on misp.* to misp@localhost;
MariaDB [(none)]> flush privileges;
MariaDB [(none)]> exit
# Import the empty MISP database from MYSQL.sql
sudo -u www-data sh -c "mysql -u misp -p misp < /var/www/MISP/INSTALL/MYSQL.sql"
# enter the password you've set in line 129 when prompted
7/ Apache configuration
-----------------------
# Now configure your Apache webserver with the DocumentRoot /var/www/MISP/app/webroot/
# If the apache version is 2.2:
sudo cp /var/www/MISP/INSTALL/apache.22.misp.ssl /etc/apache2/sites-available/misp-ssl.conf
# If the apache version is 2.4:
sudo cp /var/www/MISP/INSTALL/apache.24.misp.ssl /etc/apache2/sites-available/misp-ssl.conf
# 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
# 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=<Country>/ST=<State>/L=<Locality>/O=<Organization>/OU=<Organizational Unit Name>/CN=<QDN.here>/emailAddress=admin@<your.FQDN.here>" \
-keyout /etc/ssl/private/misp.local.key -out /etc/ssl/private/misp.local.crt
# 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
# Also remember to verify the SSLCertificateChainFile property in your config file - this is usually commented out for the self-generated certificate in the sample configurations, such as the one pasted below.
# 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
# activate new vhost
sudo a2dissite default-ssl
sudo a2ensite misp-ssl
# Restart apache
sudo systemctl restart apache2
8/ Log rotation
---------------
# MISP saves the stdout and stderr of its workers in /var/www/MISP/app/tmp/logs
# To rotate these logs install the supplied logrotate script:
sudo cp /var/www/MISP/INSTALL/misp.logrotate /etc/logrotate.d/misp
9/ MISP configuration
---------------------
# There are 4 sample configuration files in /var/www/MISP/app/Config that need to be copied
sudo -u www-data cp -a /var/www/MISP/app/Config/bootstrap.default.php /var/www/MISP/app/Config/bootstrap.php
sudo -u www-data cp -a /var/www/MISP/app/Config/database.default.php /var/www/MISP/app/Config/database.php
sudo -u www-data cp -a /var/www/MISP/app/Config/core.default.php /var/www/MISP/app/Config/core.php
sudo -u www-data cp -a /var/www/MISP/app/Config/config.default.php /var/www/MISP/app/Config/config.php
# Configure the fields in the newly created files:
sudo -u www-data vim /var/www/MISP/app/Config/database.php
# DATABASE_CONFIG has to be filled
# With the default values provided in section 6, this would look like:
# class DATABASE_CONFIG {
# public $default = array(
# 'datasource' => 'Database/Mysql',
# 'persistent' => false,
# 'host' => 'localhost',
# 'login' => 'misp', // grant usage on *.* to misp@localhost
# 'port' => 3306,
# 'password' => 'XXXXdbpasswordhereXXXXX', // identified by 'XXXXdbpasswordhereXXXXX';
# 'database' => 'misp', // create database misp;
# 'prefix' => '',
# 'encoding' => 'utf8',
# );
#}
# Important! Change the salt key in /var/www/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,
# you can reset the admin password with the following command
/var/www/MISP/app/Console/cake Password admin@admin.test Password1234
# Change baseurl
/var/www/MISP/app/Console/cake Baseurl https://<your.FQDN.here>
# alternatively, you can leave this field empty if you would like to use relative pathing in MISP.
# This however is highly advised against.
# and make sure the file permissions are still OK
sudo chown -R www-data:www-data /var/www/MISP/app/Config
sudo chmod -R 750 /var/www/MISP/app/Config
# Generate a GPG encryption key.
sudo -u www-data mkdir /var/www/MISP/.gnupg
sudo chmod 700 /var/www/MISP/.gnupg
sudo -u www-data gpg --homedir /var/www/MISP/.gnupg --gen-key
# The email address should match the one set in the config.php / set in the configuration menu in the administration menu configuration file
# NOTE: if entropy is not high enough, you can install rng-tools and then run rngd -r /dev/urandom do fix it quickly
# And export the public key to the webroot
sudo -u www-data sh -c "gpg --homedir /var/www/MISP/.gnupg --export --armor YOUR-KEYS-EMAIL-HERE > /var/www/MISP/app/webroot/gpg.asc"
# To make the background workers start on boot
sudo chmod +x /var/www/MISP/app/Console/worker/start.sh
sudo vim /etc/rc.local
# Add the following line before the last line (exit 0). Make sure that you replace www-data with your apache user:
sudo -u www-data bash /var/www/MISP/app/Console/worker/start.sh
# Now log in using the webinterface:
# The default user/pass = admin@admin.test/admin
# Using the server settings tool in the admin interface (Administration -> Server Settings), set MISP up to your preference
# It is especially vital that no critical issues remain!
# start the workers by navigating to the workers tab and clicking restart all workers
# Don't forget to change the email, password and authentication key after installation.
# Once done, have a look at the diagnostics
# If any of the directories that MISP uses to store files is not writeable to the apache user, change the permissions
# you can do this by running the following commands:
sudo chmod -R 750 /var/www/MISP/<directory path with an indicated issue>
sudo chown -R www-data:www-data /var/www/MISP/<directory path with an indicated issue>
# Make sure that the STIX libraries and GnuPG work as intended, if not, refer to INSTALL.txt's paragraphs dealing with these two items
# If anything goes wrong, make sure that you check MISP's logs for errors:
# /var/www/MISP/app/tmp/logs/error.log
# /var/www/MISP/app/tmp/logs/resque-worker-error.log
# /var/www/MISP/app/tmp/logs/resque-scheduler-error.log
# /var/www/MISP/app/tmp/logs/resque-2015-01-01.log // where the actual date is the current date
Recommended actions
-------------------
- By default CakePHP exposes its name and version in email headers. Apply a patch to remove this behavior.
- You should really harden your OS
- You should really harden the configuration of Apache
- You should really harden the configuration of MySQL/MariaDB
- Keep your software up2date (OS, MISP, CakePHP and everything else)
- Log and audit
Optional features
-----------------
# MISP has a new pub/sub feature, using ZeroMQ. To enable it, simply run the following command
sudo pip install pyzmq
# ZeroMQ depends on the Python client for Redis
sudo pip install redis
# For the experimental ssdeep correlations, run the following installation:
# installing ssdeep
wget http://downloads.sourceforge.net/project/ssdeep/ssdeep-2.13/ssdeep-2.13.tar.gz
tar zxvf ssdeep-2.13.tar.gz
cd ssdeep-2.13
./configure
make
sudo make install
ssdeep -h # test
#installing ssdeep_php
sudo pecl install ssdeep
# You should add "extension=ssdeep.so" to mods-available - Check /etc/php for your current version
echo "extension=ssdeep.so" | sudo tee /etc/php/7.2/mods-available/ssdeep.ini
sudo phpenmod ssdeep
sudo service apache2 restart
Optional features: misp-modules
-------------------------------
# If you want to add the misp modules functionality, follow the setup procedure described in misp-modules:
# https://github.com/MISP/misp-modules#how-to-install-and-start-misp-modules
# Then the enrichment, export and import modules can be enabled in MISP via the settings.

View File

@ -0,0 +1 @@
../../docs/archive/INSTALL.ubuntu1604.md

View File

@ -1 +1 @@
../../docs/old-2_3to2_4-UPGRADE.md
../../docs/archive/old-2_3to2_4-UPGRADE.md

View File

@ -1,490 +0,0 @@
INSTALLATION INSTRUCTIONS
------------------------- for FreeBSD 11.2-amd64
0/ WIP /!\ You are warned, this does not work yet! /!\
NOT working: pydeep, lief, py-yara, MAEC
1/ Minimal FreeBSD install
--------------------------
# Install standard FreeBSD-amd64 with:
- sshd
- ntpd
- ports
# System Hardening
- Clean /tmp
- Disable Syslogd network socket
- Disable Sendmail service
# Install pkg and point to latest
Install pkg by typing:
```
$ su -
# pkg
```
# Install sudo
pkg install sudo
# Install bash
sudo pkg install bash
Make sure users in group wheel can sudo, uncomment in /usr/local/etc/sudoers :
```
%wheel ALL=(ALL) ALL
```
# Update system
```
sudo freebsd-update fetch install
```
# Make python3 default
echo "DEFAULT_VERSIONS= python=3.6 python2=2.7 python3=3.6" >> /etc/make.conf
sudo ln -s /usr/local/bin/python3 /usr/local/bin/python
# Install postfix
```
sudo pkg install postfix
# Optional but useful, add a local misp user
sudo pw user add misp -s /usr/local/bin/bash -G wheel,www
sudo mkdir /home/misp ; sudo chown misp:misp /home/misp
sudo passwd misp
```
# FAMP
## Install misc dependencies
```
sudo pkg install curl git python3 vim m4 help2man gmake automake libtool
```
/!\ N.B: MariaDB 10.3 currently segfaults on 11.2: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=229219
```
sudo pkg install apache24 \
logrotate \
gnupg \
mariadb102-server mariadb102-client \
php72 \
php72-mysqli \
php72-xml \
php72-openssl \
php72-pcntl \
php72-mbstring \
php72-pdo_mysql \
php72-phar \
php72-json \
php72-filter \
php72-dom \
php72-opcache \
php72-session \
mod_php72
sudo cp -p /usr/local/etc/php.ini-development /usr/local/etc/php.ini
sudo sysrc apache24_enable="yes"
sudo sysrc mysql_enable="yes"
sudo sysrc mysql_args="--bind-address=127.0.0.1"
sudo service apache24 start
sudo service mysql-server start
sudo /usr/local/bin/mysql_secure_installation
```
```
sudo vi /usr/local/etc/apache24/Includes/php.conf
```
Add:
```
<IfModule dir_module>
DirectoryIndex index.php index.html
<FilesMatch "\.php$">
SetHandler application/x-httpd-php
</FilesMatch>
<FilesMatch "\.phps$">
SetHandler application/x-httpd-php-source
</FilesMatch>
</IfModule>
```
## Redis need to be installed via ports
```
cd /usr/ports/databases/redis
sudo make install clean
sudo sysrc redis_enable="yes"
```
### php-redis
```
cd /use/ports/databases/pecl-redis
sudo make install clean
```
## Maybe needed, had to add the path for php CLI to work…
add this: PATH=$PATH:/usr/local/bin
to: /usr/local/etc/apache24/envvars.d/php.env
```
sudo service apache24 restart
```
3/ MISP code
------------
# Download MISP using git in the /usr/local/www/ directory.
sudo mkdir /usr/local/www/MISP
sudo chown www:www /usr/local/www/MISP
cd /usr/local/www/MISP
sudo -u www git clone https://github.com/MISP/MISP.git /usr/local/www/MISP
# Make git ignore filesystem permission differences
sudo -u www git config core.filemode false
# install Mitre's STIX and its dependencies by running the following commands:
##sudo apt-get install python-dev zlib1g-dev python-setuptools
sudo pkg install py27-pip py36-pip libxml2 libxslt
cd /usr/local/www/MISP/app/files/scripts
sudo -u www git clone https://github.com/CybOXProject/python-cybox.git
sudo -u www git clone https://github.com/STIXProject/python-stix.git
cd /usr/local/www/MISP/app/files/scripts/python-cybox
sudo python3 setup.py install
cd /usr/local/www/MISP/app/files/scripts/python-stix
sudo python3 setup.py install
# install mixbox to accommodate the new STIX dependencies:
cd /usr/local/www/MISP/app/files/scripts/
sudo -u www git clone https://github.com/CybOXProject/mixbox.git
cd /usr/local/www/MISP/app/files/scripts/mixbox
sudo python3 setup.py install
4/ CakePHP
-----------
# CakePHP is included as a submodule of MISP, execute the following commands to let git fetch it:
cd /usr/local/www/MISP
sudo -u www git submodule update --init --recursive
# Make git ignore filesystem permission differences for submodules
sudo -u www git submodule foreach --recursive git config core.filemode false
# Once done, install CakeResque along with its dependencies if you intend to use the built in background jobs:
cd /usr/local/www/MISP/app
sudo -u www php composer.phar require kamisama/cake-resque:4.1.2
sudo -u www php composer.phar config vendor-dir Vendor
sudo -u www php composer.phar install
# To use the scheduler worker for scheduled tasks, do the following:
sudo -u www cp -fa /usr/local/www/MISP/INSTALL/setup/config.php /usr/local/www/MISP/app/Plugin/CakeResque/Config/config.php
5/ Set the permissions
----------------------
# Check if the permissions are set correctly using the following commands:
sudo chown -R www:www /usr/local/www/MISP
sudo chmod -R 750 /usr/local/www/MISP
sudo chmod -R g+ws /usr/local/www/MISP/app/tmp
sudo chmod -R g+ws /usr/local/www/MISP/app/files
sudo chmod -R g+ws /usr/local/www/MISP/app/files/scripts/tmp
6/ Create a database and user
-----------------------------
# Enter the mysql shell
sudo mysql -u root -p
MariaDB [(none)]> create database misp;
MariaDB [(none)]> grant usage on *.* to misp@localhost identified by 'XXXXdbpasswordhereXXXXX';
MariaDB [(none)]> grant all privileges on misp.* to misp@localhost;
MariaDB [(none)]> flush privileges;
MariaDB [(none)]> exit
# Import the empty MISP database from MYSQL.sql
sudo -u www sh -c "mysql -u misp -p misp < /usr/local/www/MISP/INSTALL/MYSQL.sql"
# enter the password you set previously
7/ Apache configuration
-----------------------
```
# Now configure your Apache webserver with the DocumentRoot /usr/local/www/MISP/app/webroot/
#2.4
sudo mkdir /usr/local/etc/apache24/sites-available/ /usr/local/etc/apache24/sites-enabled/
# If the apache version is 2.4:
sudo cp /usr/local/www/MISP/INSTALL/apache.24.misp.ssl /usr/local/etc/apache24/sites-available/misp-ssl.conf
# 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
sudo mkdir /etc/ssl/private/
# If a valid SSL certificate is not already created for the server, create a self-signed certificate: (Make sure to fill the <…>)
sudo openssl req -newkey rsa:4096 -days 365 -nodes -x509 \
-subj "/C=<Country>/ST=<State>/L=<Locality>/O=<Organization>/OU=<Organizational Unit Name>/CN=<QDN.here>/emailAddress=admin@<your.FQDN.here>" \
-keyout /etc/ssl/private/misp.local.key -out /etc/ssl/private/misp.local.crt
sudo chmod 750 /etc/ssl/private/
sudo chmod 640 /etc/ssl/private/*
# Otherwise, copy the SSLCertificateFile, SSLCertificateKeyFile, and SSLCertificateChainFile to /etc/ssl/private/. (Modify path and config to fit your environment)
sudo mkdir /var/log/apache24/
```
Now edit: /usr/local/etc/apache24/sites-available/misp-ssl.conf to reflect the below.
Make sure the ssl fqdn will reflect what you entered as a CN in the SSL-Cert.
You might see this: "AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 127.0.0.1. Set the 'ServerName' directive globally to suppress this message"
Edit:
```
============================================= 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/apache24/misp.local_error.log
CustomLog /var/log/apache24/misp.local_access.log combined
ServerSignature Off
</VirtualHost>
<VirtualHost <IP, FQDN, or *>:443>
ServerAdmin admin@<your.FQDN.here>
ServerName <your.FQDN.here>
DocumentRoot /usr/local/www/MISP/app/webroot
<Directory /usr/local/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/apache24/misp.local_error.log
CustomLog /var/log/apache24/misp.local_access.log combined
ServerSignature Off
</VirtualHost>
============================================= End sample working SSL config for MISP
```
```
# activate new vhost
cd /usr/local/etc/apache24/sites-enabled/
sudo ln -s ../sites-available/misp-ssl.conf
echo "Include etc/apache24/sites-enabled/*.conf" >> /usr/local/etc/apache24/httpd.conf
echo "IncludeOptional etc/apache24/sites-enabled/*.conf" >> /usr/local/etc/apache24/httpd.conf
sudo vi /usr/local/etc/apache24/httpd.conf
/!\ Enable mod_rewrite in httpd.conf /!\
LoadModule rewrite_module libexec/apache24/mod_rewrite.so
LoadModule ssl_module libexec/apache24/mod_ssl.so
Listen 443
# Restart apache
sudo service apache24 restart
```
8/ Log rotation
---------------
# MISP saves the stdout and stderr of its workers in /usr/local/www/MISP/app/tmp/logs
# To rotate these logs install the supplied logrotate script:
sudo cp /usr/local/www/MISP/INSTALL/misp.logrotate /usr/local/etc/logrotate.d/misp
chmod 0640 /usr/local/etc/logrotate.d/misp
9/ MISP configuration
---------------------
# There are 4 sample configuration files in /usr/local/www/MISP/app/Config that need to be copied
sudo -u www cp -a /usr/local/www/MISP/app/Config/bootstrap.default.php /usr/local/www/MISP/app/Config/bootstrap.php
sudo -u www cp -a /usr/local/www/MISP/app/Config/database.default.php /usr/local/www/MISP/app/Config/database.php
sudo -u www cp -a /usr/local/www/MISP/app/Config/core.default.php /usr/local/www/MISP/app/Config/core.php
sudo -u www cp -a /usr/local/www/MISP/app/Config/config.default.php /usr/local/www/MISP/app/Config/config.php
# Configure the fields in the newly created files:
sudo -u www vim /usr/local/www/MISP/app/Config/database.php
# DATABASE_CONFIG has to be filled
# With the default values provided in section 6, this would look like:
# class DATABASE_CONFIG {
# public $default = array(
# 'datasource' => 'Database/Mysql',
# 'persistent' => false,
# 'host' => 'localhost',
# 'login' => 'misp', // grant usage on *.* to misp@localhost
# 'port' => 3306,
# 'password' => 'XXXXdbpasswordhereXXXXX', // identified by 'XXXXdbpasswordhereXXXXX';
# 'database' => 'misp', // create database misp;
# 'prefix' => '',
# 'encoding' => 'utf8',
# );
#}
# Important! Change the salt key in /usr/local/www/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)
# Change base url in config.php
sudo -u www vim /usr/local/www/MISP/app/Config/config.php
# example: 'baseurl' => 'https://<your.FQDN.here>',
# alternatively, you can leave this field empty if you would like to use relative pathing in MISP
# 'baseurl' => '',
# and make sure the file permissions are still OK
sudo chown -R www:www /usr/local/www/MISP/app/Config
sudo chmod -R 750 /usr/local/www/MISP/app/Config
# Generate a GPG encryption key.
sudo -u www mkdir /usr/local/www/MISP/.gnupg
sudo chmod 700 /usr/local/www/MISP/.gnupg
##### sudo -u www gpg --homedir /usr/local/www/MISP/.gnupg --gen-key <- Broken
# The email address should match the one set in the config.php / set in the configuration menu in the administration menu configuration file
# And export the public key to the webroot
sudo -u www sh -c "gpg --homedir /usr/local/www/MISP/.gnupg --export --armor YOUR-KEYS-EMAIL-HERE > /usr/local/www/MISP/app/webroot/gpg.asc"
# To make the background workers start on boot
sudo chmod +x /usr/local/www/MISP/app/Console/worker/start.sh
sudo vim /etc/rc.local
# Add the following line before the last line (exit 0). Make sure that you replace www with your apache user:
sudo -u www bash /usr/local/www/MISP/app/Console/worker/start.sh
# Now log in using the webinterface:
# The default user/pass = admin@admin.test/admin
# Using the server settings tool in the admin interface (Administration -> Server Settings), set MISP up to your preference
# It is especially vital that no critical issues remain!
# start the workers by navigating to the workers tab and clicking restart all workers
# Don't forget to change the email, password and authentication key after installation.
# Once done, have a look at the diagnostics
# If any of the directories that MISP uses to store files is not writeable to the apache user, change the permissions
# you can do this by running the following commands:
sudo chmod -R 750 /usr/local/www/MISP/<directory path with an indicated issue>
sudo chown -R www:www /usr/local/www/MISP/<directory path with an indicated issue>
# Make sure that the STIX libraries and GnuPG work as intended, if not, refer to INSTALL.txt's paragraphs dealing with these two items
# If anything goes wrong, make sure that you check MISP's logs for errors:
# /usr/local/www/MISP/app/tmp/logs/error.log
# /usr/local/www/MISP/app/tmp/logs/resque-worker-error.log
# /usr/local/www/MISP/app/tmp/logs/resque-scheduler-error.log
# /usr/local/www/MISP/app/tmp/logs/resque-2015-01-01.log // where the actual date is the current date
set PATH_TO_MISP='/usr/local/www/MISP'
set MISP_BASEURL=''
set MISP_LIVE='1'
set FQDN='localhost'
# Enable Enrichment set better timeouts
sudo $PATH_TO_MISP/app/Console/cake Admin setSetting "Plugin.Enrichment_services_enable" true
sudo $PATH_TO_MISP/app/Console/cake Admin setSetting "Plugin.Enrichment_hover_enable" true
sudo $PATH_TO_MISP/app/Console/cake Admin setSetting "Plugin.Enrichment_timeout" 300
sudo $PATH_TO_MISP/app/Console/cake Admin setSetting "Plugin.Enrichment_hover_timeout" 150
sudo $PATH_TO_MISP/app/Console/cake Admin setSetting "Plugin.Enrichment_cve_enabled" true
sudo $PATH_TO_MISP/app/Console/cake Admin setSetting "Plugin.Enrichment_dns_enabled" true
# Enable Import modules set better timout
sudo $PATH_TO_MISP/app/Console/cake Admin setSetting "Plugin.Import_services_enable" true
sudo $PATH_TO_MISP/app/Console/cake Admin setSetting "Plugin.Import_timeout" 300
sudo $PATH_TO_MISP/app/Console/cake Admin setSetting "Plugin.Import_ocr_enabled" true
sudo $PATH_TO_MISP/app/Console/cake Admin setSetting "Plugin.Import_csvimport_enabled" true
# Enable Export modules set better timout
sudo $PATH_TO_MISP/app/Console/cake Admin setSetting "Plugin.Export_services_enable" true
sudo $PATH_TO_MISP/app/Console/cake Admin setSetting "Plugin.Export_timeout" 300
sudo $PATH_TO_MISP/app/Console/cake Admin setSetting "Plugin.Export_pdfexport_enabled" true
sudo $PATH_TO_MISP/app/Console/cake Live $MISP_LIVE
# Enable installer org and tune some configurables
sudo $PATH_TO_MISP/app/Console/cake Admin setSetting "MISP.host_org_id" 1
sudo $PATH_TO_MISP/app/Console/cake Admin setSetting "MISP.email" "info@admin.test"
sudo $PATH_TO_MISP/app/Console/cake Admin setSetting "MISP.disable_emailing" true
sudo $PATH_TO_MISP/app/Console/cake Admin setSetting "MISP.contact" "info@admin.test"
sudo $PATH_TO_MISP/app/Console/cake Admin setSetting "MISP.disablerestalert" true
sudo $PATH_TO_MISP/app/Console/cake Admin setSetting "MISP.showCorrelationsOnIndex" true
# Force defaults to make MISP Server Settings less RED
sudo $PATH_TO_MISP/app/Console/cake Admin setSetting "MISP.language" "eng"
sudo $PATH_TO_MISP/app/Console/cake Admin setSetting "MISP.proposals_block_attributes" false
## Redis block
sudo $PATH_TO_MISP/app/Console/cake Admin setSetting "MISP.redis_host" "127.0.0.1"
sudo $PATH_TO_MISP/app/Console/cake Admin setSetting "MISP.redis_port" 6379
sudo $PATH_TO_MISP/app/Console/cake Admin setSetting "MISP.redis_database" 13
sudo $PATH_TO_MISP/app/Console/cake Admin setSetting "MISP.redis_password" ""
# Tune global time outs
sudo $PATH_TO_MISP/app/Console/cake Admin setSetting "Session.autoRegenerate" 0
sudo $PATH_TO_MISP/app/Console/cake Admin setSetting "Session.timeout" 600
sudo $PATH_TO_MISP/app/Console/cake Admin setSetting "Session.cookie_timeout" 3600
Recommended actions
-------------------
- By default CakePHP exposes its name and version in email headers. Apply a patch to remove this behavior.
- You should really harden your OS
- You should really harden the configuration of Apache
- You should really harden the configuration of MySQL/MariaDB
- Keep your software up2date (OS, MISP, CakePHP and everything else)
- Log and audit
10/ MISP modulesß
sudo pkg install yara
sudo mkdir /usr/local/src/
cd /usr/local/src/
sudo git clone https://github.com/MISP/misp-modules.git
cd misp-modules
# pip3 install
sudo pip-3.6 install -I -r REQUIREMENTS
sudo pip-3.6 install -I .
##sudo pip-3.6 install lief
sudo pip-3.6 install maec
sudo pip-3.6 install pymisp python-magic wand yara
##sudo pip-3.6 install git+https://github.com/kbandla/pydeep.git
# pip2 install
sudo pip-2.7 install pymisp python-magic wand yara
##sudo pip-2.7 install git+https://github.com/kbandla/pydeep.git
##sudo pip-2.7 install lief
# install STIX2.0 library to support STIX 2.0 export:
sudo pip-3.6 install stix2
Add this to rc.local:
```
sudo -u www misp-modules -l 0.0.0.0 -s &
```
Optional features
-------------------
# MISP has a new pub/sub feature, using ZeroMQ. To enable it, simply run the following command
sudo pkg install libzmq4
# ZeroMQ depends on the Python client for Redis

View File

@ -0,0 +1 @@
../../docs/archive/xINSTALL.FreeBSD.md

View File

@ -0,0 +1 @@
../docs/xINSTALL.debian9.md

View File

@ -0,0 +1,620 @@
#!/usr/bin/env bash
#INSTALLATION INSTRUCTIONS
#------------------------- for Tsurugi Linux
#
#0/ Quick MISP Instance on Tsurugi Linux - Status
#---------------------------------------------
#
#1/ Prepare Tsurugi with a MISP User
#--------------------------------
# You will need a working OpenSSH server, reconfigure as follows:
# sudo update-rc.d -f ssh remove
# sudo update-rc.d -f ssh defaults
# sudo dpkg-reconfigure openssh-server
# sudo systemctl restart ssh
# If you installed tsurugi the locale is a little all over the place. I assume en_US to be default unless you know what you're doing.
# sudo sed -i 's/ja_JP/en_US/g' /etc/default/locale
# sudo sed -i 's/ja_JP.UTF/# ja_JP.UTF/g' /etc/locale.gen
# sudo dpkg-reconfigure locales
# To install MISP on Tsurugi copy paste this in your r00t shell:
# wget -O /tmp/misp-tsurugi.sh https://raw.githubusercontent.com/MISP/MISP/2.4/INSTALL/INSTALL.tsurugi.txt && bash /tmp/misp-tsurugi.sh
# /!\ Please read the installer script before randomly doing the above.
# The script is tested on a plain vanilla Tsurugi Linux Boot CD and installs quite a few dependencies.
MISP_USER='misp'
MISP_PASSWORD='Password1234'
function tsurugiOnRootR0ckz() {
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root"
exit 1
elif [[ $(id $MISP_USER >/dev/null; echo $?) -ne 0 ]]; then
useradd -s /bin/bash -m -G adm,cdrom,sudo,dip,plugdev,www-data $MISP_USER
echo $MISP_USER:$MISP_PASSWORD | chpasswd
else
echo "User ${MISP_USER} exists, skipping creation"
adduser $MISP_USER www-data
fi
}
function installMISPonTsurugi() {
# MISP configuration variables
PATH_TO_MISP='/var/www/MISP'
MISP_BASEURL='https://misp.local'
MISP_LIVE='1'
CAKE="$PATH_TO_MISP/app/Console/cake"
# Database configuration
DBHOST='localhost'
DBNAME='misp'
DBUSER_ADMIN='root'
DBPASSWORD_ADMIN="$(openssl rand -hex 32)"
DBUSER_MISP='misp'
DBPASSWORD_MISP="$(openssl rand -hex 32)"
# Webserver configuration
FQDN='misp.local'
# OpenSSL configuration
OPENSSL_CN=$FQDN
OPENSSL_C='LU'
OPENSSL_ST='State'
OPENSSL_L='Location'
OPENSSL_O='Organization'
OPENSSL_OU='Organizational Unit'
OPENSSL_EMAILADDRESS='info@localhost'
# GPG configuration
GPG_REAL_NAME='Autogenerated Key'
GPG_COMMENT='WARNING: MISP AutoGenerated Key consider this Key VOID!'
GPG_EMAIL_ADDRESS='admin@admin.test'
GPG_KEY_LENGTH='2048'
GPG_PASSPHRASE='Password1234'
# php.ini configuration
upload_max_filesize=50M
post_max_size=50M
max_execution_time=300
memory_limit=512M
PHP_INI=/etc/php/7.0/apache2/php.ini
# apt config
export DEBIAN_FRONTEND=noninteractive
# sudo config to run $LUSER commands
SUDO="sudo -H -u ${MISP_USER}"
SUDO_WWW="sudo -H -u www-data"
echo "Admin (${DBUSER_ADMIN}) DB Password: ${DBPASSWORD_ADMIN}"
echo "User (${DBUSER_MISP}) DB Password: ${DBPASSWORD_MISP}"
echo "-----------------------------------------------------------------------"
echo "Disabling sleep etc…"
gsettings set org.gnome.settings-daemon.plugins.power sleep-inactive-ac-timeout 0
gsettings set org.gnome.settings-daemon.plugins.power sleep-inactive-battery-timeout 0
gsettings set org.gnome.settings-daemon.plugins.power sleep-inactive-battery-type 'nothing'
xset s 0 0
xset dpms 0 0
xset s off
apt update
apt install -qy etckeeper
# Skip dist-upgrade for now, pulls in 500+ updated packages
#sudo apt -y dist-upgrade
git config --global user.email "root@tsurugi.lan"
git config --global user.name "Root User"
apt install -qy postfix
apt install -qy \
curl gcc git gnupg-agent make openssl redis-server zip libyara-dev python3-yara python3-redis python3-zmq \
mariadb-client \
mariadb-server \
apache2 apache2-doc apache2-utils \
libapache2-mod-php7.0 php7.0 php7.0-cli php7.0-mbstring php-pear php7.0-dev php7.0-json php7.0-xml php7.0-mysql php7.0-opcache php7.0-readline \
python3-dev python3-pip libpq5 libjpeg-dev libfuzzy-dev ruby asciidoctor \
libxml2-dev libxslt1-dev zlib1g-dev python3-setuptools expect
apt install -qy haveged
systemctl restart haveged
systemctl restart mysql.service
a2dismod status
a2enmod ssl rewrite headers
a2dissite 000-default
a2ensite default-ssl
pear channel-update pear.php.net
pear install Crypt_GPG
pecl channel-update pecl.php.net
yes '' |pecl install redis
echo "extension=redis.so" | tee /etc/php/7.0/mods-available/redis.ini
phpenmod redis
# You can make Python 3 default, if you wish to.
#update-alternatives --install /usr/bin/python python /usr/bin/python2.7 1
#update-alternatives --install /usr/bin/python python /usr/bin/python3.5 2
mkdir $PATH_TO_MISP
chown www-data:www-data $PATH_TO_MISP
cd $PATH_TO_MISP
$SUDO_WWW git clone https://github.com/MISP/MISP.git $PATH_TO_MISP
$SUDO_WWW git config core.filemode false
cp -p /etc/lsb-release /etc/lsb-release.tmp
sudo sed -i 's/TSURUGI/Ubuntu/g' /etc/lsb-release
sudo sed -i 's/bamboo/xenial/g' /etc/lsb-release
sudo add-apt-repository ppa:jonathonf/python-3.6 -y
sudo apt-get update
sudo apt-get install python3.6 python3.6-dev -y
mv /etc/lsb-release.tmp /etc/lsb-release
$SUDO_WWW virtualenv -p python3.6 $PATH_TO_MISP/venv
cd $PATH_TO_MISP/app/files/scripts
$SUDO_WWW git clone https://github.com/CybOXProject/python-cybox.git
$SUDO_WWW git clone https://github.com/STIXProject/python-stix.git
$SUDO_WWW git clone https://github.com/CybOXProject/mixbox.git
mkdir /var/www/.cache
chown www-data:www-data /var/www/.cache
cd $PATH_TO_MISP/app/files/scripts/python-stix
$SUDO_WWW $PATH_TO_MISP/venv/bin/pip install .
cd $PATH_TO_MISP/app/files/scripts/python-cybox
$SUDO_WWW $PATH_TO_MISP/venv/bin/pip install .
cd $PATH_TO_MISP/app/files/scripts/mixbox
$SUDO_WWW $PATH_TO_MISP/venv/bin/pip install .
cd $PATH_TO_MISP
$SUDO_WWW git submodule update --init --recursive
# Make git ignore filesystem permission differences for submodules
$SUDO_WWW git submodule foreach --recursive git config core.filemode false
# install PyMISP
$SUDO_WWW $PATH_TO_MISP/venv/bin/pip install enum34
cd $PATH_TO_MISP/PyMISP
$SUDO_WWW $PATH_TO_MISP/venv/bin/pip install .
cd $PATH_TO_MISP/app
mkdir /var/www/.composer ; chown www-data:www-data /var/www/.composer
$SUDO_WWW php composer.phar require kamisama/cake-resque:4.1.2
$SUDO_WWW php composer.phar config vendor-dir Vendor
$SUDO_WWW php composer.phar install
$SUDO_WWW cp -fa $PATH_TO_MISP/INSTALL/setup/config.php $PATH_TO_MISP/app/Plugin/CakeResque/Config/config.php
chown -R www-data:www-data $PATH_TO_MISP
chmod -R 750 $PATH_TO_MISP
chmod -R g+ws $PATH_TO_MISP/app/tmp
chmod -R g+ws $PATH_TO_MISP/app/files
chmod -R g+ws $PATH_TO_MISP/app/files/scripts/tmp
if [ ! -e /var/lib/mysql/misp/users.ibd ]; then
echo "
set timeout 10
spawn mysql_secure_installation
expect \"Enter current password for root (enter for none):\"
send -- \"\r\"
expect \"Set root password?\"
send -- \"y\r\"
expect \"New password:\"
send -- \"${DBPASSWORD_ADMIN}\r\"
expect \"Re-enter new password:\"
send -- \"${DBPASSWORD_ADMIN}\r\"
expect \"Remove anonymous users?\"
send -- \"y\r\"
expect \"Disallow root login remotely?\"
send -- \"y\r\"
expect \"Remove test database and access to it?\"
send -- \"y\r\"
expect \"Reload privilege tables now?\"
send -- \"y\r\"
expect eof" | expect -f -
mysql -u $DBUSER_ADMIN -p$DBPASSWORD_ADMIN -e "create database $DBNAME;"
mysql -u $DBUSER_ADMIN -p$DBPASSWORD_ADMIN -e "grant usage on *.* to $DBNAME@localhost identified by '$DBPASSWORD_MISP';"
mysql -u $DBUSER_ADMIN -p$DBPASSWORD_ADMIN -e "grant all privileges on $DBNAME.* to '$DBUSER_MISP'@'localhost';"
mysql -u $DBUSER_ADMIN -p$DBPASSWORD_ADMIN -e "flush privileges;"
update-rc.d mysql enable
update-rc.d apache2 enable
update-rc.d redis-server enable
$SUDO_WWW cat $PATH_TO_MISP/INSTALL/MYSQL.sql | mysql -u $DBUSER_MISP -p$DBPASSWORD_MISP $DBNAME
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
else
echo "There might be a database already existing here: /var/lib/mysql/misp/users.ibd"
echo "Skipping any creations…"
sleep 3
fi
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
if [ ! -e /etc/rc.local ]
then
echo '#!/bin/sh -e' | tee -a /etc/rc.local
echo 'exit 0' | tee -a /etc/rc.local
chmod u+x /etc/rc.local
fi
cd /var/www
mkdir misp-dashboard
chown www-data:www-data misp-dashboard
$SUDO_WWW git clone https://github.com/MISP/misp-dashboard.git
cd misp-dashboard
$SUDO_WWW $PATH_TO_MISP/venv/bin/pip install zmq
/var/www/misp-dashboard/install_dependencies.sh
sed -i "s/^host\ =\ localhost/host\ =\ 0.0.0.0/g" /var/www/misp-dashboard/config/config.cfg
sed -i -e '$i \sudo -u www-data bash /var/www/misp-dashboard/start_all.sh\n' /etc/rc.local
sed -i -e '$i \sudo -u misp /usr/local/src/viper/viper-web -p 8888 -H 0.0.0.0 &\n' /etc/rc.local
sed -i -e '$i \git_dirs="/usr/local/src/misp-modules/ /var/www/misp-dashboard /usr/local/src/faup /usr/local/src/mail_to_misp /usr/local/src/misp-modules /usr/local/src/viper /var/www/misp-dashboard"\n' /etc/rc.local
sed -i -e '$i \for d in $git_dirs; do\n' /etc/rc.local
sed -i -e '$i \ echo "Updating ${d}"\n' /etc/rc.local
sed -i -e '$i \ cd $d && sudo git pull &\n' /etc/rc.local
sed -i -e '$i \done\n' /etc/rc.local
$SUDO_WWW bash /var/www/misp-dashboard/start_all.sh
apt install libapache2-mod-wsgi-py3 -y
echo "<VirtualHost _default_:80>
ServerAdmin admin@localhost.lu
ServerName misp.local
Redirect permanent / https://misp.local
LogLevel warn
ErrorLog /var/log/apache2/misp.local_error.log
CustomLog /var/log/apache2/misp.local_access.log combined
ServerSignature Off
</VirtualHost>
<VirtualHost _default_:443>
ServerAdmin admin@localhost.lu
ServerName misp.local
DocumentRoot $PATH_TO_MISP/app/webroot
<Directory $PATH_TO_MISP/app/webroot>
Options -Indexes
AllowOverride all
Require all granted
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
Header set X-Content-Type-Options nosniff
Header set X-Frame-Options DENY
</VirtualHost>" | tee /etc/apache2/sites-available/misp-ssl.conf
echo "127.0.0.1 misp.local" | tee -a /etc/hosts
echo "<VirtualHost *:8001>
ServerAdmin admin@misp.local
ServerName misp.local
DocumentRoot /var/www/misp-dashboard
WSGIDaemonProcess misp-dashboard \
user=misp group=misp \
python-home=/var/www/misp-dashboard/DASHENV \
processes=1 \
threads=15 \
maximum-requests=5000 \
listen-backlog=100 \
queue-timeout=45 \
socket-timeout=60 \
connect-timeout=15 \
request-timeout=60 \
inactivity-timeout=0 \
deadlock-timeout=60 \
graceful-timeout=15 \
shutdown-timeout=5 \
send-buffer-size=0 \
receive-buffer-size=0 \
header-buffer-size=0
WSGIScriptAlias / /var/www/misp-dashboard/misp-dashboard.wsgi
<Directory /var/www/misp-dashboard>
WSGIProcessGroup misp-dashboard
WSGIApplicationGroup %{GLOBAL}
Require all granted
</Directory>
LogLevel info
ErrorLog /var/log/apache2/misp-dashboard.local_error.log
CustomLog /var/log/apache2/misp-dashboard.local_access.log combined
ServerSignature Off
</VirtualHost>" | tee /etc/apache2/sites-available/misp-dashboard.conf
a2dissite default-ssl
a2ensite misp-ssl
a2ensite misp-dashboard
for key in upload_max_filesize post_max_size max_execution_time max_input_time memory_limit
do
sed -i "s/^\($key\).*/\1 = $(eval echo \${$key})/" $PHP_INI
done
systemctl restart apache2
cp $PATH_TO_MISP/INSTALL/misp.logrotate /etc/logrotate.d/misp
chmod 0640 /etc/logrotate.d/misp
$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/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
chown -R www-data:www-data $PATH_TO_MISP/app/Config
chmod -R 750 $PATH_TO_MISP/app/Config
$CAKE Live $MISP_LIVE
$CAKE Baseurl $MISP_BASEURL
echo "%echo Generating a default key
Key-Type: 1
Key-Length: $GPG_KEY_LENGTH
Subkey-Type: 1
Name-Real: $GPG_REAL_NAME
Name-Comment: $GPG_COMMENT
Name-Email: $GPG_EMAIL_ADDRESS
Expire-Date: 0
Passphrase: $GPG_PASSPHRASE
# Do a commit here, so that we can later print "done"
%commit
%echo done" > /tmp/gen-key-script
$SUDO_WWW gpg --homedir $PATH_TO_MISP/.gnupg --batch --gen-key /tmp/gen-key-script
$SUDO_WWW sh -c "gpg --homedir $PATH_TO_MISP/.gnupg --export --armor $GPG_EMAIL_ADDRESS" | $SUDO_WWW tee $PATH_TO_MISP/app/webroot/gpg.asc
chmod +x $PATH_TO_MISP/app/Console/worker/start.sh
$CAKE userInit -q
AUTH_KEY=$(mysql -u $DBUSER_MISP -p$DBPASSWORD_MISP misp -e "SELECT authkey FROM users;" | tail -1)
$CAKE Admin setSetting "MISP.python_bin" "${PATH_TO_MISP}/venv/bin/python"
$CAKE Admin setSetting "Plugin.ZeroMQ_enable" true
$CAKE Admin setSetting "Plugin.ZeroMQ_event_notifications_enable" true
$CAKE Admin setSetting "Plugin.ZeroMQ_object_notifications_enable" true
$CAKE Admin setSetting "Plugin.ZeroMQ_object_reference_notifications_enable" true
$CAKE Admin setSetting "Plugin.ZeroMQ_attribute_notifications_enable" true
$CAKE Admin setSetting "Plugin.ZeroMQ_sighting_notifications_enable" true
$CAKE Admin setSetting "Plugin.ZeroMQ_user_notifications_enable" true
$CAKE Admin setSetting "Plugin.ZeroMQ_organisation_notifications_enable" true
$CAKE Admin setSetting "Plugin.ZeroMQ_port" 50000
$CAKE Admin setSetting "Plugin.ZeroMQ_redis_host" "localhost"
$CAKE Admin setSetting "Plugin.ZeroMQ_redis_port" 6379
$CAKE Admin setSetting "Plugin.ZeroMQ_redis_database" 1
$CAKE Admin setSetting "Plugin.ZeroMQ_redis_namespace" "mispq"
$CAKE Admin setSetting "Plugin.ZeroMQ_include_attachments" false
$CAKE Admin setSetting "Plugin.ZeroMQ_tag_notifications_enable" false
$CAKE Admin setSetting "Plugin.ZeroMQ_audit_notifications_enable" false
$CAKE Admin setSetting "GnuPG.email" "admin@admin.test"
$CAKE Admin setSetting "GnuPG.homedir" "/var/www/MISP/.gnupg"
$CAKE Admin setSetting "GnuPG.password" "Password1234"
$CAKE Admin setSetting "Plugin.Enrichment_services_enable" true
$CAKE Admin setSetting "Plugin.Enrichment_hover_enable" true
$CAKE Admin setSetting "Plugin.Enrichment_timeout" 300
$CAKE Admin setSetting "Plugin.Enrichment_hover_timeout" 150
$CAKE Admin setSetting "Plugin.Enrichment_cve_enabled" true
$CAKE Admin setSetting "Plugin.Enrichment_dns_enabled" true
$CAKE Admin setSetting "Plugin.Enrichment_services_url" "http://127.0.0.1"
$CAKE Admin setSetting "Plugin.Enrichment_services_port" 6666
$CAKE Admin setSetting "Plugin.Import_services_enable" true
$CAKE Admin setSetting "Plugin.Import_services_url" "http://127.0.0.1"
$CAKE Admin setSetting "Plugin.Import_services_port" 6666
$CAKE Admin setSetting "Plugin.Import_timeout" 300
$CAKE Admin setSetting "Plugin.Import_ocr_enabled" true
$CAKE Admin setSetting "Plugin.Import_csvimport_enabled" true
$CAKE Admin setSetting "Plugin.Export_services_enable" true
$CAKE Admin setSetting "Plugin.Export_services_url" "http://127.0.0.1"
$CAKE Admin setSetting "Plugin.Export_services_port" 6666
$CAKE Admin setSetting "Plugin.Export_timeout" 300
$CAKE Admin setSetting "Plugin.Export_pdfexport_enabled" true
$CAKE Admin setSetting "MISP.host_org_id" 1
$CAKE Admin setSetting "MISP.email" "info@admin.test"
$CAKE Admin setSetting "MISP.disable_emailing" false
$CAKE Admin setSetting "MISP.contact" "info@admin.test"
$CAKE Admin setSetting "MISP.disablerestalert" true
$CAKE Admin setSetting "MISP.showCorrelationsOnIndex" true
$CAKE Admin setSetting "Plugin.Cortex_services_enable" false
$CAKE Admin setSetting "Plugin.Cortex_services_url" "http://127.0.0.1"
$CAKE Admin setSetting "Plugin.Cortex_services_port" 9000
$CAKE Admin setSetting "Plugin.Cortex_timeout" 120
$CAKE Admin setSetting "Plugin.Cortex_services_url" "http://127.0.0.1"
$CAKE Admin setSetting "Plugin.Cortex_services_port" 9000
$CAKE Admin setSetting "Plugin.Cortex_services_timeout" 120
$CAKE Admin setSetting "Plugin.Cortex_services_authkey" ""
$CAKE Admin setSetting "Plugin.Cortex_ssl_verify_peer" false
$CAKE Admin setSetting "Plugin.Cortex_ssl_verify_host" false
$CAKE Admin setSetting "Plugin.Cortex_ssl_allow_self_signed" true
$CAKE Admin setSetting "Plugin.Sightings_policy" 0
$CAKE Admin setSetting "Plugin.Sightings_anonymise" false
$CAKE Admin setSetting "Plugin.Sightings_range" 365
$CAKE Admin setSetting "Plugin.CustomAuth_disable_logout" false
$CAKE Admin setSetting "Plugin.RPZ_policy" "DROP"
$CAKE Admin setSetting "Plugin.RPZ_walled_garden" "127.0.0.1"
$CAKE Admin setSetting "Plugin.RPZ_serial" "\$date00"
$CAKE Admin setSetting "Plugin.RPZ_refresh" "2h"
$CAKE Admin setSetting "Plugin.RPZ_retry" "30m"
$CAKE Admin setSetting "Plugin.RPZ_expiry" "30d"
$CAKE Admin setSetting "Plugin.RPZ_minimum_ttl" "1h"
$CAKE Admin setSetting "Plugin.RPZ_ttl" "1w"
$CAKE Admin setSetting "Plugin.RPZ_ns" "localhost."
$CAKE Admin setSetting "Plugin.RPZ_ns_alt" ""
$CAKE Admin setSetting "Plugin.RPZ_email" "root.localhost"
$CAKE Admin setSetting "MISP.language" "eng"
$CAKE Admin setSetting "MISP.proposals_block_attributes" false
$CAKE Admin setSetting "MISP.redis_host" "127.0.0.1"
$CAKE Admin setSetting "MISP.redis_port" 6379
$CAKE Admin setSetting "MISP.redis_database" 13
$CAKE Admin setSetting "MISP.redis_password" ""
$CAKE Admin setSetting "MISP.ssdeep_correlation_threshold" 40
$CAKE Admin setSetting "MISP.extended_alert_subject" false
$CAKE Admin setSetting "MISP.default_event_threat_level" 4
$CAKE Admin setSetting "MISP.newUserText" "Dear new MISP user,\\n\\nWe would hereby like to welcome you to the \$org MISP community.\\n\\n Use the credentials below to log into MISP at \$misp, where you will be prompted to manually change your password to something of your own choice.\\n\\nUsername: \$username\\nPassword: \$password\\n\\nIf you have any questions, don't hesitate to contact us at: \$contact.\\n\\nBest regards,\\nYour \$org MISP support team"
$CAKE Admin setSetting "MISP.passwordResetText" "Dear MISP user,\\n\\nA password reset has been triggered for your account. Use the below provided temporary password to log into MISP at \$misp, where you will be prompted to manually change your password to something of your own choice.\\n\\nUsername: \$username\\nYour temporary password: \$password\\n\\nIf you have any questions, don't hesitate to contact us at: \$contact.\\n\\nBest regards,\\nYour \$org MISP support team"
$CAKE Admin setSetting "MISP.enableEventBlacklisting" true
$CAKE Admin setSetting "MISP.enableOrgBlacklisting" true
$CAKE Admin setSetting "MISP.log_client_ip" false
$CAKE Admin setSetting "MISP.log_auth" false
$CAKE Admin setSetting "MISP.disableUserSelfManagement" false
$CAKE Admin setSetting "MISP.block_event_alert" false
$CAKE Admin setSetting "MISP.block_event_alert_tag" "no-alerts=\"true\""
$CAKE Admin setSetting "MISP.block_old_event_alert" false
$CAKE Admin setSetting "MISP.block_old_event_alert_age" ""
$CAKE Admin setSetting "MISP.incoming_tags_disabled_by_default" false
$CAKE Admin setSetting "MISP.footermidleft" "This is an autogenerated install"
$CAKE Admin setSetting "MISP.footermidright" "Please configure accordingly and do not use in production"
$CAKE Admin setSetting "MISP.welcome_text_top" "Autogenerated install, please configure and harden accordingly"
$CAKE Admin setSetting "MISP.welcome_text_bottom" "Welcome to MISP on Tsurugi"
$CAKE Admin setSetting "Security.password_policy_length" 12
$CAKE Admin setSetting "Security.password_policy_complexity" '/^((?=.*\d)|(?=.*\W+))(?![\n])(?=.*[A-Z])(?=.*[a-z]).*$|.{16,}/'
$CAKE Admin setSetting "Session.autoRegenerate" 0
$CAKE Admin setSetting "Session.timeout" 600
$CAKE Admin setSetting "Session.cookie_timeout" 3600
$CAKE Live $MISP_LIVE
$CAKE Admin updateGalaxies
$CAKE Admin updateTaxonomies
#$CAKE Admin updateWarningLists
curl --header "Authorization: $AUTH_KEY" --header "Accept: application/json" --header "Content-Type: application/json" -k -X POST https://127.0.0.1/warninglists/update
curl --header "Authorization: $AUTH_KEY" --header "Accept: application/json" --header "Content-Type: application/json" -k -X POST https://127.0.0.1/noticelists/update
curl --header "Authorization: $AUTH_KEY" --header "Accept: application/json" --header "Content-Type: application/json" -k -X POST https://127.0.0.1/objectTemplates/update
sed -i -e '$i \echo never > /sys/kernel/mm/transparent_hugepage/enabled\n' /etc/rc.local
sed -i -e '$i \echo 1024 > /proc/sys/net/core/somaxconn\n' /etc/rc.local
sed -i -e '$i \sysctl vm.overcommit_memory=1\n' /etc/rc.local
sed -i -e '$i \sudo -u www-data bash /var/www/MISP/app/Console/worker/start.sh\n' /etc/rc.local
sed -i -e '$i \sudo -u www-data /var/www/MISP/venv/bin/misp-modules -l 127.0.0.1 -s > /tmp/misp-modules_rc.local.log 2> /dev/null &\n' /etc/rc.local
$SUDO_WWW bash $PATH_TO_MISP/app/Console/worker/start.sh
cd /usr/local/src/
git clone https://github.com/MISP/misp-modules.git
cd misp-modules
# pip3 install
$SUDO_WWW $PATH_TO_MISP/venv/bin/pip install -I -r REQUIREMENTS
$SUDO_WWW $PATH_TO_MISP/venv/bin/pip install -I .
$SUDO_WWW $PATH_TO_MISP/venv/bin/pip install maec python-magic wand lief yara-python
$SUDO_WWW $PATH_TO_MISP/venv/bin/pip install git+https://github.com/kbandla/pydeep.git
$SUDO_WWW $PATH_TO_MISP/venv/bin/pip install stix2
gem install pygments.rb
gem install asciidoctor-pdf --pre
$SUDO_WWW misp-modules -l 0.0.0.0 -s &
cd /usr/local/src/
apt-get install -y libssl-dev swig python3-ssdeep p7zip-full unrar-free sqlite python3-pyclamd exiftool radare2
pip3 install SQLAlchemy PrettyTable python-magic
git clone https://github.com/viper-framework/viper.git
chown -R $MISP_USER:$MISP_USER viper
cd viper
virtualenv -p python3.6 venv
$SUDO git submodule update --init --recursive
# There is a bug with yara-python, removing for the time being
sed -i 's/yara-python==3.7.0//g' requirements-modules.txt
./venv/bin/pip install scrapy
./venv/bin/pip install -r requirements.txt
./venv/bin/pip uninstall yara -y
sed -i '1 s/^.*$/\#!\/usr\/local\/src\/viper\/venv\/bin\/python/' viper-cli
sed -i '1 s/^.*$/\#!\/usr\/local\/src\/viper\/venv\/bin\/python/' viper-web
$SUDO /usr/local/src/viper/viper-cli -h > /dev/null
$SUDO /usr/local/src/viper/viper-web -p 8888 -H 0.0.0.0 &
echo 'PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/local/src/viper:/var/www/MISP/app/Console"' |tee /etc/environment
echo ". /etc/environment" >> /home/${MISP_USER}/.profile
$SUDO sed -i "s/^misp_url\ =/misp_url\ =\ http:\/\/localhost/g" /home/${MISP_USER}/.viper/viper.conf
$SUDO sed -i "s/^misp_key\ =/misp_key\ =\ $AUTH_KEY/g" /home/${MISP_USER}/.viper/viper.conf
while [ "$(sqlite3 /home/${MISP_USER}/.viper/admin.db 'UPDATE auth_user SET password="pbkdf2_sha256$100000$iXgEJh8hz7Cf$vfdDAwLX8tko1t0M1TLTtGlxERkNnltUnMhbv56wK/U="'; echo $?)" -ne "0" ]; do
# FIXME This might lead to a race condition, the while loop is sub-par
chown $MISP_USER:$MISP_USER /home/${MISP_USER}/.viper/admin.db
echo "Updating viper-web admin password, giving process time to start-up, sleeping 5, 4, 3,…"
sleep 6
done
chown -R www-data:www-data $PATH_TO_MISP
chmod -R 750 $PATH_TO_MISP
chmod -R g+ws $PATH_TO_MISP/app/tmp
chmod -R g+ws $PATH_TO_MISP/app/files
chmod -R g+ws $PATH_TO_MISP/app/files/scripts/tmp
# TODO: fix faup
cd /usr/local/src/
apt-get install -y cmake
git clone https://github.com/MISP/mail_to_misp.git
git clone git://github.com/stricaud/faup.git faup
chown -R ${MISP_USER}:${MISP_USER} faup mail_to_misp
cd faup
$SUDO mkdir -p build
cd build
$SUDO cmake .. && $SUDO make
make install
ldconfig
cd ../../
cd mail_to_misp
pip3 install -r requirements.txt
$SUDO cp mail_to_misp_config.py-example mail_to_misp_config.py
sed -i "s/^misp_url\ =\ 'YOUR_MISP_URL'/misp_url\ =\ 'http:\/\/localhost'/g" /usr/local/src/mail_to_misp/mail_to_misp_config.py
sed -i "s/^misp_key\ =\ 'YOUR_KEY_HERE'/misp_key\ =\ '$AUTH_KEY'/g" /usr/local/src/mail_to_misp/mail_to_misp_config.py
echo ""
echo "Admin (root) DB Password: $DBPASSWORD_ADMIN" > /home/${MISP_USER}/mysql.txt
echo "User (misp) DB Password: $DBPASSWORD_MISP" >> /home/${MISP_USER}/mysql.txt
echo "Authkey: $AUTH_KEY" > /home/${MISP_USER}/MISP-authkey.txt
clear
echo "-------------------------------------------------------------------------"
echo "MISP Installed, access here: https://misp.local"
echo "User: admin@admin.test"
echo "Password: admin"
echo "MISP Dashboard, access here: http://misp.local:8001"
echo "-------------------------------------------------------------------------"
cat /home/${MISP_USER}/mysql.txt
cat /home/${MISP_USER}/MISP-authkey.txt
echo "-------------------------------------------------------------------------"
echo "The LOCAL system credentials:"
echo "User: ${MISP_USER}"
echo "Password: ${MISP_PASSWORD}"
echo "-------------------------------------------------------------------------"
echo "viper-web installed, access here: http://misp.local:8888"
echo "viper-cli configured with your MISP Site Admin Auth Key"
echo "User: admin"
echo "Password: Password1234"
echo "-------------------------------------------------------------------------"
echo "To enable outgoing mails via postfix set a permissive SMTP server for the domains you want to contact:"
echo ""
echo "sudo postconf -e 'relayhost = example.com'"
echo "sudo postfix reload"
echo "-------------------------------------------------------------------------"
echo "Enjoy using MISP. For any issues see here: https://github.com/MISP/MISP/issues"
su - misp
}
tsurugiOnRootR0ckz
installMISPonTsurugi

View File

@ -0,0 +1 @@
../docs/xINSTALL.ubuntu1804.with.webmin.md

2
PyMISP

@ -1 +1 @@
Subproject commit cb2dbbd481f587e4a4c77f7f8bfa0a536fc9105c
Subproject commit 634ecc3ac308d01ebf5f5fbb9aace7746a2b8707

View File

@ -31,33 +31,34 @@ MISP - Malware Information Sharing Platform and Threat Sharing
</table>
MISP, is an open source software solution for collecting, storing, distributing and sharing cyber security indicators and threat about cyber security incidents analysis and malware analysis. MISP is designed by and for incident analysts, security and ICT professionals or malware reverser to support their day-to-day operations to share structured informations efficiently.
MISP is an open source software solution for collecting, storing, distributing and sharing cyber security indicators and threats about cyber security incidents analysis and malware analysis. MISP is designed by and for incident analysts, security and ICT professionals or malware reversers to support their day-to-day operations to share structured information efficiently.
The objective of MISP is to foster the sharing of structured information within the security community and abroad. MISP provides functionalities to support the exchange of information but also the consumption of the information by Network Intrusion Detection System (NIDS), LIDS but also log analysis tools, SIEMs.
The objective of MISP is to foster the sharing of structured information within the security community and abroad. MISP provides functionalities to support the exchange of information but also the consumption of said information by Network Intrusion Detection Systems (NIDS), LIDS but also log analysis tools, SIEMs.
MISP, Malware Information Sharing Platform and Threat Sharing, core functionalities are:
- An **efficient IOC and indicators** database allowing to store technical and non-technical information about malware samples, incidents, attackers and intelligence.
- Automatic **correlation** finding relationships between attributes and indicators from malware, attacks campaigns or analysis. attacks campaigns or analysis. Correlation engine includes correlation between attributes and more advanced correlations like Fuzzy hashing correlation (e.g. ssdeep) or CIDR block matching. Correlation can be also enabled or event disabled per attribute.
- Automatic **correlation** finding relationships between attributes and indicators from malware, attack campaigns or analysis. The correlation engine includes correlation between attributes and more advanced correlations like Fuzzy hashing correlation (e.g. ssdeep) or CIDR block matching. Correlation can also be enabled or event disabled per attribute.
- A **flexible data model** where complex [objects](https://www.misp-project.org/objects.html) can be expressed and **linked together to express threat intelligence, incidents or connected elements**.
- Built-in **sharing functionality** to ease data sharing using different model of distributions. MISP can synchronize automatically events and attributes among different MISP. Advanced filtering functionalities can be used to meet each organization sharing policy including a **flexible sharing group** capacity and an attribute level distribution mechanisms.
- An **intuitive user-interface** for end-users to create, update and collaborate on events and attributes/indicators. A **graphical interface** to navigate seamlessly between events and their correlations. Advanced filtering functionalities and [warning list](https://github.com/MISP/misp-warninglists) to help the analysts to contribute events and attributes.
- Built-in **sharing functionality** to ease data sharing using different model of distributions. MISP can automatically synchronize events and attributes among different MISP instances. Advanced filtering functionalities can be used to meet each organization's sharing policy including a **flexible sharing group** capacity and an attribute level distribution mechanisms.
- An **intuitive user-interface** for end-users to create, update and collaborate on events and attributes/indicators. A **graphical interface** to navigate seamlessly between events and their correlations. An **event graph** functionality to create and view relationships between objects and attributes. Advanced filtering functionalities and [warning lists](https://github.com/MISP/misp-warninglists) to help the analysts to contribute events and attributes and limit the risk of false-positives.
- **storing data** in a structured format (allowing automated use of the database for various purposes) with an extensive support of cyber security indicators along fraud indicators as in the financial sector.
- **export**: generating IDS, OpenIOC, plain text, CSV, MISP XML or JSON output to integrate with other systems (network IDS, host IDS, custom tools), STIX (XML and JSON), NIDS export (Suricata, Snort and Bro) or RPZ zone. Many other formats easily added via the [misp-modules](https://github.com/MISP/misp-modules).
- **import**: bulk-import, batch-import, import from OpenIOC, GFI sandbox, ThreatConnect CSV. Many other formats easily added via the [misp-modules](https://github.com/MISP/misp-modules).
- **export**: generating IDS, OpenIOC, plain text, CSV, MISP XML or JSON output to integrate with other systems (network IDS, host IDS, custom tools), Cache format (used for forensic tools), STIX (XML and JSON) 1 and 2, NIDS export (Suricata, Snort and Bro/Zeek) or RPZ zone. Many other formats can be easily added via the [misp-modules](https://github.com/MISP/misp-modules).
- **import**: bulk-import, batch-import, import from OpenIOC, GFI sandbox, ThreatConnect CSV, MISP standard format or STIX 1.1/2.0. Many other formats easily added via the [misp-modules](https://github.com/MISP/misp-modules).
- Flexible **free text import** tool to ease the integration of unstructured reports into MISP.
- A gentle system to **collaborate** on events and attributes allowing MISP users to propose changes or updates to attributes/indicators.
- **data-sharing**: automatically exchange and synchronization with other parties and trust-groups using MISP.
- **data-sharing**: automatically exchange and synchronize with other parties and trust-groups using MISP.
- **delegating of sharing**: allows a simple pseudo-anonymous mechanism to delegate publication of event/indicators to another organization.
- Flexible **API** to integrate MISP with your own solutions. MISP is bundled with [PyMISP](https://github.com/MISP/PyMISP) which is a flexible Python Library to fetch, add or update events attributes, handle malware samples or search for attributes.
- Flexible **API** to integrate MISP with your own solutions. MISP is bundled with [PyMISP](https://github.com/MISP/PyMISP) which is a flexible Python Library to fetch, add or update events attributes, handle malware samples or search for attributes. An exhaustive restSearch API to easily search for indicators in MISP and exports those in all the format supported by MISP.
- **Adjustable taxonomy** to classify and tag events following your own classification schemes or [existing classification](https://github.com/MISP/misp-taxonomies). The taxonomy can be local to your MISP but also shareable among MISP instances.
- **Intelligence vocabularies** called MISP galaxy and bundled with existing [threat actors, malware, RAT, ransomware or MITRE ATT&CK](https://www.misp-project.org/galaxy.html) which can be easily linked with events in MISP.
- **Intelligence vocabularies** called MISP galaxy and bundled with existing [threat actors, malware, RAT, ransomware or MITRE ATT&CK](https://www.misp-project.org/galaxy.html) which can be easily linked with events and attributes in MISP.
- **Expansion modules in Python** to expand MISP with your own services or activate already available [misp-modules](https://github.com/MISP/misp-modules).
- **Sighting support** to get observations from organizations concerning shared indicators and attributes. Sighting [can be contributed](https://www.circl.lu/doc/misp/automation/index.html#sightings-api) via MISP user-interface, API as MISP document or STIX sighting documents.
- **STIX support**: export data in the STIX format (XML and JSON). Additional STIX import and export is supported by [MISP-STIX-Converter](https://github.com/MISP/MISP-STIX-Converter) or [MISP-Taxii-Server](https://github.com/MISP/MISP-Taxii-Server).
- **Integrated encryption and signing of the notifications** via GnuPG and/or S/MIME depending of the user preferences.
- **STIX support**: import and export data in the STIX version 1 and version 2 format.
- **Integrated encryption and signing of the notifications** via GnuPG and/or S/MIME depending on the user's preferences.
- **Real-time** publish-subscribe channel within MISP to automatically get all changes (e.g. new events, indicators, sightings or tagging) in ZMQ (e.g. [misp-dashboard](https://github.com/MISP/misp-dashboard)) or ElasticSearch logging.
Exchanging info results in *faster detection* of targeted attacks and improves the detection ratio while reducing the false positives. We also avoid reversing similar malware as we know very fast that others team or organizations who already analyzed a specific malware.
Exchanging info results in *faster detection* of targeted attacks and improves the detection ratio while reducing the false positives. We also avoid reversing similar malware as we know very fast that other teams or organizations have already analyzed a specific malware.
![MISP 2.4 overview](https://raw.githubusercontent.com/MISP/MISP/2.4/INSTALL/screenshots/misp-panorama.png)
@ -77,7 +78,7 @@ Documentation
[MISP user-guide (MISP-book)](https://github.com/MISP/misp-book) is available [online](https://www.circl.lu/doc/misp/) or as [PDF](https://www.circl.lu/doc/misp/book.pdf) or as [EPUB](https://www.circl.lu/doc/misp/book.epub) or as [MOBI/Kindle](https://www.circl.lu/doc/misp/book.mobi).
For installation guide see [INSTALL](https://github.com/MISP/MISP/tree/2.4/INSTALL) or the [download section](https://www.misp-project.org/download/).
For the installation guide see the [INSTALL](https://github.com/MISP/MISP/tree/2.4/INSTALL) or [download section](https://www.misp-project.org/download/).
Contributing
------------
@ -106,8 +107,8 @@ This software is licensed under [GNU Affero General Public License version 3](ht
* Copyright (C) 2012 Christophe Vandeplas
* Copyright (C) 2012 Belgian Defence
* Copyright (C) 2012 NATO / NCIRC
* Copyright (C) 2013-2018 Andras Iklody
* Copyright (C) 2015-2018 CIRCL - Computer Incident Response Center Luxembourg
* Copyright (C) 2013-2019 Andras Iklody
* Copyright (C) 2015-2019 CIRCL - Computer Incident Response Center Luxembourg
* Copyright (C) 2016 Andreas Ziegler
For more information, [the list of authors and contributors](AUTHORS) is available.

View File

@ -1 +1 @@
{"major":2, "minor":4, "hotfix":96}
{"major":2, "minor":4, "hotfix":102}

View File

@ -134,6 +134,7 @@ $config = array(
'apacheEnv' => 'REMOTE_USER', // If proxy variable = HTTP_REMOTE_USER
'ldapServer' => 'ldap://example.com', // FQDN or IP
'ldapProtocol' => 3,
'ldapNetworkTimeout' => -1, // use -1 for unlimited network timeout
'ldapReaderUser' => 'cn=userWithReadAccess,ou=users,dc=example,dc=com', // DN ou RDN LDAP with reader user right
'ldapReaderPassword' => 'UserPassword', // the LDAP reader user password
'ldapDN' => 'dc=example,dc=com',

View File

@ -2,7 +2,7 @@
App::uses('AppShell', 'Console/Command');
class AdminShell extends AppShell
{
public $uses = array('Event', 'Post', 'Attribute', 'Job', 'User', 'Task', 'Whitelist', 'Server', 'Organisation', 'AdminSetting', 'Galaxy', 'Taxonomy', 'Warninglist', 'Noticelist', 'ObjectTemplate');
public $uses = array('Event', 'Post', 'Attribute', 'Job', 'User', 'Task', 'Whitelist', 'Server', 'Organisation', 'AdminSetting', 'Galaxy', 'Taxonomy', 'Warninglist', 'Noticelist', 'ObjectTemplate', 'Bruteforce');
public function jobGenerateCorrelation() {
$jobId = $this->args[0];
@ -146,15 +146,26 @@ class AdminShell extends AppShell
}
public function setSetting() {
$setting = !isset($this->args[0]) ? null : $this->args[0];
$setting_name = !isset($this->args[0]) ? null : $this->args[0];
$value = !isset($this->args[1]) ? null : $this->args[1];
if ($value === 'false') $value = 0;
if ($value === 'true') $value = 1;
if (empty($setting) || $value === null) {
$cli_user = array('id' => 0, 'email' => 'SYSTEM', 'Organisation' => array('name' => 'SYSTEM'));
if (empty($setting_name) || $value === null) {
echo 'Invalid parameters. Usage: ' . APP . 'Console/cake Admin setSetting [setting_name] [setting_value]';
} else {
$this->Server->serverSettingsSaveValue($setting, $value);
$setting = $this->Server->getSettingData($setting_name);
if (empty($setting)) {
echo 'Invalid setting. Please make sure that the setting that you are attempting to change exists.';
}
$result = $this->Server->serverSettingsEditValue($cli_user, $setting, $value);
if ($result === true) {
echo 'Setting changed.';
} else {
echo $result;
}
}
echo PHP_EOL;
}
public function setDatabaseVersion() {
@ -173,6 +184,12 @@ class AdminShell extends AppShell
}
}
public function updateDatabase() {
echo 'Executing all updates to bring the database up to date with the current version.' . PHP_EOL;
$this->Server->runUpdates(true);
echo 'All updates completed.' . PHP_EOL;
}
public function getAuthkey() {
if (empty($this->args[0])) {
echo 'Invalid parameters. Usage: ' . APP . 'Console/cake Admin getAuthkey [user_email]' . PHP_EOL;
@ -190,4 +207,18 @@ class AdminShell extends AppShell
}
}
public function clearBruteforce()
{
$conditions = array('Bruteforce.username !=' => '');
if (!empty($this->args[0])) {
$conditions = array('Bruteforce.username' => $this->args[0]);
}
$result = $this->Bruteforce->deleteAll($conditions, false, false);
$target = empty($this->args[0]) ? 'all users' : $this->args[0];
if ($result) {
echo 'Brutefoce entries for ' . $target . ' deleted.' . PHP_EOL;
} else {
echo 'Something went wrong, could not delete bruteforce entries for ' . $target . '.' . PHP_EOL;
}
}
}

View File

@ -558,12 +558,24 @@ class EventShell extends AppShell
$this->Job->save($data);
$jobId = $this->Job->id;
}
$job = $this->Job->read(null, $jobId);
$options = array(
'user' => $user,
'event_id' => $eventId,
'modules' => $modules
);
$result = $this->Event->enrichment($options);
$job['Job']['progress'] = 100;
$job['Job']['date_modified'] = date("y-m-d H:i:s");
if ($result) {
$job['Job']['message'] = 'Added ' . $result . ' attribute' . ($result > 1 ? 's.' : '.');
} else {
$job['Job']['message'] = 'Enrichment finished, but no attributes added.';
}
$this->Job->save($job);
$log = ClassRegistry::init('Log');
$log->create();
$log->createLogEntry($user, 'enrichment', 'Event', $eventId, 'Event (' . $eventId . '): enriched.', 'enriched () => (1)');
}
public function processfreetext() {

View File

@ -1,16 +0,0 @@
<?php
class Populate023Shell extends AppShell {
public $tasks = array('Roles', 'RoleToAroAco', 'RoleId', 'Users');
public function main() {
// perform tasks
sleep(30);
$this->Roles->execute();
$this->RoleId->execute('2');
$this->RoleToAroAco->execute();
// on user data
$this->Users->execute();
}
}

View File

@ -8,7 +8,7 @@ class ServerShell extends AppShell
public function pull() {
if (empty($this->args[0]) || empty($this->args[1])) {
die('Usage: ' . $this->Server->command_line_functions['pull'] . PHP_EOL);
die('Usage: ' . $this->Server->command_line_functions['console_automation_tasks']['data']['pull'] . PHP_EOL);
}
$userId = $this->args[0];
$user = $this->User->getAuthUser($userId);
@ -56,7 +56,7 @@ class ServerShell extends AppShell
public function push() {
if (empty($this->args[0]) || empty($this->args[1])) {
die('Usage: ' . $this->Server->command_line_functions['push'] . PHP_EOL);
die('Usage: ' . $this->Server->command_line_functions['console_automation_tasks']['data']['push'] . PHP_EOL);
}
$userId = $this->args[0];
$user = $this->User->getAuthUser($userId);
@ -103,7 +103,7 @@ class ServerShell extends AppShell
public function fetchFeed() {
if (empty($this->args[0]) || empty($this->args[1])) {
die('Usage: ' . $this->Server->command_line_functions['fetchFeed'] . PHP_EOL);
die('Usage: ' . $this->Server->command_line_functions['console_automation_tasks']['data']['fetchFeed'] . PHP_EOL);
}
$userId = $this->args[0];
$user = $this->User->getAuthUser($userId);
@ -129,31 +129,107 @@ class ServerShell extends AppShell
$jobId = $this->Job->id;
}
$this->Job->read(null, $jobId);
$result = $this->Feed->downloadFromFeedInitiator($feedId, $user, $jobId);
$this->Job->id = $jobId;
if (!$result) {
$message = 'Job Failed.';
$this->Job->save(array(
'id' => $jobId,
'message' => $message,
'progress' => 0,
'status' => 3
$outcome = array(
'id' => $jobId,
'message' => 'Job done.',
'progress' => 100,
'status' => 4
);
if ($feedId == 'all') {
$feedIds = $this->Feed->find('list', array(
'fields' => array('Feed.id', 'Feed.id'),
'conditions' => array('Feed.enabled' => 1)
));
$feedIds = array_values($feedIds);
$successes = 0;
$fails = 0;
foreach ($feedIds as $k => $feedId) {
$jobStatus = array(
'id' => $jobId,
'message' => 'Fetching feed: ' . $feedId,
'progress' => 100 * $k / count($feedIds),
'status' => 0
);
$this->Job->id = $jobId;
$this->Job->save($jobStatus);
$result = $this->Feed->downloadFromFeedInitiator($feedId, $user);
if ($result) {
$successes++;
} else {
$fails++;
}
}
$outcome['message'] = 'Job done. ' . $successes . ' feeds pulled successfuly, ' . $fails . ' feeds could not be pulled.';
} else {
$message = 'Job done.';
$this->Job->save(array(
'id' => $jobId,
'message' => $message,
'progress' => 100,
'status' => 4
$temp = $this->Feed->find('first', array(
'fields' => array('Feed.id', 'Feed.id'),
'conditions' => array('Feed.enabled' => 1, 'Feed.id' => $feedId)
));
if (!empty($temp)) {
$result = $this->Feed->downloadFromFeedInitiator($feedId, $user, $jobId);
if (!$result) {
$outcome['progress'] = 0;
$outcome['status'] = 3;
$outcome['message'] = 'Job failed.';
}
}
}
echo $message . PHP_EOL;
$this->Job->id = $jobId;
$this->Job->save($outcome);
echo $outcome['message'] . PHP_EOL;
}
public function cacheServer() {
if (empty($this->args[0]) || empty($this->args[1])) {
die('Usage: ' . $this->Server->command_line_functions['console_automation_tasks']['data']['cacheServer'] . PHP_EOL);
}
$userId = $this->args[0];
$user = $this->User->getAuthUser($userId);
if (empty($user)) die('Invalid user.' . PHP_EOL);
$scope = $this->args[1];
if (!empty($this->args[2])) {
$jobId = $this->args[2];
} else {
$this->Job->create();
$data = array(
'worker' => 'default',
'job_type' => 'cache_servers',
'job_input' => 'Server: ' . $id,
'status' => 0,
'retries' => 0,
'org' => $user['Organisation']['name'],
'message' => 'Starting server caching.',
);
$this->Job->save($data);
$jobId = $this->Job->id;
}
$this->Job->read(null, $jobId);
$result = $this->Server->cacheServerInitiator($user, $scope, $jobId);
$this->Job->id = $jobId;
if ($result !== true) {
$message = 'Job Failed. Reason: ';
$this->Job->save(array(
'id' => $jobId,
'message' => $message . $result,
'progress' => 0,
'status' => 3
));
} else {
$message = 'Job done.';
$this->Job->save(array(
'id' => $jobId,
'message' => $message,
'progress' => 100,
'status' => 4
));
}
echo $message . PHP_EOL;
}
public function cacheFeed() {
if (empty($this->args[0]) || empty($this->args[1])) {
die('Usage: ' . $this->Server->command_line_functions['cacheFeed'] . PHP_EOL);
die('Usage: ' . $this->Server->command_line_functions['console_automation_tasks']['data']['cacheFeed'] . PHP_EOL);
}
$userId = $this->args[0];
$user = $this->User->getAuthUser($userId);

View File

@ -1,16 +0,0 @@
<?php
App::uses('UsersController', 'Controller');
class RoleIdTask extends Shell {
public $uses = array('User');
public $Users;
public function execute($fk = '1') {
$this->Users = new UsersController();
$this->Users->constructClasses();
$this->Users->setRoleId($fk);
//$this->Users->generateAllForRoleId($fk); // TODO
}
}

View File

@ -1,19 +0,0 @@
<?php
App::uses('RolesController', 'Controller');
class RoleToAroAcoTask extends Shell {
public $uses = array('Role');
public $Roles;
public function execute() {
$this->Roles = new RolesController();
$this->Roles->constructClasses();
$roles = $this->Role->find('all');
foreach ($roles as $role) {
$this->Roles->saveAcl(array('model' => 'Role', 'foreign_key' => $role['Role']['id']), $role['Role']['perm_add'], $role['Role']['perm_modify'], $role['Role']['perm_publish'], $role['Role']['perm_admin'], $role['Role']['perm_sync'], $role['Role']['perm_auth'], $role['Role']['perm_audit']);
}
}
}

View File

@ -1,24 +0,0 @@
<?php
App::uses('RolesController', 'Controller');
class RolesTask extends Shell {
public $uses = array('Role');
public $Roles;
public function execute() {
$this->Roles = new RolesController();
$this->Roles->constructClasses();
$roles = ClassRegistry::init('Role');
$roles->create();
$roles->save(array('Role' => array('name' => 'admin', 'perm_add' => 1, 'perm_modify' => 1, 'perm_publish' => 1, 'perm_full' => 1, 'perm_sync' => 1, 'perm_audit' => 1, 'perm_auth' => 1)));
$roles->create();
$roles->save(array('Role' => array('name' => 'org_admin', 'perm_add' => 1, 'perm_modify' => 1, 'perm_publish' => 0, 'perm_full' => 0, 'perm_sync' => 1, 'perm_audit' => 1, 'perm_auth' => 1)));
$roles->create();
$roles->save(array('Role' => array('name' => 'User', 'perm_add' => 1, 'perm_modify' => 1, 'perm_publish' => 0, 'perm_full' => 0, 'perm_sync' => 1, 'perm_audit' => 1, 'perm_auth' => 0)));
$roles->create();
$roles->save(array('Role' => array('name' => 'Sync', 'perm_add' => 1, 'perm_modify' => 1, 'perm_publish' => 1, 'perm_full' => 0, 'perm_sync' => 1, 'perm_audit' => 1, 'perm_auth' => 1)));
}
}

View File

@ -1,18 +0,0 @@
<?php
App::uses('UsersController', 'Controller');
class UsersTask extends Shell {
public $uses = array('User');
public $Users;
public function execute() {
$this->Users = new UsersController();
$this->Users->constructClasses();
$users = ClassRegistry::init('User');
// perform clean
$users->checkAndCorrectPgps();
}
}

View File

@ -1,16 +0,0 @@
<?php
class Populate023Shell extends AppShell {
public $tasks = array('Roles', 'RoleToAroAco', 'RoleId', 'Users');
public function main() {
// perform tasks
sleep(30);
$this->Roles->execute();
$this->RoleId->execute('2');
$this->RoleToAroAco->execute();
// on user data
$this->Users->execute();
}
}

View File

@ -1,12 +0,0 @@
#!/bin/sh
# degrate 0.2.3 to 0.2.2
# step into project and ..
PRJCT=/var/www/MISP/app
cd ${PRJCT}
# update Schema, remove Users.role_id
./Console/cake schema update -s 0.2.2
exit 0;

View File

@ -1,38 +0,0 @@
#!/bin/sh
# migrate 0.2.2 to 0.2.3
# DataBase migrate, Audit and Access Control granulation
# step into project and ..
PRJCT=../../../app
cd ${PRJCT}
# create ACL tables
./Console/cake schema create DbAcl
# populate ACL acos
./Console/cake acl create aco root controllers
./Console/cake AclExtras.AclExtras aco_sync
# create Correlation table
./Console/cake schema create DbCorrelation
# create Regexp table
./Console/cake schema create DbRegexp
# create Whitelist table
./Console/cake schema create DbWhitelist
# update Schema, add Users.role_id
./Console/cake schema update -s 0.2.2.1
# create Log table
./Console/cake schema create DbLog
# create Roles, populate ACL aros and Users.role_id
./Console/cake schema create DbRole
# populate 0.2.3
./Console/cake populate0_2_3
exit 0;

View File

@ -1,14 +0,0 @@
#!/bin/sh
# migrate 0.2.1.1 to 0.2.2
# Servers.lastpushedid and Servers.lastpulledid
# step into project and ..
PRJCT=/var/www/MISP/app
cd ${PRJCT}
# update Schema, add Users.role_id
./Console/cake schema update -s 0.2.2
exit 0

View File

@ -1,16 +0,0 @@
#!/bin/sh
USER=noud
CY_HOME=../../../../MISP
chown -R ${USER}:www-data ${CY_HOME}
chmod -R 750 ${CY_HOME}
chmod -R g+s ${CY_HOME}
cd ${CY_HOME}/app/
chmod -R g+w tmp
chmod -R g+w files
# GnuPG
chmod -R ug+rwx ${CY_HOME}/.gnupg
exit 0

View File

@ -46,13 +46,13 @@ class AppController extends Controller
public $helpers = array('Utility', 'OrgImg');
private $__queryVersion = '46';
public $pyMispVersion = '2.4.96';
public $phpmin = '5.6.5';
private $__queryVersion = '60';
public $pyMispVersion = '2.4.102';
public $phpmin = '7.0.16';
public $phprec = '7.0.16';
public $baseurl = '';
public $sql_dump = false;
public $sql_dump = false;
// Used for _isAutomation(), a check that returns true if the controller & action combo matches an action that is a non-xml and non-json automation method
// This is used to allow authentication via headers for methods not covered by _isRest() - as that only checks for JSON and XML formats
@ -90,7 +90,7 @@ class AppController extends Controller
'ACL',
'RestResponse',
'Flash'
//,'DebugKit.Toolbar'
//,'DebugKit.Toolbar'
);
private function __isApiFunction($controller, $action)
@ -103,9 +103,24 @@ class AppController extends Controller
public function beforeFilter()
{
if (!empty($this->params['named']['sql'])) {
$this->sql_dump = 1;
}
if (Configure::read('Security.allow_cors')) {
// Add CORS headers
$this->response->cors($this->request,
explode(',', Configure::read('Security.cors_origins')),
['*'],
['Origin', 'Content-Type', 'Authorization', 'Accept']);
if ($this->request->is('options')) {
// Stop here!
// CORS only needs the headers
$this->response->send();
$this->_stop();
}
}
if (!empty($this->params['named']['sql'])) {
$this->sql_dump = 1;
}
// check for a supported datasource configuration
$dataSourceConfig = ConnectionManager::getDataSource('default')->config;
if (!isset($dataSourceConfig['encoding'])) {
@ -333,6 +348,9 @@ class AppController extends Controller
}
} else {
if (!($this->params['controller'] === 'users' && $this->params['action'] === 'login')) {
if (!$this->request->is('ajax')) {
$this->Session->write('pre_login_requested_url', $this->here);
}
$this->redirect(array('controller' => 'users', 'action' => 'login', 'admin' => false));
}
}
@ -360,20 +378,20 @@ class AppController extends Controller
if ($this->Session->check(AuthComponent::$sessionKey)) {
if ($this->action !== 'checkIfLoggedIn' || $this->request->params['controller'] !== 'users') {
$this->User->id = $this->Auth->user('id');
if (!$this->User->exists()) {
$message = __('Something went wrong. Your user account that you are authenticated with doesn\'t exist anymore.');
if ($this->_isRest) {
$this->RestResponse->throwException(
401,
$message
);
} else {
$this->Flash->info($message);
}
$this->Auth->logout();
$this->redirect(array('controller' => 'users', 'action' => 'login', 'admin' => false));
}
$this->User->id = $this->Auth->user('id');
if (!$this->User->exists()) {
$message = __('Something went wrong. Your user account that you are authenticated with doesn\'t exist anymore.');
if ($this->_isRest) {
$this->RestResponse->throwException(
401,
$message
);
} else {
$this->Flash->info($message);
}
$this->Auth->logout();
$this->redirect(array('controller' => 'users', 'action' => 'login', 'admin' => false));
}
if (!empty(Configure::read('MISP.terms_file')) && !$this->Auth->user('termsaccepted') && (!in_array($this->request->here, array($base_dir.'/users/terms', $base_dir.'/users/logout', $base_dir.'/users/login', $base_dir.'/users/downloadTerms')))) {
//if ($this->_isRest()) throw new MethodNotAllowedException('You have not accepted the terms of use yet, please log in via the web interface and accept them.');
if (!$this->_isRest()) {
@ -407,6 +425,7 @@ class AppController extends Controller
$this->set('me', $this->Auth->user());
$this->set('isAdmin', $role['perm_admin']);
$this->set('isSiteAdmin', $role['perm_site_admin']);
$this->set('hostOrgUser', $this->Auth->user('org_id') == Configure::read('MISP.host_org_id'));
$this->set('isAclAdd', $role['perm_add']);
$this->set('isAclModify', $role['perm_modify']);
$this->set('isAclModifyOrg', $role['perm_modify_org']);
@ -454,13 +473,13 @@ class AppController extends Controller
$this->ACL->checkAccess($this->Auth->user(), Inflector::variable($this->request->params['controller']), $this->action);
}
public function afterFilter()
{
if (Configure::read('debug') > 1 && !empty($this->sql_dump) && $this->_isRest()) {
$this->Log = ClassRegistry::init('Log');
echo json_encode($this->Log->getDataSource()->getLog(false, false), JSON_PRETTY_PRINT);
}
}
public function afterFilter()
{
if (Configure::read('debug') > 1 && !empty($this->sql_dump) && $this->_isRest()) {
$this->Log = ClassRegistry::init('Log');
echo json_encode($this->Log->getDataSource()->getLog(false, false), JSON_PRETTY_PRINT);
}
}
public function queryACL($debugType='findMissingFunctionNames', $content = false)
{
@ -505,14 +524,14 @@ class AppController extends Controller
return $this->request->header('Accept') === 'application/json' || $this->RequestHandler->prefers() === 'json';
}
protected function _isCsv($data=false)
{
if ($this->params['ext'] === 'csv' || $this->request->header('Accept') === 'application/csv' || $this->RequestHandler->prefers() === 'csv') {
return true;
} else {
return false;
}
}
protected function _isCsv($data=false)
{
if ($this->params['ext'] === 'csv' || $this->request->header('Accept') === 'application/csv' || $this->RequestHandler->prefers() === 'csv') {
return true;
} else {
return false;
}
}
protected function _isRest()
{
@ -583,7 +602,7 @@ class AppController extends Controller
);
return false;
}
$key = 'json';
$key = 'json';
} else {
if (!$this->Auth->user('id')) {
$exception = $this->RestResponse->throwException(
@ -627,21 +646,37 @@ class AppController extends Controller
$data[$p] = str_replace(';', ':', $data[$p]);
}
if (isset($options['named_params'][$p])) {
$data[$p] = $options['named_params'][$p];
$data[$p] = str_replace(';', ':', $options['named_params'][$p]);
}
}
}
foreach ($data as $k => $v) {
if (!is_array($data[$k])) {
$data[$k] = trim($data[$k]);
if (strpos($data[$k], '||')) {
$data[$k] = explode('||', $data[$k]);
}
}
}
if (!empty($options['additional_delimiters'])) {
if (!is_array($options['additional_delimiters'])) {
$options['additional_delimiters'] = array($options['additional_delimiters']);
}
foreach ($data as $k => $v) {
$found = false;
foreach ($options['additional_delimiters'] as $delim) {
if (strpos($v, $delim) !== false) {
$found = true;
}
}
if ($found) {
$data[$k] = explode($options['additional_delimiters'][0], str_replace($options['additional_delimiters'], $options['additional_delimiters'][0], $v));
foreach ($data[$k] as $k2 => $value) {
$data[$k][$k2] = trim($data[$k][$k2]);
}
}
}
}
if (!empty($options['additional_delimiters'])) {
if (!is_array($options['additional_delimiters'])) {
$options['additional_delimiters'] = array($options['additional_delimiters']);
}
foreach ($data as $k => $v) {
$data[$k] = explode($options['additional_delimiters'][0], str_replace($options['additional_delimiters'], $options['additional_delimiters'][0], $v));
foreach ($data[$k] as $k2 => $value) {
$data[$k][$k2] = trim($data[$k][$k2]);
}
}
}
return $data;
}

View File

@ -59,14 +59,17 @@ class AttributesController extends AppController
{
$this->Attribute->recursive = -1;
if (!$this->_isRest()) {
$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')
'fields' => array('Event.id', 'Event.orgc_id', 'Event.org_id', 'Event.info', 'Event.user_id', 'Event.date'),
'Orgc' => array('fields' => array('Orgc.id', 'Orgc.name')),
'Org' => array('fields' => array('Org.id', 'Org.name'))
),
'AttributeTag' => array('Tag'),
'Object' => array(
'fields' => array('Object.id', 'Object.distribution', 'Object.sharing_group_id')
),
'AttributeTag'
)
);
$this->Attribute->contain(array('AttributeTag' => array('Tag')));
}
@ -77,28 +80,6 @@ class AttributesController extends AppController
}
$org_ids = array();
$tag_ids = array();
foreach ($attributes as $k => $attribute) {
if (empty($attribute['Event']['id'])) {
unset($attribute[$k]);
continue;
}
if ($attribute['Attribute']['type'] == 'attachment' && preg_match('/.*\.(jpg|png|jpeg|gif)$/i', $attribute['Attribute']['value'])) {
$attributes[$k]['Attribute']['image'] = $this->Attribute->base64EncodeAttachment($attribute['Attribute']);
}
if (!in_array($attribute['Event']['orgc_id'], $org_ids)) {
$org_ids[] = $attribute['Event']['orgc_id'];
}
if (!in_array($attribute['Event']['org_id'], $org_ids)) {
$org_ids[] = $attribute['Event']['org_id'];
}
if (!empty($attribute['AttributeTag'])) {
foreach ($attribute['AttributeTag'] as $k => $v) {
if (!in_array($v['tag_id'], $tag_ids)) {
$tag_ids[] = $v['tag_id'];
}
}
}
}
$orgs = $this->Attribute->Event->Orgc->find('list', array(
'conditions' => array('Orgc.id' => $org_ids),
'fields' => array('Orgc.id', 'Orgc.name')
@ -110,21 +91,16 @@ class AttributesController extends AppController
'fields' => array('Tag.id', 'Tag.name', 'Tag.colour')
));
}
foreach ($attributes as $k => $attribute) {
$attributes[$k]['Event']['Orgc'] = array('id' => $attribute['Event']['orgc_id'], 'name' => $orgs[$attribute['Event']['orgc_id']]);
$attributes[$k]['Event']['Org'] = array('id' => $attribute['Event']['org_id'], 'name' => $orgs[$attribute['Event']['org_id']]);
if (!empty($attribute['AttributeTag'])) {
foreach ($attribute['AttributeTag'] as $kat => $at) {
foreach ($tags as $ktag => $tag) {
if ($tag['Tag']['id'] == $at['tag_id']) {
$attributes[$k]['AttributeTag'][$kat]['Tag'] = $tag['Tag'];
}
}
}
}
if (!$this->_isRest()) {
$temp = $this->__searchUI($attributes);
$this->loadModel('Galaxy');
$this->set('mitreAttackGalaxyId', $this->Galaxy->getMitreAttackGalaxyId());
$attributes = $temp[0];
$sightingsData = $temp[1];
$this->set('sightingsData', $sightingsData);
}
$this->set('orgs', $orgs);
$this->set('shortDist', $this->Attribute->shortDist);
$this->set('attributes', $attributes);
$this->set('attrDescriptions', $this->Attribute->fieldDescriptions);
$this->set('typeDefinitions', $this->Attribute->typeDefinitions);
@ -190,9 +166,10 @@ class AttributesController extends AppController
} else {
$values = explode("\n", $this->request->data['Attribute']['value']);
}
$temp = $this->request->data['Attribute'];
foreach ($values as $value) {
$this->request->data['Attribute']['value'] = $value;
$attributes[] = $this->request->data['Attribute'];
$temp['value'] = $value;
$attributes[] = $temp;
}
} else {
$attributes = $this->request->data['Attribute'];
@ -318,18 +295,19 @@ class AttributesController extends AppController
if (empty($fails)) {
$message = 'Attributes saved.';
} else {
if (count($attributes) > 1) {
if ($attributeCount > 1) {
$failKeys = array_keys($fails);
foreach ($failKeys as $k => $v) {
$v = explode('_', $v);
$failKeys[$k] = intval($v[1]) + 1;
$failKeys[$k] = intval($v[1]);
}
$message = 'Attributes saved, however, attributes ' . implode(', ', $failKeys) . ' could not be saved.';
$failed = 1;
$message = sprintf('Attributes saved, however, %s attributes could not be saved. Click %s for more info', count($fails), '$flashErrorMessage');
} else {
if (!empty($fails["attribute_0"])) {
foreach ($fails["attribute_0"] as $k => $v) {
$failed = 1;
$message = '$this->Flash->info [' . $k . ']: ' . $v[0];
$message = $k . ': ' . $v[0];
break;
}
} else {
@ -338,6 +316,25 @@ class AttributesController extends AppController
}
}
}
if (!empty($failKeys)) {
$flashErrorMessage = array();
$original_values = trim($this->request->data['Attribute']['value']);
$original_values = explode("\n", $original_values);
foreach ($original_values as $k => $original_value) {
$original_value = trim($original_value);
if (in_array($k, $failKeys)) {
$reason = '';
foreach ($fails["attribute_" . $k] as $failKey => $failData) {
$reason = $failKey . ': ' . $failData[0];
}
$flashErrorMessage[] = '<span class="red bold">' . h($original_value) . '</span> (' . h($reason) . ')';
} else {
$flashErrorMessage[] = '<span class="green bold">' . h($original_value) . '</span>';
}
}
$flashErrorMessage = implode('<br />', $flashErrorMessage);
$this->Session->write('flashErrorMessage', $flashErrorMessage);
}
if ($this->request->is('ajax')) {
$this->autoRender = false;
$errors = ($attributeCount > 1) ? $message : $this->Attribute->validationErrors;
@ -483,7 +480,10 @@ class AttributesController extends AppController
$this->loadModel('Event');
$this->Event->id = $this->request->data['Attribute']['event_id'];
$this->Event->recursive = -1;
$this->Event->read();
$event = $this->Event->read();
if (empty($event)) {
throw new NotFoundException(__('Invalid Event.'));
}
if (!$this->_isSiteAdmin() && ($this->Event->data['Event']['orgc_id'] != $this->_checkOrg() || !$this->userRole['perm_modify'])) {
throw new UnauthorizedException(__('You do not have permission to do that.'));
}
@ -648,6 +648,9 @@ class AttributesController extends AppController
$this->set('sharingGroups', $sgs);
$events = $this->Event->findById($eventId);
if (empty($events)) {
throw new NotFoundException(__('Invalid Event.'));
}
$this->set('currentDist', $events['Event']['distribution']);
$this->set('published', $events['Event']['published']);
}
@ -877,8 +880,13 @@ class AttributesController extends AppController
|| $this->userRole['perm_modify_org'])) {
// Allow the edit
} else {
$this->Flash->error(__('Invalid attribute.'));
$this->redirect(array('controller' => 'events', 'action' => 'index'));
$message = __('Invalid attribute.');
if ($this->_isRest()) {
throw new MethodNotAllowedException($message);
} else {
$this->Flash->error($message);
$this->redirect(array('controller' => 'events', 'action' => 'index'));
}
}
}
if (!$this->_isRest()) {
@ -980,10 +988,14 @@ class AttributesController extends AppController
$this->redirect(array('controller' => 'events', 'action' => 'view', $eventId));
}
} else {
if (!CakeSession::read('Message.flash')) {
$this->Flash->error(__('The attribute could not be saved. Please, try again.'));
if ($this->_isRest()) {
return $this->RestResponse->saveFailResponse('Attributes', 'edit', false, $this->Attribute->validationErrors);
} else {
$this->request->data = $this->Attribute->read(null, $id);
if (!CakeSession::read('Message.flash')) {
$this->Flash->error(__('The attribute could not be saved. Please, try again.'));
} else {
$this->request->data = $this->Attribute->read(null, $id);
}
}
}
} else {
@ -1454,12 +1466,11 @@ class AttributesController extends AppController
}
}
public function editSelected($id)
public function editSelected($id, $selectedAttributeIds = "[]")
{
if (!$this->request->is('ajax')) {
throw new MethodNotAllowedException(__('This method can only be accessed via AJAX.'));
}
if ($this->request->is('post')) {
$event = $this->Attribute->Event->find('first', array(
'conditions' => array('id' => $id),
@ -1480,7 +1491,18 @@ class AttributesController extends AppController
'recursive' => -1,
));
if ($this->request->data['Attribute']['to_ids'] == 2 && $this->request->data['Attribute']['distribution'] == 6 && $this->request->data['Attribute']['comment'] == null) {
$tags_ids_remove = json_decode($this->request->data['Attribute']['tags_ids_remove']);
$tags_ids_add = json_decode($this->request->data['Attribute']['tags_ids_add']);
$clusters_ids_remove = json_decode($this->request->data['Attribute']['clusters_ids_remove']);
$clusters_ids_add = json_decode($this->request->data['Attribute']['clusters_ids_add']);
$changeInTagOrCluster = ($tags_ids_remove !== null && count($tags_ids_remove) > 0)
|| ($tags_ids_add === null || count($tags_ids_add) > 0)
|| ($clusters_ids_remove === null || count($clusters_ids_remove) > 0)
|| ($clusters_ids_add === null || count($clusters_ids_add) > 0);
$changeInAttribute = ($this->request->data['Attribute']['to_ids'] != 2) || ($this->request->data['Attribute']['distribution'] != 6) || ($this->request->data['Attribute']['comment'] != null);
if (!$changeInAttribute && !$changeInTagOrCluster) {
$this->autoRender = false;
return new CakeResponse(array('body'=> json_encode(array('saved' => true)), 'status' => 200, 'type' => 'json'));
}
@ -1518,29 +1540,158 @@ class AttributesController extends AppController
$attributes[$key]['Attribute']['timestamp'] = $timestamp;
}
if ($this->Attribute->saveMany($attributes)) {
if (!$this->_isRest()) {
$this->Attribute->Event->insertLock($this->Auth->user(), $id);
if ($changeInAttribute) {
if ($this->Attribute->saveMany($attributes)) {
if (!$this->_isRest()) {
$this->Attribute->Event->insertLock($this->Auth->user(), $id);
}
$event['Event']['timestamp'] = $date->getTimestamp();
$event['Event']['published'] = 0;
$this->Attribute->Event->save($event, array('fieldList' => array('published', 'timestamp', 'info', 'id')));
$this->autoRender = false;
return new CakeResponse(array('body'=> json_encode(array('saved' => true)), 'status' => 200, 'type' => 'json'));
} else {
$this->autoRender = false;
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'validationErrors' => $this->Attribute->validationErrors)), 'status' => 200, 'type' => 'json'));
}
$event['Event']['timestamp'] = $date->getTimestamp();
$event['Event']['published'] = 0;
$this->Attribute->Event->save($event, array('fieldList' => array('published', 'timestamp', 'info', 'id')));
$this->autoRender = false;
return new CakeResponse(array('body'=> json_encode(array('saved' => true)), 'status' => 200, 'type' => 'json'));
} else {
$this->autoRender = false;
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'validationErrors' => $this->Attribute->validationErrors)), 'status' => 200, 'type' => 'json'));
}
// apply changes in tag/cluster
foreach ($attributes as $key => $attribute) {
foreach ($tags_ids_remove as $t => $tag_id) {
$this->removeTag($attributes[$key]['Attribute']['id'], $tag_id);
}
foreach ($tags_ids_add as $t => $tag_id) {
$this->addTag($attributes[$key]['Attribute']['id'], $tag_id);
}
$this->Galaxy = ClassRegistry::init('Galaxy');
foreach ($clusters_ids_remove as $c => $cluster_id) {
$this->Galaxy->detachCluster($this->Auth->user(), 'attribute', $attributes[$key]['Attribute']['id'], $cluster_id);
}
foreach ($clusters_ids_add as $c => $cluster_id) {
$this->Galaxy->attachCluster($this->Auth->user(), 'attribute', $attributes[$key]['Attribute']['id'], $cluster_id);
}
}
return new CakeResponse(array('body'=> json_encode(array('saved' => true)), 'status' => 200, 'type' => 'json'));
} else {
if (!isset($id)) {
throw new MethodNotAllowedException(__('No event ID provided.'));
}
$selectedAttributeIds = json_decode($selectedAttributeIds);
if ($selectedAttributeIds === null) {
$selectedAttributeIds = array();
}
// tags to remove
$tags = $this->Attribute->AttributeTag->getAttributesTags($this->Auth->user(), $id, $selectedAttributeIds);
$tagItemsRemove = array();
foreach ($tags as $k => $tag) {
$tagName = $tag['name'];
$tagItemsRemove[] = array(
'name' => $tagName,
'value' => $tag['id'],
'template' => array(
'name' => array(
'name' => $tagName,
'label' => array(
'background' => isset($tag['colour']) ? $tag['colour'] : '#ffffff'
)
),
)
);
}
unset($tags);
// clusters to remove
$clusters = $this->Attribute->AttributeTag->getAttributesClusters($this->Auth->user(), $id, $selectedAttributeIds);
$clusterItemsRemove = array();
foreach ($clusters as $k => $cluster) {
$name = $cluster['value'];
$optionName = $cluster['value'];
$synom = $cluster['synonyms_string'] !== '' ? ' (' . $cluster['synonyms_string'] . ')' : '';
$optionName .= $synom;
$temp = array(
'name' => $optionName,
'value' => $cluster['id'],
'template' => array(
'name' => $name,
'infoExtra' => $cluster['description']
)
);
if ($cluster['synonyms_string'] !== '') {
$temp['infoContextual'] = __('Synonyms: ') . $cluster['synonyms_string'];
}
$clusterItemsRemove[] = $temp;
}
unset($clusters);
$conditions = array();
if (!$this->_isSiteAdmin()) {
$conditions = array('Tag.org_id' => array(0, $this->Auth->user('org_id')));
$conditions = array('Tag.user_id' => array(0, $this->Auth->user('id')));
$conditions = array('Tag.hide_tag' => 0);
}
$allTags = $this->Attribute->AttributeTag->Tag->find('all', array('conditions' => $conditions, 'recursive' => -1));
$tags = array();
foreach ($allTags as $i => $tag) {
$tags[$tag['Tag']['id']] = $tag['Tag'];
}
unset($allTags);
$tagItemsAdd = array();
foreach ($tags as $k => $tag) {
$tagName = $tag['name'];
$tagItemsAdd[] = array(
'name' => $tagName,
'value' => $tag['id'],
'template' => array(
'name' => array(
'name' => $tagName,
'label' => array(
'background' => isset($tag['colour']) ? $tag['colour'] : '#ffffff'
)
),
)
);
}
// clusters to add
$this->GalaxyCluster = ClassRegistry::init('GalaxyCluster');
$clusters = $this->GalaxyCluster->find('all', array(
'fields' => array('value', 'id'),
'recursive' => -1
));
$clusterItemsAdd = array();
foreach ($clusters as $k => $cluster) {
$clusterItemsAdd[] = array(
'name' => $cluster['GalaxyCluster']['value'],
'value' => $cluster['GalaxyCluster']['id']
);
}
unset($clusters);
$this->layout = 'ajax';
$this->set('id', $id);
$this->set('sgs', $this->Attribute->SharingGroup->fetchAllAuthorised($this->Auth->user(), 'name', true));
$this->set('distributionLevels', $this->Attribute->distributionLevels);
$this->set('distributionDescriptions', $this->Attribute->distributionDescriptions);
$this->set('attrDescriptions', $this->Attribute->fieldDescriptions);
$this->set('tagItemsRemove', $tagItemsRemove);
$this->set('tagItemsAdd', $tagItemsAdd);
$this->set('clusterItemsAdd', $clusterItemsAdd);
$this->set('clusterItemsRemove', $clusterItemsRemove);
$this->set('options', array( // set chosen (select picker) options
'multiple' => -1,
'disabledSubmitButton' => true,
'flag_redraw_chosen' => true,
'select_options' => array(
'additionalData' => array(
'event_id' => $id,
),
),
));
$this->render('ajax/attributeEditMassForm');
}
}
@ -1566,87 +1717,159 @@ class AttributesController extends AppController
public function search($continue = false)
{
$this->set('attrDescriptions', $this->Attribute->fieldDescriptions);
$this->set('typeDefinitions', $this->Attribute->typeDefinitions);
$this->set('categoryDefinitions', $this->Attribute->categoryDefinitions);
if ($this->request->is('post')) {
if (isset($this->request->data['Attribute'])) {
$this->request->data = $this->request->data['Attribute'];
}
$checkForEmpty = array('value', 'tags', 'uuid', 'org', 'type', 'category');
foreach ($checkForEmpty as $field) {
if (empty($this->request->data[$field]) || $this->request->data[$field] === 'ALL') {
unset($this->request->data[$field]);
}
}
if (empty($this->request->data['to_ids'])) {
unset($this->request->data['to_ids']);
$this->request->data['ignore'] = 1;
}
$paramArray = array('value' , 'type', 'category', 'org', 'tags', 'from', 'to', 'last', 'eventid', 'withAttachments', 'uuid', 'publish_timestamp', 'timestamp', 'enforceWarninglist', 'to_ids', 'deleted', 'includeEventUuid', 'event_timestamp', 'threat_level_id', 'includeEventTags');
$filterData = array(
'request' => $this->request,
'named_params' => $this->params['named'],
'paramArray' => $paramArray,
'ordered_url_params' => compact($paramArray),
'additional_delimiters' => PHP_EOL
);
$exception = false;
$filters = $this->_harvestParameters($filterData, $exception);
unset($filterData);
if ($filters === false) {
return $exception;
}
$this->Session->write('search_attributes_filters', json_encode($filters));
} else if ($continue === 'results') {
$filters = $this->Session->read('search_attributes_filters');
if (empty($filters)) {
$filters = array();
} else {
$filters = json_decode($filters, true);
}
} else {
$types = array('' => array('ALL' => 'ALL'), 'types' => array());
$types['types'] = array_merge($types['types'], $this->_arrayToValuesIndexArray(array_keys($this->Attribute->typeDefinitions)));
ksort($types['types']);
$this->set('types', $types);
// combobox for categories
$categories['categories'] = array_merge(array('ALL' => 'ALL'), $this->_arrayToValuesIndexArray(array_keys($this->Attribute->categoryDefinitions)));
$this->set('categories', $categories);
$this->Session->write('search_attributes_filters', null);
}
if (isset($filters)) {
$params = $this->Attribute->restSearch($this->Auth->user(), 'json', $filters, true);
$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'),
'Orgc' => array('fields' => array('Orgc.id', 'Orgc.name')),
'Org' => array('fields' => array('Org.id', 'Org.name'))
$this->set('attrDescriptions', $this->Attribute->fieldDescriptions);
$this->set('typeDefinitions', $this->Attribute->typeDefinitions);
$this->set('categoryDefinitions', $this->Attribute->categoryDefinitions);
$this->set('shortDist', $this->Attribute->shortDist);
if ($this->request->is('post') || !empty($this->request->params['named']['tags'])) {
if (isset($this->request->data['Attribute'])) {
$this->request->data = $this->request->data['Attribute'];
}
$checkForEmpty = array('value', 'tags', 'uuid', 'org', 'type', 'category');
foreach ($checkForEmpty as $field) {
if (empty($this->request->data[$field]) || $this->request->data[$field] === 'ALL') {
unset($this->request->data[$field]);
}
}
if (empty($this->request->data['to_ids'])) {
unset($this->request->data['to_ids']);
$this->request->data['ignore'] = 1;
}
$paramArray = array('value' , 'type', 'category', 'org', 'tags', 'from', 'to', 'last', 'eventid', 'withAttachments', 'uuid', 'publish_timestamp', 'timestamp', 'enforceWarninglist', 'to_ids', 'deleted', 'includeEventUuid', 'event_timestamp', 'threat_level_id', 'includeEventTags');
$filterData = array(
'request' => $this->request,
'named_params' => $this->params['named'],
'paramArray' => $paramArray,
'ordered_url_params' => compact($paramArray),
'additional_delimiters' => PHP_EOL
);
$exception = false;
$filters = $this->_harvestParameters($filterData, $exception);
unset($filterData);
if ($filters === false) {
return $exception;
}
$this->Session->write('search_attributes_filters', json_encode($filters));
} elseif ($continue === 'results') {
$filters = $this->Session->read('search_attributes_filters');
if (empty($filters)) {
$filters = array();
} else {
$filters = json_decode($filters, true);
}
} else {
$types = array('' => array('ALL' => 'ALL'), 'types' => array());
$types['types'] = array_merge($types['types'], $this->_arrayToValuesIndexArray(array_keys($this->Attribute->typeDefinitions)));
ksort($types['types']);
$this->set('types', $types);
// combobox for categories
$categories['categories'] = array_merge(array('ALL' => 'ALL'), $this->_arrayToValuesIndexArray(array_keys($this->Attribute->categoryDefinitions)));
$this->set('categories', $categories);
$this->Session->write('search_attributes_filters', null);
}
if (isset($filters)) {
$params = $this->Attribute->restSearch($this->Auth->user(), 'json', $filters, true);
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'),
'Orgc' => array('fields' => array('Orgc.id', 'Orgc.name')),
'Org' => array('fields' => array('Org.id', 'Org.name'))
),
'AttributeTag' => array('Tag'),
'Object' => array(
'AttributeTag' => array('Tag'),
'Object' => array(
'fields' => array('Object.id', 'Object.distribution', 'Object.sharing_group_id')
)
);
$attributes = $this->paginate();
$this->set('filters', $filters);
$this->set('attributes', $attributes);
$this->set('isSearch', 1);
$this->render('index');
}
);
$attributes = $this->paginate();
if (!$this->_isRest()) {
$temp = $this->__searchUI($attributes);
$this->loadModel('Galaxy');
$this->set('mitreAttackGalaxyId', $this->Galaxy->getMitreAttackGalaxyId());
$attributes = $temp[0];
$sightingsData = $temp[1];
$this->set('sightingsData', $sightingsData);
} else {
return $this->RestResponse->viewData($attributes, $this->response->type());
}
if (isset($filters['tags']) && !empty($filters['tags'])) {
// if the tag is passed by ID - show its name in the view
$this->loadModel('Tag');
if (!is_array($filters['tags'])) {
$filters['tags'] = array($filters['tags']);
}
foreach ($filters['tags'] as $k => &$v) {
if (!is_numeric($v))
continue;
$tag = $this->Tag->find('first', [
'conditions' => ['Tag.id' => $v],
'fields' => ['name'],
'recursive' => -1
]);
if (!empty($tag)) {
$v = $tag['Tag']['name'];
}
}
}
$this->set('filters', $filters);
$this->set('attributes', $attributes);
$this->set('isSearch', 1);
$this->render('index');
}
if (isset($attributeTags)) {
$this->set('attributeTags', $attributeTags);
}
}
private function __searchUI($attributes)
{
$sightingsData = array();
$sgids = $this->Attribute->Event->cacheSgids($this->Auth->user(), true);
$this->Feed = ClassRegistry::init('Feed');
if (!empty($options['overrideLimit'])) {
$overrideLimit = true;
} else {
$overrideLimit = false;
}
$this->loadModel('GalaxyCluster');
$cluster_names = $this->GalaxyCluster->find('list', array('fields' => array('GalaxyCluster.tag_name'), 'group' => array('GalaxyCluster.tag_name', 'GalaxyCluster.id')));
$this->loadModel('Sighting');
foreach ($attributes as $k => $attribute) {
$attributes[$k]['Attribute']['AttributeTag'] = $attributes[$k]['AttributeTag'];
$attributes[$k]['Attribute'] = $this->Attribute->Event->massageTags($attributes[$k]['Attribute'], 'Attribute');
unset($attributes[$k]['AttributeTag']);
foreach ($attributes[$k]['Attribute']['AttributeTag'] as $k2 => $attributeTag) {
if (in_array($attributeTag['Tag']['name'], $cluster_names)) {
unset($attributes[$k]['Attribute']['AttributeTag'][$k2]);
}
}
$sightingsData = array_merge(
$sightingsData,
$this->Sighting->attachToEvent($attribute, $this->Auth->user(), $attributes[$k]['Attribute']['id'], $extraConditions = false)
);
$correlations = $this->Attribute->Event->getRelatedAttributes($this->Auth->user(), $attributes[$k]['Attribute']['id'], false, false, 'attribute');
if (!empty($correlations)) {
$attributes[$k]['Attribute']['RelatedAttribute'] = $correlations[$attributes[$k]['Attribute']['id']];
}
$temp = $this->Feed->attachFeedCorrelations(array($attributes[$k]['Attribute']), $this->Auth->user, $attributes[$k]['Event'], $overrideLimit);
if (!empty($temp)) {
$attributes[$k]['Attribute'] = $temp[0];
}
}
$sightingsData = $this->Attribute->Event->getSightingData(array('Sighting' => $sightingsData));
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)
@ -1714,35 +1937,48 @@ class AttributesController extends AppController
$this->set('fails', $this->Attribute->checkComposites());
}
public function restSearch($returnFormat = 'json', $value = false, $type = false, $category = false, $org = false, $tags = false, $from = false, $to = false, $last = false, $eventid = false, $withAttachments = false, $uuid = false, $publish_timestamp = false, $published = false, $timestamp = false, $enforceWarninglist = false, $to_ids = false, $deleted = false, $includeEventUuid = false, $event_timestamp = false, $threat_level_id = false) {
$paramArray = array('value' , 'type', 'category', 'org', 'tags', 'from', 'to', 'last', 'eventid', 'withAttachments', 'uuid', 'publish_timestamp', 'timestamp', 'enforceWarninglist', 'to_ids', 'deleted', 'includeEventUuid', 'event_timestamp', 'threat_level_id', 'includeEventTags');
public function restSearch(
$returnFormat = false, $value = false, $type = false, $category = false, $org = false, $tags = false, $from = false,
$to = false, $last = false, $eventid = false, $withAttachments = false, $uuid = false, $publish_timestamp = false, $published = false,
$timestamp = false, $enforceWarninglist = false, $to_ids = false, $deleted = false, $includeEventUuid = false, $event_timestamp = false,
$threat_level_id = false
)
{
$paramArray = array(
'value' , 'type', 'category', 'org', 'tags', 'from', 'to', 'last', 'eventid', 'withAttachments', 'uuid', 'publish_timestamp',
'timestamp', 'enforceWarninglist', 'to_ids', 'deleted', 'includeEventUuid', 'event_timestamp', 'threat_level_id', 'includeEventTags',
'includeProposals', 'returnFormat', 'published', 'limit', 'page', 'requested_attributes', 'includeContext', 'headerless'
);
$filterData = array(
'request' => $this->request,
'named_params' => $this->params['named'],
'paramArray' => $paramArray,
'ordered_url_params' => compact($paramArray)
);
$validFormats = $this->Attribute->validFormats;
$validFormats = $this->Attribute->validFormats;
$exception = false;
$filters = $this->_harvestParameters($filterData, $exception);
unset($filterData);
if ($filters === false) {
return $exception;
return $exception;
}
$list = array();
$user = $this->_getApiAuthUser($returnFormat, $exception);
if ($user === false) {
return $exception;
return $exception;
}
if (isset($filters['returnFormat'])) {
$returnFormat = $filters['returnFormat'];
$returnFormat = $filters['returnFormat'];
} else {
$returnFormat = 'json';
}
if ($returnFormat === 'download') {
$returnFormat = 'json';
}
$final = $this->Attribute->restSearch($user, $returnFormat, $filters);
if ($returnFormat === 'download') {
$returnFormat = 'json';
}
$elementCounter = 0;
$final = $this->Attribute->restSearch($user, $returnFormat, $filters, false, false, $elementCounter);
$responseType = $validFormats[$returnFormat][0];
return $this->RestResponse->viewData($final, $responseType, false, true);
return $this->RestResponse->viewData($final, $responseType, false, true, false, array('X-Result-Count' => $elementCounter, 'X-Export-Module-Used' => $returnFormat, 'X-Response-Format' => $responseType));
}
// returns an XML with attributes that belong to an event. The type of attributes to be returned can be restricted by type using the 3rd parameter.
@ -2632,7 +2868,7 @@ class AttributesController extends AppController
$this->redirect('/pages/display/administration');
}
public function hoverEnrichment($id)
public function hoverEnrichment($id, $persistent = false)
{
$attribute = $this->Attribute->fetchAttributes($this->Auth->user(), array('conditions' => array('Attribute.id' => $id), 'flatten' => 1));
if (empty($attribute)) {
@ -2665,6 +2901,9 @@ class AttributesController extends AppController
throw new MethodNotAllowedException(__('No valid enrichment options found for this attribute.'));
}
$data = array('module' => $type, $attribute[0]['Attribute']['type'] => $attribute[0]['Attribute']['value']);
if ($persistent) {
$data['persistent'] = 1;
}
if (!empty($options)) {
$data['config'] = $options;
}
@ -2672,11 +2911,11 @@ class AttributesController extends AppController
$result = $this->Module->queryModuleServer('/query', $data, true);
if ($result) {
if (!is_array($result)) {
$resultArray[] = array($type => $result);
$resultArray[$type][] = array($type => $result);
}
} else {
// TODO: i18n?
$resultArray[] = array($type => 'Enrichment service not reachable.');
$resultArray[$type][] = array($type => 'Enrichment service not reachable.');
continue;
}
if (!empty($result['results'])) {
@ -2689,11 +2928,11 @@ class AttributesController extends AppController
}
$tempArray[$k] = $v;
}
$resultArray[] = array($type => $tempArray);
$resultArray[$type][] = array($type => $tempArray);
} elseif ($r['values'] == null) {
$resultArray[] = array($type => 'No result');
$resultArray[$type][] = array($type => 'No result');
} else {
$resultArray[] = array($type => $r['values']);
$resultArray[$type][] = array($type => $r['values']);
}
}
}
@ -2772,15 +3011,52 @@ class AttributesController extends AppController
$tag_id = $this->request->data['tag'];
}
if (!is_numeric($tag_id)) {
$tag = $this->Attribute->AttributeTag->Tag->find('first', array('recursive' => -1, 'conditions' => array('LOWER(Tag.name) LIKE' => strtolower(trim($tag_id)))));
if (empty($tag)) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid Tag.')), 'status' => 200, 'type' => 'json'));
if (preg_match('/^collection_[0-9]+$/i', $tag_id)) {
$tagChoice = explode('_', $tag_id)[1];
$this->loadModel('TagCollection');
$tagCollection = $this->TagCollection->fetchTagCollection($this->Auth->user(), array('conditions' => array('TagCollection.id' => $tagChoice)));
if (empty($tagCollection)) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid Tag Collection.')), 'status'=>200, 'type' => 'json'));
}
$tag_id_list = array();
foreach ($tagCollection[0]['TagCollectionTag'] as $tagCollectionTag) {
$tag_id_list[] = $tagCollectionTag['tag_id'];
}
} else {
// try to parse json array
$tag_ids = json_decode($tag_id);
if ($tag_ids !== null) { // can decode json
$tag_id_list = array();
foreach ($tag_ids as $tag_id) {
if (preg_match('/^collection_[0-9]+$/i', $tag_id)) {
$tagChoice = explode('_', $tag_id)[1];
$this->loadModel('TagCollection');
$tagCollection = $this->TagCollection->fetchTagCollection($this->Auth->user(), array('conditions' => array('TagCollection.id' => $tagChoice)));
if (empty($tagCollection)) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid Tag Collection.')), 'status'=>200, 'type' => 'json'));
}
foreach ($tagCollection[0]['TagCollectionTag'] as $tagCollectionTag) {
$tag_id_list[] = $tagCollectionTag['tag_id'];
}
} else {
$tag_id_list[] = $tag_id;
}
}
} else {
$tag = $this->Event->EventTag->Tag->find('first', array('recursive' => -1, 'conditions' => $conditions));
if (empty($tag)) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid Tag.')), 'status'=>200, 'type' => 'json'));
}
$tag_id = $tag['Tag']['id'];
}
}
$tag_id = $tag['Tag']['id'];
}
if (!isset($idList)) {
$idList = array($id);
}
if (empty($tag_id_list)) {
$tag_id_list = array($tag_id);
}
$success = 0;
$fails = 0;
foreach ($idList as $id) {
@ -2789,11 +3065,14 @@ class AttributesController extends AppController
throw new NotFoundException(__('Invalid attribute'));
}
$this->Attribute->read();
if (!$this->_isSiteAdmin() && $this->Attribute->data['Event']['orgc_id'] !== $this->Auth->user('org_id')) {
$fails++;
continue;
}
if ($this->Attribute->data['Attribute']['deleted']) {
throw new NotFoundException(__('Invalid attribute'));
}
$eventId = $this->Attribute->data['Attribute']['event_id'];
$this->Attribute->Event->recursive = -1;
$event = $this->Attribute->Event->read(array(), $eventId);
if (!$this->_isSiteAdmin() && !$this->userRole['perm_sync']) {
@ -2805,40 +3084,44 @@ class AttributesController extends AppController
$this->Attribute->Event->insertLock($this->Auth->user(), $eventId);
}
$this->Attribute->recursive = -1;
$this->Attribute->AttributeTag->Tag->id = $tag_id;
if (!$this->Attribute->AttributeTag->Tag->exists()) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid Tag.')), 'status' => 200, 'type' => 'json'));
}
$tag = $this->Attribute->AttributeTag->Tag->find('first', array(
'conditions' => array('Tag.id' => $tag_id),
'recursive' => -1,
'fields' => array('Tag.name')
));
$found = $this->Attribute->AttributeTag->find('first', array(
'conditions' => array(
'attribute_id' => $id,
'tag_id' => $tag_id
),
'recursive' => -1,
));
$this->autoRender = false;
if (!empty($found)) {
$fails++;
continue;
}
$this->Attribute->AttributeTag->create();
if ($this->Attribute->AttributeTag->save(array('attribute_id' => $id, 'tag_id' => $tag_id, 'event_id' => $eventId))) {
$event['Event']['published'] = 0;
$date = new DateTime();
$event['Event']['timestamp'] = $date->getTimestamp();
$this->Attribute->Event->save($event);
$this->Attribute->data['Attribute']['timestamp'] = $date->getTimestamp();
$this->Attribute->save($this->Attribute->data);
$log = ClassRegistry::init('Log');
$log->createLogEntry($this->Auth->user(), 'tag', 'Attribute', $id, 'Attached tag (' . $tag_id . ') "' . $tag['Tag']['name'] . '" to attribute (' . $id . ')', 'Attribute (' . $id . ') tagged as Tag (' . $tag_id . ')');
$success++;
} else {
$fails++;
foreach ($tag_id_list as $tag_id) {
$this->Attribute->AttributeTag->Tag->id = $tag_id;
if (!$this->Attribute->AttributeTag->Tag->exists()) {
$fails++;
continue;
}
$tag = $this->Attribute->AttributeTag->Tag->find('first', array(
'conditions' => array('Tag.id' => $tag_id),
'recursive' => -1,
'fields' => array('Tag.name')
));
$found = $this->Attribute->AttributeTag->find('first', array(
'conditions' => array(
'attribute_id' => $id,
'tag_id' => $tag_id
),
'recursive' => -1,
));
$this->autoRender = false;
if (!empty($found)) {
$fails++;
continue;
}
$this->Attribute->AttributeTag->create();
if ($this->Attribute->AttributeTag->save(array('attribute_id' => $id, 'tag_id' => $tag_id, 'event_id' => $eventId))) {
$event['Event']['published'] = 0;
$date = new DateTime();
$event['Event']['timestamp'] = $date->getTimestamp();
$this->Attribute->Event->save($event);
$this->Attribute->data['Attribute']['timestamp'] = $date->getTimestamp();
$this->Attribute->save($this->Attribute->data);
$log = ClassRegistry::init('Log');
$log->createLogEntry($this->Auth->user(), 'tag', 'Attribute', $id, 'Attached tag (' . $tag_id . ') "' . $tag['Tag']['name'] . '" to attribute (' . $id . ')', 'Attribute (' . $id . ') tagged as Tag (' . $tag_id . ')');
$success++;
} else {
$fails++;
}
}
}
if ($fails == 0) {
@ -2952,7 +3235,7 @@ class AttributesController extends AppController
public function toggleCorrelation($id)
{
if (!$this->_isSiteAdmin() && Configure.read('MISP.allow_disabling_correlation')) {
if (!$this->_isSiteAdmin() && Configure::read('MISP.allow_disabling_correlation')) {
throw new MethodNotAllowedException(__('Disabling the correlation is not permitted on this instance.'));
}
$this->Attribute->id = $id;
@ -3001,6 +3284,12 @@ class AttributesController extends AppController
}
}
public function toggleToIDS($id)
{
return $this->fetchEditForm($id, 'to_ids');
}
public function checkAttachments()
{
$attributes = $this->Attribute->find(
@ -3025,19 +3314,18 @@ class AttributesController extends AppController
return new CakeResponse(array('body'=>$counter, 'status'=>200));
}
public function exportSearch($type = false)
{
if (empty($type)) {
$exports = array_keys($this->Attribute->validFormats);
$this->set('exports', $exports);
$this->render('ajax/exportSearch');
} else {
$filters = $this->Session->read('search_attributes_filters');
$filters = json_decode($filters, true);
$final = $this->Attribute->restSearch($this->Auth->user(), $type, $filters);
$responseType = $this->Attribute->validFormats[$type][0];
return $this->RestResponse->viewData($final, $responseType, false, true, 'search.' . $type . '.' . $responseType);
}
}
public function exportSearch($type = false)
{
if (empty($type)) {
$exports = array_keys($this->Attribute->validFormats);
$this->set('exports', $exports);
$this->render('ajax/exportSearch');
} else {
$filters = $this->Session->read('search_attributes_filters');
$filters = json_decode($filters, true);
$final = $this->Attribute->restSearch($this->Auth->user(), $type, $filters);
$responseType = $this->Attribute->validFormats[$type][0];
return $this->RestResponse->viewData($final, $responseType, false, true, 'search.' . $type . '.' . $responseType);
}
}
}

View File

@ -48,7 +48,7 @@ class ACLComponent extends Component
'edit' => array('perm_add'),
'editField' => array('perm_add'),
'editSelected' => array('perm_add'),
'exportSearch' => array('*'),
'exportSearch' => array('*'),
'fetchEditForm' => array('perm_add'),
'fetchViewValue' => array('*'),
'generateCorrelation' => array(),
@ -105,6 +105,7 @@ class ACLComponent extends Component
'enrichEvent' => array('perm_add'),
'export' => array('*'),
'exportChoice' => array('*'),
'exportModule' => array('*'),
'filterEventIdsForPush' => array('perm_sync'),
'filterEventIndex' => array('*'),
'freeTextImport' => array('perm_add'),
@ -117,10 +118,12 @@ class ACLComponent extends Component
'getReferenceData' => array('*'),
'getReferences' => array('*'),
'getObjectTemplate' => array('*'),
'viewMitreAttackMatrix' => array('*'),
'hids' => array('*'),
'index' => array('*'),
'importChoice' => array('*'),
'importModule' => array('*'),
'massDelete' => array('perm_site_admin'),
'merge' => array('perm_modify'),
'nids' => array('*'),
'proposalEventIndex' => array('*'),
'publish' => array('perm_publish'),
@ -136,18 +139,17 @@ class ACLComponent extends Component
'stix2' => array('*'),
'strposarray' => array(),
'toggleCorrelation' => array('perm_add'),
'unpublish' => array('perm_modify'),
'updateGraph' => array('*'),
'upload_analysis_file' => array('perm_add'),
'upload_sample' => array('AND' => array('perm_auth', 'perm_add')),
'upload_stix' => array('perm_add'),
'view' => array('*'),
'viewEventAttributes' => array('*'),
'viewEventGraph' => array('*'),
'viewGraph' => array('*'),
'xml' => array('*'),
'merge' => array('perm_modify'),
'importChoice' => array('*'),
'importModule' => array('*'),
'exportModule' => array('*')
'viewGalaxyMatrix' => array('*'),
'xml' => array('*')
),
'favouriteTags' => array(
'index' => array('*'),
@ -157,7 +159,7 @@ class ACLComponent extends Component
'feeds' => array(
'add' => array(),
'cacheFeeds' => array(),
'compareFeeds' => array(),
'compareFeeds' => array('*'),
'delete' => array(),
'disable' => array(),
'edit' => array(),
@ -167,11 +169,11 @@ class ACLComponent extends Component
'fetchSelectedFromFreetextIndex' => array(),
'getEvent' => array(),
'importFeeds' => array(),
'index' => array(),
'previewEvent' => array(),
'previewIndex' => array(),
'index' => array('*'),
'previewEvent' => array('*'),
'previewIndex' => array('*'),
'toggleSelected' => array('perm_site_admin'),
'view' => array(),
'view' => array('*'),
),
'galaxies' => array(
'attachCluster' => array('perm_tagger'),
@ -180,13 +182,14 @@ class ACLComponent extends Component
'selectGalaxy' => array('perm_tagger'),
'selectGalaxyNamespace' => array('perm_tagger'),
'selectCluster' => array('perm_tagger'),
'showGalaxies' => array('*'),
'update' => array(),
'view' => array('*'),
'viewGraph' => array('*')
),
'galaxyClusters' => array(
'attachToEvent' => array('perm_tagger'),
'delete' => array('perm_site_admin'),
'delete' => array('perm_site_admin'),
'detach' => array('perm_tagger'),
'index' => array('*'),
'view' => array('*')
@ -252,6 +255,7 @@ class ACLComponent extends Component
'delete' => array('perm_object_template'),
'getToggleField' => array(),
'objectChoice' => array('*'),
'objectMetaChoice' => array('perm_add'),
'view' => array('*'),
'viewElements' => array('*'),
'index' => array('*'),
@ -308,13 +312,14 @@ class ACLComponent extends Component
),
'servers' => array(
'add' => array(),
'cache' => array('perm_site_admin'),
'checkout' => array(),
'delete' => array(),
'deleteFile' => array(),
'edit' => array(),
'fetchServersForSG' => array('*'),
'filterEventIndex' => array(),
'getApiInfo' => array('*'),
'getApiInfo' => array('*'),
'getGit' => array(),
'getInstanceUUID' => array('perm_sync'),
'getPyMISPVersion' => array('*'),
@ -372,12 +377,25 @@ class ACLComponent extends Component
),
'sightings' => array(
'add' => array('perm_sighting'),
'restSearch' => array('perm_sighting'),
'advanced' => array('perm_sighting'),
'delete' => array('perm_sighting'),
'index' => array('*'),
'listSightings' => array('perm_sighting'),
'quickDelete' => array('perm_sighting'),
'viewSightings' => array('perm_sighting')
'viewSightings' => array('perm_sighting'),
'quickAdd' => array('perm_sighting')
),
'tagCollections' => array(
'add' => array('perm_tag_editor'),
'addTag' => array('perm_tag_editor'),
'delete' => array('perm_tag_editor'),
'edit' => array('perm_tag_editor'),
'getRow' => array('perm_tag_editor'),
'import' => array('perm_tag_editor'),
'index' => array('*'),
'removeTag' => array('perm_tag_editor'),
'view' => array('*')
),
'tags' => array(
'add' => array('perm_tag_editor'),
@ -387,10 +405,12 @@ class ACLComponent extends Component
'index' => array('*'),
'quickAdd' => array('perm_tag_editor'),
'removeTagFromObject' => array('perm_tagger'),
'search' => array('*'),
'selectTag' => array('perm_tagger'),
'selectTaxonomy' => array('perm_tagger'),
'showEventTag' => array('*'),
'showAttributeTag' => array('*'),
'showTagControllerTag' => array('*'),
'tagStatistics' => array('*'),
'view' => array('*'),
'viewGraph' => array('*'),
@ -472,7 +492,7 @@ class ACLComponent extends Component
'view' => array('*'),
),
'warninglists' => array(
'checkValue' => array('perm_auth'),
'checkValue' => array('perm_auth'),
'delete' => array(),
'enableWarninglist' => array(),
'getToggleField' => array(),
@ -547,9 +567,9 @@ class ACLComponent extends Component
private function __error($code, $message, $soft = false)
{
if ($soft) {
return $code;
}
if ($soft) {
return $code;
}
switch ($code) {
case 404:
throw new NotFoundException($message);

View File

@ -51,7 +51,9 @@ class ApacheAuthenticate extends BaseAuthenticate
$ldaprdn = Configure::read('ApacheSecureAuth.ldapReaderUser'); // DN ou RDN LDAP
$ldappass = Configure::read('ApacheSecureAuth.ldapReaderPassword');
$ldapSearchFilter = Configure::read('ApacheSecureAuth.ldapSearchFilter');
// LDAP connection
ldap_set_option(NULL, LDAP_OPT_NETWORK_TIMEOUT, Configure::read('ApacheSecureAuth.ldapNetworkTimeout', -1));
$ldapconn = ldap_connect(Configure::read('ApacheSecureAuth.ldapServer'))
or die('LDAP server connection failed');

View File

@ -12,9 +12,9 @@ class BlackListComponent extends Component
public function index($rest = false, $filters = array())
{
if (!empty($filters)) {
$this->controller->paginate['conditions'] = $filters;
}
if (!empty($filters)) {
$this->controller->paginate['conditions'] = $filters;
}
if ($this->controller->response->type() === 'application/json' || $this->controller->response->type() == 'application/xml' || $rest) {
$blackList = $this->controller->paginate();
$blacklist= array();

File diff suppressed because it is too large Load Diff

View File

@ -19,7 +19,7 @@ class EventBlacklistsController extends AppController
public $paginate = array(
'limit' => 60,
'maxLimit' => 9999, // LATER we will bump here on a problem once we have more than 9999 events <- no we won't, this is the max a user van view/page.
'maxLimit' => 9999, // LATER we will bump here on a problem once we have more than 9999 events <- no we won't, this is the max a user van view/page.
'order' => array(
'EventBlacklist.created' => 'DESC'
),
@ -27,13 +27,13 @@ class EventBlacklistsController extends AppController
public function index()
{
$params = array();
$validParams = array('event_uuid', 'comment');
foreach ($validParams as $validParam) {
if (!empty($this->params['named'][$validParam])) {
$params[$validParam] = $this->params['named'][$validParam];
}
}
$params = array();
$validParams = array('event_uuid', 'comment');
foreach ($validParams as $validParam) {
if (!empty($this->params['named'][$validParam])) {
$params[$validParam] = $this->params['named'][$validParam];
}
}
$this->BlackList->index($this->_isRest(), $params);
}

View File

@ -7,7 +7,7 @@ class EventDelegationsController extends AppController
public $paginate = array(
'limit' => 60,
'maxLimit' => 9999, // LATER we will bump here on a problem once we have more than 9999 events <- no we won't, this is the max a user van view/page.
'maxLimit' => 9999, // LATER we will bump here on a problem once we have more than 9999 events <- no we won't, this is the max a user van view/page.
'order' => array(
'EventDelegations.id' => 'DESC'
),

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@ class FavouriteTagsController extends AppController
public $paginate = array(
'limit' => 60,
'maxLimit' => 9999, // LATER we will bump here on a problem once we have more than 9999 events <- no we won't, this is the max a user van view/page.
'maxLimit' => 9999, // LATER we will bump here on a problem once we have more than 9999 events <- no we won't, this is the max a user van view/page.
'order' => array(
'FavouriteTag.id' => 'DESC'
),

View File

@ -4,7 +4,7 @@ App::uses('Xml', 'Utility');
class FeedsController extends AppController
{
public $components = array('Security' ,'RequestHandler'); // XXX ACL component
public $components = array('Security' ,'RequestHandler'); // XXX ACL component
public $paginate = array(
'limit' => 60,
@ -22,14 +22,17 @@ class FeedsController extends AppController
public function beforeFilter()
{
parent::beforeFilter();
$this->Security->unlockedActions = array('previewIndex');
if (!$this->_isSiteAdmin()) {
$this->Security->unlockedActions[] = 'previewIndex';
if (!$this->_isSiteAdmin() && $this->Auth->user('org_id') != Configure::read('MISP.host_org_id')) {
throw new MethodNotAllowedException(__('You don\'t have the required privileges to do that.'));
}
}
public function index()
{
if (!$this->_isSiteAdmin() && !$this->Auth->user('org_id') == Configure::read('MISP.host_org_id')) {
throw NotAllowedException('You don\'t have access to this feature.');
}
$this->Feed->load_default_feeds();
$scope = isset($this->passedArgs['scope']) ? $this->passedArgs['scope'] : 'all';
if ($scope !== 'all') {
@ -77,6 +80,9 @@ class FeedsController extends AppController
public function view($feedId)
{
if (!$this->_isSiteAdmin() && !$this->Auth->user('org_id') == Configure::read('MISP.host_org_id')) {
throw NotAllowedException('You don\'t have access to this feature.');
}
$feed = $this->Feed->find('first', array(
'conditions' => array('Feed.id' => $feedId),
'recursive' => -1,
@ -127,6 +133,9 @@ class FeedsController extends AppController
$tags = $this->Event->EventTag->Tag->find('list', array('fields' => array('Tag.name'), 'order' => array('lower(Tag.name) asc')));
$tags[0] = 'None';
$this->set('tags', $tags);
if (empty($this->request->data['Feed']['fixed_event'])) {
$this->request->data['Feed']['fixed_event'] = 1;
}
if ($this->request->is('post')) {
if ($this->_isRest()) {
if (empty($this->request->data['Feed'])) {
@ -150,6 +159,9 @@ class FeedsController extends AppController
$this->request->data['Feed']['sharing_group_id'] = 0;
}
$this->request->data['Feed']['default'] = 0;
if (!isset($this->request->data['Feed']['source_format'])) {
$this->request->data['Feed']['source_format'] = 'freetext';
}
if ($this->request->data['Feed']['source_format'] == 'freetext') {
if ($this->request->data['Feed']['fixed_event'] == 1) {
if (!empty($this->request->data['Feed']['target_event']) && is_numeric($this->request->data['Feed']['target_event'])) {
@ -390,10 +402,10 @@ class FeedsController extends AppController
$message = __('Fetching the feed has successfuly completed.');
if ($this->Feed->data['Feed']['source_format'] == 'misp') {
if (isset($result['add'])) {
$message['result'] .= ' Downloaded ' . count($result['add']) . ' new event(s).';
$message .= ' Downloaded ' . count($result['add']) . ' new event(s).';
}
if (isset($result['edit'])) {
$message['result'] .= ' Updated ' . count($result['edit']) . ' event(s).';
$message .= ' Updated ' . count($result['edit']) . ' event(s).';
}
}
}
@ -497,6 +509,9 @@ class FeedsController extends AppController
public function previewIndex($feedId)
{
if (!$this->_isSiteAdmin() && !$this->Auth->user('org_id') == Configure::read('MISP.host_org_id')) {
throw NotAllowedException('You don\'t have access to this feature.');
}
$this->Feed->id = $feedId;
if (!$this->Feed->exists()) {
throw new NotFoundException(__('Invalid feed.'));
@ -535,6 +550,27 @@ class FeedsController extends AppController
$this->Flash->info($events);
$this->redirect(array('controller' => 'feeds', 'action' => 'index'));
}
if (!empty($this->params['named']['searchall'])) {
foreach ($events as $uuid => $event) {
$found = false;
if (strpos(strtolower($event['info']), strtolower($this->params['named']['searchall'])) !== false) {
$found = true;
}
if (strpos(strtolower($event['Orgc']['name']), strtolower($this->params['named']['searchall'])) !== false) {
$found = true;
}
if (!empty($event['Tag'])) {
foreach ($event['Tag'] as $tag) {
if (strpos(strtolower($tag['name']), strtolower($this->params['named']['searchall'])) !== false) {
$found = true;
}
}
}
if (!$found) {
unset($events[$uuid]);
}
}
}
foreach ($filterParams as $k => $filter) {
if (!empty($filter)) {
$filterParams[$k] = json_decode($filter);
@ -677,6 +713,9 @@ class FeedsController extends AppController
public function previewEvent($feedId, $eventUuid, $all = false)
{
if (!$this->_isSiteAdmin() && !$this->Auth->user('org_id') == Configure::read('MISP.host_org_id')) {
throw NotAllowedException('You don\'t have access to this feature.');
}
$this->Feed->id = $feedId;
if (!$this->Feed->exists()) {
throw new NotFoundException(__('Invalid feed.'));
@ -836,6 +875,9 @@ class FeedsController extends AppController
public function compareFeeds($id = false)
{
if (!$this->_isSiteAdmin() && !$this->Auth->user('org_id') == Configure::read('MISP.host_org_id')) {
throw NotAllowedException('You don\'t have access to this feature.');
}
$feeds = $this->Feed->compareFeeds($id);
if ($this->_isRest()) {
return $this->RestResponse->viewData($feeds, $this->response->type());

View File

@ -7,7 +7,7 @@ class GalaxiesController extends AppController
public $paginate = array(
'limit' => 60,
'maxLimit' => 9999, // LATER we will bump here on a problem once we have more than 9999 events <- no we won't, this is the max a user van view/page.
'maxLimit' => 9999, // LATER we will bump here on a problem once we have more than 9999 events <- no we won't, this is the max a user van view/page.
'contain' => array(
),
@ -35,8 +35,8 @@ class GalaxiesController extends AppController
if (!empty($this->params['named']['force'])) {
$force = 1;
} else {
$force = 0;
}
$force = 0;
}
$result = $this->Galaxy->update($force);
$message = 'Galaxies updated.';
if ($this->_isRest()) {
@ -79,36 +79,46 @@ class GalaxiesController extends AppController
public function selectGalaxy($target_id, $target_type='event', $namespace='misp')
{
$expectedDescription = 'ATT&CK Tactic';
$mitreAttackGalaxyId = $this->Galaxy->getMitreAttackGalaxyId();
$conditions = $namespace == '0' ? array() : array('namespace' => $namespace);
if ($namespace == 'mitre-attack' || $namespace == '0') {
$conditions[] = array('description !=' => $expectedDescription);
$conditions2 = array('namespace' => 'mitre-attack');
$conditions2[] = array('description' => $expectedDescription);
$tacticGalaxies = $this->Galaxy->find('all', array(
'recursive' => -1,
'conditions' => $conditions2,
));
}
$galaxies = $this->Galaxy->find('all', array(
'recursive' => -1,
'conditions' => $conditions,
'order' => array('name asc')
));
if (!empty($tacticGalaxies)) {
array_unshift($galaxies, array('Galaxy' => array(
'id' => '-1',
'uuid' => '-1',
'name' => $expectedDescription,
'type' => '-1',
'icon' => '/img/mitre-attack-icon.ico',
'namespace' => 'mitre-attack'
)));
$items = array();
$items[] = array(
'name' => __('All clusters'),
'value' => "/galaxies/selectCluster/" . h($target_id) . '/' . h($target_type) . '/0'
);
foreach ($galaxies as $galaxy) {
if (!isset($galaxy['Galaxy']['kill_chain_order'])) {
$items[] = array(
'name' => h($galaxy['Galaxy']['name']),
'value' => "/galaxies/selectCluster/" . $target_id . '/' . $target_type . '/' . $galaxy['Galaxy']['id'],
'template' => array(
'preIcon' => 'fa-' . $galaxy['Galaxy']['icon'],
'name' => $galaxy['Galaxy']['name'],
'infoExtra' => $galaxy['Galaxy']['description'],
)
);
} else { // should use matrix instead
$param = array(
'name' => $galaxy['Galaxy']['name'],
'functionName' => "getMatrixPopup('" . $target_type . "', '" . $target_id . "', " . $galaxy['Galaxy']['id'] . ")",
'isPill' => true,
'isMatrix' => true
);
if ($galaxy['Galaxy']['id'] == $mitreAttackGalaxyId) {
$param['img'] = "/img/mitre-attack-icon.ico";
}
$items[] = $param;
}
}
$this->set('galaxies', $galaxies);
$this->set('target_id', $target_id);
$this->set('target_type', $target_type);
$this->render('ajax/galaxy_choice');
$this->set('items', $items);
$this->render('/Elements/generic_picker');
}
public function selectGalaxyNamespace($target_id, $target_type='event')
@ -116,12 +126,27 @@ class GalaxiesController extends AppController
$namespaces = $this->Galaxy->find('list', array(
'recursive' => -1,
'fields' => array('namespace', 'namespace'),
'group' => array('namespace')
'group' => array('namespace'),
'order' => array('namespace asc')
));
$this->set('namespaces', $namespaces);
$this->set('target_id', $target_id);
$this->set('target_type', $target_type);
$this->render('ajax/galaxy_namespace_choice');
$items = array();
$items[] = array(
'name' => __('All namespaces'),
'value' => "/galaxies/selectGalaxy/" . $target_id . '/' . $target_type . '/0'
);
foreach ($namespaces as $namespace) {
$items[] = array(
'name' => $namespace,
'value' => "/galaxies/selectGalaxy/" . $target_id . '/' . $target_type . '/' . $namespace
);
}
$this->set('items', $items);
$this->set('options', array( // set chosen (select picker) options
'multiple' => 0,
));
$this->render('/Elements/generic_picker');
}
public function selectCluster($target_id, $target_type = 'event', $selectGalaxy = false)
@ -132,60 +157,116 @@ class GalaxiesController extends AppController
}
$data = $this->Galaxy->GalaxyCluster->find('all', array(
'conditions' => $conditions,
'fields' => array('value', 'description', 'source', 'type'),
'contain' => array(
'GalaxyElement' => array(
'conditions' => array('GalaxyElement.key' => 'synonyms')
)
),
'fields' => array('value', 'description', 'source', 'type', 'id'),
'order' => array('value asc'),
'recursive' => -1
));
$clusters = array();
$lookup_table = array();
foreach ($data as $k => $cluster) {
$temp = $this->Galaxy->GalaxyCluster->GalaxyElement->find('all', array(
'conditions' => array(
'GalaxyElement.galaxy_cluster_id' => $cluster['GalaxyCluster']['id'],
'GalaxyElement.key' => 'synonyms'
),
'recursive' => -1
));
$cluster['GalaxyCluster']['synonyms_string'] = array();
foreach ($cluster['GalaxyElement'] as $element) {
$cluster['GalaxyCluster']['synonyms_string'][] = $element['value'];
if (isset($lookup_table[$cluster['GalaxyCluster']['type']][$element['value']])) {
$lookup_table[$cluster['GalaxyCluster']['type']][$element['value']][] = $cluster['GalaxyCluster']['id'];
} else {
$lookup_table[$cluster['GalaxyCluster']['type']][$element['value']] = array($cluster['GalaxyCluster']['id']);
}
foreach ($temp as $element) {
$cluster['GalaxyCluster']['synonyms_string'][] = $element['GalaxyElement']['value'];
$cluster['GalaxyElement'][] = $element['GalaxyElement'];
}
unset($temp);
$cluster['GalaxyCluster']['synonyms_string'] = implode(', ', $cluster['GalaxyCluster']['synonyms_string']);
unset($cluster['GalaxyElement']);
$clusters[$cluster['GalaxyCluster']['type']][$cluster['GalaxyCluster']['value']] = $cluster['GalaxyCluster'];
if (isset($lookup_table[$cluster['GalaxyCluster']['type']][$cluster['GalaxyCluster']['value']])) {
$lookup_table[$cluster['GalaxyCluster']['type']][$cluster['GalaxyCluster']['value']][] = $cluster['GalaxyCluster']['id'];
} else {
$lookup_table[$cluster['GalaxyCluster']['type']][$cluster['GalaxyCluster']['value']] = array($cluster['GalaxyCluster']['id']);
}
}
ksort($clusters);
$this->set('clusters', $clusters);
$this->set('target_id', $target_id);
$this->set('target_type', $target_type);
$this->set('lookup_table', $lookup_table);
$this->render('ajax/cluster_choice');
$items = array();
foreach ($clusters as $namespace => $cluster_data) {
foreach ($cluster_data as $k => $cluster) {
$name = $cluster['value'];
$optionName = $cluster['value'];
if ($cluster['synonyms_string'] !== '') {
$synom = __('Synonyms: ') . $cluster['synonyms_string'];
$optionName .= $cluster['synonyms_string'] !== '' ? ' (' . $cluster['synonyms_string'] . ')' : '';
} else {
$synom = '';
}
$itemParam = array(
'name' => $optionName,
'value' => $cluster['id'],
'template' => array(
'name' => $name,
'infoExtra' => $cluster['description'],
)
);
if ($cluster['synonyms_string'] !== '') {
$itemParam['template']['infoContextual'] = $synom;
}
$items[] = $itemParam;
unset($cluster_data[$k]);
}
}
$onClickForm = 'quickSubmitGalaxyForm';
if ($this->_isRest()) {
return $this->RestResponse->viewData($items, $this->response->type());
} else {
$this->set('items', $items);
$this->set('options', array( // set chosen (select picker) options
'functionName' => $onClickForm,
'multiple' => '-1',
'select_options' => array(
'additionalData' => array(
'target_id' => $target_id,
'target_type' => $target_type,
)
),
));
$this->render('ajax/cluster_choice');
}
}
public function attachCluster($target_id, $target_type = 'event')
{
$cluster_id = $this->request->data['Galaxy']['target_id'];
$result = $this->Galaxy->attachCluster($this->Auth->user(), $target_type, $target_id, $cluster_id);
$this->Flash->info($result);
$this->redirect($this->referer());
return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'success' => $result, 'check_publish' => true)), 'status'=>200, 'type' => 'json'));
}
public function attachMultipleClusters($target_id, $target_type = 'event')
{
$cluster_ids = json_decode($this->request->data['Galaxy']['target_ids'], true);
$result = "";
foreach ($cluster_ids as $cluster_id) {
$result = $this->Galaxy->attachCluster($this->Auth->user(), $target_type, $target_id, $cluster_id);
if ($target_id === 'selected') {
$target_id_list = json_decode($this->request->data['Galaxy']['attribute_ids']);
} else {
$target_id_list = array($target_id);
}
$cluster_ids = $this->request->data['Galaxy']['target_ids'];
if (!empty($cluster_ids)) {
$cluster_ids = json_decode($cluster_ids, true);
if ($cluster_ids === null) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'error' => __('Failed to parse request.'))), 'status'=>200, 'type' => 'json'));
}
} else {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'error' => __('No clusters picked.'))), 'status'=>200, 'type' => 'json'));
}
$result = "";
if (!is_array($cluster_ids)) { // in case we only want to attach 1
$cluster_ids = array($cluster_ids);
}
foreach ($cluster_ids as $cluster_id) {
foreach ($target_id_list as $target_id) {
$result = $this->Galaxy->attachCluster($this->Auth->user(), $target_type, $target_id, $cluster_id);
}
}
if ($this->request->is('ajax')) {
return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'success' => $result, 'check_publish' => true)), 'status'=>200, 'type' => 'json'));
} else {
$this->Flash->info($result);
$this->redirect($this->referer());
}
$this->Flash->info($result);
$this->redirect($this->referer());
}
public function viewGraph($id)
@ -204,4 +285,34 @@ class GalaxiesController extends AppController
$this->set('galaxy_id', $cluster['Galaxy']['id']);
$this->render('/Events/view_graph');
}
public function showGalaxies($id, $scope = 'event')
{
$this->layout = 'ajax';
$this->set('scope', $scope);
if ($scope == 'event') {
$this->loadModel('Event');
$object = $this->Event->fetchEvent($this->Auth->user(), array('eventid' => $id, 'metadata' => 1));
if (empty($object)) {
throw new MethodNotAllowedException('Invalid event.');
}
$this->set('object', $object[0]);
} elseif ($scope == 'attribute') {
$this->loadModel('Attribute');
$object = $this->Attribute->fetchAttributes($this->Auth->user(), array('conditions' => array('Attribute.id' => $id), 'flatten' => 1));
if (empty($object)) {
throw new MethodNotAllowedException('Invalid attribute.');
}
$object[0] = $this->Attribute->Event->massageTags($object[0], 'Attribute');
} elseif ($scope == 'tag_collection') {
$this->loadModel('TagCollection');
$object = $this->TagCollection->fetchTagCollection($this->Auth->user(), array('conditions' => array('TagCollection.id' => $id)));
if (empty($object)) {
throw new MethodNotAllowedException('Invalid Tag Collection.');
}
}
$this->set('object', $object[0]);
$this->render('/Events/ajax/ajaxGalaxies');
}
}

View File

@ -7,7 +7,7 @@ class GalaxyClustersController extends AppController
public $paginate = array(
'limit' => 60,
'maxLimit' => 9999, // LATER we will bump here on a problem once we have more than 9999 events <- no we won't, this is the max a user van view/page.
'maxLimit' => 9999, // LATER we will bump here on a problem once we have more than 9999 events <- no we won't, this is the max a user van view/page.
'recursive' => -1,
'order' => array(
'GalaxyCluster.value' => 'ASC'
@ -115,14 +115,14 @@ class GalaxyClustersController extends AppController
public function view($id)
{
$conditions = array('GalaxyCluster.id' => $id);
if (Validation::uuid($id)) {
$conditions = array('GalaxyCluster.uuid' => $id);
}
$contain = array('Galaxy');
if ($this->_isRest()) {
$contain[] = 'GalaxyElement';
}
$conditions = array('GalaxyCluster.id' => $id);
if (Validation::uuid($id)) {
$conditions = array('GalaxyCluster.uuid' => $id);
}
$contain = array('Galaxy');
if ($this->_isRest()) {
$contain[] = 'GalaxyElement';
}
$cluster = $this->GalaxyCluster->find('first', array(
'recursive' => -1,
'contain' => $contain,
@ -143,16 +143,18 @@ class GalaxyClustersController extends AppController
$cluster['GalaxyCluster']['tag_count'] = count($tag['EventTag']);
$cluster['GalaxyCluster']['tag_id'] = $tag['Tag']['id'];
}
} else {
throw new NotFoundException('Cluster not found.');
}
if ($this->_isRest()) {
$cluster['GalaxyCluster']['Galaxy'] = $cluster['Galaxy'];
$cluster['GalaxyCluster']['GalaxyElement'] = $cluster['GalaxyElement'];
return $this->RestResponse->viewData(array('GalaxyCluster' => $cluster['GalaxyCluster']), $this->response->type());
} else {
$this->set('id', $id);
$this->set('galaxy_id', $cluster['Galaxy']['id']);
$this->set('cluster', $cluster);
}
if ($this->_isRest()) {
$cluster['GalaxyCluster']['Galaxy'] = $cluster['Galaxy'];
$cluster['GalaxyCluster']['GalaxyElement'] = $cluster['GalaxyElement'];
return $this->RestResponse->viewData(array('GalaxyCluster' => $cluster['GalaxyCluster']), $this->response->type());
} else {
$this->set('id', $id);
$this->set('galaxy_id', $cluster['Galaxy']['id']);
$this->set('cluster', $cluster);
}
}
public function attachToEvent($event_id, $tag_name)
@ -222,20 +224,40 @@ class GalaxyClustersController extends AppController
$event_id = $attribute['Attribute']['event_id'];
} elseif ($target_type == 'event') {
$event_id = $target_id;
} elseif ($target_type === 'tag_collection') {
// pass
} else {
throw new MethodNotAllowedException('Invalid options');
}
$this->Event->id = $event_id;
$this->Event->recursive = -1;
$event = $this->Event->read(array(), $event_id);
if (empty($event)) {
throw new MethodNotAllowedException('Invalid Event.');
}
if (!$this->_isSiteAdmin() && !$this->userRole['perm_sync']) {
if (!$this->userRole['perm_tagger'] || ($this->Auth->user('org_id') !== $event['Event']['org_id'] && $this->Auth->user('org_id') !== $event['Event']['orgc_id'])) {
if ($target_type === 'tag_collection') {
$tag_collection = $this->GalaxyCluster->Tag->TagCollectionTag->TagCollection->fetchTagCollection($this->Auth->user(), array(
'conditions' => array('TagCollection.id' => $target_id),
'contain' => array('Organisation', 'TagCollectionTag' => array('Tag'))
));
if (empty($tag_collection)) {
throw new MethodNotAllowedException('Invalid Tag Collection');
}
$tag_collection = $tag_collection[0];
if (!$this->_isSiteAdmin()) {
if (!$this->userRole['perm_tag_editor'] || $this->Auth->user('org_id') !== $tag_collection['TagCollection']['org_id']) {
throw new MethodNotAllowedException('Invalid Tag Collection');
}
}
} else {
$this->Event->id = $event_id;
$this->Event->recursive = -1;
$event = $this->Event->read(array(), $event_id);
if (empty($event)) {
throw new MethodNotAllowedException('Invalid Event.');
}
if (!$this->_isSiteAdmin() && !$this->userRole['perm_sync']) {
if (!$this->userRole['perm_tagger'] || ($this->Auth->user('org_id') !== $event['Event']['org_id'] && $this->Auth->user('org_id') !== $event['Event']['orgc_id'])) {
throw new MethodNotAllowedException('Invalid Event.');
}
}
}
if ($target_type == 'attribute') {
$existingTargetTag = $this->Event->Attribute->AttributeTag->find('first', array(
'conditions' => array('AttributeTag.tag_id' => $tag_id, 'AttributeTag.attribute_id' => $target_id),
@ -248,6 +270,12 @@ class GalaxyClustersController extends AppController
'recursive' => -1,
'contain' => array('Tag')
));
} elseif ($target_type == 'tag_collection') {
$existingTargetTag = $this->GalaxyCluster->Tag->TagCollectionTag->find('first', array(
'conditions' => array('TagCollectionTag.tag_id' => $tag_id, 'TagCollectionTag.tag_collection_id' => $target_id),
'recursive' => -1,
'contain' => array('Tag')
));
}
if (empty($existingTargetTag)) {
@ -261,6 +289,8 @@ class GalaxyClustersController extends AppController
$result = $this->Event->EventTag->delete($existingTargetTag['EventTag']['id']);
} elseif ($target_type == 'attribute') {
$result = $this->Event->Attribute->AttributeTag->delete($existingTargetTag['AttributeTag']['id']);
} elseif ($target_type == 'tag_collection') {
$result = $this->GalaxyCluster->Tag->TagCollectionTag->delete($existingTargetTag['TagCollectionTag']['id']);
}
if ($result) {
$event['Event']['published'] = 0;
@ -286,43 +316,44 @@ class GalaxyClustersController extends AppController
$this->redirect($this->referer());
}
public function delete($id) {
{
if ($this->request->is('post')) {
$result = false;
$galaxy_cluster = $this->GalaxyCluster->find('first', array(
'recursive' => -1,
'conditions' => array('GalaxyCluster.id' => $id)
));
if (!empty($galaxy_cluster)) {
$result = $this->GalaxyCluster->delete($id, true);
$galaxy_id = $galaxy_cluster['GalaxyCluster']['galaxy_id'];
}
if ($result) {
$message = 'Galaxy cluster successfuly deleted.';
if ($this->_isRest()) {
return $this->RestResponse->saveSuccessResponse('GalaxyCluster', 'delete', $id, $this->response->type());
} else {
$this->Flash->success($message);
$this->redirect(array('controller' => 'galaxies', 'action' => 'view', $galaxy_id));
}
} else {
$message = 'Galaxy cluster could not be deleted.';
if ($this->_isRest()) {
return $this->RestResponse->saveFailResponse('GalaxyCluster', 'delete', $id, $message, $this->response->type());
} else {
$this->Flash->error($message);
$this->redirect(array('controller' => 'taxonomies', 'action' => 'index'));
}
}
} else {
if ($this->request->is('ajax')) {
$this->set('id', $id);
$this->render('ajax/galaxy_cluster_delete_confirmation');
} else {
throw new MethodNotAllowedException('This function can only be reached via AJAX.');
}
}
}
}
public function delete($id)
{
{
if ($this->request->is('post')) {
$result = false;
$galaxy_cluster = $this->GalaxyCluster->find('first', array(
'recursive' => -1,
'conditions' => array('GalaxyCluster.id' => $id)
));
if (!empty($galaxy_cluster)) {
$result = $this->GalaxyCluster->delete($id, true);
$galaxy_id = $galaxy_cluster['GalaxyCluster']['galaxy_id'];
}
if ($result) {
$message = 'Galaxy cluster successfuly deleted.';
if ($this->_isRest()) {
return $this->RestResponse->saveSuccessResponse('GalaxyCluster', 'delete', $id, $this->response->type());
} else {
$this->Flash->success($message);
$this->redirect(array('controller' => 'galaxies', 'action' => 'view', $galaxy_id));
}
} else {
$message = 'Galaxy cluster could not be deleted.';
if ($this->_isRest()) {
return $this->RestResponse->saveFailResponse('GalaxyCluster', 'delete', $id, $message, $this->response->type());
} else {
$this->Flash->error($message);
$this->redirect(array('controller' => 'taxonomies', 'action' => 'index'));
}
}
} else {
if ($this->request->is('ajax')) {
$this->set('id', $id);
$this->render('ajax/galaxy_cluster_delete_confirmation');
} else {
throw new MethodNotAllowedException('This function can only be reached via AJAX.');
}
}
}
}
}

View File

@ -7,7 +7,7 @@ class GalaxyElementsController extends AppController
public $paginate = array(
'limit' => 20,
'maxLimit' => 9999, // LATER we will bump here on a problem once we have more than 9999 events <- no we won't, this is the max a user van view/page.
'maxLimit' => 9999, // LATER we will bump here on a problem once we have more than 9999 events <- no we won't, this is the max a user van view/page.
'recursive' => -1,
'order' => array(
'GalaxyElement.key' => 'ASC'

View File

@ -29,98 +29,120 @@ class LogsController extends AppController
}
}
private function __resolveSpecial($data, $type, $fields) {
if (!is_array($data)) {
$data = array($data);
}
foreach ($data as $k => $element) {
if (!is_numeric($data)) {
$this->loadModel($type);
$params = array(
'conditions' => array(),
'recursive' => -1,
'fields' => array($type . '.id')
);
foreach ($fields as $field) {
$params['conditions']['OR'][$type . '.' . $field] = $element;
}
$records = $this->$type->find('all', $params);
if (empty($records)) {
$data[$k] = -1;
} else {
$temp = array();
foreach ($records as $record) {
$temp[] = $record[$type]['id'];
}
$data = array_merge($data, $temp);
}
}
}
return $data;
}
private function __resolveSpecial($data, $type, $fields)
{
if (!is_array($data)) {
$data = array($data);
}
foreach ($data as $k => $element) {
if (!is_numeric($data)) {
$this->loadModel($type);
$params = array(
'conditions' => array(),
'recursive' => -1,
'fields' => array($type . '.id')
);
foreach ($fields as $field) {
$params['conditions']['OR'][$type . '.' . $field] = $element;
}
$records = $this->$type->find('all', $params);
if (empty($records)) {
$data[$k] = -1;
} else {
$temp = array();
foreach ($records as $record) {
$temp[] = $record[$type]['id'];
}
$data = array_merge($data, $temp);
}
}
}
return $data;
}
public function admin_index()
{
if ($this->_isRest()) {
$paramArray = array('id', 'title', 'created', 'model', 'model_id', 'action', 'user_id', 'change', 'email', 'org', 'description', 'ip');
$filterData = array(
'request' => $this->request,
'named_params' => $this->params['named'],
'paramArray' => $paramArray,
'ordered_url_params' => compact($paramArray)
);
$exception = false;
$filters = $this->_harvestParameters($filterData, $exception);
unset($filterData);
if ($filters === false) {
return $exception;
}
$conditions = array();
foreach ($filters as $filter => $data) {
$data = array('OR' => $data);
$conditions = $this->Log->generic_add_filter($conditions, $data, 'Log.' . $filter);
}
if (!$this->_isSiteAdmin()) {
$orgRestriction = $this->Auth->user('Organisation')['name'];
$conditions['AND']['Log.org'] = $orgRestriction;
}
$params = array(
'conditions' => $conditions,
'recursive' => -1
);
if (isset($filters['limit'])) {
$params['limit'] = $filters['limit'];
}
if (isset($filters['page'])) {
$params['page'] = $filters['page'];
}
$log_entries = $this->Log->find('all', $params);
return $this->RestResponse->viewData($log_entries, 'json');
} else {
if (!$this->userRole['perm_audit']) {
$this->redirect(array('controller' => 'events', 'action' => 'index', 'admin' => false));
}
$this->set('isSearch', 0);
$this->recursive = 0;
$validFilters = $this->Log->logMeta;
if (!$this->_isSiteAdmin()) {
$orgRestriction = $this->Auth->user('Organisation')['name'];
$conditions['Log.org'] = $orgRestriction;
$this->paginate = array(
'limit' => 60,
'conditions' => $conditions,
'order' => array('Log.id' => 'DESC')
);
} else {
$validFilters = array_merge_recursive($validFilters, $this->Log->logMetaAdmin);
}
if (isset($this->params['named']['filter']) && in_array($this->params['named']['filter'], array_keys($validFilters))) {
$this->paginate['conditions']['Log.action'] = $validFilters[$this->params['named']['filter']]['values'];
}
$this->set('validFilters', $validFilters);
$this->set('filter', isset($this->params['named']['filter']) ? $this->params['named']['filter'] : false);
$this->set('list', $this->paginate());
}
if ($this->_isRest()) {
$paramArray = array('id', 'title', 'created', 'model', 'model_id', 'action', 'user_id', 'change', 'email', 'org', 'description', 'ip');
$filterData = array(
'request' => $this->request,
'named_params' => $this->params['named'],
'paramArray' => $paramArray,
'ordered_url_params' => compact($paramArray)
);
$exception = false;
$filters = $this->_harvestParameters($filterData, $exception);
unset($filterData);
if ($filters === false) {
return $exception;
}
$conditions = array();
foreach ($filters as $filter => $data) {
if ($filter === 'created') {
$tempData = $data;
if (!is_array($data)) {
$tempData = array($data);
}
foreach ($tempData as $k => $v) {
$tempData[$k] = $this->Log->resolveTimeDelta($v);
}
if (count($tempData) == 1) {
$conditions['AND']['created >='] = date("Y-m-d H:i:s", $tempData[0]);
} else {
if ($tempData[0] < $tempData[1]) {
$temp = $tempData[1];
$tempData[1] = $tempData[0];
$tempData[0] = $temp;
}
$conditions['AND'][] = array('created <= ' => date("Y-m-d H:i:s", $tempData[0]));
$conditions['AND'][] = array('created >= ' => date("Y-m-d H:i:s", $tempData[1]));
}
} else {
$data = array('OR' => $data);
$conditions = $this->Log->generic_add_filter($conditions, $data, 'Log.' . $filter);
}
}
if (!$this->_isSiteAdmin()) {
$orgRestriction = $this->Auth->user('Organisation')['name'];
$conditions['AND']['Log.org'] = $orgRestriction;
}
$params = array(
'conditions' => $conditions,
'recursive' => -1
);
if (isset($filters['limit'])) {
$params['limit'] = $filters['limit'];
}
if (isset($filters['page'])) {
$params['page'] = $filters['page'];
}
$log_entries = $this->Log->find('all', $params);
return $this->RestResponse->viewData($log_entries, 'json');
} else {
if (!$this->userRole['perm_audit']) {
$this->redirect(array('controller' => 'events', 'action' => 'index', 'admin' => false));
}
$this->set('isSearch', 0);
$this->recursive = 0;
$validFilters = $this->Log->logMeta;
if (!$this->_isSiteAdmin()) {
$orgRestriction = $this->Auth->user('Organisation')['name'];
$conditions['Log.org'] = $orgRestriction;
$this->paginate = array(
'limit' => 60,
'conditions' => $conditions,
'order' => array('Log.id' => 'DESC')
);
} else {
$validFilters = array_merge_recursive($validFilters, $this->Log->logMetaAdmin);
}
if (isset($this->params['named']['filter']) && in_array($this->params['named']['filter'], array_keys($validFilters))) {
$this->paginate['conditions']['Log.action'] = $validFilters[$this->params['named']['filter']]['values'];
}
$this->set('validFilters', $validFilters);
$this->set('filter', isset($this->params['named']['filter']) ? $this->params['named']['filter'] : false);
$this->set('list', $this->paginate());
}
}
// Shows a minimalistic history for the currently selected event

View File

@ -7,7 +7,7 @@ class NewsController extends AppController
public $paginate = array(
'limit' => 5,
'maxLimit' => 9999, // LATER we will bump here on a problem once we have more than 9999 events <- no we won't, this is the max a user van view/page.
'maxLimit' => 9999, // LATER we will bump here on a problem once we have more than 9999 events <- no we won't, this is the max a user van view/page.
'order' => array(
'News.id' => 'DESC'
),
@ -31,10 +31,10 @@ class NewsController extends AppController
}
}
$this->User->id = $this->Auth->user('id');
//if ($this->User->exists()) {
$this->User->saveField('newsread', time());
$this->set('newsItems', $newsItems);
//}
//if ($this->User->exists()) {
$this->User->saveField('newsread', time());
$this->set('newsItems', $newsItems);
//}
}
public function add()

View File

@ -162,6 +162,7 @@ class ObjectReferencesController extends AppController
$relationships[$v['ObjectRelationship']['name']] = $v['ObjectRelationship']['name'];
}
$relationships['custom'] = 'custom';
ksort($relationships);
$this->set('relationships', $relationships);
$this->set('event', $event);
$this->set('objectId', $objectId);

View File

@ -17,36 +17,91 @@ class ObjectTemplatesController extends AppController
'recursive' => -1
);
public function objectChoice($event_id)
{
$this->ObjectTemplate->populateIfEmpty($this->Auth->user());
$templates_raw = $this->ObjectTemplate->find('all', array(
public function objectMetaChoice($event_id) {
$metas = $this->ObjectTemplate->find('list', array(
'recursive' => -1,
'conditions' => array('ObjectTemplate.active' => 1),
'fields' => array('meta-category', 'meta-category'),
'group' => array('ObjectTemplate.meta-category'),
'order' => array('ObjectTemplate.meta-category asc')
));
$items = array();
$items[] = array(
'name' => __('All Objects'),
'value' => "/ObjectTemplates/objectChoice/" . h($event_id) . "/" . "0"
);
foreach($metas as $meta) {
$items[] = array(
'name' => $meta,
'value' => "/ObjectTemplates/objectChoice/" . h($event_id) . "/" . h($meta)
);
}
$this->set('items', $items);
$this->set('options', array(
'multiple' => 0,
));
$this->render('/Elements/generic_picker');
}
public function objectChoice($event_id, $category=false)
{
$this->ObjectTemplate->populateIfEmpty($this->Auth->user());
$conditions = array('ObjectTemplate.active' => 1);
if ($category !== false && $category !== "0") {
$conditions['meta-category'] = $category;
}
$templates_raw = $this->ObjectTemplate->find('all', array(
'recursive' => -1,
'conditions' => $conditions,
'fields' => array('id', 'meta-category', 'name', 'description', 'org_id'),
'contain' => array('Organisation.name'),
'sort' => array('ObjectTemplate.name asc')
'order' => array('ObjectTemplate.name asc')
));
$templates = array('all' => array());
foreach ($templates_raw as $k => $template) {
unset($template['ObjectTemplate']['meta-category']);
$template['ObjectTemplate']['org_name'] = $template['Organisation']['name'];
$templates[$templates_raw[$k]['ObjectTemplate']['meta-category']][] = $template['ObjectTemplate'];
$templates['all'][] = $template['ObjectTemplate'];
$items = array();
foreach($templates_raw as $template) {
$template = $template['ObjectTemplate'];
$items[] = array(
'name' => $template['name'],
'value' => $template['id'],
'template' => array(
'name' => $template['name'],
'infoExtra' => $template['description'],
'infoContextual' => $template['meta-category']
)
);
}
foreach ($templates as $category => $template_list) {
$templates[$category] = Hash::sort($templates[$category], '{n}.name');
}
$template_categories = array_keys($templates);
$this->layout = false;
$this->set('template_categories', $template_categories);
$this->set('eventId', $event_id);
$this->set('templates', $templates);
$this->render('ajax/object_choice');
$fun = 'redirectAddObject';
$this->set('items', $items);
$this->set('options', array(
'functionName' => $fun,
'multiple' => 0,
'select_options' => array(
'additionalData' => array('event_id' => $event_id),
),
));
$this->render('/Elements/generic_picker');
}
public function view($id)
{
if (Validation::uuid($id)) {
$temp = $this->ObjectTemplate->find('first', array(
'recursive' => -1,
'conditions' => array('ObjectTemplate.uuid' => $id),
'fields' => array('ObjectTemplate.id', 'ObjectTemplate.uuid'),
'order' => array('ObjectTemplate.version desc')
));
if (empty($temp)) {
throw new NotFoundException(__('Invalid object template'));
}
$id = $temp['ObjectTemplate']['id'];
} elseif (!is_numeric($id)) {
throw new NotFoundException(__('Invalid object template id.'));
}
$params = array(
'recursive' => -1,
'contain' => array(

View File

@ -42,7 +42,7 @@ class ObjectsController extends AppController
)
));
$event = $this->MispObject->Event->find('first', $eventFindParams);
if (empty($event) || (!$this->_isSiteAdmin() && $event['Event']['orgc_id'] != $this->Auth->user('org_id'))) {
if (empty($event) || (!$this->_isSiteAdmin() && $event['Event']['orgc_id'] != $this->Auth->user('org_id'))) {
throw new NotFoundException(__('Invalid event.'));
}
$sharing_groups = array();
@ -140,7 +140,7 @@ class ObjectsController extends AppController
throw new NotFoundException(__('Invalid event.'));
}
$event = $this->MispObject->Event->find('first', $eventFindParams);
if (empty($event) || (!$this->_isSiteAdmin() && $event['Event']['orgc_id'] != $this->Auth->user('org_id'))) {
if (empty($event) || (!$this->_isSiteAdmin() && $event['Event']['orgc_id'] != $this->Auth->user('org_id'))) {
throw new NotFoundException(__('Invalid event.'));
}
$eventId = $event['Event']['id'];
@ -194,6 +194,7 @@ class ObjectsController extends AppController
$error = 'Could not save the object as no attributes were set.';
} else {
foreach ($object['Attribute'] as $k => $attribute) {
unset($object['Attribute'][$k]['id']);
$object['Attribute'][$k]['event_id'] = $eventId;
$this->MispObject->Event->Attribute->set($attribute);
if (!$this->MispObject->Event->Attribute->validates()) {
@ -220,6 +221,7 @@ class ObjectsController extends AppController
$error = $this->MispObject->ObjectTemplate->checkTemplateConformity($template, $object);
}
if ($error === true) {
unset($object['Object']['id']);
$result = $this->MispObject->saveObject($object, $eventId, $template, $this->Auth->user(), $errorBehaviour = 'halt');
if (is_numeric($result)) {
$this->MispObject->Event->unpublishEvent($eventId);
@ -234,6 +236,10 @@ class ObjectsController extends AppController
'conditions' => array('Object.id' => $result),
'contain' => array('Attribute')
));
if (!empty($object)) {
$object['Object']['Attribute'] = $object['Attribute'];
unset($object['Attribute']);
}
return $this->RestResponse->viewData($object, $this->response->type());
} else {
return $this->RestResponse->saveFailResponse('Objects', 'add', false, $error, $this->response->type());
@ -324,7 +330,7 @@ class ObjectsController extends AppController
);
$event = $this->MispObject->Event->find('first', $eventFindParams);
if (empty($event) || (!$this->_isSiteAdmin() && $event['Event']['orgc_id'] != $this->Auth->user('org_id'))) {
if (empty($event) || (!$this->_isSiteAdmin() && $event['Event']['orgc_id'] != $this->Auth->user('org_id'))) {
throw new NotFoundException(__('Invalid object.'));
}
if (!$this->_isRest()) {
@ -370,6 +376,10 @@ class ObjectsController extends AppController
'conditions' => array('Object.id' => $id),
'contain' => array('Attribute')
));
if (!empty($objectToSave)) {
$objectToSave['Object']['Attribute'] = $objectToSave['Attribute'];
unset($objectToSave['Attribute']);
}
$this->MispObject->Event->unpublishEvent($object['Object']['event_id']);
return $this->RestResponse->viewData($objectToSave, $this->response->type());
} else {

View File

@ -19,7 +19,7 @@ class OrgBlacklistsController extends AppController
public $paginate = array(
'limit' => 60,
'maxLimit' => 9999, // LATER we will bump here on a problem once we have more than 9999 events <- no we won't, this is the max a user van view/page.
'maxLimit' => 9999, // LATER we will bump here on a problem once we have more than 9999 events <- no we won't, this is the max a user van view/page.
'order' => array(
'OrgBlacklist.created' => 'DESC'
),

View File

@ -15,10 +15,10 @@ class OrganisationsController extends AppController
public $paginate = array(
'limit' => 60,
'maxLimit' => 9999, // LATER we will bump here on a problem once we have more than 9999 events <- no we won't, this is the max a user van view/page.
'maxLimit' => 9999, // LATER we will bump here on a problem once we have more than 9999 events <- no we won't, this is the max a user van view/page.
'order' => 'LOWER(Organisation.name)'
//'order' => array(
// 'Organisation.name' => 'ASC'
// 'Organisation.name' => 'ASC'
//),
);
@ -171,8 +171,8 @@ class OrganisationsController extends AppController
} else {
$temp['Organisation'][$field] = $existingOrg['Organisation'][$field];
}
$this->request->data = $temp;
}
$this->request->data = $temp;
}
$this->request->data['Organisation']['id'] = $id;
if ($this->Organisation->save($this->request->data)) {

View File

@ -4,7 +4,7 @@ App::uses('Xml', 'Utility');
class ServersController extends AppController
{
public $components = array('Security' ,'RequestHandler'); // XXX ACL component
public $components = array('Security' ,'RequestHandler'); // XXX ACL component
public $paginate = array(
'limit' => 60,
@ -31,7 +31,7 @@ class ServersController extends AppController
public function beforeFilter()
{
parent::beforeFilter();
$this->Security->unlockedActions[] = 'getApiInfo';
$this->Security->unlockedActions[] = 'getApiInfo';
// permit reuse of CSRF tokens on some pages.
switch ($this->request->params['action']) {
case 'push':
@ -51,27 +51,37 @@ class ServersController extends AppController
$this->paginate['conditions'] = array('Server.org_id LIKE' => $this->Auth->user('org_id'));
}
if ($this->_isRest()) {
$params = array(
'recursive' => -1,
'contain' => array(
'Organisation' => array('Organisation.id', 'Organisation.name', 'Organisation.uuid', 'Organisation.nationality', 'Organisation.sector', 'Organisation.type'),
'RemoteOrg' => array('RemoteOrg.id', 'RemoteOrg.name', 'RemoteOrg.uuid', 'RemoteOrg.nationality', 'RemoteOrg.sector', 'RemoteOrg.type'),
)
);
$servers = $this->Server->find('all', $params);
return $this->RestResponse->viewData($servers, $this->response->type());
} else {
$this->set('servers', $this->paginate());
$collection = array();
$collection['orgs'] = $this->Server->Organisation->find('list', array(
'fields' => array('id', 'name'),
));
$this->loadModel('Tag');
$collection['tags'] = $this->Tag->find('list', array(
'fields' => array('id', 'name'),
));
$this->set('collection', $collection);
}
$params = array(
'recursive' => -1,
'contain' => array(
'User' => array(
'fields' => array('User.id', 'User.org_id', 'User.email'),
),
'Organisation' => array(
'fields' => array('Organisation.id', 'Organisation.name', 'Organisation.uuid', 'Organisation.nationality', 'Organisation.sector', 'Organisation.type'),
),
'RemoteOrg' => array(
'fields' => array('RemoteOrg.id', 'RemoteOrg.name', 'RemoteOrg.uuid', 'RemoteOrg.nationality', 'RemoteOrg.sector', 'RemoteOrg.type'),
),
),
);
$servers = $this->Server->find('all', $params);
$servers = $this->Server->attachServerCacheTimestamps($servers);
return $this->RestResponse->viewData($servers, $this->response->type());
} else {
$servers = $this->paginate();
$servers = $this->Server->attachServerCacheTimestamps($servers);
$this->set('servers', $servers);
$collection = array();
$collection['orgs'] = $this->Server->Organisation->find('list', array(
'fields' => array('id', 'name'),
));
$this->loadModel('Tag');
$collection['tags'] = $this->Tag->find('list', array(
'fields' => array('id', 'name'),
));
$this->set('collection', $collection);
}
}
public function previewIndex($id)
@ -236,6 +246,7 @@ class ServersController extends AppController
$defaults = array(
'push' => 0,
'pull' => 0,
'caching_enabled' => 0,
'json' => '[]',
'push_rules' => '[]',
'pull_rules' => '[]',
@ -422,7 +433,7 @@ class ServersController extends AppController
}
if (!$fail) {
// say what fields are to be updated
$fieldList = array('id', 'url', 'push', 'pull', 'unpublish_event', 'publish_without_email', 'remote_org_id', 'name' ,'self_signed', 'cert_file', 'client_cert_file', 'push_rules', 'pull_rules', 'internal', 'skip_proxy');
$fieldList = array('id', 'url', 'push', 'pull', 'caching_enabled', 'unpublish_event', 'publish_without_email', 'remote_org_id', 'name' ,'self_signed', 'cert_file', 'client_cert_file', 'push_rules', 'pull_rules', 'internal', 'skip_proxy');
$this->request->data['Server']['id'] = $id;
if (isset($this->request->data['Server']['authkey']) && "" != $this->request->data['Server']['authkey']) {
$fieldList[] = 'authkey';
@ -563,6 +574,7 @@ class ServersController extends AppController
}
$this->set('allTags', $allTags);
$this->set('server', $s);
$this->set('id', $id);
$this->set('host_org_id', Configure::read('MISP.host_org_id'));
}
}
@ -591,9 +603,9 @@ class ServersController extends AppController
/**
* Pull one or more events with attributes from a remote instance.
* Set $technique to
* full - download everything
* incremental - only new events
* <int> - specific id of the event to pull
* full - download everything
* incremental - only new events
* <int> - specific id of the event to pull
*/
public function pull($id = null, $technique='full')
{
@ -602,66 +614,66 @@ class ServersController extends AppController
throw new NotFoundException(__('Invalid server'));
}
$s = $this->Server->read(null, $id);
$error = false;
$error = false;
if (!$this->_isSiteAdmin() && !($s['Server']['org_id'] == $this->Auth->user('org_id') && $this->_isAdmin())) {
throw new MethodNotAllowedException(__('You are not authorised to do that.'));
throw new MethodNotAllowedException(__('You are not authorised to do that.'));
}
$this->Server->id = $id;
if (!$this->Server->exists()) {
throw new NotFoundException(__('Invalid server'));
}
if (false == $this->Server->data['Server']['pull'] && ($technique == 'full' || $technique == 'incremental')) {
$error = __('Pull setting not enabled for this server.');
$error = __('Pull setting not enabled for this server.');
}
if (empty($error)) {
if (!Configure::read('MISP.background_jobs')) {
$result = $this->Server->pull($this->Auth->user(), $id, $technique, $s);
if (is_array($result)) {
$success = sprintf(__('Pull completed. %s events pulled, %s events could not be pulled, %s proposals pulled.', count($result[0]), count($result[1]), count($result[2])));
} else {
$error = $result;
}
$this->set('successes', $result[0]);
$this->set('fails', $result[1]);
$this->set('pulledProposals', $result[2]);
} else {
$this->loadModel('Job');
$this->Job->create();
$data = array(
'worker' => 'default',
'job_type' => 'pull',
'job_input' => 'Server: ' . $id,
'status' => 0,
'retries' => 0,
'org' => $this->Auth->user('Organisation')['name'],
'message' => 'Pulling.',
);
$this->Job->save($data);
$jobId = $this->Job->id;
$process_id = CakeResque::enqueue(
'default',
'ServerShell',
array('pull', $this->Auth->user('id'), $id, $technique, $jobId)
);
$this->Job->saveField('process_id', $process_id);
$success = sprintf(__('Pull queued for background execution. Job ID: %s'), $jobId);
}
}
if ($this->_isRest()) {
if (!empty($error)) {
return $this->RestResponse->saveFailResponse('Servers', 'pull', false, $error, $this->response->type());
} else {
return $this->RestResponse->saveSuccessResponse('Servers', 'pull', $success, $this->response->type());
}
} else {
if (!empty($error)) {
$this->Flash->error($error);
$this->redirect(array('action' => 'index'));
} else {
$this->Flash->success($success);
$this->redirect($this->referer());
}
}
if (empty($error)) {
if (!Configure::read('MISP.background_jobs')) {
$result = $this->Server->pull($this->Auth->user(), $id, $technique, $s);
if (is_array($result)) {
$success = sprintf(__('Pull completed. %s events pulled, %s events could not be pulled, %s proposals pulled.', count($result[0]), count($result[1]), count($result[2])));
} else {
$error = $result;
}
$this->set('successes', $result[0]);
$this->set('fails', $result[1]);
$this->set('pulledProposals', $result[2]);
} else {
$this->loadModel('Job');
$this->Job->create();
$data = array(
'worker' => 'default',
'job_type' => 'pull',
'job_input' => 'Server: ' . $id,
'status' => 0,
'retries' => 0,
'org' => $this->Auth->user('Organisation')['name'],
'message' => 'Pulling.',
);
$this->Job->save($data);
$jobId = $this->Job->id;
$process_id = CakeResque::enqueue(
'default',
'ServerShell',
array('pull', $this->Auth->user('id'), $id, $technique, $jobId)
);
$this->Job->saveField('process_id', $process_id);
$success = sprintf(__('Pull queued for background execution. Job ID: %s'), $jobId);
}
}
if ($this->_isRest()) {
if (!empty($error)) {
return $this->RestResponse->saveFailResponse('Servers', 'pull', false, $error, $this->response->type());
} else {
return $this->RestResponse->saveSuccessResponse('Servers', 'pull', $success, $this->response->type());
}
} else {
if (!empty($error)) {
$this->Flash->error($error);
$this->redirect(array('action' => 'index'));
} else {
$this->Flash->success($success);
$this->redirect($this->referer());
}
}
}
public function push($id = null, $technique=false)
@ -681,24 +693,24 @@ class ServersController extends AppController
$HttpSocket = $syncTool->setupHttpSocket($server);
$result = $this->Server->push($id, $technique, false, $HttpSocket, $this->Auth->user());
if ($result === false) {
$error = __('The remote server is too outdated to initiate a push towards it. Please notify the hosting organisation of the remote instance.');
} else if (!is_array($result)) {
$error = $result;
}
if (!empty($error)) {
if ($this->_isRest()) {
return $this->RestResponse->saveFailResponse('Servers', 'push', false, $error, $this->response->type());
} else {
$this->Flash->info($error);
$this->redirect(array('action' => 'index'));
}
}
if ($this->_isRest()) {
return $this->RestResponse->saveSuccessResponse('Servers', 'push', array(sprintf(__('Push complete. %s events pushed, %s events could not be pushed.', $result[0], $result[1]))), $this->response->type());
} else {
$this->set('successes', $result[0]);
$this->set('fails', $result[1]);
}
$error = __('The remote server is too outdated to initiate a push towards it. Please notify the hosting organisation of the remote instance.');
} elseif (!is_array($result)) {
$error = $result;
}
if (!empty($error)) {
if ($this->_isRest()) {
return $this->RestResponse->saveFailResponse('Servers', 'push', false, $error, $this->response->type());
} else {
$this->Flash->info($error);
$this->redirect(array('action' => 'index'));
}
}
if ($this->_isRest()) {
return $this->RestResponse->saveSuccessResponse('Servers', 'push', array(sprintf(__('Push complete. %s events pushed, %s events could not be pushed.', $result[0], $result[1]))), $this->response->type());
} else {
$this->set('successes', $result[0]);
$this->set('fails', $result[1]);
}
} else {
$this->loadModel('Job');
$this->Job->create();
@ -719,10 +731,10 @@ class ServersController extends AppController
array('push', $this->Auth->user('id'), $id, $jobId)
);
$this->Job->saveField('process_id', $process_id);
$message = sprintf(__('Push queued for background execution. Job ID: %s'), $jobId);
if ($this->_isRest()) {
return $this->RestResponse->saveSuccessResponse('Servers', 'push', $message, $this->response->type());
}
$message = sprintf(__('Push queued for background execution. Job ID: %s'), $jobId);
if ($this->_isRest()) {
return $this->RestResponse->saveSuccessResponse('Servers', 'push', $message, $this->response->type());
}
$this->Flash->success($message);
$this->redirect(array('action' => 'index'));
}
@ -751,7 +763,7 @@ class ServersController extends AppController
}
$file = new File($server['Server'][$subm]['name']);
$ext = $file->ext();
if (($ext != 'pem') || !$server['Server'][$subm]['size'] > 0) {
if (!$server['Server'][$subm]['size'] > 0) {
$this->Flash->error('Incorrect extension or empty file.');
$this->redirect(array('action' => 'index'));
}
@ -821,6 +833,11 @@ class ServersController extends AppController
return $this->Server->loadAvailableLanguages();
}
private function __loadTagCollections()
{
return $this->Server->loadTagCollections($this->Auth->user());
}
private function __loadLocalOrgs()
{
$this->loadModel('Organisation');
@ -852,10 +869,11 @@ class ServersController extends AppController
$zmqErrors = array(0 => 'OK', 1 => 'not enabled (so not tested)', 2 => 'Python ZeroMQ library not installed correctly.', 3 => 'ZeroMQ script not running.');
$stixOperational = array(0 => 'Some of the libraries related to STIX are not installed. Make sure that all libraries listed below are correctly installed.', 1 => 'OK');
$stixVersion = array(0 => 'Incorrect STIX version installed, found $current, expecting $expected', 1 => 'OK');
$stix2Version = array(0 => 'Incorrect STIX2 version installed, found $current, expecting $expected', 1 => 'OK');
$cyboxVersion = array(0 => 'Incorrect CyBox version installed, found $current, expecting $expected', 1 => 'OK');
$mixboxVersion = array(0 => 'Incorrect mixbox version installed, found $current, expecting $expected', 1 => 'OK');
$maecVersion = array(0 => 'Incorrect maec version installed, found $current, expecting $expected', 1 => 'OK');
$pymispVersion = array(0 => 'Incorrect pymisp version installed, found $current, expecting $expected', 1 => 'OK');
$pymispVersion = array(0 => 'Incorrect PyMISP version installed, found $current, expecting $expected', 1 => 'OK');
$sessionErrors = array(0 => 'OK', 1 => 'High', 2 => 'Alternative setting used', 3 => 'Test failed');
$moduleErrors = array(0 => 'OK', 1 => 'System not enabled', 2 => 'No modules found');
@ -975,7 +993,7 @@ class ServersController extends AppController
}
// check if the STIX and Cybox libraries are working and the correct version using the test script stixtest.py
$stix = $this->Server->stixDiagnostics($diagnostic_errors, $stixVersion, $cyboxVersion, $mixboxVersion, $maecVersion, $pymispVersion);
$stix = $this->Server->stixDiagnostics($diagnostic_errors, $stixVersion, $cyboxVersion, $mixboxVersion, $maecVersion, $stix2Version, $pymispVersion);
// if GnuPG is set up in the settings, try to encrypt a test message
$gpgStatus = $this->Server->gpgDiagnostics($diagnostic_errors);
@ -996,7 +1014,7 @@ class ServersController extends AppController
$sessionStatus = $this->Server->sessionDiagnostics($diagnostic_errors, $sessionCount);
$this->set('sessionCount', $sessionCount);
$additionalViewVars = array('gpgStatus', 'sessionErrors', 'proxyStatus', 'sessionStatus', 'zmqStatus', 'stixVersion', 'cyboxVersion', 'mixboxVersion', 'maecVersion', 'pymispVersion', 'moduleStatus', 'gpgErrors', 'proxyErrors', 'zmqErrors', 'stixOperational', 'stix', 'moduleErrors', 'moduleTypes');
$additionalViewVars = array('gpgStatus', 'sessionErrors', 'proxyStatus', 'sessionStatus', 'zmqStatus', 'stixVersion', 'cyboxVersion', 'mixboxVersion', 'maecVersion', 'stix2Version', 'pymispVersion', 'moduleStatus', 'gpgErrors', 'proxyErrors', 'zmqErrors', 'stixOperational', 'stix', 'moduleErrors', 'moduleTypes');
}
// check whether the files are writeable
$writeableDirs = $this->Server->writeableDirsDiagnostics($diagnostic_errors);
@ -1119,67 +1137,39 @@ class ServersController extends AppController
}
}
public function serverSettingsEdit($setting, $id = false, $forceSave = false)
public function serverSettingsEdit($setting_name, $id = false, $forceSave = false)
{
// invalidate config.php from php opcode cache
if (function_exists('opcache_reset')) {
opcache_reset();
}
if (!$this->_isSiteAdmin()) {
throw new MethodNotAllowedException();
}
if (!isset($setting) || !isset($id)) {
if (!isset($setting_name) || !isset($id)) {
throw new MethodNotAllowedException();
}
$this->set('id', $id);
if (strpos($setting, 'Plugin.Enrichment') !== false || strpos($setting, 'Plugin.Import') !== false || strpos($setting, 'Plugin.Export') !== false || strpos($setting, 'Plugin.Cortex') !== false) {
$serverSettings = $this->Server->getCurrentServerSettings();
} else {
$serverSettings = $this->Server->serverSettings;
}
$relevantSettings = (array_intersect_key(Configure::read(), $serverSettings));
$found = null;
foreach ($serverSettings as $k => $s) {
if (isset($s['branch'])) {
foreach ($s as $ek => $es) {
if ($ek != 'branch') {
if ($setting == $k . '.' . $ek) {
$found = $es;
continue 2;
}
}
}
} else {
if ($setting == $k) {
$found = $s;
continue;
}
}
}
$setting = $this->Server->getSettingData($setting_name);
if ($this->request->is('get')) {
if ($found != null) {
$value = Configure::read($setting);
if ($setting != null) {
$value = Configure::read($setting['name']);
if ($value) {
$found['value'] = $value;
$setting['value'] = $value;
}
$found['setting'] = $setting;
$setting['setting'] = $setting['name'];
}
if (isset($found['optionsSource']) && !empty($found['optionsSource'])) {
$found['options'] = $this->{'__load' . $found['optionsSource']}();
if (isset($setting['optionsSource']) && !empty($setting['optionsSource'])) {
$setting['options'] = $this->{'__load' . $setting['optionsSource']}();
}
$subGroup = 'general';
$subGroup = explode('.', $setting);
$subGroup = explode('.', $setting['name']);
if ($subGroup[0] === 'Plugin') {
$subGroup = explode('_', $subGroup[1])[0];
} else {
$subGroup = 'general';
}
if ($this->_isRest()) {
return $this->RestResponse->viewData(array($setting => $found['value']));
return $this->RestResponse->viewData(array($setting['name'] => $setting['value']));
} else {
$this->set('subGroup', $subGroup);
$this->set('setting', $found);
$this->set('setting', $setting);
$this->render('ajax/server_settings_edit');
}
}
@ -1211,7 +1201,7 @@ class ServersController extends AppController
'action' => 'serverSettingsEdit',
'user_id' => $this->Auth->user('id'),
'title' => 'Server setting issue',
'change' => 'There was an issue witch changing ' . $setting . ' to ' . $this->request->data['Server']['value'] . '. The error message returned is: app/Config.config.php is not writeable to the apache user. No changes were made.',
'change' => 'There was an issue witch changing ' . $setting['name'] . ' to ' . $this->request->data['Server']['value'] . '. The error message returned is: app/Config.config.php is not writeable to the apache user. No changes were made.',
));
if ($this->_isRest()) {
return $this->RestResponse->saveFailResponse('Servers', 'serverSettingsEdit', false, 'app/Config.config.php is not writeable to the apache user.', $this->response->type());
@ -1219,92 +1209,19 @@ class ServersController extends AppController
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'app/Config.config.php is not writeable to the apache user.')), 'status'=>200, 'type' => 'json'));
}
}
if (isset($found['beforeHook'])) {
$beforeResult = call_user_func_array(array($this->Server, $found['beforeHook']), array($setting, $this->request->data['Server']['value']));
if ($beforeResult !== true) {
$this->Log->create();
$result = $this->Log->save(array(
'org' => $this->Auth->user('Organisation')['name'],
'model' => 'Server',
'model_id' => 0,
'email' => $this->Auth->user('email'),
'action' => 'serverSettingsEdit',
'user_id' => $this->Auth->user('id'),
'title' => 'Server setting issue',
'change' => 'There was an issue witch changing ' . $setting . ' to ' . $this->request->data['Server']['value'] . '. The error message returned is: ' . $beforeResult . 'No changes were made.',
));
if ($this->_isRest) {
return $this->RestResponse->saveFailResponse('Servers', 'serverSettingsEdit', false, $beforeResult, $this->response->type());
} else {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => $beforeResult)), 'status'=>200, 'type' => 'json'));
}
}
}
$this->request->data['Server']['value'] = trim($this->request->data['Server']['value']);
if ($found['type'] == 'boolean') {
$this->request->data['Server']['value'] = ($this->request->data['Server']['value'] ? true : false);
}
if ($found['type'] == 'numeric') {
$this->request->data['Server']['value'] = intval($this->request->data['Server']['value']);
}
if (!empty($leafValue['test'])) {
$testResult = $this->Server->{$found['test']}($this->request->data['Server']['value']);
} else {
$testResult = true; # No test defined for this setting: cannot fail
}
if (!$forceSave && $testResult !== true) {
if ($testResult === false) {
$errorMessage = $found['errorMessage'];
} else {
$errorMessage = $testResult;
}
if ($this->_isRest) {
return $this->RestResponse->saveFailResponse('Servers', 'serverSettingsEdit', false, $errorMessage, $this->response->type());
} else {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => $errorMessage)), 'status'=>200, 'type' => 'json'));
}
} else {
$oldValue = Configure::read($setting);
$this->Server->serverSettingsSaveValue($setting, $this->request->data['Server']['value']);
$this->Log->create();
$result = $this->Log->save(array(
'org' => $this->Auth->user('Organisation')['name'],
'model' => 'Server',
'model_id' => 0,
'email' => $this->Auth->user('email'),
'action' => 'serverSettingsEdit',
'user_id' => $this->Auth->user('id'),
'title' => 'Server setting changed',
'change' => $setting . ' (' . $oldValue . ') => (' . $this->request->data['Server']['value'] . ')',
));
// execute after hook
if (isset($found['afterHook'])) {
$afterResult = call_user_func_array(array($this->Server, $found['afterHook']), array($setting, $this->request->data['Server']['value']));
if ($afterResult !== true) {
$this->Log->create();
$result = $this->Log->save(array(
'org' => $this->Auth->user('Organisation')['name'],
'model' => 'Server',
'model_id' => 0,
'email' => $this->Auth->user('email'),
'action' => 'serverSettingsEdit',
'user_id' => $this->Auth->user('id'),
'title' => 'Server setting issue',
'change' => 'There was an issue after setting a new setting. The error message returned is: ' . $afterResult,
));
if ($this->_isRest) {
return $this->RestResponse->saveFailResponse('Servers', 'serverSettingsEdit', false, $afterResult, $this->response->type());
} else {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => $afterResult)), 'status'=>200, 'type' => 'json'));
}
}
}
if ($this->_isRest) {
$result = $this->Server->serverSettingsEditValue($this->Auth->user(), $setting, $this->request->data['Server']['value'], $forceSave);
if ($result === true) {
if ($this->_isRest()) {
return $this->RestResponse->saveSuccessResponse('Servers', 'serverSettingsEdit', false, $this->response->type(), 'Field updated');
} else {
return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'success' => 'Field updated.')), 'status'=>200, 'type' => 'json'));
}
} else {
if ($this->_isRest) {
return $this->RestResponse->saveFailResponse('Servers', 'serverSettingsEdit', false, $result, $this->response->type());
} else {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => $result)), 'status'=>200, 'type' => 'json'));
}
}
}
}
@ -1614,17 +1531,18 @@ class ServersController extends AppController
public function rest()
{
$allValidApis = $this->RestResponse->getAllApis($this->Auth->user(), $this);
$allValidApis = $this->RestResponse->getAllApis($this->Auth->user());
$allValidApisFieldsContraint = $this->RestResponse->getAllApisFieldsConstraint($this->Auth->user());
if ($this->request->is('post')) {
$request = $this->request->data;
if (!empty($request['Server'])) {
$request = $this->request->data['Server'];
}
$curl = '';
$python = '';
$curl = '';
$python = '';
$result = $this->__doRestQuery($request, $curl, $python);
$this->set('curl', $curl);
$this->set('python', $python);
$this->set('curl', $curl);
$this->set('python', $python);
if (!$result) {
$this->Flash->error('Something went wrong. Make sure you set the http method, body (when sending POST requests) and URL correctly.');
} else {
@ -1636,7 +1554,14 @@ class ServersController extends AppController
'Accept: application/json' . PHP_EOL .
'Content-Type: application/json';
$this->set('header', $header);
$this->set('allValidApis', $allValidApis);
$this->set('allValidApis', $allValidApis);
// formating for optgroup
$allValidApisFormated = array();
foreach ($allValidApis as $endpoint_url => $endpoint_data) {
$allValidApisFormated[$endpoint_data['controller']][] = array('url' => $endpoint_url, 'action' => $endpoint_data['action']);
}
$this->set('allValidApisFormated', $allValidApisFormated);
$this->set('allValidApisFieldsContraint', $allValidApisFieldsContraint);
}
private function __doRestQuery($request, &$curl = false, &$python = false)
@ -1644,20 +1569,20 @@ class ServersController extends AppController
App::uses('SyncTool', 'Tools');
$params = array();
if (!empty($request['url'])) {
if (empty($request['use_full_path'])) {
$path = preg_replace('#^(://|[^/?])+#', '', $request['url']);
$url = Configure::read('MISP.baseurl') . $path;
unset($request['url']);
} else {
$url = $request['url'];
}
if (empty($request['use_full_path'])) {
$path = preg_replace('#^(://|[^/?])+#', '', $request['url']);
$url = Configure::read('MISP.baseurl') . $path;
unset($request['url']);
} else {
$url = $request['url'];
}
} else {
throw new InvalidArgumentException('Url not set.');
}
if (!empty($request['skip_ssl_validation'])) {
$params['ssl_verify_peer'] = false;
}
$params['timeout'] = 300;
if (!empty($request['skip_ssl_validation'])) {
$params['ssl_verify_peer'] = false;
}
$params['timeout'] = 300;
App::uses('HttpSocket', 'Network/Http');
$HttpSocket = new HttpSocket($params);
$view_data = array();
@ -1678,24 +1603,24 @@ class ServersController extends AppController
!empty($request['method']) &&
$request['method'] === 'GET'
) {
if ($curl !== false) {
$curl = $this->__generateCurlQuery('get', $request, $url);
}
if ($python !== false) {
$python = $this->__generatePythonScript($request, $url);
}
if ($curl !== false) {
$curl = $this->__generateCurlQuery('get', $request, $url);
}
if ($python !== false) {
$python = $this->__generatePythonScript($request, $url);
}
$response = $HttpSocket->get($url, false, array('header' => $request['header']));
} elseif (
!empty($request['method']) &&
$request['method'] === 'POST' &&
!empty($request['body'])
) {
if ($curl !== false) {
$curl = $this->__generateCurlQuery('post', $request, $url);
}
if ($python !== false) {
$python = $this->__generatePythonScript($request, $url);
}
if ($curl !== false) {
$curl = $this->__generateCurlQuery('post', $request, $url);
}
if ($python !== false) {
$python = $this->__generatePythonScript($request, $url);
}
$response = $HttpSocket->post($url, $request['body'], array('header' => $request['header']));
} else {
return false;
@ -1716,28 +1641,28 @@ class ServersController extends AppController
return $view_data;
}
private function __generatePythonScript($request, $url)
{
$slashCounter = 0;
$baseurl = '';
$relative = '';
$verifyCert = ($url[4] === 's') ? 'True' : 'False';
for ($i = 0; $i < strlen($url); $i++) {
//foreach ($url as $url[$i]) {
if ($url[$i] === '/') {
$slashCounter += 1;
if ($slashCounter == 3) {
continue;
}
}
if ($slashCounter < 3) {
$baseurl .= $url[$i];
} else {
$relative .= $url[$i];
}
}
$python_script =
sprintf(
private function __generatePythonScript($request, $url)
{
$slashCounter = 0;
$baseurl = '';
$relative = '';
$verifyCert = ($url[4] === 's') ? 'True' : 'False';
for ($i = 0; $i < strlen($url); $i++) {
//foreach ($url as $url[$i]) {
if ($url[$i] === '/') {
$slashCounter += 1;
if ($slashCounter == 3) {
continue;
}
}
if ($slashCounter < 3) {
$baseurl .= $url[$i];
} else {
$relative .= $url[$i];
}
}
$python_script =
sprintf(
'misp_url = \'%s\'
misp_key = \'%s\'
misp_verifycert = %s
@ -1749,63 +1674,102 @@ from pymisp import PyMISP
misp = PyMISP(misp_url, misp_key, misp_verifycert)
misp.direct_call(relative_path, body)
',
$baseurl,
$request['header']['Authorization'],
$verifyCert,
$relative,
(empty($request['body']) ? 'Null' : '\'' . $request['body'] . '\'')
);
return $python_script;
}
$baseurl,
$request['header']['Authorization'],
$verifyCert,
$relative,
(empty($request['body']) ? 'Null' : '\'' . $request['body'] . '\'')
);
return $python_script;
}
private function __generateCurlQuery($type, $request, $url)
{
if ($type === 'get') {
$curl = sprintf(
'curl \%s -H "Authorization: %s" \%s -H "Accept: %s" \%s -H "Content-type: %s" \%s %s',
PHP_EOL,
$request['header']['Authorization'],
PHP_EOL,
$request['header']['Accept'],
PHP_EOL,
$request['header']['Content-Type'],
PHP_EOL,
$url
);
} else {
$curl = sprintf(
'curl \%s -d \'%s\' \%s -H "Authorization: %s" \%s -H "Accept: %s" \%s -H "Content-type: %s" \%s -X POST %s',
PHP_EOL,
json_encode(json_decode($request['body']), true),
PHP_EOL,
$request['header']['Authorization'],
PHP_EOL,
$request['header']['Accept'],
PHP_EOL,
$request['header']['Content-Type'],
PHP_EOL,
$url
);
}
return $curl;
}
public function getApiInfo() {
$relative_path = $this->request->data['url'];
$result = $this->RestResponse->getApiInfo($relative_path);
if ($this->_isRest()) {
return $result;
} else {
$result = json_decode($result, true);
if (empty($result)) {
return $this->RestResponse->viewData('&nbsp;', $this->response->type());
}
$this->layout = false;
$this->autoRender = false;
$this->set('api_info', $result);
$this->render('ajax/get_api_info');
}
}
private function __generateCurlQuery($type, $request, $url)
{
if ($type === 'get') {
$curl = sprintf(
'curl \%s -H "Authorization: %s" \%s -H "Accept: %s" \%s -H "Content-type: %s" \%s %s',
PHP_EOL,
$request['header']['Authorization'],
PHP_EOL,
$request['header']['Accept'],
PHP_EOL,
$request['header']['Content-Type'],
PHP_EOL,
$url
);
} else {
$curl = sprintf(
'curl \%s -d \'%s\' \%s -H "Authorization: %s" \%s -H "Accept: %s" \%s -H "Content-type: %s" \%s -X POST %s',
PHP_EOL,
json_encode(json_decode($request['body']), true),
PHP_EOL,
$request['header']['Authorization'],
PHP_EOL,
$request['header']['Accept'],
PHP_EOL,
$request['header']['Content-Type'],
PHP_EOL,
$url
);
}
return $curl;
}
public function getApiInfo()
{
$relative_path = $this->request->data['url'];
$result = $this->RestResponse->getApiInfo($relative_path);
if ($this->_isRest()) {
return $result;
} else {
$result = json_decode($result, true);
if (empty($result)) {
return $this->RestResponse->viewData('&nbsp;', $this->response->type());
}
$this->layout = false;
$this->autoRender = false;
$this->set('api_info', $result);
$this->render('ajax/get_api_info');
}
}
public function cache($id = 'all')
{
if (Configure::read('MISP.background_jobs')) {
$this->loadModel('Job');
$this->Job->create();
$data = array(
'worker' => 'default',
'job_type' => 'cache_servers',
'job_input' => intval($id) ? $id : 'all',
'status' => 0,
'retries' => 0,
'org' => $this->Auth->user('Organisation')['name'],
'message' => __('Starting server caching.'),
);
$this->Job->save($data);
$jobId = $this->Job->id;
$process_id = CakeResque::enqueue(
'default',
'ServerShell',
array('cacheServer', $this->Auth->user('id'), $id, $jobId),
true
);
$this->Job->saveField('process_id', $process_id);
$message = 'Server caching job initiated.';
} else {
$result = $this->Server->cacheServerInitiator($this->Auth->user(), $id);
if (!$result) {
$this->Flash->error(__('Caching the servers has failed.'));
$this->redirect(array('action' => 'index'));
}
$message = __('Caching the servers has successfully completed.');
}
if ($this->_isRest()) {
return $this->RestResponse->saveSuccessResponse('Server', 'cache', false, $this->response->type(), $message);
} else {
$this->Flash->info($message);
$this->redirect(array('action' => 'index'));
}
}
}

View File

@ -347,7 +347,7 @@ class ShadowAttributesController extends AppController
if (!$this->_isRest() && (isset($this->request->data['ShadowAttribute']['batch_import']) && $this->request->data['ShadowAttribute']['batch_import'] == 1)) {
// make array from value field
$attributes = explode("\n", $this->request->data['ShadowAttribute']['value']);
$fails = ""; // will be used to keep a list of the lines that failed or succeeded
$fails = ""; // will be used to keep a list of the lines that failed or succeeded
$successes = "";
// TODO loopholes
// the value null value thing
@ -824,7 +824,7 @@ class ShadowAttributesController extends AppController
$id = $temp['Attribute']['id'];
}
$existingAttribute = $this->ShadowAttribute->Event->Attribute->fetchAttributes($this->Auth->user(), array('Attriute.id' => $id));
$existingAttribute = $this->ShadowAttribute->Event->Attribute->fetchAttributes($this->Auth->user(), array('conditions' => array('Attribute.id' => $id)));
if (empty($existingAttribute)) {
throw new NotFoundException(__('Invalid attribute.'));
}
@ -833,6 +833,7 @@ class ShadowAttributesController extends AppController
if (empty($existingAttribute)) {
return new CakeResponse(array('body'=> json_encode(array('false' => true, 'errors' => 'Invalid Attribute.')), 'status'=>200, 'type' => 'json'));
}
$existingAttribute = $existingAttribute[0];
$this->ShadowAttribute->create();
$sa = array(
'old_id' => $existingAttribute['Attribute']['id'],
@ -861,6 +862,7 @@ class ShadowAttributesController extends AppController
if (empty($existingAttribute)) {
throw new NotFoundException(__('Invalid Attribute'));
}
$existingAttribute = $existingAttribute[0];
$this->set('id', $id);
$this->set('event_id', $existingAttribute['Attribute']['event_id']);
$this->render('ajax/deletionProposalConfirmationForm');

View File

@ -17,7 +17,7 @@ class SharingGroupsController extends AppController
public $paginate = array(
'limit' => 60,
'maxLimit' => 9999, // LATER we will bump here on a problem once we have more than 9999 events <- no we won't, this is the max a user van view/page.
'maxLimit' => 9999, // LATER we will bump here on a problem once we have more than 9999 events <- no we won't, this is the max a user van view/page.
'order' => array(
'SharingGroup.name' => 'ASC'
),

View File

@ -12,7 +12,7 @@ class SightingsController extends AppController
public $paginate = array(
'limit' => 60,
'maxLimit' => 9999, // LATER we will bump here on a problem once we have more than 9999 events <- no we won't, this is the max a user van view/page.
'maxLimit' => 9999, // LATER we will bump here on a problem once we have more than 9999 events <- no we won't, this is the max a user van view/page.
'order' => array('Sighting.date_sighting' => 'DESC'),
);
@ -83,9 +83,22 @@ class SightingsController extends AppController
}
} else {
if ($error) {
return $this->RestResponse->saveFailResponse('Sighting', 'add', $id, $error);
$error_message = __('Could not add the Sighting. Reason: ') . $error;
if ($this->_isRest() || $this->response->type() === 'application/json') {
$this->set('message', $error_message);
$this->set('_serialize', array('message'));
} else {
$this->Flash->error($error_message);
$this->redirect($this->referer());
}
} else {
return $this->RestResponse->saveSuccessResponse('Sighting', 'add', $id, false, $result . ' ' . $this->Sighting->type[$type] . (($result == 1) ? '' : 's') . ' successfuly added.');
if ($this->_isRest() || $this->response->type() === 'application/json') {
$this->set('message', __('Sighting added'));
$this->set('_serialize', array('message'));
} else {
$this->Flash->success(__('Sighting added'));
$this->redirect($this->referer());
}
}
}
} else {
@ -133,6 +146,50 @@ class SightingsController extends AppController
$this->render('/Sightings/ajax/advanced');
}
public function quickAdd($id=false, $type=1, $onvalue=false)
{
if (!$this->userRole['perm_modify_org']) {
throw new MethodNotAllowedException(__('You are not authorised to remove sightings data as you don\'t have permission to modify your organisation\'s data.'));
}
if (!$this->request->is('post')) {
$this->loadModel('Attribute');
$attribute = $this->Attribute->fetchAttributes($this->Auth->user(), array('conditions' => array('Attribute.id' => $id, 'Attribute.deleted' => 0), 'flatten' => 1));
if (empty($attribute)) {
throw new MethodNotAllowedException(__('Attribute not found'));
} else {
$attribute = $attribute[0]['Attribute'];
if (!$onvalue) {
$this->set('id', $attribute['id']);
$this->set('tosight', $attribute['id']);
} else {
$this->set('id', '');
$this->set('tosight', $attribute['value']);
}
$this->set('value', $attribute['value']);
$this->set('event_id', $attribute['event_id']);
$this->set('sighting_type', $type);
$this->set('onvalue', $onvalue);
$this->render('ajax/quickAddConfirmationForm');
}
} else {
if (!isset($id)) {
return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'errors' => __('Invalid request.'))), 'status' => 200, 'type' => 'json'));
} else {
if ($onvalue) {
$result = $this->Sighting->add();
} else {
$result = $this->Sighting->add($id);
}
if ($result) {
return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'success' => __('Sighting added.'))), 'status' => 200, 'type' => 'json'));
} else {
return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'errors' => __('Sighting could not be added'))), 'status' => 200, 'type' => 'json'));
}
}
}
}
public function quickDelete($id, $rawId, $context)
{
if (!$this->userRole['perm_modify_org']) {
@ -220,6 +277,42 @@ class SightingsController extends AppController
return $this->RestResponse->viewData($sightings);
}
public function restSearch($context = false)
{
$allowedContext = array(false, 'event', 'attribute');
$paramArray = array('returnFormat', 'id', 'type', 'from', 'to', 'last', 'org_id', 'source', 'includeAttribute', 'includeEvent');
$filterData = array(
'request' => $this->request,
'named_params' => $this->params['named'],
'paramArray' => $paramArray,
'ordered_url_params' => compact($paramArray)
);
$filters = $this->_harvestParameters($filterData, $exception);
// validate context
if (!in_array($context, $allowedContext, true)) {
throw new MethodNotAllowedException(_('Invalid context.'));
}
// ensure that an id is provided if context is set
if ($context !== false && !isset($filters['id'])) {
throw new MethodNotAllowedException(_('An id must be provided if the context is set.'));
}
$filters['context'] = $context;
if (isset($filters['returnFormat'])) {
$returnFormat = $filters['returnFormat'];
}
if ($returnFormat === 'download') {
$returnFormat = 'json';
}
$sightings = $this->Sighting->restSearch($this->Auth->user(), $returnFormat, $filters);
$validFormats = $this->Sighting->validFormats;
$responseType = $validFormats[$returnFormat][0];
return $this->RestResponse->viewData($sightings, $responseType, false, true);
}
public function listSightings($id, $context = 'attribute', $org_id = false)
{
$this->loadModel('Event');

View File

@ -0,0 +1,500 @@
<?php
App::uses('AppController', 'Controller');
class TagCollectionsController extends AppController
{
public $components = array(
'Security',
'AdminCrud',
'RequestHandler'
);
public $paginate = array(
'limit' => 60,
'order' => array(
'TagCollection.name' => 'ASC'
),
'recursive' => -1,
'contain' => array(
'TagCollectionTag' => array(
'Tag'
),
'Organisation' => array(
'fields' => array(
'Organisation.id',
'Organisation.name',
'Organisation.uuid'
)
),
'User' => array(
'fields' => array(
'User.email',
'User.id'
)
)
)
);
public function add()
{
if ($this->request->is('post')) {
$this->TagCollection->create();
if (!isset($this->request->data['TagCollection'])) {
$this->request->data = array('TagCollection' => $this->request->data);
}
$this->request->data['TagCollection']['org_id'] = $this->Auth->user('org_id');
$this->request->data['TagCollection']['user_id'] = $this->Auth->user('id');
if ($this->TagCollection->save($this->request->data)) {
if ($this->_isRest()) {
$tagCollection = $this->TagCollection->find('first', array(
'recursive' => -1,
'conditions' => array('TagCollection.id' => $this->TagCollection->id)
));
return $this->RestResponse->viewData($tagCollection, $this->response->type());
} else {
$this->Flash->success(__('The tag collection has been saved'));
$this->redirect(array('action' => 'index'));
}
} else {
$message = json_encode($this->TagCollection->validationErrors);
if ($this->_isRest()) {
return $this->RestResponse->saveFailResponse('TagCollection', 'add', false, $message, $this->response->type());
} else {
$this->Flash->error(__('The tag collection could not be added. Reason: ') . $message);
}
}
} elseif ($this->_isRest()) {
return $this->RestResponse->describe('TagCollection', 'add', false, $this->response->type());
}
$this->set('action', 'add');
}
public function import()
{
if ($this->request->is('post')) {
if (isset($this->request->data['TagCollection']['json'])) {
$data = json_decode($this->request->data['TagCollection']['json'], true);
} else {
$data = $this->request->data;
}
$results = $this->TagCollection->import($data, $this->Auth->user());
if ($results['successes'] > 0) {
$flashType = 'success';
$message = sprintf(
__('%s new tag collections added.'),
$results['successes']
);
} else {
$flashType = 'info';
$message = 'No new tag_collections to add.';
}
if ($results['fails']) {
$message .= sprintf(
' %s tag collections could not be added (possibly because they already exist)',
$results['fails']
);
}
if ($this->_isRest()) {
return $this->RestResponse->saveSuccessResponse('TagCollections', 'import', false, $this->response->type(), $message);
} else {
$this->Flash->{$flashType}($message);
$this->redirect(array('action' => 'index'));
}
}
}
public function view($id)
{
$conditions = array();
if (!$this->_isSiteAdmin()) {
$conditions = array(
'OR' => array(
'TagCollection.all_orgs' => 1,
'TagCollection.org_id' => $this->Auth->user('org_id')
)
);
$this->paginate['conditions'] = $conditions;
}
$conditions['TagCollection.id'] = $id;
$params = array(
'recursive' => -1,
'contain' => array('TagCollectionTag' => array('Tag'), 'Organisation' => array('fields' => array('id', 'name', 'uuid')), 'User' => array('fields' => array('User.id', 'User.email')))
);
if (!empty($conditions)) {
$params['conditions'] = $conditions;
}
$collection = $this->TagCollection->find('first', $params);
if (empty($collection)) {
throw new NotFoundException('Invalid Tag Collection');
}
$collection = $this->TagCollection->cullBlockedTags($this->Auth->user(), $collection);
$this->loadModel('Event');
$collection = $this->Event->massageTags($collection, 'TagCollection', false, true);
if (!$this->_isSiteAdmin() && $collection['TagCollection']['org_id'] !== $this->Auth->user('org_id')) {
unset($collection['User']);
unset($collection['TagCollection']['user_id']);
}
if (!empty($collection['TagCollectionTag'])) {
foreach ($collection['TagCollectionTag'] as $k => $tct) {
$collection['TagCollectionTag'][$k]['Tag'] = array(
'id' => $tct['Tag']['id'],
'name' => $tct['Tag']['name'],
'colour' => $tct['Tag']['colour']
);
}
}
return $this->RestResponse->viewData($collection, $this->response->type());
}
public function edit($id)
{
$this->TagCollection->id = $id;
if (!$this->TagCollection->exists()) {
throw new NotFoundException(__('Invalid Tag Collection'));
}
$tagCollection = $this->TagCollection->find('first', array(
'conditions' => array('TagCollection.id' => $id),
'recursive' => -1
));
if (!$this->_isSiteAdmin() && $tagCollection['TagCollection']['org_id'] !== $this->Auth->user('org_id')) {
throw new MethodNotAllowedException(__('You don\'t have editing rights on this Tag Collection.'));
}
if ($this->request->is('post') || $this->request->is('put')) {
if (!isset($this->request->data['TagCollection'])) {
$this->request->data = array('TagCollection' => $this->request->data);
}
$this->request->data['TagCollection']['id'] = $tagCollection['TagCollection']['id'];
$this->request->data['TagCollection']['uuid'] = $tagCollection['TagCollection']['uuid'];
if ($this->TagCollection->save($this->request->data)) {
if ($this->_isRest()) {
$tagCollection = $this->TagCollection->find('first', array(
'recursive' => -1,
'conditions' => array('TagCollection.id' => $this->TagCollection->id)
));
return $this->RestResponse->viewData($tagCollection, $this->response->type());
} else {
$this->Flash->success(__('The tag collection has been saved'));
$this->redirect(array('action' => 'index'));
}
} else {
$message = json_encode($this->TagCollection->validationErrors);
if ($this->_isRest()) {
return $this->RestResponse->saveFailResponse('TagCollection', 'add', false, $message, $this->response->type());
} else {
$this->Flash->error(__('The tag collection could not be added. Reason: ') . $message);
}
}
} elseif ($this->_isRest()) {
return $this->RestResponse->describe('TagCollection', 'add', false, $this->response->type());
} else {
$this->request->data = $tagCollection;
}
$this->set('action', 'edit');
$this->render('add');
}
public function delete($id)
{
$tagCollection = $this->TagCollection->fetchTagCollection($this->Auth->user(), array('conditions' => array('TagCollection.id' => $id)));
if (empty($tagCollection)) {
throw new NotFoundException(__('Invalid tag collection.'));
}
$tagCollection = $tagCollection[0];
if ($this->TagCollection->checkAccess($this->Auth->user(), $tagCollection, 'write')) {
$result = $this->TagCollection->delete($id);
if ($result) {
$message = __('Tag collection deleted.');
if ($this->_isRest()) {
return $this->RestResponse->saveSuccessResponse('TagCollections', 'delete', false, $this->response->type(), $message);
} else {
$this->Flash->success($message);
$this->redirect(array('action' => 'index'));
}
} else {
$message = __('Tag collection could not be deleted.');
if ($this->_isRest()) {
return $this->RestResponse->saveFailResponse('TagCollections', 'delete', false, $message, $this->response->type());
} else {
$this->Flash->error($message);
$this->redirect(array('action' => 'index'));
}
}
} else {
throw new NotFoundException(__('You are not allowed to delete that.'));
}
}
public function addTag($id = false, $tag_id = false)
{
if (!$this->request->is('post')) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'You don\'t have permission to do that.')), 'status'=>200, 'type' => 'json'));
}
$rearrangeRules = array(
'request' => false,
'TagCollection' => false,
'tag_id' => 'tag',
'tag_collection_id' => 'tag_collection',
'id' => 'tag_collection'
);
$RearrangeTool = new RequestRearrangeTool();
$this->request->data = $RearrangeTool->rearrangeArray($this->request->data, $rearrangeRules);
if ($id === false) {
$id = $this->request->data['tag_collection'];
}
if ($tag_id === false) {
$tag_id = $this->request->data['tag'];
}
$conditions = array();
if (!$this->_isSiteAdmin()) {
$conditions['Tag.org_id'] = array('0', $this->Auth->user('org_id'));
$conditions['Tag.user_id'] = array('0', $this->Auth->user('id'));
}
if (!is_numeric($tag_id)) {
$tag_ids = json_decode($tag_id);
$tag_lookups = array();
foreach ($tag_ids as $temp) {
if (is_numeric($temp)) {
$tag_lookups['OR']['Tag.id'][] = $temp;
} else {
$tag_lookups['OR']['LOWER(Tag.name) LIKE'][] = strtolower(trim($tag_id));
}
}
if ($tag_ids !== null && is_array($tag_ids)) { // can decode json
$tag_ids = $this->TagCollection->TagCollectionTag->Tag->find('list', array(
'conditions' => array(
'AND' => array(
$conditions,
$tag_lookups
)
),
'fields' => array('Tag.id', 'Tag.id')
));
$tag_id_list = array_values($tag_ids);
if (empty($tag_id_list)) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid Tag(s).')), 'status'=>200, 'type' => 'json'));
}
} else {
$tag = $this->TagCollection->TagCollectionTag->Tag->find('first', array('recursive' => -1, 'conditions' => $conditions));
if (empty($tag)) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid Tag.')), 'status'=>200, 'type' => 'json'));
}
$tag_id = $tag['Tag']['id'];
}
}
$tagCollection = $this->TagCollection->find('first', array(
'recursive' => -1,
'conditions' => array('TagCollection.id' => $id)
));
if (empty($tagCollection)) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid tag collection.')), 'status'=>200, 'type' => 'json'));
}
if (!$this->_isSiteAdmin()) {
if (!$this->userRole['perm_tagger'] || ($this->Auth->user('org_id') !== $tagCollection['TagCollection']['org_id'])) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'You don\'t have permission to do that.')), 'status'=>200, 'type' => 'json'));
}
}
$this->autoRender = false;
$error = false;
$success = false;
if (empty($tag_id_list)) {
$tag_id_list = array($tag_id);
}
foreach ($tag_id_list as $tag_id) {
$this->TagCollection->TagCollectionTag->Tag->id = $tag_id;
if (!$this->TagCollection->TagCollectionTag->Tag->exists()) {
$error = __('Invalid Tag.');
continue;
}
$tag = $this->TagCollection->TagCollectionTag->Tag->find('first', array(
'conditions' => array('Tag.id' => $tag_id),
'recursive' => -1,
'fields' => array('Tag.name')
));
$found = $this->TagCollection->TagCollectionTag->find('first', array(
'conditions' => array(
'tag_collection_id' => $id,
'tag_id' => $tag_id
),
'recursive' => -1,
));
if (!empty($found)) {
$error = __('Tag is already attached to this event.');
continue;
}
$this->TagCollection->TagCollectionTag->create();
if ($this->TagCollection->TagCollectionTag->save(array('tag_collection_id' => $id, 'tag_id' => $tag_id))) {
$log = ClassRegistry::init('Log');
$log->createLogEntry($this->Auth->user(), 'tag', 'TagCollection', $id, 'Attached tag (' . $tag_id . ') "' . $tag['Tag']['name'] . '" to collection (' . $id . ')', 'Event (' . $id . ') tagged as Tag (' . $tag_id . ')');
$success = __('Tag(s) added.');
} else {
$fail = __('Tag(s) could not be added.');
}
}
if ($success) {
return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'success' => $success)), 'status'=>200, 'type' => 'json'));
} elseif (empty($fail)) {
return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'success' => __('All tags are already present, nothing to add.'), 'check_publish' => true)), 'status'=>200, 'type' => 'json'));
} else {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => $fail)), 'status'=>200, 'type' => 'json'));
}
}
public function removeTag($id = false, $tag_id = false)
{
if (!$this->request->is('post')) {
$this->set('id', $id);
$this->set('tag_id', $tag_id);
$this->set('model', 'tag_collection');
$this->layout = 'ajax';
$this->render('/Attributes/ajax/tagRemoveConfirmation');
} else {
$rearrangeRules = array(
'request' => false,
'TagCollection' => false,
'tag_id' => 'tag',
'tag_collection_id' => 'tag_collection',
'id' => 'tag_collection'
);
$RearrangeTool = new RequestRearrangeTool();
$this->request->data = $RearrangeTool->rearrangeArray($this->request->data, $rearrangeRules);
if ($id === false) {
$id = $this->request->data['tag_collection'];
}
if ($tag_id === false) {
$tag_id = $this->request->data['tag'];
}
$tagCollection = $this->TagCollection->find('first', array(
'recursive' => -1,
'conditions' => array(
'TagCollection.id' => $id
),
'contain' => array(
'TagCollectionTag' => array(
'Tag'
)
)
));
if (empty($tagCollection)) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => __('Invalid tag collection.'))), 'status' => 200, 'type' => 'json'));
}
$found = false;
if (!$this->_isSiteAdmin() && $this->Auth->user('org_id') !== $tagCollection['TagCollection']['org_id']) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => __('Insufficient privileges to remove the tag from the collection.'))), 'status' => 200, 'type' => 'json'));
}
foreach ($tagCollection['TagCollectionTag'] as $TagCollectionTag) {
if ((is_numeric($tag_id) && $TagCollectionTag['Tag']['id'] == $tag_id) || $TagCollectionTag['Tag']['name'] === $tag_id) {
$found = true;
$tag = $TagCollectionTag;
$result = $this->TagCollection->TagCollectionTag->delete($TagCollectionTag['id']);
break;
}
}
if (!$found) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => __('Invalid tag or tag not associated with the collection.'))), 'status' => 200, 'type' => 'json'));
}
if (!$result) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => __('Failed to remove tag from the collection.'))), 'status' => 200, 'type' => 'json'));
}
$log = ClassRegistry::init('Log');
$log->createLogEntry($this->Auth->user(), 'tag', 'TagCollection', $id, 'Removed tag (' . $tag['Tag']['id'] . ') "' . $tag['Tag']['name'] . '" from tag collection (' . $id . ')', 'Tag collection (' . $id . ') - untagged Tag (' . $tag_id . ')');
return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'success' => 'Tag removed.')), 'status' => 200));
}
}
public function index()
{
//$this->Auth->user('Role')['perm_site_admin']);
$conditions = array();
if (!$this->_isSiteAdmin()) {
$conditions = array(
'OR' => array(
'TagCollection.all_orgs' => 1,
'TagCollection.org_id' => $this->Auth->user('org_id')
)
);
$this->paginate['conditions'] = $conditions;
}
if ($this->_isRest()) {
$params = array(
'recursive' => -1,
'contain' => array(
'TagCollectionTag' => array(
'Tag'
),
'Organisation' => array(
'fields' => array(
'Organisation.id',
'Organisation.name',
'Organisation.uuid'
)
),
'User' => array(
'fields' => array(
'User.email',
'User.id'
)
)
)
);
if (!empty($conditions)) {
$params['conditions'] = $conditions;
}
$namedParams = array('limit', 'page');
foreach ($namedParams as $namedParam) {
if (!empty($this->params['named'][$namedParam])) {
$params['limit'] = $this->params['named'][$namedParam];
}
}
$list = $this->TagCollection->find('all', $params);
} else {
$list = $this->paginate();
}
$this->loadModel('Event');
foreach ($list as $k => $tag_collection) {
$list[$k] = $this->TagCollection->cullBlockedTags($this->Auth->user(), $tag_collection);
$list[$k] = $this->Event->massageTags($list[$k], 'TagCollection', false, true);
if (!$this->_isSiteAdmin() && $list[$k]['TagCollection']['org_id'] !== $this->Auth->user('org_id')) {
unset($list[$k]['User']);
unset($list[$k]['TagCollection']['user_id']);
}
if (!empty($list[$k]['TagCollectionTag'])) {
foreach ($list[$k]['TagCollectionTag'] as $k2 => $tct) {
$list[$k]['TagCollectionTag'][$k2]['Tag'] = array(
'id' => $tct['Tag']['id'],
'name' => $tct['Tag']['name'],
'colour' => $tct['Tag']['colour']
);
}
}
}
if ($this->_isRest()) {
return $this->RestResponse->viewData($list, $this->response->type());
} else {
$this->set('list', $list);
}
}
public function getRow($id)
{
$params = array(
'recursive' => -1,
'contain' => array('TagCollectionTag' => array('Tag'), 'User', 'Organisation'),
'conditions' => array('TagCollection.id' => $id)
);
$item = $this->TagCollection->find('first', $params);
if (empty($item)) {
throw new NotFoundException('Invalid tag collection.');
}
if (!$this->_isSiteAdmin() && $item['TagCollection']['org_id'] !== $this->Auth->user('org_id')) {
unset($item['User']);
unset($item['TagCollection']['user_id']);
}
$this->loadModel('Event');
$item = $this->Event->massageTags($item, 'TagCollection', false, true);
$this->layout = false;
$this->set('item', $item);
}
}

View File

@ -293,7 +293,7 @@ class TagsController extends AppController
if ($this->Tag->save($this->request->data)) {
if ($this->_isRest()) {
$tag = $this->Tag->find('first', array(
'contidions' => array(
'conditions' => array(
'Tag.id' => $id
),
'recursive' => -1
@ -500,6 +500,13 @@ class TagsController extends AppController
'contain' => array('Tag'),
'fields' => array('Tag.id', 'Tag.colour', 'Tag.name'),
));
$this->loadModel('GalaxyCluster');
$cluster_names = $this->GalaxyCluster->find('list', array('fields' => array('GalaxyCluster.tag_name'), 'group' => array('GalaxyCluster.tag_name', 'GalaxyCluster.id')));
foreach ($attributeTags as $k => $attributeTag) {
if (in_array($attributeTag['Tag']['name'], $cluster_names)) {
unset($attributeTags[$k]);
}
}
$event = $this->Tag->AttributeTag->Attribute->Event->find('first', array(
'recursive' => -1,
'fields' => array('Event.id', 'Event.orgc_id', 'Event.org_id', 'Event.user_id'),
@ -512,6 +519,39 @@ class TagsController extends AppController
$this->render('/Attributes/ajax/ajaxAttributeTags');
}
public function showTagControllerTag($id)
{
$this->loadModel('TagCollection');
$tagCollection = $this->TagCollection->find('first', array(
'recursive' => -1,
'contain' => array('TagCollection'),
'conditions' => array('TagCollection.id' => $id)
));
if (empty($tagCollection) || (!$this->_isSiteAdmin() && $tagCollection['org_id'] !== $this->Auth->user('org_id'))) {
throw new MethodNotAllowedException('Invalid tag_collection.');
}
$this->loadModel('GalaxyCluster');
$cluster_names = $this->GalaxyCluster->find('list', array('fields' => array('GalaxyCluster.tag_name'), 'group' => array('GalaxyCluster.id', 'GalaxyCluster.tag_name')));
$this->helpers[] = 'TextColour';
$tags = $this->TagCollection->TagCollectionTag->find('all', array(
'conditions' => array(
'tag_collection_id' => $id,
'Tag.name !=' => $cluster_names
),
'contain' => array('Tag'),
'fields' => array('Tag.id', 'Tag.colour', 'Tag.name'),
));
$this->set('tags', $tags);
$event = $this->Tag->EventTag->Event->find('first', array(
'recursive' => -1,
'fields' => array('Event.id', 'Event.orgc_id', 'Event.org_id', 'Event.user_id'),
'conditions' => array('Event.id' => $id)
));
$this->set('event', $event);
$this->layout = 'ajax';
$this->render('/Events/ajax/ajaxTags');
}
public function viewTag($id)
{
$tag = $this->Tag->find('first', array(
@ -527,109 +567,206 @@ class TagsController extends AppController
}
public function selectTaxonomy($id, $attributeTag = false)
public function selectTaxonomy($id, $scope = 'event')
{
if (!$this->_isSiteAdmin() && !$this->userRole['perm_tagger']) {
throw new NotFoundException('You don\'t have permission to do that.');
}
$items = array();
$favourites = $this->Tag->FavouriteTag->find('count', array('conditions' => array('FavouriteTag.user_id' => $this->Auth->user('id'))));
if ($favourites) {
$items[] = array(
'name' => __('Favourite Tags'),
'value' => "/tags/selectTag/" . h($id) . "/favourites/" . h($scope)
);
}
if ($scope !== 'tag_collection') {
$items[] = array(
'name' => __('Tag Collections'),
'value' => "/tags/selectTag/" . h($id) . "/collections/" . h($scope)
);
}
$items[] = array(
'name' => __('All Tags'),
'value' => "/tags/selectTag/" . h($id) . "/all/" . h($scope)
);
$this->loadModel('Taxonomy');
$options = $this->Taxonomy->find('list', array('conditions' => array('enabled' => true), 'fields' => array('namespace'), 'order' => array('Taxonomy.namespace ASC')));
foreach ($options as $k => $option) {
$tags = $this->Taxonomy->getTaxonomyTags($k, false, true);
if (empty($tags)) {
unset($options[$k]);
if (!empty($tags)) {
$items[] = array(
'name' => __('Taxonomy Library') . ":" . h($option),
'value' => "/tags/selectTag/" . h($id) . "/" . h($k) . "/" . h($scope)
);
}
}
if ($attributeTag !== false) {
$this->set('attributeTag', true);
}
$this->set('object_id', $id);
$this->set('options', $options);
$this->set('favourites', $favourites);
$this->render('ajax/taxonomy_choice');
$this->set('items', $items);
$this->set('options', array( // set chosen (select picker) options
'select_options' => array(
'multiple' => 0,
),
));
$this->render('/Elements/generic_picker');
}
public function selectTag($id, $taxonomy_id, $attributeTag = false, $filterData = '')
public function selectTag($id, $taxonomy_id, $scope = 'event', $filterData = '')
{
if (!$this->_isSiteAdmin() && !$this->userRole['perm_tagger']) {
throw new NotFoundException('You don\'t have permission to do that.');
}
$this->loadModel('Taxonomy');
$expanded = array();
if ($taxonomy_id === '0') {
$options = $this->Taxonomy->getAllTaxonomyTags(true);
$expanded = $options;
} elseif ($taxonomy_id === 'favourites') {
$conditions = array('FavouriteTag.user_id' => $this->Auth->user('id'));
$tags = $this->Tag->FavouriteTag->find('all', array(
'conditions' => $conditions,
'recursive' => -1,
'contain' => array('Tag.name')
));
foreach ($tags as $tag) {
$options[$tag['FavouriteTag']['tag_id']] = $tag['Tag']['name'];
$expanded = $options;
}
} elseif ($taxonomy_id === 'all') {
$conditions = array('Tag.org_id' => array(0, $this->Auth->user('org_id')));
$conditions = array('Tag.user_id' => array(0, $this->Auth->user('id')));
$conditions['Tag.hide_tag'] = 0;
$options = $this->Tag->find('list', array('fields' => array('Tag.name'), 'conditions' => $conditions));
$expanded = $options;
} else {
$taxonomies = $this->Taxonomy->getTaxonomy($taxonomy_id);
$options = array();
foreach ($taxonomies['entries'] as $entry) {
if (!empty($entry['existing_tag']['Tag'])) {
$options[$entry['existing_tag']['Tag']['id']] = $entry['existing_tag']['Tag']['name'];
$expanded[$entry['existing_tag']['Tag']['id']] = $entry['expanded'];
}
}
}
// Unset all tags that this user cannot use for tagging, determined by the org restriction on tags
if (!$this->_isSiteAdmin()) {
$banned_tags = $this->Tag->find('list', array(
'conditions' => array(
'NOT' => array(
'Tag.org_id' => array(
0,
$this->Auth->user('org_id')
),
'Tag.user_id' => array(
0,
$this->Auth->user('id')
)
)
),
'fields' => array('Tag.id')
));
foreach ($banned_tags as $banned_tag) {
unset($options[$banned_tag]);
unset($expanded[$banned_tag]);
}
}
$hidden_tags = $this->Tag->find('list', array(
'conditions' => array('Tag.hide_tag' => 1),
$banned_tags = $this->Tag->find('list', array(
'conditions' => array(
'NOT' => array(
'Tag.org_id' => array(
0,
$this->Auth->user('org_id')
),
'Tag.user_id' => array(
0,
$this->Auth->user('id')
)
)
),
'fields' => array('Tag.id')
));
foreach ($hidden_tags as $hidden_tag) {
unset($options[$hidden_tag]);
unset($expanded[$hidden_tag]);
}
if ($attributeTag !== false && $attributeTag !== "false") {
$this->set('attributeTag', true);
}
$this->set('object_id', $id);
foreach ($options as $k => $v) {
if (substr($v, 0, strlen('misp-galaxy:')) === 'misp-galaxy:') {
unset($options[$k]);
$this->set('taxonomy_id', $taxonomy_id);
if ($taxonomy_id === 'collections') {
$this->loadModel('TagCollection');
$tagCollections = $this->TagCollection->fetchTagCollection($this->Auth->user());
$tags = array();
$inludedTagListString = array();
$expanded = array();
foreach ($tagCollections as &$tagCollection) {
$tags[$tagCollection['TagCollection']['id']] = $tagCollection['TagCollection'];
$expanded[$tagCollection['TagCollection']['id']] = empty($tagCollection['TagCollection']['description']) ? $tagCollection['TagCollection']['name'] : $tagCollection['TagCollection']['description'];
if (!empty($tagCollection['TagCollectionTag'])) {
$tagList = array();
foreach ($tagCollection['TagCollectionTag'] as $k => $tce) {
if (in_array($tce['tag_id'], $banned_tags)) {
unset($tagCollection['TagCollectionTag'][$k]);
} else {
$tagList[] = $tce['Tag']['name'];
}
$tagCollection['TagCollectionTag'] = array_values($tagCollection['TagCollectionTag']);
}
$tagList = implode(', ', $tagList);
$inludedTagListString[$tagCollection['TagCollection']['id']] = $tagList;
$expanded[$tagCollection['TagCollection']['id']] .= sprintf(' (%s)', $tagList);
}
}
} else {
if ($taxonomy_id === '0') {
$tags = $this->Taxonomy->getAllTaxonomyTags(true);
$expanded = $tags;
} elseif ($taxonomy_id === 'favourites') {
$tags = array();
$conditions = array('FavouriteTag.user_id' => $this->Auth->user('id'));
$favTags = $this->Tag->FavouriteTag->find('all', array(
'conditions' => $conditions,
'recursive' => -1,
'contain' => array('Tag'),
'order' => array('Tag.name asc')
));
foreach ($favTags as $favTag) {
$tags[$favTag['FavouriteTag']['tag_id']] = $favTag['Tag'];
$expanded = $tags;
}
} elseif ($taxonomy_id === 'all') {
$conditions = array('Tag.org_id' => array(0, $this->Auth->user('org_id')));
$conditions = array('Tag.user_id' => array(0, $this->Auth->user('id')));
$conditions['Tag.hide_tag'] = 0;
$allTags = $this->Tag->find('all', array('conditions' => $conditions, 'recursive' => -1, 'order' => array('name asc')));
$allTags = $this->Tag->EventTag->Event->massageTags(array('EventTag' => $allTags), 'Event', false);
$allTags = $allTags['EventTag'];
$tags = array();
foreach ($allTags as $i => $tag) {
if (!empty($tag['Tag'])) {
$tags[$tag['Tag']['id']] = $tag['Tag'];
}
}
unset($allTags);
$expanded = $tags;
} else {
$taxonomies = $this->Taxonomy->getTaxonomy($taxonomy_id);
$tags = array();
if (!empty($taxonomies['entries'])) {
foreach ($taxonomies['entries'] as $entry) {
if (!empty($entry['existing_tag']['Tag'])) {
$tags[$entry['existing_tag']['Tag']['id']] = $entry['existing_tag']['Tag'];
$expanded[$entry['existing_tag']['Tag']['id']] = $entry['expanded'];
}
}
}
}
// Unset all tags that this user cannot use for tagging, determined by the org restriction on tags
if (!$this->_isSiteAdmin()) {
foreach ($banned_tags as $banned_tag) {
unset($tags[$banned_tag]);
unset($expanded[$banned_tag]);
}
}
$hidden_tags = $this->Tag->find('list', array(
'conditions' => array('Tag.hide_tag' => 1),
'fields' => array('Tag.id')
));
foreach ($hidden_tags as $hidden_tag) {
unset($tags[$hidden_tag]);
unset($expanded[$hidden_tag]);
}
}
$this->set('options', $options);
$this->set('expanded', $expanded);
$this->set('custom', $taxonomy_id == 0 ? true : false);
$this->set('filterData', $filterData);
$this->set('scope', $scope);
$this->set('object_id', $id);
if ($scope === 'attribute') {
$onClickForm = 'quickSubmitAttributeTagForm';
} elseif ($scope === 'tag_collection') {
$onClickForm = 'quickSubmitTagCollectionTagForm';
} else {
$onClickForm = 'quickSubmitTagForm';
}
$items = array();
foreach ($tags as $k => $tag) {
$tagName = $tag['name'];
$choice_id = $k;
if ($taxonomy_id === 'collections') {
$choice_id = 'collection_' . $choice_id;
}
$itemParam = array(
'name' => $tagName,
'value' => $choice_id,
'template' => array(
'name' => array(
'name' => $tagName,
'label' => array(
'background' => isset($tag['colour']) ? $tag['colour'] : '#ffffff'
)
),
'infoExtra' => $expanded[$tag['id']]
)
);
if ($taxonomy_id === 'collections') {
$itemParam['template']['infoContextual'] = __('Includes: ') . $inludedTagListString[$tag['id']];
}
$items[] = $itemParam;
}
$this->set('items', $items);
$this->set('options', array( // set chosen (select picker) options
'functionName' => $onClickForm,
'multiple' => -1,
'select_options' => array(
'additionalData' => array(
'id' => $id
),
),
));
$this->render('ajax/select_tag');
}
@ -804,6 +941,18 @@ class TagsController extends AppController
}
$result = $this->$objectType->$connectorObject->save($data);
if ($result) {
$tempObject = $this->$objectType->find('first', array(
'recursive' => -1,
'conditions' => array($objectType . '.id' => $object[$objectType]['id'])
));
$date = new DateTime();
$tempObject[$objectType]['timestamp'] = $date->getTimestamp();
$this->$objectType->save($tempObject);
if ($objectType === 'Attribute') {
$this->$objectType->Event->unpublishEvent($object['Event']['id']);
} else if ($objectType === 'Event') {
$this->Event->unpublishEvent($object['Event']['id']);
}
$message = 'Tag ' . $existingTag['Tag']['name'] . '(' . $existingTag['Tag']['id'] . ') successfully attached to ' . $objectType . '(' . $object[$objectType]['id'] . ').';
return $this->RestResponse->saveSuccessResponse('Tags', 'attachTagToObject', false, $this->response->type(), $message);
} else {
@ -885,4 +1034,55 @@ class TagsController extends AppController
$this->set('id', $id);
$this->render('/Events/view_graph');
}
public function search($tag = false)
{
if (isset($this->request->data['Tag'])) {
$this->request->data = $this->request->data['Tag'];
}
if (!empty($this->request->data['tag'])) {
$tag = $this->request->data['tag'];
} else if (!empty($this->request->data)) {
$tag = $this->request->data;
}
if (!is_array($tag)) {
$tag = array($tag);
}
foreach ($tag as $k => $t) {
$tag[$k] = strtolower($t);
}
$this->loadModel('GalaxyCluster');
$conditions = array('OR' => array('LOWER(GalaxyCluster.value) LIKE' => $t, array('GalaxyElement.key' => 'synonyms', 'OR' => array())));
foreach ($tag as $k => $t) {
$conditions['OR'][0]['OR'][] = array('LOWER(GalaxyElement.value) LIKE' => $t);
}
$elements = $this->GalaxyCluster->GalaxyElement->find('all', array(
'recursive' => -1,
'conditions' => $conditions,
'contain' => array('GalaxyCluster.tag_name')
));
foreach ($elements as $element) {
$tag[] = strtolower($element['GalaxyCluster']['tag_name']);
}
$conditions = array();
foreach ($tag as $k => $t) {
$conditions['OR'][] = array('LOWER(Tag.name) LIKE' => $t);
}
$tags = $this->Tag->find('all', array(
'conditions' => $conditions,
'recursive' => -1
));
$this->loadModel('Taxonomy');
foreach ($tags as $k => $t) {
$taxonomy = $this->Taxonomy->getTaxonomyForTag($t['Tag']['name'], true);
if (!empty($taxonomy)) {
$tags[$k]['Taxonomy'] = $taxonomy['Taxonomy'];
}
$cluster = $this->GalaxyCluster->getCluster($t['Tag']['name']);
if (!empty($cluster)) {
$tags[$k]['GalaxyCluster'] = $cluster['GalaxyCluster'];
}
}
return $this->RestResponse->viewData($tags, $this->response->type());
}
}

View File

@ -7,7 +7,7 @@ class TaxonomiesController extends AppController
public $paginate = array(
'limit' => 60,
'maxLimit' => 9999, // LATER we will bump here on a problem once we have more than 9999 events <- no we won't, this is the max a user van view/page.
'maxLimit' => 9999, // LATER we will bump here on a problem once we have more than 9999 events <- no we won't, this is the max a user van view/page.
'contain' => array(
'TaxonomyPredicate' => array(
'fields' => array('TaxonomyPredicate.id'),
@ -119,6 +119,7 @@ class TaxonomiesController extends AppController
'recursive' => -1,
'conditions' => array('Taxonomy.id' => $id),
));
$this->Taxonomy->disableTags($id);
$taxonomy['Taxonomy']['enabled'] = 0;
$this->Taxonomy->save($taxonomy);
$this->Log = ClassRegistry::init('Log');

View File

@ -1065,7 +1065,11 @@ class UsersController extends AppController
public function routeafterlogin()
{
// Events list
$this->redirect(array('controller' => 'events', 'action' => 'index'));
$url = $this->Session->consume('pre_login_requested_url');
if (empty($url)) {
$url = array('controller' => 'events', 'action' => 'index');
}
$this->redirect($url);
}
public function logout()
@ -1375,70 +1379,110 @@ class UsersController extends AppController
$this->set('user', $user);
}
public function admin_email()
public function admin_email($isPreview=false)
{
if (!$this->_isAdmin()) {
throw new MethodNotAllowedException();
}
// User has filled in his contact form, send out the email.
if ($this->request->is('post') || $this->request->is('put')) {
$conditions = array();
if (!$this->_isSiteAdmin()) {
$conditions = array('org_id' => $this->Auth->user('org_id'));
}
if ($this->request->data['User']['recipient'] != 1) {
$conditions['id'] = $this->request->data['User']['recipientEmailList'];
}
$conditions['AND'][] = array('User.disabled' => 0);
$users = $this->User->find('all', array('recursive' => -1, 'order' => array('email ASC'), 'conditions' => $conditions));
$this->request->data['User']['message'] = $this->User->adminMessageResolve($this->request->data['User']['message']);
$failures = '';
foreach ($users as $user) {
$password = $this->User->generateRandomPassword();
$body = str_replace('$password', $password, $this->request->data['User']['message']);
$body = str_replace('$username', $user['User']['email'], $body);
$result = $this->User->sendEmail($user, $body, false, $this->request->data['User']['subject']);
// if sending successful and action was a password change, update the user's password.
if ($result && $this->request->data['User']['action'] != '0') {
$this->User->id = $user['User']['id'];
$this->User->saveField('password', $password);
$this->User->saveField('change_pw', '1');
}
if (!$result) {
if ($failures != '') {
$failures .= ', ';
}
$failures .= $user['User']['email'];
}
}
if ($failures != '') {
$this->Flash->success(__('E-mails sent, but failed to deliver the messages to the following recipients: ' . $failures));
} else {
$this->Flash->success(__('E-mails sent.'));
}
}
$isPostOrPut = $this->request->is('post') || $this->request->is('put');
$conditions = array();
if (!$this->_isSiteAdmin()) {
$conditions = array('org_id' => $this->Auth->user('org_id'));
}
$conditions['User.disabled'] = 0;
$temp = $this->User->find('all', array('recursive' => -1, 'fields' => array('id', 'email'), 'order' => array('email ASC'), 'conditions' => $conditions));
$emails = array();
// save all the emails of the users and set it for the dropdown list in the form
foreach ($temp as $user) {
$emails[$user['User']['id']] = $user['User']['email'];
// harvest parameters
if ($isPostOrPut) {
$recipient = $this->request->data['User']['recipient'];
} else {
$recipient = isset($this->request->query['recipient']) ? $this->request->query['recipient'] : null;
}
$this->set('users', $temp);
$this->set('recipientEmail', $emails);
$this->set('org', Configure::read('MISP.org'));
$textsToFetch = array('newUserText', 'passwordResetText');
$this->loadModel('Server');
foreach ($textsToFetch as $text) {
${$text} = Configure::read('MISP.' . $text);
if (!${$text}) {
${$text} = $this->Server->serverSettings['MISP'][$text]['value'];
if ($isPostOrPut) {
$recipientEmailList = $this->request->data['User']['recipientEmailList'];
} else {
$recipientEmailList = isset($this->request->query['recipientEmailList']) ? $this->request->query['recipientEmailList'] : null;
}
if ($isPostOrPut) {
$orgNameList = $this->request->data['User']['orgNameList'];
} else {
$orgNameList = isset($this->request->query['orgNameList']) ? $this->request->query['orgNameList'] : null;
}
if (!is_null($recipient) && $recipient == 0) {
if (is_null($recipientEmailList)) {
throw new NotFoundException(__('Recipient email not provided'));
}
$conditions['id'] = $recipientEmailList;
} elseif (!is_null($recipient) && $recipient == 2) {
if (is_null($orgNameList)) {
throw new NotFoundException(__('Recipient organisation not provided'));
}
$conditions['org_id'] = $orgNameList;
}
$conditions['AND'][] = array('User.disabled' => 0);
// Allow to mimic real form post
if ($isPreview) {
$users = $this->User->find('list', array('recursive' => -1, 'order' => array('email ASC'), 'conditions' => $conditions, 'fields' => array('email')));
$this->set('emails', $users);
$this->set('emailsCount', count($users));
$this->render('ajax/emailConfirmTemplate');
} else {
$users = $this->User->find('all', array('recursive' => -1, 'order' => array('email ASC'), 'conditions' => $conditions));
// User has filled in his contact form, send out the email.
if ($isPostOrPut) {
$this->request->data['User']['message'] = $this->User->adminMessageResolve($this->request->data['User']['message']);
$failures = '';
foreach ($users as $user) {
$password = $this->User->generateRandomPassword();
$body = str_replace('$password', $password, $this->request->data['User']['message']);
$body = str_replace('$username', $user['User']['email'], $body);
$result = $this->User->sendEmail($user, $body, false, $this->request->data['User']['subject']);
// if sending successful and action was a password change, update the user's password.
if ($result && $this->request->data['User']['action'] != '0') {
$this->User->id = $user['User']['id'];
$this->User->saveField('password', $password);
$this->User->saveField('change_pw', '1');
}
if (!$result) {
if ($failures != '') {
$failures .= ', ';
}
$failures .= $user['User']['email'];
}
}
if ($failures != '') {
$this->Flash->success(__('E-mails sent, but failed to deliver the messages to the following recipients: ' . $failures));
} else {
$this->Flash->success(__('E-mails sent.'));
}
}
$conditions = array();
if (!$this->_isSiteAdmin()) {
$conditions = array('org_id' => $this->Auth->user('org_id'));
}
$conditions['User.disabled'] = 0;
$temp = $this->User->find('all', array('recursive' => -1, 'fields' => array('id', 'email', 'Organisation.name'), 'order' => array('email ASC'), 'conditions' => $conditions, 'contain' => array('Organisation')));
$emails = array();
$orgName = array();
// save all the emails of the users and set it for the dropdown list in the form
foreach ($temp as $user) {
$emails[$user['User']['id']] = $user['User']['email'];
$orgName[$user['Organisation']['id']] = $user['Organisation']['name'];
}
$this->set('users', $temp);
$this->set('recipientEmail', $emails);
$this->set('orgName', $orgName);
$this->set('org', Configure::read('MISP.org'));
$textsToFetch = array('newUserText', 'passwordResetText');
$this->loadModel('Server');
foreach ($textsToFetch as $text) {
${$text} = Configure::read('MISP.' . $text);
if (!${$text}) {
${$text} = $this->Server->serverSettings['MISP'][$text]['value'];
}
$this->set($text, ${$text});
}
$this->set($text, ${$text});
}
}
@ -1521,12 +1565,16 @@ class UsersController extends AppController
// set all of the data up for the heatmaps
$params = array(
'fields' => array('name'),
'recursive' => -1
'recursive' => -1,
'conditions' => array()
);
if (!$this->_isSiteAdmin() && !empty(Configure::read('Security.hide_organisation_index_from_users'))) {
$params['conditions'] = array('Organisation.id' => $this->Auth->user('org_id'));
}
$orgs = $this->User->Organisation->find('all', $params);
$local_orgs_params = $params;
$local_orgs_params['conditions']['Organisation.local'] = 1;
$local_orgs = $this->User->Organisation->find('all', $local_orgs_params);
$this->loadModel('Log');
$year = date('Y');
$month = date('n');
@ -1552,7 +1600,10 @@ class UsersController extends AppController
$stats['proposal_count'] = $this->User->Event->ShadowAttribute->find('count', array('recursive' => -1));
$stats['user_count'] = $this->User->find('count', array('recursive' => -1));
$stats['user_count_pgp'] = $this->User->find('count', array('recursive' => -1, 'conditions' => array('User.gpgkey !=' => '')));
$stats['org_count'] = count($orgs);
$stats['local_org_count'] = count($local_orgs);
$stats['average_user_per_org'] = round($stats['user_count'] / $stats['local_org_count'], 1);
$this->loadModel('Thread');
$stats['thread_count'] = $this->Thread->find('count', array('conditions' => array('Thread.post_count >' => 0), 'recursive' => -1));
@ -1808,23 +1859,68 @@ class UsersController extends AppController
{
$this->loadModel('Event');
$this->loadModel('Galaxy');
$attackTacticData = $this->Galaxy->getMitreAttackMatrix();
$attackTactic = $attackTacticData['attackTactic'];
$attackTags = $attackTacticData['attackTags'];
$killChainOrders = $attackTacticData['killChain'];
$instanceUUID = $attackTacticData['instance-uuid'];
$scoresDataAttr = $this->Event->Attribute->AttributeTag->getTagScores(0, $attackTags);
$scoresDataEvent = $this->Event->EventTag->getTagScores(0, $attackTags);
$galaxy_id = $this->Galaxy->getMitreAttackGalaxyId();
$matrixData = $this->Galaxy->getMatrix($galaxy_id);
$tabs = $matrixData['tabs'];
$matrixTags = $matrixData['matrixTags'];
$killChainOrders = $matrixData['killChain'];
$instanceUUID = $matrixData['instance-uuid'];
$scoresDataAttr = $this->Event->Attribute->AttributeTag->getTagScores(0, $matrixTags);
$scoresDataEvent = $this->Event->EventTag->getTagScores(0, $matrixTags);
$scoresData = array();
foreach (array_keys($scoresDataAttr['scores'] + $scoresDataEvent['scores']) as $key) {
$scoresData[$key] = (isset($scoresDataAttr['scores'][$key]) ? $scoresDataAttr['scores'][$key] : 0) + (isset($scoresDataEvent['scores'][$key]) ? $scoresDataEvent['scores'][$key] : 0);
}
$maxScore = max($scoresDataAttr['maxScore'], $scoresDataEvent['maxScore']);
$scores = $scoresData;
// FIXME: temporary fix: add the score of deprecated mitre galaxies to the new one (for the stats)
if ($matrixData['galaxy']['id'] == $galaxy_id) {
$mergedScore = array();
foreach ($scoresData as $tag => $v) {
$predicateValue = explode(':', $tag, 2)[1];
$predicateValue = explode('=', $predicateValue, 2);
$predicate = $predicateValue[0];
$clusterValue = $predicateValue[1];
$mappedTag = '';
$mappingWithoutExternalId = array();
if ($predicate == 'mitre-attack-pattern') {
$mappedTag = $tag;
$name = explode(" ", $tag);
$name = join(" ", array_slice($name, 0, -2)); // remove " - external_id"
$mappingWithoutExternalId[$name] = $tag;
} else {
$name = explode(" ", $clusterValue);
$name = join(" ", array_slice($name, 0, -2)); // remove " - external_id"
if (isset($mappingWithoutExternalId[$name])) {
$mappedTag = $mappingWithoutExternalId[$name];
} else {
$adjustedTagName = $this->Galaxy->GalaxyCluster->find('list', array(
'group' => array('GalaxyCluster.id', 'GalaxyCluster.tag_name'),
'conditions' => array('GalaxyCluster.tag_name LIKE' => 'misp-galaxy:mitre-attack-pattern=' . $name . '% T%'),
'fields' => array('GalaxyCluster.tag_name')
));
$adjustedTagName = array_values($adjustedTagName)[0];
$mappingWithoutExternalId[$name] = $adjustedTagName;
$mappedTag = $mappingWithoutExternalId[$name];
}
}
if (isset($mergedScore[$mappedTag])) {
$mergedScore[$mappedTag] += $v;
} else {
$mergedScore[$mappedTag] = $v;
}
}
$scores = $mergedScore;
$maxScore = max(array_values($mergedScore));
}
// end FIXME
if ($this->_isRest()) {
$json = array('matrix' => $attackTactic, 'scores' => $scores, 'instance-uuid' => $instanceUUID);
$json = array('matrix' => $tabs, 'scores' => $scores, 'instance-uuid' => $instanceUUID);
return $this->RestResponse->viewData($json, $this->response->type());
} else {
App::uses('ColourGradientTool', 'Tools');
@ -1832,12 +1928,17 @@ class UsersController extends AppController
$colours = $gradientTool->createGradientFromValues($scores);
$this->set('target_type', 'attribute');
$this->set('killChainOrders', $killChainOrders);
$this->set('attackTactic', $attackTactic);
$this->set('columnOrders', $killChainOrders);
$this->set('tabs', $tabs);
$this->set('scores', $scores);
$this->set('maxScore', $maxScore);
$this->set('colours', $colours);
if (!empty($colours)) {
$this->set('colours', $colours['mapping']);
$this->set('interpolation', $colours['interpolation']);
}
$this->set('pickingMode', false);
$this->set('defaultTabName', "mitre-attack");
$this->set('removeTrailling', 2);
$this->render('statistics_attackmatrix');
}

View File

@ -7,7 +7,7 @@ class WarninglistsController extends AppController
public $paginate = array(
'limit' => 60,
'maxLimit' => 9999, // LATER we will bump here on a problem once we have more than 9999 events <- no we won't, this is the max a user van view/page.
'maxLimit' => 9999, // LATER we will bump here on a problem once we have more than 9999 events <- no we won't, this is the max a user van view/page.
'contain' => array(
'WarninglistType'
),
@ -117,45 +117,45 @@ class WarninglistsController extends AppController
}
}
/*
* toggle warninglists on or offset
* Simply POST an ID or a list of IDs to toggle the current state
* To control what state the warninglists should have after execution instead of just blindly toggling them, simply pass the enabled flag
* Example:
* {"id": [5, 8], "enabled": 1}
/*
* toggle warninglists on or offset
* Simply POST an ID or a list of IDs to toggle the current state
* To control what state the warninglists should have after execution instead of just blindly toggling them, simply pass the enabled flag
* Example:
* {"id": [5, 8], "enabled": 1}
* Alternatively search by a substring in the warninglist's named, such as:
* {"name": ["%alexa%", "%iana%"], "enabled": 1}
*/
*/
public function toggleEnable()
{
if (!$this->request->is('post')) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'This function only accepts POST requests.')), 'status' => 200, 'type' => 'json'));
}
if (isset($this->request->data['Warninglist']['data'])) {
$id = $this->request->data['Warninglist']['data'];
} else {
if (!empty($this->request->data['id'])) {
$id = $this->request->data['id'];
} else if (!empty($this->request->data['name'])) {
if (!is_array($this->request->data['name'])) {
$names = array($this->request->data['name']);
} else {
$names = $this->request->data['name'];
}
$conditions = array();
foreach ($names as $k => $name) {
$conditions['OR'][] = array('LOWER(Warninglist.name) LIKE' => strtolower($name));
}
$id = $this->Warninglist->find('list', array(
'conditions' => $conditions,
'recursive' => -1,
'fields' => array('Warninglist.id', 'Warninglist.id')
));
}
}
if (isset($this->request->data['enabled'])) {
$enabled = $this->request->data['enabled'];
}
if (!$this->request->is('post')) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'This function only accepts POST requests.')), 'status' => 200, 'type' => 'json'));
}
if (isset($this->request->data['Warninglist']['data'])) {
$id = $this->request->data['Warninglist']['data'];
} else {
if (!empty($this->request->data['id'])) {
$id = $this->request->data['id'];
} elseif (!empty($this->request->data['name'])) {
if (!is_array($this->request->data['name'])) {
$names = array($this->request->data['name']);
} else {
$names = $this->request->data['name'];
}
$conditions = array();
foreach ($names as $k => $name) {
$conditions['OR'][] = array('LOWER(Warninglist.name) LIKE' => strtolower($name));
}
$id = $this->Warninglist->find('list', array(
'conditions' => $conditions,
'recursive' => -1,
'fields' => array('Warninglist.id', 'Warninglist.id')
));
}
}
if (isset($this->request->data['enabled'])) {
$enabled = $this->request->data['enabled'];
}
if (empty($id)) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Warninglist not found.')), 'status' => 200, 'type' => 'json'));
}
@ -163,28 +163,28 @@ class WarninglistsController extends AppController
if (empty($currentState)) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Warninglist(s) not found.')), 'status' => 200, 'type' => 'json'));
}
$success = 0;
foreach ($currentState as $warningList) {
if (isset($enabled)) {
$warningList['Warninglist']['enabled'] = $enabled;
$message = $enabled ? 'enabled' : 'disabled';
} else {
if ($warningList['Warninglist']['enabled']) {
$warningList['Warninglist']['enabled'] = 0;
$message = 'disabled';
} else {
$warningList['Warninglist']['enabled'] = 1;
$message = 'enabled';
}
if (!isset($enabled) && count($currentState) > 1) {
$message = 'toggled';
}
}
if ($this->Warninglist->save($warningList)) {
$success += 1;
}
$this->Warninglist->regenerateWarninglistCaches($warningList['Warninglist']['id']);
}
$success = 0;
foreach ($currentState as $warningList) {
if (isset($enabled)) {
$warningList['Warninglist']['enabled'] = $enabled;
$message = $enabled ? 'enabled' : 'disabled';
} else {
if ($warningList['Warninglist']['enabled']) {
$warningList['Warninglist']['enabled'] = 0;
$message = 'disabled';
} else {
$warningList['Warninglist']['enabled'] = 1;
$message = 'enabled';
}
if (!isset($enabled) && count($currentState) > 1) {
$message = 'toggled';
}
}
if ($this->Warninglist->save($warningList)) {
$success += 1;
}
$this->Warninglist->regenerateWarninglistCaches($warningList['Warninglist']['id']);
}
if ($success) {
$this->Warninglist->regenerateWarninglistCaches($id);
return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'success' => $success . ' warninglist(s) ' . $message)), 'status' => 200, 'type' => 'json'));
@ -259,30 +259,34 @@ class WarninglistsController extends AppController
}
}
public function checkValue() {
if ($this->request->is('post')) {
$warninglists = $this->Warninglist->getWarninglists(array());
if (empty($this->request->data)) {
throw new NotFoundException('No valid data received.');
}
$data = $this->request->data;
if (!is_array($data)) {
$data = array($data);
}
$hits = array();
foreach ($data as $dataPoint) {
foreach ($warninglists as $warninglist) {
$listValues = $this->Warninglist->getWarninglistEntries($warninglist['Warninglist']['id']);
$listValues = array_combine($listValues, $listValues);
$result = $this->Warninglist->quickCheckValue($listValues, $dataPoint, $warninglist['Warninglist']['type']);
if ($result) {
$hits[$dataPoint][] = array('id' => $warninglist['Warninglist']['id'], 'name' => $warninglist['Warninglist']['name']);
}
}
}
return $this->RestResponse->viewData($hits, $this->response->type());
public function checkValue()
{
if ($this->request->is('post')) {
$warninglists = $this->Warninglist->getWarninglists(array());
if (empty($this->request->data)) {
throw new NotFoundException('No valid data received.');
}
$data = $this->request->data;
if (!is_array($data)) {
$data = array($data);
}
if (array_key_exists('[]', $data)) {
$data = $data['[]'];
}
$hits = array();
foreach ($data as $dataPoint) {
foreach ($warninglists as $warninglist) {
$listValues = $this->Warninglist->getWarninglistEntries($warninglist['Warninglist']['id']);
$listValues = array_combine($listValues, $listValues);
$result = $this->Warninglist->quickCheckValue($listValues, $dataPoint, $warninglist['Warninglist']['type']);
if ($result) {
$hits[$dataPoint][] = array('id' => $warninglist['Warninglist']['id'], 'name' => $warninglist['Warninglist']['name']);
}
}
}
return $this->RestResponse->viewData($hits, $this->response->type());
} else {
return $this->RestResponse->describe('Warninglists', 'checkValue', false, $this->response->type());
return $this->RestResponse->describe('Warninglists', 'checkValue', false, $this->response->type());
}
}
}
}

View File

@ -46,6 +46,7 @@ class BroExport
'sha512/224' => array('brotype' => 'FILE_HASH'),
'sha512/256' => array('brotype' => 'FILE_HASH'),
'tlsh' => array('brotype' => 'FILE_HASH'),
'cdhash' => array('brotype' => 'FILE_HASH'),
'filename|authentihash' => array('brotype' => 'FILE_NAME', 'composite' => 'FILE_HASH'),
'filename|ssdeep' => array('brotype' => 'FILE_NAME', 'composite' => 'FILE_HASH'),
'filename|imphash' => array('brotype' => 'FILE_NAME', 'composite' => 'FILE_HASH'),
@ -133,7 +134,22 @@ class BroExport
private $whitelist = null;
public function export($items, $orgs, $valueField, $whitelist, $instanceString)
public function handler($data, $options = array())
{
}
public function footer()
{
return "\n";
}
public function separator()
{
return "\n";
}
public function export($items, $orgs, $valueField, $whitelist = array(), $instanceString)
{
$intel = array();
//For bro format organisation
@ -155,10 +171,10 @@ class BroExport
return $intel;
}
private function __generateRule($attribute, $ruleFormat, $valueField, $whitelist)
private function __generateRule($attribute, $ruleFormat, $valueField, $whitelist = array())
{
if (isset($this->mapping[$attribute['type']])) {
if (! $this->checkWhitelist($attribute['value'], $whitelist)) {
if (empty($whitelist) || !$this->checkWhitelist($attribute['value'], $whitelist)) {
$brotype = $this->mapping[$attribute['type']]['brotype'];
if (isset($this->mapping[$attribute['type']]['alternate'])) {
if (preg_match($this->mapping[$attribute['type']]['alternate'][0], $attribute['value'])) {

View File

@ -15,12 +15,20 @@ class CacheExport
throw new MethodNotAllowedException('Invalid hashing algo');
}
if ($options['scope'] === 'Attribute') {
return hash($hash_type, $data['Attribute']['value']);
$temp = hash($hash_type, $data['Attribute']['value']);
if (!empty($options['filters']['includeEventUuid'])) {
$temp .= ',' . $data['Event']['uuid'];
}
return $temp;
}
if ($options['scope'] === 'Event') {
$result = array();
foreach ($data['Attribute'] as $attribute) {
$result[] = hash($hash_type, $data['Attribute']['value']);
$temp = hash($hash_type, $data['Attribute']['value']);
if (!empty($options['filters']['includeEventUuid'])) {
$temp .= ',' . $data['Event']['uuid'];
}
$result[] = $temp;
}
return implode($this->separator(), $result);
}

View File

@ -14,6 +14,8 @@ class CsvExport
$lines = $this->__attributesHandler($data, $options);
} else if($options['scope'] === 'Event') {
$lines = $this->__eventsHandler($data, $options);
} else if($options['scope'] === 'Sighting') {
$lines = $this->__sightingsHandler($data, $options);
}
return $lines;
}
@ -29,8 +31,6 @@ class CsvExport
'Event' => array('fields' => array('Event.*'), 'EventTag' => 'Tag', 'Org.name', 'Orgc.name', 'ThreatLevel')
));
unset($params['fields']);
$params['includeEventUuid'] = 0;
$params['includeEventTags'] = 0;
$params['withAttachments'] = 0;
return $params;
}
@ -46,6 +46,32 @@ class CsvExport
return $this->__addLine($attribute, $options);
}
private function __sightingsHandler($sighting, $options)
{
$lines = '';
if (isset($sighting['Sighting']['Event'])) {
foreach($sighting['Sighting']['Event'] as $k => $event_val) {
$new_key = 'event_' . $k;
// in case we have an array, e.g. orc => name
if (is_array($event_val)) {
$v2 = reset($event_val);
$k2 = key($event_val);
$new_key .= '_' . $k2;
$event_val = $v2;
}
$sighting['Sighting'][$new_key] = $event_val;
}
}
if (isset($sighting['Sighting']['Attribute'])) {
foreach($sighting['Sighting']['Attribute'] as $k => $attribute_val) {
$new_key = 'attribute_' . $k;
$sighting['Sighting'][$new_key] = $attribute_val;
}
}
$lines .= $this->__addLine($sighting['Sighting'], $options);
return $lines;
}
private function __eventsHandler($event, $options)
{
$lines = '';

View File

@ -9,8 +9,10 @@ class JsonExport
{
if ($options['scope'] === 'Attribute') {
return $this->__attributeHandler($data, $options);
} else {
} else if($options['scope'] === 'Event') {
return $this->__eventHandler($data, $options);
} else if($options['scope'] === 'Sighting') {
return $this->__sightingsHandler($data, $options);
}
}
@ -47,6 +49,11 @@ class JsonExport
return json_encode($attribute);
}
private function __sightingsHandler($sighting, $options = array())
{
return json_encode($sighting);
}
public function header($options = array())
{
if ($options['scope'] === 'Attribute') {

View File

@ -14,12 +14,14 @@ class Stix1Export extends StixExport
$this->__baseurl = escapeshellarg(Configure::read('MISP.baseurl'));
$this->__org = escapeshellarg(Configure::read('MISP.org'));
$framing_file = $this->__scripts_dir . 'misp_framing.py ';
return 'python3 ' . $framing_file . $this->__return_type . ' ' . $this->__baseurl . ' ' . $this->__org . ' xml' . $this->__end_of_cmd;
$my_server = ClassRegistry::init('Server');
return $my_server->getPythonVersion() . ' ' . $framing_file . $this->__return_type . ' ' . $this->__baseurl . ' ' . $this->__org . ' xml' . $this->__end_of_cmd;
}
protected function __parse_misp_events($filename)
{
$scriptFile = $this->__scripts_dir . $this->__script_name;
return shell_exec('python3 ' . $scriptFile . ' ' . $filename . ' xml ' . $this->__baseurl . ' ' . $this->__org . $this->__end_of_cmd);
$my_server = ClassRegistry::init('Server');
return shell_exec($my_server->getPythonVersion() . ' ' . $scriptFile . ' ' . $filename . ' xml ' . $this->__baseurl . ' ' . $this->__org . $this->__end_of_cmd);
}
}

View File

@ -10,13 +10,15 @@ class Stix2Export extends StixExport
protected function initiate_framing_params()
{
$framing_file = $this->__scripts_dir . 'misp_framing.py ';
return 'python3 ' . $framing_file . $this->__return_type . ' ' . escapeshellarg(CakeText::uuid()) . $this->__end_of_cmd;
$my_server = ClassRegistry::init('Server');
return $my_server->getPythonVersion() . ' ' . $framing_file . $this->__return_type . ' ' . escapeshellarg(CakeText::uuid()) . $this->__end_of_cmd;
}
protected function __parse_misp_events($filename)
{
$scriptFile = $this->__scripts_dir . $this->__script_name;
$filename = $this->__scripts_dir . 'tmp/' . $filename;
return shell_exec('python3 ' . $scriptFile . ' ' . $filename . $this->__end_of_cmd);
$my_server = ClassRegistry::init('Server');
return shell_exec($my_server->getPythonVersion() . ' ' . $scriptFile . ' ' . $filename . $this->__end_of_cmd);
}
}

View File

@ -21,7 +21,9 @@ class StixExport
{
$attributes_count = count($data['Attribute']);
foreach ($data['Object'] as $_object) {
$attributes_count += count($_object['Attribute']);
if (isset($_object['Attribute'])) {
$attributes_count += count($_object['Attribute']);
}
}
App::uses('JSONConverterTool', 'Tools');
$converter = new JSONConverterTool();

View File

@ -9,8 +9,10 @@ class XmlExport
{
if ($options['scope'] === 'Attribute') {
return $this->__attributeHandler($data, $options);
} else {
} else if($options['scope'] === 'Event') {
return $this->__eventHandler($data, $options);
} else if($options['scope'] === 'Sighting') {
return $this->__sightingsHandler($data, $options);
}
}
@ -50,6 +52,12 @@ class XmlExport
return substr($xmlString, strpos($xmlString, "\n") + 1);
}
private function __sightingsHandler($sighting, $options = array()) {
$xmlObject = Xml::fromArray(array('Sighting' => $sighting['Sighting']), array('format' => 'tags'));
$xmlString = $xmlObject->asXML();
return substr($xmlString, strpos($xmlString, "\n") + 1);
}
public function header($options = array())
{
return '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL . '<response>';

View File

@ -77,18 +77,25 @@ class AWSS3Client
}
public function deleteDirectory($prefix) {
$keys = $s3->listObjects([
$keys = $this->__client->listObjectsV2([
'Bucket' => $this->__settings['bucket_name'],
'Prefix' => $prefix
]) ->getPath('Contents/*/Key');
$s3->deleteObjects([
'Bucket' => $bucket,
'Delete' => [
'Objects' => array_map(function ($key) {
return ['Key' => $key];
}, $keys)
],
]);
$toDelete = array_map(
function ($key) {
return ['Key' => $key['Key']];
},
is_array($keys['Contents'])?$keys['Contents']:[]
);
if (sizeof($toDelete) != 0) {
$this->__client->deleteObjects([
'Bucket' => $this->__settings['bucket_name'],
'Delete' => [
'Objects' => $toDelete
]
]);
}
}
}

View File

@ -1,45 +1,113 @@
<?php
class ColourGradientTool
{
public function createGradient($step)
{
$stepHex = dechex($step);
$minHex = 0x0000FF;
$maxHex = 0xFF0000;
$intervalHex = ($maxHex-$minHex) / $stepHex;
$colours = array();
for ($i=$minHex; $i<$maxHex; $i+=$intervalHex) {
$colours[] = $i;
}
return $colours;
}
// source: https://graphicdesign.stackexchange.com/a/83867
// $values of the form array(item1: val1, item2: val2, ...)
public function createGradientFromValues($items)
{
$starColor = '#0000FF';
$endColor = '#FF0000';
if (count($items) == 0) {
return array();
}
$maxColorHex = 0x0000FF;
$minColorHex = 0xE0E0FF;
$vals = array_values($items);
$maxDec = max($vals);
$minDec = min($vals);
if ($maxDec == $minDec) {
$intervalHex = 0x0;
} else {
$intervalHex = ($maxColorHex - $minColorHex)/($maxDec-$minDec);
}
$interpolation = $this->interpolateColors($starColor, $endColor, $maxDec+1, true);
$coloursMapping = array();
foreach ($items as $name => $val) {
$ratio = ($val-$minDec)*($intervalHex);
$colour = $maxDec == $minDec ? $maxColorHex : $ratio + $minColorHex;
$coloursMapping[$name] = '#' . str_pad(dechex($colour), 6, '0', STR_PAD_LEFT);
$color = $interpolation[$val];
$coloursMapping[$name] = '#' . str_pad(dechex($color[0]), 2, '0', STR_PAD_LEFT) . str_pad(dechex($color[1]), 2, '0', STR_PAD_LEFT) . str_pad(dechex($color[2]), 2, '0', STR_PAD_LEFT);
}
return array('mapping' => $coloursMapping, 'interpolation' => $interpolation);
}
private function hue2rgb($p, $q, $t) {
if ($t < 0) $t += 1;
if ($t > 1) $t -= 1;
if ($t < 1/6) return $p + ($q - $p) * 6 * $t;
if ($t < 1/2) return $q;
if ($t < 2/3) return $p + ($q - $p) * (2/3 - $t) * 6;
return $p;
}
private function hsl2rgb($color) {
$l = $color[2];
if ($color[1] == 0) {
$l = round($l*255);
return array($l, $l, $l);
} else {
$s = $color[1];
$q = ($l < 0.5 ? $l * (1 + $s) : $l + $s - $l * $s);
$p = 2 * $l - $q;
$r = $this->hue2rgb($p, $q, $color[0] + 1/3);
$g = $this->hue2rgb($p, $q, $color[0]);
$b = $this->hue2rgb($p, $q, $color[0] - 1/3);
return array(round($r*255), round($g*255), round($b*255));
}
return $coloursMapping;
}
private function rgb2hsl($color) {
$r = $color[0]/255;
$g = $color[1]/255;
$b = $color[2]/255;
$arrRGB = array($r, $g, $b);
$max = max($arrRGB);
$min = min($arrRGB);
$h = ($max - $min) / 2;
$s = $h;
$l = $h;
if ($max == $min) {
$s = 0; // achromatic
$h = 0;
} else {
$d = $max - $min;
$s = ($l > 0.5 ? $d / (2 - $max - $min) : $d / ($max + $min) );
if ($max == $r) {
$h = ($g - $b) / $d + ($g < $b ? 6 : 0);
} elseif ($max == $g) {
$h = ($b - $r) / $d + 2;
} elseif ($max == $b) {
$h = ($r - $g) / $d + 4;
}
$h = $h / 6;
return array($h, $s, $l);
}
}
private function interpolateColor($color1, $color2, $factor, $useHSL=false) {
if ($useHSL) {
$hsl1 = $this->rgb2hsl($color1);
$hsl2 = $this->rgb2hsl($color2);
for ($i=0; $i<3; $i++) {
$hsl1[$i] += $factor*($hsl2[$i] - $hsl1[$i]);
}
$result = $this->hsl2rgb($hsl1);
} else {
$result = $color1;
for ($i = 0; $i < 3; $i++) {
$result[$i] = round($result[$i] + $factor * ($color2[$i] - $color1[$i]));
}
}
return $result;
}
public function interpolateColors($hexColor1, $hexColor2, $steps, $useHSL=false) {
$stepFactor = 1 / ($steps - 1);
$interpolatedColorArray = array();
$color1 = sscanf($hexColor1, "#%02x%02x%02x");
$color2 = sscanf($hexColor2, "#%02x%02x%02x");
for($i = 0; $i < $steps; $i++) {
$interpolatedColorArray[$i] = $this->interpolateColor($color1, $color2, $stepFactor * $i, $useHSL);
}
return $interpolatedColorArray;
}
}

View File

@ -220,7 +220,7 @@ class ComplexTypeTool
private $__hexHashTypes = array(
32 => array('single' => array('md5', 'imphash', 'x509-fingerprint-md5'), 'composite' => array('filename|md5', 'filename|imphash')),
40 => array('single' => array('sha1', 'pehash', 'x509-fingerprint-sha1'), 'composite' => array('filename|sha1', 'filename|pehash')),
40 => array('single' => array('sha1', 'pehash', 'x509-fingerprint-sha1', 'cdhash'), 'composite' => array('filename|sha1', 'filename|pehash')),
56 => array('single' => array('sha224', 'sha512/224'), 'composite' => array('filename|sha224', 'filename|sha512/224')),
64 => array('single' => array('sha256', 'authentihash', 'sha512/256', 'x509-fingerprint-sha256'), 'composite' => array('filename|sha256', 'filename|authentihash', 'filename|sha512/256')),
96 => array('single' => array('sha384'), 'composite' => array('filename|sha384')),
@ -228,7 +228,7 @@ class ComplexTypeTool
);
// algorithms to run through in order
private $__checks = array('Hashes', 'Email', 'IP', 'DomainOrFilename', 'SimpleRegex', 'AS');
private $__checks = array('Hashes', 'Email', 'IP', 'DomainOrFilename', 'SimpleRegex', 'AS', 'BTC');
private function __resolveType($raw_input)
{
@ -247,6 +247,14 @@ class ComplexTypeTool
return false;
}
private function __checkForBTC($input)
{
if (preg_match("#^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$#i", $input['raw'])) {
return array('types' => array('btc'), 'categories' => array('Financial fraud'), 'to_ids' => true, 'default_type' => 'btc', 'value' => $input['raw']);
}
return false;
}
private function __checkForEmail($input)
{
// quick filter for an @ to see if we should validate a potential e-mail address
@ -288,7 +296,11 @@ class ComplexTypeTool
// check for hashes
foreach ($this->__hexHashTypes as $k => $v) {
if (strlen($input['raw']) == $k && preg_match("#[0-9a-f]{" . $k . "}$#i", $input['raw'])) {
return array('types' => $v['single'], 'to_ids' => true, 'default_type' => $v['single'][0], 'value' => $input['raw']);
$types = $v['single'];
if (!empty($this->__checkForBTC($input))) {
$types[] = 'btc';
}
return array('types' => $types, 'to_ids' => true, 'default_type' => $v['single'][0], 'value' => $input['raw']);
}
}
// ssdeep has a different pattern

View File

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: misp\n"
"PO-Revision-Date: 2018-10-15 23:37\n"
"PO-Revision-Date: 2019-01-22 21:21\n"
"Last-Translator: SteveClement <steve@localhost.lu>\n"
"Language-Team: Czech\n"
"MIME-Version: 1.0\n"

View File

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: misp\n"
"PO-Revision-Date: 2018-10-15 23:37\n"
"PO-Revision-Date: 2019-01-22 21:22\n"
"Last-Translator: SteveClement <steve@localhost.lu>\n"
"Language-Team: Danish\n"
"MIME-Version: 1.0\n"
@ -5461,11 +5461,11 @@ msgstr "EventGraph Sletning"
#: View/EventGraph/ajax/eventGraph_delete_form.ctp:8
msgid "Are you sure you want to delete eventGraph #%s? The eventGraph will be permanently deleted and unrecoverable."
msgstr ""
msgstr "Er du sikker på du vil slette eventGraph #%s? EventGraph vil være permanent slettede og uoprettelig."
#: View/Events/add.ctp:3
msgid "The event created %s, but not synchronised to other MISP instances until it is published."
msgstr ""
msgstr "Begivenheden oprettet %s, men synkroniseret ikke til andre forekomster af MISP, indtil det er offentliggjort."
#: View/Events/add.ctp:3
msgid "will be restricted to your organisation"
@ -5895,7 +5895,8 @@ msgstr "Inkluder events der ikke er publicerede."
#: View/Events/automation.ctp:208;275
msgid "You can also chain several tag commands together with the '&amp;&amp;' operator. Please be aware the colons (:) cannot be used in the tag search.\n"
" Use semicolons instead (the search will automatically search for colons instead). For example, to include tag1 and tag2 but exclude tag3 you would use"
msgstr ""
msgstr "Du kan også sammenkæde flere tagkommandoer med &amp;&amp;-operatoren. Vær opmærksom på, at kolon (:) ikke kan benyttes i tag-søgning.\n"
" Benyt i stedet somikolon (søgningen vil automatisk søge efter koloner i stedet). For f.eks. at medtage tag1 og tag2, men udelukke tag3, skal du benytte"
#: View/Events/automation.ctp:211
msgid "Bro IDS export"
@ -6951,7 +6952,7 @@ msgstr "Skift pivotgraf"
#: View/Events/view.ctp:360
msgid "Pivots"
msgstr ""
msgstr "Pivots"
#: View/Events/view.ctp:363
msgid "Toggle galaxies"

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: misp\n"
"PO-Revision-Date: 2018-10-15 23:35\n"
"PO-Revision-Date: 2019-01-22 21:23\n"
"Last-Translator: SteveClement <steve@localhost.lu>\n"
"Language-Team: German\n"
"MIME-Version: 1.0\n"
@ -61,7 +61,7 @@ msgstr "Sie haben keine Berechtigung dieses Event anzuzeigen."
#: Controller/AttributesController.php:472
msgid "Attribute not an attachment or malware-sample"
msgstr "Attribut ist keine Anlage oder Malware-Sample"
msgstr "Attribut ist kein Anhang oder Malware-Sample"
#: Controller/AttributesController.php:504;677
#: Controller/ShadowAttributesController.php:548
@ -220,7 +220,7 @@ msgstr "Ungültiges Event-ID-Format."
#: Controller/AttributesController.php:2645
#: Controller/ShadowAttributesController.php:1254
msgid "All done. "
msgstr "Alles erledigt. "
msgstr "Fertig. "
#: Controller/AttributesController.php:2677;2724
#: Controller/ShadowAttributesController.php:1062
@ -1819,19 +1819,19 @@ msgstr "Einstellung des Bereichs für Sightings für das generieren von Graphen.
#: Model/Server.php:1465
msgid "Enable this functionality if you would like to handle the authentication via an external tool and authenticate with MISP using a custom header."
msgstr ""
msgstr "Aktivieren Sie diese Funktion, falls Sie die Authentifizierung mit MISP durch ein externes Tool und custom Header handhaben möchten."
#: Model/Server.php:1475
msgid "Set the header that MISP should look for here. If left empty it will default to the Authorization header."
msgstr ""
msgstr "Stellen Sie hier die Kopfzeile ein, nach der MISP hier suchen soll. Ohne weitere Angabe wird als Default nach der Authorisierungskopfzeile gesucht."
#: Model/Server.php:1484
msgid "Use a header namespace for the auth header - default setting is enabled"
msgstr ""
msgstr "Verwenden Sie einen Namespace (Namensbereich) für den Authentifizierungsheader - Standardeinstellung ist aktiviert"
#: Model/Server.php:1493
msgid "The default header namespace for the auth header - default setting is HTTP_"
msgstr ""
msgstr "Der Standard Namespace für den Authentifizierungsheader - Standardeinstellung ist HTTP"
#: Model/Server.php:1502
msgid "If this setting is enabled then the only way to authenticate will be using the custom header. Altnertatively you can run in mixed mode that will log users in via the header if found, otherwise users will be redirected to the normal login page."
@ -1847,7 +1847,7 @@ msgstr ""
#: Model/Server.php:1529
msgid "Disable the logout button for users authenticate with the external auth mechanism."
msgstr ""
msgstr "Deaktivieren Sie den Logout-Button für User, die sich extern authentifizieren."
#: Model/Server.php:1537
msgid "Enable/disable the enrichment services"
@ -3909,7 +3909,7 @@ msgstr ""
#: View/Elements/side_menu.ctp:533
msgid "Update Galaxies"
msgstr ""
msgstr "Galaxien aktualisieren"
#: View/Elements/side_menu.ctp:533
msgid "Are you sure you want to reimport all galaxies from the submodule?"
@ -3943,7 +3943,7 @@ msgstr ""
#: View/Layouts/default.ctp:84
#: View/Layouts/graph.ctp:84
msgid "Loading"
msgstr ""
msgstr "Lädt"
#: View/Elements/view_event_distribution_graph.ctp:17
msgid "Elements having lower distribution level than the event"
@ -12487,7 +12487,7 @@ msgstr ""
#: View/Users/admin_add.ctp:88
#: View/Users/admin_edit.ctp:78
msgid "Disable this user account"
msgstr ""
msgstr "Diesen Useraccount deaktivieren"
#: View/Users/admin_add.ctp:90
msgid "Send credentials automatically"

View File

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: misp\n"
"PO-Revision-Date: 2018-10-15 14:03\n"
"PO-Revision-Date: 2019-01-22 21:22\n"
"Last-Translator: SteveClement <steve@localhost.lu>\n"
"Language-Team: French\n"
"MIME-Version: 1.0\n"

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: misp\n"
"PO-Revision-Date: 2018-10-15 23:37\n"
"PO-Revision-Date: 2019-01-22 21:24\n"
"Last-Translator: SteveClement <steve@localhost.lu>\n"
"Language-Team: Italian\n"
"MIME-Version: 1.0\n"

View File

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: misp\n"
"PO-Revision-Date: 2018-10-15 23:37\n"
"PO-Revision-Date: 2019-01-22 21:25\n"
"Last-Translator: SteveClement <steve@localhost.lu>\n"
"Language-Team: Japanese\n"
"MIME-Version: 1.0\n"

View File

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: misp\n"
"PO-Revision-Date: 2018-10-15 23:37\n"
"PO-Revision-Date: 2019-01-22 21:25\n"
"Last-Translator: SteveClement <steve@localhost.lu>\n"
"Language-Team: Korean\n"
"MIME-Version: 1.0\n"
@ -609,35 +609,35 @@ msgstr "다운로드에 실패했습니다."
#: Controller/FeedsController.php:561
msgid "Feed could not be fetched. The HTTP error code returned was: "
msgstr ""
msgstr "피드를 가져올 수 없습니다. 리턴된 HTTP 오류 코드는 다음과 같습니다: "
#: Controller/FeedsController.php:600;651
msgid "Invalid feed type."
msgstr ""
msgstr "잘못된 피드 유형입니다."
#: Controller/FeedsController.php:714
msgid "This event is blocked by the Feed filters."
msgstr ""
msgstr "이 이벤트는 피드 필터에 의해 차단되어 있습니다."
#: Controller/FeedsController.php:716
msgid "Could not download the selected Event"
msgstr ""
msgstr "선택한 이벤트를 다운로드 할 수 없습니다"
#: Controller/FeedsController.php:752;756
msgid "Invalid Feed."
msgstr ""
msgstr "잘못된 피드입니다."
#: Controller/FeedsController.php:777
msgid "Only POST requests are allowed."
msgstr ""
msgstr "POST 요청 만 허용되어 있습니다."
#: Controller/FeedsController.php:781
msgid "Feed not found."
msgstr ""
msgstr "피드가 없습니다."
#: Controller/FeedsController.php:790
msgid "Data pulled."
msgstr ""
msgstr "데이터를 가져왔습니다."
#: Controller/FeedsController.php:792
msgid "Could not pull the selected data. Reason: %s"
@ -645,27 +645,27 @@ msgstr ""
#: Controller/FeedsController.php:809
msgid "Starting feed caching."
msgstr ""
msgstr "피드 캐싱 시작."
#: Controller/FeedsController.php:824
msgid "Caching the feeds has failed."
msgstr ""
msgstr "피드를 캐싱에 실패 했습니다."
#: Controller/FeedsController.php:827
msgid "Caching the feeds has successfully completed."
msgstr ""
msgstr "피드 캐싱을 성공적으로 완료 했습니다."
#: Controller/FeedsController.php:858
msgid "Invalid feed list received."
msgstr ""
msgstr "잘못 된 피드 리스트를 받았습니다."
#: Controller/JobsController.php:156
msgid "All completed jobs have been purged"
msgstr ""
msgstr "모든 완료 된 작업이 제거 되었습니다."
#: Controller/JobsController.php:159
msgid "All jobs have been purged"
msgstr ""
msgstr "모든 작업이 제거 되었습니다."
#: Controller/ObjectReferencesController.php:37
msgid "Invalid object"
@ -677,19 +677,19 @@ msgstr "올바르지 않은 객체 참조"
#: Controller/ObjectTemplatesController.php:88
msgid "ObjectTemplate deleted"
msgstr ""
msgstr "오브젝트템플릿이 삭제 되었습니다."
#: Controller/ObjectsController.php:29
msgid "This action can only be reached via POST requests"
msgstr ""
msgstr "이 행위는 POST 요청을 통해 서만 이용할 수 있습니다."
#: Controller/ObjectsController.php:69;82
msgid "Invalid sharing group."
msgstr ""
msgstr "잘못 된 공유 그룹입니다."
#: Controller/ObjectsController.php:103
msgid "You don't have permissions to create objects."
msgstr ""
msgstr "오브젝트를 생성할 수있는 권한이 없습니다."
#: Controller/ObjectsController.php:131
#: Model/Template.php:25
@ -698,7 +698,7 @@ msgstr "올바르지 않은 양식입니다."
#: Controller/ObjectsController.php:303
msgid "You don't have permissions to edit objects."
msgstr ""
msgstr "오브젝트를 수정할 수있는 권한이 없습니다."
#: Controller/ObjectsController.php:317;328;427
msgid "Invalid object."

View File

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: misp\n"
"PO-Revision-Date: 2018-10-15 23:37\n"
"PO-Revision-Date: 2019-01-22 21:26\n"
"Last-Translator: SteveClement <steve@localhost.lu>\n"
"Language-Team: Portuguese, Brazilian\n"
"MIME-Version: 1.0\n"

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More