From bbb57927418db2a3038a26880f1ab364c01e779a Mon Sep 17 00:00:00 2001 From: bodik <bodik@civ.zcu.cz> Date: Tue, 9 Apr 2013 11:10:39 +0200 Subject: [PATCH] pridani a presun kostejova udelatoru, merge vetvi se nam moc nepovedl takze to musime udelat takto osklive rucne --- .../warden-app/Modules/DNSblacklist.pm | 52 +++ src/contrib/warden-app/Modules/IPblacklist.pm | 36 ++ src/contrib/warden-app/Modules/IPtables.pm | 40 +++ src/contrib/warden-app/Modules/MailReport.pm | 74 +++++ src/contrib/warden-app/WardenApp/Constants.pm | 116 +++++++ src/contrib/warden-app/WardenApp/DB.pm | 105 ++++++ src/contrib/warden-app/WardenApp/Factory.pm | 59 ++++ src/contrib/warden-app/WardenApp/Receiver.pm | 71 ++++ src/contrib/warden-app/WardenApp/Utils.pm | 111 +++++++ src/contrib/warden-app/bin/warden-cleaner.pl | 61 ++++ src/contrib/warden-app/bin/warden-factory.pl | 48 +++ src/contrib/warden-app/bin/warden-receiver.pl | 65 ++++ src/contrib/warden-app/doc/WApp.README | 309 ++++++++++++++++++ src/contrib/warden-app/doc/WApp.cron | 19 ++ src/contrib/warden-app/etc/cleaner.conf | 8 + src/contrib/warden-app/etc/db.conf | 22 ++ src/contrib/warden-app/etc/factory.conf | 105 ++++++ src/contrib/warden-app/etc/receiver.conf | 24 ++ .../warden-app/sh/create_tables_mysql.sh | 29 ++ .../warden-app/sh/create_tables_sqlite.sh | 13 + 20 files changed, 1367 insertions(+) create mode 100644 src/contrib/warden-app/Modules/DNSblacklist.pm create mode 100644 src/contrib/warden-app/Modules/IPblacklist.pm create mode 100644 src/contrib/warden-app/Modules/IPtables.pm create mode 100644 src/contrib/warden-app/Modules/MailReport.pm create mode 100644 src/contrib/warden-app/WardenApp/Constants.pm create mode 100644 src/contrib/warden-app/WardenApp/DB.pm create mode 100644 src/contrib/warden-app/WardenApp/Factory.pm create mode 100644 src/contrib/warden-app/WardenApp/Receiver.pm create mode 100644 src/contrib/warden-app/WardenApp/Utils.pm create mode 100755 src/contrib/warden-app/bin/warden-cleaner.pl create mode 100755 src/contrib/warden-app/bin/warden-factory.pl create mode 100755 src/contrib/warden-app/bin/warden-receiver.pl create mode 100644 src/contrib/warden-app/doc/WApp.README create mode 100644 src/contrib/warden-app/doc/WApp.cron create mode 100644 src/contrib/warden-app/etc/cleaner.conf create mode 100644 src/contrib/warden-app/etc/db.conf create mode 100644 src/contrib/warden-app/etc/factory.conf create mode 100644 src/contrib/warden-app/etc/receiver.conf create mode 100755 src/contrib/warden-app/sh/create_tables_mysql.sh create mode 100755 src/contrib/warden-app/sh/create_tables_sqlite.sh diff --git a/src/contrib/warden-app/Modules/DNSblacklist.pm b/src/contrib/warden-app/Modules/DNSblacklist.pm new file mode 100644 index 0000000..fd5143e --- /dev/null +++ b/src/contrib/warden-app/Modules/DNSblacklist.pm @@ -0,0 +1,52 @@ +package DNSblacklist; +use strict; +use warnings; +use Data::Dumper; + +my %CONSTANTS = ( + target => "127.0.0.2", + outputfile => "tmp/blacklist.csv", + threshold => 10, + excludedip => [], + eventtype => [], + maxage => "1D", + ttl => "3600", + zone => "@", + dns => "dns.example.com", + hostmaster => "hostmaster\@example.com", + refresh => "1800 ; refresh (30 minutes)", + retry => "600 ; retry (10 minutes)", + expire => "1209600 ; expire (2 weeks)", + minimum => "86400 ; minimum (1 day)", + ); + +my %FORMAT = ( maxage => qr/\d+[hdmHDM]/, ); + +sub run { + my (undef, $modprefix, $cfg, $dbh, $db_engine) = @_; + + my $v = Constants::mergeConfigs($cfg, $modprefix, \%CONSTANTS, \%FORMAT); + + my $eventtype_query = DB::joinIN("type", \@{$v->{'eventtype'}}); + my $excluded_query = DB::joinNotIN("source", \@{$v->{'excludedip'}}); + + my $condition = substr($excluded_query . $eventtype_query, 0, -5); + my @columns= ("source", "note"); + my @params = ($condition, DB::getOldDataDB($db_engine, "NEWER", $v->{'maxage'})); + my $query = DB::getQueryCondThreshold($db_engine, "events", \@columns, \@params, $v->{'threshold'}); + + my @rows = Utils::fetchall_array_hashref($dbh, $query); + + my ($sec, $min, $hr, $day, $mon, $year) = localtime; + + $v->{'serial'} = sprintf("%02d%02d%02d%02d%02d", $year - 100 , $mon + 1, $day, $hr, $min); + $v->{'hostmaster'} =~ s/\@/\./; + + sub header { my $v = shift; return "\$ORIGIN .\n\$TTL $v->{'ttl'}\n$v->{'zone'}\t\t\t\t\t\tIN\tSOA\t$v->{'dns'}. $v->{'hostmaster'}. (\n\t\t\t\t\t\t\t\t$v->{'serial'} ; serial\n\t\t\t\t\t\t\t\t$v->{'refresh'}\n\t\t\t\t\t\t\t\t$v->{'retry'}\n\t\t\t\t\t\t\t\t$v->{'expire'}\n\t\t\t\t\t\t\t\t$v->{'minimum'}\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\tNS\t$v->{'dns'}.\n"; }; + + sub record { my ($r, $v) = @_; $r->{'note'} = "" if !defined $r->{'note'}; return ";" . "$r->{'source'}\n" . join(".", reverse( split(/\./, $r->{'source'}))) . "\t\tIN\t\tA\t$v->{'target'}\n\t\t\t\t\tIN\t\tTXT\t\"$r->{'note'}\"\n"; }; + + my $ret = Utils::generateOutput($v->{'outputfile'}, \@rows, \&header, \&record, undef, $v); + return $ret; +} +1; diff --git a/src/contrib/warden-app/Modules/IPblacklist.pm b/src/contrib/warden-app/Modules/IPblacklist.pm new file mode 100644 index 0000000..9ffce12 --- /dev/null +++ b/src/contrib/warden-app/Modules/IPblacklist.pm @@ -0,0 +1,36 @@ +package IPblacklist; +use strict; +use warnings; +use Data::Dumper; + +my %CONSTANTS = ( + outputfile => "tmp/blacklist.csv", + threshold => 200, + excludedip => [], + eventtype => [], + maxage => "1D", + ); + +my %FORMAT = ( maxage => qr/\d+[hdmHDM]/, ); + + +sub run { + my (undef, $modprefix, $cfg, $dbh, $db_engine) = @_; + my $v = Constants::mergeConfigs($cfg, $modprefix, \%CONSTANTS, \%FORMAT); + + my $eventtype_query = DB::joinIN("type", \@{$v->{'eventtype'}}); + my $excluded_query = DB::joinNotIN("source", \@{$v->{'excludedip'}}); + + my $condition = substr($excluded_query . $eventtype_query, 0, -5); + my @columns= ("source"); + my @params = ($condition, DB::getOldDataDB($db_engine, "NEWER", $v->{'maxage'})); + my $query = DB::getQueryCondThreshold($db_engine, "events", \@columns, \@params, $v->{'threshold'}); + + my @rows = Utils::fetchall_array_hashref($dbh, $query); + + sub record { my $r = shift; return "$r->{'source'},\n"; }; + + my $ret = Utils::generateOutput($v->{'outputfile'}, \@rows, undef, \&record, undef, $v); + return $ret; +} +1; diff --git a/src/contrib/warden-app/Modules/IPtables.pm b/src/contrib/warden-app/Modules/IPtables.pm new file mode 100644 index 0000000..7d0205e --- /dev/null +++ b/src/contrib/warden-app/Modules/IPtables.pm @@ -0,0 +1,40 @@ +package IPtables; +use strict; +use warnings; +use Data::Dumper; + +my %CONSTANTS = ( + enabled => "no", + outputfile => "tmp/iptables.txt", + threshold => 250, + excludedip => [], + eventtype => [], + chainname => "BLOCK", + destchain => "DROP", + maxage => "1D", + ); + +my %FORMAT = ( maxage => qr/\d+[hdmHDM]/, logging => qr/enable|disable/,); + +sub run { + my (undef, $modprefix, $cfg, $dbh, $db_engine) = @_; + + my $v = Constants::mergeConfigs($cfg, $modprefix, \%CONSTANTS, \%FORMAT); + + my $eventtype_query = DB::joinIN("type", \@{$v->{'eventtype'}}); + my $excluded_query = DB::joinNotIN("source", \@{$v->{'excludedip'}}); + + my $condition = substr($excluded_query . $eventtype_query, 0, -5); + my @columns= ("source"); + my @params = ($condition, DB::getOldDataDB($db_engine, "NEWER", $v->{'maxage'})); + my $query = DB::getQueryCondThreshold($db_engine, "events", \@columns, \@params, $v->{'threshold'}); + + my @rows = Utils::fetchall_array_hashref($dbh, $query); + + sub header { my $v = shift; return "/sbin/iptables -F $v->{'chainname'}\n"; }; + sub record { my ($r, $v) = @_; return "/sbin/iptables -A $v->{'chainname'} -s $r->{'source'}/32 -j $v->{'destchain'}\n"; }; + + my $ret = Utils::generateOutput($v->{'outputfile'}, \@rows, \&header, \&record, undef, $v); + return $ret; +} +1; diff --git a/src/contrib/warden-app/Modules/MailReport.pm b/src/contrib/warden-app/Modules/MailReport.pm new file mode 100644 index 0000000..990bcb6 --- /dev/null +++ b/src/contrib/warden-app/Modules/MailReport.pm @@ -0,0 +1,74 @@ +package MailReport; +use strict; +use warnings; + +my %CONSTANTS = ( + tool => "sendmail", + sender => "", + recipients => [], + subject => "", + subnets => ["147."], + signature => "XXX", + threshold => 0, + excludedsensor => [], + excludedip => [], + eventtype => [], + maxage => "1D", + summary => "yes", + ); + +my %FORMAT = ( maxage => qr/\d+[hdmHDM]/, + tool => qr/(ssmtp|sendmail)/, + ); + +sub run { + my (undef, $modprefix, $cfg, $dbh, $db_engine) = @_; + + my $v = Constants::mergeConfigs($cfg, $modprefix, \%CONSTANTS, \%FORMAT); + + my $eventtype_query = DB::joinIN("type", \@{$v->{'eventtype'}}); + my $excluded_query = DB::joinNotIN("source", \@{$v->{'excludedip'}}); + my $excludedsensor_query = DB::joinNotIN("service", \@{$v->{'excludedsensor'}}); + my $subnets_query = DB::joinLIKE("source", \@{$v->{'subnets'}}); + + my $condition = substr($excluded_query . $eventtype_query . $excludedsensor_query . $subnets_query, 0, -5); + my @columns= ("source", "hostname", "service", "type", "detected", "target_proto", "target_port", "attack_scale"); + my @params = ($condition, DB::getOldDataDB($db_engine, "NEWER", $v->{'maxage'})); + my $query = DB::getQueryCondThreshold($db_engine, "events", \@columns, \@params, $v->{'threshold'}); + + my @rows = Utils::fetchall_array_hashref($dbh, $query); + + if($v->{'subject'} eq "") { + my $hostname = `hostname -f`; + $v->{'subject'} = "$modprefix (Warden-app) on $hostname"; + } + + $v->{'modprefix'} = $modprefix; + + sub header { + my $v = shift; + my $header; + + $header = "$v->{'modprefix'} noticed following events during $v->{'maxage'} timeframe:\n\n"; + $header .= sprintf("+-------------------------------+---------------------+------------+-----------------+-------+----------+--------+\n"); + $header .= sprintf("| Detector/Service | Detected | Type | Source | Dport | Proto | Volume |\n"); + $header .= sprintf("+-------------------------------+---------------------+------------+-----------------+-------+----------+--------+\n"); + + return $header + }; + + sub record { my $r = shift; return sprintf("|%30s | %19s | %10s | %15s | %5s | %8s | %6s |\n", "$r->{'hostname'}/$r->{'service'}", $r->{'detected'}, $r->{'type'}, $r->{'source'}, $r->{'target_port'}, $r->{'target_proto'}, $r->{'attack_scale'}); }; + + sub footer { + my $v = shift; + my $footer = sprintf("+-------------------------------+---------------------+------------+-----------------+-------+----------+--------+\n\n"); + $footer .= $v->{'signature'}; + + return $footer; + }; + + Utils::generateEmails($v->{'tool'}, \@{$v->{'recipients'}}, $v->{'sender'}, $v->{'subject'}, \@rows, \&header, \&record, \&footer, $v, $v->{'summary'}); + + return 1; +} +1; diff --git a/src/contrib/warden-app/WardenApp/Constants.pm b/src/contrib/warden-app/WardenApp/Constants.pm new file mode 100644 index 0000000..dfa1362 --- /dev/null +++ b/src/contrib/warden-app/WardenApp/Constants.pm @@ -0,0 +1,116 @@ +package Constants; +use strict; +use warnings; +use Data::Dumper; + +use constant SCALAR => 'SCALAR'; + +our %DEFAULTS = +( + factory => { + GENERAL_logfile => "var/log/factory.log", + GENERAL_modpath => "Modules", + }, + + receiver => { + GENERAL_method => ( "stdout" ), + GENERAL_logfile => "var/log/receiver.log", + GENERAL_wardenpath => "/opt/warden/client", + GENERAL_requested_type => "_all_", + + FILE_directory => "var/fileout/", + FILE_method => "append", + FILE_appendfilename => "received", + FILE_extension => "csv", + + DB_dbengine => "sqlite", + }, + + + db => { + SQLITE_db => "var/db.sqlite", + SQLITE_user => "", + SQLITE_pass => "", + + MYSQL_db => "warden", + MYSQL_user => "root", + MYSQL_pass => "", + MYSQL_host => "localhost", + MYSQL_port => "3306", + }, + + cleaner => { + GENERAL_method => ( "db" ), + GENERAL_maxage => "11D", + }, +); + + +sub getDefaultValue { + my ($valuename, $section) = @_; + + $valuename =~ s/\./_/g; + my @value = $DEFAULTS{$section}{$valuename}; + die "Value '$valuename' is not defined" if not @value; + + return (wantarray ? @value : $value[0]); +} + +sub assignValue { + my ($valuename, $cfg, $section, $nocheck) = @_; + + my @configvalue = $cfg->param($valuename); + $valuename =~ s/\./_/g; + + my @value; + + if(!defined $nocheck) { + my @defaultvalue = getDefaultValue($valuename, $section); + @value = (@configvalue ? @configvalue : @defaultvalue); + } + else { + @value = @configvalue; + } + die "Value '$valuename' is not defined" if not defined $value[0]; + + if(wantarray and $value[0] eq "") { + return (); + } + else { + return (wantarray ? @value : $value[0]); + } +} + + +sub mergeConfigs { + my ($config, $section, $constants, $format) = @_; + my %ret; + + my $conf_hash = $config->get_block($section); + + foreach my $const_key ( keys %$constants ) + { + if( exists $conf_hash->{$const_key} ) { + if(ref($constants->{$const_key}) eq ref($conf_hash->{$const_key})) { + $ret{$const_key} = $conf_hash->{$const_key}; + } + elsif (ref($constants->{$const_key}) eq 'ARRAY') { + $ret{$const_key} = (defined $conf_hash->{$const_key} ? [$conf_hash->{$const_key}] : []); + } + elsif (ref(\$constants->{$const_key}) eq 'SCALAR') { + $ret{$const_key} = (defined $conf_hash->{$const_key} ? $conf_hash->{$const_key}->[0] : ""); + } + + if(exists $format->{$const_key}) { + if($ret{$const_key} !~ $format->{$const_key}) { + $ret{$const_key} = $constants->{$const_key}; + } + } + } + else { + $ret{$const_key} = $constants->{$const_key}; + } + } + + return \%ret; +} diff --git a/src/contrib/warden-app/WardenApp/DB.pm b/src/contrib/warden-app/WardenApp/DB.pm new file mode 100644 index 0000000..257ea1f --- /dev/null +++ b/src/contrib/warden-app/WardenApp/DB.pm @@ -0,0 +1,105 @@ +package DB; +use strict; +use warnings; + +use WardenApp::Constants; + +use constant DB_ENGINE_MYSQL => 'mysql'; +use constant DB_ENGINE_SQLITE => 'sqlite'; +use constant DB_SECTION => 'db'; + +use DBI; + +sub connectDB { + my ($cfg, $db_engine) = @_; + + my $dbh; + + if(lc $db_engine eq DB_ENGINE_MYSQL) { + + my $db = Constants::assignValue('MYSQL.db', $cfg, DB_SECTION); + my $host = Constants::assignValue('MYSQL.host', $cfg, DB_SECTION); + my $user = Constants::assignValue('MYSQL.user', $cfg, DB_SECTION); + my $pass = Constants::assignValue('MYSQL.pass', $cfg, DB_SECTION); + my $port = Constants::assignValue('MYSQL.port', $cfg, DB_SECTION); + + $dbh = DBI->connect("DBI:mysql:host=" . $host . ";port=" . $port . ";database=" . $db, + $user, + $pass, + {RaiseError => 0,AutoCommit => 0}) || die "Database connection not made: $DBI::errstr"; + } + elsif (lc $db_engine eq DB_ENGINE_SQLITE) { + + my $db = Constants::assignValue('SQLITE.db', $cfg, DB_SECTION); + my $user = Constants::assignValue('SQLITE.user', $cfg, DB_SECTION); + my $pass = Constants::assignValue('SQLITE.pass', $cfg, DB_SECTION); + + $dbh = DBI->connect("DBI:SQLite:" . $db, + $user, + $pass, + {RaiseError => 0,AutoCommit => 1}) || die "Database connection not made: $DBI::errstr"; + } + + return \$dbh; +} + +sub getOldDataDB { + + my ($db_engine, $expr, $maxage) = @_; + + my ($num, $word) = $maxage =~ /(\d+)([dmhDMH])/; + my ($word_long, $word_desc); + + $word_long = "HOUR" if $word =~ /[hH]/; + $word_long = "DAY" if $word =~ /[dD]/; + $word_long = "MONTH" if $word =~ /[mM]/; + + my $c; + $c = "<" if($expr eq "OLDER"); + $c = ">" if($expr eq "NEWER"); + + + if($db_engine eq DB_ENGINE_MYSQL) { + return sprintf("detected %s DATE_SUB(NOW(), INTERVAL %d %s)", $c, $num, $word_long); + } + + if($db_engine eq DB_ENGINE_SQLITE) { + return sprintf("datetime(detected) %s datetime('now','-%d %s')", $c, $num, $word_long); + } + + return ""; +} + +sub closeDB { + my $dbh = shift; + $$dbh->disconnect; +} + +sub getQueryCondThreshold { + my ($db_engine, $table, $columns, $params, $threshold) = @_; + + my $columns_q = join ", ", @$columns; + my $params_q = join " AND ", grep { $_ } @$params; + + return sprintf("SELECT %s FROM %s WHERE %s GROUP BY source HAVING COUNT(id) > %s", $columns_q, $table, $params_q, $threshold); +} + +sub joinIN { + my ($column, $data) = @_; + return (@$data ? sprintf("%s IN (%s) AND ", $column, join ",", map { "'$_'" } @$data) : ""); +} + +sub joinNotIN { + my ($column, $data) = @_; + return (@$data ? sprintf("%s NOT IN (%s) AND ", $column, join ",", map { "'$_'" } @$data) : ""); +} + +sub joinLIKE { + my ($column, $data) = @_; + my $ret = (@$data ? sprintf("%s", join ",", map { "$column LIKE '$_%' OR " } @$data) : ""); + + return ($ret ne "" ? substr($ret, 0, -4) . " AND " : ""); +} + + +1; diff --git a/src/contrib/warden-app/WardenApp/Factory.pm b/src/contrib/warden-app/WardenApp/Factory.pm new file mode 100644 index 0000000..05100aa --- /dev/null +++ b/src/contrib/warden-app/WardenApp/Factory.pm @@ -0,0 +1,59 @@ +package Factory; +use strict; +use warnings; + +use Config::Simple; +use WardenApp::Constants; +use WardenApp::DB; +use WardenApp::Utils; +use Data::Dumper; + +use constant TRUE => 1; +use constant FALSE => 0; +use constant ENABLED => 'yes'; + +use constant DB_ENGINE_MYSQL => 'mysql'; +use constant DB_ENGINE_SQLITE => 'sqlite'; + +use constant FACTORY_SECTION => 'factory'; +use constant CFG_MODULE_DIR => 'GENERAL.modpath'; + + +sub isModEnabled { + my ($modprefix, $cfg) = @_; + + my $enabled = Constants::assignValue($modprefix . ".enabled", $cfg, FACTORY_SECTION); + if ($enabled eq ENABLED) { + return TRUE; + } + else { + return FALSE; + } +} + +sub runModule { + my ($modulename, $cfg, $dbh, $db_engine) = @_; + + unless(isModEnabled($modulename, $cfg)) { + print "Module '$modulename' disabled! See configuration file!\n"; + return 0; + } + + my $moddir = Constants::assignValue(CFG_MODULE_DIR, $cfg, FACTORY_SECTION); + my $module = Constants::assignValue($modulename . ".module", $cfg, FACTORY_SECTION, "nocheck"); + + require "$moddir/$module.pm"; + + print "Module '$modulename' started\n"; + my $ret = $module->run($modulename, $cfg, $dbh, $db_engine); + + if($ret) { + print "Module '$modulename' finished\n"; + return 1; + } + else { + print "Module '$modulename' finished with errors\n"; + return 0; + } +} +1; diff --git a/src/contrib/warden-app/WardenApp/Receiver.pm b/src/contrib/warden-app/WardenApp/Receiver.pm new file mode 100644 index 0000000..6be70dd --- /dev/null +++ b/src/contrib/warden-app/WardenApp/Receiver.pm @@ -0,0 +1,71 @@ +package Receiver; +use strict; +use warnings; + +use WardenApp::Constants; + +use constant RECEIVER_SECTION => 'receiver'; +use constant SQL_INSERT_EVENT => "INSERT INTO events VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)"; + +sub openfile { + my ($cfg) = @_; + my ($filename, $openparam); + + my $method = Constants::assignValue('FILE.method', $cfg, RECEIVER_SECTION); + + if($method ne 'newfile' and $method ne 'append') { + $method = Constants::getDefaultValue('FILE.method', RECEIVER_SECTION); + } + + if($method eq 'newfile') { + my ($sec, $min, $hr, $day, $mon, $year) = localtime; + + $openparam = ">"; + $filename = sprintf("%02d-%02d-%04d_%02d-%02d", $day, $mon + 1, 1900 + $year, $hr, $min); + + } + elsif ($method eq 'append') { + $openparam = ">>"; + $filename = Constants::assignValue('FILE.appendfilename', $cfg, RECEIVER_SECTION); + } + + + my $directory = Constants::assignValue('FILE.directory', $cfg, RECEIVER_SECTION); + my $extension = Constants::assignValue('FILE.extension', $cfg, RECEIVER_SECTION); + + my $openstring = $openparam . $directory . "/" . $filename . "." . $extension; + open FILE, $openstring or die $!; + return \*FILE; + +} + +sub saveToDB { + my ($dbh, $event, $db_engine) = @_; + + my $sth = $$dbh->prepare(SQL_INSERT_EVENT); + #my $data = join(',', @$event); + $sth->execute(@$event) || die $sth->errstr; + + print "Receiver-$db_engine:\tError \"$@\" while processing data\n" if $@; +} + +sub saveToFile { + my ($file, $event) = @_; + my $data = join(';', @$event); + + print $file $data . "\n"; +} + +sub printToStdout { + my $event = shift; + + print "| " . join(' | ', @$event ) . " |" . "\n"; +} + +sub closeFile { + my $file = shift; + close $file; +} + +1; + diff --git a/src/contrib/warden-app/WardenApp/Utils.pm b/src/contrib/warden-app/WardenApp/Utils.pm new file mode 100644 index 0000000..7ab2eea --- /dev/null +++ b/src/contrib/warden-app/WardenApp/Utils.pm @@ -0,0 +1,111 @@ +package Utils; +use strict; +use warnings; +use Data::Dumper; + + +sub generateOutput { + my ($outputfile, $rows, $header, $record, $footer, $values) = @_; + + return 0 if not defined $record; + + if(open FILE, ">$outputfile") { + print FILE &$header($values) if defined $header; + + foreach my $r (@$rows) { + my $record_alt = &$record($r, $values); + print FILE $record_alt; + } + + print FILE &$footer($values) . "\n" if defined $footer; + close FILE; + + return 1; + } + else { + return 0; + } +} + + +sub generateEmails { + my ($tool, $to, $from, $subject, $rows, $header, $record, $footer, $values, $summary) = @_; + + my ($msg, $body) = ("", ""); + if($summary eq "yes") { + foreach my $r (@$rows) { + $body .= &$record($r, $values) if defined $record; + } + + if($body ne "") { + $msg .= &$header($values) if defined $header; + $msg .= $body; + $msg .= &$footer($values) if defined $footer; + + foreach my $recipient (@$to) { + sendEmail($tool, $recipient, $from, $subject, $msg) if defined $record; + } + } + } + else { + foreach my $r (@$rows) { + $msg = ""; + $msg .= &$header($values) if defined &$header; + $msg .= &$record($r, $values); + $msg .= &$footer($values) . "\n" if defined $footer; + + if(defined $record) { + foreach my $recipient (@$to) { + sendEmail($tool, $recipient, $from, $subject, $msg) if defined $record; + } + } + } + } +} + +sub sendEmail { + my($tool, $to, $from, $subject, $body) = @_; + + if(($from !~ /^(\w|\-|\_|\.)+\@((\w|\-|\_)+\.)+[a-zA-Z]{2,}$/) || ($from =~ /\.@|\.\./)) { + print "Senders address ('$from') is not valid!\n"; + return 0; + } + + if(($to !~ /^(\w|\-|\_|\.)+\@((\w|\-|\_)+\.)+[a-zA-Z]{2,}$/) || ($to =~ /\.@|\.\./)) { + print "Recipients address ('$to') is not valid!\n"; + return 0; + } + + if($subject eq "") { + print "Subject cannot be empty!\n"; + return 0; + } + + if(open(MAIL, "|/usr/sbin/$tool -t")) { + print MAIL "To: $to\n"; + print MAIL "From: $from\n"; + print MAIL "Subject: $subject\n\n"; + + print MAIL "$body"; + close(MAIL); + return 1; + } + else { + return (0, "Sending email failed: $!"); + } +} + +sub fetchall_array_hashref { + my ($dbh, $query) = @_; + + my $sth = $$dbh->prepare($query); + $sth->execute(); + + my (@rows, $x); + push(@rows, $x) while ($x = $sth->fetchrow_hashref()); + + return @rows; +} + + +1; diff --git a/src/contrib/warden-app/bin/warden-cleaner.pl b/src/contrib/warden-app/bin/warden-cleaner.pl new file mode 100755 index 0000000..9fb61e8 --- /dev/null +++ b/src/contrib/warden-app/bin/warden-cleaner.pl @@ -0,0 +1,61 @@ +#!/usr/bin/perl +use strict; +use warnings; + +use FindBin qw($Bin); +use lib "$Bin/../"; + +use WardenApp::DB; +use WardenApp::Constants; +use Config::Simple; + +use constant GENERAL_CONFIG_FILE => "$Bin/../etc/cleaner.conf"; +use constant DB_CONFIG_FILE => "$Bin/../etc/db.conf"; +use constant RECV_CONFIG_FILE => "$Bin/../etc/receiver.conf"; +use constant RECEIVER_SECTION => 'receiver'; +use constant CLEANER_SECTION => 'cleaner'; + +use constant DB_ENGINE_MYSQL => 'mysql'; +use constant DB_ENGINE_SQLITE => 'sqlite'; + +use constant TRUE => 1; +use constant FALSE => 0; + +my $cfg = new Config::Simple; +$cfg->read(GENERAL_CONFIG_FILE) or die $cfg->error(); + +my $cfg_rcv = new Config::Simple; +$cfg_rcv->read(RECV_CONFIG_FILE) or die $cfg_rcv->error(); + +my $cfg_db = new Config::Simple; +$cfg_db->read(DB_CONFIG_FILE) or die $cfg_db->error(); + +my @general_method = Constants::assignValue('GENERAL.method', $cfg, CLEANER_SECTION); +my $general_method_db = (grep (/db/, @general_method) ? TRUE : FALSE); +my $general_maxage = Constants::assignValue('GENERAL.maxage', $cfg, CLEANER_SECTION); +$general_maxage = Constants::getDefaultValue('GENERAL.maxage', CLEANER_SECTION) if $general_maxage !~ /\d+[hdmHDM]/; + +if($general_method_db) { + my $db_engine = Constants::assignValue('DB.dbengine', $cfg_rcv, RECEIVER_SECTION); + my $dbh = DB::connectDB($cfg_db, $db_engine); + if($dbh) { + my $query = sprintf("DELETE FROM events WHERE %s", DB::getOldDataDB($db_engine, "OLDER", $general_maxage)); + my $sth = $$dbh->prepare($query); + $sth->execute; + + my $num_deleted = $sth->rows; + print "Removed '$num_deleted' events older than $general_maxage.\n"; + + DB::closeDB($dbh); + + exit 1; + } + else { + exit 0; + } +} +else { + print "General DB method is not configured\n"; + exit 0; +} + diff --git a/src/contrib/warden-app/bin/warden-factory.pl b/src/contrib/warden-app/bin/warden-factory.pl new file mode 100755 index 0000000..a74ef27 --- /dev/null +++ b/src/contrib/warden-app/bin/warden-factory.pl @@ -0,0 +1,48 @@ +#!/usr/bin/perl +use strict; +use warnings; + +use FindBin qw($Bin); +use lib "$Bin/../"; + +use WardenApp::DB; +use WardenApp::Factory; +use Config::Simple; + +use WardenApp::Constants; + +use constant RECEIVER_SECTION => 'receiver'; +use constant DB_CONFIG_FILE => "$Bin/../etc/db.conf"; +use constant RECV_CONFIG_FILE => "$Bin/../etc/receiver.conf"; +use constant GENERAL_CONFIG_FILE => "$Bin/../etc/factory.conf"; + +my $cfg = new Config::Simple; +$cfg->read(GENERAL_CONFIG_FILE) or die $cfg->error(); + +my $cfg_rcv = new Config::Simple; +$cfg_rcv->read(RECV_CONFIG_FILE) or die $cfg_rcv->error(); + +my $cfg_db = new Config::Simple; +$cfg_db->read(DB_CONFIG_FILE) or die $cfg_db->error(); + +my $db_engine = Constants::assignValue("DB.dbengine", $cfg_rcv, RECEIVER_SECTION); +my $dbh = DB::connectDB($cfg_db, $db_engine); +if(not defined $dbh) { + exit 0; +} + +if(defined $ARGV[0] and $ARGV[0] ne "") { + if(Factory::runModule($ARGV[0], $cfg, $dbh, $db_engine)) { + exit 1; + } + else { + exit 0; + } +} +else { + print "Use module's name as parameter", "\n"; + exit 0; +} + +DB::closeDB($dbh); + diff --git a/src/contrib/warden-app/bin/warden-receiver.pl b/src/contrib/warden-app/bin/warden-receiver.pl new file mode 100755 index 0000000..bd58a69 --- /dev/null +++ b/src/contrib/warden-app/bin/warden-receiver.pl @@ -0,0 +1,65 @@ +#!/usr/bin/perl -w +use strict; +use warnings; + +use FindBin qw($Bin); +use lib "$Bin/../"; + +use Config::Simple; +use WardenApp::DB; +use WardenApp::Receiver; +use WardenApp::Constants; + +use constant GENERAL_CONFIG_FILE => "$Bin/../etc/receiver.conf"; +use constant DB_CONFIG_FILE => "$Bin/../etc/db.conf"; +use constant RECEIVER_SECTION => 'receiver'; +use constant DEFAULT_REQ_ALL => "_all_"; + +use constant TRUE => 1; +use constant FALSE => 0; + +use Data::Dumper; + +my $cfg = new Config::Simple; +$cfg->read(GENERAL_CONFIG_FILE) or exit 0; + +my $cfg_db = new Config::Simple; +$cfg_db->read(DB_CONFIG_FILE) or exit 0; + +my @general_method = Constants::assignValue('GENERAL.method', $cfg, RECEIVER_SECTION); +my $general_method_stdout = (grep (/stdout/, @general_method) ? TRUE : FALSE); +my $general_method_file = (grep (/file/, @general_method) ? TRUE : FALSE); +my $general_method_db = (grep (/db/, @general_method) ? TRUE : FALSE); + +my $warden_path = Constants::assignValue('GENERAL.wardenpath', $cfg, RECEIVER_SECTION); +my $requested_type = Constants::assignValue('GENERAL.requested_type', $cfg, RECEIVER_SECTION); +$requested_type = DEFAULT_REQ_ALL if $requested_type eq ""; + +my $logfile = Constants::assignValue('GENERAL.logfile', $cfg, RECEIVER_SECTION); +my $db_engine = Constants::assignValue('DB.dbengine', $cfg, RECEIVER_SECTION); + +my $dbh = DB::connectDB($cfg_db, $db_engine) if $general_method_db; +my $file_ref = Receiver::openfile($cfg) if $general_method_file; + +require $warden_path . '/lib/WardenClientReceive.pm'; + +# Download of new evetns from Warden server +while (my @new_events = WardenClientReceive::getNewEvents($warden_path, $requested_type)) { + foreach my $event_ref (@new_events) { + if($general_method_stdout) { + Receiver::printToStdout($event_ref); + } + + if($general_method_file) { + Receiver::saveToFile($file_ref, $event_ref); + } + + if($general_method_db) { + Receiver::saveToDB($dbh, $event_ref, $db_engine); + } + } +} + +DB::closeDB($dbh) if $general_method_db; +Receiver::closeFile($file_ref) if $general_method_file; + diff --git a/src/contrib/warden-app/doc/WApp.README b/src/contrib/warden-app/doc/WApp.README new file mode 100644 index 0000000..bbfc484 --- /dev/null +++ b/src/contrib/warden-app/doc/WApp.README @@ -0,0 +1,309 @@ ++-------------------------------+ +| README - WardenApp (WApp) 0.1 | ++-------------------------------+ + +Content + + A. Overall Information + B. Installation Dependencies + C. Installation + D. Uninstallation + E. Configuration + F. Modules + G. Run + X. Tutorial: Running of the WApp along with the database backend + XX. Tutorial: Writing your own module + +-------------------------------------------------------------------------------- +A. Overall Information + + 1. About WardenApp + + Warden is a client-based architecture service designed to share detected + security events (issues) among CSIRT and CERT teams in a simple and fast + way. + + WardenApp included in this package is an extension of classical Warden Client. + It allows automated evaluation received data and generates base of data for + another tools or just allows generating reports for human checking. + + 2. Version + + 0.1 (2013-03-20) + + 3. Package structure + + warden-app/ + |-- bin + | |-- warden-cleaner.pl + | |-- warden-factory.pl + | `-- warden-receiver.pl + |-- doc + | |-- WApp.cron + | `-- WApp.README + |-- etc + | |-- cleaner.conf + | |-- db.conf + | |-- factory.conf + | `-- receiver.conf + |-- Modules + | |-- DNSblacklist.pm + | |-- IPblacklist.pm + | |-- IPtables.pm + | `-- MailReport.pm + |-- sh + | |-- create_tables_mysql.sh + | `-- create_tables_sqlite.sh + `-- WardenApp + |-- Constants.pm + |-- DB.pm + |-- Factory.pm + |-- Receiver.pm + `-- Utils.pm + + +-------------------------------------------------------------------------------- +A1. Essence of WardenApp + + The core consists of three parts with this specific functions: + + Receiver - Receives data and stores it in the selected location (stdout, file, db [sqlite, MySQL]) + + Factory - Generates output that is requested. In short, it processes the data from the database + and generates an output dependent on the module. More about modules in section X. + + Cleaner - Erases old unnecessary events. + + Each part is represented by a Perl script that runs at defined intervals by the cron daemon. See + section H. + +-------------------------------------------------------------------------------- +B. Installation Dependencies + + Perl >= 5.10.1 + Config::Simple >= 4.59-5 + DBI + + Supported drivers for DBI are DBD::mysql and DBD::SQLite. + +-------------------------------------------------------------------------------- +C. Installation + + 1. Check SHA1 checksum of corresponding Warden client package archive + + $ sha1sum -c warden-app-0.1.tar.gz.sig + + 2. Untar it + + $ tar xzvf warden-app-0.1.tar.gz + + 3. Just copy + + Copy to any directory. For simplicity, use the default location of the Warden + project (/opt). + + 4. Installation Privileges + + The Warden client is designed to be run under standard privileges. It should + be a part of other applications that are run under usual user privileges. + + 5. Configuration files + + The files are located in directory 'conf'. For defails, see section E. + + 6. Initialize database backend + + WApp has interface for use MySQL or sqlite as database engine. Preparing + for the basic database structure can use the scripts from 'bin' directory. + + MySQL - create_tables_mysql.sh + sqlite - create_tables_sqlite.sh + +-------------------------------------------------------------------------------- +D. Uninstallation + + Simply delete all files from WardenApp's installation directory. + Optionally delete database if you used this choice. + +-------------------------------------------------------------------------------- +E. Configuration + + All configuration files are placed in 'conf' directory. File 'factory.conf' + is used for configuration each of modules, other 'db.conf', 'receiver.conf' + and 'cleaner.conf' are used for general purposes. + + Each of configuration parameters is described directly in configuration file. + +-------------------------------------------------------------------------------- +F. Modules + + Modules are placed in 'Modules' directory. Module is assigned to specific configuration + section in 'conf/facory.conf' file. + + This package includes these modules with these specific functions: + + DNSblacklist - generates zone file for the most widely used DNS software on the Internet. + IPblacklist - generates traditional CSV file with IP addresses. + IPtables - generates iptables rules. + MailReport - generates reports which are sent to specific recipients. + + Section XX. describes how to write own module. + +-------------------------------------------------------------------------------- +G. Run + + 1. Receiver + Usage: warden-receiver.pl + + 2. Factory + Usage: warden-factory.pl MODULE_CONF_NAME + + MODULE_CONF_NAME + Represents specific configuration section placed in 'factory.conf'. Each of modules + can have more configuration alternatives which are distinguished by name. + + For simple call of individual modules is possible use prepared cron script + placed in 'etc/cron.d/' directory. + + + *WARNING: When generating a report using cron, the interval in configuration file and + interval in cron script must be IDENTICAL, otherwise a result may be INACCURATE. + + 3. Cleaner + Usage: warden-cleaner.pl + +-------------------------------------------------------------------------------- +X. Tutorial: Running of the WApp along with the database backend + + 1. Database engine configuration (conf/db.conf) + + [SQLITE] + db="var/warden.db" + user= + pass= + + 2. Receiver configuration (conf/receiver.conf) + + [GENERAL] + method="db" + wardenpath="/opt/warden-client" + requested_type="_all_" + + [DB] + dbengine="sqlite" + + 3. Factory configuration, IPtables module (conf/factory.conf) + + [MOD_IPTABLES_1] + enabled="yes" + module="IPtables" + outputfile="tmp/iptables.txt" + threshold="10" + excludedip="1.1.1.1","2.2.2.2" + eventtype= + chainname="BLOCK" + destchain="DROP" + maxage="4M" + + 4. Cleaner configuration (conf/cleaner.conf) + + [GENERAL] + method="db" + maxage="5D" + + [DB] + dbengine="sqlite" + + 5. Run + + I. Manually + # ./warden-receiver.pl + # ./warden-factory.pl MOD_IPTABLES_1 + # ./warden-cleaner.pl + + II. Regularly using cron (example in etc/cron.d/wardenapp) + + SCRIPT_PATH=/opt/warden-app/ + + */5 * * * * root cd $SCRIPT_PATH; ./warden-receiver.pl + 21 * * * * root cd $SCRIPT_PATH; ./warden-factory.pl MOD_IPTABLES_1 + 1 1 * * * root cd $SCRIPT_PATH; ./warden-cleaner.pl + + +-------------------------------------------------------------------------------- +X. Tutorial: Writing your own module + + The base for modules is interface with hashes '%CONSTANTS', '%FORMAT' and sub 'run()'. + Both of them has to be implemented. Modules are placed in 'Modules' directory. + + sub run() - Main subroutine, which is always called from the parent's environment. + %CONSTANTS - Variable with all supported options and their default values. + %FORMAT - Regexp for variables which must have a specific format. + + IPtables module more deeply + =========================== + + 1. Defining configuration parameters + All configuration options with their default values are stored in %CONSTANTS hash. + + my %CONSTANTS = ( + enabled => "no", + outputfile => "tmp/iptables.txt", + threshold => 250, + excludedip => [], + eventtype => [], + chainname => "BLOCK", + destchain => "DROP", + maxage => "1D", + ); + + In this case is used parameter maxage which must be in format '\d+[hdmHDM]'. Then it is + possible use '%FORMAT' hash to enforce specific format, otherwise will be used default + value from '%CONSTANTS'. + + my %FORMAT = ( maxage => qr/\d+[hdmHDM]/, ); + + + 2. Implementation of the main function + + I. The usual start function, reading the parameters from the parent function and retrieving + values from the config file. + + sub run { + my (undef, $modprefix, $cfg, $dbh, $db_engine) = @_; + my $v = Constants::mergeConfigs($cfg, $modprefix, \%CONSTANTS, \%FORMAT); + + II. Creating of string with database query. It is possible use built-in routines like joinIN, + joinNotIN, getOldDataDB or getQueryCondThreshold. + + my $eventtype_query = DB::joinIN("type", \@{$v->{'eventtype'}}); + my $excluded_query = DB::joinNotIN("source", \@{$v->{'excludedip'}}); + + my $condition = substr($excluded_query . $eventtype_query, 0, -5); + my @columns= ("source"); + my @params = ($condition, DB::getOldDataDB($db_engine, "NEWER", $v->{'maxage'})); + my $query = DB::getQueryCondThreshold($db_engine, "events", \@columns, \@params, $v->{'threshold'}); + + III. Executing of created query and storing result to array. + + my @rows = Utils::fetchall_array_hashref($dbh, $query); + + IV. Implementing of subroutines 'header', 'record' and 'footer'. References to these functions + can be used like parameter in routine, which generates the final output. Mentioned routines + can get configuration values as a parameter and in addition, 'record' gets value of actual + record in loop over result of query. + + sub header { my $v = shift; return "/sbin/iptables -F $v->{'chainname'}\n"; }; + sub record { my ($r, $v) = @_; return "/sbin/iptables -A $v->{'chainname'} -s $r->{'source'}/32 -j $v->{'destchain'}\n"; }; + + my $ret = Utils::generateOutput($v->{'outputfile'}, \@rows, \&header, \&record, undef, $v); + + V. Exit code is returned to parent. + + return $ret; + } + + +-------------------------------------------------------------------------------- +Copyright (C) 2013 Cesnet z.s.p.o + diff --git a/src/contrib/warden-app/doc/WApp.cron b/src/contrib/warden-app/doc/WApp.cron new file mode 100644 index 0000000..e057652 --- /dev/null +++ b/src/contrib/warden-app/doc/WApp.cron @@ -0,0 +1,19 @@ +#+--------------------------- minute [0-59;*/10 means every 10 minutes (0,10,20,30,40,50)] +#| +------------------- hour [0-23] +#| | +--------------- day of month [1-31] +#| | | +------------- month [1-12] +#| | | | +----------- day of week [0-7; 0 or 7 is Sunday] +#| | | | | +-------- user +#| | | | | | +-- command +#| | | | | | | + +SCRIPT_PATH=/opt/warden-app/ + +*/5 * * * * root cd $SCRIPT_PATH; ./warden-receiver.pl + +21 * * * * root cd $SCRIPT_PATH; ./warden-factory.pl MOD_IPTABLES_1 + +21 * * * * root cd $SCRIPT_PATH; ./warden-factory.pl MOD_BLACKLISTIP_1 + +1 1 * * * root cd $SCRIPT_PATH; ./warden-cleaner.pl + diff --git a/src/contrib/warden-app/etc/cleaner.conf b/src/contrib/warden-app/etc/cleaner.conf new file mode 100644 index 0000000..0f3233f --- /dev/null +++ b/src/contrib/warden-app/etc/cleaner.conf @@ -0,0 +1,8 @@ +#CLEANER configuration file + +[GENERAL] +#What will be cleaned; [db] +method="db" +#How old events will be deleted [D - Days, M - Months, H - Hours]; +maxage="5M" + diff --git a/src/contrib/warden-app/etc/db.conf b/src/contrib/warden-app/etc/db.conf new file mode 100644 index 0000000..637ea68 --- /dev/null +++ b/src/contrib/warden-app/etc/db.conf @@ -0,0 +1,22 @@ +#DB configuration file + +[SQLITE] +# Path to sqlite database file +db="/root/warden/src/warden-app/var/warden.db" +# Username +user= +# Password +pass= + +[MYSQL] +# Name of MySQL database +db="warden2" +# Username +user="root" +# Password +pass= +# Hostname or IP of MySQL server +host="localhost" +# Port +port="3306" + diff --git a/src/contrib/warden-app/etc/factory.conf b/src/contrib/warden-app/etc/factory.conf new file mode 100644 index 0000000..f0c23d0 --- /dev/null +++ b/src/contrib/warden-app/etc/factory.conf @@ -0,0 +1,105 @@ +#FACTORY configuration file + +[GENERAL] +# Directory with modules +moddir="Modules" + +[MOD_BLACKLISTIP_1] +# Enabling module [yes, no] +enabled="yes" +# Type of module; see 'moddir' directory +module="IPblacklist" +# Where will be result stored +outputfile="/root/warden/src/warden-app/tmp/blacklist.csv" +# Threshold for SQL query (events grouped by source IP) [number] +threshold="2" +# Which source IP we want to exclude from result [ip1, ip2, ipN] +excludedip="147.228.1.70","147.228.1.61" +# Which type of events we want to process [ see Warden manual ] +eventtype="portscan","bruteforce","spam" +# Time interval for generating data [D - Days, M - Months, H - Hours]; +maxage="10M" + +[MOD_IPTABLES_1] +# Enabling module [yes, no] +enabled="yes" +# Type of module; see 'moddir' directory +module="IPtables" +# Where will be result stored +outputfile="/root/warden/src/warden-app/tmp/iptables2.txt" +# Threshold for SQL query (events grouped by source IP) [number] +threshold="10" +# Which source IP we want to exclude from result [ip1, ip2, ipN] +excludedip="1.1.1.1" +# Which type of events we want to process [ see Warden manual ] +eventtype= +# Chain in which will be iptables rules inserted +chainname="BLOCK" +# Default chain after -j (jump) statement +destchain="DROP" +# Time interval for generating data [D - Days, M - Months, H - Hours]; +maxage="4M" + +[MOD_DNSBL_1] +# Enabling module [yes, no] +enabled="yes" +# Type of module; see 'moddir' directory +module="DNSblacklist" +# Where will be result stored +outputfile="/root/warden/src/warden-app/tmp/dnsbl2.txt" +# Default target for blacklisted A record +target="127.0.0.2" +# Threshold for SQL query (events grouped by source IP) [number] +threshold="0" +# Which source IP we want to exclude from result [ip1, ip2, ipN] +excludedip= +# Which type of events we want to process [ see Warden manual ] +eventtype= +# Chain in which will be iptables rules inserted +maxage="10M" +# Default TTL for DNS zone file +ttl="3600" +# DNS name of zone +zone="@" +# SOA authoritative DNS server for zone +dns="dns3.example.com" +# SOA hostmaster's e-mail +hostmaster="hostmaster@example.com" +# SOA refresh value [s] +refresh="1800 ; refresh (30 minutes)" +# SOA retry value [s] +retry="600 ; retry (10 minutes)" +# SOA expire value [s] +expire="1209600 ; expire (2 weeks)" +# SOA minimum value [s] +minimum="86400 ; minimum (1 day)" + +[MOD_MREPORT_1] +# Enabling module [yes, no] +enabled="yes" +# Type of module; see 'moddir' directory +module="MailReport" +# Tool for send e-mails [sendmail,ssmtp] +tool="sendmail" +# Senders address +sender="wardenapp@domena.cz" +# Recipient addresses +recipients="kostenec@zcu.cz","kostenec@civ.zcu.cz" +# Subject of e-mail; leave blank for subject like [MOD_NAME (Warden-app) on HOSTNAME +subject="" +# E-mail signature +signature="XXX Incidents Response Team (XIRT)" +# List of excluded sensors +excludedsensor= +# Watched network subnets [syntax LIKE subnet%] +subnets="147.228." +# Threshold for SQL query (events grouped by source IP) [number] +threshold="0" +# Which source IP we want to exclude from result [ip1, ip2, ipN] +excludedip="147.228.209.171","147.228.1.61" +# Which type of events we want to process [ see Warden manual ] +eventtype= +# Chain in which will be iptables rules inserted +maxage="3M" +# All records will be sent in one summarized e-mail or one e-mail per record [yes,no] +summary="yes" diff --git a/src/contrib/warden-app/etc/receiver.conf b/src/contrib/warden-app/etc/receiver.conf new file mode 100644 index 0000000..626aaf1 --- /dev/null +++ b/src/contrib/warden-app/etc/receiver.conf @@ -0,0 +1,24 @@ +#RECEIVER configuration file +[GENERAL] +# Where will be received events stored [stdout,file,db] +method="stdout","file","db" +# Path to Warden client +wardenpath="/opt/warden-client" +# Type of event which will be requested. To get all types of event, leave this option blank. +requested_type= + +[FILE] +# Where will be received results stored +directory="/root/warden/src/warden-app/var/fileout/" +# How we will handle files +# append - one file named by 'appendfilename' param, +# newfile - new file for every client's call in dd-mm-yyyy_hh_mm ended by 'extension' param +method="append" +# Name of file when method 'append' will be chosen +appendfilename="warden-received" +# Extension of file when method 'newfile' or 'append' will be chosen +extension="csv" + +[DB] +# Database engine in which will be received events stored +dbengine="sqlite" diff --git a/src/contrib/warden-app/sh/create_tables_mysql.sh b/src/contrib/warden-app/sh/create_tables_mysql.sh new file mode 100755 index 0000000..4e73fd7 --- /dev/null +++ b/src/contrib/warden-app/sh/create_tables_mysql.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +USER=$1 +DB=$2 + +if [ $# -ne 2 ]; then +echo "Usage: $0 username dbname" +exit -1 +fi + +# create table events +echo "CREATE TABLE \`events\` ( + \`id\` int(11) NOT NULL AUTO_INCREMENT, + \`hostname\` varchar(256) DEFAULT NULL, + \`service\` varchar(64) DEFAULT NULL, + \`detected\` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', + \`type\` varchar(64) DEFAULT NULL, + \`source_type\` varchar(64) DEFAULT NULL, + \`source\` varchar(256) DEFAULT NULL, + \`target_proto\` varchar(16) DEFAULT NULL, + \`target_port\` int(2) DEFAULT NULL, + \`attack_scale\` int(4) DEFAULT NULL, + \`note\` text, + \`priority\` int(1) DEFAULT NULL, + \`timeout\` int(2) DEFAULT NULL, + PRIMARY KEY (\`id\`) +) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;" | mysql -u$USER -p $DB + +exit 0 diff --git a/src/contrib/warden-app/sh/create_tables_sqlite.sh b/src/contrib/warden-app/sh/create_tables_sqlite.sh new file mode 100755 index 0000000..d6ad257 --- /dev/null +++ b/src/contrib/warden-app/sh/create_tables_sqlite.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +db_file=$1 + +if [ $# -ne 1 ]; then +echo "Usage: $0 dbfile" +exit -1 +fi + +# create table events +sqlite3 $db_file "CREATE TABLE events (id INTEGER, hostname VARCHAR(256), service VARCHAR(64), detected TIMESTAMP, type VARCHAR(64), source_type VARCHAR(64), source VARCHAR(256), target_proto VARCHAR(16), target_port INT(2), attack_scale INT(4), note TEXT, priority INT(1), timeout INT(2));" + +exit 0 -- GitLab