Содержание статьи
Интернет — это опасная и враждебная территория. Сотни злоумышленников могут
проверять и испытывать твою сеть 24 часа в сутки, 7 дней в неделю. Не стоит
полагаться только на брандмауэр. Применяй комплексный подход к защите — с
привлечением нестандартных приемов обеспечения безопасности.
В авангарде сетевого мостостроения
Всего лишь несколькими командами можно превратить обычный компьютер класса
Pentium-1 с двумя сетевыми картами на борту в интеллектуальный коммутатор,
соединяющий различные сети между собой. Так, что компьютер из одной сети будет
общаться с компьютером из другой без участия маршрутизатора! Причем, подобный
сетевой мост позволит фильтровать входящий и исходящий трафик, выполнять
нормализацию и дефрагментацию IPv4‑пакетов, нарезать канал, организовать
привязку IP-адресов к MAC’ам, противодействовать DOS-атакам, попыткам
сканирования и спуфинга. Что интересно, мост можно сделать прозрачным (транспарентным;
когда ни одному из сетевых интерфейсов не назначается IP-адрес) либо
полупрозрачным (внешний интерфейс наделен сетевым адресом, а внутренний — нет).
Стоит отметить: вне зависимости от типа моста задействованные сетевые
интерфейсы будут автоматически переведены в режим приема всех пакетов, что может
вызвать недовольство со стороны провайдера. С теоретической частью закончили,
переходим к практике. Чтобы создать прозрачный сетевой мост, первым делом нужно
поднять интерфейсы vr0 и vr1 (это карточки на чипсете VIA RhineII), не указывая
их сетевые настройки, и выставить корректные права доступа к файлам
конфигурации:
# echo "up" | tee /etc/hostname.vr{0,1}
# chmod 600 /etc/hostname.vr{0,1}
Примечание: здесь и далее предполагается, что мы работаем в OpenBSD 4.4.
Настроим мост так, чтобы он своими силами блокировал трафик, отличный от IP,
например, соединения по протоколам IPX или NETBEUI (опция blocknonip), и
запрещал перенаправление широковещательных пакетов (опция link0):
# vi /etc/bridg ename.bridg e0
add vr0
add vr1
blocknonip vr0
blocknonip vr1
link0
up
Теперь достаточно перезагрузиться либо набрать команды
ifconfig bridge0 create; brconfig bridge0 `cat /etc/ bridgename.bridge0`
и прозрачный мост начнет пропускать через себя проходящий трафик. Поскольку
бридж самостоятельно перенаправляет пакетики с одного сетевого интерфейса на
другой, нет необходимости в файле /etc/sysctl.conf устанавливать значение
переменной net.inet.ip.forwarding равным единице.
Есть один момент, о котором нельзя не упомянуть. При использовании pf сетевой
пакет, проходящий через мост, попадает под проверку фильтра дважды: при входе на
одном интерфейсе и при выходе — на другом. Поэтому при составлении правил
файрвола нужно разрешать прохождение пакетов на внешнем интерфейсе, а фильтрацию
производить только на внутреннем. Либо наоборот: фильтровать на внешнем и
разрешать все на внутреннем.
# vi /etc/pf.conf
/* Задаем черный список подсетей и адресов */
table <blacklist> { 127.0.0.0/8, 192.168.0.0/16, \
172.16.0.0/12, 0.0.0.0/8, 169.254.0.0/16, \
192.0.2.0/24, 224.0.0.0/3, 255.255.255.255/32 }
/* Производим нормализацию и дефрагментацию IPv4‑пакетов, отбрасываем пакеты с
недопустимыми комбинациями флагов (например, SYN и FIN или SYN и RST) */
scrub in
/* Разрешаем прохождение трафика на внешнем сетевом интерфейсе без ограничений
*/
pass quick on $ext_if
/* Применяем политику запрета по умолчанию */
block on $int_if
/* Блокируем и регистрируем соединения по протоколам IPv6 и IGMP, а также
широковещательные запросы и пакеты с фальсифицированным адресом источника */
block drop log quick on $int_if inet6 all
block drop log quick on $int_if inet proto igmp all
block drop in log quick on $int_if inet from <blacklist>
to any
block drop out log quick on $int_if inet from any to
<blacklist>
/* Далее идут разрешающие правила */
Кстати! Так как наш транспарентный бридж не имеет ни одного IP-адреса, нам не
удастся воспользоваться его сетевыми службами, в частности, удалено зайти на
него по telnet/ssh (что с точки зрения безопасности — огромный плюс). Для
изменения настроек нужно будет сесть непосредственно за компьютер либо, если он
работает в режиме headless (нет монитора и клавиатуры), воспользоваться
нуль-модемным кабелем и терминальной программой типа SecureCRT.
Настройка полупрозрачного моста аналогична. Просто нужно одному из сетевых
интерфейсов назначить IP-адрес. Чтобы пример сделать интереснее, объединим
проводной и беспроводной участки локальной сети. Первым делом сконфигурируем
LAN-интерфейс:
# echo "inet 192.168.1.230 255.255.255.0 NONE" > /etc/
hostname.vr0
Далее следует сгенерировать 256‑битный ключ WPA-PSK, который будет
использоваться для авторизации беспроводных клиентов на точке доступа. Формат
команды таков: «wpa-psk <ssid> <password>».
# /sbin/wpa-psk wlan mypassword
0x5f3e35[...]
В моем случае беспроводная карточка Gigabyte GN-WPKG 802.11 b/g обеспечивает
работу по спецификации 802.11g (mode 11g) на 11‑ом частотном канале (chan 11) в
режиме точки доступа (mediaopt hostap) с уникальным идентификатором сети (nwid
wlan) и поддержкой WPA/WPA2:
# vi /etc/host name.ral0
up media autoselect mode 11g mediaopt hostap \
nwid wlan chan 11 wpa wpaprotos wpa1,wpa2 \
wpaakms psk wpapsk 0x5f3e35[...]
Если по какой-то причине в /etc/hostname.ral0 ты хочешь держать не ключ, а
незашифрованный пароль, то последняя строчка конфига будет выглядеть так:
wpaakms psk wpapsk $(wpa-psk wlan mypassword)
Мы же не хотим, чтобы любой залогинившийся в систему пользователь мог узнать
наш ключ/пароль?
# chmod 600 /etc/hostname.{vr0,ral0}
Дальнейшая процедура полностью аналогична описанной выше: создаем /etc/bridgename.bridge0
(в предыдущем примере все вхождения vr1 нужно заменить на ral0) и
перезагружаемся.
Для проверки состояния помещенных в мост сетевых интерфейсов запускаем
штатную утилиту brconfig:
% brconfig bridg e0 | head -7
bridge0: flags=1041<UP,RUNNING,LINK0>
priority 32768 hellotime 2 fwddelay 15 maxage 20
holdcnt 6 proto rstp
designated: id 00:00:00:00:00:00 priority 0
ral0 flags=7<LEARNING,DISCOVER,BLOCKNONIP>
port 2 ifpriority 0 ifcost 0
vr0 flags=7<LEARNING,DISCOVER,BLOCKNONIP>
port 1 ifpriority 0 ifcost 0
Сокрушительный удар по спамерам
Почтовый сервер в режиме greylisting способен отфильтровывать до 98% спама,
при этом не затрачивая время и ресурсы на трафик и обработку «грязных» писем.
Суть идеи «серых списков» заключается в следующем. Корректно сконфигурированный
SMTP-сервер отправителя, получив определенный ответ от сервера получателя,
обязан повторить попытку доставки письма через некоторый промежуток времени
(обычно — от 5 до 60 минут). Зная это, в качестве ответа на соединение от
неизвестного почтового сервера мы можем (с помощью фейкового SMTP-демона)
возвращать не стандартное SMTP-сообщение «OK» или «Rejected», а ошибку с кодом
450, 451 или 550 («Временно не доступен»). Когда почтовый сервер отправителя
повторит доставку письма (а по RFC он обязан это сделать), мы примем к сведению,
что данный сервер в течение небольшого промежутка времени уже несколько раз
пытался отправить нам письмо, а значит, он не спамер. И тогда мы примем
корреспонденцию.
Вообще говоря, greylisting настраивается без особых проблем. Сложность
возникнет, когда ты решишь поднять защиту от спама на (полу)прозрачном мосте.
Ведь ввиду специфики сетевой модели (разные уровни OSI) пакеты, которые
форвардятся с одного интерфейса на другой, просто не дойдут до IP-стека
операционной системы. Соответственно, правила перенаправления (rdr) не будут
работать для пакетов, не адресованных бриджу. В данном случае одного редиректа
недостаточно, нужно роутить (route-to) входящие SMTP-подключения на интерфейс
обратной петли. Если перейти на язык конфигов, ларчик открывается следующим
образом:
# vi /etc/pf.conf
/* Список доверенных SMTP-серверов либо известных публичных почтовых систем,
которые не осуществляют повторную доставку письма */
table <my-white> persist file "/etc/mail/
whitelist"
/* Здесь будем хранить IP-адреса SMTP-серверов, которые прошли
greylisting-проверку */
table <spamd-white> persist
/* Если подключившийся хост не содержится в белом списке, отправляем его к spamd
*/
no rdr proto tcp from <my-white> to any
rdr pass on egress inet proto tcp from !<spamdwhite>
to any port smtp -> 127.0.0.1 port spamd
/* Из-за специфики работы моста воспользуемся ключевым словом route-to */
pass out route-to lo0 inet proto tcp from any \
to 127.0.0.1 port spamd
/* Обеспечиваем доступ к нашему почтовому серверу */
pass in log inet proto tcp from <spamd-white> \
to any port smtp keep state
Вот так на прозрачном мосте, не имеющем ни одного IP-адреса, можно поднять
надежную защиту от спама.
Мыльное шоу с переодеванием
В продолжение разговора о почте хочу поделиться еще парочкой камуфляжных
приемов. Используя средства маскировки, встроенные в почтмейстер Sendmail, можно
сделать так, что все исходящие письма будут выглядеть как отправленные с одного
компьютера. Достигается это путем включения макроса MASQUERADE_AS.
# cd /usr/share/sendmail/cf
# vi mydomain.cf
MASQUERADE_AS(mydomain.ru)dnl
FEATURE(allmasquerade)dnl
FEATURE(masquerade_envelope)dnl
EXPOSED_USER('root', 'Mailer-Daemon')dnl
Существуют разные способы почтового маскарадинга, однако директивы
allmasquerade и masquerade_envelope рекомендуется использовать вместе — тогда
все адреса в заголовках и конвертах писем будут маскироваться одинаково. Если
один домен обслуживают несколько почтовых концентраторов, то чтобы впоследствии
легче было выяснить, с какого из них получено сообщение об ошибке, имеет смысл с
помощью макроса EXPOSED_USER исключить из процесса маскировки пользователей root
и Mailer-Daemon.
Чтобы изменения вступили в силу, пересобираем mc-файл и даем указание демону
перечитать свой конфиг:
# m4 ../m4/cf.m4 mydomain.cf > /etc/mail/
sendmail.cf
# kill -HUP 'head -1 /var/run/sendmail.pid'
Теперь почтовый адрес отправителя user@host.mydomain.ru будет переписываться
на user@mydomain.ru. Но так мы только создали видимость, что почта поступает с
одного компьютера. По умолчанию Sendmail всем честно рассказывает, с какого
внутреннего IP-адреса было отправлено письмо. Это можно проверить, просто
посмотрев в любом MUA (Mail User Agent: The Bat!, Outlook, Thunderbird) на
заголовок почтового сообщения:
Received: from Garry ([192.168.1.3])
by myhost.mydomain (8.14.1/8.14.1) with
SMTP id l19FoM622652
for <user@somedomain.ru>; Fri, 9 Feb 2008
18:50:22 +0300
Чтобы скрыть эту информацию, нужно генерировать собственные заголовки:
# vi mydomain.cf
define('confRECEIVED_HEADER', '$?sfrom $g
$.$?{auth_type}(authenticated with
${auth_type})
$.by $j (Hidden)$?r with $r$.$?{daemon_
family}/${daemon_family}$. id $i$?{tls_version}
(using ${tls_version} with cipher ${cipher}
(${cipher_bits} bits) verified ${verify})$.$?u
for $u; $.$b$?g’)dnl
Прелести прозрачного проксирования
Любой современный браузер можно сконфигурировать для работы через прокси. Но
если у сервера, на котором висит Squid, изменится адрес или порт, то на всех
клиентских компьютерах придется менять настройки (а если рабочих станций
несколько сотен или тысяч?).
При использовании прозрачного проксирования все пакеты, в адресах назначения
которых содержится порт 80/tcp, автоматически перенаправляются на порт
прокси-сервера. Такой механизм работы заметно упрощает администрирование и
открывает поистине бескрайний простор для деятельности и фантазии! Проксю можно
подвесить на другой порт, перенести на другой сервер или подключить к каскаду
прокси-серверов. Контент можно проверять на вирусы (Squid + HAVP + Clamav),
www-запросы подвергать жесткой фильтрации (Squid + squidGuard), а баннеры и
всплывающие окна нещадно блокировать (Squid + Adzapper + Bfilter). Клиенты даже
не поймут, что весь www-трафик проходит сквозь кэш, фильтры и медные трубы. Для
работы в этом режиме Squid необходимо собрать с поддержкой штатного файрвола
('--enable-pftransparent'), назначить ограниченные права доступа для
псевдоустройства /dev/pf (команды «chgrp _squid /dev/pf» и «chmod g+r /dev/pf»)
и в /etc/squid/squid.conf добавить следующие записи:
# vi /etc/squid /squid .conf
/* Для Squid версии 2.4 */
http_port 127.0.0.1:3128
httpd_accel_host virtual
httpd_accel_port 80
httpd_accel_with_proxy on
httpd_accel_uses_host_header on
/* Для Squid 2.6 достаточно одной строчки */
http_port 127.0.0.1:3128 transparent
Не лишним будет настроить директивы forwarded_for и anonymize_headers, чтобы
перевести кальмара в режим работы анонимного проксика:
forwarded_for off
anonymize_headers deny From Referer Server
anonymize_headers deny User-Agent WWW-Authenticate Link
Для экономии журнального места приведу только те правила файрво ла, которые
затрагивают систему NAT и редирект http-трафика:
# vi /etc/pf.conf
/* Определяем списки, в которые заносим IP-адреса клиентов, а также
www-серверов, содержимое которых кэшировать не следует */
table <clients> persist file "/etc/clients.conf"
table <no_cache> { 192.168.1.0/24, 192.168.2.0/24 }
/* Выполняем трансляцию сетевых адресов */
nat on $ext_if inet from <clients> to any -> $ext_if
/* Заворачиваем на проксик все http-запросы, поступающие от клиентов на
внутренний сетевой интерфейс */
rdr on $int_if inet proto tcp from <clients> to \
! <no_cache> port www -> 127.0.0.1 port 3128
Шлюзование с секретом
С помощью связки pf + authpf можно контролировать доступ к службам, хостам и
закрытым сегментам сети, основываясь на правах зарегистрировавшегося по ssh
пользователя. Другими словами, в зависимости от введенных юзером логина и пароля
на шлюзе будут вступать в силу персональные правила файрвола. Разве не сказка?
Допустим, нам из дома нужно получить доступ к институтскому серверу
терминалов (192.168.1.100), расположенному за шлюзом (81.211.11.11). Настраиваем
псевдооболочку authpf (о том, как это сделать, рассказывалось в статье
«Деликатное проникновение в частную сеть», опубликованной в
февральском "Хакере")
и создаем нового пользователя rdp:
# useradd -m -c 'authpf rdp user' -g authpf -L authpf \
-s /usr/sbin/authpf rdp
# passwd rdp
# mkdir -p /etc/authpf/users/rdp
Определяем для него специальный набор правил файрвола:
# vi /etc/authpf/users /rd p/authpf.rules
/* Внешний сетевой интерфейс */
ext_if = "fxp0"
/* IP-адрес сервера терминалов, скрытого за NAT’ом */
rdp_server = "192.168.1.100"
/* Проксируем входящие RDP-соединения */
rdr on $ext_if inet proto tcp from $user_ip to
$ext_if \
port 3389 tag RDP -> $rdp_server
pass in log quick on $ext_if tagged RDP
synproxy state
Для получения доступа «извне» к серверу терминалов вводим следующую команду:
c:\putty> plink.exe -pw mypassword
rdp@81.211.11.11
Hello rdp. You are authenticated from host
"79.167.22.22"
This service is for authorised clients only.
Please play nice.
Теперь для клиента 79.167.22.22 на шлюзе 81.211.11.11 порт 3389/tcp будет
открыт до тех пор, пока пользователь rdp в окне ssh-клиента не нажмет комбинацию
<Ctrl+C>.
Все, запускаем TS Client:
c:\putty> mstsc.exe /v:81.211.11.11:3389
Расщепление пространства доменных имен
В BIND 9 появились виды (views) — мощный механизм, позволяющий хранить
несколько наборов настроек и данных в пределах одной копии демона named. На
основании списка соответствия адресов демон выясняет, какие данные нужны тому
или иному клиенту. Для примера затеним пространство имен на DNS-сервере,
получающем запросы как от внутренних узлов, так и от интернет-узлов.
# vi /var/named/etc/named.conf
/* Внутренний вид нашей зоны */
view "internal" {
/* Список адресов, определяющий, кто имеет доступ к этому виду */
match-clients { 192.168.1/24; 192.168.2/24;
};
/* Рекурсия разрешена только для внутренних клиентов */
recursion yes;
/* Полное содержимое зоны */
zone "mydomain.ru" {
type master;
file "master/db.int.mydomain.ru";
};
};
/* Вид нашей зоны, доступный внешнему миру */
view "external" {
match-clients { any; };
recursion no;
/*
Мы можем удалить лишнюю информацию из внешнего представления зоны, объявить
только общедоступные узлы либо преобразовать внутренние адреса в их видимые
извне эквиваленты */
zone "mydomain.ru" {
type master;
file "master/db.ext.mydomain.ru";
};
};
Чтобы объявить внешнему миру совсем не те зональные данные, что доступны
внутренним узлам, осталось лишь создать файлы зонных данных (db.int.mydomain.ru,
db.ext.mydomain.ru) и перезапустить демон named командой «rndc reload».
|