====== DPI из подручных материалов ======
* [[https://habr.com/ru/articles/813799/|DPI из подручных материалов]]
Всем привет!
Однажды, много лет назад, во времена эпидемии вируса [[https://ru.wikipedia.org/wiki/Code_Red|Code Red]], я работал сисадмином в одном вузе и невежливо ответил на электронное письмо из какого то-банка с требованием немедленно прекратить атаку на их веб сервер, работающий под управлением Apache, через месяц пришло бумажное письмо от их службы безопасности, и завертелось. Так я познакомился с системой [[https://ru.wikipedia.org/wiki/Snort|Snort]], которая некоторое время защищала Интернет от наших студентов. Со временем, большая часть трафика стала https, и решение потеряло смысл, но, есть места, где он снова превращается в http, например после https прокси. Тут то мы и сможем его "подсмотреть", выявить атаки и заблокировать злоумышленника!
Что бы было интереснее, не будем рассматривать [[https://youtu.be/oIczkkD-hOU?si=tb7ucLRAdH2rbSVL|реальный кейс]], а воспроизведем все "в домашних условиях". На единственной системе развернем https прокси, веб приложение за ним, и защитим от атак на основе анализа содержимого http запросов. Потребуется VirtualBox (или любой другой гипервизор) и дистрибутив Linux, например Ubuntu, там Snort имеется в виде пакета. Можно взять мой готовый ova образ:
https://val.bmstu.ru/unix/img/My%20Documents/ubuntu_24.04_01.ova
и выполнить 1-й шаг из [[https://habr.com/ru/articles/716454/|этой статьи]]
===== Шаг 2. Разворачиваем http приложение =====
Можно развернуть [[https://youtu.be/ykWLHQ2i_8E?si=VBVfi9w-vhl_bGDg|что-нибудь поинтереснее]], но, сути это не меняет, поэтому обойдемся простым вариантом:
$ 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 приложение готово!
===== Шаг 2. Создаем сертификат для https прокси =====
Для "игрушечного" примера подойдет само подписанный сертификат 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 адресу)
===== Шаг 3. Разворачиваем https прокси =====
В качестве 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_адрес_виртульной_машины/ правда, браузер будет ругаться на сертификат и придется "перейти на сайт небезопасно"
===== Шаг 4. Разворачиваем IDS Snort =====
# 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
===== Шаг 5. Превращаем IDS в IPS =====
Теперь в журнале поваляются адреса клиентов, сигнатуры пакетов которых попадают в правила 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: .*
# 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
Спасибо что дочитали, надеюсь было интересно, буду рад ответить на вопросы!