Всем привет!
Однажды, много лет назад, во времена эпидемии вируса Code Red, я работал сисадмином в одном вузе и невежливо ответил на электронное письмо из какого то-банка с требованием немедленно прекратить атаку на их веб сервер, работающий под управлением Apache, через месяц пришло бумажное письмо от их службы безопасности, и завертелось. Так я познакомился с системой Snort, которая некоторое время защищала Интернет от наших студентов. Со временем, большая часть трафика стала https, и решение потеряло смысл, но, есть места, где он снова превращается в http, например после https прокси. Тут то мы и сможем его “подсмотреть”, выявить атаки и заблокировать злоумышленника!
Что бы было интереснее, не будем рассматривать реальный кейс, а воспроизведем все “в домашних условиях”. На единственной системе развернем https прокси, веб приложение за ним, и защитим от атак на основе анализа содержимого http запросов. Потребуется VirtualBox (или любой другой гипервизор) и дистрибутив Linux, например Ubuntu, там Snort имеется в виде пакета. Можно взять мой готовый ova образ:
https://val.bmstu.ru/unix/img/My%20Documents/ubuntu_24.04_01.ova
и выполнить 1-й шаг из этой статьи
Можно развернуть что-нибудь поинтереснее, но, сути это не меняет, поэтому обойдемся простым вариантом:
$ sudo -i # apt update # apt install docker.io # docker run --name http-app -d --restart=always httpd # docker inspect http-app -f {{.NetworkSettings.IPAddress}} # curl http://172.17.0.2
http приложение готово!
Для “игрушечного” примера подойдет само подписанный сертификат c атрибутами “по умолчанию”
# openssl genrsa -out /etc/ssl/private/http-app.key 2048 # openssl req -new -x509 -days 3650 -key /etc/ssl/private/http-app.key -out /etc/ssl/certs/http-app.crt
На все “вопросы” последней команды достаточно нажать Enter (даже про Common Name, поскольку тестировать все будем по ip адресу)
В качестве https прокси рассмотрим nginx (можно haproxy, суть не изменится). Поскольку тестировать все будем по ip адресу, настроим перенаправление любых запросов (server_name _) на 443 порт в наше http приложение. X-Forwarded-For в нашем случае нужен потому, что только в этом заголовке будет ip адрес клиента в трафике между https прокси и приложением.
# apt install nginx # nano /etc/nginx/sites-available/http-app
server { listen 443 ssl; server_name _; ssl_certificate /etc/ssl/certs/http-app.crt; ssl_certificate_key /etc/ssl/private/http-app.key; location / { proxy_pass http://172.17.0.2; proxy_set_header X-Forwarded-For $remote_addr; } }
# ln -s /etc/nginx/sites-available/http-app /etc/nginx/sites-enabled/http-app # systemctl restart nginx.service
Теперь наше http приложение должно быть доступно по URL: https://ip_адрес_виртульной_машины/ правда, браузер будет ругаться на сертификат и придется “перейти на сайт небезопасно”
# apt install snort
В вопросах инсталлятора про сетевые интерфейсы указываем docker0, в нашем случае именно через него идет трафик между https прокси и http приложением в контейнере. Остальные ответы “по умолчанию”, результат работы инсталлятора записывается в файл:
# less /etc/snort/snort.debian.conf
... DEBIAN_SNORT_INTERFACE="docker0" ...
В основном файле конфигурации отключаем проверку контрольной суммы пакетов, поскольку эта функциональность актуальна только для “входящего” трафика, а в нашем случае, http трафик будет “выходить” из интерфейса docker0, добавляем опцию анализа заголовка X-Forwarded-For в http трафике и настраиваем вывод сообщений об обнаруженных атаках в syslog с типом сообщений auth и уровнем важности alert:
# nano /etc/snort/snort.conf
... # Configure IP / TCP checksum mode config checksum_mode: none ... preprocessor http_inspect_server: server default \ ... enable_xff \ webroot no ... #################################################################### # Step #6: Configure output plugins ... output alert_syslog: LOG_AUTH LOG_ALERT ...
# systemctl restart snort.service
Для тестирования будем использовать тот самый злополучный Code Red, для которого, как раз, есть правило “из коробки”:
# less /etc/snort/rules/web-iis.rules
... alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (msg:"WEB-IIS CodeRed v2 root.exe access"; flow:to_server,established; uricontent:"/root.exe"; nocase; reference:url,www.cert.org/advisories/CA-2001-19.html; classtype:web-application-attack; sid:1256; rev:8;) ...
Симулировать атаку можно обращаясь к нашему приложению по URL: https://ip_адрес_виртульной_машины/root.exe
В журнале должны появляться характерные сообщения:
# tail -f /var/log/auth.log
... 2024-05-12T18:06:07.467018+00:00 ubuntu snort[6978]: [1:1256:8] WEB-IIS CodeRed v2 root.exe access [Classification: Web Application Attack] [Priority: 1] {TCP} 172.17.0.1:40890 -> 172.17.0.2:80 ...
Но, стоп, в них отсутствует адрес клиента, здесь только адрес прокси и самого приложения!
Оказывается, информация из заголовка X-Forwarded-For попадает в двоичный файл, для анализа которого авторы Snort добавили специальную утилиту:
# u2spewfoo /var/log/snort/snort.alert
... priority: 1 ip source: 172.17.0.1 ip destination: 172.17.0.2 ... type: 1 datatype: 1 bloblength: 12 Original Client IP: 192.168.1.100 ...
Этот файл создается и непрерывно растет с момента запуска Snort, а утилита умеет выводить его только целиком. Для нашей следующей задачи будет удобнее, если полученная таким образом информация будет тоже последовательно писаться в журнал. Пришлось “сочинить” такого “крокодила” (ключи -с +1 команды tail из-за двоичного формата файла, u2spewfoo не умеет читать из STDIN, stdbuf отключает буферизацию ввода и вывода, logger все пишет в syslog от имени приложения snort с типом сообщений auth и уровнем важности info):
# stdbuf -i0 -o0 u2spewfoo <(tail -c +1 -f /var/log/snort/snort.alert) | logger -t snort -p auth.info
В журнале теперь будут появляться такие сообщения (понадобится вторая консоль):
# tail -f /var/log/auth.log
... 2024-05-12T18:16:25.965360+00:00 ubuntu snort: #011type: 1#011datatype: 1#011bloblength: 12#011Original Client IP: 192.168.1.100 ...
Можно оформить запуск “крокодила” через systemd
# nano /etc/systemd/system/snort-alert-unified2-syslog.service
[Unit] Description=Send snort alert_unified2 to syslog After=snort.service [Service] ExecStart=/bin/bash -c '/usr/bin/stdbuf -i0 -o0 /usr/sbin/u2spewfoo <(/usr/bin/tail -c +1 -f /var/log/snort/snort.alert) | /usr/bin/logger -t snort -p auth.info' [Install] WantedBy=multi-user.target
# systemctl enable snort-alert-unified2-syslog --now
Теперь в журнале поваляются адреса клиентов, сигнатуры пакетов которых попадают в правила Snort (с правилами все печально, Snort принадлежит Cisco, были платные подписки или бесплатно с месячной задержкой, теперь только Community rules, в составе пакета, ну, и, можно писать свои)
Для чтения журнала и блокировки злоумышленников будем использовать fail2ban
Вообще, он ставится командой:
# apt install fail2ban
но, на текущий момент (май 2024) в 24-й ubuntu он не работает (надеюсь, починят) и приходится устанавливать его так:
# wget https://launchpad.net/ubuntu/+source/fail2ban/1.1.0-1/+build/28291332/+files/fail2ban_1.1.0-1_all.deb # dpkg -i fail2ban_1.1.0-1_all.deb
В любом случае, конфигурация выглядит так:
# nano /etc/fail2ban/filter.d/snort_filter.conf
[Definition] failregex = .*Original Client IP: <HOST>.*
# nano /etc/fail2ban/jail.d/snort_jail.conf
[snort] enabled = true bantime = 300 filter = snort_filter maxretry = 3 logpath = /var/log/auth.log action = iptables-allports
# systemctl restart fail2ban.service
Вот тут я “забанил” сам себя и потерял history команд при подготовке статьи, так что лучше продолжать “атаки” с другого домашнего устройства, например с телефона :)
https://ip_адрес_виртульной_машины/root.exe
В журнале можно наблюдать реакцию fail2ban на “атаки”:
# tail -f /var/log/fail2ban.log
А также снять блокировку:
# fail2ban-client status snort # fail2ban-client set snort unbanip <IP>
Спасибо что дочитали, надеюсь было интересно, буду рад ответить на вопросы!