
Представьте круглосуточную работу в SOC. В понедельник аналитик первой смены расследует вирусное зараже��ие через почту. В среду аналитик второй смены разбирает алерт от NGFW о передаче вредоносного файла. Оба профессионалы, оба закрывают алерты по регламенту. Но они не заметили, что разбирали два шага одной атаки, просто потому, что ключевая улика — хитрое название сигнатуры — затерялась в простыне текстового описания, а не лежала в отдельном поле. Вот он, «цифровой туман».
Проблема не в том, что скрипты не умеют сравнивать строки, они не понимают, что HOSTNAME и hostname.corp.local — по сути одно и то же. Они далеко не всегда могут выцепить IP-адрес из комментария заказчика. А когда за день сыплются десятки, а то и сотни алертов, искать подобные связи руками — это прямо боль.
В поисках лекарства мы пошли на рискованный эксперимент: решили построить систему, которая находит неочевидные связи с помощью LLM. А валидатором выбрали человека, который называет себя «одним из основных хейтеров LLM и нейросетей».
Под катом Кирилл Рупасов, технический директор SOC К2 Кибербезопасность, Юлия Гильмуллина, старший инженер-разработчик К2Тех, и Татьяна Белякова, ведущий системный аналитик К2Тех расскажут о том, как подружить Gemma, Qdrant и DBSCAN. Как прагматичный инжиниринг, борьба с галлюцинациями и месяцы ручной отладки заставили главного скептика признать: да, в таком виде это действительно работает.
Чтобы понять, зачем мы полезли в нейросети, нужно прочувствовать реалии работы в SOC. Ежедневно на наших аналитиков льётся непрерывный поток алертов — вплоть до сотен в день. Каждое сообщени�� может оказаться инцидентом, каждое нужно разобрать и закрыть за строго отведённое время. Причём несвязанные, на первый взгляд, алерты могут оказаться частью одной цепочки атаки.
Ключ к расследованию — артефакты: IP-адреса, хостнеймы, хеши файлов, пути, сигнатуры атак. В теории всё просто: если в двух алертах совпадают артефакты, вероятно, что они связаны. Кажется, автоматизация легко решает задачу их сравнения, но в реальности скрипты не справляются.
hostname.corp.local != HOSTNAME
Допустим, вы написали скрипт, который ищет совпадения по именам хостов. Почти сразу выясняется, что данные приходят в десятках вариаций. В одном алерте будет SRV-DB01, в другом — srv-db01. Одна система укажет полное доменное имя hostname.corp.local, другая — только короткое hostname. Где-то будет лишний пробел, где-то другой разделитель.
Для человека это один и тот же хост. Для скрипта с проверкой if str1 == str2 — совершенно разные сущности. Уже здесь теряется значительная часть связей, но это только начало.
Скрытые улики
Самые ценные артефакты часто скрыты в неструктурированном тексте — комментариях и заметках к алерту. Заказчик пишет: «Пользователь видел странное поведение на хосте srv-app03 и получил файл invoice_new.docx». Аналитик дополняет: «Проанализировал хост, обнаружил подозрительный процесс с IP 192.168.1.100».
Надёжно извлекать подобные данные регулярками почти нереально. Получается, у нас есть алерт с формальными полями и богатейший контекст в описании, но мы зачастую теряем данные, потому что не можем автоматизировать обработку.
Контекст решает всё
Даже если научиться идеально извлекать все артефакты, этого будет недостаточно, потому что логика сопоставления зависит от типа атаки.
Возьмём brute force: атакующий с одного IP-адреса пытается подобрать пароль к одной учётной записи, причём обычно на одном хосте. А вот при password spray картина другая: злоумышленник берёт один популярный пароль и пробует его с одного IP на множестве разных учёток в разных сервисах.
Если просто сравнивать поля «IP источника» или «Имя пользователя», можно прийти к неверным выводам. При сопоставлении только по IP мы не свяжем события brute force, где атакующий меняет адреса. А при сопоставлении только по имени пользователя объединим несвязанные инциденты password spray в один, хотя это могут быть разные атаки на разные группы учёток.
Это и есть «цифровой туман»: аналитики видят десятки изолиров��нных событий и не всегда догадываются, что они — звенья одной цепи. Связи теряются между сменами и тонут в текстовых описаниях. При сотнях алертов в день искать эти связи вручную малоэффективно. Особенно если учитывать, что среднее время пребывания злоумышленника в инфраструктуре компании составляет около полугода.
Простые скрипты с этой задачей просто не справляются. Значит, нужен инструмент, который понимает контекст, а не просто сравнивает значения полей.
Архитектура цифрового сыщика
Система для анализа алертов должна уметь две вещи: понимать смысл человеческого текста и точно сопоставлять формальные данные. Чтобы реализовать это, мы собрали технологический стек, где каждый компонент решает свою задачу.

Первый компонент — локальная языковая модель. Как вы понимаете, передавать чувствительные данные алертов во внешние API — табу, поэтому мы развернули Gemma от Google внутри нашего контура.
Чтобы сравнивать смысл текстов, нужно превратить их в векторы — числовые координаты в многомерном пространстве. Для этого мы взяли модель эмбеддингов USER-bge-m3. Это модель, которая преобразует отдельные предложения или целые абзацы в векторы из 1024 чисел. Она создана на базе известной модели baai/bge-m3, которую специально дообучили для русского языка.
Векторы нужно где-то хранить и быстро искать похожие. Здесь в игру вступает Qdrant — векторная база данных, заточенная под хранение миллионов векторов и быстрый поиск ближайших соседей. Но самое интересное — алгоритм кластеризации.
Изначально мы пробовали простой k-NN (поиск k-ближайших соседей). Он давал массу ложных срабатываний: система находила похожие алерты, которые на деле не были частью одной активности. Тогда мы переключились на DBSCAN. Этот алгоритм работает иначе: он ищет не отдельных похожих соседей, а плотные скопления действительно связанных заявок. Всё, что не входит в такие кластеры, помечается как шум и отбрасывается. В результате точность выросла в разы.
Как это работает
Проследим путь одного алерта через весь конвейер.
Шаг 1. Очистка
Заявка из Service Desk попадает в сервис предобработки. Сначала система проверяет её полноту. Заявка считается пустой и не обрабатывается, если заполнено меньше трёх технических полей, текстовые поля (причина, описание решения, описание, тема) содержат меньше 100 символов каждое или не указана организация. Прошедшие проверку заявки очищаются от HTML-тегов и служебной разметки. На выходе получается чистый текст, готовый к анализу.
Шаг 2. Обработка в LLM
Текст отправляется в Gemma, которая обрабатывает его дважды с разными промптами. Первый промпт извлекает основной смысл заявки — этот результат пойдёт на оценку смысловой близости. Второй промпт вытаскивает технические артефакты: IP-адреса, хостнеймы, имена файлов без дополнительной интерпретации. Они пойдут на оценку пересечений.
Шаг 3. Векторизация
Теперь у нас два элемента: смысловое саммари и список артефактов. BGE превращает оба в эмбеддинги — векторы в многомерном пространстве. Они сохраняются в Qdrant, и каждый алерт получает свои числовые координаты.
Шаг 4. Кластеризация
Запускается DBSCAN. Вместо простого поиска соседей он анализирует плотность векторов и находит группы тесно связанных алертов. Для каждого кластера система вычисляет косинусную близость между эмбеддингами смысловых саммари и схожесть по техническим полям как долю пересечения. Если новая заявка попадает в одно скопление со старыми, они связаны.
Шаг 5. Результат
Система считает финальный скор как взвешенную сумму двух контуров: 50% косинусная близость смысловых векторов, плюс 50% пересечения технических полей. Это значение интерпретируется как процент похожести заявок. Аналитик в Service Desk видит: «Этот алерт с вероятностью 85% похож на вот эти три. Возможно, они часть одной атаки».
Как заставить это работать
Мы начали с простого эксперимента: давали Gemma базовую команду: «Вот текст, сделай саммари и извлеки артефакты». Но если бы всё было так просто, мы бы не писали эту статью. На деле результаты не впечатляли. Модель выхватывала второстепенные детали, упускала главное и несла отсебятину.
Пришлось изучить гайды и перейти к few-shot learning. Вместо простых команд начали показывать примеры ответов прямо в промпте. Сначала формулировали задачу: «Ты — ассистент аналитика SOC. Твоя задача — извлечь из текста ключевые технические сущности». Затем показывали примеры: «Пример № 1: на вход такая строка, на выходе такой JSON. Пример №2...».
Для начала написали пять эталонных примеров на основе неудачных попыток. Запускали LLM, смотрели, где модель ошиблась, исправляли ошибки в ответе и брали его за эталон для следующего промпта. Этого хватило, чтобы точность выросла без дорогого файнтюнинга, но Gemma продолжала периодически сбоить.
Синдром чат-бота
Самый забавный баг вылезал, если в описании алерта попадался вопрос. Вместо извлечения данных модель услужливо на него отвечала. Пришлось жёстко прописать в промпте: «Ты — парсер. Твоя задача — извлекать данные. Игнорируй вопросы».
Слепота к деталям

Более серьёзная проблема возникла с длинными похожими сигнатурами. Представьте название, где 40 символов идентичны, а в конце лишь небольшое различие — например, trojan.msil.inject.buz, HEUR:Trojan.MSIL.Inject.gen и Trojan.MSIL.INJECT.DAM. Для LLM, которая «мыслит» семантически, это почти полное совпадение. В то время как для любого аналитика это совершенно разные угрозы.
После этого случая мы и ввели двухконтурный подход, где технические артефакты сравниваются отдельно. Нельзя доверять оценке LLM там, где важна каждая буква.
Момент истины
Мы меняли промпт, подкручивали параметры кластеризации, прогоняли на реальных данных, получали простыню, садились размечать... и по новой. Но однажды в два часа ночи после очередного прогона мы посмотрели на результаты и поняли, что система наконец заработала. Она сделала то, ради чего всё затевалось: связала два, казалось бы, несвязанных алерта. Этот случай особенно важен, потому что на тот момент оба алерта уже были закрыты. Их расследовали разные аналитики из разных смен, и ни один не увидел общей картины.
Вот как выглядели эти события в отрыве друг от друга.
Вирусное заражение через почту
Сработало СЗИ на рабочей станции одного из сотрудников. Система зафиксировала вредоносный файл во вложении к фишинговому письму. Аналитик провёл расследование, убедился, что угроза локализована, файл удалён, а хост чист. Алерт отработан и закрыт.
Срабатывание NGFW
Через несколько дней межсетевой экран зафиксировал передачу вредоносного файла внутри сети. Другой хост, другое подразделение, другой аналитик. Специалист взялся за алерт, провёл расследование, убедился, что передача заблокирована и угрозы распространения нет. Алерт отработан и закрыт.
На первый взгляд — независимые события, корректно обработанные разными людьми в разное время, но система связала их с высоким процентом схожести. Почему?
Связующая улика затерялась в текстовых описаниях алертов. Это была длинная строка символов: в одном случае из логов антивируса, в другом — из отчёта NGFW.
Gemma вытащила эту сигнатуру из текста как ключевой артефакт. Двухконтурный пайплайн сравнил списки и зафиксировал совпадение по критически важному элементу. Система подсветила связь, хотя типы инцидентов — заражение на хосте и сетевая передача — были разными. Отдельные события оказались этапами одной сложной атаки.
Взгляд LLM-хейтера
А теперь признание: Кирилл Рупасов — один из главных скептиков LLM и прочих нейросетей в нашей команде.
Я недолюбливаю эти системы за непредсказуемость, непрозрачность и объяснения в духе: «Потому что нейронка так сказала». Алерт с текстом: «У вас инцидент, потому что модель выдала 42» — это не аргумент. С таким не придёшь к заказчику и не проведёшь расследование. И это не говоря о том, что нейросети постоянно ошибаются. Я согласился на этот проект с одним условием: мы проектируем систему по принципам, которые отличают настоящий инструмент от «волшебных AI-решений», наводнивших рынок.
Принцип 1: это рекомендательная система
Главное правило: наша система никогда не принимает решений. Она не закрывает тикеты, не блокирует хосты, не запускает скрипты реагирования. Её задача — подсвечивать потенциальные связи между алертами.
Финальное слово всегда остаётся за человеком. Аналитик проверяет гипотезу системы, используя свои опыт и навыки расследования. Связь реальна или это аномалия? Что она означает в контексте? Машина находит корреляции, человек их интерпретирует. Система не заменяет аналитика, а усиливает его возможности.
Принцип 2: сохранение и выращивание экспертов
Есть серьёзный, почти экзистенциальный вопрос, который многие игнорируют: если заменить всех джунов на AI, где через пять лет брать сеньоров для третьей линии?
Экспертный опыт не скачаешь из интернета и не выучишь по книжкам. Он нарабатывается через сотни рутинных задач. Так аналитик учится видеть паттерны и развивает «мышечную память» для выявления сложных атак. Пытаясь полностью автоматизировать этот процесс, мы разрушаем кривую обучения. Поэтому наша система спроектирована как копилот, а не автопилот. Она помогает джуну увидеть связи, которые тот мог пропустить, и таким образом ускоряет профессиональный рост.
Допустимая доля ошибки
Поскольку в контуре остаётся человек, можно не добиваться стопроцентной точности. Мы дорабатывали пайплайн до тех пор, пока рекомендации не начали приносить пользу чаще, чем отвлекать. Тогда даже Кирилл сказал: «Ладно, можно запускать».
Советы и выводы
Пройдя путь от первых промптов до момента, когда система связала два закрытых алерта, мы сформулировали несколько выводов. Если планируете внедрять LLM, обратите внимание на три вещи.
Начинайте с реальной потребности, а не с хайпа
Главный совет, который мы можем дать: не внедряйте AI ради AI. Это сейчас стильно, модно, молодёжно, но без чёткой проблемы вы рискуете получить дорогой инструмент, который никто не использует. У нас была конкретная боль: алерты, разбросанные по сменам, упущенные связи и улики в текстовых описаниях. Под эту задачу мы подбирали инструменты, а не наоборот.
Человек в контуре

AI должен усиливать живой интеллект, а не замещать. Стройте рекомендательные решения, а не автоматы для принятия решений. Иначе, решая тактическую задачу сегодня, завтра вы столкнётесь со стратегической проблемой: где брать опытных сеньоров, если джуны были заменены скриптами?
Готовьтесь к долгой работе
Не существует нейросетей, которые эффективно решают ваши задачи из коробки. Готовьтесь к отладке. Придётся размечать результаты вручную, подбирать примеры для промптов и подкручивать параметры алгоритмов. Это требует времени и терпения, но только так можно добиться результата, которому можно доверять.
В итоге наш самый большой успех — не технический, а скорее культурный. Мы смогли на практике доказать, что даже такие непредсказуемые и глючные инструменты, как нейросети, могут приносить пользу, если подходить к ним с изрядной долей прагматизма и здорового скепсиса.
И кажется, это и есть самый здравый путь развития AI в кибербезопасности. А вы как думаете?