Skip to content
Snippets Groups Projects
Commit 5b262f79 authored by Jakub Cegan's avatar Jakub Cegan
Browse files

Task #613 jednoduche cmd

 * pridal jsem dva prepinace
  * -c pro konfiguracni soubor i s cestou
  * -i pro interval ve dnech pro dotazy (napr. jak dlouho je klient neaktivni)
 * uklid neporadku v contrib
parent 7cfc7cb6
No related branches found
No related tags found
No related merge requests found
#!/usr/bin/perl
#
# networkReporter.pl - Warden client for communication with RT ticketing system
#
# Copyright (C) 2012 Masaryk University
# Author(s): Jakub CEGAN <cegan@ics.muni.cz>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Masaryk University nor the names of its contributors may be
# used to endorse or promote products derived from this software without
# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
use warnings;
use strict;
use lib '/opt/warden-client';
use Email::Simple;
use Sys::Hostname;
use Text::Wrap;
use DateTime;
sub sendmailWrapper{
my $message = shift;
if(open(my $sendmail, '|/usr/sbin/sendmail -oi -t')){
print $sendmail $message;
close $sendmail;
return 1;
} else {
return (0, "Sending email failed: $!");
}
}
sub timeToLocal{
my $time = shift;
my ($y,$m,$d,$h,$mm,$s);
if(!($$time =~ m/(\d{4})\-(\d{2})\-(\d{2})\ (\d{2})\:(\d{2})\:(\d{2})/)){
return (0, "Bad time format!\n");
}
($y,$m,$d,$h,$mm,$s) = $$time =~ m/(\d{4})\-(\d{2})\-(\d{2})\ (\d{2})\:(\d{2})\:(\d{2})/;
eval{
my $dt = DateTime->new(
year => $y,
month => $m,
day => $d,
hour => $h,
minute => $mm,
second => $s,
time_zone =>'gmt');
$dt->set_time_zone('local');
$$time = $dt->strftime('%d. %m. %Y v %H:%M');};
if($@){
return (0, "Can't convert time to epoch format!\n");
}
return 1;
}
#-------------------------------------------------------------------------------
# reportToRT - fuction for creating tickets in the RT system
#
# param: hash with gateway address and warden event array
#
# return: ok || fail
#-------------------------------------------------------------------------------
sub reportToRT{
my $inputData = shift;
my $toGateway = $$inputData{'gateway'};
my @event = @{$$inputData{'data'}};
my $fromHostname;
my $message;
my ($rc, $err);
if(!($toGateway)){
return (0, "Empty 'To' email header!\n");
}
eval{
$fromHostname = hostname();
if(!($fromHostname =~ m/\.ics\.muni\.cz/gi)){
$fromHostname .= '.ics.muni.cz';
}
};
if($@){
return (0, "Can't retrive hostname for 'From' header!\n");
}
($rc, $err) = timeToLocal(\$event[3]);
if(!$rc){
return (0, $err);
}
my $text = "Dobrý den,
z Vaší IP adresy $event[6] jsme zaznamenali $event[3] celkem $event[9] pokus(y) o připojení k neexistující službě (tzv. honeypotu). V tomto konkrétním případě se jednalo o protokol $event[7] a port číslo $event[8]. Je pravděpodobné, že se jedná o virus, napadený počítač či zneužitý uživatelský účet. Doporučujeme Vám zkontrolovat zabezpečení tohoto počitače.
S pozdravem
CSIRT-MU
http://www.muni.cz/csirt";
eval{
$message = Email::Simple->create(
header => [
To => $toGateway,
From => 'tools@'.$fromHostname,
Subject => 'Pristup na honeypot v siti CESNET'],
body => fill('','',$text));
};
if($@){
return (0, "Can't create email message\n");
}
($rc, $err) = sendmailWrapper($message->as_string);
if(!$rc){
return (0, $err);
}
return 1;
}
my $warden_path = '/opt/warden-client';
require $warden_path . '/lib/WardenClientReceive.pm';
my $requested_type = "portscan";
my $ip_reg = '147\.251\.\d+\.\d+';
my $client = 'CESNET_IDS';
my $gateway = 'rt@rt-devel.ics.muni.cz';
$Text::Wrap::columns = 90;
my $logger;
my @new_events;
@new_events = WardenClientReceive::getNewEvents($warden_path, $requested_type);
#@new_events = (["5179620","au1.cesnet.cz","CESNET_IDS","2012-11-08 17:04:56","portscan","IP","147.251.216.8","XXX","666","2","","0","720"]);
foreach (@new_events) {
my @event = @$_;
if(($event[6] =~ /^$ip_reg$/i) and ($event[2] =~ /^$client$/i)){
my %input = (gateway => $gateway, data => \@event);
my ($rc,$err) = reportToRT(\%input);
if(!$rc){
#print "ERR: $err\n";
syslog("err|Warden client - networkReporter $err\n");
}
}
}
exit 0;
#!/usr/bin/perl
#
# WardenWatchdog.pl
#
# Copyright (C) 2011-2012 Cesnet z.s.p.o
#
# Use of this source is governed by a BSD-style license, see LICENSE file.
#use WardenConf;
use strict;
use warnings;
use DBI;
use DBD::mysql;
use DateTime;
use Email::Simple;
use Sys::Hostname;
use Data::Dumper;
sub sendmail_wrapper{
my $message = shift;
if(open(my $sendmail, '|/usr/sbin/sendmail -oi -t')){
print $sendmail $message;
close $sendmail;
return 1;
} else {
return (0, "Sending email failed: $!");
}
}
# Array of hashes
#{query => ; text => ; contact => }
sub send_report{
my $input_data = shift;
my $contact = $$input_data{'contact'};
my $domain = $$input_data{'domain'};
my $text = $$input_data{'text'};
my $from_hostname;
my $message;
if(!($contact)){
return (0, "Empty 'To' email header!\n");
}
$domain =~ s/\./\./;
eval{
$from_hostname = hostname();
if(!($from_hostname =~ m/^$domain$/gi)){
$from_hostname = $domain;
}
1;
} or do {
return (0, "Can't retrive hostname for 'From' header!\n");
};
eval{
$message = Email::Simple->create(
header => [
To => $contact,
From => 'warden_watchdog@'.$from_hostname,
Subject => "Kotrola stavu udalosti warden serveru na stroji $domain"],
body => $text);
} or do {
return (0, "Can't create email message\n");
};
my ($rc, $err) = sendmail_wrapper($message->as_string);
if(!$rc){
return (0, $err);
}
return 1;
}
sub connect_to_DB {
my $dbPlatform = 'mysql';
my $dbName = 'warden';
my $dbHostname = 'localhost';
my $dbUser = 'root';
my $dbPasswd = 'w4rd3n&r00t';
my $dbhRef = shift;
my $dbh;
if($dbh = DBI->connect( "dbi:$dbPlatform:database=$dbName;host=$dbHostname", $dbUser, $dbPasswd, {RaiseError => 1, mysql_auto_reconnect => 1})){
$$dbhRef = $dbh;
return 1;
}
else{
return (0,"Cannot connect to database! ".DBI->errstr);
}
}
sub update_procedures{
my $procRef = shift;
my @procedures = @{$procRef};
my $dbh;
# connect to DB
my ($rc,$err) = connect_to_DB(\$dbh);
if (!$rc){
return (0,'update_procedures can\'t connect do DB: '.$err);
}
foreach my $proc (@procedures) {
$dbh->do($proc);
}
# disconnect to DB
$dbh->disconnect;
return 1;
}
sub send_query{
my $configRef = shift;
my $eventsRef = shift;
my @config = @{$configRef};
my %bad_events;
my ($rc,$err);
my $dbh;
my $i = 0;
# connect to DB
($rc,$err) = connect_to_DB(\$dbh);
if (!$rc){
return (0,'send_query can\'t connect do DB: '.$err);
}
while ($i < scalar(@config)) {
# run DB query -> requestor, client name
my $sth;
if (defined($config[$i]{query})){
$sth = $dbh->prepare($config[$i]{query});
}
else{
return (0, "No query availble\n");
}
if (!($sth->execute)){
return (0, "Couldn't get data from my database: $sth->errstr\n");
};
my @result;
my $contact;
my $msg_text = 1;
while(@result = $sth->fetchrow()){
if (defined($config[$i]{contact})){
$contact = $config[$i]{contact};
if($msg_text){
$bad_events{$contact} .= $config[$i]{text} . "\n\n";
$msg_text = 0;
}
$bad_events{$contact} .= join(", ",@result) . "\n";
}
else{
$contact = "from_db\@$result[0]";
$bad_events{$contact} .= $config[$i]{text} . "\n\n";
$bad_events{$contact} .= join(", ",@result) . "\n";
}
}
foreach my $key (keys %bad_events){
$bad_events{$key} .= "\n\n";
}
$sth->finish;
$i++;
}
# disconnect to DB
$dbh->disconnect;
%$eventsRef = %bad_events;
return 1;
}
sub run{
my $domain = shift;
my $period = shift;
my $date;
eval{
my $dt = DateTime->now();
$dt = DateTime->now()->subtract(days => $period);
$date = $dt->date();
} or do {
#print "Warden watchdog - can't work with date\n";
syslog("err|Warden watchdog - can't work with date\n");
};
# stored procedures
# iptest - is ip from private network
my @procedures = ('DROP FUNCTION IF EXISTS iptest;', 'CREATE FUNCTION iptest(ip VARCHAR(15)) RETURNS TINYINT(1) DETERMINISTIC
BEGIN
SET @nip = INET_ATON(ip);
IF(
ISNULL( @nip) OR
@nip BETWEEN 0 AND 16777216 OR
@nip BETWEEN 167772160 AND 171966464 OR
@nip BETWEEN 2130706432 AND 2130706433 OR
@nip BETWEEN 2851995648 AND 2851995649 OR
@nip BETWEEN 2886729728 AND 2886729729 OR
@nip BETWEEN 3221225472 AND 3221225473 OR
@nip BETWEEN 3221225984 AND 3221225985 OR
@nip BETWEEN 3227017984 AND 3227017985 OR
@nip BETWEEN 3232235520 AND 3232235521 OR
@nip BETWEEN 3323068416 AND 3323068417 OR
@nip BETWEEN 3325256704 AND 3325256705 OR
@nip BETWEEN 3405803776 AND 3405803777 OR
@nip BETWEEN 3758096384 AND 3758096385 OR
@nip BETWEEN 4026531840 AND 4026531841 OR
@nip > 4294967295) THEN
RETURN TRUE;
ELSE
RETURN FALSE;
END IF;
END;');
# {query => ; text => ; contact => }
# Time of last event of each client.
# Is it unsupported type of event?
# Is event from the future?
# Martane - Is IP from the private network?
my @configuration = (
{query => "SELECT hostname, service, MAX(received) FROM events WHERE valid = 't' GROUP BY hostname, service ORDER BY MAX(received) ASC;", text => "Uvedeny klient, nebo klienti jiz delsi dobu nereportovali zadne udalosti do Wardenu. Je mozne, ze nefunguji spravne.", contact => 'jakubcegan@cesnet.cz, ph@cesnet.cz'},
{query => "SELECT requestor FROM clients WHERE service IN (SELECT service FROM events WHERE detected > '$date' AND type NOT IN ('portscan', 'bruteforce', 'probe', 'spam', 'phishing', 'botnet_c_c', 'dos', 'malware', 'copyright', 'webattack', 'test', 'other') AND valid = 't' GROUP BY service) GROUP BY requestor;", text => "Uvedeny klient, nebo klienti zasilaji nepodporovany nebo zastaraly typ udalosti na server Warden", contact => 'jakubcegan@cesnet.cz, ph@cesnet.cz'},
{query => "SELECT hostname, service, type, COUNT(*) FROM events WHERE detected - received > 0 AND received > '$date' GROUP BY hostname, service, type;", text => "Uvedeny klient, nebo klienti odesilaji odesilaji udalosti s casem z budoucnosti. Cas prirazeny serverem pri prichodu udalosti (received) musi byt vzdy roven nebo vetsi casu detekce (detected).", contact => 'jakubcegan@cesnet.cz, ph@cesnet.cz'},
{query => "SELECT hostname, service, received, source, count(source) AS c, min(received), max(received) FROM events WHERE valid = 't' AND source_type = 'IP' AND iptest(source) GROUP BY hostname, service, source ORDER BY c DESC;", text => "Uvedeni klient, nebo klienti odesilaji udalosti se zdrojovou adresou, ktera by se nemela objevit v internetu (privatni rozsah), nebo je neplatna (prazdny oktet, oktet je vetsi nez 255, apod.). kvuli omezeni verzi MySQL serveru funguje zatim pouze pro IPv6.", contact => 'jakubcegan@cesnet.cz, ph@cesnet.cz'});
my ($rc,$err) = update_procedures(\@procedures);
if (!$rc){
#print "Warden watchdog - $err\n";
syslog("err|Warden watchdog - $err\n");
}
my %bad_events;
my $i = 0;
while ($i < scalar(@configuration)) {
my ($rc,$err) = send_query(\@configuration,\%bad_events);
if (!$rc){
#print "Warden watchdog - $err\n";
syslog("err|Warden watchdog - $err\n");
}
$i++;
}
while (my ($contact, $text) = each(%bad_events)){
my %input = (contact => $contact, domain => $domain, text => $text);
my ($rc,$err) = send_report(\%input);
if (!$rc){
#print $err;
syslog("err|Warden client - networkReporter $err\n");
}
}
}
run('warden-dev.cesnet.cz',7);
1;
#!/usr/bin/perl
use strict;
use warnings;
use DBI;
use DBD::mysql;
use Data::Dumper;
use Test::More tests => 7;
use Test::MockModule;
use Test::Exception;
use lib '..';
use wardenWatchdog;
my (%input, $retCode, $result);
print "== wardenWatchdog::send_report ==\n";
*wardenWatchdog::sendmail_wrapper = sub {print "sendmailWrapper is set to broken!\nSending of emails will fail\n"; return 0;};
%input = (contact => 'test@test.receiver.cz', domain => 'test.domain.cz', text => 'TEST MSG!');
($retCode, $result) = wardenWatchdog::send_report(\%input);
ok ($retCode == 0, 'Broken sendmail');
*wardenWatchdog::sendmail_wrapper = sub {print "sendmailWrapper is OFF!\nSending of emails is blocked\n"; return 1;};
%input = (contact => '', domain => 'test.domain.cz', text => 'TEST MSG!');
($retCode, $result) = wardenWatchdog::send_report(\%input);
ok ($retCode == 0, 'No contact');
%input = (contact => 'test@test.receiver.cz', domain => '', text => 'TEST MSG!');
($retCode, $result) = wardenWatchdog::send_report(\%input);
ok ($retCode == 0, 'No domain');
%input = (contact => '', domain => 'test.domain.cz', text => '');
($retCode, $result) = wardenWatchdog::send_report(\%input);
ok ($retCode == 0, 'No text');
%input = (contact => 'test@test.receiver.cz', domain => 'test.domain.cz', text => 'TEST MSG!');
($retCode, $result) = wardenWatchdog::send_report(\%input);
ok ($retCode == 1, 'All OK');
print "== wardenWatchdog::connect_to_DB ==\n";
my $dbh;
($retCode, $result) = connect_to_DB(\$dbh);
ok ($retCode == 1, 'Connected to the DB');
# FAILED DB CONNECTION
print "== wardenWatchdog::update_procedures ==\n";
# CORRECT RUN OF update_procedures
print "== wardenWatchdog::send_query ==\n";
# RUN WITH BROKEN DB CONNECTION
# RUN WITH NO query
# CORRECT RUN OF send_query
print "== wardenWatchdog::run ==\n";
# RUN WITHOUT domain
# RUN WITHOUT period
# CORRECT RUN OF send_query
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment