Защищаем ssh от брутфорса средствами pf
# создаём таблицу table <sshblock> persist # пропускаем проверку на петле set skip on lo0 # для отброшенных пакетов TCP отсылается пакет TCP RST set block-policy return # для прочих ICMP Unreachable ### если DOSят то можно указать "drop" ### set block-policy drop #пакет молча отбрасывается #собираем все части пакета перед отправкой scrub in all #запретим все отовсюду block all #блокируем тех кто попал в sshblock block in log quick from <sshblock> # пропускаем на ssh из внутренней подсети, а злодеев заносим в таблицу pass in on $int_if proto tcp from $int_if:network to $int_if port ssh \ synproxy state (max-src-conn-rate 2/60, overload <sshblock> flush global) # пропускаем на ssh из вешней подсети, и тоже заносим злодеев в таблицу pass in on $ext_if proto tcp from any to $ext_if port ssh \ synproxy state (max-src-conn-rate 2/60, overload <sshblock> flush global) # разрешаем всё из локальной сети pass in on $int_if from any to any # разрешаем серверу доступ в интернет pass out on $ext_if from $ext_if to any # разрешаем ping pass in inet proto icmp all icmp-type echoreq
Посмотреть тех кто в таблице можно так:
pfctl -t sshblock -T show
Удалить ip адрес (например 192.168.1.9), из таблицы можно так:
pfctl -t sshblock -T delete 192.168.1.9
осталось настроить cron
crontab -e
30 * * * * root /sbin/pfctl -t sshblock -T expire 86400
Каждые час (в 30 минут) -T expire 86400 удаляет все записи из таблицы старше 86400 секунд (сутки)
max number Ограничение максимального количества записей в таблице состояний, которое может сделать данное правило. По достижении этого предела, будет отброшен любой пакет, который должен был бы завести новую запись в таблице состояний. Пакеты будут отбрасываться до тех пор, пока число записей в таблице состояний не уменьшится.
source-track Эта опция даёт возможность отслеживать количество записей в таблице состояний в пересчёте на каждый адрес источника. Возможные форматы опции:
source-track rule — Максимальное количество записей в таблице состояний созданных данным правилом ограничивается опциями max-src-nodes и max-src-states, заданными в этом правиле. Счётчики заводятся не глобальные, а локальные.
source-track global — То же что и в предыдущем слуаче, но счётчики ведутся глобально. При этом каждое правило может иметь свои пределы max-src-nodes и max-src-states, однако счётчики будут общими для всех правил.
Общее количество адресов источников, для которых осуществляется глобальный контроль количества строк в таблице состояний, ограничивается при помощи опции src-nodes.
max-src-nodes number При использовании опции source-track опция max-src-nodes ограничивает количество IP-адресов с которых можно одновременно открыть соединения.
max-src-states number При использовании опции source-track опция max-src-states ограничивает количество соединений с одного IP-адреса.
max-src-conn number Ограничение максимального количества TCP соединений прошедших тройное рукопожатие, которые можно открыть с одного IP-адреса.
max-src-conn-rate number / interval Ограничение скорости с которой можно открывать новые соединения. Задаётся количество соединений за интервал времени.
Обе опции автоматически включают опцию state-track rule и не совместимы с state-track global.
В комбинации с данными опциями можно употреблять более агрессивные опции, для «наказания» «провинившихся».
overload При превышении лимитов занести адрес источника в таблицу.
flash [global] Уничтожить все записи в таблице состояний соответствующие соединениям с данного IP-адреса. При указании опции global записи в таблице состояний сбрасываются независимо от того, какое правило её создало.
Дополнительно то же самое
Brute force — это самый грубый и легко уловимый в файлах журналов (в log-ах) метод проникновения на сервер, использующий перебор возможных паролей. В некоторых случаях это может сработать, так как многие используют простые легко запоминаемые пароли (состоящие, к примеру, только из цифр, непосредственно связанных с человеком). Автоматический подбор паролей ведет к заполнению логов множеством записей о попытках авторизации к сервису, прослушиваемый порт которого доступен для мира. Уже с этого можно сделать вывод, что желательно менять стандартный открытый порт демона на любой другой (лучше, в диапазоне 1024-65536, которые являются непривилегированными) для таких служб, к примеру, как SSH и ограничивать подключения с определенных IP-адресов, если есть такая возможность.
Для борьбы с brute force-атаками полезными будут знания специфики «тройного рукопожатия» при установке TCP-соединения. Это передача трех пакетов, которые инициализируют и устанавливают соединение. Первый пакет приходит с установленным флагом SYN, в ответ на который передается SYN/ACK пакет и для него, в свою очередь, приходит подтверждение ACK. После этого по открытому/установленному соединению передаются данные. С помощью возможностей механизма «проверки состояния соединений» сетевым фильтром открывается много гибких возможностей для контроля сессий.
PF (packet filter) хранит информацию о каждом соединении в таблице состояний. После установки соединения последующие пакеты, относящиеся к нему, независимо от направления прохождения, не будут заново проверяться имеющимися правилами пакетного фильтра, что улучшает производительность брандмауэра. При просмотре имеющихся правил:
pfctl -sr
можно увидеть в конце опцию «keep state», если фильтрующее правило создает state-запись, когда пакет соответствует правилу. Эта опция включена по умолчанию.
Правила nat, binat, и rdr тоже создают записи в таблице состояний, которые хранятся до тех пор, пока фильтрующие правила их пропускают. Правила NAT и RDR срабатывают до правил фильтрации.
Полезными в правилах опциями таблицы состояний могут быть:
max number – максимальное количество соединений для данного правила, которое применяется пока не достигнут максимум;
no state – не создавать записи в таблице состояний;
source-track [rule|global] – для отслеживания кол-ва соединений, созданных IP адресом, применяется к одному правилу или всем, где эта опция упоминается. Каждое правило может указать разные max-src-nodes и max-src-states опции, которые соответственно ограничивает количество исходных IP адресов, одновременно создающих соединения, и одновременно созданных соединений с одного исходного IP адреса.
Для уже установившихся соединений:
max-src-conn number – максимальное количество одновременно существующих соединений с одного IP;
max-src-conn-rate number / interval – количество новых соединений, которые можно открывать за указанный интервал времени;
overload <table> – помещение в данную таблицу IP-адреса нарушителей;
flush [global] – уничтожить все соединения, которые были созданы этим исходным IP адресом, а с опцией « global» для всех правил, где с этого IP-адреса создавалось соединение.
Поскольку при brute force происходит постоянное переподключение к открытому порту, то можно лишить смысла такие атаки, установив разумные лимиты количества соединений за определенный промежуток времени. В этом будет крайне полезна опция max-src-conn-rate, которая и задает эти настройки. Также, дополнительно, будут не лишними опции overload и flush.
В /etc/pf.conf следует добавить в нужные места следующие правила:
# динамический список с IP-адресами нарушителей: table <ssh-bruteforce> persist # правило для блокирования подключений с этих IP-адресов: block drop in quick on $ext_if from <ssh-bruteforce> # собственно правило, которое будет заполнять список недоброжелателей, #т.е. тех, кто превысил лимит подключений, больше трех за 60секунд к сервису SSH, #с сбросом существующих соединений, инициированных данным IP-адресом: pass in quick on $ext_if proto tcp from any to ($ext_if) port 22 \ flags S/SA keep state (max-src-conn-rate 3/60, overload <ssh-bruteforce> flush global)
Для проверки правил:
pfctl -nf /etc/pf.conf
а потом для их применения:
pfctl -f /etc/pf.conf
Посмотреть содержимое любой таблицы можно так:
/sbin/pfctl -t ssh-bruteforce -T show
Для удаления определенного IP-адреса:
/sbin/pfctl -t ssh-bruteforce -T delete IP
Для полной очистки таблицы:
/sbin/pfctl -t ssh-bruteforce -T flush
Если нет желания блокировать IP-адреса в таблице ssh-bruteforce до следующей перезагрузки сервера, то ее можно очищать вручную с помощью посторонних утилит (security/expiretable) либо средствами самого PF (pfctl). Критерием удаления записей в таблице служит время, прошедшее после их занесения в нее.
Для автоматического очищения таблицы от записей «старше» двух часов каждый час нужно добавить в задачи пользователя root следующую строку (crontab -e):
* */1 * * * /usr/local/sbin/expiretable -t 7200 ssh-bruteforce
или же
* */1 * * * /sbin/pfctl -t ssh-bruteforce -T expire 7200