Merge branch '2.4' of github.com:MISP/MISP into decaying

pull/5032/head
mokaddem 2019-07-03 13:45:49 +02:00
commit 76cddeb264
No known key found for this signature in database
GPG Key ID: 164C473F627A06FA
224 changed files with 86321 additions and 24197 deletions

4
.gitignore vendored
View File

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

View File

@ -1,7 +1,6 @@
language: php
php:
- 7.0
- 7.1
- 7.2
- 7.3
@ -27,7 +26,9 @@ before_install:
install:
- sudo add-apt-repository -y ppa:deadsnakes/ppa
- sudo apt-get -y update
- sudo apt-get -y install python3.6 python3-pip python3.6-dev python3-nose libxml2-dev libzmq3-dev zlib1g-dev apache2 curl php-mysql php-dev php-cli libapache2-mod-php libfuzzy-dev php-mbstring libonig2
# Travis lacks entropy.
- sudo apt-get -y install haveged
- sudo apt-get -y install python3.6 python3-pip python3.6-dev python3-nose libxml2-dev libzmq3-dev zlib1g-dev apache2 curl php-mysql php-dev php-cli libapache2-mod-php libfuzzy-dev php-mbstring libonig4
- sudo apt-get -y dist-upgrade
- wget https://bootstrap.pypa.io/get-pip.py
- sudo python3.6 get-pip.py
@ -112,7 +113,8 @@ script:
- ./curl_tests.sh $AUTH
- popd
- pushd PyMISP
- pipenv install -d
# FIXME: should be install, but as lief is changing all the time, we have to use update instead: https://github.com/MISP/PyMISP/issues/391
- pipenv update -d
- pushd tests
- git clone https://github.com/viper-framework/viper-test-files.git
- popd

View File

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

837
INSTALL/INSTALL.debian.sh → INSTALL/INSTALL.sh Executable file → Normal file

File diff suppressed because it is too large Load Diff

5
INSTALL/INSTALL.sh.sfv Normal file
View File

@ -0,0 +1,5 @@
; Generated by RHash v1.3.8 on 2019-07-02 at 12:28.32
; Written by Kravchenko Aleksey (Akademgorodok) - http://rhash.sf.net/
;
; 99476 12:28.32 2019-07-02 INSTALL.sh
INSTALL.sh 064C49340280B33DA2078761BB649794D8E31F6C 86BA12B0F85366B89106C901341C43D39ABB4F1EF546143D40EE44CD7DA578F7 AAE62AA039BA822CD39A5937DCBD22F0AC991802DED6F94A0F9754BE87CA091E9EAF457C5AB1831E6C583F4F0B286BE3 D77A1290A34453EFCCA50970FED5BC7035C49652E35EDC4108D82A7C4BA3CF1F020B41D36DD2E80AA9A557CF3F176F370CFC797130E9956C859E48AC272832E8

1
INSTALL/INSTALL.sh.sha1 Normal file
View File

@ -0,0 +1 @@
064c49340280b33da2078761bb649794d8e31f6c INSTALL.sh

View File

@ -0,0 +1 @@
86ba12b0f85366b89106c901341c43d39abb4f1ef546143d40ee44cd7da578f7 INSTALL.sh

View File

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

View File

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

View File

@ -24,11 +24,11 @@
# 1/ For other Debian based Linux distributions, download script and run as **unprivileged** user |
#-------------------------------------------------------------------------------------------------|
#
# The following installs only MISP-core:
# $ curl -fsSL https://raw.githubusercontent.com/MISP/MISP/2.4/INSTALL/INSTALL.debian.sh | bash -s -- -c
# The following installs only MISP Core:
# $ wget --no-cache -O /tmp/INSTALL.sh https://raw.githubusercontent.com/MISP/MISP/2.4/INSTALL/INSTALL.sh ; bash /tmp/INSTALL.sh -c
#
# This will install MISP Core and misp-modules (recommended)
# $ curl -fsSL https://raw.githubusercontent.com/MISP/MISP/2.4/INSTALL/INSTALL.debian.sh | bash -s -- -c -M
# This will install MISP Core and misp-modules
# $ wget --no-cache -O /tmp/INSTALL.sh https://raw.githubusercontent.com/MISP/MISP/2.4/INSTALL/INSTALL.sh ; bash /tmp/INSTALL.sh -c -M
#
#
#-------------------------------------------------------|
@ -36,7 +36,7 @@
#-------------------------------------------------------|
#
# 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
# # wget --no-cache -O /tmp/misp-kali.sh https://raw.githubusercontent.com/MISP/MISP/2.4/INSTALL/INSTALL.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.
#
@ -49,7 +49,7 @@
# $ 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
# $ cd MISP/INSTALL ; ./INSTALL.tpl.sh
#
##
###
@ -117,15 +117,15 @@ generateInstaller () {
exit 1
fi
if [[ $(echo $0 |grep -e '^\.\/') != "./INSTALL.debian.tpl.sh" ]]; then
if [[ $(echo $0 |grep -e '^\.\/') != "./INSTALL.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 "To generate the installer call it with './INSTALL.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 .
cp ../INSTALL.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
@ -139,39 +139,43 @@ generateInstaller () {
# TODO: Fix the below.
# $ for f in `echo ls [0-9]_*`; do
# $ perl -pe 's/## ${f} ##/`cat ${f}`/ge' -i INSTALL.debian.sh
# $ perl -pe 's/## ${f} ##/`cat ${f}`/ge' -i INSTALL.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/^## 0_installDepsPhp70.sh ##/`cat 0_installDepsPhp70.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
perl -pe 's/^## 0_global-vars.sh ##/`cat 0_global-vars.sh`/ge' -i INSTALL.tpl.sh
perl -pe 's/^## 0_apt-upgrade.sh ##/`cat 0_apt-upgrade.sh`/ge' -i INSTALL.tpl.sh
perl -pe 's/^## 0_sudoKeeper.sh ##/`cat 0_sudoKeeper.sh`/ge' -i INSTALL.tpl.sh
perl -pe 's/^## 0_installCoreDeps.sh ##/`cat 0_installCoreDeps.sh`/ge' -i INSTALL.tpl.sh
perl -pe 's/^## 0_installDepsPhp73.sh ##/`cat 0_installDepsPhp73.sh`/ge' -i INSTALL.tpl.sh
perl -pe 's/^## 0_installDepsPhp72.sh ##/`cat 0_installDepsPhp72.sh`/ge' -i INSTALL.tpl.sh
perl -pe 's/^## 0_installDepsPhp70.sh ##/`cat 0_installDepsPhp70.sh`/ge' -i INSTALL.tpl.sh
perl -pe 's/^## 1_prepareDB.sh ##/`cat 1_prepareDB.sh`/ge' -i INSTALL.tpl.sh
perl -pe 's/^## 1_apacheConfig.sh ##/`cat 1_apacheConfig.sh`/ge' -i INSTALL.tpl.sh
perl -pe 's/^## 1_mispCoreInstall.sh ##/`cat 1_mispCoreInstall.sh`/ge' -i INSTALL.tpl.sh
perl -pe 's/^## 1_installCake.sh ##/`cat 1_installCake.sh`/ge' -i INSTALL.tpl.sh
perl -pe 's/^## 2_permissions.sh ##/`cat 2_permissions.sh`/ge' -i INSTALL.tpl.sh
perl -pe 's/^## 2_configMISP.sh ##/`cat 2_configMISP.sh`/ge' -i INSTALL.tpl.sh
perl -pe 's/^## 0_support-functions.sh ##/`cat 0_support-functions.sh`/ge' -i INSTALL.tpl.sh
perl -pe 's/^## 2_gnupg.sh ##/`cat 2_gnupg.sh`/ge' -i INSTALL.tpl.sh
perl -pe 's/^## 2_logRotation.sh ##/`cat 2_logRotation.sh`/ge' -i INSTALL.tpl.sh
perl -pe 's/^## 2_backgroundWorkers.sh ##/`cat 2_backgroundWorkers.sh`/ge' -i INSTALL.tpl.sh
perl -pe 's/^## 2_core-cake.sh ##/`cat 2_core-cake.sh`/ge' -i INSTALL.tpl.sh
perl -pe 's/^## 3_misp-modules.sh ##/`cat 3_misp-modules.sh`/ge' -i INSTALL.tpl.sh
perl -pe 's/^## 4_misp-dashboard-cake.sh ##/`cat 4_misp-dashboard-cake.sh`/ge' -i INSTALL.tpl.sh
perl -pe 's/^## 4_misp-dashboard.sh ##/`cat 4_misp-dashboard.sh`/ge' -i INSTALL.tpl.sh
perl -pe 's/^## 5_mail_to_misp.sh ##/`cat 5_mail_to_misp.sh`/ge' -i INSTALL.tpl.sh
perl -pe 's/^## 6_viper.sh ##/`cat 6_viper.sh`/ge' -i INSTALL.tpl.sh
perl -pe 's/^## 6_ssdeep.sh ##/`cat 6_ssdeep.sh`/ge' -i INSTALL.tpl.sh
cp INSTALL.debian.tpl.sh ../INSTALL.debian.sh
cp INSTALL.tpl.sh ../INSTALL.sh
cd ..
for ALGO in $(echo "1 256 384 512"); do
shasum -a ${ALGO} INSTALL.sh > INSTALL.sh.sha${ALGO}
done
[[ "$(which rhash > /dev/null 2>&1 ; echo $?)" == "0" ]] && rhash --sfv --sha1 --sha256 --sha384 --sha512 INSTALL.sh > INSTALL.sh.sfv
rm -rf installer
echo -e "${LBLUE}Generated INSTALL.debian.sh${NC}"
echo -e "${LBLUE}Generated INSTALL.sh${NC}"
exit 0
}
@ -204,6 +208,7 @@ installSupported () {
# Check if sudo is installed and etckeeper - functionLocation('generic/sudo_etckeeper.md')
[[ -n $CORE ]] || [[ -n $ALL ]] && checkSudoKeeper 2> /dev/null > /dev/null
[[ ! -z ${MISP_USER} ]] && [[ ! -f /etc/sudoers.d/misp ]] && echo "%${MISP_USER} ALL=(ALL:ALL) NOPASSWD:ALL" |sudo tee /etc/sudoers.d/misp
progress 4
# Set locale if not set - functionLocation('generic/supportFunctions.md')
@ -390,7 +395,7 @@ installMISPonKali () {
debug "git clone, submodule update everything"
mkdir $PATH_TO_MISP
chown www-data:www-data $PATH_TO_MISP
chown $WWW_USER:$WWW_USER $PATH_TO_MISP
cd $PATH_TO_MISP
$SUDO_WWW git clone https://github.com/MISP/MISP.git $PATH_TO_MISP
@ -413,43 +418,43 @@ installMISPonKali () {
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
chown $WWW_USER:$WWW_USER /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
$SUDO_WWW 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
$SUDO_WWW ${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
$SUDO_WWW ${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
$SUDO_WWW ${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
$SUDO_WWW ${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
$SUDO_WWW ${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
$SUDO_WWW ${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
@ -460,6 +465,12 @@ installMISPonKali () {
# install python-magic
$SUDO_WWW ${PATH_TO_MISP}/venv/bin/pip install python-magic 2> /dev/null > /dev/null
# install plyara
$SUDO_WWW ${PATH_TO_MISP}/venv/bin/pip install plyara 2> /dev/null > /dev/null
# install zmq needed by mispzmq
$SUDO_WWW ${PATH_TO_MISP}/venv/bin/pip install zmq 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
@ -472,7 +483,7 @@ installMISPonKali () {
$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
chown -R $WWW_USER:$WWW_USER $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
@ -502,7 +513,7 @@ installMISPonKali () {
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 USAGE ON *.* TO $DBUSER_MISP@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;"
@ -562,7 +573,7 @@ installMISPonKali () {
$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
chown -R $WWW_USER:$WWW_USER $PATH_TO_MISP/app/Config
chmod -R 750 $PATH_TO_MISP/app/Config
debug "Setting up GnuPG"
@ -607,10 +618,13 @@ installMISPonKali () {
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
if [[ "$0" == "./INSTALL.tpl.sh" || "$(echo $0 |grep -o -e 'INSTALL.tpl.sh')" == "INSTALL.tpl.sh" ]]; then
generateInstaller
fi
debug "Checking if we are uptodate and checksums match"
checkInstaller
space
debug "Setting MISP variables"
MISPvars
@ -653,9 +667,38 @@ fi
[[ -n $NUKE ]] && nuke && exit
# TODO: Move support map to top
SUPPORT_MAP="
x86_64-centos-8
x86_64-rhel-7
x86_64-rhel-8
x86_64-fedora-30
x86_64-debian-stretch
x86_64-debian-buster
x86_64-ubuntu-bionic
armv6l-raspbian-stretch
armv7l-raspbian-stretch
armv7l-debian-jessie
armv7l-debian-stretch
armv7l-debian-buster
armv7l-ubuntu-bionic
"
# Check if we actually support this configuration
if ! echo "$SUPPORT_MAP" | grep "$(uname -m)-$FLAVOUR-$dist_version" >/dev/null; then
cat >&2 <<-'EOF'
Either your platform is not easily detectable or is not supported by this
installer script.
Please visit the following URL for more detailed installation instructions:
https://misp.github.io/MISP/
EOF
exit 1
fi
# 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])
RELEASE=$(lsb_release -s -r| tr '[:upper:]' '[:lower:]')
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"
@ -666,7 +709,9 @@ if [ "${FLAVOUR}" == "ubuntu" ]; then
installSupported && exit || exit
fi
if [ "${RELEASE}" == "19.04" ]; then
echo "Install on Ubuntu 19.04 not supported, bye"
echo "Install on Ubuntu 19.04 under development."
echo "Please report bugs/issues here: https://github.com/MISP/MISP/issues"
installSupported && exit || exit
exit 1
fi
if [ "${RELEASE}" == "19.10" ]; then
@ -679,7 +724,7 @@ 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])
CODE=$(lsb_release -s -c| tr '[:upper:]' '[:lower:]')
if [ "${CODE}" == "buster" ]; then
echo "Install on Debian testing fully supported."
echo "Please report bugs/issues here: https://github.com/MISP/MISP/issues"
@ -701,7 +746,7 @@ 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])
CODE=$(lsb_release -s -c| tr '[:upper:]' '[:lower:]')
if [ "${CODE}" == "bamboo" ]; then
echo "Install on Tsurugi Lab partially supported."
echo "Please report bugs/issues here: https://github.com/MISP/MISP/issues"

View File

@ -1269,13 +1269,13 @@ INSERT INTO `roles` (`id`, `name`, `created`, `modified`, `perm_add`, `perm_modi
VALUES (2, 'Org Admin', NOW(), NOW(), 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0);
INSERT INTO `roles` (`id`, `name`, `created`, `modified`, `perm_add`, `perm_modify`, `perm_modify_org`, `perm_publish`, `perm_publish_zmq`, `perm_publish_kafka`, `perm_sync`, `perm_admin`, `perm_audit`, `perm_full`, `perm_auth`, `perm_regexp_access`, `perm_tagger`, `perm_site_admin`, `perm_template`, `perm_sharing_group`, `perm_tag_editor`, `perm_delegate`, `perm_sighting`, `perm_object_template`, `default_role`)
VALUES (3, 'User', NOW(), NOW(), 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1);
VALUES (3, 'User', NOW(), NOW(), 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1);
INSERT INTO `roles` (`id`, `name`, `created`, `modified`, `perm_add`, `perm_modify`, `perm_modify_org`, `perm_publish`, `perm_publish_zmq`, `perm_publish_kafka`, `perm_sync`, `perm_admin`, `perm_audit`, `perm_full`, `perm_auth`, `perm_regexp_access`, `perm_tagger`, `perm_site_admin`, `perm_template`, `perm_sharing_group`, `perm_tag_editor`, `perm_delegate`, `perm_sighting`, `perm_object_template`, `default_role`)
VALUES (4, 'Publisher', NOW(), NOW(), 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0);
VALUES (4, 'Publisher', NOW(), NOW(), 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0);
INSERT INTO `roles` (`id`, `name`, `created`, `modified`, `perm_add`, `perm_modify`, `perm_modify_org`, `perm_publish`, `perm_publish_zmq`, `perm_publish_kafka`, `perm_sync`, `perm_admin`, `perm_audit`, `perm_full`, `perm_auth`, `perm_regexp_access`, `perm_tagger`, `perm_site_admin`, `perm_template`, `perm_sharing_group`, `perm_tag_editor`, `perm_delegate`, `perm_sighting`, `perm_object_template`, `default_role`)
VALUES (5, 'Sync user', NOW(), NOW(), 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0);
VALUES (5, 'Sync user', NOW(), NOW(), 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0);
INSERT INTO `roles` (`id`, `name`, `created`, `modified`, `perm_add`, `perm_modify`, `perm_modify_org`, `perm_publish`, `perm_publish_zmq`, `perm_publish_kafka`, `perm_sync`, `perm_admin`, `perm_audit`, `perm_full`, `perm_auth`, `perm_regexp_access`, `perm_tagger`, `perm_site_admin`, `perm_template`, `perm_sharing_group`, `perm_tag_editor`, `perm_delegate`, `perm_sighting`, `perm_object_template`, `default_role`)
VALUES (6, 'Read Only', NOW(), NOW(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);

View File

@ -1,5 +1,23 @@
<VirtualHost *:80>
ServerAdmin serveradmin@misp.local
ServerName misp.local
# In theory not needed, left for debug purposes
# LogLevel warn
# ErrorLog /var/log/apache2/misp.local_p80_error.log
# CustomLog /var/log/apache2/misp.local_p80_access.log combined
Header always unset "X-Powered-By"
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R,L]
ServerSignature Off
</VirtualHost>
<VirtualHost *:443>
ServerAdmin me@me.local
ServerAdmin serveradmin@misp.local
ServerName misp.local
DocumentRoot /var/www/MISP/app/webroot
<Directory /var/www/MISP/app/webroot>

View File

@ -1,620 +0,0 @@
#!/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

2
PyMISP

@ -1 +1 @@
Subproject commit a68bd80ab9dceaee9674bd9a2b0bffc4f387fcdc
Subproject commit 583fb6592495ea358aad47a8a1ec92d43c13348a

View File

@ -56,7 +56,7 @@ MISP, Malware Information Sharing Platform and Threat Sharing, core functionalit
- **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**: 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.
- **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 Kafka publishing.
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.

View File

@ -1 +1 @@
{"major":2, "minor":4, "hotfix":105}
{"major":2, "minor":4, "hotfix":109}

View File

@ -65,7 +65,7 @@ class AdminShell extends AppShell
public function restartWorker()
{
if (empty($this->args[0]) || !is_numeric($this->args[0])) {
echo 'Usage: ' . APP . '/cake ' . 'Admin restartWorker [PID]';
echo 'Usage: ' . APP . '/cake ' . 'Admin restartWorker [PID]' . PHP_EOL;
}
$pid = $this->args[0];
$result = $this->Server->restartWorker($pid);
@ -85,7 +85,7 @@ class AdminShell extends AppShell
public function killWorker()
{
if (empty($this->args[0]) || !is_numeric($this->args[0])) {
echo 'Usage: ' . APP . '/cake ' . 'Admin killWorker [PID]';
echo 'Usage: ' . APP . '/cake ' . 'Admin killWorker [PID]' . PHP_EOL;
die();
}
$pid = $this->args[0];
@ -101,7 +101,7 @@ class AdminShell extends AppShell
public function startWorker()
{
if (empty($this->args[0])) {
echo 'Usage: ' . APP . '/cake ' . 'Admin startWorker [queue]';
echo 'Usage: ' . APP . '/cake ' . 'Admin startWorker [queue]' . PHP_EOL;
die();
}
$queue = $this->args[0];
@ -115,19 +115,18 @@ class AdminShell extends AppShell
}
public function updateJSON() {
$toUpdate = array('Galaxy', 'Noticelist', 'Warninglist', 'Taxonomy', 'ObjectTemplate');
echo 'Updating all JSON structures.' . PHP_EOL;
foreach ($toUpdate as $target) {
$result = $this->$target->update();
$results = $this->Server->updateJSON();
foreach ($results as $type => $result) {
if ($result !== false) {
echo sprintf(
__('%s updated.') . PHP_EOL,
Inflector::pluralize(Inflector::humanize($target))
Inflector::pluralize(Inflector::humanize($type))
);
} else {
echo sprintf(
__('Could not update %s.') . PHP_EOL,
Inflector::pluralize(Inflector::humanize($target))
Inflector::pluralize(Inflector::humanize($type))
);
}
}
@ -144,9 +143,9 @@ class AdminShell extends AppShell
$force = $value;
$result = $this->Galaxy->update($force);
if ($result) {
echo 'Galaxies updated';
echo 'Galaxies updated' . PHP_EOL;
} else {
echo 'Could not update Galaxies';
echo 'Could not update Galaxies' . PHP_EOL;
}
}
@ -154,34 +153,34 @@ class AdminShell extends AppShell
public function updateTaxonomies() {
$result = $this->Taxonomy->update();
if ($result) {
echo 'Taxonomies updated';
echo 'Taxonomies updated' . PHP_EOL;
} else {
echo 'Could not update Taxonomies';
echo 'Could not update Taxonomies' . PHP_EOL;
}
}
public function updateWarningLists() {
$result = $this->Galaxy->update();
if ($result) {
echo 'Warning lists updated';
echo 'Warning lists updated' . PHP_EOL;
} else {
echo 'Could not update warning lists';
echo 'Could not update warning lists' . PHP_EOL;
}
}
public function updateNoticeLists() {
$result = $this->Noticelist->update();
if ($result) {
echo 'Notice lists updated';
echo 'Notice lists updated' . PHP_EOL;
} else {
echo 'Could not update notice lists';
echo 'Could not update notice lists' . PHP_EOL;
}
}
# FIXME: Debug and make it work, fails to pass userId/orgId properly
# FIXME: Fails to pass userId/orgId properly, global update works.
public function updateObjectTemplates() {
if (empty($this->args[0])) {
echo 'Usage: ' . APP . '/cake ' . 'Admin updateNoticeLists [user_id]';
echo 'Usage: ' . APP . '/cake ' . 'Admin updateObjectTemplates [user_id]' . PHP_EOL;
} else {
$userId = $this->args[0];
$user = $this->User->find('first', array(
@ -191,14 +190,21 @@ class AdminShell extends AppShell
),
'fields' => array('User.id', 'User.org_id')
));
# If the user_id passed does not exist, do a global update.
if (empty($user)) {
echo 'User not found';
echo 'User with ID: ' . $userId . ' not found' . PHP_EOL;
$result = $this->ObjectTemplate->update();
if ($result) {
echo 'Object templates updated' . PHP_EOL;
} else {
echo 'Could not update object templates' . PHP_EOL;
}
} else {
$result = $this->ObjectTemplate->update($user, false,false);
if ($result) {
echo 'Object templates updated';
echo 'Object templates updated' . PHP_EOL;
} else {
echo 'Could not update object templates';
echo 'Could not update object templates' . PHP_EOL;
}
}
}
@ -276,15 +282,15 @@ class AdminShell extends AppShell
if ($value === 'true') $value = 1;
$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]';
echo 'Invalid parameters. Usage: ' . APP . 'Console/cake Admin setSetting [setting_name] [setting_value]' . PHP_EOL;
} else {
$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.';
echo 'Invalid setting "' . $setting_name . '". Please make sure that the setting that you are attempting to change exists and if a module parameter, the modules are running.' . PHP_EOL;
}
$result = $this->Server->serverSettingsEditValue($cli_user, $setting, $value);
if ($result === true) {
echo 'Setting changed.';
echo 'Setting "' . $setting_name . '" changed to ' . $value . PHP_EOL;
} else {
echo $result;
}
@ -309,11 +315,48 @@ 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;
$whoami = exec('whoami');
if ($whoami === 'httpd' || $whoami === 'www-data' || $whoami === 'apache') {
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;
} else {
die('This OS user is not allowed to run this command.'. PHP_EOL. 'Run it under `www-data` or `httpd`.' . PHP_EOL . 'You tried to run this command as: ' . $whoami . PHP_EOL);
}
}
public function updateApp() {
$whoami = exec('whoami');
if ($whoami === 'httpd' || $whoami === 'www-data' || $whoami === 'apache') {
$command = $this->args[0];
if (!empty($this->args[1])) {
$processId = $this->args[1];
$job = $this->Job->read(null, $processId);
} else { // create worker
$this->Job->create();
$job_data = array(
'worker' => 'prio',
'job_type' => 'update_app',
'job_input' => 'command: ' . $command,
'status' => 0,
'retries' => 0,
'org_id' => '',
'org' => '',
'message' => 'Updating.',
);
$this->Job->save($job_data);
$job = $this->Job->read(null, $this->Job->id);
}
$result = $this->Server->updateDatabase($command, false);
$job['Job']['progress'] = 100;
$job['Job']['message'] = 'Update done';
$this->Job->save($job);
} else {
die('This OS user is not allowed to run this command.' . PHP_EOL . 'Run it under `www-data` or `httpd`.' . PHP_EOL . 'You tried to run this command as: ' . $whoami . PHP_EOL);
}
}
public function getAuthkey() {
if (empty($this->args[0])) {
echo 'Invalid parameters. Usage: ' . APP . 'Console/cake Admin getAuthkey [user_email]' . PHP_EOL;
@ -380,7 +423,7 @@ class AdminShell extends AppShell
public function change_authkey()
{
if (empty($this->args[0])) {
echo 'MISP apikey command line tool.' . PHP_EOL . 'To assign a new random API key for a user: ' . APP . 'Console/cake Password [email]' . PHP_EOL . 'To assign a fixed API key: ' . APP . 'Console/cake Password [email] [authkey]';
echo 'MISP apikey command line tool.' . PHP_EOL . 'To assign a new random API key for a user: ' . APP . 'Console/cake Password [email]' . PHP_EOL . 'To assign a fixed API key: ' . APP . 'Console/cake Password [email] [authkey]' . PHP_EOL;
die();
}
if (!empty($this->args[1])) {
@ -394,7 +437,7 @@ class AdminShell extends AppShell
'fields' => array('User.id', 'User.email', 'User.authkey')
));
if (empty($user)) {
echo 'Invalid e-mail, user not found.';
echo 'Invalid e-mail, user not found.' . PHP_EOL;
die();
}
$user['User']['authkey'] = $authKey;
@ -405,4 +448,55 @@ class AdminShell extends AppShell
}
echo 'Updated, new key:' . PHP_EOL . $authKey . PHP_EOL;
}
public function getOptionParser() {
$parser = parent::getOptionParser();
$parser->addSubcommand('updateJSON', array(
'help' => __('Update the JSON definitions of MISP.'),
'parser' => array(
'arguments' => array(
'update' => array('help' => __('Update the submodules before ingestion.'), 'short' => 'u', 'boolean' => 1)
)
)
));
return $parser;
}
public function recoverSinceLastSuccessfulUpdate()
{
$this->loadModel('Log');
$logs = $this->Log->find('all', array(
'conditions' => array(
'action' => 'update_database',
'title LIKE ' => array(
'Successfuly executed the SQL query for %',
'Issues executing the SQL query for %'
)
),
'order' => 'id DESC'
));
$last_db_num = -1;
foreach ($logs as $i => $log) {
preg_match_all('/.* the SQL query for (\d+)/', $log['Log']['title'], $matches);
if (!empty($matches[1])) {
$last_db_num = $matches[1][0];
break;
}
}
if ($last_db_num > 0) {
echo __('Last DB num which was successfully executed: ') . h($last_db_num) . PHP_EOL;
// replay all update from that point.
$this->loadModel('AdminSetting');
$db_version = $this->AdminSetting->find('first', array('conditions' => array('setting' => 'db_version')));
if (!empty($db_version)) {
$db_version['AdminSetting']['value'] = $last_db_num;
$this->AdminSetting->save($db_version);
$this->Server->runUpdates(true);
} else {
echo __('Something went wrong. Could not find the existing db version') . PHP_EOL;
}
} else {
echo __('DB was never successfully updated or we are on a fresh install') . PHP_EOL;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -446,4 +446,5 @@ class ServerShell extends AppShell
$this->Task->id = $task['Task']['id'];
$this->Task->saveField('message', count($servers) . ' job(s) completed at ' . date('d/m/Y - H:i:s') . '.');
}
}

View File

@ -1,57 +1,18 @@
#!/usr/bin/env bash
# TODO: Put some logic inside if many worker PIDs are detected
# Extract base directory where this script is and cd into it
cd "${0%/*}"
# Set to the current webroot owner
WWW_USER=$(ls -l ../cake |awk {'print $3'}|tail -1)
# In most cases the owner of the cake script is also the user as which it should be executed.
if [[ "$USER" != "$WWW_USER" ]]; then
echo "You run this script as $USER and the owner of the cake command is $WWW_USER. This might be an issue."
fi
# Check if run as root
if [[ "$EUID" -eq "0" ]]; then
if [ "$EUID" -eq 0 ]; then
echo "Please DO NOT run the worker script as root"
exit 1
fi
# Check if jq is present and enable advanced checks
if [[ "$(jq -V > /dev/null 2> /dev/null; echo $?)" != 0 ]]; then
echo "jq is not installed, disabling advanced checks."
ADVANCED="0"
else
ADVANCED="1"
fi
# Extract base directory where this script is and cd into it
cd "${0%/*}"
../cake CakeResque.CakeResque stop --all
../cake CakeResque.CakeResque start --interval 5 --queue default
../cake CakeResque.CakeResque start --interval 5 --queue prio
../cake CakeResque.CakeResque start --interval 5 --queue cache
../cake CakeResque.CakeResque start --interval 5 --queue email
../cake CakeResque.CakeResque startscheduler --interval 5
if [[ "$ADVANCED" == "1" ]]; then
for worker in `echo cache default email prio scheduler`; do
workerStatus=$(../cake Admin getWorkers |tail -n +7 |jq -r ".$worker" |jq -r '.ok')
PIDcount=$(../cake admin getWorkers |tail -n +7 |jq -r ".$worker.workers" |grep pid | wc -l)
echo -n "$worker has $PIDcount PID(s)"
if [[ "$workerStatus" != "true" ]]; then
echo ", trying to restart."
if [[ "$worker" != "scheduler" ]]; then
../cake CakeResque.CakeResque start --interval 5 --queue $worker
else
../cake CakeResque.CakeResque startscheduler --interval 5
fi
else
echo ", up and running."
fi
done
exit 0
else
../cake CakeResque.CakeResque stop --all
../cake CakeResque.CakeResque start --interval 5 --queue default
../cake CakeResque.CakeResque start --interval 5 --queue prio
../cake CakeResque.CakeResque start --interval 5 --queue cache
../cake CakeResque.CakeResque start --interval 5 --queue email
../cake CakeResque.CakeResque startscheduler --interval 5
exit 0
fi
exit 0

View File

@ -0,0 +1,57 @@
#!/usr/bin/env bash
# TODO: Put some logic inside if many worker PIDs are detected
# Extract base directory where this script is and cd into it
cd "${0%/*}"
# Set to the current webroot owner
WWW_USER=$(ls -l ../cake |awk {'print $3'}|tail -1)
# In most cases the owner of the cake script is also the user as which it should be executed.
if [[ "$USER" != "$WWW_USER" ]]; then
echo "You run this script as $USER and the owner of the cake command is $WWW_USER. This might be an issue."
fi
# Check if run as root
if [[ "$EUID" -eq "0" ]]; then
echo "Please DO NOT run the worker script as root"
exit 1
fi
# Check if jq is present and enable advanced checks
if [[ "$(jq -V > /dev/null 2> /dev/null; echo $?)" != 0 ]]; then
echo "jq is not installed, disabling advanced checks."
ADVANCED="0"
else
ADVANCED="1"
fi
if [[ "$ADVANCED" == "1" ]]; then
for worker in `echo cache default email prio scheduler`; do
workerStatus=$(../cake Admin getWorkers |tail -n +7 |jq -r ".$worker" |jq -r '.ok')
PIDcount=$(../cake admin getWorkers |tail -n +7 |jq -r ".$worker.workers" |grep pid | wc -l)
echo -n "$worker has $PIDcount PID(s)"
if [[ "$workerStatus" != "true" ]]; then
echo ", trying to restart."
if [[ "$worker" != "scheduler" ]]; then
../cake CakeResque.CakeResque start --interval 5 --queue $worker
else
../cake CakeResque.CakeResque startscheduler --interval 5
fi
else
echo ", up and running."
fi
done
exit 0
else
../cake CakeResque.CakeResque stop --all
../cake CakeResque.CakeResque start --interval 5 --queue default
../cake CakeResque.CakeResque start --interval 5 --queue prio
../cake CakeResque.CakeResque start --interval 5 --queue cache
../cake CakeResque.CakeResque start --interval 5 --queue email
../cake CakeResque.CakeResque startscheduler --interval 5
exit 0
fi

View File

@ -46,10 +46,11 @@ class AppController extends Controller
public $helpers = array('Utility', 'OrgImg', 'FontAwesome');
private $__queryVersion = '65';
public $pyMispVersion = '2.4.103';
private $__queryVersion = '79';
public $pyMispVersion = '2.4.106';
public $phpmin = '7.0';
public $phprec = '7.2';
public $isApiAuthed = false;
public $baseurl = '';
public $sql_dump = false;
@ -251,6 +252,7 @@ class AppController extends Controller
}
$this->Session->renew();
$this->Session->write(AuthComponent::$sessionKey, $user['User']);
$this->isApiAuthed = true;
} else {
// User not authenticated correctly
// reset the session information
@ -372,7 +374,7 @@ class AppController extends Controller
$this->Auth->logout();
throw new MethodNotAllowedException($message);//todo this should pb be removed?
} else {
$this->Flash->error('Warning: MISP is currently disabled for all users. Enable it in Server Settings (Administration -> Server Settings -> MISP tab -> live)', array('clear' => 1));
$this->Flash->error('Warning: MISP is currently disabled for all users. Enable it in Server Settings (Administration -> Server Settings -> MISP tab -> live). An update might also be in progress, you can see the progress in ' , array('params' => array('url' => $baseurl . '/servers/advancedUpdate/', 'urlName' => 'Advanced Update'), 'clear' => 1));
}
}
@ -444,6 +446,28 @@ class AppController extends Controller
$this->set('isAclZmq', isset($role['perm_publish_zmq']) ? $role['perm_publish_zmq'] : false);
$this->set('isAclKafka', isset($role['perm_publish_kafka']) ? $role['perm_publish_kafka'] : false);
$this->userRole = $role;
if (Configure::read('MISP.log_paranoid')) {
$this->Log = ClassRegistry::init('Log');
$this->Log->create();
$change = 'HTTP method: ' . $_SERVER['REQUEST_METHOD'] . PHP_EOL . 'Target: ' . $this->here;
if (($this->request->is('post') || $this->request->is('put')) && !empty(Configure::read('MISP.log_paranoid_include_post_body'))) {
$payload = $this->request->data;
if (!empty($payload['_Token'])) {
unset($payload['_Token']);
}
$change .= PHP_EOL . 'Request body: ' . json_encode($payload);
}
$log = array(
'org' => $this->Auth->user('Organisation')['name'],
'model' => 'User',
'model_id' => $this->Auth->user('id'),
'email' => $this->Auth->user('email'),
'action' => 'request',
'title' => 'Paranoid log entry',
'change' => $change,
);
$this->Log->save($log);
}
} else {
$this->set('me', false);
}
@ -480,6 +504,9 @@ class AppController extends Controller
$this->Log = ClassRegistry::init('Log');
echo json_encode($this->Log->getDataSource()->getLog(false, false), JSON_PRETTY_PRINT);
}
if ($this->isApiAuthed && $this->_isRest()) {
session_destroy();
}
}
public function queryACL($debugType='findMissingFunctionNames', $content = false)
@ -498,7 +525,7 @@ class AppController extends Controller
private function __convertEmailToName($email)
{
$name = explode('@', $email);
$name = explode('@', (string)$email);
$name = explode('.', $name[0]);
foreach ($name as $key => $value) {
$name[$key] = ucfirst($value);
@ -641,7 +668,7 @@ class AppController extends Controller
foreach ($options['paramArray'] as $p) {
if (
isset($options['ordered_url_params'][$p]) &&
(!in_array(strtolower($options['ordered_url_params'][$p]), array('null', '0', false, 'false', null)))
(!in_array(strtolower((string)$options['ordered_url_params'][$p]), array('null', '0', false, 'false', null)))
) {
$data[$p] = $options['ordered_url_params'][$p];
$data[$p] = str_replace(';', ':', $data[$p]);
@ -835,7 +862,11 @@ class AppController extends Controller
}
$this->Server->updateDatabase($command);
$this->Flash->success('Done.');
$this->redirect(array('controller' => 'pages', 'action' => 'display', 'administration'));
if ($liveOff) {
$this->redirect(array('controller' => 'servers', 'action' => 'updateProgress'));
} else {
$this->redirect(array('controller' => 'pages', 'action' => 'display', 'administration'));
}
}
public function upgrade2324()

View File

@ -1197,7 +1197,7 @@ class AttributesController extends AppController
}
}
public function viewPicture($id, $thumbnail=false, $width=200, $height=200)
public function viewPicture($id, $thumbnail=false)
{
if (Validation::uuid($id)) {
$temp = $this->Attribute->find('first', array(
@ -1221,11 +1221,15 @@ class AttributesController extends AppController
'Attribute.id' => $id,
'Attribute.type' => 'attachment'
),
'withAttachments' => true,
'includeAllTags' => false,
'includeAttributeUuid' => true,
'flatten' => true
);
if ($this->_isRest()) {
$conditions['withAttachments'] = true;
}
$attribute = $this->Attribute->fetchAttributes($this->Auth->user(), $conditions);
if (empty($attribute)) {
throw new MethodNotAllowedException('Invalid attribute');
@ -1235,49 +1239,11 @@ class AttributesController extends AppController
if ($this->_isRest()) {
return $this->RestResponse->viewData($attribute['Attribute']['data'], $this->response->type());
} else {
$width = isset($this->request->params['named']['width']) ? $this->request->params['named']['width'] : 200;
$height = isset($this->request->params['named']['height']) ? $this->request->params['named']['height'] : 200;
$image_data = $this->Attribute->getPictureData($attribute, $thumbnail, $width, $height);
$extension = explode('.', $attribute['Attribute']['value']);
$extension = end($extension);
if (extension_loaded('gd')) {
$image = ImageCreateFromString(base64_decode($attribute['Attribute']['data']));
if (!$thumbnail) {
ob_start ();
switch ($extension) {
case 'gif':
imagegif($image);
break;
case 'jpg':
case 'jpeg':
imagejpeg($image);
break;
case 'png':
imagepng($image);
break;
default:
break;
}
$image_data = $extension != 'gif' ? ob_get_contents() : base64_decode($attribute['Attribute']['data']);
ob_end_clean ();
imagedestroy($image);
} else { // thumbnail requested, resample picture with desired dimension
$width = isset($this->request->params['named']['width']) ? $this->request->params['named']['width'] : 150;
$height = isset($this->request->params['named']['height']) ? $this->request->params['named']['height'] : 150;
if ($extension == 'gif') {
$image_data = base64_decode($attribute['Attribute']['data']);
} else {
$extension = 'jpg';
$imageTC = ImageCreateTrueColor($width, $height);
ImageCopyResampled($imageTC, $image, 0, 0, 0, 0, $width, $height, ImageSX($image), ImageSY($image));
ob_start ();
imagejpeg ($imageTC);
$image_data = ob_get_contents();
ob_end_clean ();
imagedestroy($image);
imagedestroy($imageTC);
}
}
} else {
$image_data = base64_decode($attribute['Attribute']['data']);
}
$this->response->type(strtolower(h($extension)));
$this->response->body($image_data);
$this->autoRender = false;
@ -1311,7 +1277,7 @@ class AttributesController extends AppController
}
if ($this->request->is('ajax')) {
if ($this->request->is('post')) {
if ($this->__delete($id, $hard)) {
if ($this->Attribute->deleteAttribute($id, $this->Auth->user(), $hard)) {
return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'success' => 'Attribute deleted.')), 'status'=>200, 'type' => 'json'));
} else {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Attribute was not deleted.')), 'status'=>200, 'type' => 'json'));
@ -1325,7 +1291,7 @@ class AttributesController extends AppController
if (!$this->request->is('post') && !$this->_isRest()) {
throw new MethodNotAllowedException();
}
if ($this->__delete($id, $hard)) {
if ($this->Attribute->deleteAttribute($id, $this->Auth->user(), $hard)) {
if ($this->_isRest() || $this->response->type() === 'application/json') {
$this->set('message', 'Attribute deleted.');
$this->set('_serialize', array('message'));
@ -1394,77 +1360,6 @@ class AttributesController extends AppController
}
}
// unification of the actual delete for the multi-select
private function __delete($id, $hard = false)
{
$this->Attribute->id = $id;
if (!$this->Attribute->exists()) {
return false;
}
$result = $this->Attribute->find('first', array(
'conditions' => array('Attribute.id' => $id),
'fields' => array('Attribute.*'),
'contain' => array('Event' => array(
'fields' => array('Event.*')
)),
));
if (empty($result)) {
throw new MethodNotAllowedException(__('Attribute not found or not authorised.'));
}
// check for permissions
if (!$this->_isSiteAdmin()) {
if ($result['Event']['locked']) {
if ($this->Auth->user('org_id') != $result['Event']['org_id'] || !$this->userRole['perm_sync']) {
throw new MethodNotAllowedException(__('Attribute not found or not authorised.'));
}
} else {
if ($this->Auth->user('org_id') != $result['Event']['orgc_id']) {
throw new MethodNotAllowedException(__('Attribute not found or not authorised.'));
}
}
}
$date = new DateTime();
if ($hard) {
$save = $this->Attribute->delete($id);
} else {
if (Configure::read('Security.sanitise_attribute_on_delete')) {
$result['Attribute']['category'] = 'Other';
$result['Attribute']['type'] = 'comment';
$result['Attribute']['value'] = 'deleted';
$result['Attribute']['comment'] = '';
$result['Attribute']['to_ids'] = 0;
}
$result['Attribute']['deleted'] = 1;
$result['Attribute']['timestamp'] = $date->getTimestamp();
$save = $this->Attribute->save($result);
$object_refs = $this->Attribute->Object->ObjectReference->find('all', array(
'conditions' => array(
'ObjectReference.referenced_type' => 0,
'ObjectReference.referenced_id' => $id,
),
'recursive' => -1
));
foreach ($object_refs as $ref) {
$ref['ObjectReference']['deleted'] = 1;
$this->Attribute->Object->ObjectReference->save($ref);
}
}
// attachment will be deleted with the beforeDelete() function in the Model
if ($save) {
// We have just deleted the attribute, let's also check if there are any shadow attributes that were attached to it and delete them
$this->loadModel('ShadowAttribute');
$this->ShadowAttribute->deleteAll(array('ShadowAttribute.old_id' => $id), false);
// remove the published flag from the event
$this->Attribute->Event->unpublishEvent($result['Event']['id']);
return true;
} else {
return false;
}
}
public function deleteSelected($id = false, $hard = false)
{
if (!$this->request->is('post')) {
@ -1531,11 +1426,11 @@ class AttributesController extends AppController
$successes = array();
foreach ($attributes as $a) {
if ($hard) {
if ($this->__delete($a['Attribute']['id'], true)) {
if ($this->Attribute->deleteAttribute($a['Attribute']['id'], $this->Auth->user(), true)) {
$successes[] = $a['Attribute']['id'];
}
} else {
if ($this->__delete($a['Attribute']['id'], $a['Attribute']['deleted'] == 1 ? true : false)) {
if ($this->Attribute->deleteAttribute($a['Attribute']['id'], $this->Auth->user(), $a['Attribute']['deleted'] == 1 ? true : false)) {
$successes[] = $a['Attribute']['id'];
}
}
@ -2038,7 +1933,8 @@ class AttributesController extends AppController
$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'
'includeProposals', 'returnFormat', 'published', 'limit', 'page', 'requested_attributes', 'includeContext', 'headerless',
'includeWarninglistHits', 'attackGalaxy', 'object_relation'
);
$filterData = array(
'request' => $this->request,
@ -2067,9 +1963,19 @@ class AttributesController extends AppController
$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, false, array('X-Result-Count' => $elementCounter, 'X-Export-Module-Used' => $returnFormat, 'X-Response-Format' => $responseType));
$renderView = '';
$final = $this->Attribute->restSearch($user, $returnFormat, $filters, false, false, $elementCounter, $renderView);
if (!empty($renderView) && !empty($final)) {
$this->layout = false;
$final = json_decode($final, true);
foreach ($final as $key => $data) {
$this->set($key, $data);
}
$this->render('/Events/module_views/' . $renderView);
} else {
$responseType = $this->Attribute->validFormats[$returnFormat][0];
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.
@ -2270,8 +2176,8 @@ class AttributesController extends AppController
{
// request handler for POSTed queries. If the request is a post, the parameters (apart from the key) will be ignored and replaced by the terms defined in the posted json or xml object.
// The correct format for both is a "request" root element, as shown by the examples below:
// For Json: {"request":{"policy": "walled-garden","garden":"garden.example.com"}}
// For XML: <request><policy>walled-garden</policy><garden>garden.example.com</gargen></request>
// For Json: {"request":{"policy": "Local-Data","walled_garden":"my.stop.page.net"}}
// For XML: <request><policy>Local-Data</policy><walled_garden>my.stop.page.net</walled_garden></request>
// the response type is used to determine the parsing method (xml/json)
if ($this->request->is('post')) {
if ($this->request->input('json_decode', true)) {
@ -2280,7 +2186,7 @@ class AttributesController extends AppController
$data = $this->request->data;
}
if (empty($data)) {
throw new BadRequestException(__('Either specify the search terms in the url, or POST a json array / xml (with the root element being "request" and specify the correct headers based on content type.'));
throw new BadRequestException(__('Either specify the search terms in the url, or POST a json array / xml (with the root element being "request" and specify the correct headers based on content type).'));
}
$paramArray = array('eventId', 'tags', 'from', 'to', 'policy', 'walled_garden', 'ns', 'email', 'serial', 'refresh', 'retry', 'expiry', 'minimum_ttl', 'ttl', 'enforceWarninglist', 'ns_alt');
foreach ($paramArray as $p) {
@ -2298,7 +2204,7 @@ class AttributesController extends AppController
${$sF} = false;
}
}
if (!in_array($policy, array('NXDOMAIN', 'NODATA', 'DROP', 'walled-garden'))) {
if (!in_array($policy, array('NXDOMAIN', 'NODATA', 'DROP', 'Local-Data', 'PASSTHRU', 'TCP-only'))) {
$policy = false;
}
App::uses('RPZExport', 'Export');
@ -3016,6 +2922,36 @@ class AttributesController extends AppController
$resultArray[$type][] = array($type => 'Enrichment service not reachable.');
continue;
}
$current_result = array();
if (isset($result['results']['Object'])) {
if (!empty($result['results']['Object'])) {
$objects = array();
foreach($result['results']['Object'] as $object) {
if (isset($object['Attribute']) && !empty($object['Attribute'])) {
$object_attributes = array();
foreach($object['Attribute'] as $object_attribute) {
array_push($object_attributes, array('object_relation' => $object_attribute['object_relation'], 'value' => $object_attribute['value']));
}
array_push($objects, array('name' => $object['name'], 'Attribute' => $object_attributes));
}
}
if (!empty($objects)) {
$current_result['Object'] = $objects;
}
}
unset($result['results']['Object']);
}
if (isset($result['results']['Attribute'])) {
if (!empty($result['results']['Attribute'])) {
$attributes = array();
foreach($result['results']['Attribute'] as $attribute) {
array_push($attributes, array('type' => $attribute['type'], 'value' => $attribute['value']));
}
$current_result['Attribute'] = $attributes;
}
unset($result['results']['Attribute']);
}
$resultArray[$type] = $current_result;
if (!empty($result['results'])) {
foreach ($result['results'] as $r) {
if (is_array($r['values']) && !empty($r['values'])) {

View File

@ -75,6 +75,7 @@ class ACLComponent extends Component
'delete' => array(),
'edit' => array(),
'index' => array(),
'massDelete' => array()
),
'eventDelegations' => array(
'acceptDelegation' => array('perm_add'),
@ -96,6 +97,7 @@ class ACLComponent extends Component
'create_dummy_event' => array(),
'create_massive_dummy_events' => array(),
'csv' => array('*'),
'cullEmptyEvents' => array(),
'delegation_index' => array('*'),
'delete' => array('perm_add'),
'deleteNode' => array('*'),
@ -249,6 +251,8 @@ class ACLComponent extends Component
'edit' => array('perm_add'),
'get_row' => array('perm_add'),
'orphanedObjectDiagnostics' => array(),
'proposeObjectsFromAttributes' => array('*'),
'groupAttributesIntoObject' => array('perm_add'),
'revise_object' => array('perm_add'),
'view' => array('*'),
),
@ -327,6 +331,7 @@ class ACLComponent extends Component
'add' => array(),
'cache' => array('perm_site_admin'),
'checkout' => array(),
'createSync' => array('perm_sync'),
'delete' => array(),
'deleteFile' => array(),
'edit' => array(),
@ -338,8 +343,11 @@ class ACLComponent extends Component
'getPyMISPVersion' => array('*'),
'getSubmodulesStatus' => array('perm_site_admin'),
'getSubmoduleQuickUpdateForm' => array('perm_site_admin'),
'getWorkers' => array(),
'getVersion' => array('*'),
'import' => ('perm_site_admin'),
'index' => array('OR' => array('perm_sync', 'perm_admin')),
'ondemandAction' => array(),
'postTest' => array('perm_sync'),
'previewEvent' => array(),
'previewIndex' => array(),
@ -358,6 +366,8 @@ class ACLComponent extends Component
'stopZeroMQServer' => array(),
'testConnection' => array('perm_sync'),
'update' => array(),
'updateJSON' => array(),
'updateProgress' => array(),
'updateSubmodule' => array(),
'uploadFile' => array(),
'clearWorkerQueue' => array()

View File

@ -47,7 +47,7 @@ class RestResponseComponent extends Component
Besides the parameters listed, other, format specific ones can be passed along (for example: requested_attributes and includeContext for the CSV export).
This API allows pagination via the page and limit parameters.",
'mandatory' => array('returnFormat'),
'optional' => array('page', 'limit', 'value' , 'type', 'category', 'org', 'tags', 'from', 'to', 'last', 'eventid', 'withAttachments', 'uuid', 'publish_timestamp', 'timestamp', 'enforceWarninglist', 'to_ids', 'deleted', 'includeEventUuid', 'includeEventTags', 'event_timestamp', 'threat_level_id', 'eventinfo', 'includeProposals'),
'optional' => array('page', 'limit', 'value' , 'type', 'category', 'org', 'tags', 'date', 'last', 'eventid', 'withAttachments', 'uuid', 'publish_timestamp', 'timestamp', 'enforceWarninglist', 'to_ids', 'deleted', 'includeEventUuid', 'includeEventTags', 'event_timestamp', 'threat_level_id', 'eventinfo', 'includeProposals'),
'params' => array()
)
),
@ -75,7 +75,7 @@ class RestResponseComponent extends Component
Besides the parameters listed, other, format specific ones can be passed along (for example: requested_attributes and includeContext for the CSV export).
This API allows pagination via the page and limit parameters.",
'mandatory' => array('returnFormat'),
'optional' => array('page', 'limit', 'value', 'type', 'category', 'org', 'tag', 'tags', 'searchall', 'from', 'to', 'last', 'eventid', 'withAttachments', 'metadata', 'uuid', 'published', 'publish_timestamp', 'timestamp', 'enforceWarninglist', 'sgReferenceOnly', 'eventinfo'),
'optional' => array('page', 'limit', 'value', 'type', 'category', 'org', 'tag', 'tags', 'searchall', 'date', 'last', 'eventid', 'withAttachments', 'metadata', 'uuid', 'published', 'publish_timestamp', 'timestamp', 'enforceWarninglist', 'sgReferenceOnly', 'eventinfo'),
'params' => array()
)
),
@ -228,6 +228,10 @@ class RestResponseComponent extends Component
'mandatory' => array('event', 'tag'),
'params' => array('tag_id')
),
'attachTagToObject' => array(
'description' => "Attach a Tag to an object, refenced by an UUID. Tag can either be a tag id or a tag name.",
'mandatory' => array('uuid', 'tag'),
)
),
'User' => array(
'admin_add' => array(
@ -421,10 +425,14 @@ class RestResponseComponent extends Component
} elseif (strtolower($format) == 'csv') {
$type = 'csv';
} else {
if (empty($format)) {
$type = 'json';
} else {
$type = $format;
}
if (!$raw) {
$response = json_encode($response, JSON_PRETTY_PRINT);
}
$type = 'json';
}
$cakeResponse = new CakeResponse(array('body'=> $response, 'status' => $code, 'type' => $type));
@ -671,6 +679,7 @@ class RestResponseComponent extends Component
'todayHighlight' => true,
'autoclose' => true
),
'help' => 'The user set date field on the event level. If you are using restSearch, you can use any of the valid time related filters (examples: 7d, timestamps, [14d, 7d] for ranges, etc.)'
),
'datefrom' => array(
'type' => 'date',
@ -830,7 +839,7 @@ class RestResponseComponent extends Component
'autoclose' => true
),
'help' => 'The date from which the event was published'
),
),
'gpgkey' => array(
'input' => 'text',
'type' => 'string',
@ -1529,6 +1538,7 @@ class RestResponseComponent extends Component
break;
}
}
private function __overwriteCategory($scope, &$field) {
$field['values'] = array_keys(ClassRegistry::init("Attribute")->categoryDefinitions);
}
@ -1552,7 +1562,7 @@ class RestResponseComponent extends Component
$field['values'] = $tags;
}
private function __overwriteNationality($scope, &$field) {
$field['values'] = array_keys(ClassRegistry::init("Organisation")->countries);
$field['values'] = ClassRegistry::init("Organisation")->countries;
}
private function __overwriteAction($scope, &$field) {
$field['values'] = array_keys(ClassRegistry::init("Log")->actionDefinitions);

View File

@ -27,13 +27,25 @@ class EventBlacklistsController extends AppController
public function index()
{
$passedArgsArray = array();
$passedArgs = $this->passedArgs;
$params = array();
$validParams = array('event_uuid', 'comment');
$validParams = array('event_uuid', 'comment', 'event_info', 'event_orgc');
foreach ($validParams as $validParam) {
if (!empty($this->params['named'][$validParam])) {
$params[$validParam] = $this->params['named'][$validParam];
}
}
if (!empty($this->params['named']['searchall'])) {
$params['AND']['OR'] = array(
'event_uuid' => $this->params['named']['searchall'],
'comment' => $this->params['named']['searchall'],
'event_info' => $this->params['named']['searchall'],
'event_orgc' => $this->params['named']['searchall']
);
}
$this->set('passedArgs', json_encode($passedArgs));
$this->set('passedArgsArray', $passedArgsArray);
$this->BlackList->index($this->_isRest(), $params);
}
@ -51,4 +63,39 @@ class EventBlacklistsController extends AppController
{
$this->BlackList->delete($this->_isRest(), $id);
}
public function massDelete()
{
if ($this->request->is('post') || $this->request->is('put')) {
$ids = $this->request->data['EventBlacklist']['ids'];
$event_ids = json_decode($ids, true);
if (empty($event_ids)) {
throw new NotFoundException(__('Invalid event IDs.'));
}
$result = $this->EventBlacklist->deleteAll(array('EventBlacklist.id' => $event_ids));
if ($result) {
if ($this->_isRest()) {
return $this->RestResponse->saveSuccessResponse('EventBlacklist', 'Deleted', $ids, $this->response->type());
} else {
$this->Flash->success('Blacklist entry removed');
$this->redirect(array('controller' => 'eventBlacklists', 'action' => 'index'));
}
} else {
$error = __('Failed to delete Event from EventBlacklist. Error: ') . PHP_EOL . h($result);
if ($this->_isRest()) {
return $this->RestResponse->saveFailResponse('EventBlacklist', 'Deleted', false, $error, $this->response->type());
} else {
$this->Flash->error($error);
$this->redirect(array('controller' => 'eventBlacklists', 'action' => 'index'));
}
}
} else {
$ids = json_decode($this->request->query('ids'), true);
if (empty($ids)) {
throw new NotFoundException(__('Invalid event IDs.'));
}
$this->set('event_ids', $ids);
}
}
}

View File

@ -1057,7 +1057,7 @@ class EventsController extends AppController
$conditions['overrideLimit'] = 1;
}
if (isset($filters['deleted'])) {
$conditions['deleted'] = $filters['deleted'] == 2 ? 0 : 1;
$conditions['deleted'] = $filters['deleted'] == 2 ? 0 : [0, 1];
}
if (isset($filters['toIDS']) && $filters['toIDS'] != 0) {
$conditions['to_ids'] = $filters['toIDS'] == 2 ? 0 : 1;
@ -1086,6 +1086,10 @@ class EventsController extends AppController
}
$event = $results[0];
$attributeTagsName = $this->Event->Attribute->AttributeTag->extractAttributeTagsNameFromEvent($event, 'both');
$this->set('attributeTags', array_values($attributeTagsName['tags']));
$this->set('attributeClusters', array_values($attributeTagsName['clusters']));
if (isset($filters['distribution'])) {
if (!is_array($filters['distribution'])) {
$filters['distribution'] = array($filters['distribution']);
@ -1187,7 +1191,11 @@ class EventsController extends AppController
$cortex_modules = $this->Module->getEnabledModules($this->Auth->user(), false, 'Cortex');
$this->set('cortex_modules', $cortex_modules);
}
$this->set('deleted', isset($filters['deleted']) ? ($filters['deleted'] == 2 ? 0 : 1) : 0);
$deleted = 0;
if (isset($filters['deleted'])) {
$deleted = $filters['deleted'] == 2 ? array(0, 1) : $filters['deleted'];
}
$this->set('deleted', $deleted);
$this->set('typeGroups', array_keys($this->Event->Attribute->typeGroupings));
$this->set('attributeFilter', isset($filters['attributeFilter']) ? $filters['attributeFilter'] : 'all');
$this->set('filters', $filters);
@ -1195,12 +1203,6 @@ class EventsController extends AppController
$this->set('advancedFilteringActive', $advancedFiltering['active'] ? 1 : 0);
$this->set('advancedFilteringActiveRules', $advancedFiltering['activeRules']);
$this->set('defaultFilteringRules', $this->defaultFilteringRules);
$attributeTags = $this->Event->Attribute->AttributeTag->getAttributesTags($this->Auth->user(), $event['Event']['id']);
$attributeTags = array_column($attributeTags, 'name');
$this->set('attributeTags', $attributeTags);
$attributeClusters = $this->Event->Attribute->AttributeTag->getAttributesClusters($this->Auth->user(), $event['Event']['id']);
$attributeClusters = array_column($attributeClusters, 'value');
$this->set('attributeClusters', $attributeClusters);
$this->disableCache();
$this->layout = 'ajax';
$this->loadModel('Sighting');
@ -1290,8 +1292,9 @@ class EventsController extends AppController
'Event' => array('eventDescriptions' => 'fieldDescriptions', 'analysisDescriptions' => 'analysisDescriptions', 'analysisLevels' => 'analysisLevels')
);
// workaround to get the event dates in to the attribute relations
// workaround to get the event dates in to the attribute relations and number of correlation per related event
$relatedDates = array();
$relatedEventCorrelationCount = array();
if (!empty($event['RelatedEvent'])) {
foreach ($event['RelatedEvent'] as $relation) {
$relatedDates[$relation['Event']['id']] = $relation['Event']['date'];
@ -1302,10 +1305,14 @@ class EventsController extends AppController
if (!empty($relatedDates[$relation['id']])) {
$event['RelatedAttribute'][$key][$key2]['date'] = $relatedDates[$relation['id']];
}
$relatedEventCorrelationCount[$relation['id']][$relation['value']] = 1;
}
}
}
}
foreach ($relatedEventCorrelationCount as $key => $relation) {
$relatedEventCorrelationCount[$key] = count($relatedEventCorrelationCount[$key]);
}
foreach ($dataForView as $m => $variables) {
if ($m === 'Event') {
@ -1340,6 +1347,9 @@ class EventsController extends AppController
}
}
}
$attributeTagsName = $this->Event->Attribute->AttributeTag->extractAttributeTagsNameFromEvent($event, 'both');
$this->set('attributeTags', array_values($attributeTagsName['tags']));
$this->set('attributeClusters', array_values($attributeTagsName['clusters']));
$startDate = $event['Event']['timestamp'];
$modDate = date("Y-m-d", $event['Event']['timestamp']);
$modificationMap[$modDate] = 1;
@ -1393,7 +1403,6 @@ class EventsController extends AppController
$sightingsData = $this->Event->getSightingData($event);
$this->set('sightingsData', $sightingsData);
$params = $this->Event->rearrangeEventForView($event, $filters, false, $sightingsData);
$this->params->params['paging'] = array($this->modelClass => $params);
$this->set('event', $event);
$dataForView = array(
@ -1461,12 +1470,19 @@ class EventsController extends AppController
$attributeUri = '/events/viewEventAttributes/' . $event['Event']['id'];
foreach ($this->params->named as $k => $v) {
if (!is_numeric($k)) {
$attributeUri .= '/' . $v;
if (is_array($v)) {
foreach ($v as $value) {
$attributeUri .= sprintf('/%s[]:%s', $k, $value);
}
} else {
$attributeUri .= sprintf('/%s:%s', $k, $v);
}
}
}
$orgTable = $this->Event->Orgc->find('list', array(
'fields' => array('Orgc.id', 'Orgc.name')
));
$this->set('relatedEventCorrelationCount', $relatedEventCorrelationCount);
$this->set('oldest_timestamp', $oldest_timestamp);
$this->set('required_taxonomies', $this->Event->getRequiredTaxonomies());
$this->set('orgTable', $orgTable);
@ -1476,12 +1492,6 @@ class EventsController extends AppController
$this->set('advancedFilteringActive', $advancedFiltering['active'] ? 1 : 0);
$this->set('advancedFilteringActiveRules', $advancedFiltering['activeRules']);
$this->set('defaultFilteringRules', $this->defaultFilteringRules);
$attributeTags = $this->Event->Attribute->AttributeTag->getAttributesTags($this->Auth->user(), $event['Event']['id']);
$attributeTags = array_column($attributeTags, 'name');
$this->set('attributeTags', $attributeTags);
$attributeClusters = $this->Event->Attribute->AttributeTag->getAttributesClusters($this->Auth->user(), $event['Event']['id']);
$attributeClusters = array_column($attributeClusters, 'value');
$this->set('attributeClusters', $attributeClusters);
$this->set('mitreAttackGalaxyId', $this->Event->GalaxyCluster->Galaxy->getMitreAttackGalaxyId());
$this->set('modificationMapCSV', $modificationMapCSV);
}
@ -1514,7 +1524,12 @@ class EventsController extends AppController
$conditions['includeAttachments'] = true;
}
if (isset($this->params['named']['deleted'])) {
$conditions['deleted'] = $this->params['named']['deleted'] == 2 ? 0 : 1;
// workaround for old instances trying to pull events with both deleted / non deleted data
if (($this->userRole['perm_sync'] && $this->_isRest() && !$this->userRole['perm_site_admin']) && $this->params['named']['deleted'] == 1) {
$conditions['deleted'] = array(0,1);
} else {
$conditions['deleted'] = $this->params['named']['deleted'] == 2 ? array(0,1) : $this->params['named']['deleted'];
}
}
if (isset($this->params['named']['toIDS']) && $this->params['named']['toIDS'] != 0) {
$conditions['to_ids'] = $this->params['named']['toIDS'] == 2 ? 0 : 1;
@ -1540,6 +1555,8 @@ class EventsController extends AppController
$conditions['includeFeedCorrelations'] = 1;
if (!$this->_isRest()) {
$conditions['includeGranularCorrelations'] = 1;
} else if (!empty($this->params['named']['includeGranularCorrelations'])) {
$conditions['includeGranularCorrelations'] = 1;
}
if (!isset($this->params['named']['includeServerCorrelations'])) {
$conditions['includeServerCorrelations'] = 1;
@ -1550,6 +1567,28 @@ class EventsController extends AppController
$conditions['includeServerCorrelations'] = $this->params['named']['includeServerCorrelations'];
}
$results = $this->Event->fetchEvent($this->Auth->user(), $conditions);
if (!empty($this->params['named']['includeGranularCorrelations'])) {
foreach ($results as $k => $event) {
if (!empty($event['RelatedAttribute'])) {
foreach ($event['RelatedAttribute'] as $attribute_id => $relation) {
foreach ($event['Attribute'] as $k2 => $attribute) {
if ((int)$attribute['id'] == $attribute_id) {
$results[$k]['Attribute'][$k2]['RelatedAttribute'][] = $relation;
break 2;
}
}
foreach ($event['Object'] as $k2 => $object) {
foreach ($object['Attribute'] as $k3 => $attribute) {
if ((int)$attribute['id'] == $attribute_id) {
$results[$k]['Object'][$k2]['Attribute'][$k3]['RelatedAttribute'][] = $relation;
break 3;
}
}
}
}
}
}
}
if (empty($results)) {
throw new NotFoundException(__('Invalid event'));
}
@ -1933,6 +1972,9 @@ class EventsController extends AppController
$this->set('info', $info);
$this->set('analysisDescriptions', $this->Event->analysisDescriptions);
$this->set('analysisLevels', $this->Event->analysisLevels);
if (isset($this->params['named']['extends'])) {
$this->set('extends_uuid', $this->params['named']['extends']);
}
}
public function addIOC($id)
@ -1998,7 +2040,7 @@ class EventsController extends AppController
throw new UnauthorizedException(__('You do not have permission to do that.'));
}
if ($this->request->is('post')) {
$original_file = !empty($this->data['Event']['original_file']) ? $this->data['Event']['stix']['name'] : None;
$original_file = !empty($this->data['Event']['original_file']) ? $this->data['Event']['stix']['name'] : '';
if ($this->_isRest()) {
$randomFileName = $this->Event->generateRandomFileName();
$tmpDir = APP . "files" . DS . "scripts" . DS . "tmp";
@ -2011,7 +2053,7 @@ class EventsController extends AppController
} elseif (is_numeric($result)) {
$event = $this->Event->fetchEvent($this->Auth->user(), array('eventid' => $result));
if (!empty($event)) {
return $this->RestResponse->viewData($event[0], $this->response->type());
return $this->RestResponse->viewData($event[0], 'json');
} else {
return $this->RestResponse->saveFailResponse('Events', 'upload_stix', false, 'Could not read saved event.', $this->response->type());
}
@ -2493,6 +2535,13 @@ class EventsController extends AppController
$errors = array();
// only allow form submit CSRF protection
if ($this->request->is('post') || $this->request->is('put')) {
if (!$this->_isRest()) {
$publishable = $this->Event->checkIfPublishable($id);
if ($publishable !== true) {
$this->Flash->error(__('Could not publish event - no tag for required taxonomies missing: %s', implode(', ', $publishable)));
$this->redirect(array('action' => 'view', $id));
}
}
// send out the email
$emailResult = $this->Event->sendAlertEmailRouter($id, $this->Auth->user(), $this->Event->data['Event']['publish_timestamp']);
if (is_bool($emailResult) && $emailResult == true) {
@ -2619,7 +2668,7 @@ class EventsController extends AppController
{
$filesize_units = array('B', 'KB', 'MB', 'GB', 'TB');
if ($this->_isSiteAdmin()) {
$this->Flash->info('Warning, you are logged in as a site admin, any export that you generate will contain the FULL UNRESTRICTED data-set. If you would like to generate an export for your own organisation, please log in with a different user.');
$this->Flash->info(__('Warning, you are logged in as a site admin, any export that you generate will contain the FULL UNRESTRICTED data-set. If you would like to generate an export for your own organisation, please log in with a different user.'));
}
// Check if the background jobs are enabled - if not, fall back to old export page.
if (Configure::read('MISP.background_jobs') && !Configure::read('MISP.disable_cached_exports')) {
@ -3279,9 +3328,9 @@ class EventsController extends AppController
$sgReferenceOnly = false
) {
$paramArray = array(
'value', 'type', 'category', 'org', 'tag', 'tags', 'searchall', 'from', 'to', 'last', 'eventid', 'withAttachments',
'value', 'type', 'category', 'object_relation', 'org', 'tag', 'tags', 'searchall', 'from', 'to', 'last', 'eventid', 'withAttachments',
'metadata', 'uuid', 'published', 'publish_timestamp', 'timestamp', 'enforceWarninglist', 'sgReferenceOnly', 'returnFormat',
'limit', 'page', 'requested_attributes', 'includeContext', 'headerless'
'limit', 'page', 'requested_attributes', 'includeContext', 'headerless', 'includeWarninglistHits', 'attackGalaxy', 'deleted'
);
$filterData = array(
'request' => $this->request,
@ -3309,9 +3358,20 @@ class EventsController extends AppController
$returnFormat = 'json';
}
$elementCounter = 0;
$final = $this->Event->restSearch($user, $returnFormat, $filters, false, false, $elementCounter);
$responseType = $this->Event->validFormats[$returnFormat][0];
return $this->RestResponse->viewData($final, $responseType, false, true, false, array('X-Result-Count' => $elementCounter, 'X-Export-Module-Used' => $returnFormat, 'X-Response-Format' => $responseType));
$renderView = false;
$final = $this->Event->restSearch($user, $returnFormat, $filters, false, false, $elementCounter, $renderView);
if (!empty($renderView) && !empty($final)) {
$this->layout = false;
$final = json_decode($final, true);
foreach ($final as $key => $data) {
$this->set($key, $data);
}
$this->render('/Events/module_views/' . $renderView);
} else {
$responseType = $this->Event->validFormats[$returnFormat][0];
return $this->RestResponse->viewData($final, $responseType, false, true, false, array('X-Result-Count' => $elementCounter, 'X-Export-Module-Used' => $returnFormat, 'X-Response-Format' => $responseType));
}
}
public function downloadOpenIOCEvent($key, $eventid, $enforceWarninglist = false)
@ -3447,7 +3507,6 @@ class EventsController extends AppController
'org_id' => $this->Auth->user('org_id'),
'orgc_id' => $this->Auth->user('org_id'),
'timestamp' => $ts,
'uuid' => CakeText::uuid(),
'user_id' => $this->Auth->user('id'),
));
$default['Event']['info'] = 'A junk event for load testing';
@ -3457,6 +3516,7 @@ class EventsController extends AppController
$default['Event']['distribution'] = '0';
for ($i = 0; $i < 50; $i++) {
$data = $default;
$data['Event']['uuid'] = CakeText::uuid();
for ($j = 0; $j < 3000; $j++) {
$value = mt_rand();
$data['Attribute'][] = array(
@ -3470,6 +3530,7 @@ class EventsController extends AppController
'comment' => '',
'uuid' => CakeText::uuid(),
'timestamp' => $ts,
'disable_correlation' => 1
);
}
$this->Event->create();
@ -3617,7 +3678,6 @@ class EventsController extends AppController
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'];
}
@ -3952,7 +4012,7 @@ class EventsController extends AppController
}
if ($this->request->is('post')) {
if (empty($this->request->data)) {
throw new BadRequestException(__('Either specify the search terms in the url, or POST an xml (with the root element being "request".'));
throw new BadRequestException(__('Either specify the search terms in the url, or POST an xml (with the root element being "request").'));
} else {
$data = $this->request->data;
}
@ -4204,60 +4264,60 @@ class EventsController extends AppController
// #TODO i18n
$exports = array(
'xml' => array(
'url' => '/events/restSearch/xml/false/false/false/false/false/false/false/false/false/' . $id . '/false.xml',
'url' => '/events/restSearch/xml/eventid:' . $id . '.xml',
'text' => 'MISP XML (metadata + all attributes)',
'requiresPublished' => false,
'checkbox' => true,
'checkbox_text' => 'Encode Attachments',
'checkbox_set' => '/events/restSearch/xml/false/false/false/false/false/false/false/false/false/' . $id . '/true.xml',
'checkbox_set' => '/events/restSearch/xml/eventid:' . $id . '/withAttachments:1.xml',
'checkbox_default' => true
),
'json' => array(
'url' => '/events/restSearch/json/false/false/false/false/false/false/false/false/false/' . $id . '/false.json',
'url' => '/events/restSearch/json/eventid:' . $id . '.json',
'text' => 'MISP JSON (metadata + all attributes)',
'requiresPublished' => false,
'checkbox' => true,
'checkbox_text' => 'Encode Attachments',
'checkbox_set' => '/events/restSearch/json/false/false/false/false/false/false/false/false/false/' . $id . '/true.json',
'checkbox_set' => '/events/restSearch/json/withAttachments:1/eventid:' . $id . '.json',
'checkbox_default' => true
),
'openIOC' => array(
'url' => '/events/downloadOpenIOCEvent/download/' . $id,
'text' => 'OpenIOC (all indicators marked to IDS)',
'requiresPublished' => true,
'requiresPublished' => false,
'checkbox' => false,
),
'csv' => array(
'url' => '/events/csv/download/' . $id,
'text' => 'CSV',
'requiresPublished' => true,
'requiresPublished' => false,
'checkbox' => true,
'checkbox_text' => 'Include non-IDS marked attributes',
'checkbox_set' => '/events/csv/download/' . $id . '/1'
),
'csv_with_context' => array(
'url' => '/events/csv/download/' . $id . '/0/0/0/0/1',
'url' => '/events/restSearch/returnFormat:csv/eventid:' . $id,
'text' => 'CSV with additional context',
'requiresPublished' => true,
'requiresPublished' => false,
'checkbox' => true,
'checkbox_text' => 'Include non-IDS marked attributes',
'checkbox_set' => '/events/csv/download/' . $id . '/1/0/0/0/1'
'checkbox_set' => '/events/restSearch/returnFormat:csv/to_ids:1||0/published:1||0/eventid:' . $id
),
'stix_xml' => array(
'url' => '/events/restSearch/stix/eventid:' . $id,
'text' => 'STIX XML (metadata + all attributes)',
'requiresPublished' => true,
'requiresPublished' => false,
'checkbox' => true,
'checkbox_text' => 'Encode Attachments',
'checkbox_set' => '/events/restSearch/stix/eventid:' . $id . '/withAttachments:1'
),
'stix_json' => array(
'url' => '/events/stix/download/' . $id . '.json',
'url' => '/events/restSearch/stix/eventid:' . $id . '.json',
'text' => 'STIX JSON (metadata + all attributes)',
'requiresPublished' => true,
'requiresPublished' => false,
'checkbox' => true,
'checkbox_text' => 'Encode Attachments',
'checkbox_set' => '/events/stix/download/' . $id . '/true.json'
'checkbox_set' => '/events/restSearch/stix/withAttachments:1/eventid:' . $id . '.json'
),
'stix2_json' => array(
'url' => '/events/restSearch/stix2/eventid:' . $id,
@ -4268,36 +4328,36 @@ class EventsController extends AppController
'checkbox_set' => '/events/restSearch/stix2/eventid:' . $id . '/withAttachments:1'
),
'rpz' => array(
'url' => '/attributes/rpz/download/false/' . $id,
'url' => '/attributes/restSearch/returnFormat:rpz/published:1||0/eventid:' . $id,
'text' => 'RPZ Zone file',
'requiresPublished' => true,
'requiresPublished' => false,
'checkbox' => false,
),
'suricata' => array(
'url' => '/events/nids/suricata/download/' . $id,
'url' => '/events/restSearch/returnFormat:suricata/published:1||0/eventid:' . $id,
'text' => 'Download Suricata rules',
'requiresPublished' => true,
'requiresPublished' => false,
'checkbox' => false,
),
'snort' => array(
'url' => '/events/nids/snort/download/' . $id,
'url' => '/events/restSearch/returnFormat:snort/published:1||0/eventid:' . $id,
'text' => 'Download Snort rules',
'requiresPublished' => true,
'requiresPublished' => false,
'checkbox' => false,
),
'bro' => array(
'url' => '/attributes/bro/download/all/false/' . $id,
'text' => 'Download Bro rules',
'requiresPublished' => true,
'requiresPublished' => false,
'checkbox' => false
),
'text' => array(
'url' => '/attributes/text/download/all/false/' . $id,
'text' => 'Export all attribute values as a text file',
'requiresPublished' => true,
'url' => '/attributes/restSearch/returnFormat:text/published:1||0/eventid:' . $id,
'requiresPublished' => false,
'checkbox' => true,
'checkbox_text' => 'Include non-IDS marked attributes',
'checkbox_set' => '/attributes/text/download/all/false/' . $id . '/true'
'checkbox_set' => '/attributes/restSearch/returnFormat:text/published:1||0/to_ids:1||0/eventid:' . $id
),
);
if ($event['Event']['published'] == 0) {
@ -4883,7 +4943,12 @@ class EventsController extends AppController
throw new Exception("Invalid options.");
}
$scoresDataAttr = $this->Event->Attribute->AttributeTag->getTagScores($eventId, $matrixTags);
$event = $this->Event->fetchEvent($this->Auth->user(), array('eventid' => $eventId, 'metadata' => true));
if (empty($event)) {
throw new NotFoundException(__('Event not found or you are not authorised to view it.'));
}
$scoresDataAttr = $this->Event->Attribute->AttributeTag->getTagScores($this->Auth->user(), $eventId, $matrixTags);
$scoresDataEvent = $this->Event->EventTag->getTagScores($eventId, $matrixTags);
$maxScore = 0;
$scoresData = array();
@ -4937,6 +5002,7 @@ class EventsController extends AppController
}
// end FIXME
$this->Galaxy->sortMatrixByScore($tabs, $scores);
if ($this->_isRest()) {
$json = array('matrix' => $tabs, 'scores' => $scores, 'instance-uuid' => $instanceUUID);
$this->response->type('json');
@ -5097,64 +5163,32 @@ class EventsController extends AppController
if (!is_array($result)) {
throw new Exception($result);
}
$defaultDistribution = 5;
if (!empty(Configure::read('MISP.default_attribute_distribution'))) {
$defaultDistribution = Configure::read('MISP.default_attribute_distribution');
if ($defaultDistribution == 'event') {
$defaultDistribution = 5;
}
}
$attributes = array();
$objects = array();
if (isset($result['results']['Attribute']) && !empty($result['results']['Attribute'])) {
foreach ($result['results']['Attribute'] as &$tmp_attribute) {
$tmp_attribute = $this->__fillAttribute($tmp_attribute, $defaultDistribution);
array_push($attributes, $tmp_attribute);
}
unset($result['results']['Attribute']);
}
if (isset($result['results']['Object']) && !empty($result['results']['Object'])) {
foreach ($result['results']['Object'] as $tmp_object) {
foreach ($tmp_object['Attribute'] as &$tmp_attribute) {
$tmp_attribute = $this->__fillAttribute($tmp_attribute, $defaultDistribution);
}
array_push($objects, $tmp_object);
}
unset($result['results']['Object']);
}
if (empty($attributes) && empty($objects)) {
$event = $this->Event->handleMispFormatFromModuleResult($result);
if (empty($event['Attribute']) && empty($event['Object'])) {
$this->__handleSimplifiedFormat($attribute, $module, $options, $result, $type);
} else {
$this->set('attributeValue', $attribute[0]['Attribute']['value']);
$this->set('module', $module);
$event = array('Event' => $attribute[0]['Event']);
$event['Attribute'] = $attributes;
$event['Object'] = $objects;
$this->set('event', $event);
if (!empty($result['results'])) {
$this->__handleSimplifiedFormat($attribute, $module, $options, $result, $type, $event = true, $render_name = 'resolved_misp_format');
} else {
$this->set('menuItem', 'enrichmentResults');
$this->set('title', 'Enrichment Results');
$this->render('resolved_misp_format');
$importComment = !empty($result['comment']) ? $result['comment'] : $attribute[0]['Attribute']['value'] . __(': Enriched via the ') . $module . ($type != 'Enrichment' ? ' ' . $type : '') . ' module';
$this->set('importComment', $importComment);
$event['Event'] = $attribute[0]['Event'];
$org_name = $this->Event->Orgc->find('first', array(
'conditions' => array('Orgc.id' => $event['Event']['orgc_id']),
'fields' => array('Orgc.name')
));
$event['Event']['orgc_name'] = $org_name['Orgc']['name'];
if ($attribute[0]['Object']['id']) {
$object_id = $attribute[0]['Object']['id'];
$initial_object = $this->Event->fetchInitialObject($event_id, $object_id);
if (!empty($initial_object)) {
$event['initialObject'] = $initial_object;
}
}
$this->set('event', $event);
$this->set('menuItem', 'enrichmentResults');
$this->set('title', 'Enrichment Results');
$this->render('resolved_misp_format');
}
}
private function __fillAttribute($attribute, $defaultDistribution)
{
if (!isset($attribute['category'])) {
$attribute['category'] = $this->Event->Attribute->typeDefinitions[$attribute['type']]['default_category'];
}
if (!isset($attribute['to_ids'])) {
$attribute['to_ids'] = $this->Event->Attribute->typeDefinitions[$attribute['type']]['to_ids'];
}
if (!isset($attribute['distribution'])) {
$attribute['distribution'] = $defaultDistribution;
}
return $attribute;
}
private function __queryOldEnrichment($attribute, $module, $options, $type)
{
$data = array('module' => $module, $attribute[0]['Attribute']['type'] => $attribute[0]['Attribute']['value'], 'event_id' => $attribute[0]['Attribute']['event_id'], 'attribute_uuid' => $attribute[0]['Attribute']['uuid']);
@ -5178,10 +5212,10 @@ class EventsController extends AppController
$this->__handleSimplifiedFormat($attribute, $module, $options, $result, $type);
}
private function __handleSimplifiedFormat($attribute, $module, $options, $result, $type, $event = false, $renderName = 'resolved_attributes')
private function __handleSimplifiedFormat($attribute, $module, $options, $result, $type, $event = false)
{
$resultArray = $this->Event->handleModuleResult($result, $attribute[0]['Attribute']['event_id']);
if (isset($result['comment']) && $result['comment'] != "") {
if (!empty($result['comment'])) {
$importComment = $result['comment'];
} else {
$importComment = $attribute[0]['Attribute']['value'] . __(': Enriched via the %s', $module) . ($type != 'Enrichment' ? ' ' . $type : '') . ' module';
@ -5218,10 +5252,10 @@ class EventsController extends AppController
$this->set('typeCategoryMapping', $typeCategoryMapping);
$this->set('title', 'Enrichment Results');
$this->set('importComment', $importComment);
$this->render($renderName);
$this->render('resolved_attributes');
}
public function handleModuleResults($eventId)
public function handleModuleResults($id)
{
if (!$this->userRole['perm_add']) {
throw new MethodNotAllowedException(__('Event not found or you don\'t have permissions to create attributes'));
@ -5230,6 +5264,15 @@ class EventsController extends AppController
if (!$this->Event->checkIfAuthorised($this->Auth->user(), $id)) {
throw new MethodNotAllowedException(__('Invalid event.'));
}
$resolved_data = json_decode($this->request->data['Event']['JsonObject'], true);
$data = json_decode($this->request->data['Event']['data'], true);
if (!empty($data['initialObject'])) {
$resolved_data['initialObject'] = $data['initialObject'];
}
unset($data);
$default_comment = $this->request->data['Event']['default_comment'];
$flashMessage = $this->Event->processModuleResultsDataRouter($this->Auth->user(), $resolved_data, $id, $default_comment);
$this->Flash->info($flashMessage);
$this->redirect(array('controller' => 'events', 'action' => 'view', $id));
} else {
throw new MethodNotAllowedException('This endpoint requires a POST request.');
@ -5335,34 +5378,44 @@ class EventsController extends AppController
if (!is_array($result)) {
throw new Exception($result);
}
$resultArray = $this->Event->handleModuleResult($result, $eventId);
if ($this->_isRest()) {
return $this->__pushFreetext(
$resultArray,
$eventId,
false,
false,
'soft'
);
}
if (isset($result['comment'])) {
$importComment = $result['comment'];
$importComment = !empty($result['comment']) ? $result['comment'] : 'Enriched via the ' . $module['name'] . ' module';
if (isset($module['mispattributes']['format']) && $module['mispattributes']['format'] === 'misp_standard') {
$event = $this->Event->handleMispFormatFromModuleResult($result);
$event['Event'] = array('id' => $eventId);
$this->set('event', $event);
$this->set('menuItem', 'importResults');
$render_name = 'resolved_misp_format';
} else {
$importComment = 'Enriched via the ' . $module['name'] . ' module';
}
$typeCategoryMapping = array();
foreach ($this->Event->Attribute->categoryDefinitions as $k => $cat) {
foreach ($cat['types'] as $type) {
$typeCategoryMapping[$type][$k] = $k;
$resultArray = $this->Event->handleModuleResult($result, $eventId);
if ($this->_isRest()) {
return $this->__pushFreetext(
$resultArray,
$eventId,
false,
false,
'soft'
);
}
}
foreach ($resultArray as $key => $result) {
$options = array(
'conditions' => array('OR' => array('Attribute.value1' => $result['value'], 'Attribute.value2' => $result['value'])),
'fields' => array('Attribute.type', 'Attribute.category', 'Attribute.value', 'Attribute.comment'),
'order' => false
);
$resultArray[$key]['related'] = $this->Event->Attribute->fetchAttributes($this->Auth->user(), $options);
$typeCategoryMapping = array();
foreach ($this->Event->Attribute->categoryDefinitions as $k => $cat) {
foreach ($cat['types'] as $type) {
$typeCategoryMapping[$type][$k] = $k;
}
}
foreach ($resultArray as $key => $result) {
$options = array(
'conditions' => array('OR' => array('Attribute.value1' => $result['value'], 'Attribute.value2' => $result['value'])),
'fields' => array('Attribute.type', 'Attribute.category', 'Attribute.value', 'Attribute.comment'),
'order' => false
);
$resultArray[$key]['related'] = $this->Event->Attribute->fetchAttributes($this->Auth->user(), $options);
}
$this->set('event', array('Event' => array('id' => $eventId)));
$this->set('resultArray', $resultArray);
$this->set('typeList', array_keys($this->Event->Attribute->typeDefinitions));
$this->set('defaultCategories', $this->Event->Attribute->defaultCategories);
$this->set('typeCategoryMapping', $typeCategoryMapping);
$render_name = 'resolved_attributes';
}
$distributions = $this->Event->Attribute->distributionLevels;
$sgs = $this->Event->SharingGroup->fetchAllAuthorised($this->Auth->user(), 'name', 1);
@ -5371,14 +5424,9 @@ class EventsController extends AppController
}
$this->set('distributions', $distributions);
$this->set('sgs', $sgs);
$this->set('event', array('Event' => array('id' => $eventId)));
$this->set('resultArray', $resultArray);
$this->set('typeList', array_keys($this->Event->Attribute->typeDefinitions));
$this->set('defaultCategories', $this->Event->Attribute->defaultCategories);
$this->set('typeCategoryMapping', $typeCategoryMapping);
$this->set('title', 'Import Results');
$this->set('importComment', $importComment);
$this->render('resolved_attributes');
$this->render($render_name);
}
}
$this->Flash->error($fail);
@ -5661,7 +5709,7 @@ class EventsController extends AppController
$this->layout = false;
$this->render('/Events/ajax/event_lock');
} else {
return $this->RestResponse->viewData('', $this->response->type());
return $this->RestResponse->viewData('', $this->response->type(), false, true);
}
}
@ -5845,4 +5893,34 @@ class EventsController extends AppController
$this->redirect('/events/view/' . $eventId);
}
}
public function cullEmptyEvents()
{
$eventIds = $this->Event->find('list', array(
'conditions' => array('Event.published' => 1),
'fields' => array('Event.id', 'Event.uuid'),
'recursive' => -1
));
$count = 0;
$this->Event->skipBlacklist = true;
foreach ($eventIds as $eventId => $eventUuid) {
$result = $this->Event->Attribute->find('first', array(
'conditions' => array('Attribute.event_id' => $eventId),
'recursive' => -1,
'fields' => array('Attribute.id', 'Attribute.event_id')
));
if (empty($result)) {
$this->Event->delete($eventId);
$count++;
}
}
$this->Event->skipBlacklist = null;
$message = __('%s event(s) deleted.', $count);
if ($this->_isRest()) {
return $this->RestResponse->viewData($message, $this->response->type());
} else {
$this->Flash->success($message);
$this->redirect($this->referer());
}
}
}

View File

@ -433,7 +433,7 @@ class FeedsController extends AppController
$this->redirect(array('action' => 'index'));
}
}
$message = __('Fetching the feed has successfuly completed.');
$message = __('Fetching the feed has successfully completed.');
if ($this->Feed->data['Feed']['source_format'] == 'misp') {
if (isset($result['add'])) {
$message .= ' Downloaded ' . count($result['add']) . ' new event(s).';

View File

@ -194,20 +194,30 @@ class GalaxiesController extends AppController
'recursive' => -1
));
$clusters = array();
$cluster_ids = array();
foreach ($data as $k => $cluster) {
$cluster_ids[] = $cluster['GalaxyCluster']['id'];
}
$synonyms = $this->Galaxy->GalaxyCluster->GalaxyElement->find('all', array(
'conditions' => array(
'GalaxyElement.galaxy_cluster_id' => $cluster_ids,
'GalaxyElement.key' => 'synonyms'
),
'recursive' => -1
));
$sorted_synonyms = array();
foreach ($synonyms as $synonym) {
$sorted_synonyms[$synonym['GalaxyElement']['galaxy_cluster_id']][] = $synonym;
}
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 ($temp as $element) {
$cluster['GalaxyCluster']['synonyms_string'][] = $element['GalaxyElement']['value'];
$cluster['GalaxyElement'][] = $element['GalaxyElement'];
if (!empty($sorted_synonyms[$cluster['GalaxyCluster']['id']])) {
foreach ($sorted_synonyms[$cluster['GalaxyCluster']['id']] as $element) {
$cluster['GalaxyCluster']['synonyms_string'][] = $element['GalaxyElement']['value'];
$cluster['GalaxyElement'][] = $element['GalaxyElement'];
}
unset($sorted_synonyms[$cluster['GalaxyCluster']['id']]);
}
unset($temp);
$cluster['GalaxyCluster']['synonyms_string'] = implode(', ', $cluster['GalaxyCluster']['synonyms_string']);
unset($cluster['GalaxyElement']);
$clusters[$cluster['GalaxyCluster']['type']][$cluster['GalaxyCluster']['value']] = $cluster['GalaxyCluster'];

View File

@ -378,27 +378,6 @@ class GalaxyClustersController extends AppController
$cluster = $cluster['GalaxyCluster'];
$tag_name = $cluster['tag_name'];
// fetch all attribute ids having the requested cluster
$attributeIds = $this->Event->Attribute->AttributeTag->find('list', array(
'contain' => array('Tag'),
'conditions' => array(
'Tag.name' => $tag_name
),
'fields' => array('attribute_id'),
'recursive' => -1
));
// fetch all related tags belonging to attack pattern
$attributeTags = $this->Event->Attribute->AttributeTag->find('all', array(
'contain' => array('Tag'),
'conditions' => array(
'attribute_id' => $attributeIds,
'Tag.name' => $attackPatternTagNames
),
'fields' => array('Tag.name, COUNT(DISTINCT event_id) as tag_count'),
'recursive' => -1,
'group' => array('Tag.name')
));
// fetch all event ids having the requested cluster
$eventIds = $this->Event->EventTag->find('list', array(
'contain' => array('Tag'),
@ -408,6 +387,27 @@ class GalaxyClustersController extends AppController
'fields' => array('event_id'),
'recursive' => -1
));
// fetch all attribute ids having the requested cluster
$attributes = $this->Event->Attribute->AttributeTag->find('all', array(
'contain' => array('Tag'),
'conditions' => array(
'Tag.name' => $tag_name
),
'fields' => array('attribute_id', 'event_id'),
'recursive' => -1
));
$attributeIds = array();
$additional_event_ids = array();
foreach ($attributes as $attribute) {
$attributeIds[] = $attribute['AttributeTag']['attribute_id'];
$additional_event_ids[$attribute['AttributeTag']['event_id']] = $attribute['AttributeTag']['event_id'];
}
$additional_event_ids = array_keys($additional_event_ids);
$eventIds = array_merge($eventIds, $additional_event_ids);
unset($attributes);
unset($additional_event_ids);
// fetch all related tags belonging to attack pattern
$eventTags = $this->Event->EventTag->find('all', array(
'contain' => array('Tag'),
@ -420,6 +420,21 @@ class GalaxyClustersController extends AppController
'group' => array('Tag.name')
));
// fetch all related tags belonging to attack pattern or belonging to an event having this cluster
$attributeTags = $this->Event->Attribute->AttributeTag->find('all', array(
'contain' => array('Tag'),
'conditions' => array(
'OR' => array(
'event_id' => $eventIds,
'attribute_id' => $attributeIds
),
'Tag.name' => $attackPatternTagNames
),
'fields' => array('Tag.name, COUNT(DISTINCT event_id) as tag_count'),
'recursive' => -1,
'group' => array('Tag.name')
));
$scores = array();
foreach ($attributeTags as $tag) {
$tagName = $tag['Tag']['name'];
@ -435,7 +450,7 @@ class GalaxyClustersController extends AppController
}
$maxScore = count($scores) > 0 ? max(array_values($scores)) : 0;
$matrixData = $this->GalaxyCluster->Galaxy->getMatrix($mitreAttackGalaxyId);
$matrixData = $this->GalaxyCluster->Galaxy->getMatrix($mitreAttackGalaxyId, $scores);
$tabs = $matrixData['tabs'];
$matrixTags = $matrixData['matrixTags'];
$killChainOrders = $matrixData['killChain'];

View File

@ -159,6 +159,8 @@ class LogsController extends AppController
'eventid' => $id,
'includeAllTags' => 1,
'sgReferenceOnly' => 1,
'deleted' => 1,
'deleted_proposals' => 1
));
$conditions = array(
'OR' => array(
@ -341,7 +343,11 @@ class LogsController extends AppController
'conditions' => $conditions,
'order' => array('Log.id' => 'DESC')
);
$this->set('list', $this->paginate());
$list = $this->paginate();
if (empty($this->Auth->user('Role')['perm_site_admin'])) {
$list = $this->Log->filterSiteAdminSensitiveLogs($list);
}
$this->set('list', $list);
// and store into session
$this->Session->write('paginate_conditions_log', $this->paginate);
@ -392,7 +398,11 @@ class LogsController extends AppController
}
$conditions = $this->__buildSearchConditions($filters);
$this->paginate['conditions'] = $conditions;
$this->set('list', $this->paginate());
$list = $this->paginate();
if (empty($this->Auth->user('Role')['perm_site_admin'])) {
$list = $this->Log->filterSiteAdminSensitiveLogs($list);
}
$this->set('list', $list);
// set the same view as the index page
$this->render('admin_index');

View File

@ -54,34 +54,7 @@ class ObjectReferencesController extends AppController
if (!isset($this->request->data['ObjectReference'])) {
$this->request->data['ObjectReference'] = $this->request->data;
}
$referenced_type = 1;
$target_object = $this->ObjectReference->Object->find('first', array(
'conditions' => array('Object.uuid' => $this->request->data['ObjectReference']['referenced_uuid'], 'Object.deleted' => 0),
'recursive' => -1,
'fields' => array('Object.id', 'Object.uuid', 'Object.event_id')
));
if (!empty($target_object)) {
$referenced_id = $target_object['Object']['id'];
$referenced_uuid = $target_object['Object']['uuid'];
if ($target_object['Object']['event_id'] != $object['Event']['id']) {
throw new NotFoundException('Invalid target. Target has to be within the same event.');
}
} else {
$target_attribute = $this->ObjectReference->Object->Attribute->find('first', array(
'conditions' => array('Attribute.uuid' => $this->request->data['ObjectReference']['referenced_uuid'], 'Attribute.deleted' => 0),
'recursive' => -1,
'fields' => array('Attribute.id', 'Attribute.uuid', 'Attribute.event_id')
));
if (empty($target_attribute)) {
throw new NotFoundException('Invalid target.');
}
if ($target_attribute['Attribute']['event_id'] != $object['Event']['id']) {
throw new NotFoundException('Invalid target. Target has to be within the same event.');
}
$referenced_id = $target_attribute['Attribute']['id'];
$referenced_uuid = $target_attribute['Attribute']['uuid'];
$referenced_type = 0;
}
list($referenced_id, $referenced_uuid, $referenced_type) = $this->ObjectReference->getReferencedInfo($this->request->data['ObjectReference']['referenced_uuid'], $object);
$relationship_type = empty($this->request->data['ObjectReference']['relationship_type']) ? '' : $this->request->data['ObjectReference']['relationship_type'];
if (!empty($this->request->data['ObjectReference']['relationship_type_select']) && $this->request->data['ObjectReference']['relationship_type_select'] !== 'custom') {
$relationship_type = $this->request->data['ObjectReference']['relationship_type_select'];

View File

@ -163,12 +163,22 @@ class ObjectTemplatesController extends AppController
public function index($all = false)
{
$passedArgsArray = array();
$passedArgs = $this->passedArgs;
if (!$all || !$this->_isSiteAdmin()) {
$this->paginate['conditions'][] = array('ObjectTemplate.active' => 1);
$this->set('all', false);
} else {
$this->set('all', true);
}
if (!empty($this->params['named']['searchall'])) {
$this->paginate['conditions']['AND']['OR'] = array(
'ObjectTemplate.uuid LIKE' => '%' . strtolower($this->params['named']['searchall']) . '%',
'LOWER(ObjectTemplate.name) LIKE' => '%' . strtolower($this->params['named']['searchall']) . '%',
'ObjectTemplate.meta-category LIKE' => '%' . strtolower($this->params['named']['searchall']) . '%',
'LOWER(ObjectTemplate.description) LIKE' => '%' . strtolower($this->params['named']['searchall']) . '%'
);
}
if ($this->_isRest()) {
$rules = $this->paginate;
unset($rules['limit']);
@ -180,6 +190,8 @@ class ObjectTemplatesController extends AppController
$objectTemplates = $this->paginate();
$this->set('list', $objectTemplates);
}
$this->set('passedArgs', json_encode($passedArgs));
$this->set('passedArgsArray', $passedArgsArray);
}
public function update($type = false, $force = false)

View File

@ -23,7 +23,7 @@ class ObjectsController extends AppController
}
}
public function revise_object($action, $event_id, $template_id, $object_id = false)
public function revise_object($action, $event_id, $template_id, $object_id = false, $similar_objects_display_threshold=15)
{
if (!$this->request->is('post') && !$this->request->is('put')) {
throw new MethodNotAllowedException(__('This action can only be reached via POST requests'));
@ -83,12 +83,62 @@ class ObjectsController extends AppController
}
$this->set('sg', $sg);
}
$multiple_template_elements = Hash::extract($template['ObjectTemplateElement'], sprintf('{n}[multiple=true]'));
$multiple_attribute_allowed = array();
foreach ($multiple_template_elements as $k => $template_element) {
$relation_type = $template_element['object_relation'] . ':' . $template_element['type'];
$multiple_attribute_allowed[$relation_type] = true;
}
$this->set('multiple_attribute_allowed', $multiple_attribute_allowed);
// try to fetch similar objects
$cur_attrs = Hash::extract($this->request->data, 'Attribute.{n}.value');
$conditions = array(
'event_id' => $event_id,
'value1' => $cur_attrs,
'object_id !=' => '0'
);
$similar_objects = $this->MispObject->Attribute->find('all', array(
'conditions' => $conditions,
'recursive' => -1,
'fields' => 'object_id, count(object_id) as similarity_amount',
'group' => 'object_id',
'order' => 'similarity_amount DESC'
));
$similar_object_ids = array();
$similar_object_similarity_amount = array();
foreach ($similar_objects as $obj) {
$similar_object_ids[] = $obj['Attribute']['object_id'];
$similar_object_similarity_amount[$obj['Attribute']['object_id']] = $obj[0]['similarity_amount'];
}
$this->set('distributionLevels', $this->MispObject->Attribute->distributionLevels);
$this->set('action', $action);
$this->set('template', $template);
$this->set('object_id', $object_id);
$this->set('event', $event);
$this->set('data', $this->request->data);
if (!empty($similar_object_ids)) {
$this->set('similar_objects_count', count($similar_object_ids));
$similar_object_ids = array_slice($similar_object_ids, 0, $similar_objects_display_threshold); // slice to honor the threshold
$similar_objects = $this->MispObject->fetchObjects($this->Auth->user(), array(
'conditions' => array(
'Object.id' => $similar_object_ids,
'Object.template_uuid' => $template['ObjectTemplate']['uuid']
)
));
foreach ($similar_objects as $key => $obj) {
$similar_objects[$key]['Object']['similarity_amount'] = $similar_object_similarity_amount[$obj['Object']['id']]; // sorting function cannot use external variables
}
usort($similar_objects, function ($a, $b) { // fetch Object returns object sorted by IDs, force the sort by the similarity amount
if ($a['Object']['similarity_amount'] == $b['Object']['similarity_amount']) {
return 0;
}
return ($a['Object']['similarity_amount'] > $b['Object']['similarity_amount']) ? -1 : 1;
});
$this->set('similar_objects', $similar_objects);
$this->set('similar_object_similarity_amount', $similar_object_similarity_amount);
$this->set('similar_objects_display_threshold', $similar_objects_display_threshold);
}
}
@ -176,6 +226,7 @@ class ObjectsController extends AppController
if (isset($this->request->data['request'])) {
$this->request->data = $this->request->data['request'];
}
if (isset($this->request->data['Object']['data'])) {
$this->request->data = json_decode($this->request->data['Object']['data'], true);
}
@ -302,7 +353,7 @@ class ObjectsController extends AppController
$this->set('element', $element);
}
public function edit($id)
public function edit($id, $update_template_available=false)
{
if (Validation::uuid($id)) {
$conditions = array('Object.uuid' => $id);
@ -354,6 +405,119 @@ class ObjectsController extends AppController
$this->Flash->error('Object cannot be edited, no valid template found.');
$this->redirect(array('controller' => 'events', 'action' => 'view', $object['Object']['event_id']));
}
$newer_template = $this->MispObject->ObjectTemplate->find('first', array(
'conditions' => array(
'ObjectTemplate.uuid' => $object['Object']['template_uuid'],
'ObjectTemplate.version >' => $object['Object']['template_version'],
),
'recursive' => -1,
'contain' => array(
'ObjectTemplateElement'
),
'order' => array('ObjectTemplate.version DESC')
));
if (!empty($newer_template)) {
$newer_template_version = $newer_template['ObjectTemplate']['version'];
// ignore IDs for comparison
$cur_template_temp = Hash::remove(Hash::remove($template['ObjectTemplateElement'], '{n}.id'), '{n}.object_template_id');
$newer_template_temp = Hash::remove(Hash::remove($newer_template['ObjectTemplateElement'], '{n}.id'), '{n}.object_template_id');
$template_difference = array();
// check how current template is included in the newer
foreach ($cur_template_temp as $cur_obj_rel) {
$flag_sim = false;
foreach ($newer_template_temp as $newer_obj_rel) {
$tmp = Hash::diff($cur_obj_rel, $newer_obj_rel);
if (count($tmp) == 0) {
$flag_sim = true;
break;
}
}
if (!$flag_sim) {
$template_difference[] = $cur_obj_rel;
}
}
$updateable_attribute = $object['Attribute'];
$not_updateable_attribute = array();
if (!empty($template_difference)) { // older template not completely embeded in newer
foreach ($template_difference as $temp_diff_element) {
foreach ($object['Attribute'] as $i => $attribute) {
if (
$attribute['object_relation'] == $temp_diff_element['object_relation']
&& $attribute['type'] == $temp_diff_element['type']
) { // This attribute cannot be merged automatically
$attribute['merge-possible'] = false;
$not_updateable_attribute[] = $attribute;
unset($updateable_attribute[$i]);
}
}
}
}
$this->set('updateable_attribute', $updateable_attribute);
$this->set('not_updateable_attribute', $not_updateable_attribute);
if ($update_template_available) { // template version bump requested
$template = $newer_template; // bump the template version
}
} else {
$newer_template_version = false;
}
if (isset($this->params['named']['revised_object'])) { // revised object data to be injected
$revised_object = json_decode(base64_decode($this->params['named']['revised_object']), true);
$revised_object_both = array('mergeable' => array(), 'notMergeable' => array());
// Loop through attributes to inject and perform the correct action
// (inject, duplicate, add warnings, ...) when applicable
foreach ($revised_object['Attribute'] as $attribute_to_inject) {
$flag_no_collision = true;
foreach ($object['Attribute'] as $attribute) {
if (
$attribute['object_relation'] == $attribute_to_inject['object_relation']
&& $attribute['type'] == $attribute_to_inject['type']
&& $attribute['value'] !== $attribute_to_inject['value']
) { // Collision on value
$multiple = !empty(Hash::extract($template['ObjectTemplateElement'], sprintf('{n}[object_relation=%s][type=%s][multiple=true]', $attribute['object_relation'], $attribute['type'])));
if ($multiple) { // if multiple is set, check if an entry exists already
$flag_entry_exists = false;
foreach ($object['Attribute'] as $attr) {
if (
$attr['object_relation'] == $attribute_to_inject['object_relation']
&& $attr['type'] == $attribute_to_inject['type']
&& $attr['value'] === $attribute_to_inject['value']
) {
$flag_entry_exists = true;
break;
}
}
if (!$flag_entry_exists) { // entry does no exists, can be duplicated
$attribute_to_inject['is_multiple'] = true;
$revised_object_both['mergeable'][] = $attribute_to_inject;
$object['Attribute'][] = $attribute_to_inject;
}
} else { // Collision on value, multiple not set => propose overwrite
$attribute_to_inject['current_value'] = $attribute['value'];
$attribute_to_inject['merge-possible'] = true; // the user can still swap value
$revised_object_both['notMergeable'][] = $attribute_to_inject;
}
$flag_no_collision = false;
} else if (
$attribute['object_relation'] == $attribute_to_inject['object_relation']
&& $attribute['type'] == $attribute_to_inject['type']
&& $attribute['value'] === $attribute_to_inject['value']
) { // all good, they are basically the same, do nothing
$revised_object_both['mergeable'][] = $attribute_to_inject;
$flag_no_collision = false;
}
}
if ($flag_no_collision) { // no collision, nor equalities => inject it straight away
$revised_object_both['mergeable'][] = $attribute_to_inject;
$object['Attribute'][] = $attribute_to_inject;
}
}
$this->set('revised_object', $revised_object_both);
}
$template = $this->MispObject->prepareTemplate($template, $object);
$enabledRows = false;
@ -426,6 +590,8 @@ class ObjectsController extends AppController
$this->set('template', $template);
$this->set('action', 'edit');
$this->set('object', $object);
$this->set('update_template_available', $update_template_available);
$this->set('newer_template_version', $newer_template_version);
$this->render('add');
}
@ -823,4 +989,154 @@ class ObjectsController extends AppController
$this->set('captured', $capturedObjects);
$this->set('unmapped', $unmappedAttributes);
}
function proposeObjectsFromAttributes($event_id, $selected_attributes='[]')
{
if (!$this->request->is('ajax')) {
throw new MethodNotAllowedException(__('This action can only be reached via AJAX.'));
}
$selected_attributes = json_decode($selected_attributes, true);
$res = $this->MispObject->validObjectsFromAttributeTypes($this->Auth->user(), $event_id, $selected_attributes);
$potential_templates = $res['templates'];
$attribute_types = $res['types'];
usort($potential_templates, function($a, $b) {
if ($a['ObjectTemplate']['id'] == $b['ObjectTemplate']['id']) {
return 0;
} else if (is_array($a['ObjectTemplate']['compatibility']) && is_array($b['ObjectTemplate']['compatibility'])) {
return count($a['ObjectTemplate']['compatibility']) > count($b['ObjectTemplate']['compatibility']) ? 1 : -1;
} else if (is_array($a['ObjectTemplate']['compatibility']) && !is_array($b['ObjectTemplate']['compatibility'])) {
return 1;
} else if (!is_array($a['ObjectTemplate']['compatibility']) && is_array($b['ObjectTemplate']['compatibility'])) {
return -1;
} else { // sort based on invalidTypes count
return count($a['ObjectTemplate']['invalidTypes']) > count($b['ObjectTemplate']['invalidTypes']) ? 1 : -1;
}
});
$this->set('potential_templates', $potential_templates);
$this->set('selected_types', $attribute_types);
$this->set('event_id', $event_id);
}
function groupAttributesIntoObject($event_id, $selected_template, $selected_attribute_ids='[]')
{
$event = $this->MispObject->Event->find('first', array(
'recursive' => -1,
'fields' => array('Event.id', 'Event.uuid', 'Event.orgc_id', 'Event.publish_timestamp'),
'conditions' => array('Event.id' => $event_id)
));
if (empty($event) || (!$this->_isSiteAdmin() && $event['Event']['orgc_id'] != $this->Auth->user('org_id'))) {
throw new NotFoundException(__('Invalid event.'));
}
$hard_delete_attribute = $event['Event']['publish_timestamp'] == 0;
if (!$this->request->is('ajax')) {
throw new MethodNotAllowedException(__('This action can only be reached via AJAX.'));
}
if ($this->request->is('post')) {
$template = $this->MispObject->ObjectTemplate->find('first', array(
'recursive' => -1,
'conditions' => array('ObjectTemplate.id' => $selected_template, 'ObjectTemplate.active' => true)
));
if (empty($template)) {
throw new NotFoundException(__('Invalid template.'));
}
$distribution = $this->request->data['Object']['distribution'];
$sharing_group_id = $this->request->data['Object']['sharing_group_id'];
$comment = $this->request->data['Object']['comment'];
$selected_attribute_ids = json_decode($this->request->data['Object']['selectedAttributeIds'], true);
$selected_object_relation_mapping = json_decode($this->request->data['Object']['selectedObjectRelationMapping'], true);
if ($distribution == 4) {
$sg = $this->MispObject->SharingGroup->find('first', array(
'conditions' => array('SharingGroup.id' => $sharing_group_id),
'recursive' => -1,
'fields' => array('SharingGroup.id', 'SharingGroup.name'),
'order' => false
));
if (empty($sg)) {
throw new NotFoundException(__('Invalid sharing group.'));
}
} else {
$sharing_group_id = 0;
}
$object = array(
'Object' => array(
'distribution' => $distribution,
'sharing_group_id' => $sharing_group_id,
'comment' => $comment,
),
'Attribute' => array()
);
$result = $this->MispObject->groupAttributesIntoObject($this->Auth->user(), $event_id, $object, $template, $selected_attribute_ids, $selected_object_relation_mapping, $hard_delete_attribute);
if (is_numeric($result)) {
$this->MispObject->Event->unpublishEvent($event_id);
return $this->RestResponse->saveSuccessResponse('Objects', 'Created from Attributes', $result, $this->response->type());
} else {
$error = __('Failed to create an Object from Attributes. Error: ') . PHP_EOL . h($result);
return $this->RestResponse->saveFailResponse('Objects', 'Created from Attributes', false, $error, $this->response->type());
}
} else {
$selected_attribute_ids = json_decode($selected_attribute_ids, true);
$selected_attributes = $this->MispObject->Attribute->fetchAttributes($this->Auth->user(), array('conditions' => array(
'Attribute.id' => $selected_attribute_ids,
'Attribute.event_id' => $event_id,
'Attribute.object_id' => 0
)));
if (empty($selected_attributes)) {
throw new MethodNotAllowedException(__('No Attribute selected.'));
}
$template = $this->MispObject->ObjectTemplate->find('first', array(
'recursive' => -1,
'conditions' => array('ObjectTemplate.id' => $selected_template, 'ObjectTemplate.active' => true),
'contain' => 'ObjectTemplateElement'
));
if (empty($template)) {
throw new NotFoundException(__('Invalid template.'));
}
$conformity_result = $this->MispObject->ObjectTemplate->checkTemplateConformityBasedOnTypes($template, $selected_attributes);
$skipped_attributes = 0;
foreach ($selected_attributes as $i => $attribute) {
if (in_array($attribute['Attribute']['type'], $conformity_result['invalidTypes'])) {
unset($selected_attributes[$i]);
$array_position = array_search($attribute['Attribute']['id'], $selected_attribute_ids);
unset($selected_attribute_ids[$array_position]);
$skipped_attributes++;
}
}
$object_relations = array();
foreach ($template['ObjectTemplateElement'] as $template_element) {
$object_relations[$template_element['type']][] = $template_element;
}
$object_references = $this->MispObject->ObjectReference->find('all', array(
'conditions' => array(
'ObjectReference.referenced_id' => $selected_attribute_ids,
),
'recursive' => -1
));
foreach ($object_references as $i => $object_reference) {
$temp_object = $this->MispObject->find('first', array('id' => $object_reference['ObjectReference']['object_id'], 'recursive' => -1));
$temp_attribute = $this->MispObject->Attribute->find('first', array('id' => $object_reference['ObjectReference']['referenced_id'], 'recursive' => -1));
if (!empty($temp_object) && !empty($temp_attribute)) {
$temp_object = $temp_object['Object'];
$temp_attribute = $temp_attribute['Attribute'];
$object_references[$i]['ObjectReference']['object_name'] = $temp_object['name'];
$object_references[$i]['ObjectReference']['attribute_name'] = sprintf('%s/%s: "%s"', $temp_attribute['category'], $temp_attribute['type'], $temp_attribute['value']);
}
}
$distributionData = $this->MispObject->Event->Attribute->fetchDistributionData($this->Auth->user());
$this->set('event_id', $event_id);
$this->set('hard_delete_attribute', $hard_delete_attribute);
$this->set('distributionData', $distributionData);
$this->set('distributionLevels', $this->MispObject->Attribute->distributionLevels);
$this->set('selectedTemplateTd', $selected_template);
$this->set('selectedAttributeIds', $selected_attribute_ids);
$this->set('template', $template);
$this->set('object_relations', $object_relations);
$this->set('attributes', $selected_attributes);
$this->set('skipped_attributes', $skipped_attributes);
$this->set('object_references', $object_references);
}
}
}

View File

@ -878,6 +878,7 @@ class ServersController extends AppController
$mixboxVersion = array(0 => __('Incorrect mixbox version installed, found $current, expecting $expected'), 1 => __('OK'));
$maecVersion = array(0 => __('Incorrect maec version installed, found $current, expecting $expected'), 1 => __('OK'));
$pymispVersion = array(0 => __('Incorrect PyMISP version installed, found $current, expecting $expected'), 1 => __('OK'));
$plyaraVersion = array(0 => __('Incorrect plyara version installed, found $current, expecting $expected'), 1 => __('OK'));
$sessionErrors = array(0 => __('OK'), 1 => __('High'), 2 => __('Alternative setting used'), 3 => __('Test failed'));
$moduleErrors = array(0 => __('OK'), 1 => __('System not enabled'), 2 => __('No modules found'));
@ -999,6 +1000,8 @@ class ServersController extends AppController
// check if the STIX and Cybox libraries are working and the correct version using the test script stixtest.py
$stix = $this->Server->stixDiagnostics($diagnostic_errors, $stixVersion, $cyboxVersion, $mixboxVersion, $maecVersion, $stix2Version, $pymispVersion);
$yaraStatus = $this->Server->yaraDiagnostics($diagnostic_errors);
// if GnuPG is set up in the settings, try to encrypt a test message
$gpgStatus = $this->Server->gpgDiagnostics($diagnostic_errors);
@ -1018,7 +1021,7 @@ class ServersController extends AppController
$sessionStatus = $this->Server->sessionDiagnostics($diagnostic_errors, $sessionCount);
$this->set('sessionCount', $sessionCount);
$additionalViewVars = array('gpgStatus', 'sessionErrors', 'proxyStatus', 'sessionStatus', 'zmqStatus', 'stixVersion', 'cyboxVersion', 'mixboxVersion', 'maecVersion', 'stix2Version', 'pymispVersion', 'moduleStatus', 'gpgErrors', 'proxyErrors', 'zmqErrors', 'stixOperational', 'stix', 'moduleErrors', 'moduleTypes');
$additionalViewVars = array('gpgStatus', 'sessionErrors', 'proxyStatus', 'sessionStatus', 'zmqStatus', 'stixVersion', 'cyboxVersion', 'mixboxVersion', 'maecVersion', 'stix2Version', 'pymispVersion', 'moduleStatus', 'yaraStatus', 'gpgErrors', 'proxyErrors', 'zmqErrors', 'stixOperational', 'stix', 'moduleErrors', 'moduleTypes');
}
// check whether the files are writeable
$writeableDirs = $this->Server->writeableDirsDiagnostics($diagnostic_errors);
@ -1100,7 +1103,13 @@ class ServersController extends AppController
} else {
shell_exec($prepend . APP . 'Console' . DS . 'cake CakeResque.CakeResque startscheduler -i 5 > /dev/null 2>&1 &');
}
$this->redirect('/servers/serverSettings/workers');
$message = __('Worker start signal sent');
if ($this->_isRest()) {
return $this->RestResponse->saveSuccessResponse('Servers', 'startWorker', $type, $this->response->type(), $message);
} else {
$this->Flash->info($message);
$this->redirect('/servers/serverSettings/workers');
}
}
public function stopWorker($pid)
@ -1109,7 +1118,20 @@ class ServersController extends AppController
throw new MethodNotAllowedException();
}
$this->Server->killWorker($pid, $this->Auth->user());
$this->redirect('/servers/serverSettings/workers');
$message = __('Worker stop signal sent');
if ($this->_isRest()) {
return $this->RestResponse->saveSuccessResponse('Servers', 'stopWorker', $pid, $this->response->type(), $message);
} else {
$this->Flash->info($message);
$this->redirect('/servers/serverSettings/workers');
}
}
public function getWorkers()
{
$issues = 0;
$worker_array = $this->Server->workerDiagnostics($issues);
return $this->RestResponse->viewData($worker_array);
}
private function __checkVersion()
@ -1165,6 +1187,9 @@ class ServersController extends AppController
}
$setting = $this->Server->getSettingData($setting_name);
if (!empty($setting['cli_only'])) {
throw new MethodNotAllowedException(__('This setting can only be edited via the CLI.'));
}
if ($this->request->is('get')) {
if ($setting != null) {
$value = Configure::read($setting['name']);
@ -1542,6 +1567,69 @@ class ServersController extends AppController
}
}
public function ondemandAction()
{
if (!$this->_isSiteAdmin()) {
throw new MethodNotAllowedException('You are not authorised to do that.');
}
$this->AdminSetting = ClassRegistry::init('AdminSetting');
$actions = $this->Server->actions_description;
$default_fields = array(
'title' => '',
'description' => '',
'liveOff' => false,
'recommendBackup' => false,
'exitOnError' => false,
'requirements' => '',
'url' => '/'
);
foreach($actions as $id => $action) {
foreach($default_fields as $field => $value) {
if (!isset($action[$field])) {
$actions[$id][$field] = $value;
}
}
$done = $this->AdminSetting->getSetting($id);
$actions[$id]['done'] = ($done == '1');
}
$this->set('actions', $actions);
$this->set('updateLocked', $this->Server->isUpdateLocked());
}
public function updateProgress()
{
if (!$this->_isSiteAdmin()) {
throw new MethodNotAllowedException('You are not authorised to do that.');
}
$update_progress = $this->Server->getUpdateProgress();
$current_index = $update_progress['current'];
$current_command = !isset($update_progress['commands'][$current_index]) ? '' : $update_progress['commands'][$current_index];
$lookup_string = preg_replace('/\s{2,}/', '', substr($current_command, 0, -1));
$sql_info = $this->Server->query("SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST;");
if (empty($sql_info)) {
$update_progress['process_list'] = array();
} else {
// retreive current update process
foreach($sql_info as $row) {
if (preg_replace('/\s{2,}/', '', $row['PROCESSLIST']['INFO']) == $lookup_string) {
$sql_info = $row['PROCESSLIST'];
break;
}
}
$update_progress['process_list'] = array();
$update_progress['process_list']['STATE'] = isset($sql_info['STATE']) ? $sql_info['STATE'] : '';
$update_progress['process_list']['PROGRESS'] = isset($sql_info['PROGRESS']) ? $sql_info['PROGRESS'] : 0;
$update_progress['process_list']['STAGE'] = isset($sql_info['STAGE']) ? $sql_info['STAGE'] : 0;
$update_progress['process_list']['MAX_STAGE'] = isset($sql_info['MAX_STAGE']) ? $sql_info['MAX_STAGE'] : 0;
}
if ($this->request->is('ajax')) {
return $this->RestResponse->viewData(h($update_progress), $this->response->type());
} else {
$this->set('updateProgress', $update_progress);
}
}
public function getSubmoduleQuickUpdateForm($submodule_path=false) {
$this->set('submodule', base64_decode($submodule_path));
$this->render('ajax/submodule_quick_update_form');
@ -1832,4 +1920,91 @@ misp.direct_call(relative_path, body)
$this->redirect(array('action' => 'index'));
}
}
public function updateJSON()
{
$results = $this->Server->updateJSON();
return $this->RestResponse->viewData($results, $this->response->type());
}
public function createSync()
{
if ($this->_isSiteAdmin()) {
throw new MethodNotAllowedException('Site admin accounts cannot be used to create server sync configurations.');
}
$baseurl = Configure::read('MISP.external_baseurl');
if (empty($baseurl)) {
$baseurl = Configure::read('MISP.baseurl');
if (empty($baseurl)) {
$baseurl = Router::url('/', true);
}
}
$server = array(
'Server' => array(
'url' => $baseurl,
'uuid' => Configure::read('MISP.uuid'),
'authkey' => $this->Auth->user('authkey'),
'Organisation' => array(
'name' => $this->Auth->user('Organisation')['name'],
'uuid' => $this->Auth->user('Organisation')['uuid']
)
)
);
if ($this->_isRest()) {
return $this->RestResponse->viewData($server, $this->response->type());
} else {
$this->set('server', $server);
}
}
public function import()
{
if ($this->request->is('post')) {
$server = $this->request->data;
if (isset($server['Server'])) {
$server = $server['Server'];
}
if (isset($server['json'])) {
$server = json_decode($server['json'], true)['Server'];
}
$this->loadModel('Organisation');
$org_id = $this->Organisation->captureOrg($server['Organisation'], $this->Auth->user());
$toSave = array(
'push' => 0,
'pull' => 0,
'caching_enabled' => 0,
'json' => '[]',
'push_rules' => '[]',
'pull_rules' => '[]',
'self_signed' => 0,
'org_id' => $this->Auth->user('org_id'),
'remote_org_id' => $org_id,
'name' => empty($server['name']) ? $server['url'] : $server['name'],
'url' => $server['url'],
'uuid' => $server['uuid'],
'authkey' => $server['authkey']
);
$this->Server->create();
$result = $this->Server->save($toSave);
if ($result) {
if ($this->_isRest()) {
$server = $this->Server->find('first', array(
'conditions' => array('Server.id' => $this->Server->id),
'recursive' => -1
));
return $this->RestResponse->viewData($server, $this->response->type());
} else {
$this->Flash->success(__('The server has been saved'));
$this->redirect(array('action' => 'index', $this->Server->id));
}
} else {
if ($this->_isRest()) {
return $this->RestResponse->saveFailResponse('Servers', 'addFromJson', false, $this->Server->validationErrors, $this->response->type());
} else {
$this->Flash->error(__('Could not save the server. Error: %s', json_encode($this->Server->validationErrors, true)));
$this->redirect(array('action' => 'index'));
}
}
}
}
}

View File

@ -19,9 +19,6 @@ class SightingsController extends AppController
// takes an attribute ID or UUID
public function add($id = false)
{
if (!$this->userRole['perm_add']) {
throw new MethodNotAllowedException('You are not authorised to add sightings data as you don\'t have write access.');
}
if ($this->request->is('post')) {
$now = time();
$values = false;

View File

@ -1064,14 +1064,15 @@ class TagsController extends AppController
if (!is_array($tag)) {
$tag = array($tag);
}
$conditions = array();
foreach ($tag as $k => $t) {
$tag[$k] = strtolower($t);
$conditions['OR'][] = array('LOWER(GalaxyCluster.value)' => $tag[$k]);
}
foreach ($tag as $k => $t) {
$conditions['OR'][] = array('AND' => array('GalaxyElement.key' => 'synonyms', 'LOWER(GalaxyElement.value) LIKE' => $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,

View File

@ -60,6 +60,7 @@ class TaxonomiesController extends AppController
$this->loadModel('AttributeTag');
foreach ($taxonomy['entries'] as $key => $value) {
$count = 0;
$count_a = 0;
if (!empty($value['existing_tag'])) {
foreach ($value['existing_tag'] as $et) {
$count = $this->EventTag->find('count', array(

View File

@ -19,7 +19,7 @@ class UsersController extends AppController
),
'contain' => array(
'Organisation' => array('id', 'name'),
'Role' => array('id', 'name', 'perm_auth')
'Role' => array('id', 'name', 'perm_auth', 'perm_site_admin')
)
);
@ -350,11 +350,16 @@ class UsersController extends AppController
),
'contain' => array(
'Organisation' => array('id', 'name'),
'Role' => array('id', 'name', 'perm_auth')
'Role' => array('id', 'name', 'perm_auth', 'perm_site_admin')
)
));
foreach ($users as $key => $value) {
unset($users['User']['password']);
if (empty($this->Auth->user('Role')['perm_site_admin'])) {
if ($value['Role']['perm_site_admin']) {
$users[$key]['User']['authkey'] = __('Redacted');
}
}
unset($users[$key]['User']['password']);
}
return $this->RestResponse->viewData($users, $this->response->type());
} else {
@ -366,7 +371,13 @@ class UsersController extends AppController
} else {
$conditions['User.org_id'] = $this->Auth->user('org_id');
$this->paginate['conditions']['AND'][] = $conditions;
$this->set('users', $this->paginate());
$users = $this->paginate();
foreach ($users as $key => $value) {
if ($value['Role']['perm_site_admin']) {
$users[$key]['User']['authkey'] = __('Redacted');
}
}
$this->set('users', $users);
}
if ($this->request->is('ajax')) {
$this->autoRender = false;
@ -462,6 +473,9 @@ class UsersController extends AppController
$user['User']['fingerprint'] = !empty($pgpDetails[4]) ? $pgpDetails[4] : 'N/A';
}
$user['User']['orgAdmins'] = $this->User->getOrgAdminsForOrg($user['User']['org_id'], $user['User']['id']);
if (empty($this->Auth->user('Role')['perm_site_admin']) && !(empty($user['Role']['perm_site_admin']))) {
$user['User']['authkey'] = __('Redacted');
}
$this->set('user', $user);
if (!$this->_isSiteAdmin() && !($this->_isAdmin() && $this->Auth->user('org_id') == $user['User']['org_id'])) {
throw new MethodNotAllowedException();
@ -694,9 +708,10 @@ class UsersController extends AppController
$params = array();
$allowedRole = '';
$userToEdit = $this->User->find('first', array(
'conditions' => array('id' => $id),
'conditions' => array('User.id' => $id),
'recursive' => -1,
'fields' => array('id', 'role_id', 'email', 'org_id'),
'fields' => array('User.id', 'User.role_id', 'User.email', 'User.org_id', 'Role.perm_site_admin'),
'contain' => array('Role')
));
if (!$this->_isSiteAdmin()) {
// Org admins should be able to select the role that is already assigned to an org user when editing them.
@ -706,8 +721,8 @@ class UsersController extends AppController
// MISP automatically chooses the first available option for the user as the selected setting (usually user)
// Org admin is downgraded to a user
// Now we make an exception for the already assigned role, both in the form and the actual edit.
if ($userToEdit['User']['org_id'] != $this->Auth->user('org_id')) {
throw new Exception('Invalid user');
if ($userToEdit['User']['org_id'] != $this->Auth->user('org_id') || !empty($userToEdit['Role']['perm_site_admin'])) {
throw new NotFoundException(__('Invalid user'));
}
$allowedRole = $userToEdit['User']['role_id'];
$params = array('conditions' => array(
@ -1906,94 +1921,149 @@ class UsersController extends AppController
} else {
$galaxy_id = $mitre_galaxy_id;
}
$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);
$organisations = $this->User->Organisation->find('all', array(
'recursive' => -1,
));
array_unshift($organisations, array('Organisation' => array('id' => 0, 'name' => 'All')));
$this->set('organisations', $organisations);
$picked_organisation = 0;
if (isset($params['organisation']) && $params['organisation'] != 0) {
$org = $this->User->Organisation->find('first', array(
'recursive' => -1,
'conditions' => array('id' => $params['organisation']),
));
if (!empty($org)) {
$picked_organisation = $org;
$this->set('picked_organisation', $picked_organisation);
} else {
$this->set('picked_organisation', array('Organisation' => array('id' => '')));
}
} else {
$this->set('picked_organisation', array('Organisation' => array('id' => '')));
}
$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'] == $mitre_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];
$rest_response_empty = true;
$ignore_score = false;
if (
isset($params['dateFrom'])
|| isset($params['dateTo'])
|| isset($params['organisation']) && $params['organisation'] != 0
) { // use restSearch
$ignore_score = true;
$filters = array();
if (isset($params['dateFrom'])) {
$filters['from'] = $params['dateFrom'];
$this->set('dateFrom', $params['dateFrom']);
}
if (isset($params['dateTo'])) {
$filters['to'] = $params['dateTo'];
$this->set('dateTo', $params['dateTo']);
}
if (isset($params['organisation'])) {
$filters['org'] = $params['organisation'];
}
$elementCounter = 0;
$renderView = '';
$final = $this->Event->restSearch($this->Auth->user(), 'attack', $filters, false, false, $elementCounter, $renderView);
$final = json_decode($final, true);
if (!empty($final)) {
$rest_response_empty = false;
foreach ($final as $key => $data) {
$this->set($key, $data);
}
}
}
// No need for restSearch or result is empty
if ($rest_response_empty) {
$matrixData = $this->Galaxy->getMatrix($galaxy_id);
$tabs = $matrixData['tabs'];
$matrixTags = $matrixData['matrixTags'];
$killChainOrders = $matrixData['killChain'];
$instanceUUID = $matrixData['instance-uuid'];
if ($ignore_score) {
$scores_uniform = array('scores' => array(), 'maxScore' => 0);
} else {
$scores_uniform = $this->Event->EventTag->getTagScoresUniform(0, $matrixTags);
}
$scores = $scores_uniform['scores'];
$maxScore = $scores_uniform['maxScore'];
// FIXME: temporary fix: add the score of deprecated mitre galaxies to the new one (for the stats)
if ($matrixData['galaxy']['id'] == $mitre_galaxy_id) {
$mergedScore = array();
foreach ($scores 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 {
$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];
$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')
));
if (!empty($adjustedTagName)) {
$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 = !empty($mergedScore) ? max(array_values($mergedScore)) : 0;
}
// end FIXME
if (isset($mergedScore[$mappedTag])) {
$mergedScore[$mappedTag] += $v;
} else {
$mergedScore[$mappedTag] = $v;
$this->Galaxy->sortMatrixByScore($tabs, $scores);
if ($this->_isRest()) {
$json = array('matrix' => $tabs, 'scores' => $scores, 'instance-uuid' => $instanceUUID);
return $this->RestResponse->viewData($json, $this->response->type());
} else {
App::uses('ColourGradientTool', 'Tools');
$gradientTool = new ColourGradientTool();
$colours = $gradientTool->createGradientFromValues($scores);
$this->set('target_type', 'attribute');
$this->set('columnOrders', $killChainOrders);
$this->set('tabs', $tabs);
$this->set('scores', $scores);
$this->set('maxScore', $maxScore);
if (!empty($colours)) {
$this->set('colours', $colours['mapping']);
$this->set('interpolation', $colours['interpolation']);
}
$this->set('pickingMode', false);
if ($matrixData['galaxy']['id'] == $mitre_galaxy_id) {
$this->set('defaultTabName', "mitre-attack");
$this->set('removeTrailling', 2);
}
$this->set('galaxyName', $matrixData['galaxy']['name']);
$this->set('galaxyId', $matrixData['galaxy']['id']);
$matrixGalaxies = $this->Galaxy->getAllowedMatrixGalaxies();
$this->set('matrixGalaxies', $matrixGalaxies);
}
$scores = $mergedScore;
$maxScore = max(array_values($mergedScore));
}
// end FIXME
if ($this->_isRest()) {
$json = array('matrix' => $tabs, 'scores' => $scores, 'instance-uuid' => $instanceUUID);
return $this->RestResponse->viewData($json, $this->response->type());
} else {
App::uses('ColourGradientTool', 'Tools');
$gradientTool = new ColourGradientTool();
$colours = $gradientTool->createGradientFromValues($scores);
$this->set('target_type', 'attribute');
$this->set('columnOrders', $killChainOrders);
$this->set('tabs', $tabs);
$this->set('scores', $scores);
$this->set('maxScore', $maxScore);
if (!empty($colours)) {
$this->set('colours', $colours['mapping']);
$this->set('interpolation', $colours['interpolation']);
}
$this->set('pickingMode', false);
if ($matrixData['galaxy']['id'] == $mitre_galaxy_id) {
$this->set('defaultTabName', "mitre-attack");
}
$this->set('removeTrailling', 2);
$this->set('galaxyName', $matrixData['galaxy']['name']);
$this->set('galaxyId', $matrixData['galaxy']['id']);
$matrixGalaxies = $this->Galaxy->getAllowedMatrixGalaxies();
$this->set('matrixGalaxies', $matrixGalaxies);
$this->render('statistics_galaxymatrix');
}
$this->render('statistics_galaxymatrix');
}
public function verifyGPG($full = false)

View File

@ -0,0 +1,132 @@
<?php
class AttackExport
{
public $additional_params = array(
'flatten' => 1,
'includeEventTags' => 1,
'includeGalaxy' => 1
);
public $non_restrictive_export = true;
public $renderView = 'attack_view';
private $__matrixData = null;
private $__clusterCounts = array();
private $__attackGalaxy = 'mitre-attack-pattern';
private $__galaxy_id = 0;
private $__galaxy_name = '';
private $__GalaxyModel = null;
private $__tabs = false;
private $__matrixTags = false;
private $__killChainOrders = false;
private $__instanceUUID = false;
public function handler($data, $options = array())
{
if (empty($this->__GalaxyModel)) {
$this->__GalaxyModel = ClassRegistry::init('Galaxy');
}
$this->__attackGalaxy = empty($options['filters']['attackGalaxy']) ? $this->__attackGalaxy : $options['filters']['attackGalaxy'];
if (empty($this->__galaxy_id)) {
$temp = $this->__GalaxyModel->find('first', array(
'recursive' => -1,
'fields' => array('id', 'name'),
'conditions' => array('Galaxy.type' => $this->__attackGalaxy, 'Galaxy.namespace !=' => 'deprecated'),
));
if (empty($temp)) {
return '';
} else {
$this->__galaxy_id = $temp['Galaxy']['id'];
$this->__galaxy_name = $temp['Galaxy']['name'];
}
}
if (empty($this->__matrixData)) {
$this->__matrixData = $this->__GalaxyModel->getMatrix($this->__galaxy_id);
}
if (empty($this->__tabs)) {
$this->__tabs = $this->__matrixData['tabs'];
$this->__matrixTags = $this->__matrixData['matrixTags'];
$this->__killChainOrders = $this->__matrixData['killChain'];
$this->__instanceUUID = $this->__matrixData['instance-uuid'];
}
$clusterData = $this->__aggregate($data, array());
if (!empty($data['Attribute'])) {
foreach ($data['Attribute'] as $attribute) {
$clusterData = $this->__aggregate($attribute, $clusterData);
}
}
foreach ($clusterData as $key => $value) {
if (empty($this->__clusterCounts[$key])) {
$this->__clusterCounts[$key] = 1;
} else {
$this->__clusterCounts[$key] += 1;
}
}
return '';
}
private function __aggregate($data, $clusterData)
{
if (!empty($data['Galaxy'])) {
foreach ($data['Galaxy'] as $galaxy) {
if ($galaxy['type'] == $this->__attackGalaxy) {
foreach ($galaxy['GalaxyCluster'] as $galaxyCluster) {
$clusterData[$galaxyCluster['tag_name']] = 1;
}
}
}
}
return $clusterData;
}
public function header($options = array())
{
return '';
}
public function footer()
{
if (empty($this->__GalaxyModel)) {
return '';
}
$maxScore = 0;
foreach ($this->__clusterCounts as $clusterCount) {
if ($clusterCount > $maxScore) {
$maxScore = $clusterCount;
}
}
$this->__GalaxyModel->sortMatrixByScore($this->__tabs, $this->__clusterCounts);
App::uses('ColourGradientTool', 'Tools');
$gradientTool = new ColourGradientTool();
$colours = $gradientTool->createGradientFromValues($this->__clusterCounts);
$result = array(
'target_type' => 'event',
'columnOrders' => $this->__killChainOrders,
'tabs' => $this->__tabs,
'scores' => $this->__clusterCounts,
'maxScore' => $maxScore,
'pickingMode' => false
);
if (!empty($colours)) {
$result['colours'] = $colours['mapping'];
$result['interpolation'] = $colours['interpolation'];
}
if ($this->__galaxy_id == $this->__GalaxyModel->getMitreAttackGalaxyId()) {
$result['defaultTabName'] = 'mitre-attack';
$result['removeTrailling'] = 2;
}
$result['galaxyName'] = $this->__galaxy_name;
$result['galaxyId'] = $this->__galaxy_id;
$matrixGalaxies = $this->__GalaxyModel->getAllowedMatrixGalaxies();
$result['matrixGalaxies'] = $matrixGalaxies;
return json_encode($result);
}
public function separator()
{
return '';
}
}

View File

@ -344,7 +344,7 @@ class NidsExport
{
$overruled = $this->checkWhitelist($attribute['value']);
$attribute['value'] = NidsExport::replaceIllegalChars($attribute['value']); // substitute chars not allowed in rule
$content = 'content:"|01 00 00 01 00 00 00 00 00 00|"; depth:10; offset:2; content:"' . NidsExport::dnsNameToRawFormat($attribute['value'], 'hostname') . '"; fast_pattern; nocase;';
$content = 'content:"|01 00 00 01 00 00 00 00 00 01|"; depth:10; offset:2; content:"' . NidsExport::dnsNameToRawFormat($attribute['value'], 'hostname') . '"; fast_pattern; nocase;';
$this->rules[] = sprintf(
$ruleFormat,
($overruled) ? '#OVERRULED BY WHITELIST# ' : '',
@ -400,7 +400,7 @@ class NidsExport
{
$overruled = $this->checkWhitelist($attribute['value']);
$attribute['value'] = NidsExport::replaceIllegalChars($attribute['value']); // substitute chars not allowed in rule
$content = 'content:"|01 00 00 01 00 00 00 00 00 00|"; depth:10; offset:2; content:"' . NidsExport::dnsNameToRawFormat($attribute['value']) . '"; fast_pattern; nocase;';
$content = 'content:"|01 00 00 01 00 00 00 00 00 01|"; depth:10; offset:2; content:"' . NidsExport::dnsNameToRawFormat($attribute['value']) . '"; fast_pattern; nocase;';
$this->rules[] = sprintf(
$ruleFormat,
($overruled) ? '#OVERRULED BY WHITELIST# ' : '',
@ -565,7 +565,7 @@ class NidsExport
/**
* Converts a DNS name to a raw format usable in NIDS like Snort.
* example host: foobar.com becomes |00||06|foobar|03|com|00|
* example host: foobar.com becomes |01||06|foobar|03|com|00|
* example domain: foobar.com becomes |06|foobar|03|com|00|
* @param string $name dns name to be converted
* @param string $type the type of dns name - domain (default) or hostname
@ -575,7 +575,7 @@ class NidsExport
{
$rawName = "";
if ('hostname' == $type) {
$rawName = '|00|';
$rawName = '|01|';
}
// explode using the dot
$explodedNames = explode('.', $name);

View File

@ -3,7 +3,7 @@
class RPZExport
{
private $__policies = array(
'walled-garden' => array(
'Local-Data' => array(
'explanation' => 'returns the defined alternate location.',
'action' => '$walled_garden',
'setting_id' => 3,
@ -23,6 +23,16 @@ class RPZExport
'action' => 'rpz-drop.',
'setting_id' => 0,
),
'PASSTHRU' => array(
'explanation' => 'lets queries through, but allows for logging the hits (useful for testing).',
'action' => 'rpz-passthru.',
'setting_id' => 4,
),
'TCP-only' => array(
'explanation' => 'force the client to use TCP.',
'action' => 'rpz-tcp-only.',
'setting_id' => 5,
),
);
private $__items = array();
@ -33,7 +43,7 @@ class RPZExport
private $__rpzSettings = array();
private $__valid_policies = array('NXDOMAIN', 'NODATA', 'DROP', 'walled-garden');
private $__valid_policies = array('NXDOMAIN', 'NODATA', 'DROP', 'Local-Data', 'PASSTHRU', 'TCP-only');
private $__server = null;
@ -100,7 +110,7 @@ class RPZExport
$lookupData = array('policy', 'walled_garden', 'ns', 'ns_alt', 'email', 'serial', 'refresh', 'retry', 'expiry', 'minimum_ttl', 'ttl');
foreach ($lookupData as $v) {
if ($v === 'policy' && isset($options['filters'][$v])) {
if (!in_array($options['filters'][$v], array('NXDOMAIN', 'NODATA', 'DROP', 'walled-garden'))) {
if (!in_array($options['filters'][$v], array('NXDOMAIN', 'NODATA', 'DROP', 'Local-Data', 'PASSTHRU', 'TCP-only'))) {
unset($options['filters'][$v]);
} else {
$options['filters'][$v] = $this->getIdByPolicy($options['filters'][$v]);
@ -158,10 +168,12 @@ class RPZExport
'hostname' => '; The following hostnames will '
);
$policy_explanations = array(
'walled-garden' => 'returns the defined alternate location.',
'Local-Data' => 'returns the defined alternate location.',
'NXDOMAIN' => 'return NXDOMAIN (name does not exist) irrespective of actual result received.',
'NODATA' => 'returns NODATA (name exists but no answers returned) irrespective of actual result received.',
'DROP' => 'timeout.',
'PASSTHRU' => 'lets queries through, but allows for logging the hits (useful for testing).',
'TCP-only' => 'force the client to use TCP.',
);
return $explanations[$type] . $this->__policies[$policy]['explanation'] . PHP_EOL;
}
@ -189,7 +201,7 @@ class RPZExport
$result = $this->buildHeader($rpzSettings);
$policy = $this->getPolicyById($rpzSettings['policy']);
$action = $this->__policies[$policy]['action'];
if ($policy == 'walled-garden') {
if ($policy == 'Local-Data') {
$action = str_replace('$walled_garden', $rpzSettings['walled_garden'], $action);
}

View File

@ -58,7 +58,7 @@ class StixExport
$randomFileName = $this->generateRandomFileName();
$this->__tmp_dir = $this->__scripts_dir . 'tmp/';
$this->__framing = json_decode(shell_exec($framing_cmd), true);
$this->__stix_file = new File($this->__tmp_dir . $randomFileName . '.stix');
$this->__stix_file = new File($this->__tmp_dir . $randomFileName . '.' . $this->__return_type);
unset($randomFileName);
$this->__stix_file->write($this->__framing['header']);
$this->__initialize_misp_file();
@ -93,7 +93,7 @@ class StixExport
$this->__stix_file->close();
$this->__stix_file->delete();
$sep_len = strlen($this->__framing['separator']);
$stix_event = substr($stix_event, 0, -$sep_len) . $this->__framing['footer'];
$stix_event = (empty($this->__filenames) ? $stix_event : substr($stix_event, 0, -$sep_len)) . $this->__framing['footer'];
return $stix_event;
}

View File

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

View File

@ -229,7 +229,7 @@ class ComplexTypeTool
public function checkFreeText($input, $settings = array())
{
$charactersToTrim = array('\'', '"', ',', '(', ')');
$charactersToTrim = array('\'', '"', ',', '(', ')', ' ');
$iocArray = preg_split("/\r\n|\n|\r|\s|\s+|,|\<|\>|;/", $input);
$quotedText = explode('"', $input);
foreach ($quotedText as $k => $temp) {
@ -245,6 +245,7 @@ class ComplexTypeTool
if (!empty($iocArray)) {
foreach ($iocArray as $ioc) {
$ioc = trim($ioc);
$ioc = str_replace("\xc2\xa0", '', $ioc);
foreach ($charactersToTrim as $c) {
$ioc = trim($ioc, $c);
}

View File

@ -83,6 +83,7 @@
// community
$orgs = $this->__organisationModel->find('list', array(
'fields' => array('name'),
'conditions' => array('local' => true)
));
$thisOrg = $this->__user['Organisation']['name'];
$this->__addAdditionalDistributionInfo(1, $thisOrg); // add current community

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -75,7 +75,22 @@ class AppModel extends Model
13 => false, 14 => false, 15 => false, 18 => false, 19 => false, 20 => false,
21 => false, 22 => false, 23 => false, 24 => false, 25 => false, 26 => false,
27 => false, 28 => false, 29 => false, 30 => false, 31 => false, 32 => false,
33 => false, 34 => false, 35 => false
33 => false, 34 => false, 35 => false, 36 => false
);
public $advanced_updates_description = array(
);
public $actions_description = array(
'verifyGnuPGkeys' => array(
'title' => 'Verify GnuPG keys',
'description' => "Run a full validation of all GnuPG keys within this instance's userbase. The script will try to identify possible issues with each key and report back on the results.",
'url' => '/users/verifyGPG/'
),
'databaseCleanupScripts' => array(
'title' => 'Database Cleanup Scripts',
'description' => 'If you run into an issue with an infinite upgrade loop (when upgrading from version ~2.4.50) that ends up filling your database with upgrade script log messages, run the following script.',
'url' => '/logs/pruneUpdateLogs/'
)
);
public function afterSave($created, $options = array())
@ -209,8 +224,46 @@ class AppModel extends Model
}
// SQL scripts for updates
public function updateDatabase($command)
public function updateDatabase($command, $useWorker=false)
{
// Exit if updates are locked
if ($this->isUpdateLocked()) {
return false;
}
$this->__resetUpdateProgress();
// restart this function by a worker
if ($useWorker && Configure::read('MISP.background_jobs')) {
$job = ClassRegistry::init('Job');
$job->create();
$data = array(
'worker' => 'prio',
'job_type' => 'update_app',
'job_input' => 'command: ' . $command,
'status' => 0,
'retries' => 0,
'org_id' => 0,
'org' => '',
'message' => 'Updating.',
);
$job->save($data);
$jobId = $job->id;
$process_id = CakeResque::enqueue(
'prio',
'AdminShell',
array('updateApp', $command, $jobId),
true
);
$job->saveField('process_id', $process_id);
return true;
}
$liveOff = false;
$exitOnError = false;
if (isset($advanced_updates_description[$command])) {
$liveOff = isset($advanced_updates_description[$command]['liveOff']) ? $advanced_updates_description[$command]['liveOff'] : $liveOff;
$exitOnError = isset($advanced_updates_description[$command]['exitOnError']) ? $advanced_updates_description[$command]['exitOnError'] : $exitOnError;
}
$dataSourceConfig = ConnectionManager::getDataSource('default')->config;
$dataSource = $dataSourceConfig['datasource'];
$sqlArray = array();
@ -1131,6 +1184,16 @@ class AppModel extends Model
$sqlArray[] = "ALTER TABLE `roles` ADD `perm_publish_kafka` tinyint(1) NOT NULL DEFAULT 0;";
break;
case 35:
$sqlArray[] = "CREATE TABLE IF NOT EXISTS `notification_logs` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`org_id` int(11) NOT NULL,
`type` varchar(255) COLLATE utf8_bin NOT NULL,
`timestamp` int(11) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
KEY `org_id` (`org_id`),
KEY `type` (`type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;";
case 36:
$sqlArray[] = "CREATE TABLE IF NOT EXISTS decaying_models (
`id` int(11) NOT NULL AUTO_INCREMENT,
`uuid` varchar(40) COLLATE utf8_bin DEFAULT NULL,
@ -1172,52 +1235,123 @@ class AppModel extends Model
return false;
break;
}
foreach ($sqlArray as $sql) {
$now = new DateTime();
$this->__changeLockState(time());
// switch MISP instance live to false
if ($liveOff) {
$this->Server = Classregistry::init('Server');
$liveSetting = 'MISP.live';
$this->Server->serverSettingsSaveValue($liveSetting, false);
}
$sql_update_count = count($sqlArray);
$index_update_count = count($indexArray);
$total_update_count = $sql_update_count + $index_update_count;
$this->__setUpdateProgress(0, $total_update_count);
$str_index_array = array();
foreach($indexArray as $toIndex) {
$str_index_array[] = __('Indexing ') . implode($toIndex, '->');
}
$this->__setUpdateCmdMessages(array_merge($sqlArray, $str_index_array));
$flag_stop = false;
$error_count = 0;
// execute test before update. Exit if it fails
if (isset($this->advanced_updates_description[$command]['preUpdate'])) {
$function_name = $this->advanced_updates_description[$command]['preUpdate'];
try {
$this->query($sql);
$this->Log->create();
$this->Log->save(array(
'org' => 'SYSTEM',
'model' => 'Server',
'model_id' => 0,
'email' => 'SYSTEM',
'action' => 'update_database',
'user_id' => 0,
'title' => 'Successfuly executed the SQL query for ' . $command,
'change' => 'The executed SQL query was: ' . $sql
));
$this->{$function_name}();
} catch (Exception $e) {
$this->Log->create();
$this->Log->save(array(
'org' => 'SYSTEM',
'model' => 'Server',
'model_id' => 0,
'email' => 'SYSTEM',
'action' => 'update_database',
'user_id' => 0,
'title' => 'Issues executing the SQL query for ' . $command,
'change' => 'The executed SQL query was: ' . $sql . PHP_EOL . ' The returned error is: ' . $e->getMessage()
));
$this->__setPreUpdateTestState(false);
$this->__setUpdateProgress(0, false);
$this->__setUpdateResMessages(0, __('Issues executing the pre-update test `') . $function_name . __('`. The returned error is: ') . PHP_EOL . $e->getMessage());
$this->__setUpdateError(0);
$error_count++;
$exitOnError = true;
$flag_stop = true;
}
}
if (!empty($indexArray)) {
if ($clean) {
$this->cleanCacheFiles();
}
foreach ($indexArray as $iA) {
if (isset($iA[2])) {
$this->__addIndex($iA[0], $iA[1], $iA[2]);
} else {
$this->__addIndex($iA[0], $iA[1]);
if (!$flag_stop) {
$this->__setPreUpdateTestState(true);
foreach ($sqlArray as $i => $sql) {
try {
$this->__setUpdateProgress($i, false);
$this->query($sql);
$this->Log->create();
$this->Log->save(array(
'org' => 'SYSTEM',
'model' => 'Server',
'model_id' => 0,
'email' => 'SYSTEM',
'action' => 'update_database',
'user_id' => 0,
'title' => __('Successfuly executed the SQL query for ') . $command,
'change' => __('The executed SQL query was: ') . $sql
));
$this->__setUpdateResMessages($i, __('Successfuly executed the SQL query for ') . $command);
} catch (Exception $e) {
$this->Log->create();
$this->Log->save(array(
'org' => 'SYSTEM',
'model' => 'Server',
'model_id' => 0,
'email' => 'SYSTEM',
'action' => 'update_database',
'user_id' => 0,
'title' => __('Issues executing the SQL query for ') . $command,
'change' => __('The executed SQL query was: ') . $sql . PHP_EOL . __(' The returned error is: ') . $e->getMessage()
));
$this->__setUpdateResMessages($i, __('Issues executing the SQL query for ') . $command . __('. The returned error is: ') . PHP_EOL . $e->getMessage());
$this->__setUpdateError($i);
$error_count++;
if ($exitOnError) {
$flag_stop = true;
break;
}
}
}
}
if (!$flag_stop) {
if (!empty($indexArray)) {
if ($clean) {
$this->cleanCacheFiles();
}
foreach ($indexArray as $i => $iA) {
$this->__setUpdateProgress(count($sqlArray)+$i, false);
if (isset($iA[2])) {
$this->__addIndex($iA[0], $iA[1], $iA[2]);
} else {
$this->__addIndex($iA[0], $iA[1]);
}
$this->__setUpdateResMessages(count($sqlArray)+$i, __('Successfuly indexed ') . implode($iA, '->'));
}
}
$this->__setUpdateProgress(count($sqlArray)+count($indexArray), false);
}
if ($clean) {
$this->cleanCacheFiles();
}
if ($liveOff) {
$liveSetting = 'MISP.live';
$this->Server->serverSettingsSaveValue($liveSetting, true);
}
if (!$flag_stop && $error_count == 0) {
$this->__postUpdate($command);
}
$this->__changeLockState(false);
return true;
}
// check whether the adminSetting should be updated after the update
private function __postUpdate($command) {
if (isset($this->advanced_updates_description[$command]['record'])) {
if($this->advanced_updates_description[$command]['record']) {
$this->AdminSetting->changeSetting($command, 1);
}
}
}
private function __dropIndex($table, $field)
{
$dataSourceConfig = ConnectionManager::getDataSource('default')->config;
@ -1412,6 +1546,126 @@ class AppModel extends Model
if ($requiresLogout) {
$this->updateDatabase('destroyAllSessions');
}
return true;
}
private function __setUpdateProgress($current, $total=false)
{
$updateProgress = $this->getUpdateProgress();
$updateProgress['current'] = $current;
if ($total !== false) {
$updateProgress['total'] = $total;
} else {
$now = new DateTime();
$updateProgress['time']['started'][$current] = $now->format('Y-m-d H:i:s');
}
$this->__saveUpdateProgress($updateProgress);
}
private function __setPreUpdateTestState($state)
{
$updateProgress = $this->getUpdateProgress();
$updateProgress['preTestSuccess'] = $state;
$this->__saveUpdateProgress($updateProgress);
}
private function __setUpdateError($index)
{
$updateProgress = $this->getUpdateProgress();
$updateProgress['failed_num'][] = $index;
$this->__saveUpdateProgress($updateProgress);
}
private function __resetUpdateProgress()
{
$updateProgress = array(
'commands' => array(),
'results' => array(),
'time' => array('started' => array(), 'elapsed' => array()),
'current' => '',
'total' => '',
'failed_num' => array()
);
$this->__saveUpdateProgress($updateProgress);
}
private function __setUpdateCmdMessages($messages)
{
$updateProgress = $this->getUpdateProgress();
$updateProgress['commands'] = $messages;
$this->__saveUpdateProgress($updateProgress);
}
private function __setUpdateResMessages($index, $message)
{
$updateProgress = $this->getUpdateProgress();
$updateProgress['results'][$index] = $message;
$temp = new DateTime();
$diff = $temp->diff(new DateTime($updateProgress['time']['started'][$index]));
$updateProgress['time']['elapsed'][$index] = $diff->format('%H:%I:%S');
$this->__saveUpdateProgress($updateProgress);
}
public function getUpdateProgress()
{
if (!isset($this->AdminSetting)) {
$this->AdminSetting = ClassRegistry::init('AdminSetting');
}
$updateProgress = $this->AdminSetting->getSetting('update_progress');
if ($updateProgress !== false) {
$updateProgress = json_decode($updateProgress, true);
} else {
$this->__resetUpdateProgress();
$updateProgress = $this->AdminSetting->getSetting('update_progress');
$updateProgress = json_decode($updateProgress, true);
}
foreach($updateProgress as $setting => $value) {
if (!is_array($value)) {
$value = $value !== false && $value !== '' ? intval($value) : 0;
}
$updateProgress[$setting] = $value;
}
return $updateProgress;
}
private function __saveUpdateProgress($updateProgress)
{
$data = json_encode($updateProgress);
$this->AdminSetting->changeSetting('update_progress', $data);
}
private function __changeLockState($locked)
{
$this->AdminSetting->changeSetting('update_locked', $locked);
}
private function getUpdateLockState()
{
if (!isset($this->AdminSetting)) {
$this->AdminSetting = ClassRegistry::init('AdminSetting');
}
$locked = $this->AdminSetting->getSetting('update_locked');
return is_null($locked) ? false : $locked;
}
public function isUpdateLocked()
{
$lockState = $this->getUpdateLockState();
if ($lockState !== false && $lockState !== '') {
// if lock is old, still allows the update
// This can be useful if the update process crashes
$diffSec = time() - intval($lockState);
if (Configure::read('MISP.updateTimeThreshold')) {
$updateWaitThreshold = intval(Configure::read('MISP.updateTimeThreshold'));
} else {
$this->Server = ClassRegistry::init('Server');
$updateWaitThreshold = intval($this->Server->serverSettings['MISP']['updateTimeThreshold']['value']);
}
if ($diffSec < $updateWaitThreshold) {
return true;
}
}
return false;
}
private function __queueCleanDB()
@ -1894,7 +2148,7 @@ class AppModel extends Model
$filter = array();
foreach ($temp as $f) {
if ($f[0] === '!') {
$filter['NOT'][] = $f;
$filter['NOT'][] = substr($f, 1);
} else {
$filter['OR'][] = $f;
}

View File

@ -388,7 +388,9 @@ class Attribute extends AppModel
'suricata' => array('txt', 'NidsSuricataExport', 'rules'),
'snort' => array('txt', 'NidsSnortExport', 'rules'),
'text' => array('txt', 'TextExport', 'txt'),
'rpz' => array('rpz', 'RPZExport', 'rpz'),
'yara' => array('txt', 'YaraExport', 'yara'),
'yara-json' => array('json', 'YaraExport', 'json'),
'rpz' => array('txt', 'RPZExport', 'rpz'),
'csv' => array('csv', 'CsvExport', 'csv'),
'cache' => array('txt', 'CacheExport', 'cache')
);
@ -1475,9 +1477,6 @@ class Attribute extends AppModel
$value = strtolower($value);
str_replace(':', '|', $value);
break;
case 'float':
$value = floatval($value);
break;
case 'hex':
$value = strtoupper($value);
break;
@ -1589,7 +1588,7 @@ class Attribute extends AppModel
}
}
public function base64EncodeAttachment($attribute)
public function getAttachment($attribute, $path_suffix='')
{
$attachments_dir = Configure::read('MISP.attachments_dir');
if (empty($attachments_dir)) {
@ -1600,21 +1599,20 @@ class Attribute extends AppModel
// S3 - we have to first get the object then we can encode it
$s3 = $this->getS3Client();
// This will return the content of the object
$content = $s3->download($attribute['event_id'] . DS . $attribute['id']);
$content = $s3->download($attribute['event_id'] . DS . $attribute['id'] . $path_suffix);
} else {
// Standard filesystem
$filepath = $attachments_dir . DS . $attribute['event_id'] . DS . $attribute['id'];
$filepath = $attachments_dir . DS . $attribute['event_id'] . DS . $attribute['id'] . $path_suffix;
$file = new File($filepath);
if (!$file->readable()) {
return '';
}
$content = $file->read();
}
return base64_encode($content);
return $content;
}
public function saveBase64EncodedAttachment($attribute)
public function saveAttachment($attribute, $path_suffix='')
{
$attachments_dir = Configure::read('MISP.attachments_dir');
if (empty($attachments_dir)) {
@ -1626,17 +1624,17 @@ class Attribute extends AppModel
// We don't need your fancy directory structures and
// PEE AICH PEE meddling
$s3 = $this->getS3Client();
$data = base64_decode($attribute['data']);
$key = $attribute['event_id'] . DS . $attribute['id'];
$data = $attribute['data'];
$key = $attribute['event_id'] . DS . $attribute['id'] . $path_suffix;
$s3->upload($key, $data);
return true;
} else {
// Plebian filesystem operations
$rootDir = $attachments_dir . DS . $attribute['event_id'];
$dir = new Folder($rootDir, true); // create directory structure
$destpath = $rootDir . DS . $attribute['id'];
$destpath = $rootDir . DS . $attribute['id'] . $path_suffix;
$file = new File($destpath, true); // create the file
$decodedData = base64_decode($attribute['data']); // decode
$decodedData = $attribute['data']; // decode
if ($file->write($decodedData)) { // save the data
return true;
} else {
@ -1646,6 +1644,73 @@ class Attribute extends AppModel
}
}
public function base64EncodeAttachment($attribute)
{
return base64_encode($this->getAttachment($attribute));
}
public function saveBase64EncodedAttachment($attribute)
{
$attribute['data'] = base64_decode($attribute['data']);
return $this->saveAttachment($attribute);
}
public function getPictureData($attribute, $thumbnail=false, $width=200, $height=200)
{
$extension = explode('.', $attribute['Attribute']['value']);
$extension = end($extension);
if (extension_loaded('gd')) {
if (!$thumbnail) {
$data = $this->getAttachment($attribute['Attribute']);
$image = ImageCreateFromString($data);
ob_start ();
switch ($extension) {
case 'gif':
// php-gd doesn't support animated gif. Skipping...
break;
case 'jpg':
case 'jpeg':
imagejpeg($image);
break;
case 'png':
imagepng($image);
break;
default:
break;
}
$image_data = $extension != 'gif' ? ob_get_contents() : $data;
ob_end_clean ();
} else { // thumbnail requested, resample picture with desired dimension and save result
$thumbnail_exists = $this->getAttachment($attribute['Attribute'], $path_suffix='_thumbnail');
if ($width == 200 && $height == 200 && $thumbnail_exists !== '') { // check if thumbnail already exists
$image_data = $thumbnail_exists;
} else {
$data = $this->getAttachment($attribute['Attribute']);
if ($extension == 'gif') {
$image_data = $data;
} else {
$image = ImageCreateFromString($data);
$extension = 'jpg';
$imageTC = ImageCreateTrueColor($width, $height);
ImageCopyResampled($imageTC, $image, 0, 0, 0, 0, $width, $height, ImageSX($image), ImageSY($image));
ob_start ();
imagejpeg ($imageTC);
$image_data = ob_get_contents();
ob_end_clean ();
imagedestroy($image);
imagedestroy($imageTC);
}
// save thumbnail for later reuse
$attribute['Attribute']['data'] = $image_data;
$this->saveAttachment($attribute['Attribute'], '_thumbnail');
}
}
} else {
$image_data = $this->getAttachment($attribute['Attribute']);
}
return $image_data;
}
public function __beforeSaveCorrelation($a)
{
// (update-only) clean up the relation of the old value: remove the existing relations related to that attribute, we DO have a reference, the id
@ -2150,9 +2215,8 @@ class Attribute extends AppModel
}
$tag = ClassRegistry::init('Tag');
$params['tags'] = $this->dissectArgs($params['tags']);
$tagArray = $tag->fetchTagIds($params['tags'][0], $params['tags'][1]);
if (!empty($params['tags'][0]) && empty($tagArray[0]) && empty($params['lax_tags'])) {
$tagArray[0] = array(-1);
foreach (array(0, 1, 2) as $tag_operator) {
$tagArray[$tag_operator] = $tag->fetchTagIdsSimple($params['tags'][$tag_operator]);
}
$temp = array();
if (!empty($tagArray[0])) {
@ -2217,6 +2281,45 @@ class Attribute extends AppModel
$conditions['AND'][] = array_merge($temp, $this->subQueryGenerator($tag->AttributeTag, $subquery_options, $lookup_field, 1));
}
}
$temp = array();
if (!empty($tagArray[2])) {
if ($tagArray[2][0] === -1) {
$conditions[] = array('Event.id' => -1);
} else {
foreach ($tagArray[2] as $k => $anded_tag) {
$subquery_options = array(
'conditions' => array(
'tag_id' => $anded_tag
),
'fields' => array(
'event_id'
)
);
$lookup_field = ($options['scope'] === 'Event') ? 'Event.id' : 'Attribute.event_id';
$temp[$k]['OR'] = array();
$temp[$k]['OR'] = array_merge(
$temp[$k]['OR'],
$this->subQueryGenerator($tag->EventTag, $subquery_options, $lookup_field)
);
$subquery_options = array(
'conditions' => array(
'tag_id' => $anded_tag
),
'fields' => array(
$options['scope'] === 'Event' ? 'Event.id' : 'attribute_id'
)
);
$lookup_field = $options['scope'] === 'Event' ? 'Event.id' : 'Attribute.id';
$temp[$k]['OR'] = array_merge(
$temp[$k]['OR'],
$this->subQueryGenerator($tag->AttributeTag, $subquery_options, $lookup_field)
);
}
}
}
if (!empty($temp)) {
$conditions['AND'][] = array('AND' => $temp);
}
$params['tags'] = array();
if (!empty($tagArray[0]) && empty($options['pop'])) {
$params['tags']['OR'] = $tagArray[0];
@ -2224,6 +2327,9 @@ class Attribute extends AppModel
if (!empty($tagArray[1])) {
$params['tags']['NOT'] = $tagArray[1];
}
if (!empty($tagArray[2]) && empty($options['pop'])) {
$params['tags']['AND'] = $tagArray[2];
}
if (empty($params['tags'])) {
unset($params['tags']);
}
@ -2535,12 +2641,12 @@ class Attribute extends AppModel
public function dissectArgs($args)
{
if (empty($args)) {
return array(0 => array(), 1 => array());
return array(0 => array(), 1 => array(), 2 => array());
}
if (!is_array($args)) {
$args = explode('&&', $args);
}
$result = array(0 => array(), 1 => array());
$result = array(0 => array(), 1 => array(), 2 => array());
if (isset($args['OR']) || isset($args['NOT']) || isset($args['AND'])) {
if (!empty($args['OR'])) {
$result[0] = $args['OR'];
@ -2548,6 +2654,9 @@ class Attribute extends AppModel
if (!empty($args['NOT'])) {
$result[1] = $args['NOT'];
}
if (!empty($args['AND'])) {
$result[2] = $args['AND'];
}
} else {
foreach ($args as $arg) {
if (substr($arg, 0, 1) == '!') {
@ -2904,6 +3013,9 @@ class Attribute extends AppModel
if (isset($options['limit'])) {
$params['limit'] = $options['limit'];
}
if (!empty($options['includeGalaxy'])) {
$this->GalaxyCluster = ClassRegistry::init('GalaxyCluster');
}
if (Configure::read('MISP.proposals_block_attributes') && isset($options['conditions']['AND']['Attribute.to_ids']) && $options['conditions']['AND']['Attribute.to_ids'] == 1) {
$this->bindModel(array('hasMany' => array('ShadowAttribute' => array('foreignKey' => 'old_id'))));
$proposalRestriction = array(
@ -2940,8 +3052,16 @@ class Attribute extends AppModel
if (!isset($options['enforceWarninglist'])) {
$options['enforceWarninglist'] = false;
}
if (!isset($options['includeWarninglistHits'])) {
$options['includeWarninglistHits'] = false;
}
if (!$user['Role']['perm_sync'] || !isset($options['deleted']) || !$options['deleted']) {
$params['conditions']['AND']['(Attribute.deleted + 0)'] = 0;
} else {
if ($options['deleted'] === "only") {
$options['deleted'] = 1;
}
$params['conditions']['AND']['(Attribute.deleted + 0)'] = $options['deleted'];
}
if (isset($options['group'])) {
$params['group'] = empty($options['group']) ? $options['group'] : false;
@ -2968,7 +3088,7 @@ class Attribute extends AppModel
return $results;
}
if ($options['enforceWarninglist'] && !isset($this->warninglists)) {
if (($options['enforceWarninglist'] || $options['includeWarninglistHits']) && !isset($this->warninglists)) {
$this->Warninglist = ClassRegistry::init('Warninglist');
$this->warninglists = $this->Warninglist->fetchForEventView();
}
@ -3027,6 +3147,9 @@ class Attribute extends AppModel
if ($options['enforceWarninglist'] && !$this->Warninglist->filterWarninglistAttributes($this->warninglists, $attribute['Attribute'])) {
continue;
}
if ($options['includeWarninglistHits']) {
$results[$key]['Attribute'] = $this->Warninglist->simpleCheckForWarning($results[$key]['Attribute'], $this->warninglists, true);
}
if (!empty($options['includeAttributeUuid']) || !empty($options['includeEventUuid'])) {
$results[$key]['Attribute']['event_uuid'] = $results[$key]['Event']['uuid'];
}
@ -3040,6 +3163,12 @@ class Attribute extends AppModel
}
}
if (!empty($results[$key])) {
if (!empty($options['includeGalaxy'])) {
$massaged_attribute = $this->Event->massageTags($results[$key], 'Attribute');
$massaged_event = $this->Event->massageTags($results[$key], 'Event');
$massaged_attribute['Galaxy'] = array_merge_recursive($massaged_attribute['Galaxy'], $massaged_event['Galaxy']);
$results[$key] = $massaged_attribute;
}
$attributes[] = $results[$key];
}
}
@ -3068,8 +3197,10 @@ class Attribute extends AppModel
$eventTags[$results[$key]['Event']['id']][] = $tag;
}
}
foreach ($eventTags[$results[$key]['Event']['id']] as $eventTag) {
$results[$key]['EventTag'][] = $eventTag['EventTag'];
if (!empty($eventTags)) {
foreach ($eventTags[$results[$key]['Event']['id']] as $eventTag) {
$results[$key]['EventTag'][] = $eventTag['EventTag'];
}
}
return $results;
}
@ -3337,7 +3468,7 @@ class Attribute extends AppModel
return $conditions;
}
public function setTimestampConditions($timestamp, $conditions, $scope = 'Event.timestamp')
public function setTimestampConditions($timestamp, $conditions, $scope = 'Event.timestamp', $returnRaw = false)
{
if (is_array($timestamp)) {
$timestamp[0] = intval($this->Event->resolveTimeDelta($timestamp[0]));
@ -3353,6 +3484,9 @@ class Attribute extends AppModel
$timestamp = intval($this->Event->resolveTimeDelta($timestamp));
$conditions['AND'][] = array($scope . ' >=' => $timestamp);
}
if ($returnRaw) {
return $timestamp;
}
return $conditions;
}
@ -3667,7 +3801,6 @@ class Attribute extends AppModel
} else {
$date = new DateTime();
$attribute['timestamp'] = $date->getTimestamp();
;
}
} else {
$this->create();
@ -3773,6 +3906,72 @@ class Attribute extends AppModel
return true;
}
public function deleteAttribute($id, $user, $hard = false)
{
$this->id = $id;
if (!$this->exists()) {
return false;
}
$result = $this->find('first', array(
'conditions' => array('Attribute.id' => $id),
'recursive' => -1,
'contain' => array('Event')
));
if (empty($result)) {
throw new MethodNotAllowedException(__('Attribute not found or not authorised.'));
}
// check for permissions
if (!$user['Role']['perm_site_admin']) {
if ($result['Event']['locked']) {
if ($user['org_id'] != $result['Event']['org_id'] || !$user['Role']['perm_sync']) {
throw new MethodNotAllowedException(__('Attribute not found or not authorised.'));
}
} else {
if ($user['org_id'] != $result['Event']['orgc_id']) {
throw new MethodNotAllowedException(__('Attribute not found or not authorised.'));
}
}
}
$date = new DateTime();
if ($hard) {
$save = $this->delete($id);
} else {
if (Configure::read('Security.sanitise_attribute_on_delete')) {
$result['Attribute']['category'] = 'Other';
$result['Attribute']['type'] = 'comment';
$result['Attribute']['value'] = 'deleted';
$result['Attribute']['comment'] = '';
$result['Attribute']['to_ids'] = 0;
}
$result['Attribute']['deleted'] = 1;
$result['Attribute']['timestamp'] = $date->getTimestamp();
$save = $this->save($result);
$object_refs = $this->Object->ObjectReference->find('all', array(
'conditions' => array(
'ObjectReference.referenced_type' => 0,
'ObjectReference.referenced_id' => $id,
),
'recursive' => -1
));
foreach ($object_refs as $ref) {
$ref['ObjectReference']['deleted'] = 1;
$this->Object->ObjectReference->save($ref);
}
}
// attachment will be deleted with the beforeDelete() function in the Model
if ($save) {
// We have just deleted the attribute, let's also check if there are any shadow attributes that were attached to it and delete them
$this->Event->ShadowAttribute->deleteAll(array('ShadowAttribute.old_id' => $id), false);
// remove the published flag from the event
$this->Event->unpublishEvent($result['Event']['id']);
return true;
} else {
return false;
}
}
public function attachValidationWarnings($adata)
{
if (!$this->__fTool) {
@ -3808,6 +4007,7 @@ class Attribute extends AppModel
'value' => array('function' => 'set_filter_value'),
'category' => array('function' => 'set_filter_simple_attribute'),
'type' => array('function' => 'set_filter_simple_attribute'),
'object_relation' => array('function' => 'set_filter_simple_attribute'),
'tags' => array('function' => 'set_filter_tags', 'pop' => true),
'uuid' => array('function' => 'set_filter_uuid'),
'deleted' => array('function' => 'set_filter_deleted'),
@ -3821,6 +4021,7 @@ class Attribute extends AppModel
'ignore' => array('function' => 'set_filter_ignore'),
'from' => array('function' => 'set_filter_timestamp'),
'to' => array('function' => 'set_filter_timestamp'),
'date' => array('function' => 'set_filter_date'),
'tags' => array('function' => 'set_filter_tags'),
'last' => array('function' => 'set_filter_timestamp', 'pop' => true),
'timestamp' => array('function' => 'set_filter_timestamp', 'pop' => true),
@ -3852,7 +4053,7 @@ class Attribute extends AppModel
return $conditions;
}
public function restSearch($user, $returnFormat, $filters, $paramsOnly = false, $jobId = false, &$elementCounter = 0)
public function restSearch($user, $returnFormat, $filters, $paramsOnly = false, $jobId = false, &$elementCounter = 0, &$renderView = false)
{
if (!isset($this->validFormats[$returnFormat][1])) {
throw new NotFoundException('Invalid output format.');
@ -3873,6 +4074,9 @@ class Attribute extends AppModel
unset($filters['value']);
}
}
if (!empty($exportTool->renderView)) {
$renderView = $exportTool->renderView;
}
if (isset($filters['searchall'])) {
if (!empty($filters['value'])) {
$filters['wildcard'] = $filters['value'];
@ -3891,8 +4095,12 @@ class Attribute extends AppModel
'flatten' => 1,
'includeEventUuid' => !empty($filters['includeEventUuid']) ? $filters['includeEventUuid'] : 0,
'includeEventTags' => !empty($filters['includeEventTags']) ? $filters['includeEventTags'] : 0,
'includeProposals' => !empty($filters['includeProposals']) ? $filters['includeProposals'] : 0
'includeProposals' => !empty($filters['includeProposals']) ? $filters['includeProposals'] : 0,
'includeWarninglistHits' => !empty($filters['includeWarninglistHits']) ? $filters['includeWarninglistHits'] : 0
);
if (!empty($filters['attackGalaxy'])) {
$params['attackGalaxy'] = $filters['attackGalaxy'];
}
if (isset($filters['include_event_uuid'])) {
$params['includeEventUuid'] = $filters['include_event_uuid'];
}
@ -3902,12 +4110,8 @@ class Attribute extends AppModel
if (isset($filters['page'])) {
$params['page'] = $filters['page'];
}
if (!empty($filtes['deleted'])) {
$params['deleted'] = 1;
if ($params['deleted'] === 'only') {
$params['conditions']['AND'][] = array('Attribute.deleted' => 1);
$params['conditions']['AND'][] = array('Object.deleted' => 1);
}
if (!empty($filters['deleted'])) {
$params['deleted'] = $filters['deleted'];
}
if ($paramsOnly) {
return $params;
@ -3942,7 +4146,11 @@ class Attribute extends AppModel
$this->__iteratedFetch($user, $params, $loop, $tmpfile, $exportTool, $exportToolParams, $elementCounter);
fwrite($tmpfile, $exportTool->footer($exportToolParams));
fseek($tmpfile, 0);
$final = fread($tmpfile, fstat($tmpfile)['size']);
if (fstat($tmpfile)['size']) {
$final = fread($tmpfile, fstat($tmpfile)['size']);
} else {
$final = '';
}
fclose($tmpfile);
return $final;
}

View File

@ -111,45 +111,58 @@ class AttributeTag extends AppModel
));
}
public function getTagScores($eventId=0, $allowedTags=array())
// Fetch all tags attached to attribute belonging to supplied event. No ACL if user not provided
public function getTagScores($user=false, $eventId=0, $allowedTags=array())
{
// get score of galaxy
$db = $this->getDataSource();
$statementArray = array(
'fields' => array('attr_tag.tag_id as id', 'count(attr_tag.tag_id) as value'),
'table' => $db->fullTableName($this),
'alias' => 'attr_tag',
'group' => 'tag_id'
);
if ($eventId != 0) {
$statementArray['conditions'] = array('event_id' => $eventId);
}
// tag along with its occurence in the event
$subQuery = $db->buildStatement(
$statementArray,
$this
);
$subQueryExpression = $db->expression($subQuery)->value;
// get related galaxies
$attributeTagScores = $this->query("SELECT name, value FROM (" . $subQueryExpression . ") AS score, tags WHERE tags.id=score.id;");
// arrange data
$scores = array();
$maxScore = 0;
foreach ($attributeTagScores as $item) {
$score = $item['score']['value'];
$name = $item['tags']['name'];
if (in_array($name, $allowedTags)) {
$maxScore = $score > $maxScore ? $score : $maxScore;
$scores[$name] = $score;
if ($user === false) {
$conditions = array('Tag.id !=' => null);
if ($eventId != 0) {
$conditions['event_id'] = $eventId;
}
$attribute_tag_scores = $this->find('all', array(
'recursive' => -1,
'conditions' => $conditions,
'contain' => array(
'Tag' => array(
'conditions' => array('name' => $allowedTags)
)
),
'fields' => array('Tag.name', 'AttributeTag.event_id')
));
$scores = array('scores' => array(), 'maxScore' => 0);
foreach ($attribute_tag_scores as $attribute_tag_score) {
$tag_name = $attribute_tag_score['Tag']['name'];
if (!isset($scores['scores'][$tag_name])) {
$scores['scores'][$tag_name] = 0;
}
$scores['scores'][$tag_name]++;
$scores['maxScore'] = $scores['scores'][$tag_name] > $scores['maxScore'] ? $scores['scores'][$tag_name] : $scores['maxScore'];
}
} else {
$allowed_tag_lookup_table = array_flip($allowedTags);
$attributes = $this->Attribute->fetchAttributes($user, array('conditions' => array(
'Attribute.event_id' => $eventId
)));
$scores = array('scores' => array(), 'maxScore' => 0);
foreach ($attributes as $attribute) {
foreach ($attribute['AttributeTag'] as $tag) {
$tag_name = $tag['Tag']['name'];
if (isset($allowed_tag_lookup_table[$tag_name])) {
if (!isset($scores['scores'][$tag_name])) {
$scores['scores'][$tag_name] = 0;
}
$scores['scores'][$tag_name]++;
$scores['maxScore'] = $scores['scores'][$tag_name] > $scores['maxScore'] ? $scores['scores'][$tag_name] : $scores['maxScore'];
}
}
}
}
return array('scores' => $scores, 'maxScore' => $maxScore);
return $scores;
}
// find all tags that belong to a list of attributes (contained in the same event)
public function getAttributesTags($user, $requestedEventId, $attributeIds=false) {
public function getAttributesTags($user, $requestedEventId, $attributeIds=false, $includeGalaxies=false) {
$conditions = array('Attribute.event_id' => $requestedEventId);
if (is_array($attributeIds) && $attributeIds !== false) {
$conditions['Attribute.id'] = $attributeIds;
@ -169,12 +182,11 @@ class AttributeTag extends AppModel
'recursive' => -1,
'fields' => array('GalaxyCluster.tag_name', 'GalaxyCluster.id'),
));
$allTags = array();
foreach ($attributes as $attribute) {
$attributeTags = $attribute['AttributeTag'];
foreach ($attributeTags as $k => $attributeTag) {
if (!isset($cluster_names[$attributeTag['Tag']['name']])) {
if ($includeGalaxies || !isset($cluster_names[$attributeTag['Tag']['name']])) {
$allTags[$attributeTag['Tag']['id']] = $attributeTag['Tag'];
}
}
@ -234,4 +246,41 @@ class AttributeTag extends AppModel
return $allClusters;
}
public function extractAttributeTagsNameFromEvent(&$event, $to_extract='both')
{
$attribute_tags_name = array('tags' => array(), 'clusters' => array());
foreach ($event['Attribute'] as $i => $attribute) {
if ($to_extract == 'tags' || $to_extract == 'both') {
foreach ($attribute['AttributeTag'] as $tag) {
$attribute_tags_name['tags'][] = $tag['Tag']['name'];
}
}
if ($to_extract == 'clusters' || $to_extract == 'both') {
foreach ($attribute['Galaxy'] as $galaxy) {
foreach ($galaxy['GalaxyCluster'] as $cluster) {
$attribute_tags_name['clusters'][] = $cluster['tag_name'];
}
}
}
}
foreach ($event['Object'] as $i => $object) {
foreach ($object['Attribute'] as $j => $object_attribute) {
if ($to_extract == 'tags' || $to_extract == 'both') {
foreach ($object_attribute['AttributeTag'] as $tag) {
$attribute_tags_name['tags'][] = $tag['Tag']['name'];
}
}
if ($to_extract == 'clusters' || $to_extract == 'both') {
foreach ($object_attribute['Galaxy'] as $galaxy) {
foreach ($galaxy['GalaxyCluster'] as $cluster) {
$attribute_tags_name['clusters'][] = $cluster['tag_name'];
}
}
}
}
}
$attribute_tags_name['tags'] = array_diff_key($attribute_tags_name['tags'], $attribute_tags_name['clusters']); // de-dup if needed.
return $attribute_tags_name;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -154,7 +154,7 @@ class EventTag extends AppModel
}
return $tags;
}
public function countForTag($tag_id, $user)
{
return $this->find('count', array(
@ -163,39 +163,96 @@ class EventTag extends AppModel
));
}
public function getTagScores($eventId=0, $allowedTags=array())
public function getTagScores($eventId=0, $allowedTags=array(), $propagateToAttribute=false)
{
// get score of galaxy
$db = $this->getDataSource();
$statementArray = array(
'fields' => array('event_tag.tag_id as id', 'count(event_tag.tag_id) as value'),
'table' => $db->fullTableName($this),
'alias' => 'event_tag',
'group' => 'tag_id'
);
if ($eventId != 0) {
$statementArray['conditions'] = array('event_id' => $eventId);
if ($propagateToAttribute) {
$eventTagScores = $this->find('all', array(
'recursive' => -1,
'conditions' => array('Tag.id !=' => null),
'contain' => array(
'Event',
'Tag' => array(
'conditions' => array('name' => $allowedTags)
)
),
'fields' => array('Tag.name', 'Event.attribute_count')
));
} else {
$conditions = array('Tag.id !=' => null);
if ($eventId != 0) {
$conditions['event_id'] = $eventId;
}
$eventTagScores = $this->find('all', array(
'recursive' => -1,
'conditions' => $conditions,
'contain' => array(
'Tag' => array(
'conditions' => array('name' => $allowedTags)
)
),
'group' => 'tag_id',
'fields' => array('Tag.name', 'EventTag.tag_id', 'count(EventTag.tag_id) as score')
));
}
// tag along with its occurence in the event
$subQuery = $db->buildStatement(
$statementArray,
$this
);
$subQueryExpression = $db->expression($subQuery)->value;
// get related galaxies
$attributeTagScores = $this->query("SELECT name, value FROM (" . $subQueryExpression . ") AS score, tags WHERE tags.id=score.id;");
// arrange data
$scores = array();
$maxScore = 0;
foreach ($attributeTagScores as $item) {
$score = $item['score']['value'];
$name = $item['tags']['name'];
foreach ($eventTagScores as $item) {
$score = isset($item['Event']) ? $item['Event']['attribute_count'] : $item[0]['score'];
$name = $item['Tag']['name'];
if (in_array($name, $allowedTags)) {
$maxScore = $score > $maxScore ? $score : $maxScore;
$scores[$name] = $score;
if (!isset($scores[$name])) {
$scores[$name] = 0;
}
$scores[$name] += $score;
}
}
return array('scores' => $scores, 'maxScore' => $maxScore);
}
// Fetch all tags contained in an event (both event and attributes) ignoring the occurence. No ACL
public function getTagScoresUniform($eventId=0, $allowedTags=array())
{
$conditions = array('Tag.id !=' => null);
if ($eventId != 0) {
$conditions['event_id'] = $eventId;
}
$event_tag_scores = $this->find('all', array(
'recursive' => -1,
'conditions' => $conditions,
'contain' => array(
'Tag' => array(
'conditions' => array('name' => $allowedTags)
)
),
'fields' => array('Tag.name', 'EventTag.event_id')
));
$attribute_tag_scores = $this->Event->Attribute->AttributeTag->find('all', array(
'recursive' => -1,
'conditions' => $conditions,
'contain' => array(
'Tag' => array(
'conditions' => array('name' => $allowedTags)
)
),
'fields' => array('Tag.name', 'AttributeTag.event_id')
));
$score_aggregation = array();
foreach ($event_tag_scores as $event_tag_score) {
$score_aggregation[$event_tag_score['Tag']['name']][$event_tag_score['EventTag']['event_id']] = 1;
}
foreach ($attribute_tag_scores as $attribute_tag_score) {
$score_aggregation[$attribute_tag_score['Tag']['name']][$attribute_tag_score['AttributeTag']['event_id']] = 1;
}
$scores = array('scores' => array(), 'maxScore' => 0);
foreach ($score_aggregation as $name => $array_ids) {
$event_count = count($array_ids);
$scores['scores'][$name] = $event_count;
$scores['maxScore'] = $event_count > $scores['maxScore'] ? $event_count : $scores['maxScore'];
}
return $scores;
}
}

View File

@ -397,7 +397,7 @@ class Galaxy extends AppModel
return $galaxies;
}
public function getMatrix($galaxy_id)
public function getMatrix($galaxy_id, $scores=array())
{
$conditions = array('Galaxy.id' => $galaxy_id);
$contains = array(
@ -454,18 +454,7 @@ class Galaxy extends AppModel
}
$matrixData['tabs'] = $cols;
foreach ($matrixData['tabs'] as $k => $v) {
foreach ($matrixData['tabs'][$k] as $kc => $v2) {
// sort clusters in the kill chains
usort(
$matrixData['tabs'][$k][$kc],
function($a, $b) {
return strcmp($a['value'], $b['value']);
}
);
}
}
$this->sortMatrixByScore($matrixData['tabs'], $scores);
// #FIXME temporary fix: retreive tag name of deprecated mitre galaxies (for the stats)
if ($galaxy['Galaxy']['id'] == $this->getMitreAttackGalaxyId()) {
$names = array('Enterprise Attack - Attack Pattern', 'Pre Attack - Attack Pattern', 'Mobile Attack - Attack Pattern');
@ -486,4 +475,34 @@ class Galaxy extends AppModel
$matrixData['matrixTags'] = array_keys($matrixData['matrixTags']);
return $matrixData;
}
public function sortMatrixByScore(&$tabs, $scores)
{
foreach (array_keys($tabs) as $i) {
foreach (array_keys($tabs[$i]) as $j) {
// major ordering based on score, minor based on alphabetical
usort($tabs[$i][$j], function ($a, $b) use($scores) {
if ($a['tag_name'] == $b['tag_name']) {
return 0;
}
if (isset($scores[$a['tag_name']]) && isset($scores[$b['tag_name']])) {
if ($scores[$a['tag_name']] < $scores[$b['tag_name']]) {
$ret = 1;
} else if ($scores[$a['tag_name']] == $scores[$b['tag_name']]) {
$ret = strcmp($a['value'], $b['value']);
} else {
$ret = -1;
}
} else if (isset($scores[$a['tag_name']])) {
$ret = -1;
} else if (isset($scores[$b['tag_name']])) {
$ret = 1;
} else { // none are set
$ret = strcmp($a['value'], $b['value']);
}
return $ret;
});
}
}
}
}

View File

@ -42,7 +42,7 @@ class Job extends AppModel
$this->save($data);
$id = $this->id;
$this->Event = ClassRegistry::init('Event');
if (in_array($type, array_keys($this->Event->export_types))) {
if (in_array($type, array_keys($this->Event->export_types)) && $type !== 'bro') {
$process_id = CakeResque::enqueue(
'cache',
$shell . 'Shell',
@ -50,13 +50,11 @@ class Job extends AppModel
true
);
} elseif ($type === 'bro') {
$extra = $type;
$type = 'bro';
$extra2 = isset($user['nids_sid']) ? $user['nids_sid'] : 0;
$process_id = CakeResque::enqueue(
'cache',
$shell . 'Shell',
array('cachebro' . $type, $user['id'], $id, $extra, $extra2),
array('cachebro', $user['id'], $id),
true
);
} else {

View File

@ -45,6 +45,7 @@ class Log extends AppModel
'pull',
'push',
'remove_dead_workers',
'request',
'request_delegation',
'reset_auth_key',
'serverSettingsEdit',
@ -115,6 +116,9 @@ class Log extends AppModel
}
}
$this->logData($this->data);
if ($this->data['Log']['action'] === 'request' && !empty(Configure::read('MISP.log_paranoid_skip_db'))) {
return false;
}
return true;
}
@ -291,4 +295,31 @@ class Log extends AppModel
}
return true;
}
public function filterSiteAdminSensitiveLogs($list)
{
$this->User = ClassRegistry::init('User');
$site_admin_roles = $this->User->Role->find('list', array(
'recursive' => -1,
'conditions' => array('Role.perm_site_admin' => 1),
'fields' => array('Role.id', 'Role.id')
));
$site_admins = $this->User->find('list', array(
'recursive' => -1,
'conditions' => array(
'User.role_id' => array_values($site_admin_roles)
),
'fields' => array('User.id', 'User.id')
));
foreach ($list as $k => $v) {
if (
$v['Log']['model'] === 'User' &&
in_array($v['Log']['model_id'], array_values($site_admins)) &&
in_array($v['Log']['action'], array('add', 'edit', 'reset_auth_key'))
) {
$list[$k]['Log']['change'] = __('Redacted');
}
}
return $list;
}
}

View File

@ -725,4 +725,113 @@ class MispObject extends AppModel
}
return count($orphans);
}
public function validObjectsFromAttributeTypes($user, $event_id, $selected_attribute_ids)
{
$attributes = $this->Attribute->fetchAttributes($user,
array(
'conditions' => array(
'Attribute.id' => $selected_attribute_ids,
'Attribute.event_id' => $event_id,
'Attribute.object_id' => 0
),
)
);
if (empty($attributes)) {
return array('templates' => array(), 'types' => array());
}
$attribute_types = array();
foreach ($attributes as $i => $attribute) {
$attribute_types[$attribute['Attribute']['type']] = 1;
$attributes[$i]['Attribute']['object_relation'] = $attribute['Attribute']['type'];
}
$attribute_types = array_keys($attribute_types);
$potential_templates = $this->ObjectTemplate->find('list', array(
'recursive' => -1,
'fields' => array(
'ObjectTemplate.id',
'COUNT(ObjectTemplateElement.type) as type_count'
),
'conditions' => array(
'ObjectTemplate.active' => true,
'ObjectTemplateElement.type' => $attribute_types
),
'joins' => array(
array(
'table' => 'object_template_elements',
'alias' => 'ObjectTemplateElement',
'type' => 'RIGHT',
'fields' => array('ObjectTemplateElement.object_relation', 'ObjectTemplateElement.type'),
'conditions' => array('ObjectTemplate.id = ObjectTemplateElement.object_template_id')
)
),
'group' => 'ObjectTemplate.id',
'order' => 'type_count DESC'
));
$potential_template_ids = array_keys($potential_templates);
$templates = $this->ObjectTemplate->find('all', array(
'recursive' => -1,
'conditions' => array('id' => $potential_template_ids),
'contain' => 'ObjectTemplateElement'
));
foreach ($templates as $i => $template) {
$res = $this->ObjectTemplate->checkTemplateConformityBasedOnTypes($template, $attributes);
$templates[$i]['ObjectTemplate']['compatibility'] = $res['valid'] ? true : $res['missingTypes'];
$templates[$i]['ObjectTemplate']['invalidTypes'] = $res['invalidTypes'];
$templates[$i]['ObjectTemplate']['invalidTypesMultiple'] = $res['invalidTypesMultiple'];
}
return array('templates' => $templates, 'types' => $attribute_types);
}
public function groupAttributesIntoObject($user, $event_id, $object, $template, $selected_attribute_ids, $selected_object_relation_mapping, $hard_delete_attribute)
{
$saved_object_id = $this->saveObject($object, $event_id, $template, $user);
if (!is_numeric($saved_object_id)) {
return $saved_object_id;
}
$saved_object = $this->find('first', array(
'recursive' => -1,
'conditions' => array('Object.id' => $saved_object_id)
));
$existing_attributes = $this->Attribute->fetchAttributes($user, array('conditions' => array(
'Attribute.id' => $selected_attribute_ids,
'Attribute.event_id' => $event_id,
'Attribute.object_id' => 0
)));
if (empty($existing_attributes)) {
return __('Selected Attributes do not exist.');
}
$event = array('Event' => $existing_attributes[0]['Event']);
// Duplicate the attribute and its context, otherwise connected instances will drop the duplicated UUID
foreach ($existing_attributes as $i => $existing_attribute) {
if (isset($selected_object_relation_mapping[$existing_attribute['Attribute']['id']])) {
$sightings = $this->Event->Sighting->attachToEvent($event, $user, $existing_attribute['Attribute']['id']);
$object_relation = $selected_object_relation_mapping[$existing_attribute['Attribute']['id']];
$created_attribute = $existing_attribute['Attribute'];
unset($created_attribute['timestamp']);
unset($created_attribute['id']);
unset($created_attribute['uuid']);
$created_attribute['object_relation'] = $object_relation;
$created_attribute['object_id'] = $saved_object['Object']['id'];
if (isset($existing_attribute['AttributeTag'])) {
$created_attribute['AttributeTag'] = $existing_attribute['AttributeTag'];
}
if (!empty($sightings)) {
$created_attribute['Sighting'] = $sightings;
}
$saved_object['Attribute'][$i] = $created_attribute;
$this->Attribute->captureAttribute($created_attribute, $event_id, $user, $saved_object['Object']['id']);
$this->Attribute->deleteAttribute($existing_attribute['Attribute']['id'], $user, $hard_delete_attribute);
}
}
return $saved_object['Object']['id'];
}
}

View File

@ -0,0 +1,62 @@
<?php
App::uses('AppModel', 'Model');
class NotificationLog extends AppModel
{
public $useTable = 'notification_logs';
public $displayField = 'name';
public $actsAs = array(
'Trim'
);
private $__counter = 0;
public function addEntry($org_id, $type)
{
$this->cleanup();
$notification = array(
'org_id' => $org_id,
'type' => $type,
'timestamp' => time()
);
$this->create();
$this->save($notification);
return true;
}
public function cleanup()
{
if ($this->__counter%100 === 0) {
$time_limit = time() - 86400;
$this->deleteAll(
array(
'NotificationLog.timestamp <' => $time_limit
)
);
}
$this->__counter++;
return true;
}
public function check($org_id, $type)
{
$this->addEntry($org_id, $type);
$this->cleanup();
if (!empty(Configure::read('MISP.org_alert_threshold'))) {
$count = $this->find('count', array(
'conditions' => array(
'org_id' => $org_id,
'type' => $type
)
));
if ((int)Configure::read('MISP.org_alert_threshold') <= ($count)) {
return false;
}
}
return true;
}
}

View File

@ -262,4 +262,41 @@ class ObjectReference extends AppModel
$result = $this->save(array('ObjectReference' => $reference));
return true;
}
public function getReferencedInfo($referencedUuid, $object, $strict = true)
{
$referenced_type = 1;
$target_object = $this->Object->find('first', array(
'conditions' => array('Object.uuid' => $referencedUuid, 'Object.deleted' => 0),
'recursive' => -1,
'fields' => array('Object.id', 'Object.uuid', 'Object.event_id')
));
if (!empty($target_object)) {
$referenced_id = $target_object['Object']['id'];
$referenced_uuid = $target_object['Object']['uuid'];
if ($target_object['Object']['event_id'] != $object['Event']['id']) {
throw new NotFoundException('Invalid target. Target has to be within the same event.');
}
} else {
$target_attribute = $this->Object->Attribute->find('first', array(
'conditions' => array('Attribute.uuid' => $referencedUuid, 'Attribute.deleted' => 0),
'recursive' => -1,
'fields' => array('Attribute.id', 'Attribute.uuid', 'Attribute.event_id')
));
if (empty($target_attribute)) {
if ($strict) {
throw new NotFoundException('Invalid target.');
} else {
return array(0, 0, 0);
}
}
if ($target_attribute['Attribute']['event_id'] != $object['Event']['id']) {
throw new NotFoundException('Invalid target. Target has to be within the same event.');
}
$referenced_id = $target_attribute['Attribute']['id'];
$referenced_uuid = $target_attribute['Attribute']['uuid'];
$referenced_type = 0;
}
return array($referenced_id, $referenced_uuid, $referenced_type);
}
}

View File

@ -204,6 +204,74 @@ class ObjectTemplate extends AppModel
return true;
}
public function checkTemplateConformityBasedOnTypes($template, $attributes)
{
$to_return = array('valid' => true, 'missingTypes' => array());
if (!empty($template['ObjectTemplate']['requirements'])) {
// check for all required attributes
if (!empty($template['ObjectTemplate']['requirements']['required'])) {
foreach ($template['ObjectTemplate']['requirements']['required'] as $requiredField) {
$requiredType = Hash::extract($template['ObjectTemplateElement'], sprintf('{n}[object_relation=%s].type', $requiredField))[0];
$found = false;
foreach ($attributes as $attribute) {
if ($attribute['Attribute']['type'] == $requiredType) {
$found = true;
}
}
if (!$found) {
$to_return = array('valid' => false, 'missingTypes' => array($requiredType));
}
}
}
// check for all required one of attributes
if (!empty($template['ObjectTemplate']['requirements']['requiredOneOf'])) {
$found = false;
$all_required_type = array();
foreach ($template['ObjectTemplate']['requirements']['requiredOneOf'] as $requiredField) {
$requiredType = Hash::extract($template['ObjectTemplateElement'], sprintf('{n}[object_relation=%s].type', $requiredField));
$requiredType = empty($requiredType) ? NULL : $requiredType[0];
$all_required_type[] = $requiredType;
foreach ($attributes as $attribute) {
if ($attribute['Attribute']['type'] == $requiredType) {
$found = true;
}
}
}
if (!$found) {
$to_return = array('valid' => false, 'missingTypes' => $all_required_type);
}
}
}
// at this point, an object could created; checking if all attribute are valids
$valid_types = array();
$to_return['invalidTypes'] = array();
$to_return['invalidTypesMultiple'] = array();
foreach ($template['ObjectTemplateElement'] as $templateElement) {
$valid_types[$templateElement['type']] = $templateElement['multiple'];
}
$check_for_multiple_type = array();
foreach ($attributes as $attribute) {
if (isset($valid_types[$attribute['Attribute']['type']])) {
if (!$valid_types[$attribute['Attribute']['type']]) { // is not multiple
if (isset($check_for_multiple_type[$attribute['Attribute']['type']])) {
$to_return['invalidTypesMultiple'][] = $attribute['Attribute']['type'];
} else {
$check_for_multiple_type[$attribute['Attribute']['type']] = 1;
}
}
} else {
$to_return['invalidTypes'][] = $attribute['Attribute']['type'];
}
}
$to_return['invalidTypes'] = array_unique($to_return['invalidTypes']);
$to_return['invalidTypesMultiple'] = array_unique($to_return['invalidTypesMultiple']);
if (!empty($to_return['invalidTypesMultiple'])) {
$to_return['valid'] = false;
}
return $to_return;
}
// simple test to see if there are any object templates - if not trigger update
public function populateIfEmpty($user)
{

View File

@ -192,6 +192,15 @@ class Server extends AppModel
'type' => 'boolean',
'null' => true
),
'server_settings_skip_backup_rotate' => array(
'level' => 1,
'description' => __('Enable this setting to directly save the config.php file without first creating a temporary file and moving it to avoid concurency issues. Generally not recommended, but useful when for example other tools modify/maintain the config.php file.'),
'value' => false,
'errorMessage' => '',
'test' => 'testBool',
'type' => 'boolean',
'null' => true
),
'python_bin' => array(
'level' => 1,
'description' => __('It is highly recommended to install all the python dependencies in a virtualenv. The recommended location is: %s/venv', ROOT),
@ -201,6 +210,7 @@ class Server extends AppModel
'test' => 'testForBinExec',
'beforeHook' => 'beforeHookBinExec',
'type' => 'string',
'cli_only' => 1
),
'disable_auto_logout' => array(
'level' => 1,
@ -456,6 +466,7 @@ class Server extends AppModel
'null' => false,
'test' => 'testForWritableDir',
'type' => 'string',
'cli_only' => 1
),
'cached_attachments' => array(
'level' => 1,
@ -712,6 +723,33 @@ class Server extends AppModel
'test' => 'testBool',
'type' => 'boolean',
),
'log_paranoid' => array(
'level' => 0,
'description' => __('If this functionality is enabled all page requests will be logged. Keep in mind this is extremely verbose and will become a burden to your database.'),
'value' => false,
'errorMessage' => '',
'test' => 'testBoolFalse',
'type' => 'boolean',
'null' => true
),
'log_paranoid_skip_db' => array(
'level' => 0,
'description' => __('You can decide to skip the logging of the paranoid logs to the database.'),
'value' => false,
'errorMessage' => '',
'test' => 'testParanoidSkipDb',
'type' => 'boolean',
'null' => true
),
'log_paranoid_include_post_body' => array(
'level' => 0,
'description' => __('If paranoid logging is enabled, include the POST body in the entries.'),
'value' => false,
'errorMessage' => '',
'test' => 'testBool',
'type' => 'boolean',
'null' => true
),
'delegation' => array(
'level' => 1,
'description' => __('This feature allows users to create org only events and ask another organisation to take ownership of the event. This allows organisations to remain anonymous by asking a partner to publish an event for them.'),
@ -785,6 +823,15 @@ class Server extends AppModel
'type' => 'string',
'null' => false,
),
'org_alert_threshold' => array(
'level' => 1,
'description' => __('Set a value to limit the number of email alerts that events can generate per creator organisation (for example, if an organisation pushes out 2000 events in one shot, only alert on the first 20).'),
'value' => 0,
'errorMessage' => '',
'test' => 'testForNumeric',
'type' => 'numeric',
'null' => true,
),
'block_old_event_alert' => array(
'level' => 1,
'description' => __('Enable this setting to start blocking alert e-mails for old events. The exact timing of what constitutes an old event is defined by MISP.block_old_event_alert_age.'),
@ -811,6 +858,7 @@ class Server extends AppModel
'test' => 'testForPath',
'type' => 'string',
'null' => true,
'cli_only' => 1
),
'custom_css' => array(
'level' => 2,
@ -915,7 +963,15 @@ class Server extends AppModel
'test' => 'testBool',
'type' => 'boolean',
'null' => true
)
),
'updateTimeThreshold' => array(
'level' => 1,
'description' => __('Sets the minimum time before being able to re-trigger an update if the previous one failed. (safe guard to avoid starting the same update multiple time)'),
'value' => '7200',
'test' => 'testForNumeric',
'type' => 'numeric',
'null' => true
)
),
'GnuPG' => array(
'branch' => 1,
@ -926,6 +982,7 @@ class Server extends AppModel
'errorMessage' => '',
'test' => 'testForGPGBinary',
'type' => 'string',
'cli_only' => 1
),
'onlyencrypted' => array(
'level' => 0,
@ -1223,15 +1280,15 @@ class Server extends AppModel
'RPZ_policy' => array(
'level' => 2,
'description' => __('The default policy action for the values added to the RPZ.'),
'value' => 0,
'value' => 1,
'errorMessage' => '',
'test' => 'testForRPZBehaviour',
'type' => 'numeric',
'options' => array(0 => 'DROP', 1 => 'NXDOMAIN', 2 => 'NODATA', 3 => 'walled-garden'),
'options' => array(0 => 'DROP', 1 => 'NXDOMAIN', 2 => 'NODATA', 3 => 'Local-Data', 4 => 'PASSTHRU', 5 => 'TCP-only' ),
),
'RPZ_walled_garden' => array(
'level' => 2,
'description' => __('The default walled garden used by the RPZ export if the walled garden setting is picked for the export.'),
'description' => __('The default walled garden used by the RPZ export if the Local-Data policy setting is picked for the export.'),
'value' => '127.0.0.1',
'errorMessage' => '',
'test' => 'testForEmpty',
@ -1239,7 +1296,7 @@ class Server extends AppModel
),
'RPZ_serial' => array(
'level' => 2,
'description' => __('The serial in the SOA portion of the zone file. (numeric, best practice is yyyymmddrr where rr is the two digit sub-revision of the file. $date will automatically get converted to the current yyyymmdd, so $date00 is a valid setting).'),
'description' => __('The serial in the SOA portion of the zone file. (numeric, best practice is yyyymmddrr where rr is the two digit sub-revision of the file. $date will automatically get converted to the current yyyymmdd, so $date00 is a valid setting). Setting it to $time will give you an unixtime-based serial (good then you need more than 99 revisions per day).'),
'value' => '$date00',
'errorMessage' => '',
'test' => 'testForRPZSerial',
@ -2158,6 +2215,31 @@ class Server extends AppModel
return $event;
}
private function __checkIfEventSaveAble($event) {
if (!empty($event['Event']['Attribute'])) {
foreach ($event['Event']['Attribute'] as $attribute) {
if (empty($attribute['deleted'])) {
return true;
}
}
}
if (!empty($event['Event']['Object'])) {
foreach ($event['Event']['Object'] as $object) {
if (!empty($object['deleted'])) {
continue;
}
if (!empty($object['Attribute'])) {
foreach ($object['Attribute'] as $attribute) {
if (empty($attribute['deleted'])) {
return true;
}
}
}
}
}
return false;
}
private function __checkIfPulledEventExistsAndAddOrUpdate($event, $eventId, &$successes, &$fails, $eventModel, $server, $user, $jobId)
{
// check if the event already exist (using the uuid)
@ -2199,7 +2281,11 @@ class Server extends AppModel
return false;
}
$event = $this->__updatePulledEventBeforeInsert($event, $server, $user);
$this->__checkIfPulledEventExistsAndAddOrUpdate($event, $eventId, $successes, $fails, $eventModel, $server, $user, $jobId);
if (!$this->__checkIfEventSaveAble($event)) {
$fails[$eventId] = __('Empty event detected.');
} else {
$this->__checkIfPulledEventExistsAndAddOrUpdate($event, $eventId, $successes, $fails, $eventModel, $server, $user, $jobId);
}
} else {
// error
$fails[$eventId] = __('failed downloading the event');
@ -2576,7 +2662,7 @@ class Server extends AppModel
'event_uuid' => $eventUuid,
'includeAttachments' => true,
'includeAllTags' => true,
'deleted' => true,
'deleted' => array(0,1),
'excludeGalaxy' => 1
));
$event = $this->Event->fetchEvent($user, $params);
@ -3003,6 +3089,9 @@ class Server extends AppModel
public function testForBinExec($value)
{
if (substr($value, 0, 7) === "phar://") {
return 'Phar protocol not allowed.';
}
$finfo = finfo_open(FILEINFO_MIME_TYPE);
if ($value === '') {
return true;
@ -3021,6 +3110,9 @@ class Server extends AppModel
public function testForWritableDir($value)
{
if (substr($value, 0, 7) === "phar://") {
return 'Phar protocol not allowed.';
}
if (!is_dir($value)) {
return 'Not a valid directory.';
}
@ -3176,6 +3268,14 @@ class Server extends AppModel
}
}
public function testParanoidSkipDb($value)
{
if (!empty(Configure::read('MISP.log_paranoid')) && empty($value)) {
return 'Perhaps consider skipping the database when using paranoid mode. A great number of entries will be added to your log database otherwise that will lead to performance degradation.';
}
return true;
}
public function testSalt($value)
{
if ($this->testForEmpty($value) !== true) {
@ -3286,8 +3386,8 @@ class Server extends AppModel
if ($numeric !== true) {
return $numeric;
}
if ($value < 0 || $value > 3) {
return 'Invalid setting, valid range is 0-3 (0 = DROP, 1 = NXDOMAIN, 2 = NODATA, 3 = walled garden.';
if ($value < 0 || $value > 5) {
return 'Invalid setting, valid range is 0-5 (0 = DROP, 1 = NXDOMAIN, 2 = NODATA, 3 = walled garden, 4 = PASSTHRU, 5 = TCP-only.';
}
return true;
}
@ -3317,7 +3417,7 @@ class Server extends AppModel
if ($this->testForEmpty($value) !== true) {
return $this->testForEmpty($value);
}
if (!preg_match('/^((\$date(\d*)|\d*))$/', $value)) {
if (!preg_match('/^((\$date(\d*)|\$time|\d*))$/', $value)) {
return 'Invalid format.';
}
return true;
@ -3643,26 +3743,30 @@ class Server extends AppModel
if (function_exists('opcache_reset')) {
opcache_reset();
}
$randomFilename = $this->generateRandomFileName();
// To protect us from 2 admin users having a concurent file write to the config file, solar flares and the bogeyman
file_put_contents(APP . 'Config' . DS . $randomFilename, $settingsString);
rename(APP . 'Config' . DS . $randomFilename, APP . 'Config' . DS . 'config.php');
$config_saved = file_get_contents(APP . 'Config' . DS . 'config.php');
// if the saved config file is empty, restore the backup.
if (strlen($config_saved) < 20) {
copy(APP . 'Config' . DS . 'config.php.bk', APP . 'Config' . DS . 'config.php');
$this->Log = ClassRegistry::init('Log');
$this->Log->create();
$this->Log->save(array(
'org' => 'SYSTEM',
'model' => 'Server',
'model_id' => $id,
'email' => 'SYSTEM',
'action' => 'error',
'user_id' => 0,
'title' => 'Error: Something went wrong saving the config file, reverted to backup file.',
));
return false;
if (empty(Configure::read('MISP.server_settings_skip_backup_rotate'))) {
$randomFilename = $this->generateRandomFileName();
// To protect us from 2 admin users having a concurent file write to the config file, solar flares and the bogeyman
file_put_contents(APP . 'Config' . DS . $randomFilename, $settingsString);
rename(APP . 'Config' . DS . $randomFilename, APP . 'Config' . DS . 'config.php');
$config_saved = file_get_contents(APP . 'Config' . DS . 'config.php');
// if the saved config file is empty, restore the backup.
if (strlen($config_saved) < 20) {
copy(APP . 'Config' . DS . 'config.php.bk', APP . 'Config' . DS . 'config.php');
$this->Log = ClassRegistry::init('Log');
$this->Log->create();
$this->Log->save(array(
'org' => 'SYSTEM',
'model' => 'Server',
'model_id' => $id,
'email' => 'SYSTEM',
'action' => 'error',
'user_id' => 0,
'title' => 'Error: Something went wrong saving the config file, reverted to backup file.',
));
return false;
}
} else {
file_put_contents(APP . 'Config' . DS . 'config.php', $settingsString);
}
return true;
}
@ -3785,6 +3889,22 @@ class Server extends AppModel
return array('status' => 6);
}
}
$this->Log = ClassRegistry::init('Log');
$this->Log->create();
$this->Log->save(array(
'org' => 'SYSTEM',
'model' => 'Server',
'model_id' => $id,
'email' => 'SYSTEM',
'action' => 'error',
'user_id' => 0,
'title' => 'Error: Connection test failed. Returned data is in the change field.',
'change' => sprintf(
'response () => (%s), response-code () => (%s)',
$response->body,
$response->code
)
));
return array('status' => 3);
}
}
@ -4046,6 +4166,13 @@ class Server extends AppModel
return $readableFiles;
}
public function yaraDiagnostics(&$diagnostic_errors)
{
$scriptResult = shell_exec($this->getPythonVersion() . ' ' . APP . 'files' . DS . 'scripts' . DS . 'yaratest.py');
$scriptResult = json_decode($scriptResult, true);
return array('operational' => $scriptResult['success'], 'plyara' => $scriptResult['plyara']);
}
public function stixDiagnostics(&$diagnostic_errors, &$stixVersion, &$cyboxVersion, &$mixboxVersion, &$maecVersion, &$stix2Version, &$pymispVersion)
{
$result = array();
@ -4616,7 +4743,11 @@ class Server extends AppModel
$submodule_name=end($submodule_name);
$submoduleRemote=exec('cd ' . $path . '; git config --get remote.origin.url');
exec(sprintf('cd %s; git rev-parse HEAD', $path), $submodule_current_commit_id);
$submodule_current_commit_id = $submodule_current_commit_id[0];
if (!empty($submodule_current_commit_id[0])) {
$submodule_current_commit_id = $submodule_current_commit_id[0];
} else {
$submodule_current_commit_id = null;
}
$status = array(
'moduleName' => $submodule_name,
'current' => $submodule_current_commit_id,
@ -4640,7 +4771,11 @@ class Server extends AppModel
}
if ($status['isReadable'] && !empty($status['remoteTimestamp']) && !empty($status['currentTimestamp'])) {
$status['timeDiff'] = (new DateTime('@' . $status['remoteTimestamp']))->diff(new DateTime('@' . $status['currentTimestamp']));
$date1 = new DateTime();
$date1->setTimestamp($status['remoteTimestamp']);
$date2 = new DateTime();
$date2->setTimestamp($status['currentTimestamp']);
$status['timeDiff'] = $date1->diff($date2);
} else {
$status['upToDate'] = 'error';
}
@ -4685,7 +4820,7 @@ class Server extends AppModel
'retries' => 0,
'org_id' => $user['org_id'],
'org' => $user['Organisation']['name'],
'message' => 'Update database after PULL.',
'message' => 'Update the database after PULLing the submodule(s).',
);
$job->save($data);
$jobId = $job->id;
@ -4918,4 +5053,16 @@ class Server extends AppModel
}
return $data;
}
public function updateJSON()
{
$toUpdate = array('Galaxy', 'Noticelist', 'Warninglist', 'Taxonomy', 'ObjectTemplate');
$results = array();
foreach ($toUpdate as $target) {
$this->$target = ClassRegistry::init($target);
$result = $this->$target->update();
$results[$target] = $result === false ? false : true;
}
return $results;
}
}

View File

@ -195,6 +195,19 @@ class Tag extends AppModel
return array($acceptIds, $rejectIds);
}
// find all of the tag Ids that belong to the accepted tags and the rejected tags
public function fetchTagIdsSimple($tags = array())
{
$results = array();
if (!empty($tags)) {
$results = $this->findTagIdsByTagNames($tags);
if (empty($results)) {
$results[] = -1;
}
}
return $results;
}
// find all of the tag Ids that belong to the accepted tags and the rejected tags
public function fetchTagIds($accept = array(), $reject = array())
{

View File

@ -282,15 +282,46 @@ class Warninglist extends AppModel
return $warninglists;
}
public function checkForWarning($object, &$eventWarnings, $warningLists)
public function simpleCheckForWarning($object, $warninglists, $returnVerboseValue = false)
{
if ($object['to_ids']) {
foreach ($warninglists as $list) {
if (in_array('ALL', $list['types']) || in_array($object['type'], $list['types'])) {
$result = $this->__checkValue($list['values'], $object['value'], $object['type'], $list['Warninglist']['type']);
if (!empty($result)) {
if ($returnVerboseValue) {
$object['warnings'][] = array(
'value' => $result,
'warninglist_name' => $list['Warninglist']['name'],
'warninglist_id' => $list['Warninglist']['id']
);
} else {
$object['warnings'][$result][] = $list['Warninglist']['name'];
}
}
}
}
}
return $object;
}
public function checkForWarning($object, &$eventWarnings, $warningLists, $returnVerboseValue = false)
{
if ($object['to_ids']) {
foreach ($warningLists as $list) {
if (in_array('ALL', $list['types']) || in_array($object['type'], $list['types'])) {
$result = $this->__checkValue($list['values'], $object['value'], $object['type'], $list['Warninglist']['type']);
$result = $this->__checkValue($list['values'], $object['value'], $object['type'], $list['Warninglist']['type'], $returnVerboseValue);
if (!empty($result)) {
$object['warnings'][$result][] = $list['Warninglist']['name'];
if (!in_array($list['Warninglist']['name'], $eventWarnings)) {
if ($returnVerboseValue) {
$object['warnings'][] = array(
'value' => $result,
'warninglist_name' => $list['Warninglist']['name'],
'warninglist_id' => $list['Warninglist']['id']
);
} else {
$object['warnings'][$result][] = $list['Warninglist']['name'];
}
if (empty($eventWarnings) || !in_array($list['Warninglist']['name'], $eventWarnings)) {
$eventWarnings[$list['Warninglist']['id']] = $list['Warninglist']['name'];
}
}
@ -325,7 +356,7 @@ class Warninglist extends AppModel
return $event;
}
private function __checkValue($listValues, $value, $type, $listType)
private function __checkValue($listValues, $value, $type, $listType, $returnVerboseValue = false)
{
if (strpos($type, '|') || $type = 'malware-sample') {
$value = explode('|', $value);
@ -349,7 +380,11 @@ class Warninglist extends AppModel
$result = $this->__evalRegex($listValues, $value[$component]);
}
if (!empty($result)) {
return ($component + 1);
if ($returnVerboseValue) {
return $value[$component];
} else {
}
return ($component + 1);
}
}
return false;

View File

@ -44,7 +44,7 @@ in the list given by apache.
If used with Apache as webserver it might be useful to make a distinction to filter out API/Syncs from SSO login. It can be added to the vhost as follows:
```Apache
<If "-T reqenv('HTTP_AUTHORIZATION')">
<If "-T req('Authorization')">
Require all granted
AuthType None
</If>

View File

@ -75,7 +75,7 @@
?>
</fieldset>
<?php
echo $this->Form->button('Upload', array('class' => 'btn btn-primary'));
echo $this->Form->button(__('Upload'), array('class' => 'btn btn-primary'));
echo $this->Form->end();
?>
</div>

View File

@ -1,8 +1,32 @@
<div style="overflow-y:auto;max-height:75vh">
<?php
foreach ($results as $enrichment_type => $enrichment_values):
echo sprintf('<span class="hover_enrichment_title blue">%s</span>: <br />', Inflector::humanize(h($enrichment_type)));
echo sprintf('<h5><span class="hover_enrichment_title blue">%s</span>:</h5>', Inflector::humanize(h($enrichment_type)));
if (empty($enrichment_values)) {
echo '<div style="padding: 2px;"><span class="empty_results_text red">Empty results</span></div>';
continue;
}
if (!empty($enrichment_values['Object'])) {
echo '<h6><span class="bold blue">Objects</span></h6>';
foreach ($enrichment_values['Object'] as $object) {
echo '<span class="object_name bold blue">' . h($object['name']) . '</span><br />';
foreach ($object['Attribute'] as $object_attribute) {
echo '<div style="padding: 2px;"><pre class="object_attribute">';
echo '<span class="attribute_object_relation bold blue">' . h($object_attribute['object_relation']) . '</span>';
echo ': <span class="attribute_value red">' . h($object_attribute['value']) . '</span></pre></div>';
}
}
unset($enrichment_values['Object']);
}
if (!empty($enrichment_values['Attribute'])) {
echo '<h6><span class="bold blue">Attributes</span><br />';
foreach ($enrichment_values['Attribute'] as $attribute) {
echo '<div style="padding: 2px;"><pre class="attribute">';
echo '<span class="attribute_type bold blue">' . h($attribute['type']) . '</span>';
echo ': <span class="attribute_value red">' . h($attribute['value']) . '</span></pre></div>';
}
unset($enrichment_values['Attribute']);
}
foreach ($enrichment_values as $attributes):
foreach ($attributes as $attribute):
echo '<div style="padding: 2px;">';
@ -12,9 +36,9 @@
echo '<span class="hover_enrichment_text blue">' . h($attribute_name) . ':</span>';
}
echo '<span><pre class="hover_enrichment_text red">' . h($attribute_value) . '</pre></span>';
}
}
} else {
echo '<span><pre class="hover_enrichment_text red ">' . h($attribute) . '</pre></span>';
echo '<span><pre class="hover_enrichment_text red ">' . h($attribute) . '</pre></span>';
}
echo '</div>';
endforeach;

View File

@ -169,7 +169,7 @@ $(document).ready(function () {
object_id = selected.join('|');
}
url = "<?php echo $baseurl; ?>" + "/sightings/advanced/" + object_id + "/" + object_context;
genericPopup(url, '#screenshot_box');
genericPopup(url, '#popover_box');
});
$('.correlation-toggle').click(function() {
var attribute_id = $(this).data('attribute-id');

View File

@ -1,6 +1,6 @@
<div id="eventFilteringQBWrapper" style="padding: 5px; display: none; border: 1px solid #dddddd; border-bottom: 0px;">
<div id="eventFilteringQB"></div>
<div style="display: flex; justify-content: flex-end">
<div id="eventFilteringQB" style="overflow-y: auto; padding-right: 5px; resize: vertical; max-height: 750px; height: 400px;"></div>
<div style="display: flex; justify-content: flex-end; margin-top: 5px;">
<input id="eventFilteringQBLinkInput" class="form-control" style="width: 66%;"></input>
<button id="eventFilteringQBLinkCopy" type="button" class="btn btn-inverse" style="margin-right: 5px; margin-left: 5px;" onclick="clickMessage(this);"> <i class="fa fa-clipboard"></i> <?php echo h('Copy to clipboard'); ?> </button>
<button id="eventFilteringQBSubmit" type="button" class="btn btn-success" style="margin-right: 5px;"> <i class="fa fa-filter"></i> <?php echo h('Filter'); ?> </button>
@ -11,8 +11,9 @@
?>
<script>
function triggerEventFilteringTool(clicked) {
var defaultFilteringRules = <?php echo json_encode($defaultFilteringRules); ?>;
var defaultFilteringRules = <?php echo json_encode($defaultFilteringRules); ?>;
var querybuilderTool;
function triggerEventFilteringTool(hide) {
var qbOptions = {
plugins: {
'filter-description' : {
@ -197,7 +198,12 @@ function triggerEventFilteringTool(clicked) {
2: "Doesn\'t have sighting(s)"
}
},
<?php if (!empty($attributeTags)): ?>
<?php
if (empty($attributeTags) && isset($filters['taggedAttributes'])) {
$attributeTags = array($filters['taggedAttributes']);
}
if (!empty($attributeTags)):
?>
{
"input": "select",
"type": "string",
@ -207,10 +213,15 @@ function triggerEventFilteringTool(clicked) {
"unique": true,
"id": "taggedAttributes",
"label": "Tags",
"values": <?php echo json_encode($attributeTags); ?>
"values": <?php echo json_encode(array_map("h", $attributeTags)); // additional `h` because values are directly insterted into the DOM by QB.?>
},
<?php endif; ?>
<?php if (!empty($attributeClusters)): ?>
<?php
if (empty($attributeClusters) && isset($filters['galaxyAttachedAttributes'])) {
$attributeClusters = array($filters['galaxyAttachedAttributes']);
}
if (!empty($attributeClusters)):
?>
{
"input": "select",
"type": "string",
@ -220,7 +231,7 @@ function triggerEventFilteringTool(clicked) {
"unique": true,
"id": "galaxyAttachedAttributes",
"label": "Galaxies",
"values": <?php echo json_encode($attributeClusters); ?>
"values": <?php echo json_encode(array_map("h", $attributeClusters)); // additional `h` because values are directly insterted into the DOM by QB.?>
},
<?php endif; ?>
{
@ -335,20 +346,24 @@ function triggerEventFilteringTool(clicked) {
value: <?php echo isset($filters['distribution']) ? json_encode($filters['distribution']) : json_encode(array(0, 1, 2, 3, 4, 5)); ?>
},
<?php endif; ?>
<?php if (!empty($attributeTags) && (count($advancedFilteringActiveRules) == 0 || isset($advancedFilteringActiveRules['taggedAttributes']))): ?>
{
field: 'taggedAttributes',
id: 'taggedAttributes',
value: '<?php echo isset($filters['taggedAttributes']) ? h($filters['taggedAttributes']) : $attributeTags[0]; ?>'
},
<?php endif; ?>
<?php if (!empty($attributeClusters) && (count($advancedFilteringActiveRules) == 0 || isset($advancedFilteringActiveRules['galaxyAttachedAttributes']))): ?>
{
field: 'galaxyAttachedAttributes',
id: 'galaxyAttachedAttributes',
value: '<?php echo isset($filters['galaxyAttachedAttributes']) ? h($filters['galaxyAttachedAttributes']) : $attributeClusters[0]; ?>'
},
<?php endif; ?>
<?php
if (!empty($filters['taggedAttributes']) && (count($advancedFilteringActiveRules) == 0 || isset($advancedFilteringActiveRules['taggedAttributes']))):
$tmp = array(
'field' => 'taggedAttributes',
'id' => 'taggedAttributes',
'value' => $filters['taggedAttributes']
);
echo json_encode($tmp) . ','; // sanitize data
endif;
if (!empty($filters['galaxyAttachedAttributes']) && (count($advancedFilteringActiveRules) == 0 || isset($advancedFilteringActiveRules['galaxyAttachedAttributes']))):
$tmp = array(
'field' => 'galaxyAttachedAttributes',
'id' => 'galaxyAttachedAttributes',
'value' => $filters['galaxyAttachedAttributes']
);
echo json_encode($tmp); // sanitize data
endif;
?>
],
flags: {
no_add_group: true,
@ -367,13 +382,16 @@ function triggerEventFilteringTool(clicked) {
var filters = <?php echo json_encode($filters); ?>;
var $wrapper = $('#eventFilteringQBWrapper');
var $ev = $('#eventFilteringQB');
var querybuilderTool = $ev.queryBuilder(qbOptions);
querybuilderTool = $ev.queryBuilder(qbOptions);
querybuilderTool = querybuilderTool[0].queryBuilder;
querybuilderTool.on('rulesChanged', function() {
updateURL();
});
$wrapper.toggle('blind', 100, { direction: 'up' });
if (hide === undefined || !hide) {
$('#eventFilteringQB').height(qbOptions.rules.rules.length < 7 ? 'unset' : $('#eventFilteringQB').height());
$wrapper.toggle('blind', 100, { direction: 'up' });
}
$('#eventFilteringQBSubmit').off('click').on('click', function() {
$button = $(this);
@ -402,29 +420,29 @@ function triggerEventFilteringTool(clicked) {
function updateURL() {
var rules = querybuilderTool.getRules({ skip_empty: true, allow_invalid: true });
var res = cleanRules(rules);
var url = "<?php echo $baseurl; ?>/events/view/<?php echo h($event['Event']['id']); ?>" + buildURL(res);
var url = "<?php echo $baseurl; ?>/events/view/<?php echo h($event['Event']['id']); ?>" + buildFilterURL(res);
$('#eventFilteringQBLinkInput').val(url);
}
}
function buildURL(res) {
var url = "";
Object.keys(res).forEach(function(k) {
var v = res[k];
if (Array.isArray(v)) {
// v = JSON.stringify(v);
v = v.join('||');
}
if (!Array.isArray(defaultFilteringRules[k]) && defaultFilteringRules[k] != v) {
url += "/" + k + ":" + v;
} else {
if (Array.isArray(defaultFilteringRules[k]) && defaultFilteringRules[k].join('||') != v) {
url += "/" + k + ":" + v;
}
}
});
return url;
}
function buildFilterURL(res) {
var url = "";
Object.keys(res).forEach(function(k) {
var v = res[k];
if (Array.isArray(v)) {
// v = JSON.stringify(v);
v = v.join('||');
}
if (!Array.isArray(defaultFilteringRules[k]) && defaultFilteringRules[k] != v) {
url += "/" + k + ":" + encodeURIComponent(v);
} else {
if (Array.isArray(defaultFilteringRules[k]) && defaultFilteringRules[k].join('||') != v) {
url += "/" + k + ":" + encodeURIComponent(v);
}
}
});
return url;
}
function recursiveInject(result, rules) {

View File

@ -0,0 +1,30 @@
<?php
$href_url = isset($href_url) ? $href_url : $baseurl . '/events';
$hide = isset($hide) ? $hide : false;
?>
<span class="<?php echo $hide ? 'hidden correlation-expanded-area' : '' ?>">
<span style="display: inline-block; border: 1px solid #ddd; border-radius: 5px; padding: 3px; background-color: white;">
<table>
<tbody>
<tr>
<td rowspan="2" style="border-right: 1px solid #ddd; padding-right: 2px; max-width: 24px; overflow: hidden; font-size: xx-small; text-overflow: ellipsis;" title="<?php echo h($related['Orgc']['name']); ?>">
<?php echo $this->OrgImg->getOrgImg(array('name' => $related['Orgc']['name'], 'id' => $related['Orgc']['id'], 'size' => 24)); ?>
</td>
<td style="line-height: 14px; padding-left: 2px; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; max-width: 430px;">
<a title="<?php echo h($related['info']); ?>" href="<?php echo h($href_url) . '/' . $related['id']?>">
<span><?php echo h($related['info']) ?>
</a>
</td>
</tr>
<tr>
<td style="line-height: 14px; padding-left: 2px;">
<i><?php echo h($related['date']); ?></i>
<?php if (isset($relatedEventCorrelationCount[$related['id']])): ?>
<b style="margin-left: 5px; float: right; cursor: help;" title="<?php echo __(sprintf('This related event contains %s unique correlation(s)', h($relatedEventCorrelationCount[$related['id']]))); ?>"> <?php echo h($relatedEventCorrelationCount[$related['id']]) ?></b>
<?php endif; ?>
</td>
</tr>
</tbody>
</table>
</span>
</span>

View File

@ -40,7 +40,7 @@
<?php
if ($mayModify):
?>
<input id = "select_<?php echo $object['id']; ?>" class="select_attribute row_checkbox" type="checkbox" data-id="<?php echo $object['id'];?>" />
<input id = "select_<?php echo $object['id']; ?>" class="select_attribute row_checkbox" type="checkbox" data-id="<?php echo $object['id'];?>" aria-label="<?php echo __('Select attribute');?>" />
<?php
endif;
?>
@ -61,7 +61,16 @@
if (!empty($extended)):
?>
<td class="short">
<?php echo '<a href="' . $baseurl . '/events/view/' . h($object['event_id']) . '">' . h($object['event_id']) . '</a>'; ?>
<?php
$event_info = '';
if (!empty($extended)) {
$event_info = sprintf('title="%s%s"',
__('Event info') . ':&#10; ',
$object['event_id'] != $event['Event']['id'] ? h($event['extensionEvents'][$object['event_id']]['info']) : h($event['Event']['info'])
);
}
?>
<?php echo '<a href="' . $baseurl . '/events/view/' . h($object['event_id']) . '" ' . $event_info . '>' . h($object['event_id']) . '</a>'; ?>
</td>
<?php
endif;
@ -184,6 +193,8 @@
<input
id="correlation_toggle_<?php echo h($object['id']); ?>"
class="correlation-toggle"
aria-label="<?php echo __('Toggle correlation');?>"
title="<?php echo __('Toggle correlation');?>"
type="checkbox"
data-attribute-id="<?php echo h($object['id']); ?>"
<?php
@ -227,8 +238,9 @@
if ($isSiteAdmin) {
if ($feed['source_format'] == 'misp') {
$liContents .= sprintf(
'<form action="%s/feeds/previewIndex/1" method="post" style="margin:0px;line-height:auto;">%s%s</form>',
'<form action="%s/feeds/previewIndex/%s" method="post" style="margin:0px;line-height:auto;">%s%s</form>',
$baseurl,
h($feed['id']),
sprintf(
'<input type="hidden" name="data[Feed][eventid]" value="%s">',
h(json_encode($feed['event_uuids'], true))
@ -243,9 +255,10 @@
$liContents .= sprintf(
'<form>%s</form>',
sprintf(
'<a href="%s/feeds/previewIndex/%s" style="margin-right:3px;">%s</a>',
'<a href="%s/feeds/previewIndex/%s" style="margin-right:3px;" data-toggle="popover" data-content="%s" data-trigger="hover">%s</a>',
$baseurl,
h($feed['id']),
h($popover),
h($feed['id'])
)
);
@ -307,7 +320,7 @@
<td class="short">
<div id = "Attribute_<?php echo $object['id']; ?>_to_ids_placeholder" class = "inline-field-placeholder"></div>
<div id = "Attribute_<?php echo $object['id']; ?>_to_ids_solid" class="inline-field-solid">
<input type="checkbox" class="toids-toggle" id="toids_toggle_<?php echo h($object['id']); ?>" data-attribute-id="<?php echo h($object['id']); ?>" <?php echo $object['to_ids'] ? 'checked' : ''; ?> ></input>
<input type="checkbox" class="toids-toggle" id="toids_toggle_<?php echo h($object['id']); ?>" data-attribute-id="<?php echo h($object['id']); ?>" aria-label="<?php echo __('Toggle IDS flag');?>" title="<?php echo __('Toggle IDS flag');?>" <?php echo $object['to_ids'] ? 'checked' : ''; ?> ></input>
</div>
</td>
<td class="short" onmouseenter="quickEditHover(this, '<?php echo $editScope; ?>', '<?php echo $object['id']; ?>', 'distribution', <?php echo $event['Event']['id'];?>);">

View File

@ -38,7 +38,7 @@
<tr id = "proposal<?php echo '_' . $object['id'] . '_tr'; ?>" class="<?php echo $tr_class; ?>" <?php echo $identifier; ?>>
<?php if ($mayModify): ?>
<td style="width:10px;" data-position="<?php echo h($object['objectType']) . '_' . h($object['id']); ?>">
<input id = "select_proposal_<?php echo $object['id']; ?>" class="select_proposal row_checkbox" type="checkbox" data-id="<?php echo $object['id'];?>" />
<input id = "select_proposal_<?php echo $object['id']; ?>" class="select_proposal row_checkbox" type="checkbox" aria-label="<?php __('Select proposal');?>" data-id="<?php echo $object['id'];?>" />
</td>
<?php endif; ?>
<td class="short context hidden">

View File

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

View File

@ -1,58 +1,60 @@
<?php
$sigDisplay = $object['value'];
if ('attachment' == $object['type'] || 'malware-sample' == $object['type'] ) {
if ($object['type'] == 'attachment' && isset($object['image'])) {
if (extension_loaded('gd')) {
$img = '<it class="fa fa-spin fa-spinner" style="font-size: large; left: 50%; top: 50%;"></it>';
$img .= '<img class="screenshot screenshot-collapsed useCursorPointer img-rounded hidden" src="' . $baseurl . '/attributes/viewPicture/' . h($object['id']) . '/1' . '" title="' . h($object['value']) . '" onload="$(this).show(200); $(this).parent().find(\'.fa-spinner\').remove();"/>';
echo $img;
$sigDisplay = $object['value'];
if ('attachment' == $object['type'] || 'malware-sample' == $object['type'] ) {
if ($object['type'] == 'attachment' && isset($object['image'])) {
if (extension_loaded('gd')) {
$img = '<it class="fa fa-spin fa-spinner" style="font-size: large; left: 50%; top: 50%;"></it>';
$img .= '<img class="screenshot screenshot-collapsed useCursorPointer img-rounded hidden" src="' . $baseurl . '/attributes/viewPicture/' . h($object['id']) . '/1' . '" title="' . h($object['value']) . '" onload="$(this).show(200); $(this).parent().find(\'.fa-spinner\').remove();"/>';
echo $img;
} else {
$extension = explode('.', $object['value']);
$extension = end($extension);
$uri = 'data:image/' . strtolower(h($extension)) . ';base64,' . h($object['image']);
echo '<img class="screenshot screenshot-collapsed useCursorPointer" src="' . $uri . '" title="' . h($object['value']) . '" />';
}
} else {
$extension = explode('.', $object['value']);
$extension = end($extension);
$uri = 'data:image/' . strtolower(h($extension)) . ';base64,' . h($object['image']);
echo '<img class="screenshot screenshot-collapsed useCursorPointer" src="' . $uri . '" title="' . h($object['value']) . '" />';
$filenameHash = explode('|', h($object['value']));
if (strrpos($filenameHash[0], '\\')) {
$filepath = substr($filenameHash[0], 0, strrpos($filenameHash[0], '\\'));
$filename = substr($filenameHash[0], strrpos($filenameHash[0], '\\'));
echo h($filepath);
echo '<a href="' . $baseurl . '/attributes/download/' . h($object['id']) . '" class="' . $linkClass . '">' . h($filename) . '</a>';
} else {
echo '<a href="' . $baseurl . '/attributes/download/' . h($object['id']) . '" class="' . $linkClass . '">' . h($filenameHash[0]) . '</a>';
}
if (isset($filenameHash[1])) echo '<br />' . $filenameHash[1];
}
} else if (strpos($object['type'], '|') !== false) {
$separator = in_array($object['type'], array('ip-dst|port', 'ip-src|port')) ? ':' : '<br />';
$value_pieces = explode('|', $object['value']);
foreach ($value_pieces as $k => $v) {
$value_pieces[$k] = h($v);
}
$object['value'] = implode($separator, $value_pieces);
echo ($object['value']);
} else if ('vulnerability' == $object['type']) {
$cveUrl = (is_null(Configure::read('MISP.cveurl'))) ? "http://www.google.com/search?q=" : Configure::read('MISP.cveurl');
echo $this->Html->link($sigDisplay, $cveUrl . $sigDisplay, array('target' => '_blank', 'class' => $linkClass));
} else if ('link' == $object['type'] && (substr($object['value'], 0, 7) === 'http://' || substr($object['value'], 0, 8) === 'https://')) {
echo $this->Html->link($sigDisplay, $sigDisplay, array('class' => $linkClass));
} else if ('cortex' == $object['type']) {
echo '<div class="cortex-json" data-cortex-json="' . h($object['value']) . '">Cortex object</div>';
} else if ('text' == $object['type']) {
if (($object['category'] == 'Internal reference' || $object['category'] == 'External analysis') && preg_match('/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/i', $object['value'])) {
echo '<a href="' . $baseurl . '/events/view/' . h($object['value']) . '" class="' . $linkClass . '">' . h($object['value']) . '</a>';
} else {
$sigDisplay = str_replace("\r", '', h($sigDisplay));
$sigDisplay = str_replace(" ", '&nbsp;', $sigDisplay);
echo $sigDisplay;
}
} else if ('hex' == $object['type']) {
$sigDisplay = str_replace("\r", '', $sigDisplay);
echo '<span class="hex-value" title="' . __('Hexadecimal representation') . '">' . h($sigDisplay) . '</span>&nbsp;<span role="button" tabindex="0" aria-label="' . __('Switch to binary representation') . '" class="icon-repeat hex-value-convert useCursorPointer" title="' . __('Switch to binary representation') . '"></span>';
} else {
$filenameHash = explode('|', h($object['value']));
if (strrpos($filenameHash[0], '\\')) {
$filepath = substr($filenameHash[0], 0, strrpos($filenameHash[0], '\\'));
$filename = substr($filenameHash[0], strrpos($filenameHash[0], '\\'));
echo h($filepath);
echo '<a href="' . $baseurl . '/attributes/download/' . h($object['id']) . '" class="' . $linkClass . '">' . h($filename) . '</a>';
} else {
echo '<a href="' . $baseurl . '/attributes/download/' . h($object['id']) . '" class="' . $linkClass . '">' . h($filenameHash[0]) . '</a>';
}
if (isset($filenameHash[1])) echo '<br />' . $filenameHash[1];
$sigDisplay = str_replace("\r", '', $sigDisplay);
echo h($sigDisplay);
}
} else if (strpos($object['type'], '|') !== false) {
$separator = in_array($object['type'], array('ip-dst|port', 'ip-src|port')) ? ':' : '<br />';
$value_pieces = explode('|', $object['value']);
foreach ($value_pieces as $k => $v) {
$value_pieces[$k] = h($v);
if (isset($object['validationIssue'])) {
echo ' <span class="fa fa-exclamation-triangle" title="' . __('Warning, this doesn\'t seem to be a legitimate ') . strtoupper(h($object['type'])) . __(' value') . '">&nbsp;</span>';
}
$object['value'] = implode($separator, $value_pieces);
echo ($object['value']);
} else if ('vulnerability' == $object['type']) {
$cveUrl = (is_null(Configure::read('MISP.cveurl'))) ? "http://www.google.com/search?q=" : Configure::read('MISP.cveurl');
echo $this->Html->link($sigDisplay, $cveUrl . $sigDisplay, array('target' => '_blank', 'class' => $linkClass));
} else if ('link' == $object['type']) {
echo $this->Html->link($sigDisplay, $sigDisplay, array('class' => $linkClass));
} else if ('cortex' == $object['type']) {
echo '<div class="cortex-json" data-cortex-json="' . h($object['value']) . '">Cortex object</div>';
} else if ('text' == $object['type']) {
if (($object['category'] == 'Internal reference' || $object['category'] == 'External analysis') && preg_match('/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/i', $object['value'])) {
echo '<a href="' . $baseurl . '/events/view/' . h($object['value']) . '" class="' . $linkClass . '">' . h($object['value']) . '</a>';
} else {
$sigDisplay = str_replace("\r", '', h($sigDisplay));
$sigDisplay = str_replace(" ", '&nbsp;', $sigDisplay);
echo $sigDisplay;
}
} else if ('hex' == $object['type']) {
$sigDisplay = str_replace("\r", '', $sigDisplay);
echo '<span class="hex-value" title="' . __('Hexadecimal representation') . '">' . h($sigDisplay) . '</span>&nbsp;<span role="button" tabindex="0" aria-label="' . __('Switch to binary representation') . '" class="icon-repeat hex-value-convert useCursorPointer" title="' . __('Switch to binary representation') . '"></span>';
} else {
$sigDisplay = str_replace("\r", '', $sigDisplay);
echo h($sigDisplay);
}
if (isset($object['validationIssue'])) echo ' <span class="fa fa-exclamation-triangle" title="' . __('Warning, this doesn\'t seem to be a legitimate ') . strtoupper(h($object['type'])) . __(' value') . '">&nbsp;</span>';
?>

View File

@ -6,6 +6,13 @@
$message = str_replace('$flashErrorMessage', '<span class="useCursorPointer underline bold" onClick="flashErrorPopover();">here</span>', $message);
}
echo $message;
if (isset($params['url'])) {
if (isset($params['urlName'])) {
echo '<a href="' . h($params['url']) . '">' . h($params['urlName']) . '</a>';
} else {
echo '<a href="' . h($params['url']) . '">' . h($params['url']) . '</a>';
}
}
if ($this->Session->read('flashErrorMessage')) {
echo sprintf('<div class="hidden" id="flashErrorMessage">%s</div>', $this->element('flashErrorMessage', array('message' => $this->Session->read('flashErrorMessage'))));
}

View File

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

View File

@ -6,16 +6,22 @@
'class' => 'Attribute_attachment'
));
else:
echo h($element['value']);
echo $this->Form->input('Attribute.' . $k . '.value', array(
'type' => 'textarea',
'required' => false,
'allowEmpty' => true,
'style' => 'height:20px;width:400px;display:none;',
'label' => false,
'div' => false,
'value' => empty($element['value']) ? '' : $element['value']
));
if (empty($element['value'])):
echo $this->Form->file('Attribute.' . $k . '.Attachment', array(
'class' => 'Attribute_attachment'
));
else:
echo h($element['value']);
echo $this->Form->input('Attribute.' . $k . '.value', array(
'type' => 'textarea',
'required' => false,
'allowEmpty' => true,
'style' => 'height:20px;width:400px;display:none;',
'label' => false,
'div' => false,
'value' => empty($element['value']) ? '' : $element['value']
));
endif;
endif;
else:
if (empty($element['values_list']) && empty($element['sane_default'])):
@ -52,6 +58,7 @@
'class' => 'Attribute_value_select',
'style' => 'width:414px;margin-bottom:0px;',
'options' => array_combine($list, $list),
'empty' => __('-- Select an option --'),
'label' => false,
'div' => false,
'value' => $choice

View File

@ -21,14 +21,24 @@
?>
<span style="display:inline-block;">
<?php
$full = $isAclTagger && $tagAccess;
$full = $isAclTagger && $tagAccess && empty($static_tags_only);
$tagData = "";
foreach ($tags as $tag) {
if (empty($tag['Tag'])) {
$tag['Tag'] = $tag;
}
if (empty($tag['Tag']['colour'])) {
$tag['Tag']['colour'] = '#0088cc';
}
$aStyle = 'display:inline-block; background-color:' . h($tag['Tag']['colour']) . ';color:' . $this->TextColour->getTextColour($tag['Tag']['colour']) . ';';
$aClass = $full ? 'tagFirstHalf' : 'tag';
$aText = h($tag['Tag']['name']);
$aSearchTagUrl = $baseurl . '/events/index/searchtag: ' . h($tag['Tag']['id']);
$span1 = sprintf('<a href="%s" style="%s" class="%s">%s</a>', $aSearchTagUrl, $aStyle, $aClass, $aText);
if (!empty($tag['Tag']['id'])) {
$aSearchTagUrl = $baseurl . '/events/index/searchtag: ' . h($tag['Tag']['id']);
$span1 = sprintf('<a href="%s" style="%s" class="%s">%s</a>', $aSearchTagUrl, $aStyle, $aClass, $aText);
} else {
$span1 = sprintf('<span style="%s" class="%s">%s</span>', $aStyle, $aClass, $aText);
}
$span2 = '';
if ($full) {
$spanClass = "tagSecondHalf useCursorPointer noPrint";

View File

@ -64,9 +64,7 @@
<li class="all <?php if ($all) echo 'disabled'; ?>">
<?php
if ($all):
?>
<span class="red">view all</span>
<?php
echo '<span class="red">' . __('view all') . '</span>';
else:
echo $this->Paginator->link(__('view all'), 'all');
endif;
@ -233,9 +231,7 @@ attributes or the appropriate distribution level. If you think there is a mistak
<li class="all <?php if ($all) echo 'disabled'; ?>">
<?php
if ($all):
?>
<span class="red">view all</span>
<?php
echo '<span class="red">' . __('view all') . '</span>';
else:
echo $this->Paginator->link(__('view all'), 'all');
endif;
@ -317,7 +313,33 @@ attributes or the appropriate distribution level. If you think there is a mistak
object_id = selected.join('|');
}
url = "<?php echo $baseurl; ?>" + "/sightings/advanced/" + object_id + "/" + object_context;
genericPopup(url, '#screenshot_box');
genericPopup(url, '#popover_box');
});
$(".eventViewAttributeHover").mouseenter(function() {
$('#' + currentPopover).popover('destroy');
var type = $(this).attr('data-object-type');
var id = $(this).attr('data-object-id');
if (type + "_" + id in ajaxResults["hover"]) {
var element = $('#' + type + '_' + id + '_container');
element.popover({
title: attributeHoverTitle(id, type),
content: ajaxResults["hover"][type + "_" + id],
placement: attributeHoverPlacement(element),
html: true,
trigger: 'manual',
container: 'body'
}).popover('show');
currentPopover = type + '_' + id + '_container';
} else {
timer = setTimeout(function () {
runHoverLookup(type, id)
},
500
);
}
}).mouseout(function() {
clearTimeout(timer);
});
});
$('#attributesFilterField').bind("keydown", function(e) {

View File

@ -79,6 +79,15 @@
'onClick' => 'popoverPopup',
'onClickParams' => array('this', 'selected/attribute', 'galaxies', 'selectGalaxyNamespace')
),
array(
'id' => 'group-into-object-button',
'title' => __('Group selected Attributes into an Object'),
'class' => 'mass-select hidden',
'fa-icon' => 'object-group',
'fa-source' => 'fa',
'onClick' => 'proposeObjectsFromSelectedAttributes',
'onClickParams' => array('this', $event['Event']['id'])
),
array(
'id' => 'multi-delete-button',
'title' => __('Delete selected Attributes'),

View File

@ -86,16 +86,16 @@
<?php
if (!$isSiteAdmin) {
if ($post['user_id'] == $myuserid) {
echo $this->Html->link('', array('controller' => 'posts', 'action' => 'edit', h($post['id']), h($context)), array('class' => 'fa fa-edit', 'title' => __('Edit')));
echo $this->Form->postLink('', array('controller' => 'posts', 'action' => 'delete', h($post['id']), h($context)), array('class' => 'fa fa-trash', 'title' => __('Delete')), __('Are you sure you want to delete this post?'));
echo $this->Html->link('', array('controller' => 'posts', 'action' => 'edit', h($post['id']), h($context)), array('class' => 'fa fa-edit', 'title' => __('Edit'), 'aria-label' => __('Edit')));
echo $this->Form->postLink('', array('controller' => 'posts', 'action' => 'delete', h($post['id']), h($context)), array('class' => 'fa fa-trash', 'title' => __('Delete'), 'aria-label' => __('Delete')), __('Are you sure you want to delete this post?'));
} else {
?>
<a href="<?php echo $baseurl.'/posts/add/post/'.h($post['id']); ?>" class="icon-comment" title = "<?php echo __('Reply');?>" aria-label = "<?php echo __('Reply');?>"></a>
<?php
}
} else {
echo $this->Html->link('', array('controller' => 'posts', 'action' => 'edit', h($post['id']), h($context)), array('class' => 'fa fa-edit', 'title' => __('Edit')));
echo $this->Form->postLink('', array('controller' => 'posts', 'action' => 'delete', h($post['id']), h($context)), array('class' => 'fa fa-trash', 'title' => __('Delete')), __('Are you sure you want to delete this post?'));
echo $this->Html->link('', array('controller' => 'posts', 'action' => 'edit', h($post['id']), h($context)), array('class' => 'fa fa-edit', 'title' => __('Edit'), 'aria-label' => __('Edit')));
echo $this->Form->postLink('', array('controller' => 'posts', 'action' => 'delete', h($post['id']), h($context)), array('class' => 'fa fa-trash', 'title' => __('Delete'), 'aria-label' => __('Delete')), __('Are you sure you want to delete this post?'));
?>
<a href = "<?php echo $baseurl.'/posts/add/post/'.h($post['id']); ?>" class="icon-comment" title = "<?php echo __('Reply');?>" aria-label = "<?php echo __('Reply');?>"></a>
<?php

View File

@ -503,6 +503,18 @@
break;
case 'sync':
if ($me['Role']['perm_sync']) {
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
'url' => '/servers/createSync',
'text' => __('Create Sync Config')
));
}
if ($menuItem === 'import' && ($me['Role']['perm_site_admin'])) {
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
'url' => '/servers/import',
'text' => __('Import Server Settings')
));
}
if ($menuItem === 'previewEvent' && ($isSiteAdmin || $hostOrg)) {
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
'url' => sprintf(
@ -594,7 +606,7 @@
));
echo $this->element('/genericElements/SideMenu/side_menu_post_link', array(
'event_id' => 'deleteUser',
'url' => '/admin/delete/' . h($id),
'url' => '/admin/users/delete/' . h($id),
'text' => __('Delete User'),
'message' => __('Are you sure you want to delete # %s? It is highly recommended to never delete users but to disable them instead.', h($id))
));

View File

@ -23,7 +23,7 @@
$class = '';
}
$post_link = $this->Form->postLink(
__($text),
__('%s', $text),
$url,
null,
empty($message) ? null : $message

View File

@ -3,7 +3,6 @@
* Generic select picker
*/
/** Config **/
$select_threshold = 7; // threshold above which pills will be replace by a select (unused if multiple is > 1)
$defaults_options = array(
'select_options' => array(
// 'multiple' => '', // set to add possibility to pick multiple options in the select
@ -19,6 +18,7 @@
'allow_single_deselect' => true,
),
'multiple' => 0,
'select_threshold' => 7, // threshold above which pills will be replace by a select (unused if multiple is > 1)
'functionName' => '', // function to be called on submit
'submitButtonText' => 'Submit',
'disabledSubmitButton' => false, // wether to not draw the submit button
@ -45,9 +45,9 @@
} else { // multiple enabled
$defaults['chosen_options']['max_selected_options'] = $defaults['multiple'] == -1 ? 'Infinity' : $defaults['multiple'];
$defaults['select_options']['multiple'] = '';
$select_threshold = 0;
$defaults['select_threshold'] = 0;
}
$use_select = count($items) > $select_threshold;
$use_select = count($items) > $defaults['select_threshold'];
$countThresholdReached = count($items) > 1000;
$option_templates = array();
$options_additionalData = array();

View File

@ -212,6 +212,16 @@
'text' => __('Sync Actions'),
'requirement' => ($isAclSync || $isAdmin || $hostOrgUser),
'children' => array(
array(
'text' => __('Create Sync Config'),
'url' => '/servers/createSync',
'requirement' => ($isAclSync && !$isSiteAdmin)
),
array(
'text' => __('Import Server Settings'),
'url' => '/servers/import',
'requirement' => ($isSiteAdmin)
),
array(
'text' => __('List Servers'),
'url' => '/servers/index',

View File

@ -34,6 +34,12 @@
<?php
echo $version['current'] . ' (' . h($commit) . ')';
?>
<?php if ($commit === ''): ?>
<br />
<span class="red bold apply_css_arrow">
<?php echo __('Unable to fetch current commit id, check apache user read privilege.'); ?>
</span>
<?php endif; ?>
</span>
</span><br />
<span><?php echo __('Latest available version…');?>
@ -60,10 +66,15 @@
</span><br />
<pre class="hidden green bold" id="gitResult"></pre>
<button title="<?php echo __('Pull the latest MISP version from github');?>" class="btn btn-inverse" style="padding-top:1px;padding-bottom:1px;" onClick = "updateMISP();"><?php echo __('Update MISP');?></button>
<a title="<?php echo __('Click the following button to go to the update progress page. This page lists all updates that are currently queued and executed.'); ?>" class="btn btn-inverse" style="padding-top:1px;padding-bottom:1px;" href="<?php echo $baseurl; ?>/servers/updateProgress/"><?php echo __('Update Progress');?></a>
</div>
<h3><?php echo __('Submodules version');?><it id="refreshSubmoduleStatus" class="fas fa-sync useCursorPointer" style="font-size: small; margin-left: 5px;"></it></h3>
<div id="divSubmoduleVersions" style="background-color:#f7f7f9;">
</div>
<h3><?php echo __('Submodules version');?>
<it id="refreshSubmoduleStatus" class="fas fa-sync useCursorPointer" style="font-size: small; margin-left: 5px;" title="<?php echo __('Refresh submodules version.'); ?>"></it>
</h3>
<div id="divSubmoduleVersions" style="background-color:#f7f7f9;"></div>
<span id="updateAllJson" class="btn btn-inverse" title="<?php echo __('Load all JSON into the database.'); ?>">
<it class="fas fa-file-upload"></it> <?php echo __("Load JSON into database"); ?>
</span>
<h3><?php echo __('Writeable Directories and files');?></h3>
<p><?php echo __('The following directories and files have to be writeable for MISP to function properly. Make sure that the apache user has write privileges for the directories below.');?></p>
@ -250,6 +261,20 @@
}
?>
</div>
<h3><?php echo __('Yara');?></h3>
<p><?php echo __('This tool tests whether plyara, the library used by the yara export tool is installed or not.');?></p>
<div style="background-color:#f7f7f9;width:400px;">
<?php
$colour = 'green';
$message = __('OK');
if ($yaraStatus['operational'] == 0) {
$colour = 'red';
$message = __('Invalid plyara version / plyara not installed. Please run pip3 install plyara');
}
echo __('plyara library installed') . '…<span style="color:' . $colour . ';">' . $message . '</span>';
?>
</div>
<h3><?php echo __('GnuPG');?></h3>
<p><?php echo __('This tool tests whether your GnuPG is set up correctly or not.');?></p>
<div style="background-color:#f7f7f9;width:400px;">
@ -344,12 +369,10 @@
</div><br />
<span class="btn btn-inverse" role="button" tabindex="0" aria-label="<?php echo __('Check for orphaned attribute');?>" title="<?php echo __('Check for orphaned attributes');?>" style="padding-top:1px;padding-bottom:1px;" onClick="checkOrphanedAttributes();"><?php echo __('Check for orphaned attributes');?></span><br /><br />
<?php echo $this->Form->postButton(__('Remove orphaned attributes'), $baseurl . '/attributes/pruneOrphanedAttributes', $options = array('class' => 'btn btn-primary', 'style' => 'padding-top:1px;padding-bottom:1px;')); ?>
<h3><?php echo __('Verify GnuPG keys');?></h3>
<p><?php echo __('Run a full validation of all GnuPG keys within this instance\'s userbase. The script will try to identify possible issues with each key and report back on the results.');?></p>
<span class="btn btn-inverse" onClick="location.href='<?php echo $baseurl;?>/users/verifyGPG';"><?php echo __('Verify GnuPG keys');?></span> (<?php echo __('Check whether every user\'s GnuPG key is usable');?>)</li>
<h3><?php echo __('Database cleanup scripts');?></h3>
<p><?php echo __('If you run into an issue with an infinite upgrade loop (when upgrading from version ~2.4.50) that ends up filling your database with upgrade script log messages, run the following script.');?></p>
<?php echo $this->Form->postButton(__('Prune upgrade logs'), $baseurl . '/logs/pruneUpdateLogs', $options = array('class' => 'btn btn-primary', 'style' => 'padding-top:1px;padding-bottom:1px;')); ?>
<?php echo $this->Form->postButton(__('Remove published empty events'), $baseurl . '/events/cullEmptyEvents', $options = array('class' => 'btn btn-primary', 'style' => 'padding-top:1px;padding-bottom:1px;')); ?>
<h3><?php echo __('Administrator On-demand Action');?></h3>
<p><?php echo __('Click the following button to go to the Administrator On-demand Action page.');?></p>
<span class="btn btn-inverse" style="padding-top:1px;padding-bottom:1px;" onClick="location.href = '<?php echo $baseurl; ?>/servers/ondemandAction/';"><?php echo __('Administrator On-demand Action');?></span>
<h3><?php echo __('Legacy Administrative Tools');?></h3>
<p><?php echo __('Click the following button to go to the legacy administrative tools page. There should in general be no need to do this unless you are upgrading a very old MISP instance (<2.4), all updates are done automatically with more current versions.');?></p>
<span class="btn btn-inverse" style="padding-top:1px;padding-bottom:1px;" onClick="location.href = '<?php echo $baseurl; ?>/pages/display/administration';"><?php echo __('Legacy Administrative Tools');?></span>
@ -365,9 +388,10 @@
<script>
$(document).ready(function() {
updateSubModulesStatus();
$('#refreshSubmoduleStatus').click(function() { updateSubModulesStatus(); });
$('#updateAllJson').click(function() { updateAllJson(); });
});
$('#refreshSubmoduleStatus').click(function() { updateSubModulesStatus(); });
function updateSubModulesStatus(message, job_sent, sync_result) {
job_sent = job_sent === undefined ? false : job_sent;
sync_result = sync_result === undefined ? '' : sync_result;
@ -391,4 +415,24 @@
}
});
}
function updateAllJson() {
$.ajax({
url: '<?php echo $baseurl . '/servers/updateJSON/'; ?>',
type: "get",
beforeSend: function() {
$('#submoduleGitResultDiv').show();
$('#submoduleGitResult').append('<it class="fa fa-spin fa-spinner" style="font-size: large; left: 50%; top: 50%;"></it>');
},
success: function(data, statusText, xhr) {
Object.keys(data).forEach(function(k) {
var val = data[k];
data[k] = val ? 'Updated' : 'Update failed';
});
$('#submoduleGitResult').html(syntaxHighlightJson(data));
},
complete: function() {
$('#submoduleGitResult').find('fa-spinner').remove();
}
});
}
</script>

View File

@ -22,11 +22,13 @@
'setting' => array(
'html' => h($setting['setting']),
'class' => 'short live_filter_target',
'ondblclick' => 'serverSettingsActivateField',
'ondblclickParams' => array(h($setting['setting']), h($k))
),
'value_passive' => array(
'html' => nl2br(h($setting['value'])),
'class' => 'inline-field-solid live_filter_target',
'requirement' => ((isset($setting['editable']) && !$setting['editable'])),
'requirement' => ((isset($setting['editable']) && !$setting['editable']) || !empty($setting['cli_only'])),
'style' => 'width:500px;',
'id' => sprintf(
'setting_%s_%s_passive',
@ -37,7 +39,7 @@
'value_solid' => array(
'html' => nl2br(h($setting['value'])),
'class' => 'inline-field-solid live_filter_target',
'requirement' => ((!isset($setting['editable']) || $setting['editable'])),
'requirement' => ((!isset($setting['editable']) || $setting['editable']) && empty($setting['cli_only'])),
'style' => 'width:500px;',
'id' => sprintf(
'setting_%s_%s_solid',
@ -49,7 +51,7 @@
),
'value_placeholder' => array(
'class' => 'inline-field-placeholder hidden',
'requirement' => ((!isset($setting['editable']) || $setting['editable'])),
'requirement' => ((!isset($setting['editable']) || $setting['editable']) && empty($setting['cli_only'])),
'style' => 'width:500px;',
'id' => sprintf(
'setting_%s_%s_placeholder',
@ -58,7 +60,11 @@
)
),
'description' => array(
'html' => h($setting['description']),
'html' => sprintf(
'%s%s',
!empty($setting['cli_only']) ? sprintf('<span class="bold">[<span class="red">%s</span>]</span> ', __('CLI only')) : '',
h($setting['description'])
),
'class' => 'live_filter_target'
),
'error' => array(

View File

@ -38,7 +38,7 @@
<?php
echo h($data['jobCount']);
if ($data['jobCount'] > 0 && $worker_array['controls']) {
echo $this->Form->postLink('<span class="fa fa-trash useCursorPointer"></span>', $baseurl . '/servers/clearWorkerQueue/' . h($type), array('escape' => false, 'inline' => true, 'style' => 'margin-left:2px;'));
echo $this->Form->postLink('<span class="fa fa-trash black useCursorPointer"></span>', $baseurl . '/servers/clearWorkerQueue/' . h($type), array('escape' => false, 'inline' => true, 'style' => 'margin-left:2px;'));
}
?>
</span>
@ -103,7 +103,7 @@
<td class="actions short" style="<?php echo $style; ?>">
<?php
if ($worker_array['controls']) {
echo $this->Form->postLink('', '/servers/stopWorker/' . h($worker['pid']), array('class' => 'fa fa-trash' . $icon_modifier, 'title' => __('Stop (if still running) and remove this worker. This will immediately terminate any jobs that are being executed by it.')));
echo $this->Form->postLink('', '/servers/stopWorker/' . h($worker['pid']), array('class' => 'fa fa-trash black' . $icon_modifier, 'title' => __('Stop (if still running) and remove this worker. This will immediately terminate any jobs that are being executed by it.')));
}
?>
</td>

View File

@ -9,19 +9,21 @@
<?php
$cnt = 0;
foreach ($typeDb as $type => $colour):
if (isset($data[0]['data'][$type])):
?>
<div class="attributehistogram-legend-line">
<div class="attributehistogram-legend-box" style="display: block;float: left;margin: 4px 6px 0 0;background-color:<?php echo $colour; ?>">&nbsp;</div>
<div style="display: inline-block;cursor: pointer;<?php if (in_array($type, $selectedTypes)) echo 'font-weight:bold';?>" role="button" tabindex="0" aria-label="<?php echo __('Toggle histogram');?>" tite="<?php echo __('Toggle histogram');?>" onClick='toggleHistogramType("<?php echo h($type); ?>", [<?php foreach ($selectedTypes as $t) echo '"' . $t . '", ' ?>]);'><?php echo h($type);?></div>
</div>
<div class="attributehistogram-legend-line">
<div class="attributehistogram-legend-box" style="display: block;float: left;margin: 4px 6px 0 0;background-color:<?php echo $colour; ?>">&nbsp;</div>
<div style="display: inline-block;cursor: pointer;<?php if (in_array($type, $selectedTypes)) echo 'font-weight:bold';?>" role="button" tabindex="0" aria-label="<?php echo __('Toggle histogram');?>" tite="<?php echo __('Toggle histogram');?>" onClick='toggleHistogramType("<?php echo h($type); ?>", [<?php foreach ($selectedTypes as $t) echo '"' . $t . '", ' ?>]);'><?php echo h($type);?></div>
</div>
<?php
if ($cnt % 12 == 11):
$cnt++;
endif;
if ($cnt % 12 == 0):
?>
</div>
<div class="attributehistogram-legend-line col">
</div>
<div class="attributehistogram-legend-line col">
<?php
endif;
$cnt++;
endif;
endforeach;
?>
</div>

View File

@ -101,12 +101,12 @@ foreach($tabs as $tabName => $column):
</div>
<?php endif; ?>
<div id="matrix_container" class="fixed-table-container-inner" style="max-height: 670px;" data-picking-mode="<?php echo $pickingMode ? 'true' : 'false'; ?>">
<div id="matrix_container" class="fixed-table-container-inner" style="" data-picking-mode="<?php echo $pickingMode ? 'true' : 'false'; ?>">
<div class="tab-content">
<?php foreach($tabs as $tabName => $column): ?>
<div class="tab-pane <?php echo $tabName==$defaultTabName ? "active" : ""; ?>" id="tabMatrix-<?php echo h($tabName); ?>">
<div class="header-background"></div>
<div class="fixed-table-container-inner" style="max-height: 670px;">
<div class="fixed-table-container-inner" style="">
<table class="table table-condensed matrix-table">
<thead>
<tr>
@ -116,7 +116,10 @@ foreach($tabs as $tabName => $column):
?>
<th>
<?php echo h(ucfirst($name)); ?>
<div class="th-inner"><?php echo h(ucfirst($name)); ?></div>
<div class="th-inner" style="flex-direction: column; align-items: flex-start; padding-top: 3px;">
<span><?php echo h(ucfirst($name)); ?></span>
<i style="font-size: smaller;"><?php echo sprintf(__('(%s items)'), isset($column[$co]) ? count($column[$co]) : 0); ?></i>
</div>
</th>
<?php endforeach; ?>
@ -197,5 +200,5 @@ foreach($tabs as $tabName => $column):
</select>
</div>
<div class="templateChoiceButton btn-matrix-submit submit-container hide"><?php echo __('Submit'); ?></div>
<div role="button" tabindex="0" aria-label="<?php echo __('Cancel');?>" title="<?php echo __('Cancel');?>" class="templateChoiceButton templateChoiceButtonLast" onClick="cancelPopoverForm('#popover_form_large');"><?php echo __('Cancel'); ?></div>
<div role="button" tabindex="0" aria-label="<?php echo __('Cancel');?>" title="<?php echo __('Cancel');?>" class="templateChoiceButton templateChoiceButtonLast" onClick="cancelPopoverForm('#popover_matrix');"><?php echo __('Cancel'); ?></div>
<?php endif; ?>

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