Содержание
Наиболее полезным средством обнаружения вирусных атак являются т.н. антивирусные мониторы -- постоянно запущенные антивирусные программы, "на лету" проверяющие все программы и данные, загружаемые в ОЗУ с диска и из сети. Каждый серьёзный антивирусный пакет имеет в своём составе антивирусный монитор. Например, в состав антивируса DrWeb входят мониторы SpIDerGuard (проверяет файлы) и SpIDerMail (проверяет сетевые соединения по протоколам POP3 и SMTP).
К недостаткам антивирусных мониторов можно отнести:
Рассматриваемое ниже решение лишено перечисленных недостатков, но имеет свои собственные:
Собственно излечение должно производиться обычным путём, то есть запуском антивирусной программы с чистого носителя.
Первый недостаток является наименее существенным, потому что именно на почтовые вирусы приходится подавляющая часть Интернет-эпидемий последних лет. Причин, по которым электронная почта превратилась в наиболее популярную для вирусных атак среду, несколько:
Чтобы иметь возможность в упреждающем порядке реагировать на появление новых вирусов до того, как эпидемия наберёт обороты, разработчики антивирусных программ используют т.н. почтовые ловушки. Почтовая ловушка представляет из себя более-менее обычный почтовый ящик, который:
Суть предлагаемого решения сводится к организации импровизированной ловушки (trap) внутри нашей собственной сети. Почтовое ПО на обслуживаемых компьютерах настраивается таким образом, чтобы сам факт обращения к ловушке, вне зависимости от передаваемого содержимого, сигнализировал о том, что соответствующий компьютер заражён.
Наша ловушка будет слегка отличаться от описанной выше и представляет из себя не почтовый ящик под управлением рабочего SMTP-сервера, а независимую программу-сервер, минимально имитирующий работу сервера настоящего, плюс некоторое обрамление на уровне операционной системы.
Выражаясь образно, перед тем, как настраивать ловушку, для неё потребуется расчистить пространство, сдвинув в сторону реально используемую почтовую инфраструктуру. Желательно при этом, чтобы с точки зрения пользователей всё продолжало работать без изменений, существенных плюс неприятных.
На каждой рабочей станции должно быть настроено два почтовых клиента:
Чем обусловлено данное требование? Все почтовые вирусы, прославившиеся масштабами разрушений, основаны на двух постулатах:
Из этого следуют два вывода:
Заражение через письмо происходит следующим образом:
Если второй способ является отличительной чертой Outlook (остальные почтовые клиенты подобной инициативностью в отношении т.н. active content не страдают), то первый расчитан на невнимательного или неквалифицированного пользователя, и подпадает под категорию т.н. social engineering.
Как правило, среднестатистический вирус не может или не пытается определить, через какой почтовый клиент он попал в систему, и начинает атаку на другие компьютеры, используя сведения из настроек и адресной книги Outlook'а или сервера MAPI (которым зачастую является всё тот же Outlook).
Конфигурация фактически используемого почтового клиента на рабочей станции должна быть изменена следующим образом:
Затем сетевому администратору потребуется выполнить настройки в одном из трёх вариантов в зависимости от того, какой SMTP-сервер, или серверы, используется в организации для отправки почты:
Далее для демонстрации настроек сервера используется, если это не оговорено особо, следующее программное обеспечение:
Чтобы перенастроить Postfix, отредактируйте в файле /etc/postfix/master.cf все строки, начинающиеся с smtp inet, заменив smtp на номер порта, например, на 325. Желательно, чтобы новый номер...
Заставьте Postfix перечитать настройки (service postfix reload) и проверьте, что они вступили в силу: netstat -ntl и netcat localhost 325.
При этом возникает проблема внешних соединений. Дело в том, что по протоколу SMTP почта на наш сервер поступает не только от клиентов, но и от других серверов из внешней сети, причём возможности заставить эти серверы пользоваться нестандартным портом не существует. Данная проблема решается простым перенаправлением IP-порта. С этой целью могут быть использованы разные программы, в том числе и стандартный супердемон xinetd. В каталоге /etc/xinetd.d на SMTP-сервере должен быть размещён файл smtp-forward с содержимым, составленным по следующему образцу:
# file: /etc/xinetd.d/smtp-forward
# description: trivial port forwarding of external SMTP requests to actual port
service smtp # This label selects listening port 25 for incoming requests
{
flags = REUSE
disable = no
user = nobody
server = /bin/false # bugfix trick for old versions
socket_type = stream
protocol = tcp
wait = no
interface = 1.2.3.4 # IP-address of extranet NIC
no_access = 192.168.30.0/24 # Internal network mask
redirect = 127.0.0.1 325 # Actual listening port of SMTP-server
# log_on_success = PID HOST USERID EXIT DURATION
# log_on_failure = HOST USERID ATTEMPT RECORD
}
После этого: service xinetd reload. Проверка: netstat -ntl и netcat 1.2.3.4 25, где 1.2.3.4 - внешний IP-адрес сервера.
Не менее просто делается редиректор с помощью пакетного фильтра iptables, работающего с Linux kernel 2.4+:
INTERNAL_IFACE=eth0
MY_PORT=325
DEST_HOST=www.mail.ru
DEST_PORT=25
# Очистка очереди входящих пакетов:
# iptables -t nat -F PREROUTING
# Все TCP-пакеты, поступающие из внутренней сети на MY_PORT,
# будут перенаправлены на другой хост и порт с подстановкой
# IP-адреса и временного порта маршрутизатора
# в качестве адреса/порта отправителя.
# См. определение Network Address Translation.
iptables -t nat -I PREROUTING -p tcp \
-i $INTERNAL_IFACE --dport $MY_PORT \
-j DNAT --to $DEST_HOST:$DEST_PORT
# Просмотр NAT-очередей:
# iptables -t nat -L -v
Любопытная особенность данного редиректора состоит в том, что пакеты подвергаются перенаправлению на основании одного только номера порта, вне зависимости от указанного в них IP-адреса цели. Это позволяет задавать в настройках клиента в качестве адреса SMTP-сервера абсолютно любое внешнее имя, например, www.gov.no. Однако по причинам, изложенным в следующем разделе, рекомендуется указывать здесь имя самого компьютера-редиректора/smtp-ловушки.
При наличии уверенности, что настройки рабочих почтовых клиентов не попадут в распоряжение вируса, можно оставить для клиентов порт отправки со значением по умолчанию, т.е. 25, но указать не внутренний IP-адрес или DNS-имя SMTP-сервера, а внешний. В этом случае SMTP-сервер для рабочего клиента и сервер-ловушка для Outlook'a будут отличаться не номером порта, а IP-адресом, хотя для их запуска и будет использоваться один и тот же компьютер: ловушка будет "слушать" подключения на внутреннем интерфейсе, а настоящий сервер - на внешнем, "глядящем" в Интернет.
Для организации этой схемы на сервере потребуется:
Тем не менее, схема с переносом настоящего SMTP-сервера на нестандартный порт на общем с ловушкой сетевом интерфейсе является более предпочтительной. Дело в том, что некоторые вирусы, добравшись до настроек почтового клиента, используют их не вполне правильным образом (мне довелось наблюдать этот эффект в своей собственной сети): вирус читает только адрес SMTP-сервера и игнорирует номер порта , используя для отправки данных стандартный порт 25. Схема с общим IP-адресом, ловушкой на стандартном порту и настоящим сервером на нестандартном засекает такой вирус, даже если определение фактически используемого почтового клиента и доступ к его настройкам в этом вирусе работают верно.
Если персонал организации имеет почтовые ящики на ограниченном множестве внешних серверов, можно обойтись простым редиректором для каждого из них. Для этого на Линукс-маршрутизаторе, имеющем выход во внешнюю сеть, потребуется создать в каталоге /etc/xinetd.d множество файлов следующего вида:
# file: /etc/xinetd.d/smtp-chat_ru
# description: trivial SMTP tunnel from intranet to mail.chat.ru
service smtp.chat.ru # any custom name, used for syslog'ging only
{
type = UNLISTED
flags = REUSE
disable = no
user = nobody
server = /bin/false # bugfix trick for old versions
socket_type = stream
protocol = tcp
wait = no
interface = 192.168.30.1 # IP-address of intranet NIC
only_from = 192.168.30.0/24 # Internal network mask
port = 325 # Listening port for incoming requests
redirect = mail.chat.ru 25 # Actual SMTP-server
# log_on_success = PID HOST USERID EXIT DURATION
# log_on_failure = HOST USERID ATTEMPT RECORD
}
# Don't forget this: service xinetd reload ;-)
Примечание: не используйте в именах файлов точку - такие файлы xinetd игнорирует!
Для этого раздела в силу его малой актуальности решение не составлялось. По всей видимости, данная задача может быть решена только с использованием прокси-сервера SOCKS и клиентской утилиты SocksCapture. Поскольку на текущий момент у меня нет опыта их использования, в качестве отправной точки для собственных изысканий всем заинтересованным читателям предлагается статья Андрея Черезова в "КомпьюТерре", из которой и почерпнуты все мои нынешние познания о SOCKS.
Попав на компьютер и заразив его, почтовый вирус начинает заражать другие компьютеры. Для этого он производит рассылку заражённых писем одним из следующих способов:
Естественно, последние два варианта требуют, чтобы заражённая рабочая станция имела выход во внешнюю сеть либо напрямую, либо через SOCKS, либо через NAT.
Соответственно, отлавливать заражённые письма будут два компонента:
Кроме того, некоторые дополнительные настройки окажутся нелишними в Outlook'e на рабочих станциях.
Принимать запросы на отправку почты через 25-й порт из локальной сети под видом SMTP-сервера будет xinetd:
#
# /etc/xinetd.d/smtp-trap
#
service smtp
{
flags = REUSE
disable = no
user = nobody
server = /bin/false
socket_type = stream
protocol = tcp
wait = no
only_from = 192.168.106.0/24 # Internal network
interface = 192.168.106.128 # Intranet IP-address
log_on_success = HOST EXIT DURATION
log_on_failure = HOST ATTEMPT
banner = /var/local/smtptrap.banner
}
## Don't forget: service xinetd reload; netstat -tl
Чтобы у инициатора соединения не возникало сомнений, что ему отвечает именно SMTP-сервер, xinetd будет немедленно посылать приглашение, взятое из файла /var/local/smtptrap.banner, как это всегда делает отвечающая сторона в SMTP. Приглашение может содержать сравнительно произвольный текст:
220 mx.necrosoft.net ESMTP MS_Exchange/NetBSD
Например, соединитесь netcat'ом с настоящим сервером SMTP и возьмите за образец приглашение, которое он выведет.
К сожалению, утилиту, отвечающую за составление и отправку оповещений, придётся запускать независимо. Дело в том, что создаваемое ею оповещение должно содержать IP-адрес, с которого было установлено соединение с ловушкой, а этот адрес xinetd умеет сообщать одним-единственным образом -- записывая его в log-файл или в syslog. В частности, в ALTLinux'е syslog настроен таким образом, что требуемые нам сообщения от xinetd попадают в файл /var/log/auth/secure.
Хотя приведённый ниже сценарий создавался скорее в демонстрационных целях, нежели для практического применения, в нём есть почти всё, что требуется полноценной программе такого рода:
Вместе с тем, не реализованы следующие моменты:
К сожалению, shell-программирование и регулярные выражения являются настолько широкими и увлекательными темами, что более подробные пояснения к исходному тексту рискуют далеко выйти за рамки данной статьи.
#!/bin/bash
#
# /usr/bin/trap-watch
#
# Purpose: watches system logs for network connections
# at specific xinetd-driven port,
# then notifies sysadmin about this event by email.
#
# Requires: screen, perl, sudo, grep, mail, id
#
# May be executed by root or any sudoer in interactive mode ($0 watch)
# or background mode ($0 start/stop/status/restart/condrestart/attach)
#
# Written by Evseev/EBCEEB at Apr 2004 http://ilya-evseev.narod.ru
# Distributed under terms of GNU GPL http://www.gnu.org/license
#
MYNAME=`basename $0`
SERVICE=smtp
TITLE=${SERVICE}trap.watch
WATCH_FILE=/var/log/auth/secure
WATCH_USER=nobody
ADMIN_EMAIL=root
SUDO=/usr/bin/sudo
function report_error() {
echo "Error: $*!" 1>&2
return 1
}
function usage() {
[ $# = 0 ] || report_error $*
echo "Usage: $MYNAME watch|start|stop|status|restart|condrestart|attach|help"
}
function watch()
{
local SUDO_TAIL SUDO_PERL PERL_TMP=${TMPDIR:-/tmp}
case `id -u` in
0 ) # We are root.
# So execute perl/mail under nobody account for security reason
SUDO_PERL="$SUDO -H -u $WATCH_USER"
PERL_TMP=/tmp
# nobody cannot write to it's own homedir..
#eval PERL_TMP=~$WATCH_USER
;;
[0-9]* )
# We are ordinal user.
# So execute tail under root account (only root can read logs)
SUDO_TAIL="$SUDO" ;;
* ) report_error "cannot detect your UID"; return 1 ;;
esac
$SUDO_TAIL tail -n0 -f $WATCH_FILE | \
TMPDIR=$PERL_TMP $SUDO_PERL perl -n \
-e "\$service=$SERVICE; \$email=$ADMIN_EMAIL;" \
-e 'if (/^(\w+ \d+ [\w:]+) \w+ xinetd\[[0-9]*\]: START: $service from=([0-9.]*)$/ ) {
$when = "$1";
$addr = "$2";
$subj = "$service trap from $addr";
$body = "$when -- $subj";
print "$body\n";
system "echo $body | mail -s \"$subj\" $email";
}'
}
function check_status() {
screen -list | grep -q $TITLE && return 0 || return 1
}
function status() {
check_status && echo "$TITLE loaded." && return 0
echo "$TITLE not loaded."
return 1
}
function start() {
if check_status; then
report_error "$TITLE is already loaded";
return 1;
fi
screen -S $TITLE -d -m $0 watch
echo "$TITLE started."
}
function stop() {
if screen -r $TITLE -X quit;
then echo "$TITLE stopped."
else report_error "cannot stop $TITLE, maybe not started?"
fi
}
function main()
{
case "$1" in
-s | start) start ;;
-d | stop) stop ;;
-q | status) status ;;
-r | restart) stop; start ;;
-c | condrestart ) check_status && restart ;;
-a | attach) screen -r $TITLE ;;
-i | watch) watch ;;
-h | --help | help | -H ) usage ;;
* ) usage "unrecognized command line: $*" ;;
esac
}
main "$@"
В задачу работающего на компьютере-маршрутизаторе пакетного фильтра входит просмотр заголовков IP-пакетов, отправляемых из внутренней сети, уничтожение тех пакетов, чьим целевым портом является smtp/25, и оповещение системного администратора.
Пакетный фильтр может решать эту задачу одним из трёх способов:
Перед вводом дополнительных правил пакетный фильтр должен быть минимально настроен, например:
service iptables start
iptables -F
iptables -X
iptables -t nat -X
iptables -t nat -F
for chain in INPUT OUTPUT FORWARD; do iptables -P $chain ACCEPT # ..или DROP
done
INTERNAL_IFACE=eth0
# Создаём составное правило с именем "trap"
iptables -N trap || iptables -F trap
# Действие 1: запись сообщения в syslog
iptables -A trap -j LOG --log-prefix "TRAP " \
-m limit --limit 1/minute --limit-burst 3 \
--log-level INFO --log-ip-options --log-tcp-options
# Действие 2, завершающее: удаление пакета
iptables -A trap -j DROP
# Правило "trap" готово.
# Все TCP-пакеты, входящие на SMTP-порт из внутренней сети,
# будут обработаны правилом "trap".
iptables -I INPUT -p tcp -i $INTERNAL_IFACE --dport smtp -j trap
# То же самое для транзитных пакетов.
iptables -I FORWARD -p tcp -i $INTERNAL_IFACE --dport smtp -j trap
За сообщениями iptables следит исправленный вариант сценария из предыдущего раздела. Исправление состоит из двух строк и заключается в имени просматриваемого файла и образце поиска:
--- trap-watch 2004-03-19 01:54:44 +0300
+++ trap-watch2 2004-04-11 00:39:02 +0400
@@ -18,7 +18,7 @@
MYNAME=`basename $0`
SERVICE=smtp
TITLE=${SERVICE}trap.watch
-WATCH_FILE=/var/log/auth/secure
+WATCH_FILE=/var/log/syslog/messages
WATCH_USER=nobody
ADMIN_EMAIL=root
SUDO=/usr/bin/sudo
@@ -54,7 +54,7 @@
$SUDO_TAIL tail -n0 -f $WATCH_FILE | \
TMPDIR=$PERL_TMP $SUDO_PERL perl -n \
-e "\$service=$SERVICE; \$email=$ADMIN_EMAIL;" \
- -e 'if (/^(\w+ \d+ [\w:]+) \w+ xinetd\[[0-9]*\]: START: $service from=([0-9.]*)$/ ) {
+ -e 'if (/^(\w+ \d+ [\w:]+) \w+ kernel: TRAP .* SRC=([0-9.]*) / ) {
$addr = "$2";
$when = "$1";
$subj = "$service trap from $addr";
Если приведённый листинг находится в файле trap-watch.diff в одном каталоге с trap-watch, то исправленный сценарий trap-watch2 создаётся командой patch < trap-watch.diff.
У данного варианта имеются два недостатка. С одной стороны, каждая попытка вируса установить SMTP-сессию будет приводить к нескольким срабатываниям ловушки, по числу попыток TCP/IP на заражённом компьютере открыть соединение. Чтобы отсекать сообщения о повторных попытках, запись в syslog производится с ключами -m limit --limit 1/minute --limit-burst 3. С другой стороны, это приведёт к тому, что повторяющиеся сообщения от фильтра станут отсекаться даже в том случае, когда они будут вызваны обращениями с разных IP-адресов. Это, в свою очередь, означает, что если заражены несколько компьютеров одновременно, информация о некоторых из них в syslog не попадёт (а о некоторых попадёт несколько раз).
В этом случае дополнительного сценария не требуется, так как всей обработкой будет заниматься сервер TRAP_HOST:
TRAP_HOST=192.168.30.10
INTERNAL_IFACE=eth0
# SMTP-пакеты перенаправляются на сервер-ловушку:
iptables -t nat -I PREROUTING -p tcp \
-i $INTERNAL_IFACE --dport smtp \
-j DNAT --to $TRAP_HOST
INTERNAL_IFACE=eth0
INTERNAL_IPADDR=192.168.30.1 # ifconfig $INTERNAL_IFACE | grep 'inet addr:' | ...
# Адрес узла назначения меняется на 127.0.0.1,
# номер порта оставляется без изменений,
# пакет попадает в SMTP-ловушку.
iptables -t nat -I PREROUTING -p tcp \
-i $INTERNAL_IFACE '!' -d $INTERNAL_IPADDR --dport smtp \
-j REDIRECT --to-port 25
# Примечание: --to-port должен быть числовым,
# название "smtp" не поддерживается!
Список адресов, по которым должна производиться рассылка, может быть составлен вирусом из самых разных источников:
Поэтому имеет смысл поместить в локальную адресную книгу фальшивую контактную запись. Фальшивая запись должна:
Благодаря этим свойствам:
Главное достоинство фальшивой контактной записи состоит в том, что данный приём может быть использован независимо от всех остальных механизмов, предлагаемых в данной статье. В минимальном варианте не требуется ни создавать фальшивую почтовую систему, ни перенастраивать рабочую - достаточно занести в настоящую адресную книгу на клиенте специальную запись, а на настоящем SMTP-сервере настроить перехват адресованных ей сообщений.
Некоторое неудобство состоит в том, что фиктивная запись обязана быть локальной, то есть не может быть однократно добавлена в адресную книгу на сервере ActiveDirectory или LDAP. Казалось бы, эту рутинную операцию не составит труда автоматизировать, однако здесь начиниются проблемы.
Во-первых, для работы с почтовой системой Microsoft предоставляет множество перекрывающихся API: MAPI, Simple MAPI, Exchange Client API и т.д. В соответствии с традициями Microsoft все они неряшливо спланированы, громоздко реализованы и намеренно невнятно документированы в той части, которая касается общего понимания. Таким образом, основная часть времени уходит на то, чтобы убедиться, что очередной API нужной функциональности не содержит .
Поиски приводят нас к WAB, Windows Address Book или адресной книге Windows. Хотя в большинстве случаев она вызывается из Outlook Express, WAB является самостоятельным приложением и имеет собственный программный интерфейс. Его применение Microsoft демонстрирует утилитой WabTool, которая доступна в виде исходных текстов. К сожалению, WabTool является GUI-приложением, то есть не может использоваться в не-интерактивном, пакетном режиме, и годится только в качестве заготовки. Принципиальное нежелание в очередной раз разгребать сочинённый Microsoft мусор помешало автору статьи написать на её базе требуемую утилиту.
Настройки для сервера Posfix должны быть дополнены следующим образом:
allow_mail_to_commands = yes
virtual_maps = hash:/etc/postfix/virtual
@smtptrap.net trap@localhost
trap: "|/var/local/posttrap"
newaliases
postmap /etc/postfix/virtual
service postfix reload
Сценарий posttrap - обработчик заражённых писем - может выглядеть так:
#!/usr/bin/perl
$admin_email = 'root@localhost';
our $when, $who, $subj, $body;
while ($line = <>) {
if ($line =~ /^\tid [0-9A-F]+\; (.*)/) {
$when = $1;
} elsif ($line =~ /^To: (.*)/) {
$who = $1;
$subj = "Mail trap from $who";
$body = "$when -- $subj";
system("echo \"$body\" | TMPDIR=/tmp mail -s \"$subj\" $admin_email");
}
}
Во-первых, управление вычислительными сетями является запутанной технической дисциплиной. Стать строже ей мешают два противоположных требования: поддерживать совместимость с ворохом исторически закрепившихся нелепиц -- и продолжать непрерывно развиваться, чтобы (а) делать более качественными существующие услуги, (б) предоставлять новые и (в) не рухнуть под собственным весом.
Здесь трудно подготовить решение, которое будет выглядеть одновременно и универсальным (то есть широким), и законченным (то есть глубоким). Любая идея, реализованная в виде суммы утилит, образцов настроек и документации, обязана вскоре после опубликования начать развитие - или будет забыта. Иногда в ходе разработки получается, что заранее обдумывавшийся приём оказывается невозможным вследствие тех или иных технических ограничений, а сочинённый экспромтом трюк становится основным. Так, наиболее удачным моментом в статье мне самому представляются фальшивые почтовые адреса - этот раздел появился, когда каркас статьи был уже готов и заполнялся материалом.
Во-вторых, редкое решение в Юниксе выполняется одной программой. Чаще требуется совместно настраивать несколько программ, каждая из которых отвечает за одну конкретную область, но раскрывает её аспекты максимально полно. Для взаимодействия этих программ необходимо создавать другие программы - сценарии, выполняемые третьими программами - командными интерпретаторами. Такой подход разительно отличается от мира Windows, где всё, что можно настроить, настраивается быстро и просто, но поверхностно и негибко. И главным инструментом настройки выступает не язык выполнения сценариев, а "манипулятор мышь". По этой причине Windows-администратор характером работы ближе к пользователю, а Юникс-администратор - к программисту (правда, линейной зависимости к уровеню их квалификации это соображение не имеет).
В-третьих, в каждой категории существует много альтернативных средств. Программы, выбранные мною - это то, что установлено на моём домашнем компьютере, и с чем я уже имел дело. В вашем случае на месте Postfix может оказаться qmail, вместо ядра Linux 2.4 с iptables - ядро 2.2 с пакетным фильтром ipchains, вместо ALT'a - Debian, вместо Линукса - OpenBSD, а grep, sed и awk покажутся вам более уместными, чем Perl.
Поэтому не стоит рассматривать предлагающийся материал как готовый рецепт. Перед вами скорее некие зарисовки, направленные на развитие фантазии и эрудиции. Если бы мне потребовалось настраивать систему ловушек в реально эксплуатируемой системе, я бы ограничился только фальшивыми адресами в WAB. Идея же фиктивной почтовой сети вызвана тем, что на протяжении нескольких лет мне пришлось администрировать почтовую сеть, состоящую из рабочих станций Lotus Notes и серверов Lotus Domino. В такой среде фиктивную сеть не пришлось бы как-то специально отделять от настоящей -- её ядром становится находящийся в балласте Outlook Express, инсталлируемый по умолчанию вместе с Windows -- ни перенастраивать настоящую сеть, потому что для передачи почты Лотус вместо протоколов SMTP/POP3/IMAP использует NotesRPC.
В завершение хочу поблагодарить своих бывших сослуживцев, А.Н. Боженко и Н.А. Рыбину, за материал, послуживший поводом для написания данной статьи.