Как работает эта ваша суриката 3 часть

от автора

Всем привет! 3 часть цикла статей по разбору устройства работы IDS/IPS решения Suricata.

По итогу второй части цикла статей, надеюсь, у Вас сложилось понимание каким образом формируются правила Suricata. Не все функции просты в использовании и понимании. Еще надо учитывать нагрузку на движок Suricata. Как используются те или иные функции, всегда можно посмотреть в документации. Помимо знания синтаксиса, нужно знать и понимать тематику сетевых атак. Так вот в своих статьях хотел посредством анализа сетевых угроз показать как пишутся сигнатурные правила Suricata. 

В рамках данной статьи рассмотрим уязвимость CVE-2025-66698. В репозитории сказано, что тип уязвимости Authentication Bypass в сервисе Veda (Semantic Machines) v5.4.8. Суть уязвимости заключается в неверной валидации параметров ticket-а. Пустое значение воспринимается сервисом как валидная сессия.

Сейчас попрактикуемся: попробуем воспроизвести активность по описанию POC-а (Proof of conception) из репозитория, запишем трафик, напишем правило и попробуем проверить его.

Сначала давайте откроем нашу виртуалку с убунтой. Поставим сервер apache следующими командами:
sudo apt install apache2

После перейдем в файл ports.conf и скорректируем прослушиваемый порт апача:
sudo nano /etc/apache2/ports.conf

Потому что Dalton у нас работает на 80 порту, а два сервиса на одном порту работать не будут.

После запускаем apache2 командой:
sudo systemctl start apache2

Проверяем в браузере через переход по uri http://localhost:8080. Если все работает, то идем дальше. Устанавливаем tcpdump:
sudo apt install tcpdump
и wireshark, если ранее он не был установлен.
sudo apt install wireshark

Мы подготовились. Теперь запустим tcpdump:
tcpdump -i lo -w CVE-2025-66698.pcap

Разберем команду:
tcpdump — утилита, которая выполняет захват пакетов;
“-i lo” — с помощью флага “-i” мы указали loopback интерфейс захвата трафика “lo”;
“-w CVE-2025-66698.pcap” — здесь с помощью флага “-w” мы указываем куда записывать захваченные данные, а именно в файл “CVE-2025-66698.pcap”.

Откроем еще одно терминальное окно и пустим http-запросы из репозитория:
sudo curl «http://localhost:8080/get\_individual?ticket=&uri=cfg:Administrator» -k
sudo curl «http://localhost:8080/get\_membership?ticket=&uri=cfg:SuperUser» -k
sudo curl «http://localhost:8080/is\_ticket\_valid?ticket=» -k

Через комбинацию ctrl+c остановим работу tcpdump и пойдем смотреть пкап.

У нас 3 http-запроса. Они неуспешные, но это нам не помешает написать правило, детектирующее реализацию уязвимости. Нам важна структура запросов.

alert http any any -> any 8080 (msg:»Possible exploit Semantic Machines v5.4.8″; flow:established,to_server; http.uri; content:»?»; content:»ticket=»; nocase; distance:0; content:»uri=»; nocase; pcre:»/(get_individual|get_membership|is_ticket_valid)\x3f.*ticket=(\x26|$)/i»; sid:101; classtype:attempted-admin; reference:cve,2025-66698;)

Перед запуском, давайте разберем правило. Мы указали, что нам нужны алерты на любые ip-адреса/сетевые зоны и соединения по порту 8080. Поскольку трафик был записал с loopback интерфейса, мы не можем в правиле указать, что нам нужны пакеты от $EXTERNAL_NET к $HOME_NET. Если мы планируем в дальнейшем правило импортировать в продукт NTA/NDR с suricata, то необходимо будет поменять значения. Далее, мы указали на детекты пакетов по направлению к серверу в рамках установленного соединения. Затем мы в uri http-запроса ищем знак вопроса, “ticket=” (как раз таки та переменная, чья валидация с пустым значением позволяет злоумышленнику обойти аутентификацию) и “uri=”. Причем расстояние между знаком вопроса и “ticket=” может быть нулевым — так мы указали distance:0; что поиск контента «ticket=» производить с конечной позиции относительно предыдущего «?» (https://docs.suricata.io/en/suricata-8.0.1/rules/payload-keywords.html#distance). Дальше мы видим регулярное выражение, которое ищет:
— сначала выражение проверяет, что в URI присутствует один из трёх уязвимых API-эндпоинтов, за которым сразу следует “?”. Группа (get_individual|get_membership|is_ticket_valid) перечисляет целевые пути. \x3f — шестнадцатеричный код символа ?.;
— Далее «.*ticket=(\x26|$)» выражение находит параметр ticket с пустым значением.».*» — пропускает любые символы до следующего сопоставления. (\x26|$) проверяет, что после ticket= идёт либо & (начало следующего параметра), либо конец URI — оба варианта означают отсутствие значения.
— Флаг i делает поиск регистронезависимым.

Вы могли задаться вопросом: “а зачем нам регулярное выражение с поиском того, что мы и так ищем модификатором http_uri?”. Есть такая практика в написании правил Suricata. В работе правила сначала будет совпадение по контенту с модификатором http_uri, а потом регулярным выражением суриката как бы верифицирует это же совпадение. Условия по регулярным выражениям требуют много ресурсов и хорошая практика — использовать их как можно реже. Соответственно, предыдущими условиями мы как бы отсеиваем всё ненужное, чтобы потом регулярка проверялась на максимально малом числе пакетов. Теперь постараюсь объяснить почему же мы взяли за условие именно эти контенты (?, ticket=, uri= и регулярка). Давайте вернемся к описанию уязвимости — Пустое значение ticket воспринимается сервисом как валидная сессия. В написании правил нам нужно опираться на паттерны уязвимости. После знака вопроса в URI начинается запрос, который передает какие-то параметры. Очень хорошо видно в Wireshark:

Самостоятельно проверьте работу правила, запустив его в Dalton-е. Уверен, оно сработает.

Теперь хотел бы перейти ко второй части этой статьи.

Sticky buffer или липкий буфер. Определение его встречается в документации 6 версии Suricata. А в документации к версии 8.0.1, на которой мы работаем, этому дано определение Multiple Buffer Matching. Итак, что это такое и зачем оно нужно. Этот модификатор говорит, что можно указать имя буфера в начале и все последующие совпадения (content, поиск по регулярным выражениям, байтовые операции) будут относиться к этому буферу. Давайте объясню на примере (откройте pcap, записанный в первой части статьи cve-2025-66698.pcap): 

я хочу найти два значения в http uri “is_ticket_valid” и “ticket=”. В моем пкапе запрос:

Если мы посмотрим на документацию, то мы увидим, что для поиска в http uri используем модификатор http.uri буфера. Но если мы посмотрим документацию более старой версии suricata или нам попадутся правила, где увидим там http_uri, то могут возникнуть вопросы. Может быть Вы обращали внимание где я ранее ставил content относительно модификаторов. Давайте разберемся как правильно.

Есть два варианта написания условия для поиска наших фраз:
a) content:»is_ticket_valid»; http_uri; content:»ticket=»; http_uri;
b) http.uri; content:»is_ticket_valid»; content:»ticket=»;

Липкий буфер был использован в варианте «b». Обратите внимание как это удобно. Мы можем в начале указать один раз какой использовать хотим буфер и писать паттерны для поиска. Вариант «a» также по-прежнему работает в новых версиях и его можно использовать в написании правил. Правда тут есть нюанс. Например, мы используем липкий буфер http.uri и сразу после него используем буфер http_method – (например: «http.uri; content:»is_ticket_valid»; content:»ticket=»; content:»GET»; http_method;») — суриката ругнется, так как не поймет что к какому буферу относится. И на этот случай его можно сбросить перед контентом с обычным буфером. Давайте составим правила для тестов:
alert http any any -> any 8080 (msg:»Test buffer uri»;content:»is_ticket_valid»; http_uri; content:»ticket=»; http_uri; sid:18;)
alert http any any -> any 8080 (msg:»Test STICKY buffer uri»; http.uri; content:»is_ticket_valid»; content:»ticket=»; sid:19;)
alert http any any -> any 8080 (msg:»Test STICKY buffer double uri»; http.uri; content:»is_ticket_valid»; http.uri; content:»ticket=»; sid:20;)

И пойдем в Dalton смотреть. Запускаем и видим, что все три варианта правил работают:

Совпадение было найдено в http-потоке. Во вкладке Alert Debug будет показано, на какой пакет в HTTP-потоке сработали все три правила.

А еще есть такой вариант, когда мы хотим использовать после липкого буфера обычный буфер (я для него названия не видел или плохо искал).
Запустим следующее правило:
alert http any any -> any any (msg:»Test buffer uri with mistake»; http.uri; content:»is_ticket_valid»; pkt_data; content:»ticket=»; http_uri; sid:22;)

Suricata скажет, что мы используем липкий буфер и нужно его сбросить перед использованием модификатора следующего. Сбрасываем:
alert http any any -> any any (msg:»Test buffer uri with mistake»; http.uri; content:»is_ticket_valid»; pkt_data; content:»ticket=»; http_uri; sid:22;)
И запускаем:

Успех!

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

Кстати здесь в конце страницы есть список всех модификаторов поддерживающих технологию, так сказать, липкого буфера.

И еще хотел Вас познакомить с вендором Emerging Threats. По этой ссылке Вы можете найти их правила. Они обновляются каждый день. Есть как платная подписка, так и бесплатная. В названии правил (модификатор msg) они используют ключевые слова. Здесь сможете найти им определение. Данные правила, считаю, полезны для изучения. На них можно ориентироваться, при тренировках в написании своих правил.

На этом данную статью хочу закончить. Всем спасибо за прочтение и Ваше внимание. Буду благодарен за конструктивную критику, предложения по разбору сетевого трафика и написания правил Suricata. Если у Вас возникли идеи или нестандартные вопросы – давайте разберемся вместе, и я постараюсь отразить в статьях наше изучение продукта.

Буду и дальше подбирать интересные примеры пкапов для расширения знаний пользования Suricata для написания сигнатурных правил.

Всем добра!

ссылка на оригинал статьи https://habr.com/ru/articles/1049776/