Защита unix сервера от подбора паролей
Ранее, я уже рассказывал о защите Unix сервера от подбора паролей ( bruteforce ). Речь шла об SSH и программе sshguard, фиксирующей неудачные попытки входа в систему по данному протоколу. Здесь хотелось-бы рассказать о более комплексном решении, для защиты практически любого сервиса - программе Fail2ban.
Собственно fail2ban, это небольшой набор скриптов, написанных на python. Принцип работы прост, отслеживать изменения в лог файлах различных сервисов и по определенным сигнатурам, выполнять определенные действия. Для поиска характерных признаков подбора пароля, используются регулярные выражения в файлах фильтров. Для выполнения действий используются action файлы.
На Linux с настройкой данной программы вообще никаких трудностей не возникает, на сервере FreeBSD всплыли некоторые специфические моменты.
Итак, операционная система FreeBSD 8.2 amd64, настраивать будем защиту sshd и фтп сервера proftpd. Для работы естественно потребуется включенный фаервол, во FreeBSD штатным является ipfw.
Установка fail2ban
freebsd82 /# cd /usr/ports/security/py-fail2ban freebsd82 /usr/ports/security/py-fail2ban# make install cleanПосле установки, которая длится меньше минуты, идем по адресу /usr/local/etc/fail2ban, наблюдаем следующую структуру каталога:
- папка action.d - содержит файлы действий
- папка filter.d - файлы фильтров
- файл fail2ban.conf - основной файл конфигурации
- файл jail.conf - файл настройки защиты конкретных сервисов
Настройка fail2ban
В первую очередь копируем файл jail.conf в файл с именем jail.local, что-бы файл по умолчанию у нас оставался нетронутым, все настройки лучше делать в jail.local.freebsd82 /# cp /usr/local/etc/fail2ban/jail.conf /usr/local/etc/fail2ban/jail.localДля начала заглянем в основной файл конфигурации:
[Definition] loglevel = 4 # На время настройки я ставлю 4, максимально подробный уровень логгирования logtarget = /var/log/fail2ban/fail2ban.log # лог файл fail2ban, имейте в виду, если вы указываете свое расположение файла логов, как я в данном случае, нужно что-бы директория, где он будет расположен, была доступна на запись только пользователю root, иначе fail2ban не запустится. socket = /var/run/fail2ban/fail2ban.sock # файл сокета для связи клиентской и серверной части программы, оставляем по умолчаниюТут я изменил только расположение файла логов, как мне удобней и поднял уровень логгирования на время отладки. Далее настроим взаимодействие с фаерволом ipfw. Идем в папку action.d, как видите фаерволы тут представлены в ассортименте, поскольку мы используем FreeBSD с ipfw, нас интересует файл bsd-ipfw.conf, вообще можно создать и свой с произвольным именем, главное не забыть это учесть при дальнейшей настройке в jail.local. По аналогии с файлом jail.conf, копируем его с именем bsd-ipfw.local. Здесь можно оставить по умолчанию но я предпочитаю дописать в actionstop, команду для обнуления таблицы с забаненными IP адресами, при выключении fail2ban. Если сравнить этот файл, например с iptables.conf ( для стандартного фаервола в linux дистрибутивах — iptables ), можно заметить некоторые отличия, поскольку данные фаерволы устроены по разному и принципы организации правил фильтрации у них тоже разные. Файл после моей правки выглядит так:
[Definition] actionstart = # команда выполняемая при старте fail2ban actionstop = pfw table 1 flush # команда выполняемая при остановке, обнуляем блокирующую таблицу actioncheck = # команда проверки actionban = ipfw table 1 addвсе остальное я закомментировал Что-бы данный вариант работал, нужно руками добавить в ipfw правило, блокирующее все IP адреса, находящиеся в таблице table 1:# забанить IP адрес, при срабатывании, IP добавляется в таблицу 1 ipfw actionunban = ipfw table 1 delete # обратное действие, удалить IP из таблицы
freebsd82 /root# ipfw add 100 deny all from table\(1\) to me # экранируем скобки и не ставим пробелов freebsd82 /root# ipfw show 00100 0 0 deny ip from table(1) to me # правило которые мы только что добавили 65535 65255 15896158 allow ip from any to anyЕсть еще один вариант, можно поступить например так: в actionstart прописать команду автоматического создания правила:
actionstart = ipfw add 100 deny all from table\(1\) to meа в actionstop, вдобавок к обнулению таблицы, дописать еще и команду удаления, например так:
actionstop = ipfw -q delete `ipfw -q show | grep "table(1)" | awk '{ print $1;}'` ipfw table 1 flushобе команды сработают по очереди. Но у ipfw есть такая особенность, в него можно добавлять кучу одинаковых правил с одним и тем-же номером, без каких-либо сообщений об ошибке. Срабатывать при этом будет только первое из них. Получится следующая ситуация, мы прописали команду в actionstart, как я привел парой строк выше, а мониторить собираемся например 3 сервиса, sshd, proftpd и dovecot, значит при инициализации fail2ban, файл bsd-ipfw.local, будет прочитан 3 раза, соответственно команда:
ipfw add 100 deny all from table\(1\) to meтоже будет выполнена трижды, и соответственно у нас в фаерволе появится 3 одинаковых правила, и 2 из них не будут выполнять никаких функций, лишь мозолить глаза и сбивать с толку:
freebsd82 /root# ipfw show 00100 9 522 deny ip from table(1) to me # 1 работающее правило 00100 0 0 deny ip from table(1) to me # 2 00100 0 0 deny ip from table(1) to me # 3 65535 67537 16429215 allow ip from any to anyесли вас это не смущает, можете сделать так, никаких негативных моментов это не несет, не считая конечно некоторой путаницы с правилами. В общем я предпочитаю первый вариант, с ручным созданием основного правила. Далее перейдем в каталог filter.d. Тут у нас лежат фильтры, которые по регулярному выражению ищут определенные строки в лог файлах. Нас интересуют sshd.conf и proftpd.conf, как и ранее копируем их в sshd.local и proftpd.local соответственно. В файле sshd.local, я все оставил как есть. В proftpd.local пришлось внести некоторые незначительные изменения. Вот содержимое измененного файла:
[Definition]
failregex = \(\S+\[<HOST>\]\)[: -]+ USER \S+: no such user found from \S+ \[\S+\] to \S+:\S+.*$
\(\S+\[<HOST>\]\)[: -]+ USER \S+ \(Login failed\): Incorrect password\..*$
\(\S+\[<HOST>\]\)[: -]+ SECURITY VIOLATION: \S+ login attempted\..*$
\(\S+\[<HOST>\]\)[: -]+ Maximum login attempts \(\d+\) exceeded.*$
ignoreregex = # Сюда можно вписать регулярные выражения строк, которые нужно игнорировать
Дело в том, что регулярные выражения прописанные тут по умолчанию, ничего не находили в лог файле. Проверить работоспособность того или иного фильтра с регулярными выражениями можно с помощью скрипта fail2ban-regex, идущего в поставке fail2ban. Например проверяем фильтр proftpd.local, натравливая его на лог файл авторизаций:
freebsd82 /root# fail2ban-regex /var/log/auth.log /usr/local/etc/fail2ban/filter.d/proftpd.localДанная команда выведет полную статистику, сколько строк из лог файла попадают под то или иное регулярное выражение, в отладке очень полезная штука. Я никогда не сталкивался с python, тем более с его регулярными выражениями, хотя они и похожи на Perl, тем не менее различия есть. Попробовав разные вариант, дописал в конец каждого выражения ".*", после чего прогнал проверку через fail2ban-regex, все что нужно, находится. С фильтрами вроде закончили, вернемся к файлу jail.local и приведем его к следующему виду:
[DEFAULT] [ssh-ipfw] enabled = true # включить мониторинг ignoreip = 127.0.0.1 192.168.50.200 # IP адреса которые нужно игнорировать filter = sshd # какой файл фильтра использовать, то есть по сути это название файла в папке filter.d, только без расширения action = bsd-ipfw # какой действие использовать, название аналогично фильтру logpath = /var/log/auth.log # анализируемый лог файл bantime = 60 # продолжительность блокировки, подбираем на свое усмотрение maxretry = 2 # количество неудачных авторизаций с IP, значение подбирается по ситуации/нагрузке на сервис в рамках данной машины findtime = 600 # время, в течении которого нужно фиксировать maxretry, то есть у нас получается 2 ошибки в течении 10 минут backend = poller # способ получения информации о модификации лог файла, можно поставить auto или gamin [proftpd-ipfw] # тут все аналогично enabled = true filter = proftpd action = bsd-ipfw logpath = /var/log/auth.log ignoreip = 127.0.0.1 192.168.50.200 bantime = 60 maxretry = 2 findtime = 600 backend = pollerВ добавок к уже прописанному действию, можно добавить уведомление по почте на нужный адрес, например так:
action = bsd-ipfw mail-whois[name=ProFTPD, dest=admin@domain.com]и отредактировать соответствующий файл в директории action.d, в данном случае mail-whois.local, там все довольно просто:
[Definition] actionstart = actionstop = actioncheck = actionban = printf %%b "Hi,\n The IPНа этом с настройками вроде закончили, можно запускать и проверять.has just been banned by Fail2Ban after attempts against .\n\n Here are more information about :\n `whois `\n Regards,\n Fail2Ban"|mail -s "[Fail2Ban] : banned " actionunban = [Init] name = default dest = admin@domain.com
Запуск и проверка fail2ban
Мне удобней просматривать лог в режиме realtime, в отдельном окне консоли или в отдельном окне, оконного менеджера для терминала — screen, делаем:freebsd82 /# tail -f /var/log/fail2ban/fail2ban.logтеперь в этом окне у нас будут вылезать на экран все строки попадающие в лог, по мере их поступления. Если запуск прошел успешно, проверяем блокировку. Я поступаю просто, со стороннего сервера запускаю:
debian:/# ssh 192.168.50.200и жму на ентер, или ввожу значения от балды и жму на ентер), наблюдая за логом fail2ban, при loglevel = 4, там буду фиксироваться все изменения наблюдаемого файла, тек-же найденные IP адреса и действия производимые с ними. В течении нескольких секунд после достижения порога неудачных логинов к ssh, IP адрес блокируется путем добавления его в таблицу table 1 фаервола, по истечении времени блокировки, адрес будет автоматически удален. Аналогично проверяется и ftp. На Linux все настраивается аналогично, разве что может чуть попроще, с использованием соответствующих фаерволу, action файлов. Вроде ничего не упустил.
Комментарии
Здравствуйте, хорошая статья, не подскажете как в случае PF все это делается?
сам не пробовал, но для PF там тоже action файл есть, думаю подкорректировать не проблема
у вас ошибка в конфиге асtion'a там вы применяете то PF то IPFW....
У меня вот ваши правила для proftpd не сработали, пришлось с помощью отладчика сделать свои:
failregex = \(.+\[::.+:\]\).+ USER \S+: no such user found from .+\[.+\] to .+$
\(.+\[::.+:\]\).+ USER .+ \(Login failed\): Incorrect password\. $
\(.+\[::.+:\]\).+ SECURITY VIOLATION: \S+ login attempted\. $
\(.+\[::.+:\]\).+ Maximum login attempts \(\d+\) exceeded $
Логи такого типа:
Jul 29 09:42:52 host proftpd[10175]: *** (::ffff:***.249.0.40[::ffff:46.249.0.40]) - USER admin: no such user found from ::ffff:46.249.0.40 [::ffff:***.249.0.40] to ::ffff:***.162.182.163:21
Jul 29 09:42:57 host proftpd[10180]: *** (::ffff:***.249.0.40[::ffff:46.249.0.40]) - SECURITY VIOLATION: root login attempted.
Jul 29 09:43:09 host proftpd[10189]: *** (::ffff:***.249.0.40[::ffff:46.249.0.40]) - USER advi-user (Login failed): Incorrect password.
Может кому пригодистся )
спасибо, честно говоря так и не понял почуму у меня дэфолтовые регекспы не матчились)
на фряхе делали, или линукс?
на фряхе, есть веб сервер созданный при помощи чистой фряхи и isp manager. Вот и решил что надо защититься от перебора паролей по ssh и фтп. Вот думаю что неплохо было бы попробовать прикрутить fail2ban к авторизации isp manager.
хорошая идея
даже правильнее будет вот так:
failregex = \(.+\[::.+:<HOST>\]\).+ USER \S+: no such user found from .+\[.+\] to .+$
\(.+\[::.+:<HOST>\]\).+ USER .+ \(Login failed\): Incorrect password\. $
\(.+\[::.+:<HOST>\]\).+ SECURITY VIOLATION: \S+ login attempted\. $
\(.+\[::.+:<HOST>\]\).+ Maximum login attempts \(\d+\) exceeded $
fail2ban без записи <HOST> - неработает
о как обратил внимание в коментах режется запись "<"HOST">", её надо вводить без кавычек в failregex = \(.+\[::.+:"<"HOST">"\]\)
да, непорядок, поправлю )
спасибо
Ребят, прошу помощи!
Проблема заключается в следующем:
при исполнении fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/profttd.conf на экран выводится:
...
No 'host' group in '/etc/fail2ban/filter.d/profttd.conf'
Cannot remove regular expression. Index 0 is not valid
No 'host' group in '/etc/fail2ban/filter.d/profttd.conf'
Cannot remove regular expression. Index 0 is not valid
Results
=======
Failregex
|- Regular expressions:
| [1] /etc/fail2ban/filter.d/profttd.conf
|
`- Number of matches:
[1] 0 match(es)
Ignoreregex
|- Regular expressions:
|
`- Number of matches:
Summary
=======
Sorry, no match
Look at the above section 'Running tests' which could contain important
information.
Вырезка из proftpd.conf:
....
failregex = \(.+\[::.+:\]\).+ USER \S+: no such user found from .+\[.+\] to .+$
\(.+\[::.+:\]\).+ USER .+ \(Login failed\): Incorrect password\. $
\(.+\[::.+:\]\).+ SECURITY VIOLATION: \S+ login attempted\. $
\(.+\[::.+:\]\).+ Maximum login attempts \(\d+\) exceeded $
...
Заранее благодарен
ты чем в коменты смотрел ? ты видел что я писал что здесь форма отправки коментов зарезала запись HOST ?
поправил <HOST> в тексте статьи
все руки не дойдут вылечить этот фильтр
Спасибо!
Настроил. По простому. Только не понял один ньюанс:
findtime = 600 Это время через которое утилита проверяет лог например постфикса?
Или она проверяет чаще. Если поставлю: findtime = 1800
то тогда злодей успеет напихать мне попыток очень много. за 30 минут
а fail2ban проверив этот отрезок и сравнив его с maxretry = 2
запоздало всетаки забанит вредителя. Может я заблуждаюсь.
немного не так, это время в течении которого учитываются неудачные попытки, если буквально, "искать 2 неудачных попытки логина, произошедшие в ПОСЛЕДНИЕ 600 секунд", само по себе, текущее время никакой роли не играет
ну и естественно вы можете выставить свои временнЫе интервалы и кол-во попыток.. исходя из своей практики и уровня паранойи :)
Ну вроде успокоили
Спасибо.
А то было сомнение. Значит fail2ban работает как бы в режиме tail -f loggmail
Не цепляя просто временные отрезки из лога (заданые findtime = )
Если 2 попытки произойдут в первые 10 сек (при findtime = 1800) то бан сработает сразу.
Я эту утилиту приспособил для постфикса. Бомбят знаете ли по авторизации sasl и еще
с ботов сыпется спам. Обработка писем занимает дольше времени чем например
авторизация, поэтому пришлось увеличить findtime =.
все верно, грубо оворя, софтина парсит последнее изменение логфайла +анализирует времееннЫе метки в самОм логе, на основнии этого делает выводы, и если что, тут-же добавляет правило на фаер.. этого вполне достаточно, что-бы остановить подбор пароля, при желании конечно можно поставить и более длинный бан, но смысла нет, потому что IP постоянно меняются
Понятно. Тогда последний вопрос. Если Вам не трудно.
Нужно ли в jail.conf отключать ## настройки по умолчанию?
Понаблюдав за логом утилиты при запуске пишет- параметры которые устанавливаются с секций конфа, потом дефолтные
устанавливаются. То есть как бы перекрываются. В логе не указывается к каким фильтрам они применяются.
Отправить комментарий