Автор работы: Пользователь скрыл имя, 22 Февраля 2013 в 11:47, дипломная работа
Проблема с вредоносным программным обеспечением (далее ВПО) не является новой, точно также она не исчезнет в ближайшем будущем. Слишком много денег вложено теми людьми, которые используют трояны, вирусы и армии ботов, чтобы просто отказаться от их использования. Целью атак этого вредоносного программного обеспечения являются не только обычные пользователя домашних компьютеров, но и также пользователи корпоративных компьютеров.
Актуальность выполнения дипломного проекта по данной теме обусловлена фактом использования вредоносных программ для решения задач промышленного шпионажа.
ВВЕДЕНИЕ 3
1 АНАЛИЗ УГРОЗ ВЫЧИСЛИТЕЛЬНОМУ ПРОЦЕССУ ПРЕДПРИЯТИЯ ОТ ВРЕДОНОСНОГО ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ 5
1.1 КЛАССИФИКАЦИЯ ВРЕДОНОСНОГО ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ 5
1.2 КАНАЛЫ РАСПРОСТРАНЕНИЯ ВРЕДОНОСНОГО ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ 6
1.3 ОПИСАНИЕ ПОПУЛЯРНЫХ ВИДОВ ВРЕДОНОСНОГО ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ 7
1.4 ОБЗОР ВПО НА ПРИМЕРЕ ВИРУСА WIN32.MANIAC.B 9
1.5 ПОСТАНОВКА ЗАДАЧИ НА ДИПЛОМНОЕ ПРОЕКТИРОВАНИЕ 12
2 МЕТОДЫ БОРЬБЫ С ВРЕДОНОСНЫМ ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ 13
2.1 КОНТРОЛЬ ПРИЛОЖЕНИЙ 13
2.2 ОРГАНИЗАЦИЯ КОНТРОЛЯ ПРИЛОЖЕНИЙ В СРЕДЕ WINDOWS 14
2.3 ОРГАНИЗАЦИЯ КОНТРОЛЯ ПРИЛОЖЕНИЙ В СРЕДЕ UNIX 16
2.4 ПРОАКТИВНЫЕ ТЕХНОЛОГИИ 16
2.5 АНТИВИРУСНАЯ ЗАЩИТА 18
2.6 ОРГАНИЗАЦИОННЫЕ МЕРЫ 20
3 РАЗРАБОТКА СИСТЕМЫ ПО ОБНАРУЖЕНИЮ ЗАПРЕЩЕННОГО И ВРЕДОНОСНОГО ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ 22
3.1 ПРОЦЕСС РАЗРАБОТКИ 22
3.2 ИСПОЛЬЗУЕМЫЕ ТЕХНОЛОГИИ В ХОДЕ РАЗРАБОТКИ 23
3.2.1 ТРАНСПОРТНЫЙ ПРОТОКОЛ UDP 23
3.2.2 СИГНАТУРНОЕ ОБНАРУЖЕНИЕ 24
3.2.3 ПРОЦЕССЫ В СРЕДЕ ОС UNIX 26
3.3 ПОИСК И СОЗДАНИЕ СИГНАТУРЫ 29
3.4 ПРИНЦИП РАБОТЫ РАЗРАБОТАННОЙ СИСТЕМЫ ПО ОБНАРУЖЕНИЮ ВПО LA_SERVER.PL И LA_CONSOLE.PL 30
РИСУНОК 17 – ДЕМОНСТРАЦИЯ РАБОТЫ LA_SERVER.PL И LA_CONSOLE.PL ПО ШИРОКОВЕЩАТЕЛЬНОМУ КАНАЛУ. 32
3.5 РАЗБОР РАБОТЫ СЕРВЕРНОЙ ЧАСТИ LA_SERVER.PL 33
3.5 РАЗБОР РАБОТЫ КЛИЕНТСКОЙ ЧАСТИ LA_CONSOLE.PL 40
ЗАКЛЮЧЕНИЕ 46
СПИСОК ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ 47
ПРИЛОЖЕНИЯ 48
Рисунок 13 – Трассировка ИЭ при помощи strace
Рисунок 14 – Открытие ИЭ редактором the.
Следующий шаг - это дизассемблирование ИЭ. На рисунке 15 показан участок, где ИЭ вызывает команду rm –fr /etc/passwd через функцию execve().
На снимке значение 409 - это смещение в байтах от начала файла и до искомой сигнатуры, а расстояние от 409 до 440 - это размер сигнатуры равный 55 байт. Ассемблерные команды mov в данном случаи передают аргументы функции execve() в регистр esp, а команда call как раз вызывает функцию execve(“rm –fr /etc/passwd”).
Сигнатура уже найдена, теперь необходимо создать ее контрольную сумму по md5, для этого был разработан скрипт sign_create.pl, который приведен в приложении Б.
По результату работы скрипта, была получена контрольная сумма и записана в файл базы сигнатур в виде:
87918881bc8bd3c24f07615650544a
Формат записи сигнатуры: MD5-сумма\tсмещение\tразмер\
На рисунке 16 приведен результат дизассемблирования
второго ИЭ, который отличается от первого,
следовательно и md5 сумма сигнатуры будет
иной. В этом случаи длина сигнатуры равна
50 байт, а контрольная сумма выглядит так c35b002c0d68e5caa3605cbd2ffed1
Рисунок 16 – Дизассемблирование второго варианта ИЭ.
Сетевое взаимодействие. На РС администратора сети устанавливается клиентская часть la_console.pl, а на остальные РС в сети устанавливается la_server.pl. Эти два приложения взаимодействуют между собой по UDP протоколу, а именно: приложение la_server.pl после сканирования локальной РС в случае обнаружения ВПО или запрещенного ПО устанавливает связь с РС на которой запущен la_console.pl использую широковещательный канал под UDP и передает полученные данные. Так же при первом запуске la_server.pl делает запрос update к console.pl с целью скачать новые базы сигнатур.
За организацию передачи данных по UDP отвечают функции udp_server() net_send(), udp_client(). Функция udp_server() слушает заданный порт переменной $src_pserver и выполняет действия согласно условию при поступлении определенных команд:
- !cmd – вернуть вывод команды оболочки shell;
- iplist – вернуть вывод команды uname;
- update – обратиться к РС с la_console.pl за обновлением баз сигнатур.
Функция udp_client() отправляет данные переданные в качестве аргумента.
Функция net_send() использует функцию udp_client() для отправки данных, но при этом если данные превышают MTU, эта функция их разбивает, добавляя к каждому пакету свой заголовок, таким образом если в адрес la_console.pl приходит много данных с разных РС сети, он собирает все пакеты воедино, используя переданный заголовок. Заголовок представляет собой номер пакета и уникальную контрольную сумму.
Сценарии la_client.pl и la_server.pl сами по себе работают как сервер так и клиент. В ходе их запуска выполняется вызов функции fork(), которая ответвляет дочерний процесс, в итоге получается родительский процесс и дочерний. Родительский процесс выступает в роли сервера, а дочерний в роли клиента в случае с la_server.pl, а в случае с la_console.pl наоборот.
Механизмы поиска la_sevrer.pl. Функция generic_fs_md5() осуществляет рекурсивный поиск по файловой систему сохраняя в хэш свойства файла и его контрольную сумму по md5.
Функция proc_mon() мониторит текущие процессы и появление новых процессов используя procfs (/dev/proc). Через procfs эта функция получат путь к файлу процесса (запущенное приложение), после чего получает его свойства stat() и контрольную сумму md5.
Функция compare() делает сравнение контрольных сумм файлов найденного с базой сигнатур.
Используемые команды. Административная часть la_console.pl поддерживает следующие команды:
- use использовать заданный IP для выполнения комманд оболочки;
- !cmd - выполнение комманд на серверах указанных в use;
- show - показать заданные IP опцией use;
- scan - сканировать фс в заданном окружении;
- iplist - вывести опрошенных по UDP бродкасту хостов
- update - обновить базы сигнатур
На рисунке 17 приведен пример взаимодействия la_server.pl и la_console.pl, используя широковещательный канал.
Интерфейс разработанной программы представляет собой консоль и изображен на рисунке 18.
Рисунок 18 – Консольный интерфейс la_console.pl и отправленный результат обнаружения ВПО.
Несмотря на то, что разработка использует широковещательный канал в своей работе, пропускная способность канала будет снижена только в том случаи, если будут сотни заражений на каждой рабочей станции.
Разработанная программная реализация в своей работе не требует установки дополнительных модулей, что удобно при установке, имеет компактный размер и всегда можно внести в код поправки, или дописать плагинную основу к командам.
Настоящая разработка не так эффективна, как скажем тот же бесплатный антивирус clamav, но сама по себе оригинальна и в случае, если попадется элемент ВПО, который по своему стандарту будет искать известные антивирусы среди запущенных процессов, эта разработка ему знакома не будет, и в случае имения сигнатуры, ВПО будет обнаружено.
Для детального понимая принципа работы серверной части la_server.pl ниже приведен исходный код сценария с описанием функций и взаимодействия оных между собой.
Ниже первая строка определяет местоположение интерпретатора Perl, далее подключаются 2е прагмы strict (отслеживает не безопасные конструкции Perl) и warnings (отвечает за предупреждение в случае нарушения синтаксиса).
#!/usr/bin/perl
use strict;
use warnings;
### --- Используемые модули --- ###
# работа с сокетами
use Socket;
# рекурсивный поиск файлов и каталогов
use File::Find;
# генерация md5 хэша
use Digest::MD5 "md5_hex";
### ---/ ###
Через our, ниже объявлены глобальные переменные, которые можно изменять. Под изменения попадают только следующие переменные : $sdbf, $tim, $scan_path_fs, $MTU, $DSZ, $src_pserver, $dst_pserver.
# файл сигнатур
our $sdbf = "sign.txt";
# таймаут сканирования
our $tim = 9;
# ХЕШ формата файл-stat()
our %fhs;
# загрузившиеся сигнатуры
our %sign;
# путь по умолчанию для сканирования ФС
our $scan_path_fs = '/home/n4n/my_diplom/src/test_
# Maximum Transmission Unit
our $MTU = 1500;
# Размер данных без своего заголовка
our $DSZ = 1472;
# локальный порт
our $src_pserver = 7777;
# удаленный порт
our $dst_pserver = 7778;
Приведенная ниже функция main() является главной функцией, из нее вызываются все остальные функции, содержащиеся в сценарии. Начало ее начинается с вызова функции fork(), которая порождает дочерний процесс, эта сделано для того что бы сценарий работал одновременно как сервер, так и клиент.
В случае сценария la_server.pl, родительский процесс производит сканирования ФС при помощи функции generic_fs_md5() и мониторинг процессов при помощи функции proc_mon(), но перед первым запуском производиться скачка новых баз сигнатур, отправляя при помощи функции udp_client() команду update. Последнюю функцию которую вызывает родительский процесс, является compare(), она производит сравнения полученных ранее вызванными функциями данные и сравнивает сигнатуры с подгруженной базой. Эти полученные данные функциями generation_fs_md5() и proc_mon() помещаются с хэш.
Дочерний процесс в
свою очередь работает сервером. Его
серверная часть ожидает
# точка входа
main:
{
# ответвляем процесс средствами fork()
die " *ERR: fork()\n" unless (defined(my $pid = fork()));
# родительский процесс
# эта часть кода делает сканирование ФС и мониторинг процессов
if($pid == 0)
{
# открыть базу сигнатур и поместить в хеш
my $tm_str; if( !($tm_str = _read_file($sdbf)) )
{
# в случае неудачи, сделать запрос на root-консоль для ее получения
print "[-] База сигнатур не найдена\n";
udp_client('update');
}
foreach my $str( split /\n/, $tm_str )
{
my ( $x, $y ) = split /\t/, $str;
$sign{$x} = $y;
}
do
{
# сканироние ФС
generic_fs_md5($scan_path_fs);
# мониторинг используемых файлов процессом
proc_mon();
# сравнение md5
compare();
} while(sleep $tim);
exit;
}
# потомок
# эта часть кода обрабатывает полученные сообщения от администратора
else
{
print "[~] Start UDP server...\n";
udp_server();
exit;
}
}
# Разбить данные на части равные MTU для сети ethernet
sub net_send
{
my ( $data, $count, $len_data, $chksum, @pos, @data_spliting ) = ( shift, 0 );
print ">> $data <<\n";
# сгенерить чексумму для пакета
$chksum = generic_pwd(7);
# размер данных
$len_data = length($data);
if( $len_data <= $DSZ )
{
udp_client($data);
}
# реформировать пакет
else
{
@data_spliting = split //, $data;
for(my $i = 0; $i <= $#data_spliting; $i += $DSZ)
{
push @pos, $i;
}
push @pos, $len_data if ( $#pos < $len_data );
}
my ( $j, $k, @packets );
for( $j = 0, $k = 1; $k <= $#pos; $k++ )
{
my $pkt = join("", @data_spliting[$pos[$j] .. $pos[$k]-1]);
push @packets, $pkt;
$j++;
}
foreach my $send ( @packets )
{
my $send_cpy = $send;
$count += 1;
if( ($count == 1) || ($count > 1 && $count < $#packets) )
{
$send = "<s:$chksum:$send_cpy:$count>"
}
else
{
$send = "<s:$chksum:$send_cpy:$count>"
}
udp_client($send);
}
}
#
sub udp_client
{
# Отправляемые данные
my $data = shift;
# Открыть сокет
socket( SOCKET, PF_INET, SOCK_DGRAM, getprotobyname("udp") ) or die "Error: can't create an udp socket: $!\n";
# Отключить буферизацию для дескриптора SOCKET
select( ( select(SOCKET), $|=1 )[0] );
# Сформировать пару IP:PORT для сокета
my $broadcastAddr = sockaddr_in( $dst_pserver, INADDR_BROADCAST );
# Установить опцию сокета SO_BROADCAST
setsockopt( SOCKET, SOL_SOCKET, SO_BROADCAST, 1 );
# Отправка данных
send( SOCKET, $data, 0, $broadcastAddr ) or die "Error at sendding: $!\n";
# Закрытие сокета
close SOCKET;
}
#
sub udp_server
{
socket( UDPSOCK, PF_INET, SOCK_DGRAM, getprotobyname('udp') ) or die "socket: $!";
select( ( select(UDPSOCK), $|=1 )[0] ); # no suffering from buffering
setsockopt( UDPSOCK, SOL_SOCKET, SO_BROADCAST, 1 ) or die "setsockopt SO_BROADCAST: $!";
# my $broadcastAddr = sockaddr_in( $udp_port, INADDR_BROADCAST );
my $broadcastAddr = sockaddr_in( $src_pserver, INADDR_ANY );
bind( UDPSOCK, $broadcastAddr ) or die "bind failed: $!\n";
my $in;
while( my $addr = recv( UDPSOCK, $in, $MTU, 0 ) )
{
my ( $r_port, $r_addr ) = unpack_sockaddr_in($addr);
my $cmd_buffer;
print inet_ntoa($r_addr) . " : $r_port $in\n";
if($in eq 'iplist')
{
# вернуть о системе, ос, проц..
$cmd_buffer = `uname -s -n -r -o`;
net_send($cmd_buffer);
}
elsif($in =~ /^cmd/)
{
$in =~ s/^cmd://;
$cmd_buffer = join("", `$in`);
net_send($cmd_buffer);
}
elsif($in =~ /^update/)
{
$in =~ s/^update//;
_write_file($sdbf, $in);
}
}
}
# поиск файлов, можно по маске
sub generic_fs_md5
{
my ( $path, $mask ) = @_;
find
(
sub
{
return unless -r;
return if( $mask && $_ !~ /$mask$/ );
open FH, $_ or warn "$path/$_ : $!";
my $file;
while(my $str = <FH>)
{
$file .= $str;
}
close FH;
@{$fhs{"$path/$_"}}{qw/md5 uid gid size atime mtime/} =
file_stat("$path/$_");
},
$path
);
}
# мониторинг процессов
sub proc_mon
{
opendir DH, "/proc" or die $!;
foreach my $d ( readdir( DH ) )
{
next if $d !~ /[0-9]/;
#$pid{$d} = _read_file("/proc/$d/cmdline")
if(my $pfname = _read_file("/proc/$d/cmdline")
{
@{$fhs{$pfname}}{qw/md5 uid gid size atime mtime/} =
file_stat($pfname) if -r $pfname;
}
}
close DH;
}
# генерация случайного пароля
sub generic_pwd
{
my ( $size, @char, $pwd ) = shift;
@char = ('a'..'z','A'..'Z','0'..'9','_
$pwd = '';
while(length($pwd) < $size)
{
$pwd .= $char[int rand @char];
}
return $pwd;
}
# получить информацию по файлу
sub file_stat
{
my ( $file, @info ) = shift;
push @info, Digest::MD5::md5_hex( _read_file($file) );
push @info, (stat($file))[4,5,7,8,9];
# формат: md5, uid, gid, size, atime, mtime
return @info;
}
# сравнение
sub compare
{
my $report;
foreach my $smd5 ( keys %sign )
{
foreach my $f ( keys %fhs )
{
$report .= "[FOUND] $f $sign{$smd5}\n" if ($smd5 eq $fhs{$f}{'md5'});
}
}
if($report)
{
net_send($report);
undef($report);
}
}
# вернуть содержимое файла
sub _read_file
{
open RFH, shift or return 0;
my $src;
while(read(RFH, my $buf, $DSZ)) { $src .= $buf; }
close RFH;
$src = 0 unless $src;
return $src;
}
# записать в файл
sub _write_file
{
my( $file, $data ) = @_;
open WFH, ">$file" or return 0;
print WFH $data;
close WFH;
}
sub avscan
{
my ( $file, $sdb ) = @_;
my %dbf;
my $vir;
# читаем файл с сигнатурами в память
open DBF, $sdb or die $!;
while(my $str = <DBF>)
{
chomp $str;
my ( $md5, $offset, $length, $desc ) = split /\t/, $str;
$dbf{$md5}{'offset'} = $offset;
$dbf{$md5}{'length'} = $length;
$dbf{$md5}{'descriptions'} = $desc;
}
close DBF;
# для быстрого поиска помещаем элемент ВПО в память
open VIR, $file or die $!;
$vir .= $_ while(<VIR>);
close VIR;
# разбиваем посичволно и помещаем в массив
my @el = split //, $vir;
undef($vir);
# сам поиск сигнатуры
foreach my $k ( keys %dbf )
{
for(my $j = 0; $j <= ($#el - $dbf{$k}{'length'}); $j++)
{
my $st = $j;
my $ed = ($j+$dbf{$k}{'length'}-1);
$vir = join("",@el[$st .. $ed]);
if( Digest::MD5::md5_hex($vir) eq $k )
{
return "File 'file' infected $dbf{$k}{'descriptions'}\n";
exit; } } } }
Для детального понимая принципа работы клиентской части la_console.pl ниже приведен исходный код сценария с описанием функций и взаимодействия оных между собой.
Ниже первая строка определяет местоположение интерпретатора Perl, далее подключаются 2е прагмы strict (отслеживает не безопасные конструкции Perl) и warnings (отвечает за предупреждение в случае нарушения синтаксиса).
#!/usr/bin/perl
use warnings;
use strict;
#
# Консоль упровления
#
### --- Используемые модули --- ###
# работа с сокетами
use Socket;
Ниже перечислины глобальные переменные, изменять можно только переменные $sdbf, $src_pserver, $dst_pserver.
### --- Глобальные переменные --- ###
# файл базы сигнатур
our $sdbf = "sign.dbf";
# локальный порт
our $src_pserver = 7778;
# удаленный порт