#!/usr/bin/env perl # # Author: Sebastien Tricaud # This script is written in Perl because it is default to most distributions # without any dependency. # # MISP Configuration is handled mostly via its UI. This script helps to configure # MISP for anything that can be configured. For now this is mostly CakePHP stuff. # # How to use? # 1) dump the configuration options that are already set: # misp-config --create # -> Will dump in /etc/misp/misp.conf.d/ unless to add a --prefix option, such as: # misp-config --misp-path /var/www/MISP --prefix /var/www/MISP/etc/ --create # # 2) set the configuration manually from /etc/misp/misp.conf.d/ with your favorite text editor (emacs) # then load to MISP using: # misp-config --apply # Of course, if your MISP instance is installed in /var/www/MISP you should do: # misp-config --misp-path /var/www/MISP --apply # # Note there is a configuration, Internal.conf, which where CakePHP has no control, for example # it will change the source code where there was a lack of configuration capability. # use strict; use warnings; use File::Path qw(make_path); use JSON; my $misp_user="www-data"; my $misp_path="/usr/share/misp"; my $misp_config_path="/etc/misp/"; my $prefix=""; my $create=0; my $apply=0; my %CATEGORIES_CREATED = (); sub print_help_exit { print "\nUsage: misp-config --user www-data \t --misp-path /usr/share/misp \t --prefix /usr/local \t --apply: Applies configuration from $misp_config_path \t --create: Create configuration from all available options\n\n"; exit; } if ($#ARGV < 0) { print_help_exit(); } sub replace_inplace_content { my ($filename, $buftoreplace, $replacement) = @_; open my $fp, "<:encoding(UTF-8)", $filename or die "unable to open $filename!"; local $/ = undef; my $data = <$fp>; close $fp; $data =~ s/$buftoreplace/$replacement/g; open $fp, ">:encoding(UTF-8)", $filename or die "Could not write to '$filename'"; print $fp $data; close $fp; } while (my ($i, $arg) = each @ARGV) { if ($arg eq "--user") { $misp_user = $ARGV[$i+1]; } if ($arg eq "--misp-path") { $misp_path = $ARGV[$i+1]; } if ($arg eq "--prefix") { $prefix = $ARGV[$i+1]; $misp_config_path = "$prefix/$misp_config_path" } if ($arg eq "--create") { $create = 1; } if ($arg eq "--apply") { $apply = 1; } if ($arg eq "--help") { print_help_exit(); } } if ( ! $apply && ! $create ) { print "Argument missing: Please use either --apply or --create.\n"; exit; } if ( $apply && $create ) { print "Argument error: Cannot use both --apply and --create.\n"; exit; } if ($create) { my $misp_config_path = "$misp_config_path/misp.conf.d"; make_path($misp_config_path); unless(-e "$misp_config_path/Internal.conf") { open(my $internalfh, ">", "$misp_config_path/Internal.conf"); print $internalfh "redis_host localhost\n"; close $internalfh; } my $settings = `sudo -u $misp_user $misp_path/app/Console/cake admin getSetting all | tail -n +7`; my $jsonconfig = decode_json($settings); foreach my $item (@$jsonconfig) { my $setting = $item->{'setting'}; my $value = $item->{'value'}; my $category = ""; my $key = ""; my $section = ""; # Plugin.S3_aws_secret_key -> false # ^ ^ # | |- Section (S3) # | |- Key (S3_aws_secret_key) # |-- Category # # We also have: # Proxy.host -> "" # Which won't create a section because of the missing _ if ($setting =~ m/(\w+)\.(\w+)/) { $category = $1; $key = $2; # print "Setting category: $1 and key: $2\n"; if ($key =~ m/(.*?)_/) { $section = $1 # print "Section: $1\n"; } else { # There is no _, so the section is the key $section = $key; } } else { # Orphan settings are debug settings: $category = "Debug"; $key = $setting; # print "Orphan setting:$setting\n"; } # # We have all we needed, we can write the files # my $conf_to_write = "$misp_config_path/$category.conf"; unless($CATEGORIES_CREATED{"$category"}) { if (-e $conf_to_write) { die "We cannot overwrite $conf_to_write, it already exists. Remove it manually.\n"; } } $CATEGORIES_CREATED{"$category"} = 1; open(my $fh, ">>", "$conf_to_write"); print $fh "#$key $value\n"; close $fh; } } if ($apply) { my $misp_config_path = "$misp_config_path/misp.conf.d"; unless(-d $misp_config_path) { die "MISP Configuration Path does not exist: $misp_config_path\n"; } foreach my $fp (glob("$misp_config_path/*.conf")) { my $category = substr($fp, length($misp_config_path)+1, -5); my $cake_config = $category eq "Internal" ? 0 : 1; # print "$category:$cake_config\n"; # print "$fp\n"; open(my $fh, "<", $fp) or die "$!"; while (my $line = <$fh>) { chomp $line; $line =~ /(\S+) (.*)/; my $key = ""; my $config_el = $1; my $first_config_char = substr($config_el, 0, 1); my $is_comment = 0; if ($first_config_char eq "#") { $is_comment = 1; } # print("config element: $config_el\n"); if ($category eq "Debug") { # The Debug category does not... have a category $key = $config_el; } elsif ($category eq "Internal") { # Internal means we are patching portions of the code to configure if ($config_el eq "redis_host") { replace_inplace_content("$misp_path/app/Lib/Tools/PubSubTool.php", "localhost", $2); replace_inplace_content("$misp_path/app/Plugin/CakeResque/Config/config.php", "localhost", $2); replace_inplace_content("$misp_path/app/Vendor/kamisama/php-resque-ex/lib/Resque.php", "localhost", $2); replace_inplace_content("$misp_path/app/Vendor/monolog/monolog/src/Monolog/Handler/RedisHandler.php", "localhost", $2); } } else { $key = "$category.$config_el"; } if ($cake_config && !$is_comment) { # print("sudo -u $misp_user $misp_path/app/Console/cake admin setSetting $key $2\n"); system("sudo -u $misp_user $misp_path/app/Console/cake admin setSetting $key $2"); } } close($fh); } }