curl, jq, dnsutils (в нём dig), nmap, openssl; письменное разрешение на сканирование (RoE); доступ к CVEngine — адрес API и способ авторизации сверьтесь с документацией> В исходных материалах канала нет спецификации CVEngine (эндпоинты, имена полей, лимиты). Всё, что относится к самому продукту, помечено как «сверьтесь с документацией»; остальные шаги — стандартные и проверяемые.

uname -a — Ubuntu 22.04+/Debian 12, macOS 13+ либо Windows 11 с WSL2.sudo нужен только для установки пакетов. SYN-скан (nmap -sS) требует root, поэтому ниже используется connect-скан -sT — он работает без root и не открывает raw-сокеты.sudo apt update && sudo apt install -y curl jq dnsutils nmap openssl.df -h /).Пример: проверка окружения одной командой.
curl --version | head -n1; jq --version; nmap --version | head -n1; dig -v
Ожидаемый вывод — четыре строки с версиями, например jq-1.6. Если jq не найден, установка выше не выполнилась.
Если CVEngine или сканер вы разворачиваете на своём железе, порядок подготовки машины описан в гайде по подключению ИИ к домашнему серверу.
Чек-лист перед стартом:
scope.txtscope.txt содержит только домены/IP из RoECVENGINE_API_BASE и CVENGINE_TOKEN заданыnmap запускается без sudoЧто сделать: создать рабочую папку, файл периметра asm/scope.txt и таблицу asm/out/resolved.csv с парами «хост → IP».
Зачем: поверхность атаки (attack surface) — это все ваши активы, доступные из интернета. ИИ-слой анализирует только то, что вы ему подали, поэтому мусор в списке хостов = мусор в отчёте.
mkdir -p asm/raw asm/out
cat > asm/scope.txt <<'EOF'
www.example.com
api.example.com
vpn.example.com
EOF
Пример: www.example.com — плейсхолдер. Замените на домены из своего RoE, по одному в строке, без https://.
Теперь разрешите имена в IP:
while read -r h; do
ip=$(dig +short "$h" | tail -n1)
echo "$h,${ip:-NXDOMAIN}"
done < asm/scope.txt | tee asm/out/resolved.csv
Ожидаемый вывод:
www.example.com,93.184.216.34
api.example.com,93.184.216.35
vpn.example.com,NXDOMAIN
Как проверить: grep -c NXDOMAIN asm/out/resolved.csv. Если счётчик больше нуля — эти хосты не существуют в DNS или опечатка в имени; исправьте до перехода к шагу 2, иначе curl и nmap упадут на них с ошибкой.
Почему это работает: dig +short отдаёт только ответ резолвера, tail -n1 берёт последнюю A-запись, а ${ip:-NXDOMAIN} подставляет заглушку вместо пустой строки, чтобы CSV не «съехал».

Что сделать: снять порты и версии сервисов, добавить HTTP-заголовки и данные TLS-сертификата, собрать всё в assets.json и отправить в CVEngine.
Зачем: ИИ-слой сопоставляет версии сервисов с известными уязвимостями, убирает дубли и ранжирует находки по критичности. Вручную сверять 50 баннеров с базами CVE — это часы; машина делает это за секунды. Точный эндпоинт и имена полей запроса — сверьтесь с документацией CVEngine.
Шаг 2.1 — сканирование портов и версий:
nmap -sT -sV --top-ports 100 -T4 \
-iL <(cut -d, -f1 asm/out/resolved.csv | grep -v NXDOMAIN) \
-oX asm/raw/scan.xml
-sT — connect-скан без root, -sV — определение версий, --top-ports 100 — 100 самых частых портов, -oX — результат в XML для машинной обработки.
Шаг 2.2 — конвертация XML в JSON штатной библиотекой Python:
import json, xml.etree.ElementTree as ET
root = ET.parse("asm/raw/scan.xml").getroot()
assets = []
for host in root.findall("host"):
addr = host.find("address").get("addr")
for port in host.findall("ports/port"):
state = port.find("state").get("state")
if state != "open":
continue
svc = port.find("service")
assets.append({
"host": addr,
"port": int(port.get("portid")),
"service": svc.get("name") if svc is not None else "unknown",
"version": (svc.get("product", "") + " " + svc.get("version", "")).strip(),
})
json.dump({"assets": assets}, open("asm/out/assets.json", "w"), indent=2)
print(f"собрано активов: {len(assets)}")
Запуск: python3 to_json.py. Ожидаемый вывод — собрано активов: 37 (число зависит от вашего периметра).
Шаг 2.3 — обогащение HTTP-заголовками и сертификатами:
for h in $(grep -v NXDOMAIN asm/out/resolved.csv | cut -d, -f1); do
echo "== $h"
curl -sSI --max-time 10 "https://$h" | head -n 5
echo | openssl s_client -connect "$h:443" -servername "$h" 2>/dev/null \
| openssl x509 -noout -subject -dates
done | tee asm/out/http_tls.txt
Результат — блоки вида == api.example.com, строка Server: nginx, затем notAfter=Mar 1 12:00:00 2026 GMT. Просроченный notAfter — сам по себе находка.
Шаг 2.4 — отправка в CVEngine:
export CVENGINE_API_BASE="https://<адрес-вашего-инстанса>"
export CVENGINE_TOKEN="<токен-из-личного-кабинета>"
curl -sS -X POST "$CVENGINE_API_BASE/<эндпоинт-загрузки-активов>" \
-H "Authorization: Bearer $CVENGINE_TOKEN" \
-H "Content-Type: application/json" \
--data @asm/out/assets.json \
-o asm/out/ai_report.json -w "%{http_code}\n"
Как проверить: код ответа 200 и валидный JSON в отчёте — jq 'keys' asm/out/ai_report.json. Должен вернуться массив ключей, например ["findings","summary"]; имена зависят от версии продукта — сверьтесь с документацией. Если вместо JSON пришёл HTML, см. раздел проблем.

Что сделать: разобрать ai_report.json, вручную подтвердить 3–5 верхних находок и зафиксировать итоговую таблицу.
Зачем: ИИ выдаёт гипотезы, а не доказательства. Версия nginx 1.18.0 в баннере может быть подменена или устареть — приоритет ставится только после ручного подтверждения.
Выборка топ-находок:
jq -r '.findings | sort_by(-.score) | .[:5][] | "\(.host):\(.port) \(.service) — \(.score)"' \
asm/out/ai_report.json
Пример: что должно появиться на экране.
93.184.216.34:443 nginx 1.18.0 — 8.7
93.184.216.35:22 openssh 8.2p1 — 6.1
93.184.216.35:8443 unknown — 5.4
Подтверждение одной находки:
nmap -sV -p 443 93.184.216.34
curl -sI https://api.example.com | grep -iE 'server|strict-transport'
Ожидаемый результат: та же версия в выводе nmap, что и в отчёте ИИ, и отсутствие Strict-Transport-Security в заголовках — это подтверждает находку, а не пересказывает её.
Итоговая таблица, которую вы отдаёте владельцу периметра:
| Приоритет | Актив | Признак | Чем подтвердили |
|---|---|---|---|
| 1 | 93.184.216.34:443 | устаревший `nginx 1.18.0` | `nmap -sV -p 443` |
| 2 | 93.184.216.35:22 | SSH открыт в интернет | `nmap -sT -p 22` |
| 3 | api.example.com | нет HSTS, сертификат истекает | `curl -sI`, `openssl x509` |
Как проверить: чек-лист приёмки.
false_positive в трекереai_report.json и scan.xml сохранены в asm/out/ с датой в имениРегулярное пересканирование (раз в неделю) удобно вешать на мониторинг с уведомлением в Telegram — схема разобрана в гайде по мониторингу VPS через Telegram-бота.
Проблема. Хост в списке есть, а данных по нему нет
curl: (6) Could not resolve host: vpn.example.comscope.txt опечатка.dig +short vpn.example.com и dig @1.1.1.1 +short vpn.example.com. Если оба пусты — уберите строку из scope.txt или запросите у владельца корректное имя. Строку NXDOMAIN в assets.json не отправляйте.Проблема. Ответ CVEngine не разбирается
jq: error (at asm/out/ai_report.json:0): Cannot index string with string "findings"{"error":"unauthorized"}. Чаще всего истёк токен или неверный эндпоинт.head -c 200 asm/out/ai_report.json — увидите фактический ответ. Проверьте echo $CVENGINE_TOKEN (не пустой, без кавычек), повторите запрос с -w "%{http_code}\n": 401 — ключ, 404 — путь эндпоинта, сверьтесь с документацией.Проблема. Сканирование падает сразу
You requested a scan type which requires root privileges. QUITTING!-sS (SYN-скан) или -O, они требуют raw-сокетов.-sT: nmap -sT -sV --top-ports 100 -T4 -iL asm/scope.txt -oX asm/raw/scan.xml. Проверка — whoami не должен требовать sudo для запуска.Вы собрали инвентарь периметра, обогатили его данными nmap/curl/openssl, прогнали через ИИ-слой CVEngine и подтвердили верхние находки руками. Дальше — поставьте пересканирование по расписанию и сравните два отчёта, чтобы видеть только новые активы и новые находки.
Чем оценка поверхности атаки отличается от пентеста?
ASM ищет и инвентаризирует всё, что торчит в интернет, и ранжирует риски без эксплуатации уязвимостей; пентест — это санкционированная попытка реально проэксплуатировать найденное.
Нужен ли root для nmap -sT?
Нет. Connect-скан устанавливает обычное TCP-соединение через системный вызов, поэтому работает от обычного пользователя. Root нужен для -sS и -O.
Можно ли сканировать чужие домены, чтобы «проверить»?
Нельзя. Сканируйте только активы из подписанного RoE; остальное — неправомерный доступ, даже если вы ничего не эксплуатировали.
Что делать с находками, которые ИИ выдал, а nmap не подтвердил?
Помечайте как ложное срабатывание и сохраняйте пару «находка + вывод проверки» — это обучающий материал для настройки правил на следующей итерации; конкретные настройки скоринга сверьте с документацией CVEngine.