Здравствуйте!

В данной статье мы рассмотрим пример реализации шлюза вэб фильтрации на базе ПО с открытым исходным кодом (стек Apache/ModSecurity/OWASP CRS/ProjectHoneyPot).

Посмотрим как это все объединить в одно целое. Где взять и как подгрузить сигнатуры. Как отладить (дефолтные конфигурации — не наш метод). В процессе напишем пару дополнительных правил, наступим на грабли, найдем что‑то похожее на изящный выход из ситуации. Узнаем как собирать статистику о ботах и как от них защититься.

В мой изначальный план так же входили Snort и защита от распределенных атак, но заглянув в мануал снорта стало понятно, что там дело не одной и думаю не пары недель (тем более очень хотелось бы разобраться с кастомными сигнатурами). Так что можете рассматривать эту статью как первую в своем цикле.

Штош,приступим!

UPDATE

Вижу, что в карму сыпятся минусы - очевидно что-то идет не так (есть некая вероятность, что это будет последняя публикация)

Поэтому позволю себе добавить опрос на тему "А нужен ли здесь такого рода контент ?" Буду благодарен если вы поможете во всем разобраться.

Спасибо

Введение

Для начала отвечу на один из главных вопросов — почему OpenSource? — Все просто, можно взять F5, Imperva, есть решения и у Fortinet, и у Check Point, и у Palo. Конечно же есть решения Российских вендоров. Взять‑то конечно можно, но вот доступ к таким технологиям имеет лишь не самая большая аудитория. По этой причине рассматриваем OpenSource

Очень актуальный сегодня вопрос согласования с ИБ оставим за скобками. Риски, как ни крути присутствуют и я бы 10 раз подумал (и отказался) прежде чем реализовывать нечто подобное для защиты критической инфраструктуры.

В то же время, данное решение может подойти малому бизнесу и энтузиастам в ИТ. Ведь сколько у нас приложений опубликовано в сеть с минимальной фильтрацией? А сколько из них обновляется?

И так, что же такое WAF?

В первую очередь — фаерволл, с функциями несколько отличающимися от типичного NGFW. Шлюзы вэб фильтрации, как несложно было бы догадаться, призваны защищать вэб приложения потенциально уязвимые к внешним атакам.

Вендорские решения охватывают несколько больший функционал. Как правило это:

  • Анализ трафика приложения облегчающий составление политик фильтрации

  • Фильтрация OWASP сигнатурами (защита от XSS, SQL инджектов, анализ HTTP заголовков, защита от известных уязвимостей нулевого дня и так далее)

  • Защита от ботов

  • Некоторые вендоры в довесок предоставляют функционал NGFW. Здесь вам и песочница, и IPS, и защита от вредоносного ПО. Все стандартно.

  • Так же встречаются WAF с функцией балансировщика

Что из этого мы можем реализовать? — Многое. Придется ли при этом страдать изобретая велосипед? — Несомненно

  • Анализ, репорты? Только своими руками. Можно (и даже нужно) конечно логи перенаправлять в SIEM именно с этой целью

  • OWASP? Ну, да. Никаких вам графических интерфейсов и только хардкор

  • Детекция приложений? Теоретически тоже да. Здесь придется писать собственные сигнатуры

  • Защита от ботов? В какой‑то мере.

Понятно конечно, что вендор и с сапортом поможет, и связан юридическими обязательствами, и потенциальный бэкдор ему в репозиторий сложнее залить, да и функционал как правило шире. Все это понятно.

Но в общеобразовательных целях мы будем рассматривать OpenSource

ModSecurity

ModSecurity есть ничто иное как кросс‑платформенный модуль шлюза вэб фильтрации для вэб сервера. Поддерживается как Apache, так и Nginx. Может выполнять фильтрацию своими силами, а может использовать сигнатуры OWASP CRS

Установка здесь тривиальная и не займет много времени. Предположу что у вас уже есть Linux дистрибутив и вэб сервер (здесь и далее рассматриваем Debian + Apache)

  • Устанавливаем пакет

apt install libapache2-mod-security2
  • Включаем модуль

a2enmod security2
  • Подгружаем рекомендованный файл конфигурации

mv /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf
  • Проверяем режим работы движка (Оставляем в DetectionOnly. У нас будет адаптивная блокировка)

grep SecRuleEngine /etc/modsecurity/modsecurity.conf
  • Проверяем включен ли скан ответов сервера

grep SecResponseBodyAccess /etc/modsecurity/modsecurity.conf
  • Проверяем все ли в порядке с конфигом модуля

cat /etc/apache2/mods-enabled/security2.conf
  • Перезагружаем Apache

systemctl restart apache2
systemctl status apache2
  • В принципе какой‑то дополнительной настройки можно и избежать

OWASP CRS

Что же это такое? Не более чем общий набор статических правил оценки и фильтрации трафика для ModSecurity

Установка

  • Подгружаем правила

cd /var/tmp

wget https://github.com/coreruleset/coreruleset/archive/refs/tags/v4.10.0.tar.gz
wget https://github.com/coreruleset/coreruleset/releases/download/v4.10.0/coreruleset-4.10.0.tar.gz.asc
  • Проверяем целостность

gpg --fetch-key https://coreruleset.org/security.asc
gpg --edit-key <RSA KEY ID>

gpg> trust
Your decision: 5 (ultimate trust)
Are you sure: Yes
gpg> quit

gpg --verify coreruleset-4.10.0.tar.gz.asc v4.10.0.tar.gz
  • Устанавливаем правила

mkdir /etc/crs4
tar -xzvf v4.10.0.tar.gz --strip-components 1 -C /etc/crs4
  • Подгружаем файл конфигурации

cd /etc/crs4
mv crs-setup.conf.example crs-setup.conf
  • Подгружаем в ModSecuirty модуль

nano -w /etc/apache2/mods-enabled/security2.conf
# Include OWASP ModSecurity CRS rules if installed
#IncludeOptional /usr/share/modsecurity-crs/*.load
IncludeOptional /etc/crs4/crs-setup.conf
IncludeOptional /etc/crs4/plugins/*-config.conf
IncludeOptional /etc/crs4/plugins/*-before.conf
IncludeOptional /etc/crs4/rules/*.conf
IncludeOptional /etc/crs4/plugins/*-after.conf
  • Перезагружаем Apache

systemctl restart apache2
systemctl status apache2

Настройка

  • Разбираемся с конфигом. Конфиг, если его прочитать, сам ответит на все возникающие вопросы.

nano -w /etc/crs4/crs-setup.conf
  • Проверяем, что модуль работает в Anomaly Scoring режиме

SecDefaultAction "phase:1,log,auditlog,pass"
SecDefaultAction "phase:2,log,auditlog,pass"
  • Выставляем Paranoia Level = 3 (А почему бы и да? Секурность мы с вами повысим, а с ложными срабатываниями разберемся при необходимости) Кто бы знал, во что это выльется :-)

SecAction \
    "id:900000,\
    phase:1,\
    pass,\
    t:none,\
    nolog,\
    tag:'OWASP_CRS',\
    ver:'OWASP_CRS/4.10.0',\
    setvar:tx.blocking_paranoia_level=3"
  • Принудительно включаем Body Processor URLENCODED для всех клиентских запросов с отсутствующим Content‑Type заголовком

SecAction \
    "id:900010,\
    phase:1,\
    pass,\
    t:none,\
    nolog,\
    tag:'OWASP_CRS',\
    ver:'OWASP_CRS/4.10.0',\
    setvar:tx.enforce_bodyproc_urlencoded=1"
  • Задаем параметры (веса?) для аномалий

SecAction \
    "id:900100,\
    phase:1,\
    pass,\
    t:none,\
    nolog,\
    tag:'OWASP_CRS',\
    ver:'OWASP_CRS/4.10.0',\
    setvar:tx.critical_anomaly_score=5,\
    setvar:tx.error_anomaly_score=4,\
    setvar:tx.warning_anomaly_score=3,\
    setvar:tx.notice_anomaly_score=2"
  • Задаем пороговые значения для блокировки. Предлагаю задрать пока не отладим.

SecAction \
    "id:900110,\
    phase:1,\
    pass,\
    t:none,\
    nolog,\
    tag:'OWASP_CRS',\
    ver:'OWASP_CRS/4.10.0',\
    setvar:tx.inbound_anomaly_score_threshold=5000,\
    setvar:tx.outbound_anomaly_score_threshold=4000"
  • Включаем второй уровень логирования (Как‑никак у нас PL=3 и видеть что именно происходит было бы крайне полезным)

SecAction \
    "id:900115,\
    phase:1,\
    pass,\
    t:none,\
    nolog,\
    tag:'OWASP_CRS',\
    ver:'OWASP_CRS/4.10.0',\
    setvar:tx.reporting_level=2"
  • Включаем дефолтный набор сигнатур

SecAction \
    "id:900130,\
    phase:1,\
    pass,\
    t:none,\
    nolog,\
    tag:'OWASP_CRS',\
    ver:'OWASP_CRS/4.10.0',\
    setvar:tx.enable_default_collections=1"
  • Включаем ограничение HTTP методов. Я добавил PUT метод используемый CMS (Здесь и далее — осторожнее, ибо многое зависит от опубликованных приложений. Я писал под себя, по этому внимательно и без копипасты) Подробнее про логику здесь и здесь

SecAction \
    "id:900200,\
    phase:1,\
    pass,\
    t:none,\
    nolog,\
    tag:'OWASP_CRS',\
    ver:'OWASP_CRS/4.10.0',\
    setvar:'tx.allowed_methods=GET HEAD POST OPTIONS PUT'"
  • Ограничиваем HTTP Content Type

SecAction \
    "id:900220,\
    phase:1,\
    pass,\
    t:none,\
    nolog,\
    tag:'OWASP_CRS',\
    ver:'OWASP_CRS/4.10.0',\
    setvar:'tx.allowed_request_content_type=|application/x-www-form-urlencoded| |text/html|'"
  • Ограничиваем HTTP версии

SecAction \
    "id:900230,\
    phase:1,\
    pass,\
    t:none,\
    nolog,\
    tag:'OWASP_CRS',\
    ver:'OWASP_CRS/4.10.0',\
    setvar:'tx.allowed_http_versions=HTTP/1.1'"
  • Ограничиваем кодировку

SecAction \
    "id:900280,\
    phase:1,\
    pass,\
    t:none,\
    nolog,\
    tag:'OWASP_CRS',\
    ver:'OWASP_CRS/4.10.0',\
    setvar:'tx.allowed_request_content_type_charset=|utf-8|'"
  • Ограничиваем количество аргументов, длину имени аргумента и его собственную длину, суммарную длину всех аргументов.

SecAction \
    "id:900300,\
    phase:1,\
    pass,\
    t:none,\
    nolog,\
    tag:'OWASP_CRS',\
    ver:'OWASP_CRS/4.10.0',\
    setvar:tx.max_num_args=255"
SecAction \
    "id:900310,\
    phase:1,\
    pass,\
    t:none,\
    nolog,\
    tag:'OWASP_CRS',\
    ver:'OWASP_CRS/4.10.0',\
    setvar:tx.arg_name_length=100"
SecAction \
    "id:900320,\
    phase:1,\
    pass,\
    t:none,\
    nolog,\
    tag:'OWASP_CRS',\
    ver:'OWASP_CRS/4.10.0',\
    setvar:tx.arg_length=400"
SecAction \
    "id:900330,\
    phase:1,\
    pass,\
    t:none,\
    nolog,\
    tag:'OWASP_CRS',\
    ver:'OWASP_CRS/4.10.0',\
    setvar:tx.total_arg_length=64000"
  • Ограничиваем размер файла в POST запросе, а так же суммарный размер всех файлов

SecAction \
    "id:900340,\
    phase:1,\
    pass,\
    t:none,\
    nolog,\
    tag:'OWASP_CRS',\
    ver:'OWASP_CRS/4.10.0',\
    setvar:tx.max_file_size=1048576"
SecAction \
    "id:900350,\
    phase:1,\
    pass,\
    t:none,\
    nolog,\
    tag:'OWASP_CRS',\
    ver:'OWASP_CRS/4.10.0',\
    setvar:tx.combined_file_sizes=1048576"
  • Проверяем наш сервер на предмет поддержки кодировки

SecAction \
    "id:900950,\
    phase:1,\
    pass,\
    t:none,\
    nolog,\
    tag:'OWASP_CRS',\
    ver:'OWASP_CRS/4.10.0',\
    setvar:tx.crs_validate_utf8_encoding=1"
  • Остальное оставляем по умолчанию

  • Включаем фильтрацию в конфигурации виртуального хоста

nano -w /etc/apache2/sites-enabled/null.conf
# WAF
<IfModule security2_module>
  SecRuleEngine On
</IfModule>
  • Перезагружаем Apache

systemctl restart apache2

Отладка

  • Берем напильник и приступаем. В одной руке — терминал

tail -f /var/log/apache2/modsec_audit.log | grep -iE ".*notice.*|*.warning.*|.*error.*|.*critical.*"
  • Другой — начинаем проверять функционал приложения

Проблема 1

Message: Rule 7faba9cd8db8 [id "951250"][file "/etc/crs4/rules/RESPONSE-951-DATA-LEAKAGES-SQL.conf"][line "365"] - Execution error - PCRE limits exceeded (-47): (null).
  • Здесь каких‑то рекомендаций кроме как trial and error нет. Предлагаю сделать следующее (не забываем рестартить Apache после внесения изменений)

nano -w /etc/modsecurity/modsecurity.conf
# PCRE Tuning
# We want to avoid a potential RegEx DoS condition
#
SecPcreMatchLimit 500000
SecPcreMatchLimitRecursion 250000

Проблема 2

Message: Warning. Match of "within %{tx.allowed_request_content_type}" against "TX:content_type" required. [file "/etc/crs4/rules/REQUEST-920-PROTOCOL-ENFORCEMENT.conf"] [line "1012"] [id "920420"] [msg "Request content type is not allowed by policy"] [data "|multipart/form-data|"] [severity "CRITICAL"] [ver "OWASP_CRS/4.10.0"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-protocol"] [tag "paranoia-level/1"] [tag "OWASP_CRS"] [tag "capec/1000/255/153"] [tag "PCI/12.1"]
  • Объективно у нас отсутствует Content Type = multipart/form‑data. Фиксим

nano -w /etc/crs4/crs-setup.conf
SecAction \
    "id:900220,\
    phase:1,\
    pass,\
    t:none,\
    nolog,\
    tag:'OWASP_CRS',\
    ver:'OWASP_CRS/4.10.0',\
    setvar:'tx.allowed_request_content_type=|application/x-www-form-urlencoded| |multipart/form-data| |text/html|'"

Проблема 3 - фундаментальная

Message: Warning. Found 24 byte(s) in ARGS:name outside range: 32-36,38-126. [file "/etc/crs4/rules/REQUEST-920-PROTOCOL-ENFORCEMENT.conf"] [line "1611"] [id "920272"] [msg "Invalid character in request (outside of printable chars below ascii 127)"]

пример
ARGS:name: \xd0\x9e\xd1\x82\xd0\xbb\xd0\xb0\xd0\xb4\xd0\xba\xd0\xb0
  • Все дело в том, что OWASP CRS отказывается в кириллические кодировки, а у нас именно тот случай. (я пробовал подсунуть ему и windows-1251 charset, и koi8-r — безрезультатно. Разработчик отделывается общими фразами аля «дефолтный конфиг работает». Не знаю, не проверял, да и зачем нам дефолт? Что либо с этим сделать не понижая PL практически невозможно, посему пишем байпас.

SecRule ARGS:name "@rx (.*)" \
        "id:001001001,\
        phase:1,\
        pass,\
        nolog,\
        msg:'Charset Check Bypass - Cyrilic encoding is not supported',\
        ctl:ruleRemoveById=920272"

Проблема 4

Message: Warning. Matched phrase "var/log" at ARGS:html. [file "/etc/crs4/rules/REQUEST-930-APPLICATION-ATTACK-LFI.conf"] [line "116"] [id "930120"] [msg "OS File Access Attempt"] [data "Matched Data: var/log found within ARGS:html: ***** tail -f /var/log/apache2/modsec_audit.log
  • Здесь он уже умничает при анализе содержимого страницы :-) Выхода три: править сигнатуру, писать байпас либо не использовать ругательных слов в контенте. Первое отработает ровно до первого апдейта, третье, в нашем случае, не вариант. Пишем байпас.

SecRule ARGS:html "@rx (.*)" \
        "id:001001002,\
        phase:1,\
        pass,\
        nolog,\
        msg:'Matched pattern bypass',\
        ctl:ruleRemoveById=930120"

Проблема 5 - отсюда вытекающая

  • По факту мы с вами столкнулись с тем, что у нас огромное количество ложных срабатываний по причине используемой кодировки и по причине весьма специфичного контента. Что же делать? Глобально — либо понижать PL либо писать байпасы (выбор ваш). Плохо и то, и другое. Поэтому учитывайте специфику при подборе WAF.

  • Я уже был готов понижать PL и вовсю парсил логи, как пришло озарение :-) 99% процентов срабатываний происходит в момент публикации контента из админки. Что это значит? Не более чем то, что мы можем привязаться к HTTP REQUEST_METHOD и сделать глобальный байпас всего.

  • Плюсы‑минусы? Плюсы — избавимся от срабатываний по кодировке и истерии по поводу скриптового контента. Минусы — на сайте есть формы поиска и авторизации, так что в них можно будет долбиться в обход политик.

  • Выбор в целом сводится к тому чтобы либо принять риски, либо писать 100 500 правил без гарантии отсутствия ложных срабатываний в будущем. Я эти риски принял. В целом можно прикрутить IPS с сигнатурами на POST метод и спать несколько спокойнее.

  • Мои кривые потуги в парсер если кому будет нужно

echo > /var/log/apache2/modsec_audit.log

cat /var/log/apache2/modsec_audit.log | grep -iE ".*notice.*|*.warning.*|.*error.*|.*critical.*" | perl -ne 'm/.*(ARGS:\w+)/ && print "$1\n"' | sort | uniq >> /var/tmp/args.txt

cat /var/log/apache2/modsec_audit.log | grep -iE ".*notice.*|*.warning.*|.*error.*|.*critical.*" | perl -ne 'm/ARGS:html.*(id "\d+")/ && print "$1\n"' | sort | uniq >> /var/tmp/args_html.txt

cat /var/tmp/args_html.txt | sed 's/id \"/ctl:ruleRemoveById=/g' | sed 's/\"/\,\\/g' >> /var/tmp/html_rules.txt
  • Правило для админки (даем два, ибо автосохранение реализовано через PUT)

SecRule REQUEST_METHOD "@rx (POST|PUT)" \
        "id:001001001,\
        phase:1,\
        pass,\
        nolog,\
        msg:'Admin Panel WAF bypass',\
        ctl:ruleEngine=Off"
  • В принципе в энтерпрайзе можно привязаться к блоку доверенных адресов и выше описанные проблемы уйдут. Например так.

SecRule REMOTE_ADDR "@ipMatchFromFile admin_panel_whitelist.txt" \
        "id:001001001,\
        phase:1,\
        pass,\
        log,\
        msg:'Admin Panel WAF bypass - POST|PUT only',\
        ctl:ruleEngine=Off,\
        chain"

SecRule REQUEST_METHOD "@rx (POST|PUT)"
  • Еще раз проверяем логи на предмет срабатываний и закручиваем порог блокировки

nano -w /etc/crs4/crs-setup.conf
SecAction \
    "id:900110,\
    phase:1,\
    pass,\
    t:none,\
    nolog,\
    tag:'OWASP_CRS',\
    ver:'OWASP_CRS/4.10.0',\
    setvar:tx.inbound_anomaly_score_threshold=5,\
    setvar:tx.outbound_anomaly_score_threshold=4"
  • Проверяем логи

Action: Intercepted (phase 2)
Apache-Handler: application/x-httpd-php
Stopwatch: 1737805433007092 8481 (- - -)
Stopwatch2: 1737805433007092 8481; combined=5102, p1=911, p2=2835, p3=0, p4=0, p5=1355, sr=75, sw=1, l=0, gc=0
Response-Body-Transformed: Dechunked
Producer: ModSecurity for Apache/2.9.7 (http://www.modsecurity.org/); OWASP_CRS/4.10.0.
Server: Apache
Engine-Mode: "ENABLED"
  • Если у вас стоит Fail2Ban, можно глянуть и туда

fail2ban-client status apache-modsecurity
Status for the jail: apache-modsecurity
|- Filter
|  |- Currently failed: 0
|  |- Total failed:     14
|  `- File list:        /var/log/apache2/error.log
`- Actions
   |- Currently banned: 1
   |- Total banned:     6
   `- Banned IP list:   193.41.206.98

Бонусные правила

  • Первым делом закроем передачу сигнатур сервера

nano -w /etc/apache2/mods-enabled/security2.conf
# Manipulating server signaturte
ServerTokens Min
SecServerSignature "null"
systemctl restart apache2
  • Проверяем

curl -i --header 'Host: null.somedomain.name' https://null.somedomain.name | less
Server: null
  • Далее подумаем, а нужно ли нам такое :-) Представим, что мы хостим некий контент на который прямых ссылок нет и не предвидится. Технически — можно пройтись каким‑нибудь кроулером по сайту в поисках HTTP 200 и дальше уже с этим работать (вопрос сложности и целесообразности оставим в стороне)

  • Альтернативно представим что кто-то просто интересуется, а что же у нас доступно

  • Что с этим можно сделать? Описанная ситуация предполагает некое количество HTTP 404 возвращенных клиенту до того как он получит HTTP 200, а с этим уже можно работать.

  • ВАЖНЫЙ МОМЕНТ: (отдельное спасибо @Borelli) Если у вас большое количество изменений на сайте то высока вероятность того, что написав подобное правило валидные роботы поисковиков будут отлетать на равне с остальными

    Что с этим делать если официальной информации о том, откуда приходят роботы поисковиков нет ? Казалось бы вариантов два:

    • Не использовать предложенный функционал при необходимости разрешить доверенных роботов

    • Парсить базы RIRов и добавлять ВСЕ адреса в белый список

Парсить базы конечно можно, но дело это такое себе, а функционал нам все таки нужен. Давайте разбираться в том, когда робот поисковика может получить от нас HTTP 404

  • В случае если ранее проиндексированная страница более недоступна

  • В случае если у нас расхождения в sitemap и широкие allow директивы в robots.txt

    Предположим, что c sitemap и robots.txt у нас все в порядке. Что делать дальше ? А дальше мы сделаем исключение для всех опубликованных URI (включая те, что были проиндексированы и более недоступны) используя переменную REQUEST_URI

    В нашем случае весь контент доступен по двум путям /shelves/* и /books/*

    Пишем нечто подобное

#
# Block content harvesting
#

# SRC IP Whitelist
SecRule TX:REAL_IP|REMOTE_ADDR "@ipMatchFromFile http_404_whitelist.txt" \
        "id:001003001,\
        phase:1,\
        pass,\
        nolog,\
        msg:'IP Whitelisted for HTTP 404',\
        ctl:ruleRemoveById=001003002,\
        ctl:ruleRemoveById=001003003,\
        ctl:ruleRemoveById=001003004"

# Bypass for published resources
SecRule REQUEST_URI "@rx (\/shelves(|\/).*|\/books(|\/).*)" \
        "id:001003002,\
        phase:1,\
        pass,\
        nolog,\
        msg:'URI Whitelisted for HTTP 404',\
        ctl:ruleRemoveById=001003003,\
        ctl:ruleRemoveById=001003004"

SecRule RESPONSE_STATUS "@streq 404" \
        "id:001003003,\
        phase:3,\
        pass,\
        setvar:IP.bad_http_request=+1,\
        expirevar:IP.bad_http_request=86400,\
        log,\
        msg:'Page Not Found - HTTP 404 - Count %{IP.bad_http_request}'"

SecRule IP:BAD_HTTP_REQUEST "@gt 10" \
        "id:001003004,\
        phase:3,\
        drop,\
        log,\
        msg:'Client Exceeded HTTP 404 Request Limit of 10 - Banned For a Day'"
  • Здесь правило 001003001 - это байпас функции для доверенных адресов

  • Правило 001003002 - байпас для опубликованных URI (по ним у нас будут ходить как боты поисковиков, так и все остальные)

  • Правило 001003003 - это проверка ответа на наличие HTTP 404 и выставление переменной IP.bad_http_request

  • Далее правило 001003004 дропает сессию при условии значения IP.bad_http_request более 10

Project Honey Pot

Что это за зверь такой? Не более чем база IP адресов ботов (впрочем, чуть более чем просто база, но об этом далее).

Установка "ловушки"

Несколько слов о том, зачем это все — в первую очередь позволяет собрать дополнительную статистику о разных ботах: роботах, кроулерах, спамерах (в том числе в камментах) и прочих харвестерах.

Работает все до нельзя просто:

  • Ханипот генерит скрипт, который потом можно захостить, активировать и тем самым получить свой ханипот

  • Дальше задача насытить сайт ссылками

  • Ну а дальше ждем пришествия роботов «прокликивающих» абсолютно все, в том числе нашу «ловушку»

  • Дальше данные о попаданце сливаются на ханипот и, собственно, к нам

  • Так же скрипт позволяет позволяет скормить ботам некоторое количество почтовых адресов и если на эти адреса пойдет спам рассылка — отправитель попадает в черный список

Надеюсь вы поняли

Приступим!

  • Регистрируемся на сайте и скачиваем скрипт для интеграции с сайтом (в нашем случае похопе).

  • Публикуем и выставляем разрешения

chown -R root:www-data /var/www/bookstack/public/hello.php
chmod 644 /var/www/bookstack/public/hello.php
  • Вызываем браузером и активируем

  • Добавляем в footer ну или куда‑либо еще (только так, чтоп человекам не видно было)

<footer class="print-hidden">
            <a href="https://null.somedomain.name/hello.php" target="_blank" rel="noopener"></a>
</footer>
  • Альтернативный способ — инджектить напрямую из ModSecurity. Вот так

SecContentInjection On
SecStreamOutBodyInspection On

SecRule RESPONSE_CONTENT_TYPE "@contains text/html" \
        "id:001003001,\
        phase:4,\
        pass,\
        nolog,\
        chain"

SecRule STREAM_OUTPUT_BODY "@rsub s/<\/html>/<a href=\"https:\/\/null.somedomain.name\/hello.php\"><\/a><\/html>/"

Привязываем черные списки к ModSecurity

Как было понятно из предыдущей главы, если где‑то есть база не очень хороших дядь и теть, то было бы странно ей не воспользоваться.

  • Генерируем ключ доступа к API на сайте проекта

  • Создаем правило (убедитесь что его айдишник отрабатывает первым)

nano -w /etc/crs4/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf
# HTTPBL Check
SecHttpBlKey API ключ

SecRule TX:REAL_IP|REMOTE_ADDR "@rbl dnsbl.httpbl.org" \
        "id:001001001,\
        phase:1,\
        capture,\
        block,\
        log,\
        msg:'HTTPBL Match of Client IP.',\
        logdata:'%{tx.httpbl_msg}',\
        setvar:tx.httpbl_msg=%{tx.0},\
        chain"

SecRule TX:0 "threat score (\d+)" "chain,capture"
SecRule TX:1 "@gt 20"

Заключение

На этом пока остановимся. Впереди Snort, DDoS Offloading, возможно SIEM (логи смотреть было бы крайне полезно).

Спасибо всем кто дочитал до конца! По традиции — кросс линк ProjectNull (сеошник во мне не умер :-)

Буду рад ответить на вопросы по теме.

Комментарии (20)


  1. x89377
    25.01.2025 21:16

    Полезная статья. Спасибо.
    Хотя мне пришлось самому написать для IIS на .NET аналог ModSecurity, но в целом всё также. Правила тоже брал OWASP CRS.


  1. Sadok
    25.01.2025 21:16

    букв много. по опыту скажу, что использование WAF - палка с N концами. "ой! о что это у нас платежи не ходят?!! - а это у нас правила WAF обновились, пардон." так что мы эту штуку у себя на балансерах отключали. заказчик хочет - пусть сам у себя на бэкендвх играется.


    1. igorv126 Автор
      25.01.2025 21:16

      На этот случай, если мы говорим о критических приложениях, у вас наверняка есть пре-прод. Собственно все обновления и тесты - в первую очередь там


  1. erley
    25.01.2025 21:16

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

    То есть там где дело доходит до того что люди себе ставят задачу развернуть-таки WAF (то есть у них и правда что-то критичное есть что защищать нужно) - там уж как-то не мелочатся, а разворачивают решение с наглядной визуализацией что происходит, кучей метрик и эвристик. У вас не будет времени залезать в текстовые конфиги и править правила когда что-то действительно будет атаковано. А "выдернуть сетевой кабель" не всегда возможно физически и/или функционально.

    Решение на апаче с этим модулем требует ещё много всего чтобы им можно было пользоваться на таких критичных проектах.

    Однако тема интересная, очень любопытно будет почитать про snort и другие open source решения, буду ждать!

    PS У нас используется Imperva и кое-где Palo Alto (у этих правда какие-то косяки в последнее время).


    1. igorv126 Автор
      25.01.2025 21:16

      Почему критичных ? Я сразу оговорился, что для критичных оно того не стоит


  1. olku
    25.01.2025 21:16

    По мне если вы не секьюрити компания, которая на этом зарабатывает, то свой велосипед будет плох и дорог по общей стоимости владения.


    1. igorv126 Автор
      25.01.2025 21:16

      Да, вы правы


  1. jhoag
    25.01.2025 21:16

    Тема интересная в рамках самообразования. Но как категория программного обеспечения WAF всегда казался мне костыльным костылём — платой за низкое качество веб-приложений и системного администрирования. То есть вместо развития культуры безопасной разработки и сисопс индустрия породила ещё одну сущность, которая прикрывает как можно больше ленивых задниц — WAF. Единственное, что кажется в таких фаерволах правда актуальным, — защища от ботов, но и для этого есть более нишевые решения.


    1. igorv126 Автор
      25.01.2025 21:16

      Да, наверное вы правы.

      Впрочем если лезть совсем уж в глубины, то сегментация критической инфраструктуры предполагает использования физически разных девайсов (местами от разных вендоров) с проверками, выполняемыми в каждой из зон (в том числе на уровне приложения и операционной системы)


    1. diver22
      25.01.2025 21:16

      У нас как раз стоит квест по защите от ботов. Можете назвать эти самые нишевые решения. Буду очень признателен.


      1. jhoag
        25.01.2025 21:16

        Не хочу никого рекламировать. Если нужны готовы решения, поищите, например, по фразе «антибот сервис».


  1. Borelli
    25.01.2025 21:16

    Из примеров не понятно, что будет с валидными парсерами валидных поисковиков? Для них отдельный котёл набор правил существует или надо добавлять все подсети яндексов-гуглов в белый список?


    1. igorv126 Автор
      25.01.2025 21:16

      Да, они будут отлетать на равне с остальными.

      Все-же конкретно эта задача изначально ставилась под ресурс не предполагающий обхода доверенными роботами. И да, все как вы и говорите, если официальной информации о том, откуда приходят роботы поисковиков нет - выхода два:

      - Не использовать предложенный функционал при необходимости разрешить доверенных роботов

      - Парсить базы RIRов и добавлять ВСЕ адреса в белый список

      Если мне удастся отловить трафик Яндекса или Гугло бота, может быть в нем найдется некий идентификатор к которому можно будет привязаться


    1. igorv126 Автор
      25.01.2025 21:16

      Придумал ! Все же парсить риров - дело такое себе. Есть способ проще. Отпишу чуть позднее


    1. igorv126 Автор
      25.01.2025 21:16

      Готово ! Сделал REQUEST_URI исключение через chain

      Статью обновил. Вам - спасибо ! :)


    1. igorv126 Автор
      25.01.2025 21:16

      Минуту, нужно переписать. Там расхождения фаз


    1. igorv126 Автор
      25.01.2025 21:16

      Вот теперь готово


  1. igorv126 Автор
    25.01.2025 21:16

    Здесь был коммент от кого-то с просьбой написать про modsecurity3 под nginx (толстые пальцы нажали не в ту кнопку и комментарий пропал, сорян)

    Возможно когда-то и соберусь в nignx, но знаний по нему у меня ноль, ровно как и практических задач


  1. werter_l
    25.01.2025 21:16

    Спасибо. Из готового на safeline waf или bunkerweb гляньте.


    1. igorv126 Автор
      25.01.2025 21:16

      Спасибо, посмотрю