Как мы написали свой EASM, потому что ни один из готовых не подошёл

—

от автора

Привет, Хабр! Меня зовут Макар Роденко, я «белый хакер», пентестер и специалист по безопасности в облачном интеграторе OXYGEN Data Centers & Clouds. Мы давно заметили, что забытые активы — больное место многих компаний. А тут ещё и недавние новости про уязвимости в PHP, и другие громкие CVE спать спокойно не дают. Для наших клиентов мы пропилотили большинство сканеров уязвимостей на российском рынке, но ни один не подошёл идеально. И тогда за 1,5 года мы сделали свой. 

Под катом разбираемся, как устроен наш EASM, как мы боремся с ложными срабатываниями и что оказалось самым сложным в разработке (и стоило нам немало бессонных ночей). Вэлком!

Зачем нужно сканировать внешний периметр?

Типичная история выглядит так: маркетинг на скорую руку поднял лендинг под акцию, разработчики открыли тестовый контур наружу, чтобы коллегам было удобнее проверять код. Никто не делал ничего плохого, но в инвентаризацию эти ресурсы не попали. Служба ИБ узнаёт о них постфактум, а нередко уже после инцидента. Классические инструменты тут не помогают: SIEM работает с известными источниками логов, NGFW фильтрует трафик через известные шлюзы. Актива, которого нет в реестре, они просто не видят. 

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

Что такое EASM

Немного матчасти. Уязвимые места во внешнем периметре находят с помощью решений класса EASM — External Attack Surface Management. Это отдельный инструмент, обычно для работы с ним достаточно браузера. Чтобы начать, просто добавляете свой домен. Сканирование происходит методом «чёрного ящика», то есть система не знает ничего про вашу компанию — как и злоумышленник. Сканер находит все вероятные уязвимости, приоритизирует их и показывает в удобном интерфейсе.

EASM это не пентест. Пентест делает человек, обычно раз в квартал или год, как правило, это очень глубокая работа. А EASM автоматически ловит новые активы при регулярном сканировании.

Слитые учетные записи, перс. данные, другую «серую» информацию EASM не найдёт — это не мониторинг даркнета. EASM работает только с вашей с собственной инфраструктурой — всем, что вы сами выставили в интернет.

Почему мы написали свой VISORA EASM?

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

С чего всё начиналось: архитектура и принципы

Собрать такую систему можно двумя способами. 

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

  • Второй — микросервисная архитектура. Каждый сервис отвечает за одну задачу: например, сканирует или хранит данные. В таком подходе для ускорения достаточно добавить дополнительные сервисы. Плюс отказоустойчивость: сбой одного из них не останавливает остальные.

Мы пошли вторым путём и разделили систему на части с четкими ролями. Для масштабирования отдельно вынесена сканирующая нода, и если нужно сканировать больше и быстрее, то мы просто добавляем новую ноду, и всё. Сканер у нас является как раз этой самой (внезапно) сканирующей нодой, которая: 

  • получает задание — например, проверить домен, 

  • запускает нужные инструменты,

  • приводит результат к единому виду,

  • отправляет обратно сервису, отвечающему за обработку результатов сканирования.

Сканер ничего не хранит и не решает, насколько находка опасна. Хранением, планированием и анализом занимается отдельный бэкенд.

Наш стек: бэкенд на FastAPI, брокер сообщений Apache Kafka, хранилище PostgreSQL. Используем стандартный OSS-набор для разведки и фаззинга.

В архитектуру VISORA мы заложили три принципа. 

  • Во-первых, результат воспроизводим: повторный скан периметра даёт тот же результат, и расхождения означают реальные изменения, а не сбой сканера. 

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

  • В-третьих, никаких додумываний: если проверку не удалось выполнить, например инструмент завис, это фиксируется в логах. 

Саму базу уязвимостей построили по принципу offline-first: сначала обновляем по API все базы данных и работаем с ними локально, так сканирование идёт быстрее. Внешние API служат только запасным вариантом.

Как понимаем, что найденная программа уязвима? Сверяемся с базами известных уязвимостей: NVD, российским БДУ ФСТЭК и дистрибутивными фидами (Debian, Ubuntu и других). Копии этих баз мы храним у себя и обновляем по расписанию. 

Разведка боем, но без боя. Как мы находим активы

Что VISORA считает активом?

  • Домены и поддомены — это основа периметра; именно здесь чаще всего всплывают забытые ресурсы.

  • IP-адреса — в том числе те, что не привязаны напрямую к доменной зоне компании.

  • Порты и сервисы — то, что реально смотрит наружу.

  • Веб-приложения с учётом технологий, на которых они построены.

  • Облачные ресурсы — bucket’ы, инстансы и другие ресурсы, которые легко забыть выключить.

  • TLS-сертификаты — источник информации не только о шифровании, но и о реальной топологии сервисов (через SAN-записи можно найти связанные хосты).

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

А что если кто-то загрузит в сканер чужой домен и увидит все активы?

Такого не случится. Кроме домена или IP мы требуем подтверждение владения через DNS TXT или HTTP-токен. И только после верификации дальше всё работает автоматически: VISORA раскручивает связи от подтвержденного актива, находит смежные домены, поддомены и ресурсы.

Краткий процесс работы

  • Начинаем с разведки: надо понять, что вообще торчит наружу. Сначала ищем домены и поддомены и смотрим их резолв (то, на какие IP они ведут). Потом определяем ASN и сканируем порты. Смотрим, что на них реально отвечает.

  • Дальше выясняем, на чём всё это работает. Тут мы не полагаемся на один инструмент: несколько источников работают параллельно, причем для сайтов и для всего остального (почта, базы, SSH) набор инструментов разный. Универсального способа опознать и nginx, и какой-нибудь экзотический сервис нет, так что приходится комбинировать. Всё сводится в один список, где у каждого продукта есть CPE: название, вендор, версия в стандартном формате. По этому паспорту потом ищутся уязвимости.

  • Отдельно строим карту поверхности: эндпоинты, параметры, методы запросов, формы, OpenAPI- и GraphQL-спецификации собираются как переиспользуемый артефакт. 

Для разных задач сканирование идет с разной частотой:

Задача

Частота

Почему так

Поиск активов (пассивный)

каждые 20 минут

дешёво по нагрузке, новый актив видно почти сразу после появления

Порты и уязвимости (активный)

раз в сутки

создаёт нагрузку на инфраструктуру клиента 

И в двух режимах:

Тип

Частота

Зачем

Лёгкий режим

ежедневно

для быстрой актуализации периметра

Глубокий режим

раз в неделю

для полного перебора скрытых параметров

Главный босс — ложные срабатывания

Это, пожалуй, самая интересная инженерная часть. Классический подход большинства сканеров — определить сервис и его версию по баннеру и сопоставить это с базой CVE. Проблема в том, что это дает огромный процент нерелевантных находок: версия ПО может быть уязвима в общем списке CVE, но конкретная сборка, которую использует вендор дистрибутива, может быть пропатчена бэкпортом — и баннер об этом ничего не знает. Без модуля на типовом Debian/Ubuntu-хосте количество «мусорных» CVE может быть от половины до ~80%.

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

Сигнатурная

Версия сопоставляется с CPE, по нему ищутся CVE в NVD и БДУ ФСТЭК. Отдельный слой сверяет реальный статус пакета в конкретном дистрибутиве и выдаёт один из четырёх вердиктов:

  • подтверждено;

  • вероятно пропатчено;

  • статус дистрибутива неизвестен;

  • вероятно ложное срабатывание.

Пользователь при этом может сам уточнить версии ПО и ОС.

Дистрибутивная верификация CVE (tools/verification/):

  • компаратор версий dpkg на чистом Python, без зависимости от apt_pkg;

  • чекеры для Red Hat, Debian и Ubuntu;

  • четыре возможных вердикта;

  • определение релиза по ревизии пакета в дистрибутиве.

Активный веб-скан

Сначала собираем поверхность: архивные URL, краулинг, фаззинг и брутфорс скрытых параметров. Только после этого по ней прогоняются детекторы по категориям уязвимостей (включая OWASP Top 10):

  • XSS, SQLi, SSTI, LFI, RCE, XXE, SSRF;

  • мисконфиги и дефолтные панели;

  • утечки секретов в JS;

  • захват поддоменов;

  • TLS-аудит;

  • GraphQL;

  • CSRF в формах;

  • SPF/DMARC.

Найденные SQL-инъекции подтверждаются отдельным инструментом.

Потом происходит очистка выдачи от шума:

  • Дедупликация. Если несколько инструментов независимо нашли одну уязвимость, запись схлопывается в одну соответствующей пометкой.

  • Liveness-фильтр. Он отбрасывает «мёртвые» находки: битые URL, 404, редиректы на логин, которые формально совпали с сигнатурой.

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

Во-первых, это красиво. Наш фронтенд

Плохой интерфейс может убить даже самый функциональный сканер. Если им неудобно пользоваться, разбор результатов будет отнимать кучу времени. Поэтому мы особое внимание уделили UI/UX, над которым много колдовал мой коллега и разработчик Андрей Исупов. 

Что у нас получилось:

  • Главный экран показывает сводку по активам, сервисам и уязвимостям, и с него можно провалиться в детали.

  • Домен или IP в карточке актива превращается в небольшую историю наблюдений: текущие свойства, связанные адреса, открытые порты, веб-приложения, уязвимости, результаты прошлых сканов и изменения во времени.

  • Единый слой запросов, построенный на React + TanStack Query. У списков, деталей и статистики разные ключи и время актуальности, а после изменения актива обновляются только затронутые запросы.

  • Вкладочная структура не дает разным типам данных конкурировать за внимание.

  • Фильтры, сортировка и пагинация сохраняются в URL, поэтому ссылку на конкретную выборку можно отправить коллеге или открыть после обновления страницы.

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

  • Графики на дашборде и в карточках сделаны отдельными компонентами с общими форматтерами данных. Компонент получает нормализованный набор значений и отвечает только за представление: шкалы, подсказки, цвета и ресайз. Визуализация не смешивается с логикой запросов, поэтому её можно менять независимо от API.

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

Наши сложности и что пришлось переделывать

Разработка VISORA EASM заняла почти 1,5 года. Одним из переломных моментов стала переработка собственного API — вместе с ним пришлось переписать и фронтенд-часть, чтобы обе стороны системы соответствовали новой архитектуре. Также мы дважды пересобрали дизайн: сначала сделали MVP, на котором проверяли структуру продукта, потом доводили до рабочего интерфейса: дорабатывали навигацию, таблицы, состояния ошибок и пустые результаты. 

«Эксплуатируете? Нет, только показываем»

Решение не эксплуатирует и не устраняет уязвимости — только собирает, структурирует и показывает их в самом удобном виде, со всей историей и приоритизацией. Версионные RCE-уязвимости в известном ПО мы вообще не эксплуатируем, вывод делается из версии и дистрибутивного вердикта. Активная проверка веба — это детект по сигнатурам. Единственное исключение — подтверждение SQL-инъекций: мы шлём минимальные проверочные пробы (boolean- и time-based), чтобы отличить реальную уязвимость от ложного срабатывания, но без дампа данных, без изменения содержимого и без деструктива — это осознанная граница «серой зоны», за которую мы не заходим.

На основе полученных данных вы можете легко контролировать внешний периметр компании и закрыть все «двери» для хакеров — но это отдельная работа. 

С устранением уязвимостей мы в OXYGEN, кстати, можем помочь: наш центр безопасности создан буквально для того, что делать вашу инфраструктуру надежнее и защищённее.

Продолжение следует…

Мы продолжаем развивать сканер, так что вы будущем появятся:

  • расширение покрытия по поиску уязвимостей;

  • углубление веб-скана: аутентифицированное сканирование, которое открывает доступ к классам уязвимостей, не видимым в черном ящике (IDOR, CSRF);

  • приоритизация находок по CVE, которые реально эксплуатируются «в дикой природе», а не просто присутствуют в базе;

  • структурированный инвентарь для популярных CMS;

  • AI для верификации находок, для поиска активов и аналитики.

А как у вас? Знаете ли вы, сколько забытых ресурсов сейчас «светится» в интернете от имени вашей компании? Проводите ли регулярное сканирование внешнего периметра или полагаетесь на периодические пентесты? Поделитесь мнением в комментариях, буду рад ответить на вопросы и дополнить, если что-то осталось за кадром.

Познакомиться с решением можно на нашем сайте. Есть 14 дней бесплатного доступа. И подписывайтесь на Telegram-канал OXYGEN, там мы регулярно делимся новостями из жизни ЦОДов, облаков и кибербеза.

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