
Всем привет! Зовут меня Владимир, я работаю специалистом информационной безопасности в бизнес‑юните Mail компании VK. Запустить сканер внешнего периметра было одной из моих важных задач. Сделать это можно было двумя способами разобрать и использовать то, что было сделано раньше или создать что‑то новое. Я пошел по второму пути и... мы развернули инструмент на всю компанию.
Для чего VK этот сканер?
Часто происходят факапы релевантные именно для компании(конкретного продукта) они зависят от софта и конфигурации. Эти инциденты желательно мониторить постоянно, чтобы они не повторялись. Для этих целей прошлой командой был разработан «Мегаскан», по сути это был баш‑скрипт запускающий по списку целей (доменов/ip) вначале nmap, а затем отдельные написанные на Python скрипты. Это был довольно медленный и негибкий по современным меркам инструмент.
По «счастливой случайности» я, как ленивый багхантер уже к тому времени сделал себе приватный «велосипед» autobb с нужной функциональностью на основе нескольких опенсорс‑проектов, оставалось также открыть исходный код и можно было использовать в компании, с небольшими переделками:)
По своей сути, это обвязка на Python для большого количества других, известных и не очень, инструментов с базой данных mongoDB, большая часть — это инструменты от Project Discovery. Да, все это можно запускать напрямую из баша собирая в пайпы, но я думаю обработка структурированных данных, таких как json не очень удобна, гораздо приятнее иметь возможность исполнять любые запросы в единой БД, плюс сверху например можно еще «прикрутить» redash и т. п.
Для большего удобства и развертывания все оформлено в один докер‑контейнер и находится тут: https://github.com/rivalsec/autobb
Сканирование разделено на несколько этапов:
Поиск доменов (пассивно и активно).
Сканирование портов.
Поиск HTTP(S) ресурсов.
Проверка на уязвимости HTTP(S) ресурсов.
Как работает всё это «безобразие», упрощенно представлено в схеме:

Первый этап: ищем (под)домены
В этом процессе участвует каждый домен из списка domains, при условии если в конфиге скоупа не указано subs_recon: false
. Эта настройка удобна для скоупов, в которых сабдомены искать не нужно, например, полная выгрузка зоны из name‑серверов.
Для начала мы собираем огромный список возможных поддоменов для последующей обработки в несколько этапов:
Пассивный поиск доменов с помощью утилиты subfinder в разных источниках, советую тут не полениться и создать конфиг с api‑ключами специальных сервисов, из которых утилита собирает данные. Как это сделать написано тут. Выдача с настроенными ключами будет примерно в два раза больше.
По словарю (опция
‑dns‑brute
).С помощью мутаций уже известных доменов (опция
‑dns‑alts
), реализовано с помощью библиотеки DNSGen.
Потом резолвим что удалось собрать. Тут на первый взгляд кажется все просто — бери любой массовый резолвер (massdns и т. п.) и запускай, но на этом этапе все когда‑либо неизбежно встречают на своем пути домен, у которого любые, даже несуществующие, сабдомены отвечают валидной записью. Подробнее про wildcard (*.domain.tld) DNS записи можно почитать, например, в вики Wildcard_DNS_record.
Чтобы не копить такой «мусор» в базе, для очистки я использую PureDns. Для получения записей он «под капотом» запускает massdns и потом обрабатывает по специальному алгоритму, что позволяет очистить большинство однотипных ответов. Похожим функционалом обладает shuffledns но, по моему опыту, результат работы первого лучше.
В этом процессе есть еще одна небольшая хитрость, которая позволяет снизить нагрузку на NS сервера исследуемых доменов. Мы все домены делим на чанки по несколько штук и процесс получения записей massdns происходит для нескольких доменов за один проход, что также увеличивает скорость за счёт распараллеливания резолвов, в случае, если попался медленный NS.
На выходе получаем в БД такую запись:

a_rev
(https://en.wikipedia.org/wiki/Reverse_DNS_lookup) — это ptr записи для всех IP домена, их полчаем отдельным dnsx-процессом.
Сканируем порты
Тут всё просто. Все найденные и указанные в конфиге хосты, IP и сети сканируются с помощью naabu. В конфиге можно указать разные списки портов для новых найденных хостов и тех, что были в базе ранее. Получить для этого топ 100 и 1000 портов из nmap можно следующим образом:
nmap -v --top-ports 100 -oG - | grep "TCP"
nmap -v --top-ports 1000 -oG - | grep "TCP"
Для каждого найденного naabu порта в БД добавляется или обновляется запись вида:

После этого сканируем новые найденные порты с помощью network шаблонов nuclei.
Поиск HTTP(S)-ресурсов
C помощью httpx среди найденных ранее новых или изменившихся портов и доменов, ищем ресурсы с валидными HTTP-пробами. Здесь для снижения нагрузки и избегания различных рейтлимитов, мы отправляем данные утилите сразу из всех скоупов в перемешанном (рандомном) порядке.
На выходе получаем примерно такую запись в БД:

Сканирование на уязвимости
Активное (опция --nuclei)
Сканируем новые или изменившиеся HTTP‑ресурсы, считается что ресурс изменился при изменении: кода ответа, заголовка, cname, common‑name HTTPS‑сертификата. Результаты записываются в БД и на новые срабатывания отправляется уведомление.
Тут хотелось бы упомянуть что у nuclei есть две опции конкурентных запросов
-bs, -bulk-size int
— максимальное количество хостов для параллельного анализа на шаблон (по умолчанию 25)
-c, -concurrency int
— максимальное количество шаблонов для параллельного выполнения (по умолчанию 25)
В autobb по умолчанию установлено bulk-size 50 concurrency 4
. Для снижения нагрузки на конкретный хост, если ресурсов для сканирования достаточно много, рекомендую выставить bulk‑size больше (100–200), а concurrency меньше (2–1)
Пассивное (опция --passive)
Если эта опция установлена при этапе поиска HTTP‑ресурсов (httpx), все ответы сохраняются во временную папку, и в последующем проверяются пассивно: https://docs.projectdiscovery.io/tools/nuclei/running#passive‑scan.
Поддержка пассивного режима ограничена шаблонами, имеющими {{BasedURL}}
или {{BasedURL/}}
в качестве базового пути запроса — это более 700 из публичного репозитория. Без дополнительного взаимодействия с ресурсом, это позволяет находить, например, секреты угоны доменов и тому подобные баги.
Создание своих шаблонов
Cканировать публичными шаблонами, конечно, хорошо, но еще лучше создавать их для найденных у себя проблем. Отчеты Bug Bounty и задачи на исправление, содержащие информацию об уязвимости, которая могла быть найдена сканированием, являются основными источниками для создания шаблонов у нас в компании. Официальная документация по созданию шаблонов для nuclei: https://docs.projectdiscovery.io/templates/introduction
Приведу для примера LFR на nginx при отключенной настройке merge_slashes
, эту ошибку принесли нам в программу Bug Bounty, ошибка довольно известная, но шаблона на тот момент в публичном репозитории не было.
id: merge-slashes-off-traversal
info:
name: Nginx merge_slashes off directory traversal
author: v.sopernikov
severity: critical
description: Directory traversal in Nginx with merge_slashes off HKRN-29549
reference:
- https://jira.vk.team/browse/HKRN-29549
tags: mail,lfi,vk,path,traversal
requests:
- method: GET
path:
- "{{BaseURL}}//////////////////////../../../../../../../../../../../../etc/passwd"
matchers-condition: and
matchers:
- type: regex
regex:
- "root:.*:0:0:"
- type: status
status:
- 200
Алерты
В течении всего процесса autobb отправляет алерты:
На новые или изменившиеся домены, считается что домен изменился при появлении/удалении cname записи или её изменении.
На новые открытые порты.
На новые или изменившиеся HTTP-ресурсы.
На новые срабатывания nuclei (старые игнорируем для того, чтобы не терять новые срабатывания среди старых ложноположительных).
Для получения уведомления можно выбрать один из двух мессенджеров Telegram или VK Teams:
Создание бота в Telegram: https://core.telegram.org/bots/tutorial#obtain-your-bot-token
Создание бота в VK Teams: https://teams.vk.com/botapi/tutorial/
У нас уведомления отправляются в наш корпоративный VK Teams. Этот вариант так же будет удобен другим компаниям кто использует VK Workspace.
«Полный» скан
Не всегда можно ориентироваться по изменениям хоста, не все изменения видны на главной странице. Исходя из этого, желательно периодически делать «полный» скан всех хостов. Но сканировать их все, а их в базе у нас сейчас больше 200к, всеми возможными шаблонами (больше 9000 в публичном репозитории nuclei) было бы слишком долго и ресурсоемко, как для сканера, так и самих для ресурсов. Для этих целей был создан отдельный скрипт, который берет все живые http‑хосты за последние несколько дней, делит их на чанки и отправляет на сканирование в nuclei. В данном режиме мы сканируем только нашими шаблонами и некоторыми категориями из публичных c severity: medium, high, critical.
Количество дней, размер чанка и опции nuclei задаются для этого в отдельной секции конфиг‑файла. Как запустить fullscan из докер контейнера написано в README.
Пару слов про наш конфиг
Основным источником для сканера у нас является RSM (ресурсно‑сервисная модель) это ПО собственной разработки, которое поддерживается другой командой. В единый репозиторий собираются данные из различных систем, таких как: name‑сервера, ip‑планы и прочие продукты для локальной инвентаризации. Специальный скрипт периодически собирает данный из RSM и создает конфиг скоупов с subs_recon:false
.
Дополнительно c добавлены скоупы для всех наших Bug Bounty программ с полным перечеслением всех поддоменов.
Что получаем в итоге
Разработанное решение на основе open‑source инструментов, позволило нам значительно повысить уровень мониторинга внешнего периметра. Оно автоматизирует поиск уязвимостей и конфигурационных ошибок, помогает предотвращать повторные инциденты путем создания шаблонов для выявленных проблем и снижает нагрузку на команду Bug Bounty, самостоятельно находя простые уязвимости до того, как о них сообщат исследователи.
Преимущества подхода:
бесплатно;
нет риска прекращения поставок ПО;
быстрый запуск;
постоянный поток новых шаблонов от сообщества;
легко создавать свои шаблоны;
не требователен к ресурсам (запускается у нас на VM с 2 CPU и 6 ГБ, но можно и меньше).
Минусы:
отсутствие дашборда;
скудный и не очень очевидный конфинг;
изменения часто приходится вносить через правки в коде.
Надеюсь этот инструмент будет полезен не только компаниям, но и независимым исследователям безопасности, помогая им автоматизировать рутинные процессы, снижать затраты времени и находить новые идеи для собственных решений.