Защищаем FreeBSD (defender +1)

Автор: Raven2000.


Как и любую другую систему FreeBSD нужно так же защищать от посягательств на нее. Она
не так уж защищена, как много людей о ней думают и ее можно так же сломать и крякнуть,
как и тот же Windows просто FreeBSD мало распространена и мало есть спецов, которые с
ней работают, а тем более которые знают ее в совершенстве, так что чем больше спецов
ее ломают тем больше дыр и руткитов будет открыто и использовано.

Да и на будущее я не претендую на аса в построение защиты и т.д. т.п. а
лишь попробую (для себя, чтобы не забыть :) и друзей) описать некоторые моменты
защиты, а остальное будет дополняться по мере просьб и необходимости.
Т.к. невозможно охватить все, да и абсолютно защищенный сервер, которого невозможно
сломать это как вечный двигатель в теории есть но на практике, увы :).
Хотя я знаю такой - это тот, который на глубине 100 метров под землей в фольге
и с вырубленным питанием :) Статья будет дополнятся и изменятся по ходу обсуждений.
Ну ладно, попробуем немного защитится от спецов :)

Защиту разделим по двум видам:
I) Защита от внешних атак
II) Защита от внутренних атак

Атака изнутри – атакующий является легальным авторизированным пользователем
с этим типом атак бывает сложнее т.к. у пользователя есть не только данные
о системе, но и валидный юзер.
Внешняя атака – Все, что на передовой.

Теперь определим фронт защиты:

I) Атака извне:
1.1) Apache - http.conf + mod_security
1.2) PHP - php.ini + mod_security + отключение опасных функций + Ограничения ресурсов
1.3) FTP – Разделение привилегий + chroot + квоты + отдельный HDD
1.4) Firewall – грамотно настроенный фаервол
1.5) Сhroot

II) Атака внутри:
2.1) Ограничения ресурсов - /etc/login.conf + /etc/sysctl.conf
2.2) Разделение привилегий - /etc/sysctl.conf + chmod + структура папок
2.3) Логии (logcheck)
2.4) top/ps

III) Общие меры
3.1) Разбор fstab
3.2) Доступ к серверу
3.3) DNS – chroot + noroot

Теперь пройдем по пунктам (некоторые пункты будут вкратце описаны т.к. обший принцип
защиты пересекается с другими пунктами) как и чем можно защитить и ограничить:

I) Прикрытие внешних дыр.

1.1) Apache + виртуальные хосты + mod_security
Прикроем дырки этого сервиса для начала нам необходимо задать ограничения
в конфиге для каждого вхоста. Добавляем следующие параметры:

<IfModule mod_php4.c>
# Включаем Safe mode
php_admin_flag safe_mode on
php_admin_flag safe_mode_gid on
php_admin_value open_basedir /home/domain.ru
# Папка, выше которой скрипт не может видеть
php_admin_value safe_mode_exec_dir /home/domain.ru
# Temp диры юзера
php_admin_value upload_tmp_dir /home/domain.ru/tmp
# Не начинать PHP сессию автоматически
php_admin_flag session.auto_start off
# Где сохранять файлы сессий
php_admin_value session.save_path /home/domain.ru/tmp
</IfModule>

Как известно, немалая часть взломов (SQL Injection, XSS атаки, инклюдинг) происходит
по сути посредством хитрого HTTP запроса. Логично предположить, что эти самые
запросы неплохо было бы фильтровать. Решение проблемы существует в виде модуля к
Апачу, и называется оно mod_security. Ставим:

# cd /usr/ports/www/mod_security/ && make install clean

После установки – идем конфигурировать. Открываем любой конфиг виртуального хоста,
например 001.admin.hosting.ru, над которым мы уже экспериментировали. Все значения
надо вводить между тегами <Virtualhost *:80> и </Virtualhost>.

# Включаем mod_security
SecFilterEngine On
# Проверяем запросы
SecFilterScanPOST On
# Проверяем ответы
SecFilterScanOutput On
# Проверяем, правильно ли закодирован URL
SecFilterCheckURLEncoding On
# Включаем этот параметр, если сайт в Unicode
SecFilterCheckUnicodeEncoding Off
# Задаем диапазон байтов
SecFilterForceByteRange 1 255
# Сохраняем в лог только срабатывания механизма
SecAuditEngine RelevantOnly
# Где живет лог :)
SecAuditLog logs/audit_log
# Возвращаем ошибку 500 при срабатывании
SecFilterDefaultAction "deny,log,status:500"
# Перекрываем dots-bug
SecFilter "../"
# Не забываем про XSS
SecFilter "<(.| )+>"
# SQL injection, куда же без него :)
SecFilter "<[[:space:]]*script"
SecFilter "delete[[:space:]]+from"
SecFilter "insert[[:space:]]+into"
SecFilter "select.+from"
# Перекрываем возможность передачи переменных PHP
SecFilterSelective ARG_b2inc "!^$"
# Исключаем возможность раскрытия пути
SecFilterSelective OUTPUT "Fatal error:"

Для и для apache 1.x в httpd.conf закоментите:

#SecFilterScanOutput
#OUTPUT
#OUTPUT_STATUS

У этого модуля – на редкость удачная дефолтная конфигурация. К ней мало, что можно
добавить, так как большинство настроек – специфичны. Общий принцип составления
правил мы рассмотрели, а остальное можно добавить по своему усмотрению.

1.2) PHP
В дополнение смотри пункт – 2.1
Рассмотрим самое уязвимое место хостинговой системы – выполняемые файлы, в частности,
PHP скрипты. Открываем конфиг PHP:

# ee /usr/local/etc/php.ini

Меняем следующие параметры:

magic_quotes_gpc = Off			    # Экранирование спецсимволов
disable_functions = system, exec, passthru # Выключаем опасные функции:

Выключить эти функции очень важно. Хоть они и недоступны при включенном safe mode,
пользователь может без труда провести успешную атаку, указав в файле .htaccess:
php_flag safe_mode off

1.3) FTP
Настройка Proftpd установите далее по разделение привилегий смотрим -2.1
в котором я указал то что вам нужно, а по Chroot см раздел 1.5 Желательно ftp
ставить на отдельный HDD чтобы непроизошло переполнения раздела и все
шайтан майфун :) а если у вас он на /etc или /var находился все хана логам и тд :)

1.4) IPFW - штатный файрволл FreeBSD

1.5) Chroot
Chroot  - песочница это конечно с одной стороны хорошо с другой – потеря
производительности, для некоторых программ лишний дополнительный
модуль + конфиг к нему. Я считаю грамотный chmod дает тот же результат , но без
заморочек и потерь ресурсов. В основном к chroot прибегают, когда нужно обезопасить
сервис, который не совсем безопасный как например BIND(о нем ниже).
Jail - мы не будем это рассматривать ось внутри оси довольно заморочено и плохо
документировано, а если все вхосты придется загонять в jail то мало непокажется.
Я пока небуду jail рассматривать :)

II) Настраиваем тыл внутренние защитные меры.

2.1) Ограничения ресурсов
Бывает так кроме основного действия PHP скрипта функция N зацикливается, попутно
вычисляя некое сложное действие. Как результат – высокая загрузка процессора.
Это очень типичная ситуация для хостинга. Чтобы предотвратить подобные ненамеренные
(и намеренные) атаки, необходимо ограничивать юзера в плане ресурсов. У *BSD для
таких целей существует система профилей пользователей. Это значит, что мы можем
легко ограничить ресурсы каждого пользователя в отдельности.
Открываем /etc/login.conf и добавляем:

# Имя профиля
hosting:
:copyright=/etc/COPYRIGHT:
:welcome=/etc/motd:
:setenv=MAIL=/var/mail/$,BLOCKSIZE=K:
:path=~/bin /bin /usr/bin /usr/local/bin:
:manpath=/usr/share/man /usr/local/man:
:nologin=/var/run/nologin:
# Мах время использования процессора
:cputime=1h30m:
# Мах кол-во памяти, выделяемой программе под данные
# Сам код программы и стэк не учитываются
:datasize=10M:
# Сколько выделяем для стека программы
:stacksize=3M:
# Мах размер физической памяти, выделяемой процессу
:memoryuse=16M:
# Мах размер файла
:filesize=50M:
# Мах размер core файлов
:coredumpsize=1M:
# Сколько файлов может открывать каждый процесс
:openfiles=128:
# Сколько процессов может запускать пользователь
:maxproc=64:
# Пускать юзера в систему только если его домашняя дира существует и доступна юзеру
:requirehome:true
# Время устаревания пароля
:passwordtime=90d:
# Остальное берем из профиля default
:tc=default:

Здесь я указал лишь основные параметры.
Список всех параметров и их описание можно найти в Handbook.
Теперь перейдем к настройке операционки. Открываем /etc/sysctl.conf и пишем туда
следующее:

# Запрещает юзерам видеть процессы соседа&root
security.bsd.see_other_uids=0
# Запрещает видеть групповые процессы
security.bsd.see_other_gids=0
# Пускаем запросы на закрытые порты в черные дыры
net.inet.tcp.blackhole=2
net.inet.udp.blackhole=1
# Указываем размер очереди сокета
kern.ipc.somaxconn=1024
# Отрубаем ip-редиректы
net.inet.icmp.drop_redirect=1
net.inet.icmp.log_redirect=1
net.inet.ip.redirect=0

# Назначаем размеры буфера для TCP-подключений. Если на сервер ожидается большая
# нагрузка, и у него много памяти – лучше поставить 65535. Значение выше 65535
# не рекомендуется.
net.inet.tcp.sendspace=32768
net.inet.tcp.recvspace=32768
# Обновляем ARP-таблицу каждые 20 минут
net.link.ether.inet.max_age=1200
# Запрещаем отвечать на все лишние запросы.
net.inet.icmp.maskrepl=0
net.inet.ip.sourceroute=0
net.inet.ip.accept_sourceroute=0
net.inet.icmp.bmcastecho=0

Здесь указаны не все параметры sysctl остальные смотримMAN SYSCTL(8)
Есть статья Некоторые опции sysctl но она еще не совсем дописана (просьба просить lissyara чтобы доконца перевел ;)).
Многие параметры для sysctl можно изменять и динамически:

sysctl <параметр>=<значение>

Например:

sysctl kern.maxprocperuid=1000

Должно быть похоже на

# sysctl kern.maxprocperuid=1000
kern.maxprocperuid: 3546 -> 1000

Теперь необходимо продублировать часть настроек в /etc/rc.conf:
Дублируем настройки sysctl

icmp_drop_redirect="YES"
icmp_log_redirect="YES"
icmp_bmcastecho="NO"
tcp_drop_synfin="YES"


2.3) Логи
Очень важным аспектом системного администрирования является слежение за сервера.
Но ковырять логии самому заморочено тогда для ленивых  существует отличная утилита
logcheck ее и поставим.

# cd /usr/ports/security/logcheck && make install clean

Утилита написана на sh скриптах, и занимает всего 29 Кб в архиве. После установки
в /usr/local/etc у вас появятся четыре конфига: переименуй их,
убрав из названия файла «sample»:

logcheck.hacking – о каких странностях сообщать;
logcheck.violations – о каких попытках взлома сообщать;
logcheck.ignore – какие странности игнорировать;
logcheck.violations.ignore – какие попытки взлома игнорировать.

В целом и общем, первый файл от второго ничем не отличается, равно как и третий
от четвертого :).Просто разработчики скрипта решили разнести сообщения о подозрительной
активности и сообщения о явной атаке в разные конфиги.

Запускаем скрипт по крону, хотя бы раз в сутки. Дописываем в cron:

0 4 * * * /bin/sh /usr/local/etc/logcheck.sh

При большой активности хостящихся сайтов, логи веб-сервера начнут
занимать немало места. И в то же время их надо сохранять.
Можно использовать утилиту logrotate

# /usr/ports/sysutils/logrotate && make install clean


III) Общие меры

3.1) HDD
Сделаем в fstab некоторые изменения для предотвращения нехороших действий.
Укажем где и что можно и нельзя делать системе.


/dev/ad4s3b none swap sw 0 0
/dev/ad4s3a / ufs rw 1 1
/dev/ad4s3e /tmp ufs rw,noexec 2 2
/dev/ad4s3f /usr ufs rw 2 2
/dev/ad4s3f /usr/home ufs rw,nosuid,nodev 2 2
/dev/ad4s3d /var ufs rw,nodev 2 2

noexec – эта опция дает понять что на данном разделе запрещено запускать что
либо даже правах на файл chmod 777 (Я знаю что некоторые защищенные сервера ломали
именно через /tmp :) в последствии админы советовали прикрывать эту дыру.
И незабываем, что в /tmp может писать почти любой сервис в системе)

nosuid – при этом значении система игнорирует suid-биты. Юзер не сможет сделать
#su и подняться до рута, даже если он знает его пароль рута и находится в группе
wheel (но необходимо понять что нужным юзверям которым нужно #su домашняя директория
будет /usr, а тем кого нужно ограничит директория будет /usr/home)

nodev – запрещаем созданиесуществование в данном разделе специальных устройств.

3.2) Доступ
Доступ к серверу следует ограничить. Т.е. серверы убрать в недоступное простым
смертным людям и закрыть на ключ. В дополнение не забываем, снять с них все причиндалы
мониторы клавы мышки и т.д. Для чего это должно быть понятно, например если я вижу
общедоступный физически сервер FreeBSD я тут же по любопытности хочу в него залезть
и поковыряться в нем. Но вы скажете, а как же пароль root и т.д. то слушаем дальше,
если вы забыли чужой пароль :) а так бывает то делаем так:

А) Загружаемся в однопользовательском режиме , для этого в приглашении загрузчика
введите boot –s
Б) Смонтируйте командой mount –u / корневой раздел в режим чтения-записи.
Затем с помощью mount –a примонтируем все что есть (т.е. только что указанно
в fstab без опции noauto)
B) Теперь меняйте пароль рута. :)

Чтобы люди не cмогли зайти без пароля рута в однопользовательском режиме делаем так:

# ee /etc/ttys

Измените в строчке console пункт secure на insecure. Если вы сделаете это,
FreeBSD даже при загрузке в однопользовательском режиме будет запрашивать пароль root.
Будьте осторожны при изменении этого значения на insecure. Если вы забудете пароль
root, загрузка в однопользовательский режим сильно усложнится.
Это все еще возможно, но несколько более сложно.

# name  getty                           type    status          comments
#
# If console is marked "insecure", then init will ask for the root password
# when going to single-user mode.
console none unknown off insecure


3.3) DNS
Засунем DNS в песочницу

# named –u 53 –t /var/named

-u – значение UID присваемое процессу named
-t – указывает корневой каталог для демона
Незабываем, что корневой каталог недолжен, быть пустым, он должен содержать все файлы
необходимые для нормальной работы демона. Если named скомпилирован так чтобы
библиотеки компоновались статически и не нужно было думать что ему надо еще в корневую
положить чтобы он запустился :) Так же некоторые советуют в конфиге DNS убрать строчку
об версии демона дескать оно сможет помочь атакующему и т.д. я не считаю это критически
она может подсказкой и самому админу.

Литература:
1) Unix руководство системного администратора (3 изд.)
2) Хакер спец 07/68/июль/2006
3) Жизнь :)

Статья дорабатывается все пожеланиядополнения на сюда.



размещено: 2007-05-13,
последнее обновление: 2007-05-22,
автор: Raven2000