Fail2ban [incremental]: Лучше, быстрее, надежнее

    fail2ban image
    Про fail2ban написано уже много, в том числе и на хабре. Эта статья немного о другом — как сделать защиту им еще надежнее и о еще пока неизвестных в широких кругах новых функциях fail2ban. Добавлю сразу — речь пойдет пока про development branch, хотя уже долго проверенный в бою.

    Краткое вступление


    В большинстве своем fail2ban устанавливается из дистрибутива (как правило это какая-нибудь стабильная старая версия) и настраивается по манам из интернета за несколько минут. Затем годами работает, без вмешательства админа. Нередко даже логи, за которыми вроде как следит fail2ban, не просматриваются.
    Так вот, сподвигнуть на написание этого поста меня заставил случай, произошедший с одним сервером моего хорошего знакомого. Классика жанра — пришла абуза, за ней вторая и пошло поехало. Хорошо еще злоумышленник попался ленивый — логи не потер, да и повезло еще крупно, что logrotate был настроен, чтобы хранить логи месяцами.
    Оказалось все довольно банально, подобрали пароль к его админской почте, который по совместительству был паролем для ssh (естественно без ключа). Не рут, но судоер, со всеми вытекающими. Первый его вопрос был: как подобрали — у меня же fail2ban там. И вот здесь как раз засада: не все представляют себе, что подбором паролей сегодня занимаются уже не отдельные компьютеры, а целые бот-сети, кстати поумневшие донельзя. Так вот по логам выяснили, что тут как раз такой случай: перебирала бот-сеть, причем на практике выяснившая его настройки в fail2ban (maxRetry=5, findTime=600 и banTime=600). Т.е. чтобы избежать бана, сеть делала 4 попытки в течении 10 минут с каждого IP. На минуточку в сети порядка 10 тысяч уникальных IP = что-то более 5 с половиной миллионов паролей в сутки.
    Кроме того его почтовик делал большую глупость — а именно паузу до 10 секунд, при логине с неправильным именем. Т.е. выяснить, что некоторые имена, в том числе admin, реально имеются, этой сетке не составило труда. Далее шел целенаправленный перебор только паролей для имеющихся имен.
    Подробнее на «ремонте» останавливаться не буду — это история долгая, и вообще тема для отдельной статьи. Скажу только, что все почистили и все разрешилось малой кровью, да и отделался он практически «легким» испугом.

    Так вот, мысль написать статью возникла после того, как мне (частично заслужено) было высказано: «Так ты про такое знал и ничего не сказал, не предупредил. Да еще и решение есть и не поделился. Ну и сволочь ты». Короче, посему посту — быть.

    Мой fail2ban


    К безопасности «своих» серверов я отношусь чрезвычайно серьезно. Кроме того же fail2ban, всегда кастомного донельзя, у меня там и мониторинг и еще куча всего. Меня просто реально бесит, что из-за бестолковой серой массы, позволяющей брать под контроль бот-сетей свое железо, приходится убивать уйму времени на защиту (и постоянное сопровождение и контроль ее в дальнейшем). Кстати, чтобы минимизировать этот контроль, я и участвую активно в разработке и fail2ban, да и других проектов от безопасности.

    Так вот, моя последняя расширенная версия [sebres:ban-time-incr], позволяет вывести этот назойливый зоопарк раз и навсегда (ну или пока они снова не приспособятся). Это фишка довольно часто обсуждалась всем коммюнити, но как-то руки не доходили. У меня оно жило в виде отдельных скриптов и каких-то кастомных изменений, пока не оформилось в готовый функционал.

    Если коротко, то система, запоминая плохие IP адреса, позволяет каждый раз динамически (экспоненциально) увеличивать время блокировки (banTime) в зависимости от количества предыдущих запретов (banCount). При этом также каждый раз уменьшая количество (maxRetry) возможных провальных попыток (failure) до следующего бана. Наглядно это можно увидеть на следующем примере:
    [Click to view LOG]
    2014-09-23 20:05:31,146 fail2ban.observer [named-refused] Increase Ban    XXX.XXX.XX.XXX (10 # 5 days, 8:04:55 -> 2014-09-29 04:10:24)
    2014-09-23 20:05:31,120 fail2ban.actions  [named-refused] Ban     XXX.XXX.XX.XXX (_ # 0:15:00 -> 2014-09-23 20:20:29)
    2014-09-23 15:30:32,625 fail2ban.actions  [named-refused] Unban   XXX.XXX.XX.XXX
    2014-09-20 23:24:14,620 fail2ban.observer [named-refused] Increase Ban    XXX.XXX.XX.XXX (9 # 2 days, 16:06:18 -> 2014-09-23 15:30:31)
    2014-09-20 23:24:14,569 fail2ban.actions  [named-refused] Ban     XXX.XXX.XX.XXX (_ # 0:15:00 -> 2014-09-20 23:39:13)
    2014-09-20 21:10:36,708 fail2ban.actions  [named-refused] Unban   XXX.XXX.XX.XXX
    2014-09-19 13:03:03,377 fail2ban.observer [named-refused] Increase Ban    XXX.XXX.XX.XXX (8 # 1 day, 8:07:34 -> 2014-09-20 21:10:36)
    2014-09-19 13:03:03,361 fail2ban.actions  [named-refused] Ban     XXX.XXX.XX.XXX (_ # 0:15:00 -> 2014-09-19 13:18:02)
    2014-09-19 12:38:17,743 fail2ban.actions  [named-refused] Unban   XXX.XXX.XX.XXX
    2014-09-18 20:13:23,647 fail2ban.observer [named-refused] Increase Ban    XXX.XXX.XX.XXX (7 # 16:24:55 -> 2014-09-19 12:38:17)
    2014-09-18 20:13:23,620 fail2ban.actions  [named-refused] Ban     XXX.XXX.XX.XXX (_ # 0:15:00 -> 2014-09-18 20:28:22)
    2014-09-18 20:07:06,053 fail2ban.actions  [named-refused] Unban   XXX.XXX.XX.XXX
    2014-09-18 12:03:53,282 fail2ban.observer [named-refused] Increase Ban    XXX.XXX.XX.XXX (6 # 8:03:14 -> 2014-09-18 20:07:05)
    2014-09-18 12:03:53,266 fail2ban.actions  [named-refused] Ban     XXX.XXX.XX.XXX (_ # 0:15:00 -> 2014-09-18 12:18:51)
    2014-09-18 11:22:40,704 fail2ban.actions  [named-refused] Unban   XXX.XXX.XX.XXX
    2014-09-18 07:11:12,200 fail2ban.observer [named-refused] Increase Ban    XXX.XXX.XX.XXX (5 # 4:09:43 -> 2014-09-18 11:20:54)
    2014-09-18 07:11:12,160 fail2ban.actions  [named-refused] Ban     XXX.XXX.XX.XXX (_ # 0:15:00 -> 2014-09-18 07:26:11)
    2014-09-18 06:47:46,618 fail2ban.actions  [named-refused] Unban   XXX.XXX.XX.XXX
    2014-09-18 04:37:29,972 fail2ban.observer [named-refused] Increase Ban    XXX.XXX.XX.XXX (4 # 2:02:16 -> 2014-09-18 06:39:44)
    2014-09-18 04:37:29,967 fail2ban.actions  [named-refused] Ban     XXX.XXX.XX.XXX (_ # 0:15:00 -> 2014-09-18 04:52:28)
    2014-09-18 04:32:49,491 fail2ban.actions  [named-refused] Unban   XXX.XXX.XX.XXX
    2014-09-18 02:55:05,706 fail2ban.observer [named-refused] Increase Ban    XXX.XXX.XX.XXX (3 # 1:23:31 -> 2014-09-18 04:18:35)
    2014-09-18 02:55:05,698 fail2ban.actions  [named-refused] Ban     XXX.XXX.XX.XXX (_ # 0:15:00 -> 2014-09-18 03:10:04)
    2014-09-18 01:18:37,976 fail2ban.actions  [named-refused] Unban   XXX.XXX.XX.XXX
    2014-09-18 00:40:09,592 fail2ban.observer [named-refused] Increase Ban    XXX.XXX.XX.XXX (2 # 0:38:30 -> 2014-09-18 01:18:37)
    2014-09-18 00:40:09,548 fail2ban.actions  [named-refused] Ban     XXX.XXX.XX.XXX (_ # 0:15:00 -> 2014-09-18 00:55:07)
    2014-09-17 22:47:05,872 fail2ban.actions  [named-refused] Unban   XXX.XXX.XX.XXX
    2014-09-17 22:32:05,804 fail2ban.actions  [named-refused] Ban     XXX.XXX.XX.XXX (_ # 0:15:00 -> 2014-09-17 22:47:05)
    

    Здесь хорошо заметно, как каждый следующий бан продлевает время блокировки от 15 минут (0:15:00) первый раз, до 5 с лишним дней (5 days, 8:04:55) после десятой блокировки. У меня в базе есть IP у которых «срок» уже — от нескольких месяцев до перманентного бана.

    Ниже можно увидеть, как новый функционал отразился на решении собственно банить IP XXX.XXX.XX.XXX. В примере параметр maxRetry установлен равным 5. Так мы видим, что пока IP не признан плохим он был первый раз забанен после 5-ти попыток, второй раз, уже как плохой — после 3-х (каждая попытка была засчитана за 2), третий и т.д. — после 2-х (попытка идет за 3) и четвертый раз забанен сразу после первой попытки (считается сразу за 5-ть):
    [Click to view LOG]
    2014-09-18 04:37:29,155 fail2ban.observer [named-refused] Found XXX.XXX.XX.XXX, bad - 2014-09-18 04:37:28, 3 # -> 5, Ban
    2014-09-18 04:37:29,148 fail2ban.filter   [named-refused] Found XXX.XXX.XX.XXX - 2014-09-18 04:37:28
    ......
    2014-09-18 02:55:04,790 fail2ban.observer [named-refused] Found XXX.XXX.XX.XXX, bad - 2014-09-18 02:55:04, 2 # -> 3, Ban
    2014-09-18 02:55:04,763 fail2ban.filter   [named-refused] Found XXX.XXX.XX.XXX - 2014-09-18 02:55:04
    2014-09-18 02:22:37,683 fail2ban.observer [named-refused] Found XXX.XXX.XX.XXX, bad - 2014-09-18 02:22:37, 2 # -> 3
    2014-09-18 02:22:37,648 fail2ban.filter   [named-refused] Found XXX.XXX.XX.XXX - 2014-09-18 02:22:37
    ......
    2014-09-18 00:40:08,908 fail2ban.observer [named-refused] Found XXX.XXX.XX.XXX, bad - 2014-09-18 00:40:08, 1 # -> 2, Ban
    2014-09-18 00:40:08,625 fail2ban.filter   [named-refused] Found XXX.XXX.XX.XXX - 2014-09-18 00:40:08
    2014-09-17 23:48:54,404 fail2ban.observer [named-refused] Found XXX.XXX.XX.XXX, bad - 2014-09-17 23:48:53, 1 # -> 2
    2014-09-17 23:48:54,397 fail2ban.filter   [named-refused] Found XXX.XXX.XX.XXX - 2014-09-17 23:48:53
    2014-09-17 22:49:04,647 fail2ban.observer [named-refused] Found XXX.XXX.XX.XXX, bad - 2014-09-17 22:49:03, 1 # -> 2
    2014-09-17 22:49:04,620 fail2ban.filter   [named-refused] Found XXX.XXX.XX.XXX - 2014-09-17 22:49:03
    ......
    2014-09-17 22:32:05,593 fail2ban.filter   [named-refused] Found XXX.XXX.XX.XXX - 2014-09-17 22:32:05
    2014-09-17 22:06:29,952 fail2ban.filter   [named-refused] Found XXX.XXX.XX.XXX - 2014-09-17 22:06:29
    2014-09-17 21:47:43,439 fail2ban.filter   [named-refused] Found XXX.XXX.XX.XXX - 2014-09-17 21:47:42
    2014-09-17 20:43:41,490 fail2ban.filter   [named-refused] Found XXX.XXX.XX.XXX - 2014-09-17 20:43:40
    2014-09-17 16:44:35,130 fail2ban.filter   [named-refused] Found XXX.XXX.XX.XXX - 2014-09-17 16:44:34
    

    Без этой логики подсчета failure, умные бот-сети научились подстраивать свою работу так, чтобы просто не попадать в бан. Когда я допилил таки и эту логику и выкатил в продакшн, за считанные дни я избавился практически от всей той нечисти, которую привык видеть годами в своих логах. Например, сейчас средний нормальный ежедневный прирост моих auth.log где то в районе 20-50 строк, раньше на некоторых серверах он был в сотни и тысячи раз больше.

    Пока что это development branch, лежит pull request-ом, релиз запланирован пока в версии 0.9.2.
    Кому интересно, почитать подробнее про реализацию и историю решения можно здесь — Ban time incr by sebres · Pull Request #716 · fail2ban/fail2ban.

    Однако пока эта версия ляжет апдейтом на ваш сервер, пройдет еще немало времени — пока релиз выйдет в mainline, пока его в дистрибутивы возьмут… История длинная, например тот же debian все еще использует 0.8.x — собственно поэтому и статья. Так что качаем руками, устанавливаем… профит.

    Взять эту версию можно здесь fail2ban-ban-time-incr.zip (sebres master branch).
    Порт для debian-ов: ban-time-incr-debian.zip (merged master debian branch, и хоть и не main line — буду стараться по возможности поддерживать ветку актуальной).

    Установить его довольно просто. Если у вас уже до того был fail2ban, установленный из дистрибутива, сохраняем из "/etc/fail2ban/" старые «fail2ban.local» и «jail.local» (Ну и лучше старые «fail2ban.conf» и «jail.conf»). Я бы на всякий случай (из-за возможных личных изменениях в filter и action) сохранил бы куда-нибудь весь каталог "/etc/fail2ban/".

    Далее сносим старый дистрибутивный fail2ban, например:
    sudo service fail2ban stop
    sudo apt-get remove fail2ban
    

    Собственно установка:
    cd /tmp
    unzip ~/downloads/fail2ban-ban-time-incr.zip
    cd fail2ban-ban-time-incr/
    sudo python setup.py install
    

    [UPD] Иногда на некоторых дистрибутивах, при ручной установке, почему-то не устанавливается сервис (например нет файла /etc/init.d/fail2ban) — и соответственно через сервис не (авто)стартует, только через fail2ban-client start.
    [Что делать...]
    Это можно поправить копированием из дистрибутива или например из архива (потом не забываем поправить права):
    cd /tmp/fail2ban-ban-time-incr-debian
    sudo cp /etc/init.d/fail2ban ~/init.fail2ban.org
    sudo cp ./files/debian-initd /etc/init.d/fail2ban
    chmod u+x,g+x,o+x /etc/init.d/fail2ban
    
    И проверить внутри путь к fail2ban-client (which fail2ban-client):
    — при /usr/local/bin/fail2ban-clientDAEMON=/usr/local/bin/$NAME-client
    — при /usr/bin/fail2ban-clientDAEMON=/usr/bin/$NAME-client
    Не забываем проверить автозапуск сервиса (update-rc.d, rcconf, file-rc… любимое подставить).
    [/UPD]

    Теперь чтобы заработал новый функционал, нужно в вашем jail.local в [default] (либо для каждой конкретной jail) добавить опцию: bantime.increment = true. Пример и описание можно пока найти в "jail.conf".
    Некоторое здесь кратко:
    • bantime.rndtime — максимальное время, используется для добавления к banTime случайного времени, для предотвращения «умных» бот-сетей вычислять точное время, когда IP разблокируется снова. Пример bantime.rndtime = 10m
    • bantime.factor — коэффициент для вычисления экспоненты роста для формулы bantime.formula или множителей bantime.multipliers, по умолчанию значение коэффициента 1, что соответствует увеличению времени запрета на 1, 2, 4, 8, 16… Увеличивая этот параметр для некоторых jail, можно увеличивать время блокировки более агрессивно.
    • bantime.formula — используется по умолчанию для вычисления следующего значения времени запрета, значение по умолчанию: bantime.formula = ban.Time * (1<<(ban.Count if ban.Count<20 else 20)) * banFactor
      Тот же рост времени запрета будет достигнут используя множители bantime.multipliers равные 1, 2, 4, 8, 16, 32…
      Пример более агрессивной формулы для фактора «1» и имеет те же значения роста только для фактора равного «2.0 / 2.885385":
      bantime.formula = ban.Time * math.exp(float(ban.Count+1)*banFactor)/math.exp(1*banFactor)
    • bantime.multipliers — параметр может используется вместо формулы дискретно для вычисления следующего значения времени запрета. Значение множителя равное "-1" (может стоять только в конце списка) и заносит адрес в перманентный бан (до ручного разблокирования).
      Пример 1: bantime.multipliers = 1 2 4 8 16 32 64 — увеличивает время запрета на 1, 2, 4,… и если последний ban count был больше последнего индекса мультипликаторов, то будет всегда использован последний множитель (64 в примере), что при факторе равном «1» и оригинальном времени запрета (10 минут) — соответствует 10.6 часам.
      Пример 2: bantime.multipliers = 1 5 30 60 300 720 1440 2880 — может использоваться для небольшого начального времени запрета (bantime = 60) — т.к. увеличение становится более агрессивным, имеем bantime равный: 1 мин, 5 мин, 30 мин, 1 час, 5 часов, 12 часов, 1 день, 2 дня соответственно.

    Если во время проб или в продакшн какой-нибудь (хороший) IP случайно многократно улетел в бан (и стал соответственно плохим) он забудется (снова станет «белым») сам по истечении трехкратного времени последнего бана и dbpurgeage (находится в fail2ban.local), либо если с него руками снять бан, используя:
    fail2ban-client set  unbanip 

    Я для тестирования регулярок использую fail2ban-regex, а для теста работоспособности что-нибудь типа: logger -t 'test:auth' -i -p auth.info "pam_unix(test:auth): authentication failure; logname= uid=0 euid=0 tty=test ruser=admin rhost=1.2.3.4"

    Не забываем про старт:
    sudo service fail2ban start
    

    Вот собственно и все, теперь надеюсь ваш сервер стал еще чуточку защищенней. Ну а вы не ленитесь и поглядывайте все-таки в логи (доверяй, но проверяй).

    P.S. Стандартная приписка: Fail2Ban is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY. Короче говоря - пользуйтесь на здоровье, но на свой страх и риск...
    И да пребудут ваши сервера в безопасности.

    P.P.S. Да чуть не забыл, у меня тут назапланировано что-то допилить, что-то уже готово, нужно просто оформить нормально и выложить, так вот - опрос "Что по вашему следовало бы (до)делать в первую очередь".
    Что по вашему следовало бы (до)делать в первую очередь

    Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

    Метки:
    Поделиться публикацией
    Комментарии 57
    • +15
      sudo python setup.py install

      уважаемый, я очень ценю ваш труд, но почему, почему вы, чёрт возьми, make install? Сколько раз твердили миру…
      Почему бы не научить, как собрать пакет и поставить его — ну реально на две команды больше, а жизнь облегчится…

      А если по теме — не думали об аналитике и попытке идентификации ботнетов? Ну или хотя бы логировании достаточной информации (кто, куда, с какими параметрами).
      • +8
        И ещё одно.

        В fail2ban не хватает возможности разделить хост-блокировщик и хост-цель (другими словами, client и server могут связаться только по AF_UNIX, но не AF_INET). То есть, вот к примеру отдельно виртуалка с почтовым сервером и отдельно система с файерволлом. Приходится копировать логи с одной на другую сислогом, чтобы банить на фаерволле по данным с мэйлсервера.

        Также, скажем, есть несколько серверов. Приятно было бы банить сразу на всех при пессимизации на каком-то одном. Опять же, решается пересылкой логов по сети, но это же ужасный костыль.

        И в догонку про ботнеты: после нескольких последовательных банов определённого сервиса для некоего хоста, можно ещё последовательно расширять горизонт бана: банить негодника на большем числе сервисов, банить на сервисах другого типа на соседних серверах и т. д. Ведь, если хост попал в ботнет и сейчас рассылает спам, не факт, что завтра он не начнёт брутить ssh.
        • 0
          Вообще, на заре интернета мы пользовались для этого drbl. но система оказалась слишком сложной
        • 0
          Вам определенно стоит почитать как работает fil2ban. Если очень кратко, то заданные логи читаются и пропускаются через заданные фильтры (поставляются с fail2ban). Если фильтр что-то находит и при привышении заданного количества в заданное время сообщений применяются задданные действия (поставляются с fail2ban). Просто приведу названия некоторых действий чтобы вам стало более понятно:
          complain
          iptables
          iptables-ipset-proto4
          mail-whois

          Эти действия можно компоновать и нет никакой проблемы изменить стандартные или написать нужные вам действия. Как раз оно в /etc/ и лежит для этого.
          Так вы можете банить командой по сети сразу на вашей системе с файрволлом.
          Или банить полностью, а не только порт сервиса.

          • 0
            вам определённо должно быть видно из активности меня в этой ветке, что я прекрасно понимаю, как он работает

            я имел ввиду расширение горизонта в том же духе, как сейчас увеличиваются сроки бана и сокращается число допустимых попыток
        • +4
          расширять горизонт бана: банить негодника на большем числе сервисов
          Вот это вот частично реализовано — bantime.overalljails = false и бутет вам счастье IP будет считаться плохим по всем jail-ам, т.е. после failure уже на любой jail и там надолго вылетает в бан.

          По поводу system across сообщений — идея правда хорошая, спасибо, надо подумать. У меня сейчас в fail2ban есть event driven модуль (observer), можно после бана (и/или failure) асинхронно инкреметально синхронизировать базу на всех серверах. Где-то даже проект завалялся похожий, ака sqlite-notifier для кластера серверов (типа звезда), может и выдеру чего оттуда.
          • 0
            Конечно же true вместо false:
            bantime.overalljails = true
            

      • 0
        уважаемый, я очень ценю ваш труд, но почему, почему вы, чёрт возьми, make install? Сколько раз твердили миру…
        Почему бы не научить, как собрать пакет и поставить его — ну реально на две команды больше, а жизнь облегчится…
        Вы не работали с Python. Если автор Python’овского пакета адекватен и использовал стандартные distutils, то pip install … и cd … && python setup.py install не отличаются по своему результату.

        Так что не надо. python setup.py install — это далеко не make install. Но только если вы считаете, что управление системными пакетами двумя менеджерами пакетов (pip и apt или что у вас там) — хорошая идея. Учитывая, что целью данной статьи не было обучение аудитории сборке пакетов на всех 100500 дистрибутивах и пакеты с distutils собираются элементарно, то всё в порядке.
        • 0
          Но только если вы считаете, что управление системными пакетами двумя менеджерами пакетов (pip и apt или что у вас там) — хорошая идея.

          Именно, я считаю, что это — плохая идея, менеджер пакетов должен быть один.

          Данная статья начата с Debian. Пусть хотя бы показано было на нём. Кстати говоря, в Gentoo написать distutils-ebuild очень просто.
          • –1
            Это ужасная идея. Особено в реалиях debian. Мне не редко приходится чекенить отдельный бранч для гема, чтобы работало и ждать пока вольется в master, а вы говорите еще ждать пока мэинтейнер соизволит обновить у себя? Нет, спасибо.
            • +1
              Вообще‐то он говорит собрать свой пакет, а не полагаться на какого‐то maintainer’а. Это не так уж и сложно, тем более что для gem’ов наверняка тоже есть что‐то готовое. Я же говорю, что sudo python setup.py install не так уж и страшен, и рассказывать про сборку пакетов в статье про fail2ban совершенно не нужно.
              • –1
                >Именно, я считаю, что это — плохая идея, менеджер пакетов должен быть один.
                • +1
                  И? Предложено было собирать свой пакет для дистрибутивного менеджера пакетов. Ни один такой менеджер не запрещает вам быть maintainer’ом своего же пакета. И даже собирать его в той же системе, в которой он будет использоваться.
    • 0
      А не подскажете случаем как можно банить адреса которые используют разные логины или банить за использование определенных логинов?
      • 0
        Первое — не понял, что значит «используют разные логины»? У вас правило — один адрес, один логин или что? А как же NAT?

        Второе — тем же самым fail2ban, написать правило, которое ловит именно эти самые определённые запрещённые логины.
        • 0
          1) В целом да, есть пару серверов где используется только одна-две учетки
          2) Уже нагуглил примеры.
          • +1
            Тогда про первое — не делать ничего. fail2ban сам подхватит n неудачных попыток зайти с несуществующими логинами и забанит.
            • +1
              Ну про это понятно, хочется более интуитивной выборки, вот например в auth.log попадали баны за попытки войти с логином wbcLogonUser, а это то ли дефолтный логин для cpanel, то ли еще что-то, так вот суть в том что максимум попыток у меня равно 3 и в логах длинный список попыток с разных адресов зайти с этим логином. Вот и интересуюсь нет ли фильтра который анализировал бы часто используемые неудачные логины и банил бы сразу без вопросов?
              • 0
                Если хочется более интуитивной выборки — возьмите и напиши сами под себя.
                На среднем сервере веб хостинга как правило живёт вагон сервисов + вагон всякого клиентского хлама, вроде вордпрессов, джумл, прочих cms, которые перебираются, подбираются и ломаются раз в день. Так что «какие логины» для каких «дефолтных логинов» перебирают у Вас, вряд ли перебирают у меня.
                Именно потому, что «часто используемые неудачные логины» меняются от сервиса к сервису, а их неисчислимое количество, надо понимать, что есть количество попыток с одного хоста. а что там уже конкретно — дело десятое.
    • 0
      Я эту проблему решил ещё одним правилом, сканирующий лог самого fail2ban. Те я банил на большее время тех, кто часто светится и навсегда — самых наглых.
      Но есть одна идея, проблемная в реализации. Всех забаненных, обращающихся на 80 порт, перенаправлять на статическую страницу (где не банят), с информацией о том, что «ваш IP заблокирован, возможно выш компьютер заражен и является частью ботнета итп». Как это сделать в iptables я не представляю.
      • 0
        да элементарно, -j REDIRECT их на другой порт, где другой вебсервер показывает эту вашу страницу.
        • 0
          Нехороший IP банится на весь сервер(по все портам). Получается нужно чтоб iptables игнорировал определённый порт? Как?
          • 0
            добавить непосредственно перед полным баном разрешение для этого конкретного порта. Примерно так:
            -t nat -A PREROUTING --match-set banned-ips --p tcp --dport 80 j REDIRECT --to-ports 8888 -m comment --comment «banned IPs going to 80 will be served by web-service hanging on 8888 instead»
            -t filter -A INPUT --match-set banned-ips -p tcp --dport 8888 -j ACCEPT -m comment --comment «on a port 8888 will listen our web server with a static page — allow our banned hosts to access this port»
            -t filter -A INPUT --match-set banned-ips -j REJECT --reject-with icmp-port-unreachable -m comment --comment «everything else will be rejected»
            не проверял правила, может и ошибся где-то, но идея видна
            • +1
              да, правила неправильные в смысле синтаксиса match-set; читайте ман и легко поправите. Там должно быть что-то вроде -m set --match-set banned-ips src

              сам по себе список banned-ips подразумевается типа hash:ip или что угодно другое :ip, сообразно ситуации
      • 0
        Какие нафик формулы и сканирование собственного лога? Fail2ban давно этой умеет сам и для этого есть jail — recidive. Туда и складывать всех на недельку. А если что-то совсем под ударом стоит, то portnocking в помощь.

        Хорошая утилита, жаль только ipv6 не умеет пока
        • 0
          У recidive есть к сожалению несколько нехороших недостатков:
          • recidive jail довольно просто обойти, т.к. считаются уже состоявшиеся баны других jail (maxRetry за промежуток времени findTime);
          • recidive jail считает только ban-ы, и ему совершенно наплевать на failure — в результате умные бот-сети подстраивают перебор под параметры maxRetry/findTime, чтобы просто тупо не слетать в бан. recidive в этом случае абсолютно бесполезен.
          • recidive фильтр сканирует собственный fail2ban.log, что чревато: совершенно никудышный performance, падающий нелинейно с ростом нагрузки, затрудненная отладка и поиск ошибок и т.д и т.п.).
          • неудачный logrotate на fail2ban.log иногда приводит к тому, что jail «recidive» падает в idle (т.е. совсем отключается).
          • recidive jail блокирует все порты и прото, что иногда не есть гуд. Как минимум когда сам после неудачных попыток зайти в почту (случайно) улетишь в бан, а залезть с другого IP чтобы разбанить себя любимого под рукой нет возможности.

          Поэтому формулы и еще раз формулы :)
    • 0
      К fail2ban отлично подходит logwatch.
      Эта программа парсит логи и присылает на почту письмо с выжимкой раз в сутки.
      Сообщения fail2ban она тоже видит.
      Если бы ваш знакомый админ получал письма, то давно бы заметил такую атаку.

      Ну и простой способ защититься от левых подборов — поменять порт ssh.
      Естественно, от целенаправленной атаки это не защита, но от постоянного сканирования всея интернета помогает.
      Например, за пару лет на сервере хостинга было всего несколько попыток подключения по ssh.
      • +5
        Оставить только аутентификацию по ключу и банить за любые попытки логина по паролю.
    • +1
      Мне придумалось, что в альтернативной реальности, где весь мир покорил Советский Союз, могла существовать программа наказания под названием «FAIL2BAM» — провинился, поехал на БАМ.

      Пятничный вечер, поэтому не судите строго ))
      • +1
        Нужны ещё Banned4Spam и Burned4Fun (рандомный наказатель).
        • 0
          Да, и новый термин «Bammed»
    • 0
      Это будет хорошее развитие filter.d/recidive.conf.
      После того как я заметил, что Slow Brute Force стал массовым (в плане размера ботнетов) и очень умным, то проспонсировал добавление в fail2ban ignorecommand (позволяет внешнему скрипту указать fail2ban, что ip не нужно банить) и сделал retry=1. Т.е всех банить сразу и надолго, но не банить доверенные ip. Например, которые где-то уже аутентифицировались, известные сети, местная страна и т.д. до 10 попыток, например. Если оно всё еще стучится, то filter.d/recidive его добивает.

    • 0
      Спасибо за работу, очень полезный функционал! Недавно как раз в asterisk 11 появилась опция security в loger.conf, и гораздо проще стало банить всяких переборщиков. Как писали выше очень был бы полезен функционал межсерверного взаимодействия. Возможно даже сервис где люди синхронизируют свои fail2ban блокировки с другими по определенным критериям или сообществам.
      • +1
        функционал межсерверного взаимодействия.

        github.com/uu/bango
        Централизованный забанятор/разбанятор.
    • 0
      как вариант CSF для CentOS
    • +1
      Отличное решение, спасибо за работу.

      Единственное что хотел уточнить. Я везде где можно использую denyhosts, скажите пожалуйста в чём его слабые места и почему следовало бы перейти на fail2ban. Мне в denyhosts нравится в первую очередь потому что там есть механизм, который умеет с удалённых серверов скачивать чёрные списки, которые постоянно обновляются (в их числе и многочисленные ботнеты).
      Хотелось бы услышать и ваше мнение поэтому поводу (если есть что сказать конечно). Благодарю!
    • 0
      Голосую за полноценную поддержку ipv6. Готов вложиться некоторым количеством рублей.

      Я пытался доработать самостоятельно патч выложенный в вики, но не хватает питон-скила и времени.
    • 0
      На freebsd ваша сборка не работает. Python 2.4.3

      root@server:/home/admin/fail2ban-ban-time-incr# /usr/local/etc/rc.d/fail2ban start
      Traceback (most recent call last):
        File "/usr/local/bin/fail2ban-client", line 28, in ?
          from fail2ban.version import version
        File "/usr/local/lib/python2.4/site-packages/fail2ban/__init__.py", line 70, in ?
          logging.handlers.SysLogHandler.priority_map['NOTICE'] = 'notice'
      AttributeError: class SysLogHandler has no attribute 'priority_map
      
      • 0
        Заработало на python 2.7
        • 0
          Всё конечно работает, но работает кривовато. Не работает bantime.increment, в лог валится:

          fail2ban.observer       [30309]: ERROR   'NoneType' object has no attribute 'getBan'
          

          Если в fail2ban.conf включить loglevel = DEBUG, то при рестарте fail2ban вываливается громадная куча ошибок — pastebin.com/23ScC602

          Буду благодарен, если подскажите в чём дело, у меня к сожалению знания питона на нуле
          • 0
            Observer и новый функционал работают только если в fail2ban.local (или fail2ban.conf) включен банк данных:
            dbfile = /var/lib/fail2ban/fail2ban.sqlite3
            
            Я так понимаю у вас оно либо откомментировано, либо не может туда писать.
            P.S. По ссылке заглянуть немогу (корпоративные политики, будь они не ладны), но думаю это все же DB.
    • 0
      А вы в курсе, что файла ./debian/fail2ban.init для выполнения sudo cp ./debian/fail2ban.init /etc/init.d/fail2ban у вас просто нет? Может по этому автоматически не будет стартовать?
      • 0
        Блин, детский сад честное слово… Ну возьмите его из дистрибутива fail2ban_0.9.1-1.debian.tar.xz, в чем проблема то.

        Не знаю что там с веткой debian в исходниках на github случилось, был готов поклясться — он там был…
        • 0
          Ну да — он там и был, просто коллега yarikoptic убрал его коммитом 67e79a14624c496f740ed3c63ae28788c6e3b346: now we will use upstream's init for debian
          В общем лежит оно теперь в /files/debian-initd. Статью сейчас поправлю.
          • 0
            Спасибо за помощь!
            Я и в правду детский сад — не очень хорошо умею работать с unix, поэтому непонятные сложности ставят в тупик и когда решение не очевидно становится очень грустно.
            Еще раз — большое спасибо за помощь — поменяю сейчас дефолтный 0.8.6-3wheezy на ваш (даром что ли столько времени с ним разбирался:))
    • 0
      Да, и как теперь удалить ваш вариант fail2ban? Скрипт setup.py ни чего, кроме install не предусматривает. Мне на будущее будет уроком не устанавливать на рабочие сервера не проверенные решения.
      • 0
        А его и не надо удалять. Просто ставте родной сверху — если вы fail2ban уже запускали, нужно будет удалить /var/lib/fail2ban/fail2ban.sqlite3, т.к. не совместим.
    • 0
      Стесняюсь спросить, а как сия утилита «работает» с динамическими адресами? То есть ботнет из 10к машин — понятно, но это не означает автоматически 10к фиксированных IP-адресов.
      • –1
        Не хуже чем со статикой (в чем-то лучше, например в том смысле, что плохие адреса не забивают базу на долгие годы). Выглядит как-то так:
        • динамический IP улетает в бан (например сначала после 3-х failure на 15 мин, затем после 2-х на 45 мин, затем сразу на 3 часа, и в итоге уже на сутки);
        • грубо говоря, такой IP сделает максимум 5 — 10 попыток в сутки (зависит от настроек)
        • провайдер как правило меняет адрес раз в сутки (иногда реже)
        • завтра все повторится опять, а из базы улетит «вчерашняя» динамика (с разницей за минусом purgeage)

        Конечно у такой бот-сети подобрать шансы выше, чем у «статичной», но не намного (кроме того провайдеры тоже бдят).
        И оно однозначно лучше, чем совсем без «инкремента».
    • 0
      Если адрес меняется раз в сутки, то, да, пожалуй, проблемы особой не видно. Ну, кроме, конечно же, большей эффективности такой сети. Но это с точки зрения защищающегося, когда стоит только одна цель — защититься от подбора пароля (или похожие). Но! Но могут начать наблюдаться проблемы с доступностью сервиса через определённых провайдеров. Небольшой кусок ботнета, сидящего в сети провайдера с динамическими адресами медленно, но верно, выкосит весь операторский пул, то есть простые (чистые) пользователи, получив адрес после заражённой машины будут сидеть в бане и, возможно, даже в вечном.
      P.S. Не наезжаю, просто, хочу взглянуть с другой стороны.
      P.P.S. Сорри, что написал не в ответ, а как новый коммент, — сплю в одном ботинке уже.
      • –1
        Небольшой кусок ботнета, сидящего в сети провайдера с динамическими адресами медленно, но верно, выкосит весь операторский пул
        Как вы думаете, сколь долго провайдер будет «терпеть» таких абонентов? Им просто позакрывают порты (например smtp, если подбирает мыло) + письмо счастья (поздравляю у вас вирус).
    • 0
      Поставил на убунту. По логу работает

      2016-03-06 13:49:58,300 fail2ban.server [24872]: INFO Changed logging target to /var/log/fail2ban.log for Fail2ban v0.9.2.dev0
      2016-03-06 13:49:58,300 fail2ban.transmitter [24872]: DEBUG Command: ['set', 'syslogsocket', 'auto']
      2016-03-06 13:49:58,301 fail2ban.transmitter [24872]: DEBUG Command: ['set', 'dbfile', '/var/lib/fail2ban/fail2ban.sqlite3']
      2016-03-06 13:49:58,301 fail2ban.transmitter [24872]: DEBUG Command: ['set', 'dbpurgeage', '1d']

      По факту нет.

      Конфиг включен.

      # «bantime.increment» allows to use database for searching of previously banned ip's to increase a
      # default ban time using special formula, default it is banTime * 1, 2, 4, 8, 16, 32…
      bantime.increment = true

      # «bantime.rndtime» is the max number of seconds using for mixing with random time
      # to prevent «clever» botnets calculate exact time IP can be unbanned again:
      bantime.rndtime = 10m

      # «bantime.maxtime» is the max number of seconds using the ban time can reach (don't grows further)
      #bantime.maxtime =

      Скажите в чем проблема?
      • 0
        По факту нет...

        Глупый вопрос: а вы хоть одну jail включили (enable = true)?

        Обычно создается файл jail.local:

        [sshd]
        enabled = true
        
        [nginx-http-auth]
        enabled = true
        
        ...
        • 0
          Сказывается моя неопытность. Теперь разобрался и завел его, спасибо!
    • +1

      Только-что выкатил пре-релиз 0.10-ветки для ban-time-incrподдержкой ipv6 и другими вкусностями)...


      Pre-release: 0.10.0-ban-time-incr-1 (2016/07/15) — ipv6-support meets ban-time-incr


      https://github.com/sebres/fail2ban/releases/tag/0.10.0-bti1


      PS. Про другие вкусности:


      • Рост скорости и снижение нагрузки: 10-я версия гораздо быстрее предыдущей и в разы меньше нагружает CPU и IO:
        • Максимальное время до блокировки (задержка блокировки от нахождения failure до ban) уменьшена практически в 1000 раз;
        • Средняя скорость блокировки выросла в десятки раз (порядка 200-300 IP/сек);
        • Рост задержки блокировки (регрессия при увеличении количества failure / ban) упал с 100 мс до 5 мс на каждую 1000 IPs.
      • Полностью переработанный клиент-сервер;
      • Возможность блокировки не только IP адресов: например использовать имена в качестве failureid и банить пользователей. Или использовать пару IP:port или другой идентификатор в качестве failure id, а банить IP адрес. Подробности см. https://github.com/fail2ban/fail2ban/pull/1459;
      • Еще много — много чего другого...

    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.