Snort. Автоматизация активной защиты.

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

Доброго времени суток!

Для сетевого контроля своей сети очень полезно использовать систему обнаружения вторжений. Промышленным стандартом является простая и удобная система Snort [0].
Snort - система обнаружения вторжения, способная анализировать трафик в реальном масштабе времени. }{ уже не раз писал об этой программе, поэтому я не буду описывать процесс установки и настройки программы. Последнюю версию всегда можно скачать на официальном сайте программы, что, кстати, очень актуально, так как в предыдущих версиях недавно была обнаружена уязвимость. Там же скачиваем набор правил для анализа и мануалы по их самостоятельному написанию :)
Итак, Snort установлен и настроен, теперь пора автоматизировать анализ его логов.
Не собираетесь ведь вы вручную их анализировать? :)
Для получения статистики по атакам можно использовать замечательный скрипт snortalog [1]. Он выведет вам топ самых популярных атак на ваш сервер.
Ваша персональнпя Чартова дюжина :)

Для 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;
################################################################
#
# ! at first set variables here !
#


# здесь устанавливаем пути к файлам
# $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";

# здесь перечислим те предупреждения, которые мы будем игнорировать
# просто пару дней погоняй скрипт с полной отсылкой алертов и 
# сам поймёшь, что бы ты хотел игнорировать :)
# put here alerts that you want to ignor ;)
@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 file that contain number of strings for ignor
#

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

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"; 


# сохраняем в файл число проанализированных строк файла алертов
#
# write sting for ignor in next time 8)
#

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";

#########################################
# SUBROUTINES:
#

#
# clear alert strings
#
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-сервером и отправляем письмо
#
# send e-mail
#
sub send_email
{
	printf "[i] send e-mail on $adminmail\n";
	
	$message="";
	
	#
	#  join all strings of alert
	#
	$i=0;
	foreach $lvar (@lines)
	{
		#
		# get alert string here :)
		#
		if(!$i) # ($lvar =~ /[\*\*]/)
		{
			$alert = $lvar;
		}
		$message = $message.$lvar;
		$i++;
	}
	#
	# remove unexercised symbols
	#
# 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 [2] - вариант cron-a для win.
Остальное уже на ваш вкус, например, я в своём почтовике настроил фильтр, чтобы все alert-ы скидывались в нужную папку и проигрывалось знаменитое "we are under attack!"

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

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

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

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

Ссылки:
[0]. Snort :
http://www.snort.org
[1]. Домашняя страница Snortalog :
http://jeremy.chartier.free.fr/snortalog/
[2]. nncron :
http://www.nncron.ru
[3]. Последнюю версию Snortalert-а всегда можно найти здесь :
http://www.noonv.h1.ru/se/snortalert.pl

Счастливо!

noonv13[at]gmail[dot]com
XIII
Рейтинг@Mail.ru
Хостинг от uCoz