Часть I содержит: общие сведения о suricata; требования к железу; описание режимов работы; описание, характеристики и возможности nDPI; описание движков.
Часть II содержит: установка suricata из исходных кодов.
Часть III содержит: подготовка к запуску и запуск suricata.
Часть IV содержит: примеры просмотра данных eve.json в консоли; просмотр лога, алертов и дропов через web-интерфес; простой пример использования suricata - блокировка торрентов; контроль работоспособности и используемых ресурсов.
Часть VI содержит: обзор бесплатных источников правил; использование правил; пример конфиг-файла suricata.yaml.
В части V будет рассмотрено:
12. Подготовка к использованию.
12.1 Исключение легитимного трафика из проверок.
12.2 Исключение доверенных сайтов из проверок.
12.3 Исключение правил проверок IP-адресов.
12.4 Создание задания на обновление правил.
12. Подготовка к использованию.
Необходимо правилами nftables исключить из проверки трафик от клиентов локальной сети на роутер и обратно для ssh, http и других локальных сервисов, как описано в части III в пункте «7.10 Перенаправление трафика в suricata».
12.1 Исключение легитимного трафика из проверок.
Правила загружаются в том порядке, в котором они указаны в файлах. Но обрабатываются они в порядке указанном в параметре ‘action-order’, который определяет приоритет действий при обработке трафика. Если пакет попадает под условия сразу нескольких правил (например, одно говорит «пропустить», а другое — «заблокировать»), движок выберет то действие, которое стоит выше в этом списке. Проверьте не изменен ли в вашем конфиг-файле порядок обработки правил. Если параметра 'action-order' в suricata.yaml нет, то порядок обработки будет установлен по умолчанию: 'pass', 'drop', 'reject', 'alert', как нам и надо. Данная очередность обработки означает следующее:
Первым делом пришедшие данные проверяются правилами с действием ‘pass’. Это своего рода «белый список». ‘pass’ применяется ко всему потоку (flow). Если правило сработало на первом пакете, остальные пакеты этого соединения пройдут без проверки. Данные проверяются до первого совпадения. Если данные попали под условие в правиле ‘pass’, то они пропускаются и остальные проверки над данными не выполняются. По умолчанию правила ‘pass’ не генерируют записи в fast.log или eve.json в секции alerts, так как они считаются «безопасными» (оповещение не выводится).
Если совпадений с правилами ‘pass’ не было, то данные проверяются правилами с действием ‘drop’. Данные проверяются до первого совпадения. Если данные попали под условие в правиле ‘drop’, то они уничтожаются и больше проверки над данными не выполняются. Оповещение выводится.
Для правил с действиями ‘reject’ выполняется все тоже самое что и для правил с действиями ‘drop’ плюс отправителю данных отправляется ответный пакет (ICMP Port Unreachable или TCP RST), сообщающий, что соединение закрыто.
Если данные не попали под все предыдущие действия, то для них выполняются проверки правилами с действиями ‘alert’. Данные проверяются на совпадение с каждым правилом ‘alert’. Оповещения выводятся на каждое совпадение. Однако максимальное количество оповещений, которые могут быть сгенерированы для проверяемого пакета данных, ограничивается параметром
'packet-alert-max' вsuricata.yaml .
Порядок (pass -> drop -> reject -> alert) является стандартным и самым безопасным для режима IPS (предотвращение вторжений). Он позволяет сначала исключить доверенный трафик, затем убить вредоносный и только потом логировать всё остальное. Для исключения трафика из проверок мы будем использовать действие ‘pass’.
Убедитесь, что в вашем конфиг-файле suricata.yaml файл /etc/suricata/rules/local.rules указан первым:
rule-files: - /etc/suricata/rules/local.rules - /var/lib/suricata/rules/suricata.rules
Нет смысла проверять всеми правилами suricata трафик, вызывающий доверие. Такой трафик целесообразно исключить из проверок.
Посмотрите какие протоколы у вас используются чаще всего:
jq -r 'select(.ndpi.proto != null) | .ndpi.proto' /var/log/suricata/eve.json | sort | uniq -c | sort -nr | head -n 20
Создайте правила для обхода проверок легитимных протоколов в файле /etc/suricata/rules/local.rules. Следите, чтобы номера правил (sid) были уникальными. Список nDPI протоколов приведен в части I в пункте «4. Описание, характеристики и возможности nDPI». Например:
pass ip any any -> any any (msg:"Windows Update Protocol"; ndpi-protocol:WindowsUpdate; sid:1000003; rev:1;) pass ip any any -> any any (msg:"Microsoft Protocol"; ndpi-protocol:Microsoft; sid:1000004; rev:1;) pass ip any any -> any any (msg:"Google Protocol"; ndpi-protocol:Google; sid:1000005; rev:1;) pass ip any any -> any any (msg:"GoogleServices Protocol"; ndpi-protocol:GoogleServices; sid:1000006; rev:1;) pass ip any any -> any any (msg:"Yandex Protocol"; ndpi-protocol:Yandex; sid:1000007; rev:1;)
Протестируйте приведенные изменения и перезагрузите новые правила:
sudo suricata -T --user suricata --group suricata suricatasc -c ruleset-reload-nonblocking
Если сомневаетесь и хотите убедиться, что написанные правила действительно определят необходимые вам протоколы, то измените действие 'pass' на 'alert', поскольку действие 'pass'не выводит оповещений. И посмотрите полученные оповещения в evebox или в консоли:
tail -f /var/log/suricata/fast.log
12.2 Исключение доверенных сайтов из проверок.
Нет смысла проверять всеми правила suricata трафик, с сайтов вызывающих доверие. Не может быть никаких угроз на сайтах microsoft, nvidia, suricata, debian и т.д, поэтому проверка трафика с данных сайтов будет пустой тратой ресурсов.
Реализовать исключение сайтов из проверок можно направив трафик на данные сайты через прокси, и исключить из проверок трафик отправляемый на прокси и обратно. Примеры настройки прокси и iptables/nftables для решения такой задачи можно легко найти в сети. Поэтому данные настройки я описывать не буду.
Для пропуска проверок доверенных сайтов я приведу пример использования возможностей самой suricata - механизм 'datasets', реализованный разработчиками для работы с огромными списками данных (десятками и сотнями тысяч элементов), без существенного замедления системы. Использование данного механизма позволяет выполнить исключение из проверок содержимого набора данных одним правилом.
Существует 2 вида наборов данных:
Статические. Определяются с помощью параметра
'load'. При старте программы или перезагрузке правил загружаются из файла. Предполагается, что они не будут изменяться во время выполнения. Для изменения набора необходимо изменить данные содержащиеся в файле. Для применения изменений необходимо перезагрузить правила. Прав на чтение файла с набором данных достаточно для работы suricata.Динамические. Определяются с помощью параметров
'state'или'save'. При старте программы загружаются из файла. При перезагрузке правил динамические наборы данных не изменяются. Операции изменения набора данных выполняются через сокет управления и применяются немедленно. Измененный набор записывается в файл при нормальном завершении работы suricata или по команде'dataset-dump'. Suricata должна иметь права на чтение и запись в файл набора данных.
Будем использовать динамический набор, т.к. это будет гораздо удобнее - изменения будут применяться немедленно и не нужно будет перезагружать правила.
Добавьте в конфиг-файл /etc/suricata.yaml определение и настройки нашего набора данных в существующий параметр 'datasets:':
datasets: domains-wl: type: string state: domains_wl.b64
domains-wl: - определяет имя набора данных.
type: string - определяет тип набора данных. Для типа 'string' каждый элемент данных должен быть представлен в виде хэша base64 а не строки! (Оцените юмор разработчиков.)
state: domains_wl.b64 - определяет файл с набором данных. Будет создан при запуске, обычно в /var/lib/suricata/data.
Создайте 2 файла:
sudo -u suricata -g suricata touch /var/lib/suricata/data/domains.txt sudo -u suricata -g suricata touch /var/lib/suricata/data/domains_black.txt
domains.txt - будет содержать те же самые домены, которые добавлены в domains_wl.b64 только в строковом виде (облегчит управление).
domains_black.txt - будет содержать домены, в благонадежности которых вы сомневаетесь (черный список) или не можете их проверить сейчас (анализ отложен на потом).
Хоть suricata и не дает добавлять в набор дублирующие записи, но эти файлы значительно облегчат управление набором данных и избавят от лишней работы.
Добавьте в самое начало файла /etc/suricata/rules/local.rules правила для пропуска трафика:
pass tls any any -> any any (msg:"TLS Whitelist Domain Detected"; tls.sni; domain; dataset:isset, domains-wl; sid:1000008; rev:1;) pass quic any any -> any any (msg:"QUIC Whitelist Domain Detected"; quic.sni; domain; dataset:isset, domains-wl; sid:1000009; rev:1;) pass http any any -> any any (msg:"HTTP Whitelist Domain Detected"; http.host; domain; dataset:isset, domains-wl, type string; sid:1000010; rev:1;)
tls, quic, http - будем анализировать данные этих протоколов на совпадение с именами доменов.
tls.sni, quic.sni, http.host - буферы соответствующих протоколов. Предоставляют данные доменного имени.
dataset:isset, domains-wl - проверять данные предоставленные буфером протокола на присутствие в наборе domains-wl.
domain - специальный механизм преобразования (Transformations), который изменяет доменное имя, предоставленное буфером протокола, так, чтобы осталось только имя основного домена, например: "mail.ru". (Т.е. удаляет поддомены). Благодаря этому преобразованию правило «поймает» трафик не только от mail.ru, но и от всех его поддоменов. Без использования механизма domain пришлось бы прописывать в наборе данных все имена поддоменов, поскольку suricata требует строгого соответствия при сравнении.
Протестируйте приведенные изменения и перезагрузите suricata:
sudo suricata -T --user suricata --group suricata sudo systemctl restart suricata
Посмотрите топ 10 адресов доменов к которым чаще всего обращались пользователи:
jq -r 'select(.event_type=="tls" or .event_type=="quic" or .event_type=="http") | (.tls.sni // .quic.sni // .ndpi.domainame)' /var/log/suricata/eve.json{,.1} | grep -vE '^[0-9.]+$|^[0-9a-f:]+$' | grep -v null | rev | cut -d'.' -f1-2 | rev | sort | uniq -c | sort -nr | head -n 10
Для записи имен доменов в набор данных используйте правильную команду:
неправильно: echo mail.ru | base64 # bWFpbC5ydQo= - включает символ перевода строки и никогда не даст совпадения. правильно: echo -n mail.ru | base64 # bWFpbC5ydQ==
Добавьте в набор данных domains-wl записи для доменов, которым вы доверяете, например, mail.ru:
d="mail.ru"; suricatasc -c "dataset-add domains-wl string `echo -n $d | base64`"; \ echo $d >> /var/lib/suricata/data/domains.txt
Посмотреть наличие записи для домена в наборе данных:
suricatasc -c "dataset-lookup domains-wl string `echo -n mail.ru | base64`"
Удалить элемент из набора данных:
d="mail.ru"; suricatasc -c "dataset-remove domains-wl string `echo -n $d | base64`"; \ sed -i "/^$d$/d" /var/lib/suricata/data/domains.txt
Сохранить данные набора в файл. Выполняйте всегда после окончания изменений набора данных.
suricatasc -c "dataset-dump domains-wl"
Проверить, что в dataset столько же строк что и в файле с именами доменов.
wc -l /var/lib/suricata/data/domains.txt /var/lib/suricata/data/domains_wl.b64
Декодировать записи набора данных из /var/lib/suricata/data/domains_wl.b64:
while read line; do echo "$line" | base64 -d; echo; done < /var/lib/suricata/data/domains_wl.b64 | sort
Не записывайте хэши имен доменов в файл /var/lib/suricata/data/domains_wl.b64, т.к. suricata перезапишет его при завершении работы. Если вы хотите воспользоваться чьим-то готовым файлом, то вы должны: остановить suricata; скопировать файл; установить владельца suricata; дать права на чтение и запись; запустить suricata.
Для облегчения добавления данных в набор предлагаю воспользоваться скриптами:
suricata_domains_get - Запускается первым. Получает данные о именах доменов всех посещенных пользователями сайтов, сортирует их по количеству посещений и записывает в /tmp/domains_tmp.txt. Затем из файла domains_tmp.txt выбирает только те записи, которых нет в файлах /var/lib/suricata/data/domains.txt и /var/lib/suricata/data/domains_black.txt и записывает их в /tmp/domains.txt. Ваша задача оставить в файле /tmp/domains.txt только те записи, которые будут добавлены в набор. (Цифры удалять не нужно. В файле должно остаться 2 колонки.) Если вы сомневаетесь в добропорядочности каких-то доменов или не можете их проверить сейчас, то перенесите их имена в файл domains_black.txt и удалите их из файла /tmp/domains.txt. Или просто удалите, тогда они опять будут помещены в /tmp/domains.txt в следующий раз.
suricata_domains_put - Запускается вторым. Скрипт записывает имена доменов из файла /tmp/domains.txt в /var/lib/suricata/data/domains.txt (текст) и в используемый dataset (base64). Может записывать в статический dataset /etc/suricata/rules/domains_wl.b64 или в динамический через сокет. Выберите в какой dataset будете сохранять имена доменов. Вывод в другой dataset отключите.
suricata_domains_get
#!/usr/bin/bash # 20260429 # В файле /var/lib/suricata/data/domains.txt хранятся в текстовом формате # имена доменов добавленных в dataset domains-wl по 1 имени на строку. # В файле /var/lib/suricata/data/domains_black.txt хранятся в текстовом формате # имена сомнительных доменов или тех с которыми некогда разбираться. # Скрипт записывает в /tmp/domains.txt домены, которых нет в файлах # /var/lib/suricata/data/domains.txt и /var/lib/suricata/data/domains_black.txt # # После отработки скрипта отредактируйте /tmp/domains.txt - # оставьте в файле только те домены, которым доверяете. # Поместите в /var/lib/suricata/data/domains_black.txt сомнительные # домены или те с которыми нет времени разбираться и удалите # их из /tmp/domains.txt. # # В /tmp/domains.txt должны остаться только те домены, которые будут # добавлены в dataset domains-wl. # /usr/bin/jq -r 'select(.event_type=="tls" or .event_type=="quic") | (.tls.sni // .quic.sni // .ndpi.domainame)' /var/log/suricata/eve.json{,.1} | /usr/bin/grep -vE '^[0-9.]+$|^[0-9a-f:]+$' | /usr/bin/grep -v null | /usr/bin/rev | /usr/bin/cut -d'.' -f1-2 | /usr/bin/rev | /usr/bin/sort | /usr/bin/uniq -c | /usr/bin/sort -nr > /tmp/domains_tmp.txt > /tmp/domains.txt if [ ! -s "/var/lib/suricata/data/domains.txt" ]; then /usr/bin/touch /var/lib/suricata/data/domains.txt #/usr/bin/chown suricata:suricata /var/lib/suricata/data/domains.txt fi if [ ! -s "/var/lib/suricata/data/domains_black.txt" ]; then /usr/bin/touch /var/lib/suricata/data/domains_black.txt #/usr/bin/chown suricata:suricata /var/lib/suricata/data/domains_black.txt fi # Читаем /tmp/domains_tmp.txt, берем вторую колонку и проверяем while read -r line; do # Извлекаем домен (второе слово в строке) domain=$(/usr/bin/echo "$line" | /usr/bin/awk '{print $2}') # Если домена НЕТ в /var/lib/suricata/data/domains.txt и в /var/lib/suricata/data/domains_black.txt if ! /usr/bin/grep -qxF "$domain" /var/lib/suricata/data/domains.txt && ! /usr/bin/grep -qxF "$domain" /var/lib/suricata/data/domains_black.txt; then /usr/bin/echo "$line" >> /tmp/domains.txt fi done < /tmp/domains_tmp.txt /usr/bin/cat /tmp/domains.txt
suricata_domains_put
#!/usr/bin/bash # 20260429 # Выберите в какой dataset будете сохранять домены. # Вывод в другой dataset отключите. # # Скрипт записывает все домены из файла /tmp/domains.txt # в /var/lib/suricata/data/domains.txt (текст) и # в используемый dataset (base64). # /usr/bin/awk '{print $2}' /tmp/domains.txt | while read domain; do # Сохраняем в текстовый файл. /usr/bin/echo "$domain" >> /var/lib/suricata/data/domains.txt # Сохраняем в файл статического dataset. # /usr/bin/echo -n "$domain" | /usr/bin/base64 >> /etc/suricata/rules/domains_wl.b64 # Отправляем через сокет в динамический dataset. /usr/bin/suricatasc -c "dataset-add domains-wl string `echo -n $domain | base64`" > /dev/null /usr/bin/echo "Добавлено: $domain" done /usr/bin/sleep 1 # Отключите если используете /etc/suricata/rules/domains_wl.b64 # Делаем сброс данных из dataset в файл, чтобы при некорректном завершении # работы suricata данные не потерялись. /usr/bin/suricatasc -c "dataset-dump domains-wl" # Сортируем файл с именами доменов для удобства. /usr/bin/sort -u /var/lib/suricata/data/domains.txt -o /var/lib/suricata/data/domains.txt # Проверяем, что файлы соответствуют по количеству записей. /usr/bin/wc -l /var/lib/suricata/data/domains.txt /var/lib/suricata/data/domains_wl.b64 > /tmp/domains.txt
12.3 Исключение правил проверок IP-адресов.
Suricata использует правила от различных составителей. Составители объединяют правила в логические группы, указывая это в поле 'msg' правила. Например, "ET CINS" - правила от источника ET/OPEN, группа CINS. Некоторые группы правил содержат проверки доступа к неблагонадежным IP-адресам и диапазонам IP-сетей:
Источник - et/open:
"ET CINS" - содержит 299 правил, включающих 14902 IP-адресов. Список известных вредоносных IP-адресов, сформированный на основе данных сообщества и систем обнаружения вторжений.
"ET CNС" - 5 правил, 5 IP-адресов. Список IP-адресов с признаками работы вирусов, троянов и бэкдоров.
"ET COMPROMISED" - 13 правил, 390 IP-адресов. Список ресурсов, которые были взломаны злоумышленниками. Содержит легитимные серверы и сайты, на которых размещено вредоносное ПО или которые используются как C2-серверы (командные центры). Список очень динамичный. Как только владелец очищает свой сервер, IP удаляется из списка.
"ET DROP" - 65 правил, 1295 диапазонов сетей. Список диапазонов вредоносных сетей от старейшего источника spamhaus.org, составленный на основе репутации и данных отчетов безопасности. Вот как описывают данный список владельцы ресурса: «Список DROP содержит диапазоны IP‑адресов, настолько опасные для пользователей интернета, что spamhaus предоставляет его любому желающему бесплатно». И рекомендуют «отбрасывать весь трафик, содержащий указанные диапазоны IP‑адресов». Обновляет свои данные не чаще, чем 1 раз в час. Блокирует назойливых клиентов, которые скачивают список чаще необходимого.
"ET Threatview.io" - 22 правила, 1052 IP-адресов. Список IP-адресов, связанных с конкретными хакерскими группировками.
Источник - etnetera/aggressive:
"ETN AGGRESSIVE" - 14 правил, 416 IP-адресов. Список IP-адресов от проекта Emerging Threats (ET Open). Выделен в отдельный источник для suricata-update. Содержит адреса, которые были замечены в агрессивном поведении: сканировании портов, попытках подбора паролей или активном распространении вредоносного ПО в последние часы или дни. Это очень динамичный список. IP-адрес попадает туда быстро и так же быстро удаляется, если агрессия прекратилась.
Итого: 418 правил с проверками 18060 адресов и сетей. Значения могут меняться, так как данные изменяются, и приведены для понимания количества адресов и сетей используемых для блокировки.
Такое большое количество адресов в правилах создаст большую нагрузку на ресурсы сервера при проверке трафика. Самым дешевым способом блокировки, по используемым ресурсам, будет использование nftables. Поскольку списки вредоносных адресов и сетей создаются и контролируются заслуживающими доверия организациями, то я предпочитаю их заблокировать, а потом уже, при необходимости, разбираться. Если вы придерживаетесь другого мнения, то можете оставить все как есть и пропустить данный пункт.
Чтобы использовать nftables для блокировки вредоносных адресов и сетей необходимо создать таблицу, цепочки, набор для данных и правила блокировки. Cамый эффективный способ блокировки черных списков - размещение блокировки в цепочке ingress таблицы netdev. Тогда блокировка срабатывает сразу после того, как пакет поступил с сетевой карты и ещё до того, как ядро начнет тратить ресурсы на обработку IP-стека. Это обеспечивает максимальную производительность - пакет сбрасывается на самом раннем этапе и экономию ресурсов - ядро не тратит время на поиск маршрута, проверку таблиц conntrack или работу с IP-заголовками.
Вы можете не выполнять приведенные команды, а взять вывод команды 'sudo nft -s list table netdev filter', выполненный после создания всего необходимого и поместить в /etc/nftables.conf. Затем обязательно протестируйте полученную конфигурацию: 'sudo nft -cf /etc/nftables.conf'.
Создадим таблицу:
sudo nft create table netdev filter
Создадим цепочки. 'lan' и 'wan' - имена сетевых интерфейсов, которые соответственно смотрят в локальную сеть и интернет.
sudo nft add chain netdev filter ingress_wan { type filter hook ingress device "wan" priority -500 \; policy accept \; } sudo nft add chain netdev filter ingress_lan { type filter hook ingress device "lan" priority -500 \; policy accept \; }
Создадим набор 'blacklist' для IP-адресов v4 (type ipv4_addr), в который могут записываться диапазоны IP-адресов (flags interval) и с возможностью автоматического объединения ядром смежных/перекрывающихся элементов множества (auto-merge). Без 'auto-merge' появление дублирующего IP-адреса или IP-адреса принадлежащего интервалу IP-адресов или наличие смежных/перекрывающихся диапазонов IP-адресов вызовет ошибку при тестировании набора и его загрузке.
sudo nft add set netdev filter blacklist { type ipv4_addr\; flags interval\; auto-merge\; }
Создаем правила, блокирующие IP-адреса, входящие в набор 'blacklist', со счетчиком, показывающим сколько раз была выполнена блокировка данных (counter) и выдачей сообщения о блокировке в журнал (log prefix NFT_BL):
sudo nft add rule netdev filter ingress_wan iifname "wan" ip saddr @blacklist counter log prefix NFT_BL drop sudo nft add rule netdev filter ingress_lan iifname "lan" ip daddr @blacklist counter log prefix NFT_BL drop
Проверяем что получилось:
sudo nft -s list table netdev filter table netdev filter { set blacklist { type ipv4_addr flags interval auto-merge } chain ingress_wan { type filter hook ingress device "wan" priority -500; policy accept; iifname "wan" ip saddr @blacklist counter log prefix "NFT_BL " drop } chain ingress_lan { type filter hook ingress device "lan" priority -500; policy accept; iifname "lan" ip daddr @blacklist counter log prefix "NFT_BL " drop } }
Сохраняем текущие настройки nftables в конфиг-файл /etc/nftables.conf:
sudo mv -i /etc/nftables.conf /etc/nftables_`date +%Y%m%d-%H%M`.conf sudo sh -c '/usr/bin/echo "#!/usr/sbin/nft -f" > /etc/nftables.conf' sudo sh -c '/usr/bin/echo "flush ruleset" >> /etc/nftables.conf' sudo sh -c '/usr/sbin/nft -s list ruleset >> /etc/nftables.conf' sudo /usr/bin/chmod +x /etc/nftables.conf
Редактируем /etc/nftables.conf и вставляем в наборе 'blacklist' после 'auto-merge' новую строку 'include "/etc/nftables/blacklist.ip"'. Это позволит при старте nftables загружать список адресов и сетей из файла '/etc/nftables/blacklist.ip' и не засорять ими основной конфиг-файл nftables. Должно получиться:
set blacklist { type ipv4_addr flags interval auto-merge include "/etc/nftables/blacklist.ip" }
Создаем файл /etc/nftables/blacklist.ip и конфиг-файл /etc/nftables/blacklist.conf. Помещаем в /etc/nftables/blacklist.conf настройки набора ‘blacklist’. Это облегчит тестирование и загрузку созданного набора.
sudo mkdir /etc/nftables sudo touch /etc/nftables/blacklist.ip sudo nano /etc/nftables/blacklist.conf
В /etc/nftables/blacklist.conf должно быть определение набора 'blacklist' один в один как в конфиг-файле /etc/nftables.conf плюс определение таблицы в которой он создан:
table netdev filter { set blacklist { type ipv4_addr flags interval auto-merge include "/etc/nftables/blacklist.ip" } }
Проверяем конфиг-файлы /etc/nftables/blacklist.conf и /etc/nftables.conf на отсутствие ошибок:
sudo nft -c -f /etc/nftables/blacklist.conf sudo nft -c -f /etc/nftables.conf
Создание списка вредоносных адресов и сетей и его загрузку в nftables будем выполнять с помощью скрипта suricata_ip_to_nft. Скрипт скачивает данные напрямую с сайтов, которые их предоставляют, а если это невозможно, то берет их из правил. Скрипт снабжен подробными комментариями и вы можете изменить его под свои нужды. Не запускайте его слишком часто, некоторые сайты блокируют отдачу данных для слишком назойливых адресов. Не прерывайте выполнение скрипта не дождавшись результата, у меня он выполняется примерно минуту.
suricata_ip_to_nft
#!/usr/bin/bash # 20260429 # примеры просмотра сета и таблицы: # nft list set netdev filter blacklist | more # nft list table netdev filter # для работы скрипта требуются: dig, aggregate, grepcidr, proxychains4, jq URL_ET_CINS="https://cinsscore.com/list/ci-badguys.txt" URL_SPAMHAUS="https://www.spamhaus.org/drop/drop_v4.json" URL_ET_THREATVIEW="https://threatview.io/Downloads/High-Confidence-CobaltStrike-C2%20-Feeds.txt" URL_ETN_AGGRESSIVE="https://security.etnetera.cz/feeds/etn_aggressive.txt" # конфиг сета blacklist BLACKLIST_CONF="/etc/nftables/blacklist.conf" # содержимое сета blacklist BLACKLIST_IP="/etc/nftables/blacklist.ip" OUT_DIR="/tmp/blacklist" #sudo -u suricata /usr/bin/suricata-update -q > /dev/null if [ -d "$OUT_DIR" ]; then /usr/bin/rm -f $OUT_DIR/* else /usr/bin/mkdir $OUT_DIR fi # получаем ip адреса, содержащиеся в правилах "ET CINS", с $URL_ET_CINS /usr/bin/curl --connect-timeout 10 --max-time 60 -Ls $URL_ET_CINS -o $OUT_DIR/badguys if [ ! -s "$OUT_DIR/badguys" ]; then /usr/bin/echo "Пиндосы не отдают данные с cinsscore.com. Получаю ip адреса из правил." /usr/bin/grep 'msg:"ET CINS ' /var/lib/suricata/rules/suricata.rules | /usr/bin/grep -Po '\[\K[^\]]+' | /usr/bin/tr ',' '\n' > $OUT_DIR/et_cins fi # получаем ip адреса из правил "ET CNС" /usr/bin/grep 'msg:"ET CNC ' /var/lib/suricata/rules/suricata.rules | /usr/bin/grep -Po -- '->\s+\[?\K[^\]\s]+' > $OUT_DIR/et_cnc # получаем ip адреса из правил "ET COMPROMISED" /usr/bin/grep 'msg:"ET COMPROMISED ' /var/lib/suricata/rules/suricata.rules | /usr/bin/grep -Po '\[\K[^\]]+' | /usr/bin/tr ',' '\n' > $OUT_DIR/compromised # получаем диапазоны ip адресов, содержащиеся в правилах "ET DROP", со www.spamhaus.org /usr/bin/curl --connect-timeout 10 --max-time 60 -Ls $URL_SPAMHAUS -o $OUT_DIR/drop_v4.json if [ ! -s "$OUT_DIR/drop_v4.json" ]; then /usr/bin/echo "Пиндосы не отдают данные со spamhaus.org. Получаю диапазоны сетей из правил." /usr/bin/grep 'msg:"ET DROP ' /var/lib/suricata/rules/suricata.rules | /usr/bin/grep -Po '\[\K[^\]]+' | /usr/bin/tr ',' '\n' > $OUT_DIR/nets.txt else /usr/bin/jq -r 'select(.cidr != null) | .cidr' "$OUT_DIR/drop_v4.json" > $OUT_DIR/nets.txt fi # получаем ip адреса, содержащиеся в правилах "ETN AGGRESSIVE", с $URL_ETN_AGGRESSIVE /usr/bin/curl --connect-timeout 10 --max-time 60 -Ls $URL_ETN_AGGRESSIVE -o $OUT_DIR/aggressive.txt if [ ! -s "$OUT_DIR/aggressive.txt" ]; then /usr/bin/echo "Пиндосы не отдают данные с etnetera.cz. Получаю ip адреса из правил." /usr/bin/grep 'msg:"ETN AGGRESSIVE ' /var/lib/suricata/rules/suricata.rules | /usr/bin/grep -Po '\[\K[^\]]+' | /usr/bin/tr ',' '\n' | /usr/bin/grep -v ":" > $OUT_DIR/aggresive else /usr/bin/cat $OUT_DIR/aggressive.txt | /usr/bin/grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}' > $OUT_DIR/aggresive fi # получаем списки известных вредоносных ip адресов, содержащихся в правилах "ET Threatview.io", с $URL_ET_THREATVIEW # нужен рабочий прокси, т.к. не отдают для России напрямую. /usr/bin/proxychains4 -q /usr/bin/curl --connect-timeout 10 --max-time 60 -Ls $URL_ET_THREATVIEW -o $OUT_DIR/feeds.txt if [ ! -s "$OUT_DIR/feeds.txt" ]; then /usr/bin/echo "Пиндосы не отдают данные с threatview.io. Получаю ip адреса из правил." /usr/bin/grep 'msg:"ET Threatview.io ' /var/lib/suricata/rules/suricata.rules | /usr/bin/grep -Po '\[\K[^\]]+' | /usr/bin/tr ',' '\n' > $OUT_DIR/et_threatview else # обрабатываем файл со списками ip адресов от "ET THREATVIEW" /usr/bin/echo "Обрабатываю сложный файл со списками ip адресов от \"ET THREATVIEW\". ЖДИТЕ!!!" /usr/bin/grep -v '^#' $OUT_DIR/feeds.txt | /usr/bin/cut -d',' -f1 | while read -r host; do if [[ $host =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then /usr/bin/echo "$host" else # Резолвим домен, берем только IPv4 и подавляем ошибки, если домен сдох /usr/bin/dig @8.8.8.8 +short A "$host" 2>/dev/null fi done | /usr/bin/grep -E '^[0-9.]+$' >> $OUT_DIR/feeds fi # убираем пересекающиеся диапазоны сетей из списка www.spamhaus.org /usr/bin/cat $OUT_DIR/nets.txt | /usr/bin/aggregate -p 32 -m 32 -o 32 -t -q > $OUT_DIR/nets_opt.txt # собираем все ip адреса в один файл if [ -s "$OUT_DIR/blacklist.txt" ]; then /usr/bin/echo -n "" > $OUT_DIR/blacklist.txt fi if [ -s "$OUT_DIR/badguys" ]; then /usr/bin/cat $OUT_DIR/badguys >> $OUT_DIR/blacklist.txt fi if [ -s "$OUT_DIR/et_cins" ]; then /usr/bin/cat $OUT_DIR/et_cins >> $OUT_DIR/blacklist.txt fi if [ -s "$OUT_DIR/feeds" ]; then /usr/bin/cat $OUT_DIR/feeds >> $OUT_DIR/blacklist.txt fi if [ -s "$OUT_DIR/et_threatview" ]; then /usr/bin/cat $OUT_DIR/et_threatview >> $OUT_DIR/blacklist.txt fi /usr/bin/cat $OUT_DIR/et_cnc $OUT_DIR/compromised $OUT_DIR/aggresive >> $OUT_DIR/blacklist.txt # сортируем и избавляемся от дубликатов /usr/bin/cat $OUT_DIR/blacklist.txt | /usr/bin/sort -h | /usr/bin/sort -u > $OUT_DIR/blacklist_sort.txt # находим ip адреса непринадлежащие диапазонам сетей от www.spamhaus.org /usr/bin/grepcidr -v -f $OUT_DIR/nets_opt.txt $OUT_DIR/blacklist_sort.txt > $OUT_DIR/blacklist # добавляем адреса сетей к тем адресам, которые не принадлежат данным сетям /usr/bin/cat $OUT_DIR/nets_opt.txt >> $OUT_DIR/blacklist # выводим адреса в конфиг-файл set-а nftables /usr/bin/echo "elements = {" > "$BLACKLIST_IP" /usr/bin/cat $OUT_DIR/blacklist | /usr/bin/sed 's/$/,/' >> "$BLACKLIST_IP" /usr/bin/sed -i '$ s/,$//' "$BLACKLIST_IP" /usr/bin/echo "}" >> "$BLACKLIST_IP" # проверяем корректность набора blacklist if ! /usr/sbin/nft -c -f "$BLACKLIST_CONF" 2>"$OUT_DIR/nft_error.log"; then /usr/bin/echo "Ошибка при проверке набора blacklist! Выход." /usr/bin/cat $OUT_DIR/nft_error.log exit fi /usr/bin/echo -n `/usr/bin/date` "Загружаю новые данные в набор blacklist." /usr/sbin/nft flush set netdev filter blacklist if ! /usr/sbin/nft -f "$BLACKLIST_CONF" 2>"$OUT_DIR/nft_error.log"; then /usr/bin/echo " Ошибка! Выход." /usr/bin/cat $OUT_DIR/nft_error.log exit fi /usr/bin/echo " Успех!" /usr/bin/echo "Всего загружено" `/usr/bin/cat $OUT_DIR/blacklist | /usr/bin/wc -l` "элементов (адресов и диапазонов сетей)." # удаляем промежуточные результаты #/usr/bin/rm -rf $OUT_DIR
Чтобы скрипт мог получать данные из правил "ETN AGGRESSIVE", если сайт источника будет недоступен, включим использование источника 'etnetera/aggressive' (предполагается, что источник 'et/open' у вас уже используется) и обновим списки правил:
sudo -u suricata suricata-update enable-source etnetera/aggressive sudo -u suricata suricata-update --no-reload
Убедимся, что новые правила выключены (закомментированы). Команда выведет не закомментированные правила которые содержат "ETN AGGRESSIVE":
grep "ETN AGGRESSIVE" /var/lib/suricata/rules/suricata.rules | grep -vE "^#"
Установите необходимые программы для работы скрипта:
sudo apt install dnsutils aggregate grepcidr proxychains4 jq
Необходимо настроить /etc/proxychains4.conf, чтобы получать списки "ET THREATVIEW", т.к. их не отдают для пользователей из России. Если вы не можете настроить proxychains4, то просто закомментируйте строку, где она используется, тогда программа возьмет данные из списка правил. Но это не очень хорошее решение, потому что составители правил берут адреса из тех же самых источников и на изменение правил требуется время, т.е. адреса появляются в правилах с задержкой. Плюс в правила их всегда почему-то включают не полностью.
Запускаем скрипт:
sudo suricata_ip_to_nft sudo cat /etc/nftables/blacklist.ip | more sudo nft list set netdev filter blacklist | more sudo nft list table netdev filter | more
Проверяем что получилось в итоге:
sudo cat /etc/nftables/blacklist.ip | more sudo nft list set netdev filter blacklist | more sudo nft list table netdev filter | more
Проверить были ли блокировки адресов, содержащихся в наборе 'blacklist' (смотрите на показания счетчика 'counter'):
sudo nft list chain netdev filter ingress_wan sudo nft list chain netdev filter ingress_lan
Посмотреть кто из клиентов локальной сети был заблокирован:
sudo journalctl | grep NFT_BL | awk '{ print $1, $2, $3, $6, $9, $10, $17, $18, $19 }' | more
Или только для вывода IP адресов:
sudo journalctl | grep NFT_BL | awk '{ print $6, $9, $10 }' | sort -u
Используйте скрипт suricata_ip_check чтобы посмотреть под какое правило блокировки попал IP-адрес или какому списку он принадлежит:
suricata_ip_check
#!/usr/bin/bash #20260430 OUT_DIR="/tmp/blacklist" if [ -z "$1" ]; then /usr/bin/echo "Использование: $0 <IP_адрес>" exit 1 fi if /usr/bin/grep -qF "$1" "/var/lib/suricata/rules/suricata.rules"; then /usr/bin/echo "Найдено в правилах:" /usr/bin/grep "$1" /var/lib/suricata/rules/suricata.rules | grep -Po 'msg:"\K[^"]+' fi if /usr/bin/grep -qxF "$1" "$OUT_DIR/et_cins"; then /usr/bin/echo "$1 найден в списке \"ET CINS\"" fi if /usr/bin/grep -qxF "$1" "$OUT_DIR/et_cnc"; then /usr/bin/echo "$1 найден в списке \"ET CNC\"" fi if /usr/bin/grep -qxF "$1" "$OUT_DIR/et_compromised"; then /usr/bin/echo "$1 найден в списке \"ET COMPROMISED\"" fi if /usr/bin/grep -qxF "$1" "$OUT_DIR/et_threatview"; then /usr/bin/echo "$1 найден в списке \"ET Threatview.io\"" fi if /usr/bin/grep -qxF "$1" "$OUT_DIR/etn_aggressive"; then /usr/bin/echo "$1 найден в списке \"EТN AGGRESSIVE\"" fi if /usr/bin/echo "$1" | /usr/bin/grepcidr -f /tmp/blacklist/et_drop >/dev/null; then /usr/bin/echo "$1 найден в списке подсетей \"EТ DROP\"" fi
Выполните на роутере:
suricata_ip_check 150.171.109.100
Затем на клиенте локальной сети, чтобы понять какой процесс пытался получить доступ к заблокированному IP-адресу (команды PowerShell для windows):
> netstat -ano -p tcp | select-string "150.171.109.100" TCP 192.168.124.1:57736 150.171.109.100:443 SYN_SENT 9892 > Get-Process -Id 9892 | Select-Object Name, Parent, Path
Либо используйте «Диспетчер задач» для поиска процесса с указанным ID.
Если вдруг окажется, что вам все-таки нужен доступ к какому-то IP-адресу из черного списка, то создайте правила для пропуска трафика:
sudo nft insert rule netdev filter ingress_wan iifname "wan" ip saddr 1.1.1.1 accept sudo nft insert rule netdev filter ingress_lan iifname "lan" ip daddr 1.1.1.1 accept
Посмотрите результат:
sudo nft list chain netdev filter ingress_wan sudo nft list chain netdev filter ingress_lan
Теперь, чтобы не включать список адресов набора ‘blacklist’ в основной конфигурационный файл nftables и не засорять его, сохраняйте текущие настройки nftbles скриптом:
nftables_save
#!/usr/bin/bash /usr/bin/mv -i /etc/nftables.conf /etc/nftables_`date +%Y%m%d-%H%M`.conf /usr/bin/echo "#!/usr/sbin/nft -f" > /etc/nftables.conf /usr/bin/echo "flush ruleset" >> /etc/nftables.conf /usr/sbin/nft -st list ruleset >> /etc/nftables.conf /usr/bin/sed -i '/auto-merge/a \\t\tinclude "/etc/nftables/blacklist.ip"' /etc/nftables.conf /usr/bin/chmod +x /etc/nftables.conf /usr/sbin/nft -cf /etc/nftables.conf 2>/dev/null && /usr/bin/echo "Конфиг /etc/nftables.conf протестирован без ошибок." || { /usr/bin/echo "Ошибка тестирования /etc/nftables.conf"; exit 1; }
Убедитесь, что строка 'include "/etc/nftables/blacklist.ip"' вставлена после 'auto-merge' именно в набор 'blacklist'.
Не забудьте, что правила содержащие "ET CINS", "ET CNС", "ET COMPROMISED", "ET DROP", "ET Threatview.io", "ETN AGGRESSIVE" никогда не должны быть активированы.
13.4 Создание задания на обновление правил.
Создадим лог-файл и назначим ему необходимые права и владельцев:
sudo touch /var/log/suricata_ip_to_nft.log sudo chown root:suricata /var/log/suricata_ip_to_nft.log sudo chmod 664 /var/log/suricata_ip_to_nft.log
Используйте скрипт suricata_ip_to_nft для обновления правил и списка вредоносных адресов и сетей. Разрешите в нем запуск suricata-update (строка 18) и закомментируйте все не важные для вас команды вывода сообщений. Создайте запись запуска скрипта в crontab с перенаправлением выводимой информации в лог-файл. Также необходимо создать запись для обновления источников правил. Не забудьте, что файл crontab должен завершаться пустой строкой.
Откройте планировщик командой 'sudo crontab -e' и добавьте строки:
1 */2 * * * /root/scripts/suricata_ip_to_nft >> /var/log/suricata_ip_to_nft.log 2>>/var/log/suricata_ip_to_nft.log 1 1 * * MON /usr/bin/sudo -u suricata /usr/bin/suricata-update update-sources > /dev/null 2>>/var/log/suricata_ip_to_nft.log
Посмотрите результат:
sudo crontab -l
Запуск suricata_ip_to_nft и 'suricata-update update-sources' не должны пересекаться. Источники правил должны обновляться не реже, чем 1 раз в 2 недели.
