"У нее на футболке написано: «Мы ненавидим ненависть». "
Тибор Фишер - "Путешествие на край комнаты"

Для сетевого контроля своей сети очень полезно использовать систему обнаружения вторжений. Промышленным стандартом является простая и удобная система Snort.

Snort - система обнаружения вторжения, способная анализировать трафик в реальном масштабе времени. }{ уже не раз писал об этой программе, поэтому я не буду описывать процесс установки и настройки программы. Последнюю версию всегда можно скачать на официальном сайте программы, что, кстати, очень актуально, так как в предыдущих версиях недавно была обнаружена уязвимость. Там же скачиваем набор правил для анализа и мануалы по их самостоятельному написанию 🙂

Итак, Snort установлен и настроен, теперь пора автоматизировать анализ его логов. Не собираетесь ведь вы вручную их анализировать? 🙂 Для получения статистики по атакам можно использовать замечательный скрипт snortalog. Он выведет вам топ самых популярных атак на ваш сервер. Ваша персональная Чартова дюжина 🙂

Для Snort-а существует множество различных надстроек и утилит, но во всех этих утилитах мне страшно не хватало оперативного сообщения об атаке. Я не жадный - письма на e-mail и смс-ки на мобильник мне вполне хватит :).

Сказано - сделано 🙂 Так как я использую несколько snort-датчиков, причём не только на сервере с FreeBSD, но и в виде сервиса на рабочих машинах под Windows, я решил написать скрипт на Perl-е. Я не специализируюсь в программировании на Perl-е и, возможно, многое можно было сделать лучше, но главный плюс моего скрипта - это его простота, а также то, что он работает.

Скрипт анализирует файл alert ( в который Snort записывает предупреждения о возможных атаках) и отсылает предупреждение на заданный e-mail. Для получения sms-ок можно использовать существующую возможность уведомления о входящей почте (для чего и вводится модификация переменной $adminmail_from - чтобы в имени отправителя сохранялось описание атаки) или использовать sms-гейт вашего оператора (просто внесите нужные изменения в функцию send_email).

#!/usr/bin/perl -w

############################################################
#
# for analyse Snort alerts (with option '-A full')
#
# XIII
############################################################

#
# <noonv13@gmail.com>
#
# version: 1.0
#

# используем сокеты для непосредственного общения с smtp-серверами

use Socket;
################################################################

# здесь устанавливаем пути к файлам
# $alerts_file - alert.ids -
файл алертов Snort-a
# $alertstr_file - alert.str -
наш файл для хранения числа строк, уже проанализированных скриптом

# path to Snort alerts -file
$alerts_file = "c:/util/Snort/log/alert.ids";# "/var/log/snort/alert";
# path to my string-number of alerts ( enable it for wtiting ! )
$alertstr_file = "c:/util/Snort/log/alert.str"; # "/var/log/snort/alert.str";

# здесь перечислим те предупреждения, которые мы будем игнорировать
#
просто пару дней погоняй скрипт с полной отсылкой алертов и
#
сам поймёшь, что бы ты хотел игнорировать :)
@alerts4ignor = #("XXXXXXXXXXXXXXXXX"); # place it for send all alerts :)
("ICMP L3retriever Ping",
"ICMP redirect host",
"unicode share access");

# $adminmail - e-mail для отправки алертов
#
$smtp - наш smtp-сервер
#
$subject - тема письма - на неё нужно будет настроить фильтр в своём почтовике
# $host_name - имя датчика, которое будет добавлено в тело письма

$adminmail = 'root@host.ru';
$adminmail_from = ""; # keep it "" (empty) if script mast generate FROM %)
$smtp = "smtp.rgs.ru";
$subject = "[!] snort alert [!]";
$host_name = "Frankensteine";

################################################################

# открываем файл и считываем число строк, уже проанализированных нашим скриптом

open FILE0, $alertstr_file or die "Can't open $alertstr_file $!\n";

$counter = 0;
$lines_for_ignor = 0;
while ( <FILE0> )
{
$lines_for_ignor = $_;
#printf $lines_for_ignor;
$counter++;
}

if($counter >1)
{
printf "[!] error in file $alertstr_file!\n";
}
printf "[i] ignor lines: $lines_for_ignor\n";

close FILE0 or die "Can't close FILE: $!\n";

#
# #########################################
#

# открываем файл алертов

open FILE, $alerts_file or die "Can't open $alerts_file $!\n";

$counter = 0;
$sendalert = 0; # flag for send alert on e-mail
@lines = ("","","","","","","","","",""); # for store lines of alert

$message=""; # message for send
$alert=""; # alert message ( usually - first string )

print "\n";
$OS = $^O;

$readed_lines = 0;

#
# main cycle %)
#
while ( <FILE> )
{
#
пропускаем нужное количество строк
#
# ignor lines here 8)
#
$readed_lines++;
if($readed_lines < $lines_for_ignor)
{
next
}

if($_ le "\r\n")
{
print "[i] here alert! str: $counter\n";
$sendalert = 1; # set default for send alert
$i=0;
#
анализируем - есть ли предупреждение в списке игнорируемых и если нет - отправляем письмо
analyse_alert();
if($sendalert)
{
if ($counter) # check on empty rules %)
{
send_email();
}
else
{
print "[i] here nothing to send\n";
}
}
$counter = 0;
clear_mas();
}
else
{
$lines[$counter]=$_;
$counter++;
}
}

close FILE or die "Can't close FILE: $!\n";

# сохраняем в файл число проанализированных строк файла алертов
#

open FILE0, ">$alertstr_file" or die "Can't open $alertstr_file for writing$!\n";
print FILE0 "$readed_lines";
close FILE0 or die "Can't close FILE: $!\n";

####
# exit here
printf "OS: $OS\n";

#########################################
#

sub clear_mas
{
$i=0;
foreach $lvar (@lines)
{
$lvar="";
$i++;
}
}

#
# analyse alert
#
sub analyse_alert
{
foreach $ignor (@alerts4ignor)
{
foreach $lvar (@lines)
{
if( $lvar =~ /$ignor/ )
{
print "[i] ignor this alert :)\n";
$sendalert = 0;
}
}
}
}

# функция отправки e-mail-ов
#
сначала формируем предупреждение и переменную для поля FROM:
#
затем общаемся с smtp-сервером и отправляем письмо
#

sub send_email
{
printf "[i] send e-mail on $adminmail\n";

$message="";

#

$i=0;
foreach $lvar (@lines)
{
#
# get alert string here :)
#
if(!$i) # ($lvar =~ /[\*\*]/)
{
$alert = $lvar;
}
$message = $message.$lvar;
$i++;
}
#
# example of alert:
# [**] [1:466:5] ICMP L3retriever Ping [**]
#
$alert2 = $alert;
$alert2 =~ s/\[\*\*\]//g; # remove [**]
$alert2 =~ s/ //g; # remove ' '
$alert2 =~ s/\[\d+:\d+:\d+\]//g; # remove [1:466:5]
$alert2 =~ s/\$/_/g; # replace bad symbols
$alert2 =~ s/\n//g; # replace '\n'

if($adminmail_from)
{
$email_from = $adminmail_from;
}
else
{
$email_from=$alert2."_".$adminmail;
}
$email_to=$adminmail;
$email_subject=$subject;
$attachment = "";

##
$host=$smtp;
print "$host\n";
$port="25";
socket(SOCK, PF_INET, SOCK_STREAM, getprotobyname('tcp'));
$iaddr = inet_aton($host);
$paddr = sockaddr_in($port, $iaddr);
connect(SOCK, $paddr);
send (SOCK, "HELO $host\r\n", 0);
$data=<SOCK>;
send (SOCK, "MAIL FROM: <$adminmail>\r\n", 0);
$data=<SOCK>;
send (SOCK, "RCPT TO:<$email_to>\r\n", 0);
$data=<SOCK>;
send (SOCK, "DATA\r\n", 0);
$data=<SOCK>;
send (SOCK, "From:<$email_from>\nTo:<$email_to>\nSubject:$email_subject\n\n$host_name\n$message\r\n", 0);
$data=<SOCK>;
send (SOCK, "\.\r\n", 0);
$data=<SOCK>;
send (SOCK, "QUIT\n\r", 0);
$data=<SOCK>;
close(SOCK);
}

Осталось прописать запуск скрипта в crontab с нужной вам регулярностью (например - каждую минуту) и ждать писем. Для датчиков под Windows автозапуск скрипта можно реализовать, используя отличную утилиту nncron - вариант cron-a для win. Остальное уже на ваш вкус, например, я в своём почтовике настроил фильтр, чтобы все alert-ы скидывались в нужную папку и проигрывалось знаменитое "we are under attack!".

Уф! Вот и всё! Как и обещал - всё очень просто :).

Теперь, попивая на природе пиво с друзьями, вы всегда получите предупредительную sms-ку. На вопрос друзей можете этак лениво ответить - "да вот какой-то умник, возомнивший себя хакером, пытается взломать мой сервер". К сожалению, я уже не смог остановиться и в новую версию скрипта добавил немного функциональности; чтобы он не просто оповещал нас об атаке, но и предпринимал некоторые активные действия. Но об этом - в следующий раз.

До встречи в сети!

Ссылки:

  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    0 комментариев
    Межтекстовые Отзывы
    Посмотреть все комментарии